I’m going to assume you’re not pranking me here. I tried to express my reservations during the roadmap meeting and was told I was being difficult. I brought it up on the proposed roadmap post on discourse (since delisted) and was told I should’ve gone to the beach house if I wanted to be heard. I’ve had long discussions with @bgoodri and @ariddell in the past where I’ve been told my proposals weren’t R-like or Pythonic, which is why I wasn’t particularly keen to spend a weekend away from home to just lose the same battle once again. This doesn’t block my applied work now that I understand how it works, so it’s not that big of a deal to me, especially as I don’t do a lot with RStan or PyStan myself, especially at this level.
Anyway, to summarize, my main objection is that it’s used for too many things, most of which leave it in a partial state. Here’s some cases off the top of my head:
-
holding the arguments, output, and intermediate products of a call to `stan(), including config, generated random seeds, a link to the model, a link to the enviornment, the draws, features of the C++ config, time stamps, timing, adaptation stepsize and metric, the name of the file in which the model was saved if it was saved, and so on; it even contains summary statistics like means by default
-
gathering external output to evaluate using
read_stan_csv()
, in which case everything but the draws seems irrelevant -
creating a log density function to use by running for zero iterations, in which case sampler config and draws are irrelevant; I’d much prefer a way to create a log density function from a compiled model and data
-
as a holder for a model to rerun (ther’s a
fit
argument in rstan, which if supplied, pulls the model out of the fit object somehow to reuse for the current run), potentially on new data with new config, so only the model link is relevant
Finally, how do we create a stanfit object when we’re able to restart sampling? Will it be mutable or do we create a copy of the data? Is it going to be used for standalone generated quantities? Which additional fields will this need? What about Laplace approximations from optimization? Or approximate draws from ADVI?
Anyway, here’s the full structure of a stanfit object in R in rstan 2.19.2.
> fit <- stan(...)
> str(fit)
Formal class 'stanfit' [package "rstan"] with 10 slots
..@ model_name: chr "ea83e6880be685a7fae174e58aafc354"
..@ model_pars: chr [1:4] "a" "b" "c" "lp__"
..@ par_dims :List of 4
.. ..$ a : num(0)
.. ..$ b : num(0)
.. ..$ c : num(0)
.. ..$ lp__: num(0)
..@ mode : int 0
..@ sim :List of 12
.. ..$ samples :List of 4
.. .. ..$ :List of 4
.. .. .. ..$ a : num [1:2000] 0.8785 0.7311 0.2686 0.0556 0.0363 ...
.. .. .. ..$ b : num [1:2000] 2.88 2.73 2.27 2.06 2.04 ...
.. .. .. ..$ c : num [1:2000] 3 3 3 3 3 3 3 3 3 3 ...
.. .. .. ..$ lp__: num [1:2000] -2.24 -1.63 -1.63 -2.95 -3.35 ...
.. .. .. ..- attr(*, "test_grad")= logi FALSE
.. .. .. ..- attr(*, "args")=List of 16
.. .. .. .. ..$ append_samples : logi FALSE
.. .. .. .. ..$ chain_id : num 1
.. .. .. .. ..$ control :List of 12
.. .. .. .. .. ..$ adapt_delta : num 0.8
.. .. .. .. .. ..$ adapt_engaged : logi TRUE
.. .. .. .. .. ..$ adapt_gamma : num 0.05
.. .. .. .. .. ..$ adapt_init_buffer: num 75
.. .. .. .. .. ..$ adapt_kappa : num 0.75
.. .. .. .. .. ..$ adapt_t0 : num 10
.. .. .. .. .. ..$ adapt_term_buffer: num 50
.. .. .. .. .. ..$ adapt_window : num 25
.. .. .. .. .. ..$ max_treedepth : int 10
.. .. .. .. .. ..$ metric : chr "diag_e"
.. .. .. .. .. ..$ stepsize : num 1
.. .. .. .. .. ..$ stepsize_jitter : num 0
.. .. .. .. ..$ enable_random_init: logi TRUE
.. .. .. .. ..$ init : chr "random"
.. .. .. .. ..$ init_list : NULL
.. .. .. .. ..$ init_radius : num 2
.. .. .. .. ..$ iter : int 2000
.. .. .. .. ..$ method : chr "sampling"
.. .. .. .. ..$ random_seed : chr "935365312"
.. .. .. .. ..$ refresh : int 200
.. .. .. .. ..$ sampler_t : chr "NUTS(diag_e)"
.. .. .. .. ..$ save_warmup : logi TRUE
.. .. .. .. ..$ test_grad : logi FALSE
.. .. .. .. ..$ thin : int 1
.. .. .. .. ..$ warmup : int 1000
.. .. .. ..- attr(*, "inits")= num [1:3] 0.879 2.879 3
.. .. .. ..- attr(*, "mean_pars")= num [1:3] 0.502 2.502 3
.. .. .. ..- attr(*, "mean_lp__")= num -1.98
.. .. .. ..- attr(*, "adaptation_info")= chr "# Adaptation terminated\n# Step size = 0.78172\n# Diagonal elements of inverse mass matrix:\n# 3.58301\n"
.. .. .. ..- attr(*, "elapsed_time")= Named num [1:2] 0.0132 0.0112
.. .. .. .. ..- attr(*, "names")= chr [1:2] "warmup" "sample"
.. .. .. ..- attr(*, "sampler_params")=List of 6
.. .. .. .. ..$ accept_stat__: num [1:2000] 2.90e-07 1.00 9.69e-01 4.46e-01 9.90e-01 ...
.. .. .. .. ..$ stepsize__ : num [1:2000] 8 2.34 2.43 3.17 1.06 ...
.. .. .. .. ..$ treedepth__ : num [1:2000] 1 1 1 1 1 1 2 1 2 1 ...
.. .. .. .. ..$ n_leapfrog__ : num [1:2000] 3 1 3 1 1 3 3 1 3 3 ...
.. .. .. .. ..$ divergent__ : num [1:2000] 0 0 0 0 0 0 0 0 0 0 ...
.. .. .. .. ..$ energy__ : num [1:2000] 2.3 2.09 1.66 3.29 3.36 ...
.. .. .. ..- attr(*, "return_code")= int 0
.. .. ..$ :List of 4
.. .. .. ..$ a : num [1:2000] 0.741 0.886 0.616 0.619 0.253 ...
.. .. .. ..$ b : num [1:2000] 2.74 2.89 2.62 2.62 2.25 ...
.. .. .. ..$ c : num [1:2000] 3 3 3 3 3 3 3 3 3 3 ...
.. .. .. ..$ lp__: num [1:2000] -1.65 -2.29 -1.44 -1.44 -1.67 ...
.. .. .. ..- attr(*, "test_grad")= logi FALSE
.. .. .. ..- attr(*, "args")=List of 16
.. .. .. .. ..$ append_samples : logi FALSE
.. .. .. .. ..$ chain_id : num 2
.. .. .. .. ..$ control :List of 12
.. .. .. .. .. ..$ adapt_delta : num 0.8
.. .. .. .. .. ..$ adapt_engaged : logi TRUE
.. .. .. .. .. ..$ adapt_gamma : num 0.05
.. .. .. .. .. ..$ adapt_init_buffer: num 75
.. .. .. .. .. ..$ adapt_kappa : num 0.75
.. .. .. .. .. ..$ adapt_t0 : num 10
.. .. .. .. .. ..$ adapt_term_buffer: num 50
.. .. .. .. .. ..$ adapt_window : num 25
.. .. .. .. .. ..$ max_treedepth : int 10
.. .. .. .. .. ..$ metric : chr "diag_e"
.. .. .. .. .. ..$ stepsize : num 1
.. .. .. .. .. ..$ stepsize_jitter : num 0
.. .. .. .. ..$ enable_random_init: logi TRUE
.. .. .. .. ..$ init : chr "random"
.. .. .. .. ..$ init_list : NULL
.. .. .. .. ..$ init_radius : num 2
.. .. .. .. ..$ iter : int 2000
.. .. .. .. ..$ method : chr "sampling"
.. .. .. .. ..$ random_seed : chr "935365312"
.. .. .. .. ..$ refresh : int 200
.. .. .. .. ..$ sampler_t : chr "NUTS(diag_e)"
.. .. .. .. ..$ save_warmup : logi TRUE
.. .. .. .. ..$ test_grad : logi FALSE
.. .. .. .. ..$ thin : int 1
.. .. .. .. ..$ warmup : int 1000
.. .. .. ..- attr(*, "inits")= num [1:3] 0.741 2.741 3
.. .. .. ..- attr(*, "mean_pars")= num [1:3] 0.471 2.471 3
.. .. .. ..- attr(*, "mean_lp__")= num -1.97
.. .. .. ..- attr(*, "adaptation_info")= chr "# Adaptation terminated\n# Step size = 0.943964\n# Diagonal elements of inverse mass matrix:\n# 2.98648\n"
.. .. .. ..- attr(*, "elapsed_time")= Named num [1:2] 0.012 0.0114
.. .. .. .. ..- attr(*, "names")= chr [1:2] "warmup" "sample"
.. .. .. ..- attr(*, "sampler_params")=List of 6
.. .. .. .. ..$ accept_stat__: num [1:2000] 0.022 0.3 0.999 1 0.979 ...
.. .. .. .. ..$ stepsize__ : num [1:2000] 4 2.43 0.491 0.564 0.811 ...
.. .. .. .. ..$ treedepth__ : num [1:2000] 1 2 2 1 2 1 2 1 1 3 ...
.. .. .. .. ..$ n_leapfrog__ : num [1:2000] 1 3 5 1 5 1 3 3 1 7 ...
.. .. .. .. ..$ divergent__ : num [1:2000] 0 0 0 0 0 0 0 0 0 0 ...
.. .. .. .. ..$ energy__ : num [1:2000] 1.91 3.49 2.43 1.45 1.91 ...
.. .. .. ..- attr(*, "return_code")= int 0
.. .. ..$ :List of 4
.. .. .. ..$ a : num [1:2000] 0.566 0.566 0.404 0.41 0.41 ...
.. .. .. ..$ b : num [1:2000] 2.57 2.57 2.4 2.41 2.41 ...
.. .. .. ..$ c : num [1:2000] 3 3 3 3 3 3 3 3 3 3 ...
.. .. .. ..$ lp__: num [1:2000] -1.4 -1.4 -1.42 -1.42 -1.42 ...
.. .. .. ..- attr(*, "test_grad")= logi FALSE
.. .. .. ..- attr(*, "args")=List of 16
.. .. .. .. ..$ append_samples : logi FALSE
.. .. .. .. ..$ chain_id : num 3
.. .. .. .. ..$ control :List of 12
.. .. .. .. .. ..$ adapt_delta : num 0.8
.. .. .. .. .. ..$ adapt_engaged : logi TRUE
.. .. .. .. .. ..$ adapt_gamma : num 0.05
.. .. .. .. .. ..$ adapt_init_buffer: num 75
.. .. .. .. .. ..$ adapt_kappa : num 0.75
.. .. .. .. .. ..$ adapt_t0 : num 10
.. .. .. .. .. ..$ adapt_term_buffer: num 50
.. .. .. .. .. ..$ adapt_window : num 25
.. .. .. .. .. ..$ max_treedepth : int 10
.. .. .. .. .. ..$ metric : chr "diag_e"
.. .. .. .. .. ..$ stepsize : num 1
.. .. .. .. .. ..$ stepsize_jitter : num 0
.. .. .. .. ..$ enable_random_init: logi TRUE
.. .. .. .. ..$ init : chr "random"
.. .. .. .. ..$ init_list : NULL
.. .. .. .. ..$ init_radius : num 2
.. .. .. .. ..$ iter : int 2000
.. .. .. .. ..$ method : chr "sampling"
.. .. .. .. ..$ random_seed : chr "935365312"
.. .. .. .. ..$ refresh : int 200
.. .. .. .. ..$ sampler_t : chr "NUTS(diag_e)"
.. .. .. .. ..$ save_warmup : logi TRUE
.. .. .. .. ..$ test_grad : logi FALSE
.. .. .. .. ..$ thin : int 1
.. .. .. .. ..$ warmup : int 1000
.. .. .. ..- attr(*, "inits")= num [1:3] 0.168 2.168 3
.. .. .. ..- attr(*, "mean_pars")= num [1:3] 0.492 2.492 3
.. .. .. ..- attr(*, "mean_lp__")= num -1.97
.. .. .. ..- attr(*, "adaptation_info")= chr "# Adaptation terminated\n# Step size = 0.92127\n# Diagonal elements of inverse mass matrix:\n# 3.33791\n"
.. .. .. ..- attr(*, "elapsed_time")= Named num [1:2] 0.0114 0.012
.. .. .. .. ..- attr(*, "names")= chr [1:2] "warmup" "sample"
.. .. .. ..- attr(*, "sampler_params")=List of 6
.. .. .. .. ..$ accept_stat__: num [1:2000] 1.00 7.41e-14 9.94e-01 1.00 5.02e-05 ...
.. .. .. .. ..$ stepsize__ : num [1:2000] 2 14.39 2.43 3.39 5.55 ...
.. .. .. .. ..$ treedepth__ : num [1:2000] 1 2 1 1 1 2 2 2 1 2 ...
.. .. .. .. ..$ n_leapfrog__ : num [1:2000] 3 3 3 1 1 7 7 7 3 3 ...
.. .. .. .. ..$ divergent__ : num [1:2000] 0 0 0 0 0 0 0 0 0 0 ...
.. .. .. .. ..$ energy__ : num [1:2000] 1.73 1.44 1.42 1.47 3.29 ...
.. .. .. ..- attr(*, "return_code")= int 0
.. .. ..$ :List of 4
.. .. .. ..$ a : num [1:2000] 0.0789 0.552 0.552 0.4402 0.7901 ...
.. .. .. ..$ b : num [1:2000] 2.08 2.55 2.55 2.44 2.79 ...
.. .. .. ..$ c : num [1:2000] 3 3 3 3 3 3 3 3 3 3 ...
.. .. .. ..$ lp__: num [1:2000] -2.62 -1.4 -1.4 -1.4 -1.8 ...
.. .. .. ..- attr(*, "test_grad")= logi FALSE
.. .. .. ..- attr(*, "args")=List of 16
.. .. .. .. ..$ append_samples : logi FALSE
.. .. .. .. ..$ chain_id : num 4
.. .. .. .. ..$ control :List of 12
.. .. .. .. .. ..$ adapt_delta : num 0.8
.. .. .. .. .. ..$ adapt_engaged : logi TRUE
.. .. .. .. .. ..$ adapt_gamma : num 0.05
.. .. .. .. .. ..$ adapt_init_buffer: num 75
.. .. .. .. .. ..$ adapt_kappa : num 0.75
.. .. .. .. .. ..$ adapt_t0 : num 10
.. .. .. .. .. ..$ adapt_term_buffer: num 50
.. .. .. .. .. ..$ adapt_window : num 25
.. .. .. .. .. ..$ max_treedepth : int 10
.. .. .. .. .. ..$ metric : chr "diag_e"
.. .. .. .. .. ..$ stepsize : num 1
.. .. .. .. .. ..$ stepsize_jitter : num 0
.. .. .. .. ..$ enable_random_init: logi TRUE
.. .. .. .. ..$ init : chr "random"
.. .. .. .. ..$ init_list : NULL
.. .. .. .. ..$ init_radius : num 2
.. .. .. .. ..$ iter : int 2000
.. .. .. .. ..$ method : chr "sampling"
.. .. .. .. ..$ random_seed : chr "935365312"
.. .. .. .. ..$ refresh : int 200
.. .. .. .. ..$ sampler_t : chr "NUTS(diag_e)"
.. .. .. .. ..$ save_warmup : logi TRUE
.. .. .. .. ..$ test_grad : logi FALSE
.. .. .. .. ..$ thin : int 1
.. .. .. .. ..$ warmup : int 1000
.. .. .. ..- attr(*, "inits")= num [1:3] 0.834 2.834 3
.. .. .. ..- attr(*, "mean_pars")= num [1:3] 0.501 2.501 3
.. .. .. ..- attr(*, "mean_lp__")= num -2.01
.. .. .. ..- attr(*, "adaptation_info")= chr "# Adaptation terminated\n# Step size = 0.972186\n# Diagonal elements of inverse mass matrix:\n# 3.23769\n"
.. .. .. ..- attr(*, "elapsed_time")= Named num [1:2] 0.013 0.0108
.. .. .. .. ..- attr(*, "names")= chr [1:2] "warmup" "sample"
.. .. .. ..- attr(*, "sampler_params")=List of 6
.. .. .. .. ..$ accept_stat__: num [1:2000] 0.198 1 0.181 0.994 0.965 ...
.. .. .. .. ..$ stepsize__ : num [1:2000] 4 3.347 3.877 0.658 0.94 ...
.. .. .. .. ..$ treedepth__ : num [1:2000] 2 1 2 2 2 1 1 1 1 1 ...
.. .. .. .. ..$ n_leapfrog__ : num [1:2000] 3 1 3 5 5 3 1 1 1 1 ...
.. .. .. .. ..$ divergent__ : num [1:2000] 0 0 0 0 0 0 0 0 0 0 ...
.. .. .. .. ..$ energy__ : num [1:2000] 2.84 1.59 3.01 1.61 1.88 ...
.. .. .. ..- attr(*, "return_code")= int 0
.. ..$ iter : num 2000
.. ..$ thin : num 1
.. ..$ warmup : num 1000
.. ..$ chains : num 4
.. ..$ n_save : num [1:4] 2000 2000 2000 2000
.. ..$ warmup2 : num [1:4] 1000 1000 1000 1000
.. ..$ permutation:List of 4
.. .. ..$ : int [1:1000] 73 31 939 983 858 75 957 258 287 425 ...
.. .. ..$ : int [1:1000] 932 807 140 586 871 101 112 762 879 175 ...
.. .. ..$ : int [1:1000] 578 525 232 489 50 906 941 237 709 532 ...
.. .. ..$ : int [1:1000] 59 232 853 513 617 678 341 302 455 907 ...
.. ..$ pars_oi : chr [1:4] "a" "b" "c" "lp__"
.. ..$ dims_oi :List of 4
.. .. ..$ a : num(0)
.. .. ..$ b : num(0)
.. .. ..$ c : num(0)
.. .. ..$ lp__: num(0)
.. ..$ fnames_oi : chr [1:4] "a" "b" "c" "lp__"
.. ..$ n_flatnames: int 4
..@ inits :List of 4
.. ..$ :List of 3
.. .. ..$ a: num 0.879
.. .. ..$ b: num 2.88
.. .. ..$ c: num 3
.. ..$ :List of 3
.. .. ..$ a: num 0.741
.. .. ..$ b: num 2.74
.. .. ..$ c: num 3
.. ..$ :List of 3
.. .. ..$ a: num 0.168
.. .. ..$ b: num 2.17
.. .. ..$ c: num 3
.. ..$ :List of 3
.. .. ..$ a: num 0.834
.. .. ..$ b: num 2.83
.. .. ..$ c: num 3
..@ stan_args :List of 4
.. ..$ :List of 9
.. .. ..$ chain_id : int 1
.. .. ..$ iter : int 2000
.. .. ..$ thin : int 1
.. .. ..$ seed : int 935365312
.. .. ..$ warmup : num 1000
.. .. ..$ init : chr "random"
.. .. ..$ algorithm : chr "NUTS"
.. .. ..$ check_unknown_args: logi FALSE
.. .. ..$ method : chr "sampling"
.. ..$ :List of 9
.. .. ..$ chain_id : int 2
.. .. ..$ iter : int 2000
.. .. ..$ thin : int 1
.. .. ..$ seed : int 935365312
.. .. ..$ warmup : num 1000
.. .. ..$ init : chr "random"
.. .. ..$ algorithm : chr "NUTS"
.. .. ..$ check_unknown_args: logi FALSE
.. .. ..$ method : chr "sampling"
.. ..$ :List of 9
.. .. ..$ chain_id : int 3
.. .. ..$ iter : int 2000
.. .. ..$ thin : int 1
.. .. ..$ seed : int 935365312
.. .. ..$ warmup : num 1000
.. .. ..$ init : chr "random"
.. .. ..$ algorithm : chr "NUTS"
.. .. ..$ check_unknown_args: logi FALSE
.. .. ..$ method : chr "sampling"
.. ..$ :List of 9
.. .. ..$ chain_id : int 4
.. .. ..$ iter : int 2000
.. .. ..$ thin : int 1
.. .. ..$ seed : int 935365312
.. .. ..$ warmup : num 1000
.. .. ..$ init : chr "random"
.. .. ..$ algorithm : chr "NUTS"
.. .. ..$ check_unknown_args: logi FALSE
.. .. ..$ method : chr "sampling"
..@ stanmodel :Formal class 'stanmodel' [package "rstan"] with 5 slots
.. .. ..@ model_name : chr "ea83e6880be685a7fae174e58aafc354"
.. .. ..@ model_code : chr "parameters { real<lower = 0, upper = 1> a; } transformed parameters { real b = a + 2; } generated quantities { real c = 3; }"
.. .. .. ..- attr(*, "model_name2")= chr "ea83e6880be685a7fae174e58aafc354"
.. .. ..@ model_cpp :List of 2
.. .. .. ..$ model_cppname: chr "model89c6853b5b5_ea83e6880be685a7fae174e58aafc354"
.. .. .. ..$ model_cppcode: chr "// Code generated by Stan version 2.19.1\n\n#include <stan/model/model_header.hpp>\n\nnamespace model89c6853b5b"| __truncated__
.. .. ..@ mk_cppmodule:function (object)
.. .. ..@ dso :Formal class 'cxxdso' [package "rstan"] with 7 slots
.. .. .. .. ..@ sig :List of 1
.. .. .. .. .. ..$ file89c64058ffcc: chr(0)
.. .. .. .. ..@ dso_saved : logi TRUE
.. .. .. .. ..@ dso_filename: chr "file89c64058ffcc"
.. .. .. .. ..@ modulename : chr "stan_fit4model89c6853b5b5_ea83e6880be685a7fae174e58aafc354_mod"
.. .. .. .. ..@ system : chr "x86_64, darwin15.6.0"
.. .. .. .. ..@ cxxflags : chr "CXXFLAGS= -O3 -mtune=native $(LTO) -w #set_by_rstan (and Bob)"
.. .. .. .. ..@ .CXXDSOMISC :<environment: 0x7fc206f3d670>
..@ date : chr "Mon Sep 23 19:55:20 2019"
..@ .MISC :<environment: 0x7fc209630598>