egglog 12.0.0__cp313-cp313t-manylinux_2_17_ppc64.manylinux2014_ppc64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- egglog/__init__.py +13 -0
- egglog/bindings.cpython-313t-powerpc64-linux-gnu.so +0 -0
- egglog/bindings.pyi +887 -0
- egglog/builtins.py +1144 -0
- egglog/config.py +8 -0
- egglog/conversion.py +290 -0
- egglog/declarations.py +964 -0
- egglog/deconstruct.py +176 -0
- egglog/egraph.py +2247 -0
- egglog/egraph_state.py +978 -0
- egglog/examples/README.rst +5 -0
- egglog/examples/__init__.py +3 -0
- egglog/examples/bignum.py +32 -0
- egglog/examples/bool.py +38 -0
- egglog/examples/eqsat_basic.py +44 -0
- egglog/examples/fib.py +28 -0
- egglog/examples/higher_order_functions.py +42 -0
- egglog/examples/jointree.py +64 -0
- egglog/examples/lambda_.py +287 -0
- egglog/examples/matrix.py +175 -0
- egglog/examples/multiset.py +60 -0
- egglog/examples/ndarrays.py +144 -0
- egglog/examples/resolution.py +84 -0
- egglog/examples/schedule_demo.py +34 -0
- egglog/exp/MoA.ipynb +617 -0
- egglog/exp/__init__.py +3 -0
- egglog/exp/any_expr.py +947 -0
- egglog/exp/any_expr_example.ipynb +408 -0
- egglog/exp/array_api.py +2019 -0
- egglog/exp/array_api_jit.py +51 -0
- egglog/exp/array_api_loopnest.py +74 -0
- egglog/exp/array_api_numba.py +69 -0
- egglog/exp/array_api_program_gen.py +510 -0
- egglog/exp/program_gen.py +427 -0
- egglog/exp/siu_examples.py +32 -0
- egglog/ipython_magic.py +41 -0
- egglog/pretty.py +566 -0
- egglog/py.typed +0 -0
- egglog/runtime.py +888 -0
- egglog/thunk.py +97 -0
- egglog/type_constraint_solver.py +111 -0
- egglog/visualizer.css +1 -0
- egglog/visualizer.js +35798 -0
- egglog/visualizer_widget.py +39 -0
- egglog-12.0.0.dist-info/METADATA +93 -0
- egglog-12.0.0.dist-info/RECORD +48 -0
- egglog-12.0.0.dist-info/WHEEL +5 -0
- egglog-12.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Matrix multiplication and Kronecker product.
|
|
3
|
+
============================================
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from egglog import *
|
|
9
|
+
|
|
10
|
+
egraph = EGraph()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Dim(Expr):
|
|
14
|
+
"""
|
|
15
|
+
A dimension of a matix.
|
|
16
|
+
|
|
17
|
+
>>> Dim(3) * Dim.named("n")
|
|
18
|
+
Dim(3) * Dim.named("n")
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
@method(egg_fn="Lit")
|
|
22
|
+
def __init__(self, value: i64Like) -> None: ...
|
|
23
|
+
|
|
24
|
+
@method(egg_fn="NamedDim")
|
|
25
|
+
@classmethod
|
|
26
|
+
def named(cls, name: StringLike) -> Dim: # type: ignore[empty-body]
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
@method(egg_fn="Times")
|
|
30
|
+
def __mul__(self, other: Dim) -> Dim: # type: ignore[empty-body]
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
a, b, c, n = vars_("a b c n", Dim)
|
|
35
|
+
i, j = vars_("i j", i64)
|
|
36
|
+
egraph.register(
|
|
37
|
+
rewrite(a * (b * c)).to((a * b) * c),
|
|
38
|
+
rewrite((a * b) * c).to(a * (b * c)),
|
|
39
|
+
rewrite(Dim(i) * Dim(j)).to(Dim(i * j)),
|
|
40
|
+
rewrite(a * b).to(b * a),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class Matrix(Expr, egg_sort="MExpr"):
|
|
45
|
+
@method(egg_fn="Id")
|
|
46
|
+
@classmethod
|
|
47
|
+
def identity(cls, dim: Dim) -> Matrix: # type: ignore[empty-body]
|
|
48
|
+
"""
|
|
49
|
+
Create an identity matrix of the given dimension.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
@method(egg_fn="NamedMat")
|
|
53
|
+
@classmethod
|
|
54
|
+
def named(cls, name: StringLike) -> Matrix: # type: ignore[empty-body]
|
|
55
|
+
"""
|
|
56
|
+
Create a named matrix.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
@method(egg_fn="MMul")
|
|
60
|
+
def __matmul__(self, other: Matrix) -> Matrix: # type: ignore[empty-body]
|
|
61
|
+
"""
|
|
62
|
+
Matrix multiplication.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
@method(egg_fn="nrows")
|
|
66
|
+
def nrows(self) -> Dim: # type: ignore[empty-body]
|
|
67
|
+
"""
|
|
68
|
+
Number of rows in the matrix.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
@method(egg_fn="ncols")
|
|
72
|
+
def ncols(self) -> Dim: # type: ignore[empty-body]
|
|
73
|
+
"""
|
|
74
|
+
Number of columns in the matrix.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@function(egg_fn="Kron")
|
|
79
|
+
def kron(a: Matrix, b: Matrix) -> Matrix: # type: ignore[empty-body]
|
|
80
|
+
"""
|
|
81
|
+
Kronecker product of two matrices.
|
|
82
|
+
|
|
83
|
+
https://en.wikipedia.org/wiki/Kronecker_product#Definition
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
A, B, C, D = vars_("A B C D", Matrix)
|
|
88
|
+
egraph.register(
|
|
89
|
+
# The dimensions of a kronecker product are the product of the dimensions
|
|
90
|
+
rewrite(kron(A, B).nrows()).to(A.nrows() * B.nrows()),
|
|
91
|
+
rewrite(kron(A, B).ncols()).to(A.ncols() * B.ncols()),
|
|
92
|
+
# The dimensions of a matrix multiplication are the number of rows of the first
|
|
93
|
+
# matrix and the number of columns of the second matrix.
|
|
94
|
+
rewrite((A @ B).nrows()).to(A.nrows()),
|
|
95
|
+
rewrite((A @ B).ncols()).to(B.ncols()),
|
|
96
|
+
# The dimensions of an identity matrix are the input dimension
|
|
97
|
+
rewrite(Matrix.identity(n).nrows()).to(n),
|
|
98
|
+
rewrite(Matrix.identity(n).ncols()).to(n),
|
|
99
|
+
)
|
|
100
|
+
egraph.register(
|
|
101
|
+
# Multiplication by an identity matrix is the same as the other matrix
|
|
102
|
+
rewrite(Matrix.identity(n) @ A).to(A),
|
|
103
|
+
rewrite(A @ Matrix.identity(n)).to(A),
|
|
104
|
+
# Matrix multiplication is associative
|
|
105
|
+
rewrite(A @ (B @ C)).to((A @ B) @ C),
|
|
106
|
+
rewrite((A @ B) @ C).to(A @ (B @ C)),
|
|
107
|
+
# Kronecker product is associative
|
|
108
|
+
rewrite(kron(A, kron(B, C))).to(kron(kron(A, B), C)),
|
|
109
|
+
rewrite(kron(kron(A, B), C)).to(kron(A, kron(B, C))),
|
|
110
|
+
# Kronecker product distributes over matrix multiplication
|
|
111
|
+
rewrite(kron(A @ C, B @ D)).to(kron(A, B) @ kron(C, D)),
|
|
112
|
+
rewrite(kron(A, B) @ kron(C, D)).to(
|
|
113
|
+
kron(A @ C, B @ D),
|
|
114
|
+
# Only when the dimensions match
|
|
115
|
+
eq(A.ncols()).to(C.nrows()),
|
|
116
|
+
eq(B.ncols()).to(D.nrows()),
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
egraph.register(
|
|
120
|
+
# demand rows and columns when we multiply matrices
|
|
121
|
+
rule(eq(C).to(A @ B)).then(
|
|
122
|
+
A.ncols(),
|
|
123
|
+
A.nrows(),
|
|
124
|
+
B.ncols(),
|
|
125
|
+
B.nrows(),
|
|
126
|
+
),
|
|
127
|
+
# demand rows and columns when we take the kronecker product
|
|
128
|
+
rule(eq(C).to(kron(A, B))).then(
|
|
129
|
+
A.ncols(),
|
|
130
|
+
A.nrows(),
|
|
131
|
+
B.ncols(),
|
|
132
|
+
B.nrows(),
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# Define a number of dimensions
|
|
138
|
+
n = egraph.let("n", Dim.named("n"))
|
|
139
|
+
m = egraph.let("m", Dim.named("m"))
|
|
140
|
+
p = egraph.let("p", Dim.named("p"))
|
|
141
|
+
|
|
142
|
+
# Define a number of matrices
|
|
143
|
+
A = egraph.let("A", Matrix.named("A"))
|
|
144
|
+
B = egraph.let("B", Matrix.named("B"))
|
|
145
|
+
C = egraph.let("C", Matrix.named("C"))
|
|
146
|
+
|
|
147
|
+
# Set each to be a square matrix of the given dimension
|
|
148
|
+
egraph.register(
|
|
149
|
+
union(A.nrows()).with_(n),
|
|
150
|
+
union(A.ncols()).with_(n),
|
|
151
|
+
union(B.nrows()).with_(m),
|
|
152
|
+
union(B.ncols()).with_(m),
|
|
153
|
+
union(C.nrows()).with_(p),
|
|
154
|
+
union(C.ncols()).with_(p),
|
|
155
|
+
)
|
|
156
|
+
# Create an example which should equal the kronecker product of A and B
|
|
157
|
+
ex1 = egraph.let("ex1", kron(Matrix.identity(n), B) @ kron(A, Matrix.identity(m)))
|
|
158
|
+
rows = egraph.let("rows", ex1.nrows())
|
|
159
|
+
cols = egraph.let("cols", ex1.ncols())
|
|
160
|
+
|
|
161
|
+
egraph.run(20)
|
|
162
|
+
|
|
163
|
+
egraph.check(eq(B.nrows()).to(m))
|
|
164
|
+
egraph.check(eq(kron(Matrix.identity(n), B).nrows()).to(n * m))
|
|
165
|
+
|
|
166
|
+
# Verify it matches the expected result
|
|
167
|
+
simple_ex1 = egraph.let("simple_ex1", kron(A, B))
|
|
168
|
+
egraph.check(eq(ex1).to(simple_ex1))
|
|
169
|
+
|
|
170
|
+
ex2 = egraph.let("ex2", kron(Matrix.identity(p), C) @ kron(A, Matrix.identity(m)))
|
|
171
|
+
|
|
172
|
+
egraph.run(10)
|
|
173
|
+
# Verify it is not simplified
|
|
174
|
+
egraph.check_fail(eq(ex2).to(kron(A, C)))
|
|
175
|
+
egraph
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# mypy: disable-error-code="empty-body"
|
|
2
|
+
"""
|
|
3
|
+
Multiset example based off of egglog version
|
|
4
|
+
============================================
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from collections import Counter
|
|
10
|
+
|
|
11
|
+
from egglog import *
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Math(Expr):
|
|
15
|
+
def __init__(self, x: i64Like) -> None: ...
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@function
|
|
19
|
+
def square(x: Math) -> Math: ...
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@ruleset
|
|
23
|
+
def math_ruleset(i: i64):
|
|
24
|
+
yield rewrite(square(Math(i))).to(Math(i * i))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
egraph = EGraph()
|
|
28
|
+
|
|
29
|
+
xs = MultiSet(Math(1), Math(2), Math(3))
|
|
30
|
+
egraph.register(xs)
|
|
31
|
+
|
|
32
|
+
egraph.check(xs == MultiSet(Math(1), Math(3), Math(2)))
|
|
33
|
+
egraph.check_fail(xs == MultiSet(Math(1), Math(1), Math(2), Math(3)))
|
|
34
|
+
|
|
35
|
+
assert Counter(egraph.extract(xs).value) == Counter({Math(1): 1, Math(2): 1, Math(3): 1})
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
inserted = MultiSet(Math(1), Math(2), Math(3), Math(4))
|
|
39
|
+
egraph.register(inserted)
|
|
40
|
+
egraph.check(xs.insert(Math(4)) == inserted)
|
|
41
|
+
egraph.check(xs.contains(Math(1)))
|
|
42
|
+
egraph.check(xs.not_contains(Math(4)))
|
|
43
|
+
assert Math(1) in xs
|
|
44
|
+
assert Math(4) not in xs
|
|
45
|
+
|
|
46
|
+
egraph.check(xs.remove(Math(1)) == MultiSet(Math(2), Math(3)))
|
|
47
|
+
|
|
48
|
+
assert egraph.extract(xs.length()).value == 3
|
|
49
|
+
assert len(xs) == 3
|
|
50
|
+
|
|
51
|
+
egraph.check(MultiSet(Math(1), Math(1)).length() == i64(2))
|
|
52
|
+
|
|
53
|
+
egraph.check(MultiSet(Math(1)).pick() == Math(1))
|
|
54
|
+
|
|
55
|
+
mapped = xs.map(square)
|
|
56
|
+
egraph.register(mapped)
|
|
57
|
+
egraph.run(math_ruleset)
|
|
58
|
+
egraph.check(mapped == MultiSet(Math(1), Math(4), Math(9)))
|
|
59
|
+
|
|
60
|
+
egraph.check(xs + xs == MultiSet(Math(1), Math(2), Math(3), Math(1), Math(2), Math(3)))
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# mypy: disable-error-code="empty-body"
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
N-Dimensional Arrays
|
|
5
|
+
====================
|
|
6
|
+
|
|
7
|
+
Example of building NDarray in the vein of Mathemetics of Arrays.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from egglog import *
|
|
13
|
+
|
|
14
|
+
egraph = EGraph()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Value(Expr):
|
|
18
|
+
def __init__(self, v: i64Like) -> None: ...
|
|
19
|
+
|
|
20
|
+
def __mul__(self, other: Value) -> Value: ...
|
|
21
|
+
|
|
22
|
+
def __add__(self, other: Value) -> Value: ...
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
i, j = vars_("i j", i64)
|
|
26
|
+
egraph.register(
|
|
27
|
+
rewrite(Value(i) * Value(j)).to(Value(i * j)),
|
|
28
|
+
rewrite(Value(i) + Value(j)).to(Value(i + j)),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Values(Expr):
|
|
33
|
+
def __init__(self, v: Vec[Value]) -> None: ...
|
|
34
|
+
|
|
35
|
+
def __getitem__(self, idx: Value) -> Value: ...
|
|
36
|
+
|
|
37
|
+
def length(self) -> Value: ...
|
|
38
|
+
|
|
39
|
+
def concat(self, other: Values) -> Values: ...
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@egraph.register
|
|
43
|
+
def _values(vs: Vec[Value], other: Vec[Value]):
|
|
44
|
+
yield rewrite(Values(vs)[Value(i)]).to(vs[i])
|
|
45
|
+
yield rewrite(Values(vs).length()).to(Value(vs.length()))
|
|
46
|
+
yield rewrite(Values(vs).concat(Values(other))).to(Values(vs.append(other)))
|
|
47
|
+
# yield rewrite(l.concat(r).length()).to(l.length() + r.length())
|
|
48
|
+
# yield rewrite(l.concat(r)[idx])
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class NDArray(Expr):
|
|
52
|
+
"""
|
|
53
|
+
An n-dimensional array.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __getitem__(self, idx: Values) -> Value: ...
|
|
57
|
+
|
|
58
|
+
def shape(self) -> Values: ...
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@function
|
|
62
|
+
def arange(n: Value) -> NDArray: ...
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@egraph.register
|
|
66
|
+
def _ndarray_arange(n: Value, idx: Values):
|
|
67
|
+
yield rewrite(arange(n).shape()).to(Values(Vec(n)))
|
|
68
|
+
yield rewrite(arange(n)[idx]).to(idx[Value(0)])
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def assert_simplifies(left: Expr, right: Expr) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Simplify and print
|
|
74
|
+
"""
|
|
75
|
+
egraph.register(left)
|
|
76
|
+
egraph.run(30)
|
|
77
|
+
res = egraph.extract(left)
|
|
78
|
+
print(f"{left} == {right} ➡ {res}")
|
|
79
|
+
egraph.check(eq(left).to(right))
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
assert_simplifies(arange(Value(10)).shape(), Values(Vec(Value(10))))
|
|
83
|
+
assert_simplifies(arange(Value(10))[Values(Vec(Value(0)))], Value(0))
|
|
84
|
+
assert_simplifies(arange(Value(10))[Values(Vec(Value(1)))], Value(1))
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@function
|
|
88
|
+
def py_value(s: StringLike) -> Value: ...
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@egraph.register
|
|
92
|
+
def _py_value(l: String, r: String):
|
|
93
|
+
yield rewrite(py_value(l) + py_value(r)).to(py_value(join(l, " + ", r)))
|
|
94
|
+
yield rewrite(py_value(l) * py_value(r)).to(py_value(join(l, " * ", r)))
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@function
|
|
98
|
+
def py_values(s: StringLike) -> Values: ...
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@egraph.register
|
|
102
|
+
def _py_values(l: String, r: String):
|
|
103
|
+
yield rewrite(py_values(l)[py_value(r)]).to(py_value(join(l, "[", r, "]")))
|
|
104
|
+
yield rewrite(py_values(l).length()).to(py_value(join("len(", l, ")")))
|
|
105
|
+
yield rewrite(py_values(l).concat(py_values(r))).to(py_values(join(l, " + ", r)))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@function
|
|
109
|
+
def py_ndarray(s: StringLike) -> NDArray: ...
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@egraph.register
|
|
113
|
+
def _py_ndarray(l: String, r: String):
|
|
114
|
+
yield rewrite(py_ndarray(l)[py_values(r)]).to(py_value(join(l, "[", r, "]")))
|
|
115
|
+
yield rewrite(py_ndarray(l).shape()).to(py_values(join(l, ".shape")))
|
|
116
|
+
yield rewrite(arange(py_value(l))).to(py_ndarray(join("np.arange(", l, ")")))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
assert_simplifies(py_ndarray("x").shape(), py_values("x.shape"))
|
|
120
|
+
assert_simplifies(arange(py_value("x"))[py_values("y")], py_value("np.arange(x)[y]"))
|
|
121
|
+
# assert_simplifies(arange(py_value("x"))[py_values("y")], py_value("y[0]"))
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@function
|
|
125
|
+
def cross(l: NDArray, r: NDArray) -> NDArray: ...
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@egraph.register
|
|
129
|
+
def _cross(l: NDArray, r: NDArray, idx: Values):
|
|
130
|
+
yield rewrite(cross(l, r).shape()).to(l.shape().concat(r.shape()))
|
|
131
|
+
yield rewrite(cross(l, r)[idx]).to(l[idx] * r[idx])
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
assert_simplifies(cross(arange(Value(10)), arange(Value(11))).shape(), Values(Vec(Value(10), Value(11))))
|
|
135
|
+
assert_simplifies(cross(py_ndarray("x"), py_ndarray("y")).shape(), py_values("x.shape + y.shape"))
|
|
136
|
+
assert_simplifies(cross(py_ndarray("x"), py_ndarray("y"))[py_values("idx")], py_value("x[idx] * y[idx]"))
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@egraph.register
|
|
140
|
+
def _cross_py(l: String, r: String):
|
|
141
|
+
yield rewrite(cross(py_ndarray(l), py_ndarray(r))).to(py_ndarray(join("np.multiply.outer(", l, ", ", r, ")")))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
assert_simplifies(cross(py_ndarray("x"), py_ndarray("y"))[py_values("idx")], py_value("np.multiply.outer(x, y)[idx]"))
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Resolution theorem proving.
|
|
3
|
+
===========================
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import ClassVar
|
|
9
|
+
|
|
10
|
+
from egglog import *
|
|
11
|
+
|
|
12
|
+
egraph = EGraph()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Boolean(Expr):
|
|
16
|
+
FALSE: ClassVar[Boolean]
|
|
17
|
+
|
|
18
|
+
def __or__(self, other: Boolean) -> Boolean: # type: ignore[empty-body]
|
|
19
|
+
...
|
|
20
|
+
|
|
21
|
+
def __invert__(self) -> Boolean: # type: ignore[empty-body]
|
|
22
|
+
...
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Show off two ways of creating constants, either as top level values or as classvars
|
|
26
|
+
T = constant("T", Boolean)
|
|
27
|
+
F = Boolean.FALSE
|
|
28
|
+
|
|
29
|
+
p, a, b, c, as_, bs = vars_("p a b c as bs", Boolean)
|
|
30
|
+
egraph.register(
|
|
31
|
+
# clauses are assumed in the normal form (or a (or b (or c False)))
|
|
32
|
+
union(~F).with_(T),
|
|
33
|
+
union(~T).with_(F),
|
|
34
|
+
# "Solving" negation equations
|
|
35
|
+
rule(eq(~p).to(T)).then(union(p).with_(F)),
|
|
36
|
+
rule(eq(~p).to(F)).then(union(p).with_(T)),
|
|
37
|
+
# canonicalize associtivity. "append" for clauses terminate with false
|
|
38
|
+
rewrite((a | b) | c).to(a | (b | c)),
|
|
39
|
+
# commutativity
|
|
40
|
+
rewrite(a | (b | c)).to(b | (a | c)),
|
|
41
|
+
# absoprtion
|
|
42
|
+
rewrite(a | (a | b)).to(a | b),
|
|
43
|
+
rewrite(a | (~a | b)).to(T),
|
|
44
|
+
# Simplification
|
|
45
|
+
rewrite(F | a).to(a),
|
|
46
|
+
rewrite(a | F).to(a),
|
|
47
|
+
rewrite(T | a).to(T),
|
|
48
|
+
rewrite(a | T).to(T),
|
|
49
|
+
# unit propagation
|
|
50
|
+
# This is kind of interesting actually.
|
|
51
|
+
# Looks a bit like equation solving
|
|
52
|
+
rule(eq(T).to(p | F)).then(union(p).with_(T)),
|
|
53
|
+
# resolution
|
|
54
|
+
# This counts on commutativity to bubble everything possible up to the front of the clause.
|
|
55
|
+
rule(
|
|
56
|
+
eq(T).to(a | as_),
|
|
57
|
+
eq(T).to(~a | bs),
|
|
58
|
+
).then(
|
|
59
|
+
union(as_ | bs).with_(T),
|
|
60
|
+
),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# Example predicate
|
|
65
|
+
@function
|
|
66
|
+
def pred(x: i64Like) -> Boolean: # type: ignore[empty-body]
|
|
67
|
+
...
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
p0 = egraph.let("p0", pred(0))
|
|
71
|
+
p1 = egraph.let("p1", pred(1))
|
|
72
|
+
p2 = egraph.let("p2", pred(2))
|
|
73
|
+
egraph.register(
|
|
74
|
+
union(p1 | (~p2 | F)).with_(T),
|
|
75
|
+
union(p2 | (~p0 | F)).with_(T),
|
|
76
|
+
union(p0 | (~p1 | F)).with_(T),
|
|
77
|
+
union(p1).with_(F),
|
|
78
|
+
union(~p0 | (~p1 | (p2 | F))).with_(T),
|
|
79
|
+
)
|
|
80
|
+
egraph.run(10)
|
|
81
|
+
egraph.check(ne(T).to(F))
|
|
82
|
+
egraph.check(eq(p0).to(F))
|
|
83
|
+
egraph.check(eq(p2).to(F))
|
|
84
|
+
egraph
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Schedule demo
|
|
3
|
+
=============
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from egglog import *
|
|
9
|
+
|
|
10
|
+
left = relation("left", i64)
|
|
11
|
+
right = relation("right", i64)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
x, y = vars_("x y", i64)
|
|
15
|
+
step_left = ruleset(
|
|
16
|
+
rule(
|
|
17
|
+
left(x),
|
|
18
|
+
right(x),
|
|
19
|
+
).then(left(x + 1)),
|
|
20
|
+
)
|
|
21
|
+
step_right = ruleset(
|
|
22
|
+
rule(
|
|
23
|
+
left(x),
|
|
24
|
+
right(y),
|
|
25
|
+
eq(x).to(y + 1),
|
|
26
|
+
).then(right(x)),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
egraph = EGraph()
|
|
30
|
+
egraph.register(left(i64(0)), right(i64(0)))
|
|
31
|
+
egraph.run((step_right.saturate() + step_left.saturate()) * 10)
|
|
32
|
+
egraph.check(left(i64(10)), right(i64(9)))
|
|
33
|
+
egraph.check_fail(left(i64(11)), right(i64(10)))
|
|
34
|
+
egraph
|