Module prelude

Module prelude 

Source
Expand description

Rust entry point for egglog.

use egglog::prelude::*;

Most workflows are best expressed as an egglog program parsed and run via crate::EGraph::parse_and_run_program: declare your sorts, functions, and rules once in egglog text, then call into the database from Rust around it.

use egglog::prelude::*;
let mut eg = EGraph::default();
eg.parse_and_run_program(
    None,
    "(datatype Math (Num i64) (Add Math Math))
     (Add (Num 1) (Num 2))",
)?;

Three cases need a Rust escape from the language:

  1. Driving the e-graph database directly — building rows, looking them up, iterating tables, running ad-hoc queries from Rust between (or instead of) running egglog rules.
  2. Custom rules whose right-hand side runs Rust — a rust_rule / rust_rule_full callback fires on every match and gets a state handle to read/write the database. Useful when the rule body needs arithmetic, control flow, or data conversion that’s awkward in egglog itself.
  3. Custom primitives callable from egglog expressions — new functions (e.g. arithmetic on a custom Rust type, an FFI call, a cost computation) that you want to invoke from egglog code as if they were built-ins. See “Extending egglog” below.

Cases 1 and 2 share the same surface: the crate::Read and crate::Write capability traits, implemented on the crate::PureState / crate::ReadState / crate::WriteState / crate::FullState wrappers. Inside a rule callback you receive one of those wrappers directly; outside a rule you get a crate::FullState from crate::EGraph::update:

use egglog::prelude::*;
let mut eg = EGraph::default();
eg.parse_and_run_program(None, "(function f (i64) i64 :no-merge)")?;

// Stage writes; flush once when the closure returns.
eg.update(|mut fs| fs.set("f", (1_i64,), 42_i64))?;

// Read in a separate `update` call — writes inside a closure
// aren't visible to reads in the same closure.
let v = eg.update(|fs| fs.lookup("f", 1_i64))?;
assert_eq!(v.map(|v| eg.value_to_base::<i64>(v)), Some(42));

§Adding and reading facts

Methods on crate::Read and crate::Write, available via the state wrappers:

§Iterating and querying

  • crate::Read::function_entries visits each entry of a function table via a callback, exposing inputs / output as raw Values.
  • crate::Read::constructor_enodes visits each enode of a constructor / relation table, exposing children / eclass.
  • crate::EGraph::query runs a one-shot pattern query and returns one HashMap<String, Value> per match, keyed by variable name. Useful for extracting bindings without compiling a persistent rule.

§Extracting terms

Pulling a Rust-side term out of an eclass:

See the crate::extract module for the full API (crate::extract::TreeExtractor, variant extraction, sort-restricted extraction, custom cost types).

To get the (sort, Value) pair an extract_value call needs in the first place, the easiest path is to let-bind a global name in egglog and then resolve it with crate::EGraph::eval_expr:

use egglog::prelude::*;
let mut eg = EGraph::default();
eg.parse_and_run_program(
    None,
    "(datatype Math (Num i64) (Add Math Math))
     (let $root (Add (Num 1) (Num 2)))",
)?;
let (sort, value) = eg.eval_expr(&exprs::var("$root"))?;
let (_dag, _term, _cost) = eg.extract_value(&sort, value)?;

§Rules

  • rule — add a rule whose RHS is egglog code.
  • rust_rule — add a rule whose RHS is a Rust closure Fn(WriteState, &[Value]) -> Option<()>. Seminaive-safe.
  • rust_rule_full — same but the closure receives a crate::FullState (can read the database in the callback). Runs :naive since the body sees live state.
  • run_ruleset / add_ruleset step rules forward.

§Extending egglog

§Caveat: type unsafety at the column level

Eclass identifiers flow through the API as bare Values. A Value returned from a Math constructor and a Value returned from a List constructor are indistinguishable at compile time and at runtime — callers track sort identity themselves. crate::Write::union does not check that its arguments are the same eq-sort; crate::Write::set and crate::Write::add do not check that their column values match the table’s declared column sorts. Arity (column count) and subtype (function vs. constructor) are checked at runtime via crate::ApiError.

Re-exports§

pub use egglog::ast::Action;
pub use egglog::ast::Fact;
pub use egglog::ast::Facts;
pub use egglog::sort::BigIntSort;
pub use egglog::sort::BigRatSort;
pub use egglog::sort::BoolSort;
pub use egglog::sort::F64Sort;
pub use egglog::sort::I64Sort;
pub use egglog::sort::StringSort;
pub use egglog::sort::UnitSort;
pub use egglog::CommandMacro;
pub use egglog::CommandMacroRegistry;
pub use egglog::Core;
pub use egglog::FullState;
pub use egglog::PureState;
pub use egglog::Read;
pub use egglog::ReadState;
pub use egglog::Write;
pub use egglog::WriteState;
pub use egglog::EGraph;
pub use egglog::sort;
pub use egglog::sort;

Modules§

exprs

Macros§

action
actions
datatype
Adds sorts and constructor tables to the database.
expr
fact
facts
sort
span
vars

Structs§

GenericActions
RustSpan

Enums§

Span

Traits§

BaseSort
A “default” implementation of Sort for simple types which just want to put some data in the e-graph. If you implement this trait, do not implement Sort or ContainerSort. Use add_base_sortto register base sorts with theEGraph. See Sortfor documentation of the methods. Do not overrideto_arcsort`.
ContainerSort
A “default” implementation of Sort for types which just want to store a pure data structure in the e-graph. If you implement this trait, do not implement Sort or BaseSort. Use add_container_sort to register container sorts with the EGraph. See Sort for documentation of the methods. Do not override to_arcsort.
LiteralConvertible
Trait for types that can be converted to/from Literal for use in validated primitives. This enables automatic validator generation for literal primitives.

Functions§

add_base_sort
Add a BaseSort to the e-graph
add_constructor
Declare a new constructor table.
add_container_sort
add_function
Declare a new function table.
add_relation
Declare a new relation table.
add_ruleset
Create a new ruleset.
add_sort
Declare a new sort.
rule
Add a rule to the e-graph whose right-hand side is made up of actions.
run_ruleset
Run one iteration of a ruleset.
rust_rule
Add a rule to the e-graph whose right-hand side is a Rust callback.
rust_rule_full
Like rust_rule, but the action callback receives a FullState — it can read tables (ctx.lookup) in addition to writing them. Action callbacks of FullPrim are only valid in Context::Full, so this helper marks the generated rule :naive: the body matches against the entire database every iteration instead of using the seminaive delta. Use this when the action genuinely needs to look up rows; prefer rust_rule when the data can be bound via the matcher in the rule body.