Function rust_rule

Source
pub fn rust_rule(
    egraph: &mut EGraph,
    rule_name: &str,
    ruleset: &str,
    vars: &[(&str, ArcSort)],
    facts: Facts<String, String>,
    func: impl Fn(&mut RustRuleContext<'_, '_>, &[Value]) -> Option<()> + Clone + Send + Sync + 'static,
) -> Result<Vec<CommandOutput>, Error>
Expand description

Add a rule to the e-graph whose right-hand side is a Rust callback.

use egglog::prelude::*;

let mut egraph = EGraph::default();
egraph.parse_and_run_program(
    None,
    "
(function fib (i64) i64 :no-merge)
(set (fib 0) 0)
(set (fib 1) 1)
(rule (
    (= f0 (fib x))
    (= f1 (fib (+ x 1)))
) (
    (set (fib (+ x 2)) (+ f0 f1))
))
(run 10)
    ",
)?;

let big_number = 20;

// check that `(fib 20)` is not in the e-graph
let results = query(
    &mut egraph,
    vars![f: i64],
    facts![(= (fib (unquote exprs::int(big_number))) f)],
)?;

assert!(results.iter().next().is_none());

let ruleset = "custom_ruleset";
add_ruleset(&mut egraph, ruleset)?;

// add the rule from `build_test_database` to the egraph
rust_rule(
    &mut egraph,
    "fib_rule",
    ruleset,
    vars![x: i64, f0: i64, f1: i64],
    facts![
        (= f0 (fib x))
        (= f1 (fib (+ x 1)))
    ],
    move |ctx, values| {
        let [x, f0, f1] = values else { unreachable!() };
        let x = ctx.value_to_base::<i64>(*x);
        let f0 = ctx.value_to_base::<i64>(*f0);
        let f1 = ctx.value_to_base::<i64>(*f1);

        let y = ctx.base_to_value::<i64>(x + 2);
        let f2 = ctx.base_to_value::<i64>(f0 + f1);
        ctx.insert("fib", [y, f2].into_iter());

        Some(())
    },
)?;

// run that rule 10 times
for _ in 0..10 {
    run_ruleset(&mut egraph, ruleset)?;
}

// check that `(fib 20)` is now in the e-graph
let results = query(
    &mut egraph,
    vars![f: i64],
    facts![(= (fib (unquote exprs::int(big_number))) f)],
)?;

let y = egraph.base_to_value::<i64>(6765);
let results: Vec<_> = results.iter().collect();
assert_eq!(results, [[y]]);