[−][src]Struct egg::Runner
Faciliates running rewrites over an EGraph
.
One use for EGraph
s is as the basis of a rewriting system.
Since an egraph never "forgets" state when applying a Rewrite
, you
can apply many rewrites many times quite efficiently.
After the egraph is "full" (the rewrites can no longer find new
equalities) or some other condition, the egraph compactly represents
many, many equivalent expressions.
At this point, the egraph is ready for extraction (see Extractor
)
which can pick the represented expression that's best according to
some cost function.
This technique is called equality saturation in general. However, there can be many challenges in implementing this "outer loop" of applying rewrites, mostly revolving around which rules to run and when to stop.
Runner
is egg
's provided equality saturation engine that has
reasonable defaults and implements many useful things like saturation
checking, egraph size limits, and customizable rule
scheduling.
Consider using Runner
before rolling your own outer loop.
Here are some of the things Runner
does for you:
-
Saturation checking
Runner
checks to see if any of the rules added anything new to theEGraph
. If none did, then it stops, returningStopReason::Saturated
. -
Iteration limits
You can set a upper limit of iterations to do in case the search doesn't stop for some other reason. If this limit is hit, it stops with
StopReason::IterationLimit
. -
EGraph
size limitYou can set a upper limit on the number of enodes in the egraph. If this limit is hit, it stops with
StopReason::NodeLimit
. -
Time limit
You can set a time limit on the runner. If this limit is hit, it stops with
StopReason::TimeLimit
. -
Rule scheduling
Some rules enable themselves, blowing up the
EGraph
and preventing other rewrites from running as many times. To prevent this, you can provide your ownRewriteScheduler
to govern when to run which rules.BackoffScheduler
is the default scheduler.
Runner
generates Iteration
s that record some data about
each iteration.
You can add your own data to this by implementing the
IterationData
trait.
Runner
is generic over the IterationData
that it will be in the
Iteration
s, but by default it uses ()
.
Example
use egg::{*, rewrite as rw}; define_language! { enum SimpleLanguage { Num(i32), "+" = Add([Id; 2]), "*" = Mul([Id; 2]), Symbol(String), } } let rules: &[Rewrite<SimpleLanguage, ()>] = &[ rw!("commute-add"; "(+ ?a ?b)" => "(+ ?b ?a)"), rw!("commute-mul"; "(* ?a ?b)" => "(* ?b ?a)"), rw!("add-0"; "(+ ?a 0)" => "?a"), rw!("mul-0"; "(* ?a 0)" => "0"), rw!("mul-1"; "(* ?a 1)" => "?a"), ]; pub struct MyIterData { smallest_so_far: usize, } type MyRunner = Runner<SimpleLanguage, (), MyIterData>; impl IterationData<SimpleLanguage, ()> for MyIterData { fn make(runner: &MyRunner) -> Self { let root = runner.roots[0]; let mut extractor = Extractor::new(&runner.egraph, AstSize); MyIterData { smallest_so_far: extractor.find_best(root).0, } } } let start = "(+ 0 (* 1 foo))".parse().unwrap(); // Runner is customizable in the builder pattern style. let runner = MyRunner::new(Default::default()) .with_iter_limit(10) .with_node_limit(10_000) .with_expr(&start) .with_scheduler(SimpleScheduler) .run(&rules); // Now we can check our iteration data to make sure that the cost only // got better over time for its in runner.iterations.windows(2) { assert!(its[0].data.smallest_so_far >= its[1].data.smallest_so_far); } println!( "Stopped after {} iterations, reason: {:?}", runner.iterations.len(), runner.stop_reason );
Fields
egraph: EGraph<L, N>
The EGraph
used.
iterations: Vec<Iteration<IterData>>
Data accumulated over each Iteration
.
roots: Vec<Id>
The roots of expressions added by the
with_expr
method, in insertion order.
stop_reason: Option<StopReason>
Why the Runner
stopped. This will be None
if it hasn't
stopped yet.
Implementations
impl<L, N, IterData> Runner<L, N, IterData> where
L: Language,
N: Analysis<L>,
IterData: IterationData<L, N>,
[src]
L: Language,
N: Analysis<L>,
IterData: IterationData<L, N>,
pub fn new(analysis: N) -> Self
[src]
Create a new Runner
with the given analysis and default parameters.
pub fn with_iter_limit(self, iter_limit: usize) -> Self
[src]
Sets the iteration limit. Default: 30
pub fn with_node_limit(self, node_limit: usize) -> Self
[src]
Sets the egraph size limit (in enodes). Default: 10,000
pub fn with_time_limit(self, time_limit: Duration) -> Self
[src]
Sets the runner time limit. Default: 5 seconds
pub fn with_scheduler(
self,
scheduler: impl RewriteScheduler<L, N> + 'static
) -> Self
[src]
self,
scheduler: impl RewriteScheduler<L, N> + 'static
) -> Self
Change out the RewriteScheduler
used by this Runner
.
The default one is BackoffScheduler
.
pub fn with_expr(self, expr: &RecExpr<L>) -> Self
[src]
Add an expression to the egraph to be run.
The eclass id of this addition will be recorded in the
roots
field, ordered by
insertion order.
pub fn with_egraph(self, egraph: EGraph<L, N>) -> Self
[src]
Replace the EGraph
of this Runner
.
pub fn run(self, rules: &[Rewrite<L, N>]) -> Self
[src]
Run this Runner
until it stops.
After this, the field
stop_reason
is guaranteeed to be
set.
pub fn print_report(&self)
[src]
Prints some information about a runners run.
impl<L, N, IterData> Runner<L, N, IterData> where
L: Language,
N: Analysis<L>,
[src]
L: Language,
N: Analysis<L>,
pub fn check_goals(&self, goals: &[RecExpr<L>])
[src]
Trait Implementations
Auto Trait Implementations
impl<L, N, IterData = ()> !RefUnwindSafe for Runner<L, N, IterData>
impl<L, N, IterData = ()> !Send for Runner<L, N, IterData>
impl<L, N, IterData = ()> !Sync for Runner<L, N, IterData>
impl<L, N, IterData> Unpin for Runner<L, N, IterData> where
IterData: Unpin,
L: Unpin,
N: Unpin,
IterData: Unpin,
L: Unpin,
N: Unpin,
impl<L, N, IterData = ()> !UnwindSafe for Runner<L, N, IterData>
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,