Packages

A lightweight Elixir interface to CmdStan, the command line interface to the Stan probabilistic programming language.

Current section

Files

Jump to
cmdstanex lib cmdstan.ex
Raw

lib/cmdstan.ex

defmodule CmdStan do
@moduledoc """
Elixir interface to CmdStan.
This library provides functionality to download, install, and manage
CmdStan releases from GitHub, similar to the Python CmdStanPy library.
"""
alias CmdStan.{Installer, Model, Summary}
@doc """
Install CmdStan from GitHub releases.
Downloads and installs a CmdStan release, builds it, and tests the compilation.
## Options
* `:version` - CmdStan version string (e.g., "2.32.2"). Defaults to latest.
* `:dir` - Installation directory. Defaults to `~/.cmdstan`.
* `:overwrite` - Boolean, whether to overwrite existing installation. Defaults to false.
* `:progress` - Boolean, whether to show progress bars. Defaults to false.
* `:verbose` - Boolean, whether to show verbose output. Defaults to false.
* `:cores` - Number of CPU cores to use for building. Defaults to number of schedulers.
* `:interactive` - Boolean, whether to run in interactive mode. Defaults to false.
## Examples
iex> CmdStan.install_cmdstan(version: "2.32.2")
:ok
iex> CmdStan.install_cmdstan(dir: "/opt/cmdstan", progress: true)
:ok
"""
@spec install_cmdstan(keyword()) :: :ok | {:error, term()}
def install_cmdstan(opts \\ []) do
Installer.install_cmdstan(opts)
end
@doc """
Compile a Stan model file to an executable.
## Parameters
- `stan_file`: Path to the Stan model file (.stan)
## Returns
A map containing model information or an error tuple.
## Examples
iex> CmdStan.compile_model("model.stan")
{:ok, %{name: "model", stan_file: "model.stan", exe_file: "model"}}
"""
@spec compile_model(String.t()) :: {:ok, map()} | {:error, term()}
def compile_model(stan_file) do
Model.compile(stan_file)
end
@doc """
Run gradient diagnostics on a compiled model.
Compares automatic differentiation gradients with finite difference gradients
to validate model implementation.
## Parameters
- `model`: Model map returned by `compile_model/1`
- `opts`: Diagnostic options
- `:data` - Data map in Stan format (required)
- `:inits` - Initial parameter values
- `:epsilon` - Step size for finite difference gradients (default: 1e-6)
- `:error` - Absolute error threshold (default: 1e-6)
- `:sig_figs` - Numerical precision for output
- `:require_gradients_ok` - Whether to raise error if gradients exceed threshold
## Returns
A result map containing diagnostics and metadata.
## Examples
iex> model = %{exe_file: "bernoulli"}
iex> data = %{"N" => 10, "y" => [0,1,0,0,0,0,0,0,0,1]}
iex> CmdStan.diagnose(model, data: data)
{:ok, %{diagnostics: [%{param_idx: 0, value: 0.5, model: -0.123, finite_diff: -0.124, error: 0.001}], metadata: %{...}}}
"""
@spec diagnose(map(), keyword()) :: {:ok, map()} | {:error, term()}
def diagnose(model, opts \\ []) do
Model.diagnose(model, opts)
end
@doc """
Run MCMC sampling on a compiled model.
## Parameters
- `model`: Model map returned by `compile_model/1`
- `data`: Data map in Stan format
- `opts`: Sampling options (chains, iterations, etc.)
## Returns
A result map containing draws, metadata, and diagnostics.
## Examples
iex> model = %{exe_file: "bernoulli"}
iex> data = %{"N" => 10, "y" => [0,1,0,0,0,0,0,0,0,1]}
iex> CmdStan.sample(model, data, chains: 1, iter: 100)
{:ok, %{draws: %{"theta" => [0.2, 0.3, ...]}, metadata: %{...}, diagnostics: %{...}}}
"""
@spec sample(map(), map(), keyword()) :: {:ok, map()} | {:error, term()}
def sample(model, data, opts \\ []) do
Model.sample(model, data, opts)
end
@doc """
Run MCMC diagnostics on sampling results.
Checks for sampling issues like divergent transitions, low E-BFMI values,
low effective sample sizes, and high R-hat values.
## Parameters
- `fit`: Fit result from `sample/3`
## Returns
A string containing the diagnostic output.
## Examples
iex> fit = CmdStan.sample(model, data, chains: 4, iter: 1000)
iex> CmdStan.diagnose_fit(fit)
"Checking sampler transitions treedepth.\\nTreedepth satisfactory for all transitions.\\n...\\n"
"""
@spec diagnose_fit(map()) :: {:ok, String.t()} | {:error, term()}
def diagnose_fit(fit) do
Model.diagnose_fit(fit)
end
@doc """
Compute summary statistics for MCMC fit results.
## Parameters
- `fit`: Fit result from `sample/3`
- `opts`: Summary options (percentiles, significant figures)
## Returns
A list of maps containing summary statistics for each variable.
## Examples
iex> fit = CmdStan.sample(model, data, chains: 4, iter: 1000)
iex> {:ok, summary} = CmdStan.summary(fit)
iex> Enum.find(summary, &(&1.variable == "theta"))
"""
@spec summary(map(), keyword()) :: {:ok, [map()]} | {:error, term()}
def summary(fit, opts \\ []) do
Summary.summary(fit, opts)
end
end