Model structure¶
An optional, static declaration of a model's factorisation — factors, Markov-blanket roles, and observation channels — that you can inspect and validate() against the matrices. Declared but not yet exploited by the engine (ADR-010): the data and inspection surface is stable; validate() is experimental.
ModelStructure
dataclass
¶
A static, hashable declaration of a model's factor / blanket / channel structure.
Three index groupings over a model with state dimension n and observation
dimension m:
factors-- name -> state indices: which indices form which cause/block.roles-- role -> state indices: the Markov-blanket typing of the state. The intended (epistemic, not metaphysical — RFC-003 section 7) vocabulary is"external"/"internal"/"active"; names are free-form labels, only partition-checked in v0.3 (the blanket independence test is v0.4).channels-- name -> observation-row indices: the sensory typing of outputs.
Construct with the tuple form directly, or :meth:from_dicts for the dict form.
Every field normalises to (("name", (idx, ...)), ...) so the whole object is
hashable — it must be, it rides in the model's pytree aux_data. There is no
construction-time _validate: every real check needs the model, so it lives in
the opt-in :meth:validate.
Source code in src/cpomdp/structure.py
factor_names
property
¶
The declared factor names, in declaration order.
from_dicts
classmethod
¶
from_dicts(
*,
factors: Mapping[str, Sequence[int]] | None = None,
roles: Mapping[str, Sequence[int]] | None = None,
channels: Mapping[str, Sequence[int]] | None = None,
) -> ModelStructure
Build from the natural dict form, e.g. factors={"pos": [0, 1]}.
Source code in src/cpomdp/structure.py
factor ¶
channel ¶
role_of ¶
The role typing state index, or None if no role contains it.
summary ¶
A readable multi-line dump of the declared structure (does not print).
Source code in src/cpomdp/structure.py
validate ¶
Raise if this declaration contradicts model (opt-in; EXPERIMENTAL).
Partition well-formedness (pure index arithmetic, a stable contract): declared
factors and roles each partition the n-state space — every index in
[0, n), pairwise disjoint, covering all of it; channels index valid,
distinct observation rows in [0, m) but need not cover them. The
full-coverage requirement for factors/roles is a strict but reversible choice
(ADR-010), to relax if it proves a faff.
Conditional independence (EXPERIMENTAL): factors declared independent must have
≈0 cross-blocks in the dynamics A (and the fixed process noise Q) to
atol, and a sensory channel must read within a single factor. A
state-dependent Q(x) has no single matrix to check, so it is skipped. This
criterion checks one-step blocks now and tightens to the rigorous
precision-based (Σ⁻¹ block-diagonal) test in v0.4.
Not run at construction to remain lean; opt in via
model.structure.validate(model).