Skip to content

feat(opt): ægraph MVP — acyclic e-graph data structure (v1.0.3 Track 2)#122

Merged
avrabe merged 1 commit into
mainfrom
release/v1.0.3-pr-egraph-mvp
May 17, 2026
Merged

feat(opt): ægraph MVP — acyclic e-graph data structure (v1.0.3 Track 2)#122
avrabe merged 1 commit into
mainfrom
release/v1.0.3-pr-egraph-mvp

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented May 17, 2026

Cranelift-style acyclic ægraph substrate per docs/research/v0.7.0/optimization-methods-survey.md. STRICTLY MVP — data structure + hash-consing + acyclic invariant + extraction + 7 tests. No pipeline integration; no rewrite engine; no union() yet. Future PRs add the rewrite layer with per-rule proofs.

432 LOC (excluding tests), 7 tests pass.

🤖 Generated with Claude Code

INFRASTRUCTURE ONLY. Lands the minimal Cranelift-style acyclic
equality-graph substrate so future PRs can grow a per-rewrite-verifiable
optimizer pipeline on top.

What ships:
- `loom-core/src/egraph.rs` (~430 non-test LOC, 180 LOC of tests)
- `Op` discriminator covering 14 i32 arithmetic / bitwise / comparison /
  load-class opcodes (Const, Const64, LocalGet, I32{Add,Sub,Mul,And,Or,
  Xor,Shl,ShrS,ShrU,Eq,Eqz}).
- `ENode { op, children: Vec<EClassId> }` with arity validation.
- `EGraph::add` performs hash-consing (structural sharing via
  `HashMap<ENode, EClassId>`) and enforces the acyclic invariant —
  every child id must be strictly less than the about-to-be-created
  class id, which makes self-reference and forward edges syntactically
  impossible.
- `ENode::from_instruction` / `EGraph::extract` round-trip helpers so
  upstream callers can opt-in incrementally; unsupported ops return
  `None` so callers cleanly fall back to existing pipeline.
- 30-LOC inline `UnionFind` (no external `union-find` crate) wired so a
  future rewrite engine can add `union()` without API churn.

Out of scope (deferred to v1.0.4+):
- Rewrite engine / `union()` API.
- Wider op coverage (i64, conversions, memory ops).
- Real cost model.
- Integration with the canonicalize / `simplify_with_env` pipeline.

Tests: 7 unit tests, all pass under `cargo test --release egraph`:
- hash-cons const, hash-cons arith tree, distinct nodes get distinct ids
  (commutativity NOT normalized — that's rewrite-engine work)
- extract round-trips through `encode::encode_wasm` and produces a valid
  wasm module header
- acyclic invariant: forging a self-referential child id is rejected
- `from_instruction` returns None for unsupported ops and wrong arity
- supported ops convert correctly when given the right children

Soundness gotchas surfaced while building this:
- Commutativity is NOT normalized in the MVP. `add(1,2)` and `add(2,1)`
  hash-cons to different e-classes. Any future rewrite rule that wants
  to unify them must do so through `union()` (not yet implemented) and
  carry its proof obligation.
- Identity-element rewrites (x+0 == x, x*1 == x, x&-1 == x, etc.) are
  also rewrite-engine work, not substrate work. The MVP intentionally
  ships zero rewrites so the substrate can be reviewed in isolation.
- The acyclic guard is "child id < new id" — this is the structural
  reason ægraphs are easier to verify than full e-graphs: there is no
  congruence-closure fixpoint that can re-introduce cycles.

Implements: track2/egraph-mvp
Refs: docs/research/v0.7.0/optimization-methods-survey.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@avrabe avrabe merged commit 8404ee5 into main May 17, 2026
9 of 19 checks passed
@avrabe avrabe deleted the release/v1.0.3-pr-egraph-mvp branch May 17, 2026 05:14
avrabe added a commit that referenced this pull request May 17, 2026
…ap) (#124)

Five-track sprint. Three landed via agents in worktrees, one
direct-work, one deferred when its agent died.

Merged:
  #120  Track 4: close SG-3..6 lifecycle gaps
  #121  Track 1 (PR-Q): real corpus fixtures (3rd attempt — success)
  #122  Track 2: ægraph MVP (acyclic e-graph substrate)
  #123  Track 5: issue triage + roadmap doc

Issues closed via the roadmap:
  #45  Rocq foundation (already shipped)
  #47  StackSignature::compose associativity (proven)
  #50  Crocus-style ISLE verification (already in verify_rules.rs)
  #75  P3 async callback trampolines (duplicate of #70)

Deferred to v1.0.4:
  Track 3: verifier table-resolver teaching (agent died)
  ægraph rewrite engine + per-rule proofs
  KEEP issues #48 #68 #70 #71

Lifecycle gaps: 4 → 0 (track 4 closed all remaining).
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