Rust Interface#
Installation#
The BridgeStan Rust client is available on crates.io and via cargo
:
cargo add bridgestan
A copy of the BridgeStan C++ sources is needed to compile models. This can be downloaded to
~/.bridgestan/
automatically if you use the download-bridgestan-src
feature.
Otherwise, it can be downloaded manually (see Getting Started).
Note that the system pre-requisites from the Getting Started guide are still required and will not be automatically installed by this method.
Example Program#
An example program is provided alongside the Rust crate in examples/example.rs
:
Show example.rs
use bridgestan::{compile_model, open_library, BridgeStanError, Model};
use std::ffi::CString;
use std::path::{Path, PathBuf};
fn main() {
// Set up logging - optional
if std::env::var("RUST_LOG").is_err() {
std::env::set_var("RUST_LOG", "bridgestan=info");
}
env_logger::init();
// The path to the Stan model
let path = Path::new(env!["CARGO_MANIFEST_DIR"])
.parent()
.unwrap()
.join("test_models")
.join("simple")
.join("simple.stan");
// You can manually set the BridgeStan src path or
// automatically download it (but remember to
// enable the download-bridgestan-src feature first)
let bs_path: PathBuf = "..".into();
// let bs_path = bridgestan::download_bridgestan_src().unwrap();
// The path to the compiled model
let path = compile_model(&bs_path, &path, &[], &[]).expect("Could not compile Stan model.");
println!("Compiled model: {:?}", path);
let lib = open_library(path).expect("Could not load compiled Stan model.");
// The dataset as json
let data = r#"{"N": 7}"#;
let data = CString::new(data.to_string().into_bytes()).unwrap();
// The seed is used in case the model contains a transformed data section
// that uses rng functions.
let seed = 42;
let model = match Model::new(&lib, Some(data), seed) {
Ok(model) => model,
Err(BridgeStanError::ConstructFailed(msg)) => {
panic!("Model initialization failed. Error message from Stan was {msg}")
}
Err(e) => {
panic!("Unexpected error:\n{e}")
}
};
let n_dim = model.param_unc_num();
assert_eq!(n_dim, 7);
let point = vec![1f64; n_dim];
let mut gradient_out = vec![0f64; n_dim];
let logp = model
.log_density_gradient(&point[..], true, true, &mut gradient_out[..])
.expect("Stan failed to evaluate the logp function.");
println!("logp: {}\ngrad: {:?}", logp, gradient_out);
}
API Reference#
This is also available on docs.rs
- crate bridgestan#
Variables
- const VERSION: &str#
Functions
- fn compile_model(bs_path: &Path, stan_file: &Path, stanc_args: &[&str], make_args: &[&str]) -> Result<PathBuf>#
Compile a Stan Model. Requires a path to the BridgeStan sources (can be downloaded with
download_bridgestan_src
if that feature is enabled), a path to the.stan
file, and additional arguments for the Stan compiler and themake
command.
- fn download_bridgestan_src() -> Result<PathBuf>#
Download and unzip the BridgeStan source distribution for this version to
~/.bridgestan/bridgestan-$VERSION
. Requires featuredownload-bridgestan-src
.
- fn open_library<P: AsRef<OsStr>>(path: P) -> Result<StanLibrary>#
Open a compiled Stan library.
The library should have been compiled with BridgeStan, with the same version as the Rust library.
Enums
- enum BridgeStanError#
Error type for bridgestan interface
- InvalidLibrary(LoadingError)#
The provided library could not be loaded.
- BadLibraryVersion(String, String)#
The version of the Stan library does not match the version of the rust crate.
- StanThreads(String)#
The Stan library could not be loaded because it was compiled without threading support.
- InvalidString(Utf8Error)#
Stan returned a string that couldn’t be decoded using UTF8.
- ConstructFailed(String)#
The model could not be instantiated, possibly because if incorrect data.
- EvaluationFailed(String)#
Stan returned an error while computing the density.
- SetCallbackFailed(String)#
Setting a print-callback failed.
- ModelCompilingFailed(String)#
Compilation of the Stan model shared object failed.
- DownloadFailed(String)#
Downloading BridgeStan’s C++ source code from GitHub failed.
Structs and Unions
- struct Model<T: Borrow<StanLibrary>>#
A Stan model instance with data
Implementations
- impl<T: Borrow<StanLibrary>> Model<T>#
Functions
- fn info(&self) -> &CStr#
Return information about the compiled model
- fn log_density(&self, theta_unc: &[f64], propto: bool, jacobian: bool) -> Result<f64>#
Compute the log of the prior times likelihood density
Drop jacobian determinant terms of the transformation from unconstrained to the constrained space if
jacobian == false
and drop terms of the density that do not depend on the parameters ifpropto == true
.
- fn log_density_gradient(&self, theta_unc: &[f64], propto: bool, jacobian: bool, grad: &mut [f64]) -> Result<f64>#
Compute the log of the prior times likelihood density and its gradient
Drop jacobian determinant terms of the transformation from unconstrained to the constrained space if
jacobian == false
and drop terms of the density that do not depend on the parameters ifpropto == true
.The gradient of the log density will be stored in
grad
.Panics if the provided buffer has incorrect shape. The gradient buffer
grad
must have lengthself.param_unc_num()
.
- fn log_density_hessian(&self, theta_unc: &[f64], propto: bool, jacobian: bool, grad: &mut [f64], hessian: &mut [f64]) -> Result<f64>#
Compute the log of the prior times likelihood density and its gradient and hessian.
Drop jacobian determinant terms of the transformation from unconstrained to the constrained space if
jacobian == false
and drop terms of the density that do not depend on the parameters ifpropto == true
.The gradient of the log density will be stored in
grad
, the hessian is stored inhessian
.Panics if the provided buffers have incorrect shapes. The gradient buffer
grad
must have lengthself.param_unc_num()
and thehessian
buffer must have lengthself.param_unc_num()
*
self.param_unc_num()
.
- fn log_density_hessian_vector_product(&self, theta_unc: &[f64], v: &[f64], propto: bool, jacobian: bool, hvp: &mut [f64]) -> Result<f64>#
Compute the log of the prior times likelihood density the product of the Hessian and specified vector.
Drop jacobian determinant terms of the transformation from unconstrained to the constrained space if
jacobian == false
and drop terms of the density that do not depend on the parameters ifpropto == true
.The product of the Hessian of the log density and the provided vector will be stored in
hvp
.Panics if the provided buffer has incorrect shape. The buffer
hvp
must have lengthself.param_unc_num()
.
- fn name(&self) -> Result<&str>#
Return the name of the model or error if UTF decode fails
- fn new<D: AsRef<CStr>>(lib: T, data: Option<D>, seed: u32) -> Result<Self>#
Create a new instance of the compiled Stan model.
Data is specified as a JSON file at the given path, a JSON string literal, or empty for no data. The seed is used if the model has RNG functions in the
transformed data
section.
- fn new_rng(&self, seed: u32) -> Result<Rng<&StanLibrary>>#
Create a new
Rng
random number generator from the library underlying this model.This can be used in
param_constrain()
when values from thegenerated quantities
block are desired.This instance can only be used with models from the same Stan library. Invalid usage will otherwise result in a panic.
- fn param_constrain<R: Borrow<StanLibrary>>(&self, theta_unc: &[f64], include_tp: bool, include_gq: bool, out: &mut [f64], rng: Option<&mut Rng<R>>) -> Result<()>#
Map a point in unconstrained parameter space to the constrained space.
theta_unc
must contain the point in the unconstrained parameter space.If
include_tp
is set the output will also include the transformed parameters of the Stan model after the parameters. Ifinclude_gq
is set, we also include the generated quantities at the very end.Panics if the provided buffer has incorrect shape. The length of the
out
buffer must beself.param_num(include_tp, include_gq)
.Panics if
include_gq
is set but no random number generator is provided.
- fn param_names(&self, include_tp: bool, include_gq: bool) -> &str#
Return a comma-separated sequence of indexed parameter names, including the transformed parameters and/or generated quantities as specified.
The parameters are returned in the order they are declared. Multivariate parameters are return in column-major (more generally last-index major) order. Parameter indices are separated with periods (
.
). For example,a[3]
is writtena.3
andb[2, 3]
asb.2.3
. The numbering follows Stan and is indexed from 1.If
include_tp
is set the names will also include the transformed parameters of the Stan model after the parameters. Ifinclude_gq
is set, we also include the names of the generated quantities at the very end.
- fn param_num(&self, include_tp: bool, include_gq: bool) -> usize#
Number of parameters in the model on the constrained scale.
Will also count transformed parameters (
include_tp
) and generated quantities (include_gq
) if requested.
- fn param_unc_names(&mut self) -> &str#
Return a comma-separated sequence of unconstrained parameters. Only parameters are unconstrained, so there are no unconstrained transformed parameters or generated quantities.
The parameters are returned in the order they are declared. Multivariate parameters are return in column-major (more generally last-index major) order. Parameter indices are separated with periods (
.
). For example,a[3]
is writtena.3
andb[2, 3]
asb.2.3
. The numbering follows Stan and is indexed from 1.
- fn param_unc_num(&self) -> usize#
Return the number of parameters on the unconstrained scale.
In particular, this is the size of the slice required by the
log_density
functions.
- fn param_unconstrain(&self, theta: &[f64], theta_unc: &mut [f64]) -> Result<()>#
Map a point in constrained parameter space to the unconstrained space.
- fn param_unconstrain_json<S: AsRef<CStr>>(&self, json: S, theta_unc: &mut [f64]) -> Result<()>#
Map a constrained point in json format to the unconstrained space.
The JSON is expected to be in the JSON Format for CmdStan. A value for each parameter in the Stan program should be provided, with dimensions and size corresponding to the Stan program declarations.
- fn ref_library(&self) -> &StanLibrary#
Return a reference to the underlying Stan library
- impl<T: Borrow<StanLibrary> + Clone> Model<T>#
Functions
- fn clone_library_ref(&self) -> T#
Return a clone of the underlying Stan library
Traits implemented
- unsafe impl<T: Sync + Borrow<StanLibrary>> Sync for Model<T>#
- unsafe impl<T: Send + Borrow<StanLibrary>> Send for Model<T>#
- impl<T: Borrow<StanLibrary>> Drop for Model<T>#
- struct Rng<T: Borrow<StanLibrary>>#
A random number generator for Stan models. This is only used in the
Model::param_constrain()
method of the model when requesting values from thegenerated quantities
block. Different threads should use different instances.Implementations
- impl<T: Borrow<StanLibrary>> Rng<T>#
Functions
- fn new(lib: T, seed: u32) -> Result<Self>#
Traits implemented
- unsafe impl<T: Sync + Borrow<StanLibrary>> Sync for Rng<T>#
- unsafe impl<T: Send + Borrow<StanLibrary>> Send for Rng<T>#
- impl<T: Borrow<StanLibrary>> Drop for Rng<T>#
- struct StanLibrary#
A loaded shared library for a Stan model
Implementations
- impl StanLibrary#
Functions
- unsafe fn set_print_callback(&mut self, callback: StanPrintCallback) -> Result<()>#
Provide a callback function to be called when Stan prints a message
Safety
The provided function must never panic.
Since the call is protected by a mutex internally, it does not need to be thread safe.
- unsafe fn unload_library(mut self)#
Unload the Stan library.
Safety
There seem to be issues around unloading libraries in threaded code that are not fully understood: roualdes/bridgestan#111
Traits implemented
- unsafe impl Send for StanLibrary#
- unsafe impl Sync for StanLibrary#
- impl Drop for StanLibrary#