Skip to content

Cap set-variant cartesian expansion (#40)#44

Merged
adamjohnwright merged 2 commits into
mainfrom
fix/variant-cap-40
Jul 15, 2026
Merged

Cap set-variant cartesian expansion (#40)#44
adamjohnwright merged 2 commits into
mainfrom
fix/variant-cap-40

Conversation

@adamjohnwright

Copy link
Copy Markdown
Contributor

Summary

Fixes #40 — set-variant expansion produced catalog-scale explosions (and hangs) that blocked generating most of the pathway catalog.

Adds an env-tunable cap LNG_MAX_VARIANTS (default 512, <=0 disables). When a complex's internal-EntitySet combinations — or a reaction's input/output combinations — would exceed the cap, all alternatives are bundled into one opaque node (named by the plain stId, no giant ::variant::<all-leaves> id) instead of materializing the full cartesian product.

Three separate cartesian sites are now capped consistently:

  1. input/output matchingreaction_generator.get_broken_apart_ids
  2. input/output emissionlogic_network_generator._complex_variant_leafsets (+ _variant_capped → plain-stId naming)
  3. negative-regulatorlogic_network_generator._expand_complex_variants

Verified against Neo4j

pathway before after
Class_I_MHC 3,287,698 edges 61,278
Chromatin_modifying_enzymes 1,391,200 34,768
Cellular_Senescence 130,879 20,050
Interferon_gamma_signaling hung 8.5h ~90s
RAF_MAP_kinase_cascade 4,769,814 (144,750 root inputs) 18,210 (762)
Signaling_by_ERBB2 (control) 9,067 9,067 (0 cap hits — byte-identical)

The cap is inert below threshold: pathways whose variant counts are under 512 take the exact same code path as before, so their output is unchanged. RUNX1 (163k edges) is intentionally untouched — it's genuinely large (bounded additive subunit decomposition), not a cartesian explosion.

Impact

Unblocked a full held-out curator holdout across 69 pathways (previously ~18 were tractable): 81.10% (12,211/15,056) at the tuned classification cutoffs, including the previously-impossible large pathways (Chromatin 95.8%, Interferon_gamma 63.5%, Class_I_MHC 62.5%).

Tests

  • TestVariantCap (matching layer): over-cap bundles to one node carrying all components; under-cap still expands.
  • TestRegulatorVariantCap (negative-regulator layer): over-cap bundles; under-cap expands.
  • Full non-DB suite green (137 passed), ruff + mypy clean, coverage 46% (> 40% gate).

🤖 Generated with Claude Code

adamjohnwright and others added 2 commits July 15, 2026 09:07
…ns (#40)

A complex whose internal-EntitySet combinations — or a reaction whose
input/output combinations — exceed LNG_MAX_VARIANTS (default 512) are now
bundled into a single opaque node instead of materializing the full cartesian
product. This is enforced at both layers so they agree a given complex is one
node:

- matching (reaction_generator.get_broken_apart_ids): when the product exceeds
  the cap, merge all alternatives' components and emit one bundled combination
  via the existing get_uids_for_iterproduct_components path.
- emission (logic_network_generator._complex_variant_leafsets): same cap;
  bundled complexes are tracked in _variant_capped so _map_annotated_entity_to_nodes
  names them by their plain stId (no giant ::variant::<all-leaves> id).

Verified against Neo4j — the four catalog-scale blockers are tamed with the
bundled node still carrying every alternative's components, and pathways below
the threshold are byte-identical (cap branch never executes):

  Class_I_MHC              3,287,698 -> 61,278 edges
  Chromatin_modifying      1,391,200 -> 34,768 edges
  Cellular_Senescence        130,879 -> 20,050 edges
  Interferon_gamma          hung 8.5h -> completes ~90s
  Signaling_by_ERBB2        9,067 edges, 0 cap hits (unchanged)

Env-tunable via LNG_MAX_VARIANTS; <= 0 disables the cap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
_expand_complex_variants — the negative-regulator decomposition path — did its
own uncapped itertools.product, separate from the input/output caps added in
the previous commit. A single inhibitor complex with large internal EntitySets
fanned out into ~144k variant nodes, each wired to every reaction it inhibits:
RAF_MAP_kinase_cascade produced 4,758,406 negative-regulator edges (4.77M edges
total, 144,750 root inputs).

Apply the same MAX_VARIANTS cap: when the variant cartesian exceeds the cap,
return the complex as one opaque node [(complex_id, 1)]. Verified vs Neo4j:

  RAF_MAP_kinase_cascade   4,769,814 -> 18,210 edges  (root inputs 144,750 -> 762)

RUNX1 (163k edges) is unaffected — that pathway is genuinely large (65k catalyst
+ boundary edges via bounded additive subunit decomposition), not a cartesian
explosion, so it is left as-is.

Adds TestRegulatorVariantCap (over-cap bundles to one node; under-cap expands).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@adamjohnwright
adamjohnwright merged commit 15b2ca3 into main Jul 15, 2026
4 checks passed
@adamjohnwright
adamjohnwright deleted the fix/variant-cap-40 branch July 15, 2026 14:22
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.

Set-variant edge explosion on high-cardinality pathways (Mit_Prophase 214k)

1 participant