Skip to content

Consume axis-wide coord_shift offset reactions in stochastic execution - #181

Merged
jc-macdonald merged 3 commits into
mainfrom
feat/180-coord-shift-offsets
Oct 2, 2026
Merged

jc-macdonald merged 3 commits into
mainfrom
feat/180-coord-shift-offsets

Conversation

@jc-macdonald

Copy link
Copy Markdown
Member

op_system #243 lets an aging chain be declared as one axis-wide coord_shift entry. Each such entry publishes one templated reaction per state template, and the shifted axis appears in a new offsets field as (axis, step) rather than in to_axes or pinned. The network compiler rejected these reactions with "inconsistent sum_axes metadata", so the numerical-engine acceptance test from ACCIDDA/op_system#238 could not run.

The compiler now validates offsets and expands each source bin into a channel that deposits at k + step. When k + step falls off the axis, the column only removes the donor (boundary: absorb). Under boundary: stay, the producer already gives those bins zero propensity. Artifacts without offsets, including those from producers that predate it, compile unchanged.

The development op_system pins advance to the #243 merge. Published dependency requirements are unchanged.

Closes #180.

Behavior

  • offsets must shift channel axes (from_axes) by a nonzero step, and those axes must not also appear in to_axes or pinned. Destination coverage is now to_axes ∪ pinned ∪ offset axes == full_axes, and sum_axes == from_axes − to_axes − offset axes. Malformed offsets fail with a ValueError.
  • A donor-only column is new for the core solvers, but it uses the same stoichiometric path as other columns. The ensemble and prescribed-event tests exercise it through direct SSA.

Coverage

  • Stoichiometry, reactant columns, and propensities for absorb and stay, forward and backward steps, with no group axis and with a retained group axis in both state-axis orders.
  • Reaction drift equals the producer RHS for steps +1, +2, and −1 under NumPy and JAX.
  • Artifacts without offsets produce the same network as before. Zero steps, overlapping copied axes, duplicate offsets, and inconsistent sum_axes all fail.
  • Prescribed direct-SSA events move one unit through each bin with the producer's per-bin rates, then remove it at the absorbing boundary, under NumPy and JAX.
  • Erlang acceptance test from op_system #238. 1,024 seeded direct-SSA replicates (64 groups × 16 seeds) start with 5 individuals in the first of 4 bins, with equal rate 2. At four observation times:
    • Bin occupancy matches the analytic Poisson probabilities.
    • Under absorb, the count that has left matches the Erlang(4, 2) distribution function.
    • Under stay, every path conserves its total, and the last bin holds the Erlang(3, 2) probability.
    • Tolerances are five binomial standard errors.
  • Mutation check. I temporarily clamped off-axis firings into the edge bin instead of removing them. The absorbing ensemble, prescribed-event, and stoichiometry tests all failed. The correct code was then restored.

Docs

  • Provider README: new section Axis-wide aging chains with a runnable direct-SSA example, the offset channel contract, and the Poisson/Erlang expectations. The Stochastic reaction networks overview now mentions offset-axis bookkeeping.
  • CHANGELOG entry under Unreleased.

Validation

  • just ci: 592 core tests passed, 2 skipped. 352 provider tests passed (34 new). Formatting, Ruff, and strict mypy passed for both packages.
  • just docs: strict documentation build passed.
  • UV_PYTHON_VERSION=3.13 just build-all: both wheels passed strict metadata checks. The clean core suite passed (579 passed, 2 skipped), and the provider suite passed against installed wheels with op_system from the #243 pin.
  • The new README example was executed directly.

As with the renewal tests from #179, the new tests require the pinned producer; published op_system 0.5.0 predates axis-wide coord_shift.

Three focused commits: 319, 141, and 70 changed lines (530 total).

🤖 Generated with Claude Code

jc-macdonald and others added 3 commits October 2, 2026 17:03
op_system #243 publishes one templated reaction per state for an
axis-wide coord_shift, with the shifted axis in a new offsets field
rather than in to_axes or pinned. The network compiler rejected these
as having inconsistent sum_axes metadata.

Validate offsets as nonzero shifts of channel axes that no other
destination field covers, and require to_axes, pinned, and offsets
together to cover the destination. Each source bin's channel deposits at
the shifted coordinate; an off-axis destination yields a donor-only
column. Artifacts without offsets compile unchanged.

Advance the development op_system pins to the #243 merge. Published
dependency requirements are unchanged.

Refs #180

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Prescribed direct-SSA events move one unit through every bin and remove
it at the absorbing boundary, under NumPy and JAX. Over 1,024 seeded
replicates, equal-rate pure aging matches the analytic Poisson bin
occupancy, and the exited count matches the Erlang(n, r) distribution
function, within five standard errors. A stay boundary conserves every
path, and its last bin accumulates the Erlang(n - 1, r) probability.

Refs #180

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add a runnable provider example for one-entry aging chains, describe the
offset channel contract and absorbing or stay boundaries, state the
Poisson occupancy and Erlang exit-time expectations, and record the
change.

Closes #180

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jc-macdonald
jc-macdonald merged commit 37afcb6 into main Oct 2, 2026
6 checks passed
@jc-macdonald
jc-macdonald deleted the feat/180-coord-shift-offsets branch October 2, 2026 21:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consume axis-wide coord_shift offset reactions in stochastic execution

1 participant