Skip to content

fix(observables): apply a Molecules count filter only where BNG2 does - #64

Merged
akutuva21 merged 1 commit into
mainfrom
fix/observable-filters
Oct 1, 2026
Merged

akutuva21 merged 1 commit into
mainfrom
fix/observable-filters

Conversation

@akutuva21

Copy link
Copy Markdown
Member

Second commit of #59, cherry-picked alone so it merges cleanly against eight lanes in OdeIntegrator.cpp.

The defect

A species count filter was comparing the number of matched embeddings against the molecule count, so A()>5 on a species with A()=10 returned 0.

The fix — and why it is a rule change, not a number change

BNG2 2.9.3 honours a quantifier only in the Species branch (Perl2/Observable.pm:278-292), not in the Molecules branch (:241-256), where it lowers the filter away entirely — its .net groups carry no threshold. So:

observable before after BNG2
A() (A=10) 10 10 10
A()>0 10 10 10
A()>5 0 10 10
A()>9 0 10 10
A()>10 0 10 10
B()>2 (B=3) 0 3 3

The threshold is ignored in the Molecules branch because that is what the oracle does. That is the honest framing: a user writing A()>5 today gets the molecule count with the quantifier silently dropped, and after this change they still get the molecule count — matching BNG2 — rather than a count filtered by an unsupported criterion.

Verification

ctest -j4 and python -m pytest tests/python green on the rebased tree, with UNDER TEST paths asserted inside a pytest session against this worktree. Failing-first demonstrated by reverting the source in place (no git stash).

Merge hazard

cpp/engine/OdeIntegrator.cpp carries eight declared lanes. Review against the function list rather than git status, and the verification token for this change is the branch-point symbol with its expected count measured on this branch.

correctness verified this independently: A_gt5, A_gt9, A_gt10, B_gt2, B_gt3 all now return the molecule count, and the landing matches BNG2 on the cases that are easy to get wrong, not just the one originally flagged.

A stoichiometric comparison on a Molecules observable was applied to
the per-species EMBEDDING count, not a molecule count. On one species
A() holding 10 molecules, `A()>5` compared 1 > 5, failed, and the
observable contributed 0 -- so A()>5, A()>9, A()>10 and A()>99 all read
0 where the model plainly has 10 molecules of A.

BNG2 2.9.3 is the oracle and it is unambiguous: Perl2/Observable.pm
tests $patt->Quantifier only inside the `Type eq "Species"` branch
(lines 278-292), while the Molecules branch (lines 241-256) accumulates
raw match counts and never inspects it. So in BNG2 `Molecules Q A()>5`
and `Molecules Q A()` are the same observable and the threshold is inert
rather than an error.

The fix gates the filter on the observable type, matching that. Measured
against BNG2 on the same model (A()=10, B()=3), all six columns now
agree exactly; before, BNG3 returned 0 for four of them. The Species
path is untouched and already agreed with BNG2.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@akutuva21
akutuva21 merged commit 9d45825 into main Oct 1, 2026
4 of 30 checks passed
@akutuva21
akutuva21 deleted the fix/observable-filters branch October 4, 2026 02:32
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.

1 participant