High Level: egglog#
The top level module contains the high level API for using e-graphs in Python.
The high level API is not documented yet, because adding supporting for our custom objects requires a custom AutoDoc extension.
The high level API builds on the low level API and is designed to:
Statically type check as much as possible with MyPy
Be concise to write
Feel “pythonic”
Here is the same example using the high level API:
from __future__ import annotations
from egglog import *
egraph = EGraph()
class Math(Expr):
def __init__(self, value: i64Like) -> None:
...
@classmethod
def var(cls, v: StringLike) -> Math:
...
def __add__(self, other: Math) -> Math:
...
def __mul__(self, other: Math) -> Math:
...
# expr1 = 2 * (x + 3)
expr1 = egraph.let("expr1", Math(2) * (Math.var("x") + Math(3)))
# expr2 = 6 + 2 * x
expr2 = egraph.let("expr2", Math(6) + Math(2) * Math.var("x"))
a, b, c = vars_("a b c", Math)
x, y = vars_("x y", i64)
egraph.register(
rewrite(a + b).to(b + a),
rewrite(a * (b + c)).to((a * b) + (a * c)),
rewrite(Math(x) + Math(y)).to(Math(x + y)),
rewrite(Math(x) * Math(y)).to(Math(x * y)),
)
egraph.run(10)
egraph.check(eq(expr1).to(expr2))
Package for creating e-graphs in Python.
- class egglog.Action(__egg_decls__, action)#
Bases:
objectA change to an EGraph, either unioning multiple expressions, setting the value of a function call, deleting an expression, or panicing.
- Parameters:
__egg_decls__ (
Declarations)action (
LetDecl|SetDecl|ExprActionDecl|ChangeDecl|UnionDecl|PanicDecl|SetCostDecl)
- class egglog.CostModel(*args, **kwargs)#
Bases:
Protocol,Generic[COST]A cost model for an e-graph. Used to determine the cost of an expression based on its structure and the costs of its sub-expressions.
Called with an expression and the costs of its children, returns the total cost of the expression.
Additionally, the cost model should guarantee that a term has a no-smaller cost than its subterms to avoid cycles in the extracted terms for common case usages. For more niche usages, a term can have a cost less than its subterms. As long as there is no negative cost cycle, the default extractor is guaranteed to terminate in computing the costs. However, the user needs to be careful to guarantee acyclicity in the extracted terms.
- class egglog.EGraph(*actions, seminaive=True, save_egglog_string=False)#
Bases:
objectA collection of expressions where each expression is part of a distinct equivalence class.
Can run actions, check facts, run schedules, or extract minimal cost expressions.
- all_function_sizes()#
Returns a list of all functions and their sizes.
- check(*facts)#
Check if a fact is true in the egraph.
- check_bool(*facts)#
Returns true if the facts are true in the egraph.
- check_fail(*facts)#
Checks that one of the facts is not true
- display(graphviz=False, **kwargs)#
Displays the e-graph.
If in IPython it will display it inline, otherwise it will write it to a file and open it.
- Parameters:
graphviz (
bool)kwargs (
Unpack[GraphvizKwargs])
- Return type:
- extract(expr, /, include_cost=False, cost_model=None)#
Extract the lowest cost expression from the egraph.
- extract_multiple(expr, n)#
Extract multiple expressions from the egraph.
- freeze()#
Freeze the current e-graph state for debugging.
The returned
FrozenEGraphcontains a snapshot of the current declarations and can be pretty-printed back into replayable high-level actions withstr(...).This is useful when debugging unexpected unions, sets, subsumptions, or costs after a run:
- Return type:
FrozenEGraph
>>> from egglog import * >>> class Math(Expr): ... def __init__(self, value: i64Like) -> None: ... ... >>> egraph = EGraph(Math(1)) >>> str(egraph.freeze()) 'EGraph(Math(1)).freeze()'
- function_size(fn)#
Returns the number of rows in a certain function
- function_values(fn, length=None)#
Given a callable that is a “function”, meaning it returns a primitive or has a merge set, returns a mapping of the function applied with its arguments to its values
If length is specified, only the first length values will be returned.
- has_custom_cost(fn)#
Checks if the any custom costs have been set for this expression callable.
- input(fn, path)#
Loads a CSV file and sets it as *input, output of the function.
- Parameters:
fn (
Callable[...,RuntimeClass])path (
str)
- Return type:
- let(name, expr)#
Define a new expression in the egraph and return a reference to it.
- lookup_function_value(expr)#
Given an expression that is a function call, looks up the value of the function call if it exists.
- push()#
Push the current state of the egraph, so that it can be popped later and reverted back.
- Return type:
- register(command_or_generator, *command_likes)#
Registers any number of rewrites or rules.
- Parameters:
command_or_generator (
Action|BaseExpr|Fact|RewriteOrRule|Callable[...,Iterable[RewriteOrRule]])command_likes (
Action|BaseExpr|Fact|RewriteOrRule)
- Return type:
- run(limit_or_schedule, /, *until, ruleset=None)#
Run the egraph until the given limit or until the given facts are true.
- saturate(schedule=None, *, expr=None, max=1000, visualize=True, print_frozen=False, **kwargs)#
Saturate the egraph, running the given schedule until the egraph is saturated. It serializes the egraph at each step and returns a widget to visualize the egraph.
If an expr is passed, it’s also extracted after each run and printed
- set_report_level(level)#
Set the level of detail recorded in subsequent run reports.
- exception egglog.ExprValueError(expr, allowed)#
Bases:
AttributeErrorRaised when an expression cannot be converted to a Python value because the value is not a constructor.
- class egglog.Fact(__egg_decls__, fact)#
Bases:
objectA query on an EGraph, either by an expression or an equivalence between multiple expressions.
- Parameters:
__egg_decls__ (
Declarations)fact (
EqDecl|ExprFactDecl)
- class egglog.GreedyDagCost(total, _costs)#
Bases:
Generic[DAG_COST]Cost of a DAG, which stores children costs. Use .total to get the underlying cost.
- class egglog.Ruleset(ident, _current_egg_decls=<factory>, deferred_rule_gens=<factory>)#
Bases:
ScheduleA collection of rules, which can be run as a schedule.
- Parameters:
ident (
Ident|None)_current_egg_decls (
Declarations)deferred_rule_gens (
list[Callable[[],Iterable[RewriteOrRule]]])
- _update_egg_decls()#
To return the egg decls, we go through our deferred rules and add any we haven’t yet
- Return type:
Declarations
- append(rule)#
Register a rule with the ruleset.
- Parameters:
rule (
RewriteOrRule)- Return type:
- register(rule_or_generator, *rules, _increase_frame=False)#
Register rewrites or rules, either as a function or as values.
- Parameters:
rule_or_generator (
RewriteOrRule|Callable[...,Iterable[RewriteOrRule]])rules (
RewriteOrRule)_increase_frame (
bool)
- Return type:
- class egglog.RunReport(_decls, iterations=<factory>, updated=False, search_and_apply_time_per_rule=<factory>, num_matches_per_rule=<factory>, search_and_apply_time_per_ruleset=<factory>, merge_time_per_ruleset=<factory>, rebuild_time_per_ruleset=<factory>)#
Bases:
objectPython-friendly wrapper around bindings.RunReport.
- class egglog.Schedule(__egg_decls_thunk__, schedule)#
Bases:
DelayedDeclarationsA composition of some rulesets, either composing them sequentially, running them repeatedly, running them till saturation, or running until some facts are met
- Parameters:
__egg_decls_thunk__ (
Callable[[],Declarations])schedule (
SaturateDecl|RepeatDecl|SequenceDecl|RunDecl|LetSchedulerDecl)
- class egglog.Unit(*args: object, **kwargs: object)#
Bases:
objectThe unit type. This is used to represent if a value exists in the e-graph or not.
- class egglog._EqBuilder(expr)#
Bases:
Generic[BASE_EXPR]- Parameters:
expr (
TypeVar(BASE_EXPR, bound= BaseExpr))
- class egglog._NeBuilder(lhs)#
Bases:
Generic[BASE_EXPR]- Parameters:
lhs (
TypeVar(BASE_EXPR, bound= BaseExpr))
- class egglog._SetBuilder(lhs)#
Bases:
Generic[BASE_EXPR]- Parameters:
lhs (
TypeVar(BASE_EXPR, bound= BaseExpr))
- egglog.back_off(match_limit=None, ban_length=None)#
Create a backoff scheduler configuration.
`python schedule = run(analysis_ruleset).saturate() + run(ruleset, scheduler=back_off(match_limit=1000, ban_length=5)) * 10 `This will run the analysis_ruleset until saturation, then run ruleset 10 times, using a backoff scheduler.
- egglog.birewrite(lhs, ruleset=None)#
Rewrite the given expression to a new expression and vice versa.
- Parameters:
- Return type:
_BirewriteBuilder[TypeVar(EXPR, bound= Expr)]
- egglog.check(x, schedule=None, *given)#
Verifies that the fact is true given some assumptions and after running the schedule.
- egglog.check_eq(x, y, schedule=None, *, add_second=True, display=False)#
Verifies that two expressions are equal after running the schedule.
If add_second is true, then the second expression is added to the egraph before running the schedule.
- egglog.constant(name, tp, default_replacement=None, /, *, egg_name=None, ruleset=None)#
A “constant” is implemented as the instantiation of a value that takes no args. This creates a function with name and return type tp and returns a value of it being called.
- egglog.convert(source, target)#
Convert a source object to a target type.
- egglog.converter(from_type, to_type, fn, cost=1)#
Register a converter from some type to an egglog type.
- egglog.default_cost_model(egraph, expr, children_costs)#
A default cost model for an e-graph, which looks up costs set on function calls, or uses 1 as the default cost.
- egglog.define_expr_method(name)#
Given the name of a method, explicitly defines it on the runtime type that holds Expr objects as a method.
Call this if you need a method to be defined on the type itself where overriding with __getattr__ does not suffice, like for NumPy’s __array_ufunc__.
- egglog.eq(expr)#
Check if the given expression is equal to the given value.
- Parameters:
expr (
TypeVar(BASE_EXPR, bound= BaseExpr))- Return type:
_EqBuilder[TypeVar(BASE_EXPR, bound= BaseExpr)]
- egglog.expr_parts(expr)#
Returns the underlying type and decleration of the expression. Useful for testing structural equality or debugging.
- Parameters:
expr (
BaseExpr)- Return type:
TypedExprDecl
- egglog.function(*args, **kwargs)#
Decorate a function typing stub to create an egglog function for it.
If a body is included, it will be added to the ruleset passed in as a default rewrite.
This will default to creating a “constructor” in egglog, unless a merge function is passed in or the return type is a primtive, then it will be a “function”.
- Return type:
- egglog.get_callable_args(x, fn=None)#
Gets all the arguments of an expression. If a function is provided, it will only return the arguments if the expression is a call to that function.
Note that recursively calling the arguments is the safe way to walk the expression tree.
- egglog.get_callable_fn(x)#
Gets the function of an expression, or if it’s a constant or classvar, return that.
- egglog.get_constant_name(x)#
Check if the expression is a constant and return its name. If it is not a constant, return None.
- egglog.get_cost(expr)#
Return a lookup of the cost of an expression. If not set, won’t match.
- Parameters:
expr (
BaseExpr)- Return type:
- egglog.get_let_name(x)#
Check if the expression is a let expression and return the name of the variable. If it is not a let expression, return None.
- egglog.get_literal_value(x)#
Returns the literal value of an expression if it is a literal. If it is not a literal, returns None.
- egglog.get_type_args()#
Get the type args for the type being converted.
- egglog.get_var_name(x)#
Check if the expression is a variable and return its name. If it is not a variable, return None.
- egglog.greedy_dag_cost_model(base=<function default_cost_model>)#
Creates a greedy dag cost model from a base cost model.
- Parameters:
- Return type:
- egglog.let(name, expr)#
Create a let binding.
- egglog.method(*, egg_fn=None, cost=None, merge=None, preserve=False, mutates_self=False, unextractable=False, subsume=False, reverse_args=False)#
Any method can be decorated with this to customize it’s behavior. This is only supported in classes which subclass
Expr.
- egglog.ne(expr)#
Check if the given expression is not equal to the given value.
- Parameters:
expr (
TypeVar(BASE_EXPR, bound= BaseExpr))- Return type:
_NeBuilder[TypeVar(BASE_EXPR, bound= BaseExpr)]
- egglog.panic(message)#
Raise an error with the given message.
- egglog.py_eval_fn(fn)#
Takes a python callable and maps it to a callable which takes and returns PyObjects.
It translates it to a call which uses py_eval to call the function, passing in the args as locals, and using the globals from function.
- Parameters:
fn (
Callable)- Return type:
PyObjectFunction
- egglog.relation(name, /, *tps, egg_fn=None)#
Creates a function whose return type is Unit and has a default value.
- egglog.rewrite(lhs, ruleset=None, *, subsume=False)#
Rewrite the given expression to a new expression.
- Parameters:
- Return type:
_RewriteBuilder[TypeVar(EXPR, bound= Expr)]
- egglog.rule(*facts, ruleset=None, name=None)#
Create a rule with the given facts.
- egglog.ruleset(rule_or_generator=None, *rules, name=None)#
Creates a ruleset with the following rules.
If no name is provided, try using the name of the funciton.
- Parameters:
rule_or_generator (
RewriteOrRule|Callable[...,Iterable[RewriteOrRule]] |None)rules (
RewriteOrRule)
- Return type:
- egglog.run(ruleset=None, *until, scheduler=None)#
Create a run configuration.
- egglog.seq(*schedules)#
Run a sequence of schedules.
- egglog.set_(lhs)#
Create a set of the given expression.
- Parameters:
lhs (
TypeVar(BASE_EXPR, bound= BaseExpr))- Return type:
_SetBuilder[TypeVar(BASE_EXPR, bound= BaseExpr)]
- egglog.set_cost(expr, cost)#
Set the cost of the given expression.
- Parameters:
expr (
BaseExpr)cost (
Union[RuntimeClass,int])
- Return type:
- egglog.subsume(expr)#
Subsume an expression so it cannot be matched against or extracted
- egglog.union(lhs)#
Create a union of the given expression.
- Parameters:
lhs (
TypeVar(EXPR, bound= Expr))- Return type:
_UnionBuilder[TypeVar(EXPR, bound= Expr)]
- egglog.unstable_combine_rulesets(*rulesets, name=None)#
Combine multiple rulesets into a single ruleset.
- egglog.var(name, bound, egg_name=None)#
Create a new variable with the given name and type.