Skip to content

Commit

Permalink
Unify constructors to always allow a .stan file to be passed (#188)
Browse files Browse the repository at this point in the history
* Unify constructors to always allow a .stan file to be passed

* Fix tests to avoid segfault

Caused by loading non-THREADS model in same instance as THREADS=1

* Update example.R

* Doc tweaks
  • Loading branch information
WardBrian authored Nov 30, 2023
1 parent 41b66b7 commit 7ca2952
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 177 deletions.
6 changes: 2 additions & 4 deletions R/example.R
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# Before running this:
# - In the terminal, run `make test_models/bernoulli/bernoulli_model.so` from inside the bridgestan folder
# - In R, make sure you are in the directory bridgestan/R
# Before running this, make sure you are in the directory bridgestan/R

library(bridgestan)

model <- StanModel$new("../test_models/bernoulli/bernoulli_model.so", "../test_models/bernoulli/bernoulli.data.json", 1234)
model <- StanModel$new("../test_models/bernoulli/bernoulli.stan", "../test_models/bernoulli/bernoulli.data.json", 1234)

print(paste0("This model's name is ", model$name(), "."))
print(paste0("This model has ", model$param_num(), " parameters."))
Expand Down
60 changes: 26 additions & 34 deletions docs/languages/julia.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,27 +116,19 @@ An example program is provided alongside the Julia interface code in `example.jl


```julia
StanModel(lib, datafile="", seed=204)
StanModel(lib, data="", seed=204; stanc_args=[], make_args=[])
```

A StanModel instance encapsulates a Stan model instantiated with data.

Construct a Stan model from the supplied library file path and data. Data should either be a string containing a JSON string literal, a path to a data file ending in `.json`, or the empty string. If seed is supplied, it is used to initialize the RNG used by the model's constructor.
Construct a Stan model from the supplied library file path and data. If lib is a path to a file ending in `.stan`, this will first compile the model. Compilation occurs if no shared object file exists for the supplied Stan file or if a shared object file exists and the Stan file has changed since last compilation. This is equivalent to calling `compile_model` and then the constructor of `StanModel`.

```
StanModel(;stan_file, data="", seed=204)
```

Construct a `StanModel` instance from a `.stan` file, compiling if necessary.

```
StanModel(;stan_file, stanc_args=[], make_args=[], data="", seed=204)
```
Data should either be a string containing a JSON string literal, a path to a data file ending in `.json`, or the empty string.

Construct a `StanModel` instance from a `.stan` file. Compilation occurs if no shared object file exists for the supplied Stan file or if a shared object file exists and the Stan file has changed since last compilation. This is equivalent to calling `compile_model` and then the original constructor of `StanModel`.
If seed is supplied, it is used to initialize the RNG used by the model's constructor.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L15-L36' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L15-L31' class='documenter-source'>source</a><br>

<a id='BridgeStan.log_density' href='#BridgeStan.log_density'>#</a>
**`BridgeStan.log_density`** &mdash; *Function*.
Expand All @@ -152,7 +144,7 @@ Return the log density of the specified unconstrained parameters.
This calculation drops constant terms that do not depend on the parameters if `propto` is `true` and includes change of variables terms for constrained parameters if `jacobian` is `true`.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L492-L499' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L497-L504' class='documenter-source'>source</a><br>

<a id='BridgeStan.log_density_gradient' href='#BridgeStan.log_density_gradient'>#</a>
**`BridgeStan.log_density_gradient`** &mdash; *Function*.
Expand All @@ -170,7 +162,7 @@ This calculation drops constant terms that do not depend on the parameters if `p
This allocates new memory for the gradient output each call. See `log_density_gradient!` for a version which allows re-using existing memory.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L575-L587' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L580-L592' class='documenter-source'>source</a><br>

<a id='BridgeStan.log_density_hessian' href='#BridgeStan.log_density_hessian'>#</a>
**`BridgeStan.log_density_hessian`** &mdash; *Function*.
Expand All @@ -188,7 +180,7 @@ This calculation drops constant terms that do not depend on the parameters if `p
This allocates new memory for the gradient and Hessian output each call. See `log_density_gradient!` for a version which allows re-using existing memory.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L662-L673' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L667-L678' class='documenter-source'>source</a><br>

<a id='BridgeStan.log_density_hessian_vector_product' href='#BridgeStan.log_density_hessian_vector_product'>#</a>
**`BridgeStan.log_density_hessian_vector_product`** &mdash; *Function*.
Expand All @@ -206,7 +198,7 @@ This calculation drops constant terms that do not depend on the parameters if `p
This allocates new memory for the output each call. See `log_density_hessian_vector_product!` for a version which allows re-using existing memory.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L744-L755' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L749-L760' class='documenter-source'>source</a><br>

<a id='BridgeStan.param_constrain' href='#BridgeStan.param_constrain'>#</a>
**`BridgeStan.param_constrain`** &mdash; *Function*.
Expand All @@ -226,7 +218,7 @@ This allocates new memory for the output each call. See `param_constrain!` for a
This is the inverse of `param_unconstrain`.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L349-L364' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L354-L369' class='documenter-source'>source</a><br>

<a id='BridgeStan.param_unconstrain' href='#BridgeStan.param_unconstrain'>#</a>
**`BridgeStan.param_unconstrain`** &mdash; *Function*.
Expand All @@ -246,7 +238,7 @@ This allocates new memory for the output each call. See `param_unconstrain!` for
This is the inverse of `param_constrain`.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L421-L434' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L426-L439' class='documenter-source'>source</a><br>

<a id='BridgeStan.param_unconstrain_json' href='#BridgeStan.param_unconstrain_json'>#</a>
**`BridgeStan.param_unconstrain_json`** &mdash; *Function*.
Expand All @@ -264,7 +256,7 @@ The JSON is expected to be in the [JSON Format for CmdStan](https://mc-stan.org/
This allocates new memory for the output each call. See `param_unconstrain_json!` for a version which allows re-using existing memory.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L476-L486' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L481-L491' class='documenter-source'>source</a><br>

<a id='BridgeStan.name' href='#BridgeStan.name'>#</a>
**`BridgeStan.name`** &mdash; *Function*.
Expand All @@ -278,7 +270,7 @@ name(sm)
Return the name of the model `sm`


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L155-L159' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L160-L164' class='documenter-source'>source</a><br>

<a id='BridgeStan.model_info' href='#BridgeStan.model_info'>#</a>
**`BridgeStan.model_info`** &mdash; *Function*.
Expand All @@ -294,7 +286,7 @@ Return information about the model `sm`.
This includes the Stan version and important compiler flags.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L170-L177' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L175-L182' class='documenter-source'>source</a><br>

<a id='BridgeStan.param_num' href='#BridgeStan.param_num'>#</a>
**`BridgeStan.param_num`** &mdash; *Function*.
Expand All @@ -310,7 +302,7 @@ Return the number of (constrained) parameters in the model.
This is the total of all the sizes of items declared in the `parameters` block of the model. If `include_tp` or `include_gq` are true, items declared in the `transformed parameters` and `generate quantities` blocks are included, respectively.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L200-L209' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L205-L214' class='documenter-source'>source</a><br>

<a id='BridgeStan.param_unc_num' href='#BridgeStan.param_unc_num'>#</a>
**`BridgeStan.param_unc_num`** &mdash; *Function*.
Expand All @@ -326,7 +318,7 @@ Return the number of unconstrained parameters in the model.
This function is mainly different from `param_num` when variables are declared with constraints. For example, `simplex[5]` has a constrained size of 5, but an unconstrained size of 4.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L222-L230' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L227-L235' class='documenter-source'>source</a><br>

<a id='BridgeStan.param_names' href='#BridgeStan.param_names'>#</a>
**`BridgeStan.param_names`** &mdash; *Function*.
Expand All @@ -344,7 +336,7 @@ For containers, indexes are separated by periods (.).
For example, the scalar `a` has indexed name `"a"`, the vector entry `a[1]` has indexed name `"a.1"` and the matrix entry `a[2, 3]` has indexed names `"a.2.3"`. Parameter order of the output is column major and more generally last-index major for containers.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L240-L251' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L245-L256' class='documenter-source'>source</a><br>

<a id='BridgeStan.param_unc_names' href='#BridgeStan.param_unc_names'>#</a>
**`BridgeStan.param_unc_names`** &mdash; *Function*.
Expand All @@ -360,7 +352,7 @@ Return the indexed names of the unconstrained parameters.
For example, a scalar unconstrained parameter `b` has indexed name `b` and a vector entry `b[3]` has indexed name `b.3`.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L264-L271' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L269-L276' class='documenter-source'>source</a><br>

<a id='BridgeStan.log_density_gradient!' href='#BridgeStan.log_density_gradient!'>#</a>
**`BridgeStan.log_density_gradient!`** &mdash; *Function*.
Expand All @@ -378,7 +370,7 @@ This calculation drops constant terms that do not depend on the parameters if `p
The gradient is stored in the vector `out`, and a reference is returned. See `log_density_gradient` for a version which allocates fresh memory.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L521-L531' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L526-L536' class='documenter-source'>source</a><br>

<a id='BridgeStan.log_density_hessian!' href='#BridgeStan.log_density_hessian!'>#</a>
**`BridgeStan.log_density_hessian!`** &mdash; *Function*.
Expand All @@ -396,7 +388,7 @@ This calculation drops constant terms that do not depend on the parameters if `p
The gradient is stored in the vector `out_grad` and the Hessian is stored in `out_hess` and references are returned. See `log_density_hessian` for a version which allocates fresh memory.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L598-L609' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L603-L614' class='documenter-source'>source</a><br>

<a id='BridgeStan.log_density_hessian_vector_product!' href='#BridgeStan.log_density_hessian_vector_product!'>#</a>
**`BridgeStan.log_density_hessian_vector_product!`** &mdash; *Function*.
Expand All @@ -414,7 +406,7 @@ This calculation drops constant terms that do not depend on the parameters if `p
The product is stored in the vector `out` and a reference is returned. See `log_density_hessian_vector_product` for a version which allocates fresh memory.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L686-L697' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L691-L702' class='documenter-source'>source</a><br>

<a id='BridgeStan.param_constrain!' href='#BridgeStan.param_constrain!'>#</a>
**`BridgeStan.param_constrain!`** &mdash; *Function*.
Expand All @@ -434,7 +426,7 @@ The result is stored in the vector `out`, and a reference is returned. See `para
This is the inverse of `param_unconstrain!`.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L282-L296' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L287-L301' class='documenter-source'>source</a><br>

<a id='BridgeStan.param_unconstrain!' href='#BridgeStan.param_unconstrain!'>#</a>
**`BridgeStan.param_unconstrain!`** &mdash; *Function*.
Expand All @@ -454,7 +446,7 @@ The result is stored in the vector `out`, and a reference is returned. See `para
This is the inverse of `param_constrain!`.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L383-L395' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L388-L400' class='documenter-source'>source</a><br>

<a id='BridgeStan.param_unconstrain_json!' href='#BridgeStan.param_unconstrain_json!'>#</a>
**`BridgeStan.param_unconstrain_json!`** &mdash; *Function*.
Expand All @@ -472,7 +464,7 @@ The JSON is expected to be in the [JSON Format for CmdStan](https://mc-stan.org/
The result is stored in the vector `out`, and a reference is returned. See `param_unconstrain_json` for a version which allocates fresh memory.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L440-L449' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L445-L454' class='documenter-source'>source</a><br>

<a id='BridgeStan.StanRNG' href='#BridgeStan.StanRNG'>#</a>
**`BridgeStan.StanRNG`** &mdash; *Type*.
Expand All @@ -490,7 +482,7 @@ This can be used in the `param_constrain` and `param_constrain!` methods when us
This object is not thread-safe, one should be created per thread.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L97-L106' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L102-L111' class='documenter-source'>source</a><br>

<a id='BridgeStan.new_rng' href='#BridgeStan.new_rng'>#</a>
**`BridgeStan.new_rng`** &mdash; *Function*.
Expand All @@ -508,7 +500,7 @@ This can be used in the `param_constrain` and `param_constrain!` methods when us
The StanRNG object created is not thread-safe, one should be created per thread.


<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L142-L152' class='documenter-source'>source</a><br>
<a target='_blank' href='https://github.com/roualdes/bridgestan/blob/main/julia/src/model.jl#L147-L157' class='documenter-source'>source</a><br>


<a id='Compilation-utilities'></a>
Expand Down
2 changes: 1 addition & 1 deletion julia/example.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ BS.set_bridgestan_path!("../")
bernoulli_stan = joinpath(@__DIR__, "../test_models/bernoulli/bernoulli.stan")
bernoulli_data = joinpath(@__DIR__, "../test_models/bernoulli/bernoulli.data.json")

smb = BS.StanModel(stan_file = bernoulli_stan, data = bernoulli_data);
smb = BS.StanModel(bernoulli_stan, bernoulli_data);

println("This model's name is $(BS.name(smb)).")
println("It has $(BS.param_num(smb)) parameters.")
Expand Down
13 changes: 10 additions & 3 deletions julia/src/BridgeStan.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,24 @@ include("compile.jl")
"""
StanModel(;stan_file, stanc_args=[], make_args=[], data="", seed=204)
Construct a StanModel instance from a `.stan` file, compiling if necessary.
Deprecated; use the normal constructor, StanModel(...), with a path to a `.stan` file, instead.
Construct a StanModel instance from a `.stan` file, compiling if necessary.
This is equivalent to calling `compile_model` and then the original constructor of StanModel.
"""
StanModel(;
function StanModel(;
stan_file::String,
stanc_args::AbstractVector{String} = String[],
make_args::AbstractVector{String} = String[],
data::String = "",
seed = 204,
) = StanModel(compile_model(stan_file; stanc_args, make_args), data, seed)
)
Base.depwarn(
"StanModel(;stan_file,... ) is deprecated. Use the normal constructor, StanModel(...) instead.",
:StanModel,
)
StanModel(stan_file, data, seed; stanc_args, make_args)
end


function __init__()
Expand Down
39 changes: 22 additions & 17 deletions julia/src/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,43 @@ mutable struct StanRNGStruct end
end

"""
StanModel(lib, datafile="", seed=204)
StanModel(lib, data="", seed=204; stanc_args=[], make_args=[])
A StanModel instance encapsulates a Stan model instantiated with data.
Construct a Stan model from the supplied library file path and data. Data
should either be a string containing a JSON string literal, a path to a data file ending in `.json`,
or the empty string.
If seed is supplied, it is used to initialize the RNG used by the model's constructor.
StanModel(;stan_file, data="", seed=204)
Construct a Stan model from the supplied library file path and data.
If lib is a path to a file ending in `.stan`, this will first compile
the model. Compilation occurs if no shared object file exists for the
supplied Stan file or if a shared object file exists and the Stan file
has changed since last compilation. This is equivalent to calling
`compile_model` and then the constructor of `StanModel`.
Construct a `StanModel` instance from a `.stan` file, compiling if necessary.
Data should either be a string containing a JSON string literal, a
path to a data file ending in `.json`, or the empty string.
StanModel(;stan_file, stanc_args=[], make_args=[], data="", seed=204)
Construct a `StanModel` instance from a `.stan` file. Compilation
occurs if no shared object file exists for the supplied Stan file or
if a shared object file exists and the Stan file has changed since
last compilation. This is equivalent to calling `compile_model` and
then the original constructor of `StanModel`.
If seed is supplied, it is used to initialize the RNG used by the model's constructor.
"""
mutable struct StanModel
lib::Ptr{Nothing}
stanmodel::Ptr{StanModelStruct}
@const data::String
@const seed::UInt32

function StanModel(lib::String, data::String = "", seed = 204)
function StanModel(
lib::String,
data::String = "",
seed = 204;
stanc_args::AbstractVector{String} = String[],
make_args::AbstractVector{String} = String[],
)
seed = convert(UInt32, seed)

if !isfile(lib)
throw(SystemError("Dynamic library file not found"))
throw(SystemError("File not found: $lib"))
end

if endswith(lib, ".stan")
lib = compile_model(lib; stanc_args, make_args)
end

if in(abspath(lib), Libc.Libdl.dllist())
Expand Down
Loading

0 comments on commit 7ca2952

Please sign in to comment.