Few minor fixes and optimization#367
Conversation
…d improve `find_costs` to be O(V+E) complexity
|
Hi, thanks for the contribution. Have you seen the https://github.com/egraphs-good/extraction-gym? Does this algorithm related to any of those? |
|
Thank you for your response, I just checked extraction-gym and Yes, it relates directly, the worklist part of this PR is essentially the gym's faster-bottom-up extractor (dedup FIFO of pending work, re-enqueue parents when a class's best cost improves), and the code it replaces corresponds to the bottom-up baseline (full re-scan fixpoint). Both are tree-cost extractors, so the extraction result is unchanged, and this PR doesn't attempt anything from the DAG-cost or ILP families. The PR has a second part the gym doesn't cover: Extractor::costs used to store (Cost, L), a clone of the winning e-node, re-cloned on every improving pass, and now stores (Cost, usize), the node's index in its e-class, resolved back to &L on demand. That's the same id-based bookkeeping the gym's extractors use for their ClassId to NodeId choices, but applied inside egg's Extractor, so it also cuts allocations and the memory held per class. The gym benchmarks standalone extractors over serialized e-graphs, so this in-library effect wouldn't show up there. The table in the description reflects both that the asymptotic win from the worklist on deep e-graphs and the constant-factor/memory win from not cloning. One caveat is that with a FIFO worklist a class can re-relax on cyclic e-graphs, so linear time is the practical bound rather than a strict guarantee, the gym's prio-queue variant(cheapest-first, each class settles exactly once) is the strict version. I kept FIFO here since it's the smallest change to egg's existing make_pass/parents structure. |
Hey, awesome project! I'm building a super-optimizer on top of it+Z3, and I've had a great experience using it. Here's my performance optimization PR results:
find_costsperformance: old vs newBenchmark of
Extractor::new(which runs all offind_costs) onEGraph<SymbolLang, ()>with theAstSizecost function. Measured withcriterionover 100 samples.find_costs: repeated full-scan fixpoint until no cost changes, cloning the chosen node into the costs map on every pass.src/extract.rs: worklist-basedfind_costs(costs propagate only to parents on change) and stores the e-node's index intoEClass::nodesinstead of cloning the node.deep_chain/200deep_chain/2000deep_chain/20000wide_tree/256leaveswide_tree/4096leaveswide_tree/16384leavessaturated/491classessaturated/1121classessaturated/10455classesScenarios
deep_chain/N: a right-nested chain(f (f (f … a)))of depthN. A single long cost-dependency chain. Worst case for the old algorithm.wide_tree/Nleaves: a complete balanced binary tree of+overNdistinct leaves. Shallow and wide.saturated/…: a realistic e-graph produced by running associativity, commutativity, distributivity/factoring, and identity rewrites on(* (+ a b) (* (+ c d) (* (+ e f) (+ g h))))to saturation with a node budget. The shapefind_costssees in real use.