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

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 inputMap<String,double[]>The host application owns file parsing and missing-data policy.
stancModelScript.compileIn-memory parsing/lowering returns a Java BayesianModel.
Compiled model executableModelCompilationCache or ModelScriptCliThe CLI emits a Java wrapper; it is not a sampler executable.
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.

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, and browse forty-one checked Stan fixtures.