Skip to content

Feature/mechanism lookup - #27

Merged
remislp merged 3 commits into
masterfrom
feature/mechanism-lookup
Nov 12, 2026
Merged

remislp merged 3 commits into
masterfrom
feature/mechanism-lookup

Conversation

@remislp

@remislp remislp commented Nov 12, 2026

Copy link
Copy Markdown
Member

No description provided.

remislp and others added 3 commits November 12, 2026 12:39
States are stored in the order Mechanism sorts them into, by state type:
open first, then short-lived shut, then long-lived shut. That is rarely the
order a paper tabulates them in. CH82 is stored as AR*, A2R*, AR, A2R, R,
and the ten-state flip mechanism of Burzomato et al. (2004) differs from the
published ordering by a swap of two states. Reading a Q matrix by position
against a published table therefore invites an error that nothing catches,
because the wrong entry is still a plausible number.

Adds, all computed on demand and none of them caching anything:

  state_names            names, in Q-matrix order
  state_index(name)      row and column of a state
  rates_by_edge()        {(from, to): Rate} for every transition
  rate(from, to)         one transition, KeyError if there is no such step
  permutation(order)     index array to reorder Q into a given order

rate() raising rather than returning None is the point of it: asking for a
step the mechanism does not have is a question about a different mechanism.
When a name is simply unknown it says so, and lists the states there are.

Reproducing a published paper previously meant writing a wrapper class to do
this; that is what prompted it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
transition_probability had three implementations, two in scalcslib and one
in scsim; transition_frequency had two. They had drifted:

  - scalcslib's copies carried empty docstrings;
  - scalcslib's transition_probability did Q.copy() without casting, so an
    integer Q matrix divided integer-wise and returned silently wrong
    numbers rather than raising;
  - scalcslib's transition_frequency computed pinf internally and so could
    only ever give equilibrium frequencies.

Both now live in qmatlib, with the rest of the plain Q-matrix algebra, and
are re-exported from scalcslib and scsim so nothing importing them breaks.

transition_frequency now takes the occupancies as an optional argument.
Called with one argument it still uses pinf, which is what every existing
call site does; passing p gives the frequencies at an instant during a
concentration jump, when the system is not at equilibrium.

The tests pin the definitions, that neither function modifies its argument,
that an integer Q is no longer truncated, and that at equilibrium detailed
balance holds edge by edge. That last one is only approximate for CH82,
whose MR-constrained rate is stored rounded to 0.66667, so its cycle closes
to about 1e-9; a mechanism whose rates come from a fit closes to 1e-12.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
update_mr() imposes the constraint. Nothing reported whether it actually
holds for the rate constants a mechanism is carrying, which is a different
question and a useful one: a set that has been averaged, transcribed, or
written by another program can fail it, and the size of the failure says how
much to trust the set.

  cycle_ratios()          [(states, forward/backward), ...], one per cycle
  reversibility_error()   max |ratio - 1| over all cycles, 0.0 if none

check_mr already returned the two products for one cycle, and these agree
with it - there is a test pinning that so they cannot drift. What they add
is the whole-mechanism summary, and failing loudly: check_mr looks each step
up with a scan that contributes nothing when no rate matches, so a cycle
naming a transition the mechanism does not have comes back as a perfectly
closed cycle. These use rate(), which raises.

Scale, for reading the number. The two ten-state datasets behind Colquhoun &
Lape (2012):

  single fitted set   1.4e-07   (stored as 32-bit floats)
  averaged set        4.2e-02   (ratios 0.9576 and 0.9671)

Averaging several fitted sets does not preserve cycle conditions, and that
is what a violation of percents rather than parts in 10^7 looks like. CH82
gives 5e-06, because its constrained rate is stored rounded to 0.66667.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@remislp
remislp merged commit 805dcf3 into master Nov 12, 2026
16 of 18 checks passed
@remislp
remislp deleted the feature/mechanism-lookup branch November 12, 2026 18:44
@remislp remislp mentioned this pull request Nov 12, 2026
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