Skip to content

Surgical performance pass on hot paths#24

Merged
edkerk merged 1 commit into
developfrom
perf/tier3-surgical
Jun 10, 2026
Merged

Surgical performance pass on hot paths#24
edkerk merged 1 commit into
developfrom
perf/tier3-surgical

Conversation

@edkerk

@edkerk edkerk commented Jun 9, 2026

Copy link
Copy Markdown
Member

Tier 3 of the raven-python review: a surgical performance pass — verified hot-path
footguns only, no redesign and no behaviour change.

Changes

  • manipulation/add.py + manipulation/change.pyadd_reactions_from_equations
    and change_reaction_equations resolved each equation token by re-scanning
    model.metabolites for a name / name[comp] match, i.e. O(R*k*M) for R reactions
    x k tokens on an M-metabolite model. Both now resolve through a shared
    (name, compartment) -> metabolite index (_build_met_index), dropping the bulk
    path to O(R*k). The index is seeded from the current mets (first match wins,
    exactly mirroring the old linear scan) and updated as new mets are created, so the
    existing cross-token / cross-reaction dedup is preserved.
  • reconstruction/homology/homology.py — the ortholog filter used
    DataFrame.apply(lambda r: ..., axis=1), which builds a Series per row. Replaced
    with a comprehension over the two columns (the model_genes values are already
    sets, so membership is O(1)); matches the zip(..., strict=True) idiom already used
    a few lines below.
  • analysis/sampling.py — the random objective was assembled with sum(terms),
    which re-canonicalises the optlang expression on every term (O(n^2) — the footgun
    documented and avoided everywhere else in the package). Switched to
    optlang.symbolics.add(terms), matching init/ftinit.py et al.

Not changed (verified no-op)

The plan's fourth perf item (trim model.copy() in the gap-fill / task loops) is
already done or load-bearing: init/taskfill.py:_feasible was converted to
with model: (see its comment — that copy had dominated gap-fill runtime), and the
remaining copies in gapfilling/fill.py build or return new models. Nothing safe left
to trim.

Tests / verification

Adds a cross-reaction metabolite-dedup regression test (the invariant the index must
preserve). pytest (619 passed), ruff check, and mypy (ad-hoc on the changed
sources) all green; no behaviour change on the existing suite.

Targeted, behaviour-preserving optimisations from the review:

- manipulation/add.py + change.py: resolve equation tokens through a shared
  (name, compartment) -> metabolite index (_build_met_index) instead of
  re-scanning model.metabolites per token. Bulk reaction add/change by name
  drops from O(R*k*M) to O(R*k); the index is updated as new mets are created
  so cross-token and cross-reaction dedup is preserved.
- reconstruction/homology/homology.py: replace DataFrame.apply(axis=1) in the
  ortholog filter with a comprehension over the columns (membership is already
  O(1); avoids per-row Series construction).
- analysis/sampling.py: build the random objective with optlang add() instead
  of sum(), which re-canonicalises the expression on every term (O(n^2)).

Adds a cross-reaction metabolite-dedup regression test for the add path.
@edkerk edkerk merged commit 4f91292 into develop Jun 10, 2026
5 checks passed
@edkerk edkerk deleted the perf/tier3-surgical branch June 10, 2026 07:41
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