Repository navigation
Refuse Arrhenius rules the load-time expansion cannot price exactly (#109) - #116
Merged
Merged
Conversation
…109) expand_binding reduces each energy pattern holding the rule's bond to at most one "this site of a center molecule is bound to anything" condition, counts it once, and ORs the conditions; the rule builders build every rule from the two bond sites alone. Outside the shapes that survive that, an Arrhenius rule ran at the wrong rate with no warning: - an energy pattern with a state, or a site required free; - one with wildcard bonds only, or a `!+` or a context bond on a site named like the reaction site; - a context site with two possible partners; - context two bonds out, or two context conditions; - a `!?` that BioNetGen counts more than once; - any context in the rule's own reactant pattern. The issue measured each 48-52 standard errors off BioNetGen's network. EnergyFunction::inexact_reason now checks every energy pattern whose count the bond can change against the shapes the expansion prices exactly. Those are the bond alone, the bond plus a lone `!+`, or the bond plus one bond to a molecule of a third type that nothing else binds, on a site declared once and not named like the reaction site; with no state, no free site, and no `!?` that BioNetGen counts more than once. collect_site_graph reads every bond the seed species and rules can hold, and each molecule type's repeated site names. try_expand_arrhenius refuses a reactant pattern carrying anything besides the two bond sites, and an unbinding written with `.`. Every refusal now names its reason. Also fixes a second misread in the same code. Every Arrhenius rule named `_reverse_X` was given the reverse half's 1-phi, but a rule the modeler labels so is a rule as written, and BNG2 gives it phi (443 vs 645 of 1000 left at t = 2). A rule is now a reverse half only if an Arrhenius rule X has the same rate constants and the mirror-image bond operation, which is what BNG2 writes for a reversible rule. Tests: - arrhenius_context_test pins the nine reproducers and five more shapes, plus five models in the exact class that must load clean. - energy_expand_test covers the remaining gate branches. - arrhenius_formula gains columns for the `_reverse_` cases and the lone `!+`, scored against BNG2. All 38 single-point mutations are killed. 249 of the 263 XMLs under tests/ run byte-identical to main at 2 seeds; the other 14 are the new fixtures and the extended arrhenius_formula.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the silent half of #109. Every Arrhenius rule the load-time expansion cannot price exactly is now refused with a Tier-0 Error, which names the energy pattern or reactant context responsible, instead of running at the wrong rate. A separate PR follows with BNG-exact pricing, which lets those models run.
Why the expansion is wrong outside a narrow class
try_expand_arrheniusturns each Arrhenius rule into conventional rules with fixed rates.expand_bindingreduces each energy pattern holding the rule's bond to at most one condition, "this site of a center molecule is bound to anything". It counts each pattern once and ORs the conditions together.That is exact only when every energy pattern whose count the bond changes is one of these:
A(b!1).B(a!1);!+on one of its two molecules,A(b!1,c!+).B(a!1);A(b!1,c!2).B(a!1).C(a!2), where nothing but C'sacan ever bind A'sc.In each case A must declare one
c, not named like the reaction site. The pattern may have no state, no site required free, and no!?that BNG2 counts more than once. BNG2 divides matches by automorphisms, so k!?on m same-named components count C(m, k) times. Beyond the patterns, the rule's reactant pattern must name only the two bond sites, and a rule that breaks the bond must write+between its products.What changed
EnergyFunction::inexact_reason(energy_expand.cpp) checks every energy pattern against that class for the rule's reaction center.!+, soA(s~1), say, is left alone..is refused, since joining or parting any two complexes can change its count.collect_site_graphreads, before the rules are converted, every bond the seed species and rules' patterns can hold, and how many components of each name each molecule type declares.try_expand_arrheniusrefuses a reactant pattern that carries anything besides the two bond sites (!?aside), and an unbinding written with.. Every refusal, old or new, now names its reason in the Error.The nine reproducers from the issue now come back as:
energy pattern A(b!1).B(a!1,s~1) requires B.s in state 1energy pattern A(b!1,c).B(a!1) requires A.c freeenergy pattern L(r!+,r!+) constrains L.r without naming the L.r-R.l bondenergy pattern L(r!1,r!+).R(l!1) names a second L.r besides the reaction siteenergy pattern L(r!1,r!2).R(l!1).S(l!2) names a second L.r besides the reaction siteenergy pattern A(b!1,c!2).B(a!1).C(a!2) requires A.c bound to C.a, but A.c can also bind D.aenergy pattern A(b!1).B(a!1,c!2).C(b!2,d!3).D(c!3) names more than one bond besides the A.b-B.a bondenergy pattern A(b!1,c!2,d!3).B(a!1).C(a!2).D(a!3) names more than one bond besides the A.b-B.a bondits reactant pattern requires A.s in state 1A second misread in the same code:
_reverse_by nameBNG2 marks the reverse half of a reversible rule X only by naming it
_reverse_X, so RM gave every Arrhenius rule of that name1-phi. A rule the modeler labels_reverse_Xis a rule as written, and BNG2 gives itphi. On bngsim'srevnamefixture, BNG2's network leaves 443 of 1000 complexes at t = 2; RM left 645.A rule is now a reverse half only if the model has an Arrhenius rule X with the same rate constants and the mirror-image bond operation on the same sites, which is what BNG2 writes for a reversible rule. One case cannot be told apart from the XML: two unidirectional rules, X and
_reverse_X, that mirror each other and name the same parameters for phi and Ea0. They write the same XML as one reversible rule, in either orientation, so RM reads them as one. With numbers instead of parameters, BNG2 writes per-rule_Aphi_Nand_AEact0_Nand the two are told apart. The documented case could only be closed by BNG2 marking reverse halves inwriteXML.Verification
Tests.
arrhenius_context_test(new) loads the nine reproducers and five more shapes. Each must be refused with an Error naming the rule and the expected reason. Five models in the exact class must load with no Arrhenius diagnostic. Against main's library it fails every refusal group.The five extra shapes are: a context partner only a rule makes, a context site declared twice, a
!?counted twice, the other rule-context checks, and an unbinding written with..energy_expand_testcovers the gate branches the fixtures do not reach.The
arrhenius_formulaBNG2-oracle model gains seven columns, scored against a regenerated BNG2 reference (the existing columns moved in the 8th significant figure):_reverse_: no rule X; an unrelated X; and an Arrhenius X differing from the mirror in rate constants, operation, or sites;!+.Main misses them by up to 102 standard errors; here the max z is 2.4.
ctest is 65/65 and
basicmodels.pyis 29/29.Mutation check. All 38 single-point mutations of the gate, the rule checks, the site-graph pre-pass and the reverse-half matcher are killed.
Independent review. Two rounds by a reviewer that built its own probe models and scored them against BNG2's network.
!?multiplicity and_reverse_Xbeside an unrelated X, plus one false refusal, the lone!+. All are fixed and pinned above.!?count from P(m, k) to C(m, k), which un-refusesL(r!1,r!?,r!?).R(l!1)onL(r,r,r)(max z 0.61 against BNG2).Cross-check with bngsim. bngsim's
refuse_rulemonkey_energy_misreads(Re-vendor RuleMonkey 3.11.0: lift method='rm''s time() and time-TFUN refusals, run rm on absolute model time, and pick up the RuleMonkey fixes since 3.10.1 lanl/bngsim#1022) is an independent implementation of the same envelope for 3.11.0. It agrees with this gate on all 23 Arrhenius fixtures underbngsim/tests/dataand on the 5 here, except for two:revname, which RM now prices correctly;state_change, which RM refused already.This gate accepts more than bngsim's in four places, each scored against BNG2's network:
!?counted once,!?in the rule's reactant pattern, and patterns the bond cannot change, max z 1.06, in a regime where a misapplied 0.7 energy halves the bound count;!+, z 1.23.Blast radius. 249 of the 263 XMLs under
tests/run byte-identical tomainat 2 seeds, stdout and exit code. The 14 that differ are the 13 new fixtures, which main runs and this refuses, and the extendedarrhenius_formula. Main's originalarrhenius_formula.xmlruns byte-identical under both binaries.Once this is vendored, bngsim can drop
refuse_rulemonkey_energy_misreads: RM now refuses every model that check refuses and RM misprices, with a message naming the pattern.