Parameter declarations¶
An optional parameters block records scientific annotations for parameters
already inferred from the RHS. It does not introduce symbols, supply values,
enforce runtime bounds, select an inference library or change the equations.
Specs without this block keep their existing behavior.
kind: expr
state: [x]
equations:
x: "offset - rate*x"
parameters:
rate:
support: positive
units: "day^-1"
description: "Loss rate"
fixed: false
offset:
support: {kind: bounded, lower: 0, upper: 10}
units: "amount/day"
fixed: true
Each entry is optional, as is each field within an entry. An omitted support
stays unknown; it is not inferred as real. Undeclared RHS parameters remain
valid. Unknown declaration fields and names that are not inferred runtime
parameters are errors. Values and priors belong in the caller or statistical
layer, outside this block.
| Field | Meaning |
|---|---|
support |
real, strict positive (x > 0), closed unit_interval (0 <= x <= 1), or a bounded mapping |
support.kind: bounded |
Requires finite numeric lower < upper; both endpoints are included |
units |
Nonempty text annotation; no dimensional-analysis proof is implied |
description |
Nonempty human-readable text |
fixed |
Boolean inference annotation, default false; it neither binds a value nor removes a runtime argument |
The same block is supported for expression and transition specs. Declare a
shaped or time-varying buffer by its base name, such as rate, rather than
rate[unit] or a coordinate-expanded cell name. Alias-only parameter
dependencies are included. States, axes and compiler-synthesized masks are
not parameters that this block can declare. Operator-only coefficients and
initial-state-only inputs are outside this RHS declaration interface.
Compilation exposes a detached read-only mapping, CompiledRhs.param_meta,
whose values are immutable ParameterDeclaration records. Their optional
support values are ParameterSupport records. Both types are exported by
op_system and op_system.specs. Metadata survives compiled-object pickle
round trips by recompiling its normalized source.
import numpy as np
from op_system import compile_spec
compiled = compile_spec({
"kind": "expr",
"state": ["x"],
"equations": {"x": "-rate*x"},
"parameters": {"rate": {"support": "positive", "fixed": True}},
})
assert compiled.param_meta["rate"].fixed
support = compiled.param_meta["rate"].support
assert support is not None and support.kind == "positive"
np.testing.assert_allclose(compiled.eval_fn(0.0, np.array([3.0]), rate=0.5), [-1.5])
Downstream tools decide how to use these declarations, including support validation, fixed-value binding, prior selection and coordinate transforms. For example, a logit transform covers the interior of a closed unit interval; endpoint atoms require their own statistical treatment. Array namespace, dtype and differentiation behavior remain properties of the numerical evaluation, independent of these static annotations.
Named latent observables can infer additional scalar or
shaped parameters and annotate them in this same parameters block. Those names
appear in param_meta and in each observable's parameter_shapes, while the
existing RHS binding requirements and param_names remain unchanged.