-
-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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