Migration guide · Java-native Stan core

Run supported Stan source in a Java-native workflow

Keep ordinary blocks, modern arrays, vectors and matrices, general bounds, scalar functions, sampling statements, target increments, generated quantities, scalar math, and probability names while learning where JDistlib deliberately differs.

Source-compatible core · independent Java execution

Command line

Use --run for inference

Build the current checkout to use this new mode. The all-in-one JAR includes runtime dependencies; the core JAR needs its generated lib/ directory beside it. Earlier releases do not include the runner.

java -jar jdistlib-all.jar --run --input model.stan --data sizes.json --data observations.json --output output.txt

For the scalar/vector model below, sizes.json can contain {"N":3} and observations.json can contain {"y":[1.2,0.8,1.5]}. Repeat --data to merge different variables. Duplicate and unknown names are errors. Bind a headerless numeric CSV/TSV directly with --data y=values.csv, select a header column with --data-column y=table.csv:response, or supply scalars using --set N=3. Paths are relative to the working directory. Arrays flatten row-major; supply dimension variables explicitly.

--run --validate checks source and data without sampling. --run --help lists controls, including --warmup, --samples, --chains and --seed. Output is CSV text with comment-prefixed metadata and diagnostics, constrained parameter draws, and generated quantities. Script inference currently uses CPU NUTS and the documented language core. Transformed parameters are evaluated internally; export a desired value through a generated quantity.

Without --run, source generation retains its three positional arguments:

java -jar jdistlib-all.jar model.stan generated.Model Model.java

Mental model

Translate services, not just syntax

Stan or CmdStanJDistlibImportant difference
.stan programModelScript.compileStanThe documented source-compatible core lowers to JDistlib's Java runtime.
JSON/R dump input--run --data or Map<String,double[]>The runner loads finite numeric JSON and CSV/TSV; R dump needs a host adapter.
stancModelScript.compileIn-memory parsing/lowering returns a Java BayesianModel.
Compiled model executableModelScriptCliThree positional arguments emit a Java wrapper; explicit --run starts NUTS.
CmdStan sampleNoUTurnSampler and Chains.parallelOptions and warmup implementation are JDistlib APIs, not CmdStan flags.
Stan CSV drawsChainResult, ChainExportRaw chain states use unconstrained coordinates.
Stan diagnosticsMcmcDiagnostics, DiagnosticGraphsInspect the documented metrics rather than expecting byte-for-byte parity.
Generated quantitiesCompiledModelScript.generateCall it explicitly for each retained state that needs generated output.

Porting example

A scalar/vector model often needs only small edits

data {
  int<lower=1> N;
  vector[N] y;
}
parameters {
  real mu;
}
model {
  mu ~ normal(0, 10);
  for (n in 1:N)
    y[n] ~ normal(mu, 1);
}
generated quantities {
  real y_rep = normal_rng(mu, 1);
}

This model uses familiar one-based indexing, an integer-range loop, sampling statements, and generated quantities. Probability calls accept Stan's vertical-bar notation, for example normal_lpdf(y[n] | mu, 1). Gamma scripts use Stan's shape/rate parameterization even though the underlying JDistlib RNG API uses scale.

Host data

Replace a Stan data file with typed Java arrays

double[] y = McmcDataIngestionExamples.readNumericColumn(
    Paths.get("examples/data/normal-observations.csv"), "y");

Map<String, double[]> data =
    new LinkedHashMap<String, double[]>();
data.put("N", new double[] {y.length});
data.put("y", y);

Integers currently cross the uniform data boundary as exactly integral doubles. Compilation validates integer declarations, bounds, and declared vector lengths. The data is defensively copied. Database, Parquet, JSON, CSV, and application objects can all be used as upstream sources as long as the adapter produces the required arrays.

Compile and sample

Replace interface commands with Java calls

String source = new String(
    Files.readAllBytes(Paths.get("model.jdm")),
    StandardCharsets.UTF_8);
CompiledModelScript compiled = ModelScript.compile(source, data);
BayesianModel model = compiled.model();

SamplingOptions options = SamplingOptions.builder()
    .warmupIterations(1000)
    .sampleIterations(1000)
    .targetAcceptance(0.85)
    .build();

ChainResult[] chains = Chains.parallel(
    new NoUTurnSampler(), model, initialStates,
    options, 12345L, 4);

Initial states and retained ChainResult columns are unconstrained sampler coordinates. Recover named constrained values with model.state(draw).scalar(name) or vector(name). Always run Gradients.check for a new or translated model before trusting HMC/NUTS output.

Posterior review

Make convergence and geometry explicit

McmcDiagnosticReport report = McmcDiagnostics.analyze(
    parameterNames, chains);
ChartSpec trace = DiagnosticGraphs.trace("mu", 0, chains);
ChartSpec ranks = DiagnosticGraphs.ranks("mu", 0, 20, chains);
String html = InferenceHtmlReport.render(
    "Posterior review", report, model.graph(), trace, ranks);

Review rank-normalized split/folded R-hat, bulk/tail ESS, MCSE, divergences, tree-depth saturation, and E-BFMI together. JDistlib provides comparable concepts, but it does not claim exact Stan transition, warmup, or diagnostic parity.

Compatibility boundary

Separate source meaning from implementation identity

Available now

Core blocks, literals, arbitrary-rank arrays and slices, real/complex vectors and matrices, procedural tuples, typed matrix and CSR algebra, forward-declared/container/tuple-valued functions, Java external bindings, numerical higher-order callbacks and sensitivities, structured constraints, control flow, tested broadcasting, target increments, scalar math and distributions, generated quantities, and RNGs.

Explicit boundary

Top-level tuple data/parameters and tuple arrays, parallel reduce/map services, modern variadic solver signatures, adjoint/event solver services, complete truncation/CDF coverage, and specialized Stan Math functions not listed in the compatibility contract remain outside 0.8.3.

Compiled scripts execute on reusable thread-local reverse tapes with selected atomic kernels. JDistlib otherwise retains JVM math, caller-owned random streams, and its own sampler/warmup implementations. The same seed or model therefore does not imply identical draws, transition paths, divergences, or last-bit log densities. Read the complete source and execution contract. Unsupported operations fail instead of silently changing a parameterization or Jacobian.

Scientific sources

Compatibility targets methods, not binary identity

Next

Use the verified migration path

Start with the CSV and compilation tutorial, continue with containers/matrices, user functions, or solver migration, inspect the exact supported-language reference, browse forty-one checked Stan fixtures, and search the method citations.