Skip to content

:>> ABIO → ABIO Architecture → ABIO-Bio-Engine

ABIO-Bio-Engine

A deterministic alien-chemistry integrator: a wrong number here corrupts every trial silently, which is why it is scanned first.

ABIO-Bio-Engine.svg

A world is authored declaratively: the suite's blocks emit string-id Compartment, Transport, GrowthLaw/DeathLaw/CountFlowSpec records plus a ChemistryImpl whose rate laws are rate_expr trees keyed by species name. WorldImpl.__init__ is the single resolution point: build_tree flattens compartments into an int-indexed CompartmentTreeImpl, a self-describing WorldStateImpl is derived from each compartment's concentrations, multiplicity and volume, and every string-id spec is rewritten into int-indexed TransportFlux, PerCapitaGrowth/Death and CountFlow objects. suite/verify.simulate then calls WorldSimulatorImpl.from_chemistry, where map_species re-keys rate laws name→id and modifiers become Modulations. Each reference step computes every reaction's desired extent from the frozen start-of-step state, rations shared reactants by single-pass min-ratio scaling, applies extents simultaneously, then the flow pass, then the population pass — each computing desire off the frozen state, rationing the summed demand per pool and applying at once (T053). The JAX path rebuilds the same reactions as padded tensors, lowers each law through lower_jax, and runs the algebraically identical rationing on device; parity to 1e-9 is a CI test. Either way the output is a Timeline of WorldStateImpl copies, and the runner rebuilds a fresh WorldImpl from the prior end-state every turn.

Modules

MODULE LOC Role
chemistry.py · molecule.py · reaction.py · atom.py 336 · 193 · 383 · 118 The entities: ChemistryImpl (bipartite graph queries via infra.graph_ops), MoleculeImpl (atoms, Hill symbol), ReactionImpl + Modulation, AtomImpl.
world.py 422 WorldImpl, Compartment, Transport, the law specs, build_tree — the resolution point.
world_state.py · compartment_tree.py 343 · 195 Dense [comp × mol] store with amount = multiplicity·volume·concentration; int-indexed parent/child topology.
flow.py · population.py 501 · 544 TransportFlux (amount-conserving), GeneralFlow, apply_flows (the flow pass); PerCapitaGrowth, PerCapitaDeath, CountFlow on the multiplicity axis and apply_population_laws (the population pass). Both passes ration the summed demand on each pool off the frozen state, as the reaction pass does (T053).
world_simulator.py 534 The reference stepper: WorldSimulatorImpl, ReactionSpec, _desired_extent, _modulation_factor, subnormal flush.
rate_expr.py 270 One compiled rate-law tree: eval_rate, lower_jax, map_species, implicit_mass_action, to_json/from_json; the one home of ROUNDING_FLOOR and RATE_CAP (a divisor below the floor is zero on both backends).
jax_core.py · jax_simulator.py 325 · 268 Padded stoichiometry tensors, apply_reactions, make_run_fn; JaxWorldSimulator with run_fast/run_batch (population laws run host-side in step; run_fast/run_batch refuse them).
conservation.py · energy.py 158 · 145 Static atom balance (called by skeleton.py), opt-in ΔG accounting, the total_quantity/total_free_energy canaries.
makers.py · __init__.py 78 · 117 Registers mk.M/R/C; the public re-export surface and the bio.io slot. The M1 layer this table used to list — simulator.py/biosystem.py/state.py, equilibrium/perturbation/quiescence, the agent/task modules, MembraneFlow — was deleted in T056 (2026-09-10).

Only four packages are imported: protocols.bio, infra.entity/graph_ops/mk, spec_lang.decorators; jax and numpy are optional and guarded. Inbound: 32 suite files, nothing from expr/ or commands/. Most-imported symbols: WorldImpl (22 sites), WorldStateImpl (11), ChemistryImpl (11, three of them pulling the private _mock_dat).

Where a wrong number would be silent

Hypotheses for the latent-bug pass (T051 box 4); each names a constructed input.

HYPOTHESIS Why it would be quiet Where
MembraneFlow.apply transports nothing the stoichiometry loop body is pass; the class is still exported flow.py ~255
The JAX path drops population laws and TransportFlux JaxWorldSimulator.__init__ accepts only reactions, GeneralFlow and native flows; a world with either runs a different trajectory with no warning jax_simulator.py ~54–73
Two death laws drive multiplicity negative each law clamps against the frozen count independently, the stepper sums them without a floor; amount() and the conservation canary flip sign population.py ~329, ~431; world_simulator.py ~261
Flows are sequential and unrationed list order decides which of a forward/reverse pair sees the pre-transfer pool; the JAX apply_native_flows has no availability clamp and runs after the negative snap world_simulator.py ~229; jax_core.py ~284–306
Constants duplicated across backends ROUNDING_FLOOR/RATE_CAP re-declared as literals in jax_core; subnormal flush on the reference path only; lower_jax assumes map_species already ran jax_core.py ~118, ~195; world_simulator.py ~35
Autocatalytic species and negative-base powers JAX collapses to P − R in one matmul, the reference subtracts (with a snap) then adds; a**b on a negative base raises in CPython and yields NaN→0 in JAX jax_core.py ~231; world_simulator.py ~406–418; rate_expr.py ~134, ~175
ReferenceSimulatorImpl is a different physics no mass-action term, no rounding snap; any parity test that pairs it with the world simulator compares two models simulator.py ~131–173