moon_egg

E-graph implementation in MoonBit

egraphs
rewrite-system
Download zip
Author
Version
0.1.0
License
Apache-2.0
Last updated
7 months ago
Downloads
29

#Moon E-graphs

Moon egg uses e-graphs to provide a new way to build program optimizers and synthesizers.

The projects port egg (a Rust e-graph library) to MoonBit, but due to the differences in the languages and ecosystems, it is not a direct translation. (e.g. Most trait abstraction in egg is replaced with simple interfaces in moon_egg).

#Warning

Most code is LLM-generated and may contain bugs. Use at your own risk.

type Id = Int

Identifier for an e-class.

ParseError

pub(all) suberror ParseError {
UnexpectedEof
UnexpectedChar(Int, Char)
ExpectedRParen(Int)
}

impl Show for ParseError

Analysis

pub(all) struct Analysis {
make : (ENode, (Int) -> Data?) -> Data
merge : (Data, Data) -> Data
modify : (EGraph, Int) -> Unit
}

Per-eclass analysis callbacks.

Applier

pub struct Applier {
apply : (EGraph, Map[String, Int]) -> Int raise
}

Applier::apply

fn Applier::apply(self : Applier, egraph : EGraph, subst : Map[String, Int]) -> Int raise

Applier::from_fn

fn Applier::from_fn(f : (EGraph, Map[String, Int]) -> Int raise) -> Applier

Applier::pattern

fn Applier::pattern(rhs : Pattern) -> Applier

Data

pub(all) struct Data {
free : Map[Int, Bool]
constant : Value?
}

Per-eclass analysis data.
impl Show for Data

EClass

pub struct EClass {
id : Int
nodes : Array[Int]
data : Data
}

EGraph

#alias(SimpleGraph)
pub struct EGraph {
uf : UnionFind
classes : Map[Int, EClass]
memo : Map[NodeKey, Int]
nodes : Array[ENode]
node_classes : Array[Int]
dirty : Bool
analysis : Analysis
allow_cycles : Bool
}

EGraph::add

fn EGraph::add(self : EGraph, enode : ENode) -> Int

EGraph::add_expr

fn EGraph::add_expr(self : EGraph, expr : Expr) -> Int

EGraph::allow_cycles

fn EGraph::allow_cycles(self : EGraph) -> Bool

EGraph::are_equivalent

fn EGraph::are_equivalent(self : EGraph, a : Int, b : Int) -> Bool

EGraph::class_for

fn EGraph::class_for(self : EGraph, id : Int) -> EClass?

EGraph::class_ids

fn EGraph::class_ids(self : EGraph) -> Array[Int]

EGraph::data

fn EGraph::data(self : EGraph, id : Int) -> Data?

EGraph::find

fn EGraph::find(self : EGraph, id : Int) -> Int

EGraph::find_read

fn EGraph::find_read(self : EGraph, id : Int) -> Int

EGraph::lookup

fn EGraph::lookup(self : EGraph, enode : ENode) -> Int?

Lookup an existing enode without mutating the e-graph.

EGraph::new

fn EGraph::new() -> EGraph

EGraph::new_with

fn EGraph::new_with(analysis : Analysis) -> EGraph

EGraph::rebuild

fn EGraph::rebuild(self : EGraph) -> Unit

EGraph::set_allow_cycles

fn EGraph::set_allow_cycles(self : EGraph, allow : Bool) -> Unit

EGraph::union

fn EGraph::union(self : EGraph, a : Int, b : Int) -> Int

ENode

pub struct ENode {
op : NodeOp
children : Array[Int]
}

impl Eq for ENode
impl Hash for ENode
impl Show for ENode

ENodeOrReg

pub enum ENodeOrReg {
Node(ENode)
Reg(Int)
}

ExplainEdge

pub struct ExplainEdge {
from : Int
to : Int
rewrite : String
iter : Int
subst : Map[String, Int]
}

impl Show for ExplainEdge

ExplainStep

pub struct ExplainStep {
iter : Int
rewrite : String
root_before : Int
rhs_id : Int
subst : Map[String, Int]
}

impl Show for ExplainStep

Explanation

pub struct Explanation {
steps : Array[ExplainStep]
edges : Map[Int, Array[ExplainEdge]]
}

Explanation::explain_path

fn Explanation::explain_path(self : Explanation, start : Int, goal : Int) -> Array[ExplainEdge]

Attempt to find a justification path between two e-class ids.

Explanation::format_path

fn Explanation::format_path(self : Explanation, egraph : EGraph, start : Int, goal : Int) -> String

Pretty format a justification path between two e-classes, if any.

Explanation::has_path

fn Explanation::has_path(self : Explanation, egraph : EGraph, a : Int, b : Int) -> Bool

Explanation::new

Explanation::record

fn Explanation::record(self : Explanation, step : ExplainStep) -> Unit

Explanation::steps

Expr

pub enum Expr {
Leaf(String)
Node(String, Array[Expr])
}

impl Eq for Expr
impl Show for Expr

Expr::to_sexpr

fn Expr::to_sexpr(self : Expr) -> String

Instruction

pub enum Instruction {
Bind(NodeOp, Int, Int, Int)
Compare(Int, Int)
Lookup(Array[ENodeOrReg], Int)
Scan(Int)
}

Instruction program for the backtracking matcher.

IterationReport

pub struct IterationReport {
iter : Int
matched : Map[String, Int]
applied : Map[String, Int]
total_matched : Int
total_applied : Int
node_count : Int
class_count : Int
saturated : Bool
}

Match

pub(all) struct Match {
root : Int
subst : Map[String, Int]
}

impl Show for Match

MultiApplier

pub struct MultiApplier {
asts : Array[(String, Pattern)]
}

MultiApplier::apply

fn MultiApplier::apply(self : MultiApplier, egraph : EGraph, subst : Map[String, Int]) -> Int raise

MultiPattern

pub struct MultiPattern {
asts : Array[(String, Pattern)]
program : Program
}

Multi-pattern support (datalog-style rules)

MultiPattern::n_matches

fn MultiPattern::n_matches(self : MultiPattern, egraph : EGraph) -> Int

MultiPattern::new

fn MultiPattern::new(asts : Array[(String, Pattern)]) -> MultiPattern

MultiPattern::search

fn MultiPattern::search(self : MultiPattern, egraph : EGraph) -> Array[Match]

NodeKey

type NodeKey

impl Eq for NodeKey
impl Hash for NodeKey

NodeOp

pub enum NodeOp {
Name(String)
Symbol(String)
Number(Float)
}

impl Eq for NodeOp
impl Hash for NodeOp
impl Show for NodeOp

NodeOp::label

fn NodeOp::label(self : NodeOp) -> String

Pattern

pub enum Pattern {
Wild
Var(String)
VarIf(String, (Int) -> Bool)
Sym(String)
Num(Float)
Node(String, Array[Pattern])
}

Program

pub struct Program {
instructions : Array[Instruction]
subst : Map[String, Int]
var_if : Map[String, (Int) -> Bool]
}

Program::compile_from_multi

fn Program::compile_from_multi(patterns : Array[(String, Pattern)]) -> Program

Program::compile_from_pattern

fn Program::compile_from_pattern(pat : Pattern) -> Program

Program::run_with_limit

fn Program::run_with_limit(self : Program, egraph : EGraph, eclass : Int, limit? : Int?) -> Array[Map[String, Int]]

Rewrite

pub struct Rewrite {
name : String
searcher : Searcher
applier : Applier
condition : (EGraph, Map[String, Int]) -> Bool
}

Rewrite::apply_all

fn Rewrite::apply_all(self : Rewrite, egraph : EGraph) -> Int raise

Rewrite::apply_all_stats

fn Rewrite::apply_all_stats(self : Rewrite, egraph : EGraph, on_applied? : (Match, Int) -> Unit) -> RewriteStats raise

Rewrite::apply_filtered

fn Rewrite::apply_filtered(self : Rewrite, egraph : EGraph, pred : (Match) -> Bool, on_applied? : (Match, Int) -> Unit, root_first? : Int?, limit? : Int?) -> RewriteStats raise

Apply rewrite to matches that satisfy predicate (e.g., reachable from root).

Rewrite::from_parts

fn Rewrite::from_parts(name : String, searcher : Searcher, applier : Applier, condition? : (EGraph, Map[String, Int]) -> Bool) -> Rewrite

Rewrite::new

fn Rewrite::new(name : String, lhs : Pattern, rhs : Pattern) -> Rewrite

Rewrite::search

fn Rewrite::search(self : Rewrite, egraph : EGraph) -> Array[Match]

Rewrite::with_condition

fn Rewrite::with_condition(name : String, lhs : Pattern, rhs : Pattern, condition : (EGraph, Map[String, Int]) -> Bool) -> Rewrite

RewriteStats

pub struct RewriteStats {
name : String
matched : Int
applied : Int
}

RunConfig

pub struct RunConfig {
iter_limit : Int
node_limit : Int?
match_limit : Int?
worklist : Worklist
allow_ematching_cycles : Bool
}

RunConfig::default

fn RunConfig::default() -> RunConfig

RunConfig::new

fn RunConfig::new(iter_limit : Int, node_limit? : Int?, match_limit? : Int?, worklist? : Worklist, allow_ematching_cycles? : Bool) -> RunConfig

RunResult

pub struct RunResult {
egraph : EGraph
root : Int
iterations : Int
stop_reason : StopReason
applied : Map[String, Int]
total_applied : Int
reports : Array[IterationReport]
explanation : Explanation
}

Runner

pub struct Runner {
rewrites : Array[Rewrite]
queue : Array[Rewrite]
egraph : EGraph
root : Int
config : RunConfig
backoff : Map[String, Int]
last_applied : Map[String, Int]
}

Runner::new

fn Runner::new(expr : Expr, rewrites : Array[Rewrite], config? : RunConfig) -> Runner

Runner::run

fn Runner::run(self : Runner) -> RunResult raise

Searcher

pub struct Searcher {
run : (EGraph) -> Array[Match]
}

Searcher::filter

fn Searcher::filter(self : Searcher, pred : (EGraph, Map[String, Int]) -> Bool) -> Searcher

Searcher::multi

fn Searcher::multi(patterns : Array[Pattern]) -> Searcher

Searcher::pattern

fn Searcher::pattern(lhs : Pattern) -> Searcher

Searcher::pattern_with

fn Searcher::pattern_with(lhs : Pattern, pred : (EGraph, Map[String, Int]) -> Bool) -> Searcher

Searcher::search

fn Searcher::search(self : Searcher, egraph : EGraph) -> Array[Match]

Searcher::with_binding

fn Searcher::with_binding(self : Searcher, binder : (EGraph, Map[String, Int]) -> (String, Int)?) -> Searcher

StopReason

pub enum StopReason {
Saturated
IterationLimit
NodeLimit
MatchLimit
}

impl Eq for StopReason
impl Show for StopReason

TodoKey

type TodoKey

Key for pending pattern nodes during compilation.
impl Eq for TodoKey
impl Hash for TodoKey

UnionFind

pub struct UnionFind {
parents : Array[Int]
sizes : Array[Int]
}

A simple union-find with path compression and union by size.
impl Show for UnionFind

UnionFind::find

fn UnionFind::find(self : UnionFind, id : Int) -> Int

UnionFind::find_read

fn UnionFind::find_read(self : UnionFind, id : Int) -> Int

UnionFind::make_set

fn UnionFind::make_set(self : UnionFind) -> Int

UnionFind::new

fn UnionFind::new() -> UnionFind

UnionFind::union

fn UnionFind::union(self : UnionFind, a : Int, b : Int) -> Int

Value

pub(all) enum Value {
Num(Float)
Bool(Bool)
}

Analysis payload supporting numeric and boolean constants plus free-variable sets.
impl Eq for Value
impl Show for Value

Worklist

pub(all) enum Worklist {
All
Queue
Backoff
Greedy
Recent
}

impl Eq for Worklist
impl Show for Worklist

bool_analysis

fn bool_analysis() -> Analysis

Boolean constant folding for propositional logic tests.

build_rhs

fn build_rhs(pat : Pattern, egraph : EGraph, subst : Map[String, Int]) -> Int raise

constant_analysis

fn constant_analysis() -> Analysis

data_bool

fn data_bool(d : Data?) -> Bool?

data_num

fn data_num(d : Data?) -> Float?

default_analysis

fn default_analysis() -> Analysis

default_cost

fn default_cost(op : NodeOp, child_costs : Array[Int]) -> Int

expr_leaf

fn expr_leaf(name : String) -> Expr

expr_node

fn expr_node(op : String, children : Array[Expr]) -> Expr

extract_best

fn extract_best(egraph : EGraph, root : Int, cost_fn? : (NodeOp, Array[Int]) -> Int) -> (Int, Expr) raise

intersect_free

fn intersect_free(a : Map[Int, Bool], b : Map[Int, Bool]) -> Map[Int, Bool]

is_const

fn is_const(name : String) -> ((EGraph, Map[String, Int]) -> Bool)

is_const_or_distinct

fn is_const_or_distinct(name : String, other : String) -> ((EGraph, Map[String, Int]) -> Bool)

is_not_zero

fn is_not_zero(name : String) -> ((EGraph, Map[String, Int]) -> Bool)

is_sym

fn is_sym(name : String) -> ((EGraph, Map[String, Int]) -> Bool)

lambda_analysis

fn lambda_analysis() -> Analysis

Lambda analysis tracking free variables and simple constant folding.

make_enode

fn make_enode(op : String, children : Array[Int]) -> ENode

make_number

fn make_number(n : Float) -> ENode

make_symbol

fn make_symbol(sym : String) -> ENode

math_rules

fn math_rules() -> Array[Rewrite] raise

merge_data

fn merge_data(left : Data, right : Data) -> Data

multi_applier

fn multi_applier(asts : Array[(String, Pattern)]) -> MultiApplier

multi_rewrite

fn multi_rewrite(name : String, lhs : String, rhs : String) -> Rewrite raise

multipattern_searcher

fn multipattern_searcher(mp : MultiPattern) -> Searcher

parse_multipattern

fn parse_multipattern(s : String) -> MultiPattern raise
Parse a multipattern string like "?x = pat1 = pat2, ?y = pat3".

parse_pattern

fn parse_pattern(expr : Expr) -> Pattern raise

parse_sexpr

fn parse_sexpr(s : String) -> Expr raise ParseError

pat_node

fn pat_node(op : String, children : Array[Pattern]) -> Pattern

pat_num

fn pat_num(n : Float) -> Pattern

pat_sym

fn pat_sym(name : String) -> Pattern

pat_var

fn pat_var(name : String) -> Pattern

pat_var_if

fn pat_var_if(name : String, pred : (Int) -> Bool) -> Pattern

pat_wild

fn pat_wild() -> Pattern

reachable_classes

fn reachable_classes(egraph : EGraph, root : Int) -> Map[Int, Bool]

Return ids reachable from the given root via enode children.

rhs_mp_applier

fn rhs_mp_applier(mp : MultiPattern, eg : EGraph, subst : Map[String, Int]) -> Int raise

run

fn run(expr : Expr, rewrites : Array[Rewrite], config? : RunConfig) -> RunResult raise

run_rewrites

fn run_rewrites(expr : Expr, rewrites : Array[Rewrite], iter_limit? : Int) -> (EGraph, Int) raise

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io