1010from collections import defaultdict
1111
1212
13- def simp1 (t : smt .ExprRef ) -> smt .ExprRef :
14- """simplify a term using z3 built in simplifier"""
15- expr = smt .FreshConst (t .sort (), prefix = "knuckle_goal" )
16- G = smt .Goal ()
17- for v in kd .kernel .defns .values ():
18- G .add (v .ax .thm )
19- G .add (expr == t )
20- G2 = smt .Then (smt .Tactic ("demodulator" ), smt .Tactic ("simplify" )).apply (G )[0 ]
21- # TODO make this extraction more robust
22- return G2 [len (G2 ) - 1 ].children ()[1 ]
23-
24-
2513def simp2 (t : smt .ExprRef ) -> smt .ExprRef :
26- """simplify a term using z3 built in simplifier"""
14+ """
15+ Simplify a term using Z3's elim-predicates tactic with definitions.
16+
17+ This is a specialized simplifier that eliminates predicates. Useful for
18+ simplifying terms with defined predicates that need to be reduced.
19+ For general simplification, use `simp()` or `full_simp()` instead.
20+ """
2721 expr = smt .FreshConst (t .sort (), prefix = "knuckle_goal" )
2822 G = smt .Goal ()
2923 for v in kd .kernel .defns .values ():
@@ -33,18 +27,6 @@ def simp2(t: smt.ExprRef) -> smt.ExprRef:
3327 return G2 [len (G2 ) - 1 ].children ()[1 ]
3428
3529
36- # TODO: Doesn't seem to do anything?
37- # def factor(t: smt.ExprRef) -> smt.ExprRef:
38- # """factor a term using z3 built in tactic"""
39- # expr = smt.FreshConst(t.sort(), prefix="knuckle_goal")
40- # G = smt.Goal()
41- # for v in kd.kernel.defns.values():
42- # G.add(v.ax.thm)
43- # G.add(expr == t)
44- # G2 = smt.Tactic("factor").apply(G)[0]
45- # return G2[len(G2) - 1].children()[1]
46-
47-
4830def unfold (
4931 e : smt .ExprRef , decls : Optional [Sequence [smt .FuncDeclRef ]] = None , trace = None
5032) -> smt .ExprRef :
@@ -112,7 +94,15 @@ def beta(e: smt.ExprRef) -> smt.ExprRef:
11294
11395def full_simp (e : smt .ExprRef , trace = None ) -> smt .ExprRef :
11496 """
115- Fully simplify using definitions and built in z3 simplifier until no progress is made.
97+ Fully simplify using definitions and Z3's built-in simplifier until a fixed point.
98+
99+ Repeatedly unfolds definitions and applies Z3's simplifier until no further progress
100+ is made. Unlike `simp()`, this does not track term size or limit iterations.
101+ Use when you want maximum simplification regardless of term size growth.
102+
103+ Args:
104+ e: The expression to simplify
105+ trace: Optional list to append simplification steps to
116106
117107 >>> import kdrag.theories.nat as nat
118108 >>> full_simp(nat.one + nat.one + nat.S(nat.one))
@@ -133,7 +123,16 @@ def full_simp(e: smt.ExprRef, trace=None) -> smt.ExprRef:
133123
134124def simp (e : smt .ExprRef , trace = None , max_iter = 3 ) -> smt .ExprRef :
135125 """
136- Simplify using definitions and built in z3 simplifier until no progress is made.
126+ Simplify using definitions and Z3's simplifier with size-based heuristics.
127+
128+ This is the default simplification function. It tracks term size and returns
129+ the smallest term found within max_iter iterations. Unlike `full_simp()`,
130+ this prevents term size explosion by preferring smaller terms.
131+
132+ Args:
133+ e: The expression to simplify
134+ trace: Optional list to append simplification proofs to
135+ max_iter: Maximum number of unfold+simplify iterations (default: 3)
137136
138137 >>> import kdrag.theories.nat as nat
139138 >>> simp(nat.one + nat.one + nat.S(nat.one))
0 commit comments