How to revise the changes when working on a package using rstan?


#1

I am working on a R package using rstan. I have changed one parameter in the new stan code, but it is not revised in the new compiled program because I received this error messages:
"
Error in new_CppObject_xp(fields$.module, fields$.pointer, …) :
variable does not exist; processing stage=data initialization; variable name=prec; base type=matrix_d"

but I don’t have variable “prec” any more, it has been changed to “prec2”


#2

You have to recompile outside of RStudio with

R CMD INSTALL --preclean package_dir/

#3

Thank you.


#4

Hi, Ben,
I have used the bioconductor::biocCheck for this package which is developed via the rstan.package.skeleton(). I have received this note:

NOTE: Avoid sapply(); use vapply() found in files:
stanmodels.R (line 25, column 14)

I have changed sapply() to vapply(), but then I received this message:
"
Error in vapply(stan_files, function(f) { :
argument “FUN.VALUE” is missing, with no default
"
The FUN.VALUE seems to be the stanmode code. I don’t want to change the stanmodel’s original purpose. Could you please advise?


#5

I would change sapply to lapply, but if you are going to use vapply then you have to specify FUN.VALUE according to its documentation. In this case, the return is an object of S4 class stanmodel.


#6

I have changed to lapply(), the return is an object not a vector.

names(stanmodels) = sub("\.stan$", “”, basename(names(stanmodels)))
Error in basename(names(stanmodels)) :
a character vector argument expected

If I used vapply(), and define the returning value as stanmodel,
then it is okay, but when I compile it , it shows
Error in vapply(stan_files, function(f) { :
values must be type ‘character’,
but FUN(X[[1]]) result is type ‘S4’


#7

What do they have against sapply out of curiosity?

And what does your actual call to vapply look like? My hunch is that FUN.VALUE is specified incorrectly as a string rather than as an actual S4 object. Hard to know without seeing what you’re actually trying.


#8

The coding style of a bioconductor package prefers using vapply() to replace sapply().

The FUN.VALUE was actually specified as an S4 object “stanmodel”.

here is the changed stanmodel:

MODELS_HOME = “exec”
if (!file.exists(MODELS_HOME)) MODELS_HOME = sub(“R$”, “exec”, getwd())
stan_files = dir(MODELS_HOME,pattern = “stan$”, full.names = TRUE)
stanmodels =vapply(stan_files,function(f) {
model_cppname = sub("\.stan$", “”, basename(f))
isystem = system.file(“chunks”,
package = methods::getPackageName(environment(), FALSE))
if (!file.exists(file.path(isystem, “common_functions.stan”)))
isystem = file.path(“inst”, “chunks”)
if (!file.exists(file.path(isystem, “common_functions.stan”)))
isystem = file.path("…", “inst”, “chunks”)
stanfit = rstan::stanc_builder(f, isystem, allow_undefined = TRUE)
stanfit$model_cpp = list(model_cppname = stanfit$model_name,
model_cppcode = stanfit$cppcode)
return(do.call(methods::new, args = c(stanfit[-seq_len(3)],
Class = “stanmodel”,
mk_cppmodule = function(x) get(paste0(“model_”, model_cppname)))))
}
,“stanmodel”
)
names(stanmodels) = sub("\.stan$", “”, basename(names(stanmodels)))
rm(MODELS_HOME)

I have tried character(1) as well, but it is not correct.


#9

Which one is FUN.VALUE? The string “stanmodel”? If so that won’t work. It needs to be an object of that class not the name of the class.


#10

Or try unlist(lapply(…)), not just lapply, which may work and is easier.


#11

thank you for the suggestion. I tried unlist(lapply(…)),

> MODELS_HOME = "exec"
> if (!file.exists(MODELS_HOME)) MODELS_HOME = sub("R$", "exec", getwd())
> stan_files = dir(MODELS_HOME,pattern = "stan$", full.names = TRUE)
> stanmodels =unlist(lapply(stan_files,function(f) {
+ model_cppname = sub("\\.stan$", "", basename(f))
+ isystem = system.file("chunks",    
+ package = methods::getPackageName(environment(), FALSE))
+ if (!file.exists(file.path(isystem, "common_functions.stan")))
+     isystem = file.path("inst", "chunks")
+ if (!file.exists(file.path(isystem, "common_functions.stan")))
+     isystem = file.path("..", "inst", "chunks")
+     stanfit = rstan::stanc_builder(f, isystem, allow_undefined = TRUE)
+     stanfit$model_cpp = list(model_cppname = stanfit$model_name, 
+                             model_cppcode = stanfit$cppcode)
+     return(do.call(methods::new, args = c(stanfit[-seq_len(3)], 
+     Class = "stanmodel", 
+     mk_cppmodule = function(x) get(paste0("model_", model_cppname)))))
+     }
+ ))
> names(stanmodels) = sub("\\.stan$", "", basename(names(stanmodels)))
Error in basename(names(stanmodels)) : 
  a character vector argument expected

#12

Did you try vapply with an actual stanmodel object? You can maybe make an empty stanmodel object with rstan::stan_model and pass that to FUN.VALUE.


#13

Don’t unlist, just use lapply.


#14

Thank you for both of your suggestions.
lapply :

stanmodels =lapply(stan_files,function(f) {

  • model_cppname = sub("\.stan$", “”, basename(f))
  • isystem = system.file(“chunks”,
  • package = methods::getPackageName(environment(), FALSE))
  • if (!file.exists(file.path(isystem, “common_functions.stan”)))
  • isystem = file.path("inst", "chunks")
    
  • if (!file.exists(file.path(isystem, “common_functions.stan”)))
  • isystem = file.path("..", "inst", "chunks")
    
  • stanfit = rstan::stanc_builder(f, isystem, allow_undefined = TRUE)
    
  • stanfit$model_cpp = list(model_cppname = stanfit$model_name, 
    
  •                         model_cppcode = stanfit$cppcode)
    
  • return(do.call(methods::new, args = c(stanfit[-seq_len(3)], 
    
  • Class = "stanmodel", 
    
  • mk_cppmodule = function(x) get(paste0("model_", model_cppname)))))
    
  • }
    
  • )

names(stanmodels) = sub("\.stan$", “”, basename(names(stanmodels)))
Error in basename(names(stanmodels)) :
a character vector argument expected

use an empty object:
xobj=rstan::stan_model()
I will have a warning, and also this message :
names(stanmodels) = sub("\.stan$", “”, basename(names(stanmodels)))
Error in basename(names(stanmodels)) :
a character vector argument expected

I think, lapply() or vapply() requires return value to be vector or matrix, sapply( ) does not have this restriction? I probability have to use sapply()


#15

sapply is never the one and only way to do something since it’s just avoiding writing a loop.

Is there anything else different in this file than in the original other than changing sapply to lapply? I think sapply was returning a list too in this case, so I think @bgoodri is right but I’m not sure why lapply doesn’t work for you .


#16

The only difference is replace sapply() by lapply(), if using lapply().
If using vapply(), I have specified the FUN.VALUE to “stanmodel” which is an object.


#17

If you’re still using the quotes around stanmodel (“stanmodel”) then it’s still a string naming the object and not that object itself. If stanmodel is being used in quotes I would remove them.


#18

Thank you for the suggestions. vapply() need to specify FUN.VALUE to be an empty object, use new(), I have not made it working though.

I now found the difference in using sapply() vs lapply() for this case.
sapply() has the name of the stan model code as one of its attribute in the returning value, but lapply() only has the stan model code without the name of the code. That is why if I use lapply(), I will have error message from “basename(names(stanmodels))”.

This is the stanmodels result heading from sapply():
$exmple_code.stan
S4 class stanmodel ‘example_code’ coded as follows:
//RSTAN code for mlmm() function
//include “license.stan” // GPL2+

And the result heading from lapply():
[[1]]
S4 class stanmodel ‘example_code’ coded as follows:
//RSTAN code for example() function
//include “license.stan” // GPL2+


#19

Just download the new stanmodels.R file from
https://raw.githubusercontent.com/stan-dev/rstanarm/master/R/stanmodels.R


#20

Thank you, there is no error message when running the stanmodel code.

While I receive this when using ::check() or ::build() though
"
Loading required package: Rcpp
Error in is(module, “character”) : object ‘m’ not found
"

The names(stan_files) dose not pass on the stan code name, because I tested it and it came back with
"

stanmodels
named list()
"
Instead of the stan model codes when using sapply() version.