moon_egg

E-graph implementation in MoonBit

egraphs
rewrite-system
moon add CAIMEOX/moon_egg@0.1.0
Download zip
Author
Version
0.1.0
License
Apache-2.0
Last updated
6 months ago
Downloads
27
README

#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