Finite discrete inference
DISCRETEPOSTERIOR(model, evidence, queries) updates a small finite model from observations. It returns posterior marginal tables, evidence probability and the complete request needed to…
Finite discrete inference
DISCRETE_POSTERIOR(model, evidence, queries) updates a small finite model from
observations. It returns posterior marginal tables, evidence probability and the
complete request needed to reproduce the answer. Computation is a pure reactive
operation in the existing Rust LIR runtime; defining or reading a model value
creates no worker, job or external effect.
Use a named ordinary record for the reusable model and a separate call for each query. The complete example is fault diagnosis.
fault_model = {
schemaVersion: 1,
id: "machine",
variables: [
{id: "fault", states: ["healthy", "faulty"]},
{id: "alarm", states: ["quiet", "sounding"]}
],
factors: [
{id: "prior", scope: ["fault"], weights: [0.9, 0.1]},
{id: "sensor", scope: ["fault", "alarm"], weights: [0.8, 0.2, 0.2, 0.8]}
]
}
posterior = DISCRETE_POSTERIOR(fault_model, {alarm: "sounding"}, ["fault"])
marginals = posterior.marginals
The evidence probability is 0.26, and the posterior probability of faulty is
4/13 (approximately 0.307692). Observing quiet instead gives 1/37.
Changing the prior weights to [0.8, 0.2] with a sounding alarm gives 0.5.
Ordinary input dependencies recompute these results when assumptions change.
Model and query contract
schemaVersionmust be 1;ididentifies the authored model. Every variable, factor and state label contains 1–256 UTF-8 bytes. Identities are case-sensitive.variablesgives ordered variable IDs and nonempty ordered state labels. Variable IDs and each variable's states must be unique.- The nonempty
factorslist gives unique IDs, an orderedscopeof variable IDs and flat nonnegative finiteweights. Each scope variable occurs once. Its last variable varies fastest. The number of weights equals the product of its domain sizes. An empty scope is a scalar factor with one weight. - Weights are general potentials. The joint distribution is their product, normalized over all assignments. Unmentioned variables have uniform weight. Conditional tables in the example follow the same rule; there is no implicit conditional-row normalization or separate CPT syntax.
evidenceis a record mapping observed variable IDs to declared state labels. An empty record means no observations. No soft evidence or automatic state coercion is performed.queriesis a nonempty list of distinct variable IDs. Each requested marginal retains its variable's state order. This profile returns single-variable marginals, not an arbitrary joint output table.
Unknown fields, variables/states, duplicate identities, wrong table shapes, negative/nonfinite weights and all-zero models are invalid. Shared factors can represent dependent variables; independence is not inferred from different names.
Reports, errors and persistence
A report contains schemaVersion, status, request, assignmentsEvaluated,
evidenceProbability, logEvidenceProbability and marginals. Each marginal
contains variable, states and probabilities. request retains the complete
model, evidence and queries: the caller's model ID alone is never treated as
proof that weights or observations are unchanged.
complete means the admitted state space was exhaustively evaluated using
binary64 arithmetic. It does not mean exact rational arithmetic. Log-domain
accumulation avoids multiplying tiny weights into a false zero. A positive
evidence probability can underflow in evidenceProbability; its finite
logEvidenceProbability and complete status distinguish this from impossibility.
impossibleEvidence means a valid model assigns exactly zero weight to the
observations. Its probability is zero, log probability is null and marginals are
empty. An invalid model produces a VALUE error containing DISCRETE_INVALID;
an exceeded admission limit produces DISCRETE_LIMIT. The controlled Rust owner
supports cancellation during admission and enumeration and returns the caller's
error, never a partial posterior. This synchronous source function introduces no
separate cancellation job or progress service.
Models, query expressions and source input edits use the existing source and LIR persistence. Saved LIR works without debug data. Runtime input overrides follow the normal model-input persistence contract; serializing the original LIR alone does not write transient overrides into its source. Retained reports include the actual request and can be reproduced through the same native inference owner. Structure or weights are admitted anew at query ingress after edits; this first profile does not retain a hidden incremental inference cache.
Bounds and execution ownership
The profile admits at most 32 variables, 64 states per variable, 256 factors, 65,536 joint assignments, 262,144 total factor entries, and 32 queried marginals. Checked admission also bounds work to 16,777,216 units: joint assignments times (variable count + query count + sum of factor scope lengths plus one per factor). Output is bounded by 2,048 marginal probabilities plus the bounded request. There is no automatic approximate fallback when a limit is exceeded.
The portable advanced-inference envelope uses kind: "discrete" with the same
{model, evidence, queries} request. Its existing import/run/emit operations
carry distinct problem kind 5 and the version-1 model schema; existing
normal-linear, HMC, variational, particle-filter and Bayesian-optimization kinds
retain their wire identities. Unknown kinds/schemas fail closed. Both source
calls and this envelope execute the same solver-owned implementation.
This profile supplies observational conditioning, not causal identification, interventions or counterfactuals. Continuous models, plates, approximate discrete inference, Stan/BUGS import and automatic fault-tree conversion remain outside its scope. Existing CAUSAL, uncertainty propagation and reliability analysis continue to serve their respective contracts.
Frozen extension catalogs remain unchanged. Native source and the advanced LIR envelope support this operation; it is not automatically exposed to extension guests through an existing frozen function API.