Repository navigation
Reaction graph encodings and integrators (#65) - #70
Merged
Merged
Conversation
test_rectangular_model_forward_and_gradients asserts a nonzero relation gradient, which about 7.5% of random initializations (15 of 200 seeds) fail through dead ReLU paths on the tiny graph. It inherited RNG state from whatever ran earlier in its xdist worker, so adding unrelated tests could flip it. Pin torch.manual_seed(0). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #65. Fills in koopman_graph.datasets.reaction.graphs and .integrate: - graphs: species_influence_graph (Jacobian-sparsity species graph with linking-reaction counts), reaction_hyperedge_index (library hyperedge layout), reaction_directed_hyperedges (reactant tails / product heads), species_reaction_bipartite (HeteroData with stoichiometric weights). - integrate: integrate_expm (exact augmented matrix exponential for linear systems, including zeroth-order feeds), linear_rate_equations, integrate_rk4 (batched, differentiable), integrate_stiff (SciPy BDF/Radau/LSODA with an exact Jacobian, behind require_scipy and the [reaction] extra), integrate_reaction_system (method="auto"), and mass_action_jacobian. SciPy is imported only inside the stiff path, so import hygiene holds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- integrate_reaction_system: method="auto" accepts substeps for linear and nonlinear systems alike (ignored on the exact path), rejects other options up front, and type-checks the system before dispatch. - integrate_expm: build the generator and propagators on the input's device instead of always on CPU. - species_reaction_bipartite: keep rate_constant in float64 so tiny or huge rate constants do not under/overflow. - mass_action_jacobian: evaluate over padded reactant slots, so memory is O(R * width^2) instead of a dense (R, S, S) tensor. - integrate_stiff: precompute stoichiometry and Jacobian slots once rather than revalidating and recasting on every solver callback. - Share one _require_system helper and reuse ReactionSystem._validate_concentrations; finiteness errors name the argument. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 15, 2026
Codecov Report✅ All modified and coverable lines are covered by tests.
🚀 New features to boost your workflow:
|
test_doubly_stochastic_row_and_column_sums drew unseeded torch.randn logits and asserted row/column sums within 1e-4. The default 8 Sinkhorn sweeps are documented as approximate: 63 of 500 random seeds leave a row sum off by more than 1e-4 (max ~2.6e-3), so the test failed about 13% of the time (seen while propagating the reaction stack). Pin torch.manual_seed(0) (error ~5e-7) instead of loosening the tolerance. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tjkessler
added a commit
that referenced
this pull request
Oct 15, 2026
Ubuntu CI failed test_card_oracle_matches_recomputation (Michaelis-Menten, random network), test_cantera_card_oracle_and_provenance, and the card builder --check: oracle['conservation_laws'] drifted. With two or more conservation laws any rotation of an orthonormal basis is valid, and torch.linalg.svd returns a different one under Linux LAPACK than under macOS Accelerate, so the committed cards held a platform-specific basis. The single-law chain card was unaffected. _stoichiometric_basis now canonicalizes the conservation laws: Gram-Schmidt in species order on the columns of the projector P = W^T W, which is basis independent, so every platform gets the same rows (to rounding) with a fixed sign. Cards regenerated; apart from the rotated laws, oracle values move only at rounding level (<= 3e-14). Adds a test that a rotated, sign-flipped basis canonicalizes back to the same rows. Also merges main (#70-#73) into the branch, which GitHub reported as behind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Refs #65. Third PR for the reaction-network datasets. Stacked on #69: it targets #69's branch, so the diff shows only this PR's changes. Merge #69 first, then retarget this PR to
mainif GitHub doesn't do it automatically.Changes
koopman_graph.datasets.reaction.graphs(built from stoichiometry only)species_influence_graph(system, *, self_loops=False)returns(edge_index, edge_weight). There is an edges → twhen speciessis a reactant of a reaction that changest, which is the sparsity pattern of the mass-action Jacobian∂(dc_t/dt)/∂c_s. Each edge's weight is the number of reactions that link the pair. Edges are unique and sorted.reaction_hyperedge_indexgives one hyperedge per reaction, over its reactants and products, in the library'shyperedge_indexlayout ((2, nnz), row 0 = species, row 1 = reaction).reaction_directed_hyperedgesreturnstail_index(reactants) andhead_index(products) in the same layout. Source and sink reactions leave a side empty, so the docstring says to passnum_reactionsexplicitly.species_reaction_bipartitereturns a PyGHeteroDatawithspeciesandreactionnodes and stoichiometric coefficients as edge weights. Reaction nodes carryrate_constant. The node/edge type names are exported as constants.koopman_graph.datasets.reaction.integrate(all paths return(len(times), ..., S), withtimes[0]the time of the initial state)integrate_expm: exact propagation for linear systems (every order ≤ 1). It foldsdc/dt = A c + binto one augmented(S+1)×(S+1)matrix exponential, so zeroth-order feeds are exact too. Takes batched initial states.linear_rate_equationsexposes(A, b).integrate_rk4: fixed-step RK4 in torch withsubstepsper output interval. Batched, keeps the input's dtype and device, and is differentiable.integrate_stiff: SciPysolve_ivpwith BDF, Radau, or LSODA and the exact Jacobian. SciPy is imported only throughrequire_scipy(), whose ImportError names[reaction]. RaisesRuntimeErrorif the solver fails.integrate_reaction_system(..., method="auto")usesexpmfor linear systems andrk4otherwise. Stiff methods must be requested explicitly.mass_action_jacobian(system, c): exact∂(dc/dt)/∂c, finite atc = 0(it never divides byc). The upcomingoraclesmodule can reuse it.Other
koopman_graph.datasets.reaction; the root anddatasets__all__are unchanged. CHANGELOG[Unreleased]entry added.tests/operators/test_hetero_rectangular.py::test_rectangular_model_forward_and_gradientshad no seed and fails for about 7.5% of random initializations (15 of 200 seeds give an all-zero relation gradient). Adding tests reshuffled the xdist workers and it began failing every time locally, so the test now setstorch.manual_seed(0).Tests
A → B → Csolution, to 1e-10 relative.element_balance_violation.A(1) ≈ 0.9664597.c = 0.Noneinsys.modules, raises the[reaction]hint.Verification (macOS arm64, Python 3.13)
ruff checkandruff format --checkonsrc/ tests/pass.pytest -n auto -m "not slow and not distributed and not ray" --cov=koopman_graph --cov-fail-under=90: 3385 passed, 26 skipped, 97.24%.graphs.pyandintegrate.pyare at 100%.sphinx-build -W --keep-goingpasses.🤖 Generated with Claude Code