Skip to content

Commit 3b41794

Browse files
Merge pull request #291 from egraphs-good/new-backend
Switch to new backend
2 parents b8be084 + 55f94bc commit 3b41794

21 files changed

+1007
-1179
lines changed

Cargo.lock

Lines changed: 547 additions & 330 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "egglog_python"
33
version = "10.0.2"
4-
edition = "2021"
4+
edition = "2024"
55

66

77
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -12,8 +12,12 @@ crate-type = ["cdylib"]
1212
[dependencies]
1313
pyo3 = { version = "0.23.0", features = ["extension-module"] }
1414

15-
egglog = { git = "https://github.com/egraphs-good/egglog", rev = "6f494282442803201b512e9d0828007b52a0b29c" }
16-
egglog-experimental = { git = "https://github.com/egraphs-good/egglog-experimental", rev = "8a1b3d6ad2723a8438f51f05027161e51f37917c" }
15+
# include this bugfix https://github.com/egraphs-good/egglog/pull/629
16+
egglog = { git = "https://github.com/saulshanabrook/egg-smol.git", rev = "1e638e6" }
17+
# egglog = { path = "../egg-smol" }
18+
egglog-bridge = { git = "https://github.com/egraphs-good/egglog-backend.git", rev = "1a1f913" }
19+
core-relations = { git = "https://github.com/egraphs-good/egglog-backend.git", rev = "1a1f913" }
20+
egglog-experimental = { git = "https://github.com/egraphs-good/egglog-experimental", rev = "202078f" }
1721
egraph-serialize = { version = "0.2.0", features = ["serde", "graphviz"] }
1822
serde_json = "1.0.140"
1923
pyo3-log = "0.12.3"
@@ -22,13 +26,11 @@ lalrpop-util = { version = "0.22", features = ["lexer"] }
2226
ordered-float = "3.7.0"
2327
uuid = { version = "1.16.0", features = ["v4"] }
2428

25-
# Use unreleased version of egglog in experimental
29+
# Use patched version of egglog in experimental
2630
[patch.'https://github.com/egraphs-good/egglog']
27-
# https://github.com/rust-lang/cargo/issues/5478#issuecomment-522719793
28-
egglog = { git = "https://github.com/egraphs-good//egglog.git", rev = "6f494282442803201b512e9d0828007b52a0b29c" }
29-
30-
# [replace]
31-
# 'https://github.com/egraphs-good/egglog.git#[email protected]' = { git = "https://github.com/egraphs-good/egglog.git", rev = "215714e1cbb13ae9e21bed2f2e1bf95804571512" }
31+
# egglog = { git = "https://github.com/egraphs-good//egglog.git", rev = "d2fa5b733de0796fb187dc5a27e570d5644aa75a" }
32+
# egglog = { path = "../egg-smol" }
33+
egglog = { git = "https://github.com/saulshanabrook/egg-smol.git", rev = "1e638e6" }
3234

3335
# enable debug symbols for easier profiling
3436
[profile.release]

docs/changelog.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ _This project uses semantic versioning_
44

55
## UNRELEASED
66

7+
- Upgrade egglog which includes new backend.
8+
- Fixes implementation of the Python Object sort to work with objects with dupliating hashes but the same value.
9+
Also changes the representation to be an index into a list instead of the ID, making egglog programs more deterministic.
10+
- Prefix constant declerations and unbound variables to not shadow let variables
11+
- BREAKING: Remove `simplify` since it was removed upstream. You can manually replace it with an insert, run, then extract.
12+
713
## 10.0.2 (2025-06-22)
814

915
- Fix using `f64Like` when not importing star (also properly includes removal of `Callable` special case from previous release).
@@ -76,7 +82,7 @@ Extracting: (+ %x 2)
7682
... print((x + 2).eval())
7783
...
7884
3
79-
````
85+
```
8086

8187
There is a tradeoff here for more ease of use at the expense of some added implicit behavior using global state.
8288

@@ -506,3 +512,4 @@ We also change the `PyObject` primitive to behave similarly. Instead of calling
506512
This release adds support for a high level API for e-graphs.
507513

508514
There is an examples of the high level API in the [tutorials](tutorials/getting-started).
515+
````

docs/reference/contributing.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ Finally, to build the docs locally and test that they work, you can run:
7272
make docs
7373
```
7474

75-
## Making changes
75+
## Debugging
76+
77+
To debug the Rust parts of this project, follow the [PyO3 debugging guide](https://pyo3.rs/main/debugging.html#debugger-specific-setup).
78+
Debug symbols are turned on by default.
79+
80+
### Making changes
7681

7782
All changes that impact users should be documented in the `docs/changelog.md` file. Please also add tests for any new features
7883
or bug fixes.

docs/reference/egglog-translation.md

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ i64(10) + i64(2)
2929
```
3030

3131
```{code-cell} python
32-
# egg: (+ (rational 1 2) (rational 2 1))
33-
Rational(i64(1), i64(2)) / Rational(i64(2), i64(1))
32+
# egg: (+ (bigrat (bigint 1) (bigint 2)) (big-rat (bigint 2) (bigint 1)))
33+
BigRat(1, 2) / BigRat(2, 1)
3434
```
3535

3636
These types are also all checked statically with MyPy, so for example, if you try to add a `String` and a `i64`, you will get a type error.
@@ -44,7 +44,7 @@ i64(10) + 2
4444
```
4545

4646
```{code-cell} python
47-
Rational(1, 2) / Rational(2, 1)
47+
BigRat(1, 2) / BigRat(2, 1)
4848
```
4949

5050
### `!=` Operator
@@ -497,15 +497,6 @@ egraph.run(10)
497497
egraph
498498
```
499499

500-
### Simplify
501-
502-
The `(simplify ...)` command in egglog translates to the `egraph.simplify` method, which combines running a schedule and extracting:
503-
504-
```{code-cell} python
505-
# egg: (simplify (Mul (Num 6) (Add (Num 2) (Mul (Var "x") (Num 2)))) 20)
506-
egraph.simplify(Math(6) * (Math(2) + Math.var("x") * Math(2)), 20)
507-
```
508-
509500
## Push/Pop
510501

511502
The `(push)` and `(pop)` commands in egglog can be translated to the context manager on the `egraph` object:

python/egglog/bindings.pyi

Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ __all__ = [
4343
"PrintSize",
4444
"Push",
4545
"PyObjectSort",
46-
"QueryExtract",
4746
"Relation",
4847
"Repeat",
4948
"Rewrite",
@@ -61,7 +60,6 @@ __all__ = [
6160
"SerializedEGraph",
6261
"Set",
6362
"SetOption",
64-
"Simplify",
6563
"Sort",
6664
"SrcFile",
6765
"String",
@@ -74,6 +72,7 @@ __all__ = [
7472
"Union",
7573
"Unit",
7674
"UnstableCombinedRuleset",
75+
"UserDefined",
7776
"Var",
7877
"Variant",
7978
"Variants",
@@ -309,14 +308,7 @@ class Expr_: # noqa: N801
309308
span: _Span
310309
expr: _Expr
311310

312-
@final
313-
class Extract:
314-
def __init__(self, span: _Span, expr: _Expr, variants: _Expr) -> None: ...
315-
span: _Span
316-
expr: _Expr
317-
variants: _Expr
318-
319-
_Action: TypeAlias = Let | Set | Change | Union | Panic | Expr_ | Extract
311+
_Action: TypeAlias = Let | Set | Change | Union | Panic | Expr_
320312

321313
##
322314
# Other Structs
@@ -367,22 +359,20 @@ class IdentSort:
367359
@final
368360
class RunReport:
369361
updated: bool
370-
search_time_per_rule: dict[str, timedelta]
371-
apply_time_per_rule: dict[str, timedelta]
372-
search_time_per_ruleset: dict[str, timedelta]
373-
apply_time_per_ruleset: dict[str, timedelta]
374-
rebuild_time_per_ruleset: dict[str, timedelta]
362+
search_and_apply_time_per_rule: dict[str, timedelta]
375363
num_matches_per_rule: dict[str, int]
364+
search_and_apply_time_per_ruleset: dict[str, timedelta]
365+
merge_time_per_ruleset: dict[str, timedelta]
366+
rebuild_time_per_ruleset: dict[str, timedelta]
376367

377368
def __init__(
378369
self,
379370
updated: bool,
380-
search_time_per_rule: dict[str, timedelta],
381-
apply_time_per_rule: dict[str, timedelta],
382-
search_time_per_ruleset: dict[str, timedelta],
383-
apply_time_per_ruleset: dict[str, timedelta],
384-
rebuild_time_per_ruleset: dict[str, timedelta],
371+
search_and_apply_time_per_rule: dict[str, timedelta],
385372
num_matches_per_rule: dict[str, int],
373+
search_and_apply_time_per_ruleset: dict[str, timedelta],
374+
merge_time_per_ruleset: dict[str, timedelta],
375+
rebuild_time_per_ruleset: dict[str, timedelta],
386376
) -> None: ...
387377

388378
@final
@@ -488,8 +478,9 @@ class Function:
488478

489479
@final
490480
class AddRuleset:
481+
span: _Span
491482
name: str
492-
def __init__(self, name: str) -> None: ...
483+
def __init__(self, span: _Span, name: str) -> None: ...
493484

494485
@final
495486
class RuleCommand:
@@ -524,18 +515,11 @@ class RunSchedule:
524515
def __init__(self, schedule: _Schedule) -> None: ...
525516

526517
@final
527-
class Simplify:
528-
span: _Span
529-
expr: _Expr
530-
schedule: _Schedule
531-
def __init__(self, span: _Span, expr: _Expr, schedule: _Schedule) -> None: ...
532-
533-
@final
534-
class QueryExtract:
518+
class Extract:
535519
span: _Span
536-
variants: int
537520
expr: _Expr
538-
def __init__(self, span: _Span, variants: int, expr: _Expr) -> None: ...
521+
variants: _Expr
522+
def __init__(self, span: _Span, expr: _Expr, variants: _Expr) -> None: ...
539523

540524
@final
541525
class Check:
@@ -614,11 +598,19 @@ class Constructor:
614598
class PrintOverallStatistics:
615599
def __init__(self) -> None: ...
616600

601+
@final
602+
class UserDefined:
603+
span: _Span
604+
name: str
605+
args: list[_Expr]
606+
def __init__(self, span: _Span, name: str, args: list[_Expr]) -> None: ...
607+
617608
@final
618609
class UnstableCombinedRuleset:
610+
span: _Span
619611
name: str
620612
rulesets: list[str]
621-
def __init__(self, name: str, rulesets: list[str]) -> None: ...
613+
def __init__(self, span: _Span, name: str, rulesets: list[str]) -> None: ...
622614

623615
_Command: TypeAlias = (
624616
SetOption
@@ -632,8 +624,7 @@ _Command: TypeAlias = (
632624
| BiRewriteCommand
633625
| ActionCommand
634626
| RunSchedule
635-
| Simplify
636-
| QueryExtract
627+
| Extract
637628
| Check
638629
| PrintFunction
639630
| PrintSize
@@ -647,6 +638,7 @@ _Command: TypeAlias = (
647638
| PrintOverallStatistics
648639
| UnstableCombinedRuleset
649640
| Constructor
641+
| UserDefined
650642
)
651643

652644
##

python/egglog/declarations.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"InitRef",
5252
"JustTypeRef",
5353
"LetDecl",
54+
"LetRefDecl",
5455
"LitDecl",
5556
"LitType",
5657
"MethodRef",
@@ -73,9 +74,9 @@
7374
"TypeOrVarRef",
7475
"TypeRefWithVars",
7576
"TypedExprDecl",
77+
"UnboundVarDecl",
7678
"UnionDecl",
7779
"UnnamedFunctionRef",
78-
"VarDecl",
7980
"replace_typed_expr",
8081
"upcast_declerations",
8182
]
@@ -361,7 +362,7 @@ def signature(self) -> FunctionSignature:
361362
arg_names = []
362363
for a in self.args:
363364
arg_types.append(a.tp.to_var())
364-
assert isinstance(a.expr, VarDecl)
365+
assert isinstance(a.expr, UnboundVarDecl)
365366
arg_names.append(a.expr.name)
366367
return FunctionSignature(
367368
arg_types=tuple(arg_types),
@@ -514,10 +515,14 @@ class ConstructorDecl:
514515

515516

516517
@dataclass(frozen=True)
517-
class VarDecl:
518+
class UnboundVarDecl:
519+
name: str
520+
egg_name: str | None = None
521+
522+
523+
@dataclass(frozen=True)
524+
class LetRefDecl:
518525
name: str
519-
# Differentiate between let bound vars and vars created in rules so that they won't shadow in egglog, by adding a prefix
520-
is_let: bool
521526

522527

523528
@dataclass(frozen=True)
@@ -628,7 +633,7 @@ class PartialCallDecl:
628633
call: CallDecl
629634

630635

631-
ExprDecl: TypeAlias = VarDecl | LitDecl | CallDecl | PyObjectDecl | PartialCallDecl
636+
ExprDecl: TypeAlias = UnboundVarDecl | LetRefDecl | LitDecl | CallDecl | PyObjectDecl | PartialCallDecl
632637

633638

634639
@dataclass(frozen=True)

0 commit comments

Comments
 (0)