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]]);