Extend a model, task or analysis
An extension should make a new question possible without changing an existing result’s meaning. Begin with a model parameter or task option when that expresses the intended change. Add a new substrate only when its equations differ.
Choose the smallest implementation
| Intent | Current path |
|---|---|
| Change a supported model | NodeSpec.parameters |
| Change task timing or observations | TaskSpec.options |
| Change node count or input scale | CompositionSpec |
| Compare a mechanism | Named targets and declared interventions |
| Explore parameters | Development-only sweep |
| Add a diagnostic | Pure offline analysis over owned result data |
| Add a new model or task family | Reviewed package implementation and resolver changes |
There is no general third-party registry or arbitrary body assembly in this release. Earlier extension methods remain available at their source revision; see version history.
Read equations and tests together
uv sync --locked --group devuv run pytest python/tests/test_sorn.py python/tests/test_task_validation.pyUse these focused suites to understand construction, update ordering, pruning, reset and task schedule validation. A passing existing suite does not validate a new equation.
Scientific specifications remain immutable host values. Keep device buffers and memory admission in execution. Use explicit generators and stable entity/feature IDs. Preserve destination/source matrices and fixed ndarray ranks with runtime dimensions.
Try a configuration change first
from brainlesslab import ( CompositionSpec, EvaluationSpec, NodeSpec, TaskSpec, profile, resolve,)
plan = profile( CompositionSpec( NodeSpec("sorn", {"eta_stdp": 0.0}), TaskSpec("delayed_cue", {"delays": (128,)}), count=32, ), evaluation=EvaluationSpec(blocks=2, trials_per_block=2, root_seed=63),)print(resolve(plan).targets[0])Expect one resolved SORN target. This disables SORN’s STDP increment from construction while retaining intrinsic plasticity and enabled weight normalisation. It is not the same intervention as freezing weights after a period of adaptation. Check implemented meanings before using a parameter as a causal control.
Separate construction from stepping
An implemented model has an immutable configuration, a host-side construct function,
an owned InitialState and a ModelBatch with device arrays. Construction receives
an explicit NumPy generator; it must not consume an unrelated task stream.
A batch exposes step(inputs, noise, active), emitted activity, effectors and finite
flags. It supports reset, weight freeze, full-plasticity freeze and owned snapshots.
Use ordered destination-owned sums instead of floating-point atomics.
Keep task labels out of the online controller. A new task needs validated options, ports, timing, a prepared world and a native scoring rule. If it uses feedback, distinguish available observations from diagnostic truth retained for scoring.
Define the new contract before integrating it
For a model, state the old-state/new-state order, threshold equality rule, emitted activity, readout, adaptation, frozen modes and reset. Test small hand-calculated states with an independent NumPy reference. Include non-finite drives, empty connectivity, inactive slots, owned snapshots and batch independence.
For a task, state available observations, action cadence, response windows, ties, termination, native units and scoring opportunity. Validate initial schedules before device allocation. Keep labels and hidden task truth outside the online controller. Choose an appropriate reference policy without calling its observed score an upper bound.
For offline analysis, preserve the independent unit and prevent fit/validation leakage. For a backend change, qualify the arithmetic/device path separately from model equations.
Only after those checks should you profile runtime costs or propose an optimisation. Preserve a single equation source when introducing fused execution. Canonical ndarray access and explicit returned status values avoid stale reads across aliased helper views.
Build a reviewable extension
Run focused tests first, then the package and site gates. Execute examples referenced by the guide. A frozen dataclass alone does not own mutable array storage: check ownership and batch independence explicitly. Keep backend qualification separate from equation conformance, and retain compilation, transfer and recording costs when measuring performance.
The active package supports two model families and ten task families. A Python class
alone does not make a supported NodeSpec or TaskSpec kind; discovery and resolution
need a reviewed package change. Evolution, durable checkpoint/resume and autodiff
are not implemented.
Continue with interfaces, learning exercises and runtime performance.