Skip to content
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

Open
wants to merge 368 commits into
base: master
Choose a base branch
from
Open

3.0 Release #185

wants to merge 368 commits into from

Conversation

0x0f0f0f
Copy link
Member

Release 3.0 when merged

@codecov-commenter
Copy link

codecov-commenter commented Jan 14, 2024

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

Attention: Patch coverage is 89.00316% with 139 lines in your changes missing coverage. Please review.

Project coverage is 82.28%. Comparing base (a8331d6) to head (f687b00).
Report is 536 commits behind head on master.

Files with missing lines Patch % Lines
src/EGraphs/Schedulers.jl 43.47% 26 Missing ⚠️
src/EGraphs/egraph.jl 88.88% 25 Missing ⚠️
src/utils.jl 11.11% 16 Missing ⚠️
src/Syntax.jl 92.10% 12 Missing ⚠️
src/Patterns.jl 87.34% 10 Missing ⚠️
src/Rules.jl 84.61% 8 Missing ⚠️
ext/Plotting.jl 0.00% 6 Missing ⚠️
src/EGraphs/saturation.jl 95.45% 6 Missing ⚠️
src/Rewriters.jl 53.84% 6 Missing ⚠️
src/ematch_compiler.jl 96.34% 6 Missing ⚠️
... and 6 more

❗ 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.
📢 Have feedback on the report? Share it here.

Copy link

github-actions bot commented Jan 14, 2024

Benchmark Results

egg-sym egg-cust MT@f687b005cd3... MT@46f2c2fd53e... egg-sym/MT@f68... egg-cust/MT@f6... MT@46f2c2fd53e...
egraph_addexpr 1.42 ms 5.15 ms 14.5 ms 0.276 2.81
basic_maths_simpl2 13.8 ms 5.18 ms 21.2 ms 828 ms 0.651 0.244 39
prop_logic_freges_theorem 2.55 ms 1.55 ms 2.31 ms 36.1 ms 1.1 0.673 15.7
calc_logic_demorgan 61 μs 34.2 μs 80.5 μs 523 μs 0.758 0.425 6.5
calc_logic_freges_theorem 22.3 ms 11.3 ms 40.2 ms 1.68e+04 ms 0.554 0.28 417
basic_maths_simpl1 6.48 ms 2.87 ms 4.59 ms 49.6 ms 1.41 0.625 10.8
egraph_constructor 0.0879 μs 0.0975 μs 0.11 μs 0.902 1.13
prop_logic_prove1 35.8 ms 14 ms 39.2 ms 8.49e+03 ms 0.913 0.358 216
prop_logic_demorgan 79.8 μs 45.3 μs 94.9 μs 761 μs 0.841 0.477 8.02
while_superinterpreter_while_10 18.2 ms 95.3 ms 5.23
prop_logic_rewrite 112 μs 112 μs 1
time_to_load 120 ms 172 ms 1.43

Benchmark Plots

A plot of the benchmark results have been uploaded as an artifact to the workflow run for this PR.
Go to "Actions"->"Benchmark a pull request"->[the most recent run]->"Artifacts" (at the bottom).

@0x0f0f0f
Copy link
Member Author

0x0f0f0f commented Jan 14, 2024

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

@0x0f0f0f
Copy link
Member Author

0x0f0f0f commented Mar 1, 2024

@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

@gkronber
Copy link
Collaborator

gkronber commented Mar 2, 2024

@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.

@shashi
Copy link
Member

shashi commented Mar 12, 2024

@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.

@0x0f0f0f
Copy link
Member Author

@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 Vector{UInt64} such that loops (which happens hundreds of thousands of times) can be vectorized. Instead of having a struct with operation, hash, flags... fields, I just encode and pack everything into UInt64.

https://github.com/JuliaSymbolics/Metatheory.jl/blob/8f228fd0f8a5e1f97fd0ed986cb1c7e94cbce5c8/src/vecexpr.jl

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

@0x0f0f0f
Copy link
Member Author

I will hold a 5 min lightning talk on thursday 6 pm CET https://egraphs.org/ if interested

@chriselrod
Copy link
Contributor

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 simplify takes a print: bool arg for whether or not it should print.

@shashi
Copy link
Member

shashi commented Apr 17, 2024

Let's go!!!

@0x0f0f0f
Copy link
Member Author

0x0f0f0f commented Apr 18, 2024

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:

@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 benchmarks directory in repository (1-1 comparison with same hyperparameters/rules where possible).

@oameye
Copy link

oameye commented Jan 23, 2025

@0x0f0f0f just wanted to let you know I am very excited to see movement here 😊

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants