-
-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
3.0 Release #185
base: master
Are you sure you want to change the base?
3.0 Release #185
Conversation
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## master #185 +/- ##
===========================================
+ Coverage 69.17% 82.28% +13.10%
===========================================
Files 16 19 +3
Lines 1353 1547 +194
===========================================
+ Hits 936 1273 +337
+ Misses 417 274 -143 ☔ View full report in Codecov by Sentry. |
Benchmark Results
Benchmark PlotsA plot of the benchmark results have been uploaded as an artifact to the workflow run for this PR. |
This is 14.5 times faster than egg in rust! Julia Code using Metatheory, BenchmarkTools
t = @theory a b begin
a + b --> b + a
a * b --> b * a
a + 0 --> a
a * 0 --> 0
a * 1 --> a
end
using BenchmarkTools
p = SaturationParams(; timer = false)
function simpl(ex)
g = EGraph(ex)
saturate!(g, t, p)
extract!(g, astsize)
end
ex = :(0 + (1 * foo) * 0 + (a * 0) + a)
simpl(ex)
@btime simpl(ex) 94.462 μs (1412 allocations: 66.08 KiB) Rust code use egg::{rewrite as rw, *};
//use std::time::Duration;
fn main() {
env_logger::init();
use egg::*;
define_language! {
enum SimpleLanguage {
Num(i32),
"+" = Add([Id; 2]),
"*" = Mul([Id; 2]),
Symbol(Symbol),
}
}
fn make_rules() -> Vec<Rewrite<SimpleLanguage, ()>> {
vec![
rewrite!("commute-add"; "(+ ?a ?b)" => "(+ ?b ?a)"),
rewrite!("commute-mul"; "(* ?a ?b)" => "(* ?b ?a)"),
rewrite!("add-0"; "(+ ?a 0)" => "?a"),
rewrite!("mul-0"; "(* ?a 0)" => "0"),
rewrite!("mul-1"; "(* ?a 1)" => "?a"),
]
}
/// parse an expression, simplify it using egg, and pretty print it back out
fn simplify(s: &str) -> String {
// parse the expression, the type annotation tells it which Language to use
let expr: RecExpr<SimpleLanguage> = s.parse().unwrap();
// simplify the expression using a Runner, which creates an e-graph with
// the given expression and runs the given rules over it
let runner = Runner::default().with_expr(&expr).run(&make_rules());
// the Runner knows which e-class the expression given with `with_expr` is in
let root = runner.roots[0];
// use an Extractor to pick the best element of the root eclass
let extractor = Extractor::new(&runner.egraph, AstSize);
let (best_cost, best) = extractor.find_best(root);
println!("Simplified {} to {} with cost {}", expr, best, best_cost);
best.to_string()
}
// assert_eq!(simplify("(* 0 42)"), "0");
let apply_time: std::time::Instant = instant::Instant::now();
// assert_eq!(simplify("(+ 0 (* 1 foo))"), "foo");
assert_eq!(simplify("(+ (+ (+ 0 (* (* 1 foo) 0)) (* a 0)) a)"), "a");
let apply_time = apply_time.elapsed().as_secs_f64();
println!("simplification time {}", apply_time);
} simplification time 0.001375786 seconds which is 1375.786microseconds 1375.786 / 94.462 = 14.56x faster well |
@gkronber I have just updated this branch to include the latest release of https://github.com/JuliaSymbolics/TermInterface.jl - the interface for custom types has changed, please let me know if you encounter any issue |
Thanks for the heads up. I only had to make minor changes because of the changed names for functions in VecExpr. |
@0x0f0f0f Can you summarize the changes in this PR? What's the huge number of deletions from? And what's the huge performance gain from? This is awesome. |
@shashi I removed some unnecessary parts of the codebase, and basically changed the core types used for rewriting. The trick for performance was basically packing e-nodes in Also some algorithms were updated, as the egg repo now has more efficient versions of parts of equality saturation (rebuilding) that were in the original paper |
I will hold a 5 min lightning talk on thursday 6 pm CET https://egraphs.org/ if interested |
For fun, I benchmarked this PR julia> @benchmark simpl(ex)
BenchmarkTools.Trial: 10000 samples with 1 evaluation.
Range (min … max): 74.508 μs … 8.173 ms ┊ GC (min … max): 0.00% … 97.73%
Time (median): 80.918 μs ┊ GC (median): 0.00%
Time (mean ± σ): 87.298 μs ± 150.197 μs ┊ GC (mean ± σ): 5.42% ± 3.34%
▂▃▂ ▄▇█▇▆▆▆▅▄▅▅▅▄▃▃▃▂▂▂▁▁▁ ▁▁▁▁ ▁ ▂
█████▆▇██████████████████████████████▇▇▇▇▇▇█▇▇▆▆▆▆▅▆▄▅▂▅▂▄▅▅ █
74.5 μs Histogram: log(frequency) by time 107 μs <
Memory estimate: 55.08 KiB, allocs estimate: 1003. > target/release/eggvsmetatheory (base)
Simplified (+ (+ (+ 0 (* (* 1 foo) 0)) (* a 0)) a) to a with cost 1
simplification time 46.603975 us It's still slower than egg for that example, but this is a huge improvement compared to being like 300x slower the last time I compared them. I modified the Rust script so that we aren't benchmarking printing, and also taking the average of 1000 runs: let apply_time: std::time::Instant = instant::Instant::now();
for _i in 0..1000 {
simplify("(+ (+ (+ 0 (* (* 1 foo) 0)) (* a 0)) a)", false);
}
let apply_time = apply_time.elapsed().as_secs_f64();
println!("simplification time {} us", apply_time*1e3); where |
Let's go!!! |
@chriselrod we just published a preprint with some results here https://arxiv.org/pdf/2404.08751.pdf @nmheim is working on https://github.com/nmheim/egg-benchmark which should be the repository containing benchmarks for egg against the ones in the |
Fixed iterate() implementation for OptBuffer.
@0x0f0f0f just wanted to let you know I am very excited to see movement here 😊 |
…lics/Metatheory.jl into ale/3.0-ematch-hashes
…ses to wrapped vector v.
…lics/Metatheory.jl into ale/3.0-ematch-hashes
Ale/3.0 ematch hashes
Ale/3.0 optimize pat
Update docs for egraph semantic analysis.
Release 3.0 when merged