kdrag.rewrite
Utilities for rewriting and simplification including pattern matching and unification.
Functions
|
Look for pattern lhs to unify with a subterm of t. |
|
|
|
Apply a rule to a target term. |
|
Do one pass of beta normalization. |
|
Build a dictionary of rules indexed by their lhs head function declaration. |
|
A notion of computational equality. |
|
Apply a rule to a target term. |
|
Fully simplify using definitions and built in z3 simplifier until no progress is made. |
|
Knuth Bendix Ordering, naive implementation. |
|
Lexicographic path ordering. |
|
Repeat rewrite until no more rewrites are possible. |
|
Rewrite at root a single time. |
|
Rewrite at root a single time. |
|
Unpack theorem of form forall vs, lhs = rhs into a Rule tuple |
|
Sweep through term once performing rewrites. |
|
Repeat rewrite until no more rewrites are possible. |
|
Unpack theorem of form forall vs, body => head into a Rule tuple |
|
Simplify using definitions and built in z3 simplifier until no progress is made. |
|
simplify a term using z3 built in simplifier |
|
simplify a term using z3 built in simplifier |
|
|
|
Do a single unfold sweep, unfolding definitions defined by kd.define. |
Classes
|
|
|
A rewrite rule tuple |
|
Exceptions
- class kdrag.rewrite.Order(*values)
Bases:
Enum
- EQ = 0
- GR = 1
- NGE = 2
- classmethod __contains__(value)
Return True if value is in cls.
value is in cls if: 1) value is a member of cls, or 2) value is the value of one of the cls’s members. 3) value is a pseudo-member (flags)
- classmethod __getitem__(name)
Return the member matching name.
- classmethod __iter__()
Return members in definition order.
- classmethod __len__()
Return the number of members (no aliases)
- class kdrag.rewrite.RewriteRule(vs: list[ExprRef], lhs: ExprRef, rhs: ExprRef, pf: Proof | None = None)
Bases:
NamedTuple
A rewrite rule tuple
- Parameters:
vs (list[ExprRef])
lhs (ExprRef)
rhs (ExprRef)
pf (Proof | None)
- count(value, /)
Return number of occurrences of value.
- freshen() RewriteRule
Freshen the rule by renaming variables.
>>> x,y= smt.Reals("x y") >>> rule = RewriteRule([x,y], x*y, y*x) >>> rule.freshen() RewriteRule(vs=[x..., y...], lhs=x...*y..., rhs=y...*x..., pf=None)
- Return type:
- classmethod from_expr(expr: BoolRef | QuantifierRef | Proof) RewriteRule
Convert a theorem of form forall vs, lhs = rhs to a rule.
- Parameters:
expr (BoolRef | QuantifierRef | Proof)
- Return type:
- index(value, start=0, stop=9223372036854775807, /)
Return first index of value.
Raises ValueError if the value is not present.
- lhs: ExprRef
Alias for field number 1
- rhs: ExprRef
Alias for field number 2
- to_expr() BoolRef | QuantifierRef
Convert the rule to a theorem of form forall vs, lhs = rhs.
>>> x,y = smt.Reals("x y") >>> RewriteRule([x,y], x*y, y*x).to_expr() ForAll([x, y], x*y == y*x)
- Return type:
BoolRef | QuantifierRef
- vs: list[ExprRef]
Alias for field number 0
- exception kdrag.rewrite.RewriteRuleException
Bases:
Exception
- add_note(object, /)
Exception.add_note(note) – add a note to the exception
- args
- with_traceback(object, /)
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
- class kdrag.rewrite.Rule(vs, hyp, conc, pf)
Bases:
NamedTuple
- Parameters:
vs (list[ExprRef])
hyp (BoolRef)
conc (BoolRef)
pf (Proof | None)
- conc: BoolRef
Alias for field number 2
- count(value, /)
Return number of occurrences of value.
- freshen()
Freshen the rule by renaming variables.
>>> x,y= smt.Reals("x y") >>> rule = Rule([x], x > 0, x < 0) >>> rule.freshen() Rule(vs=[x...], hyp=x... > 0, conc=x... < 0, pf=None)
- hyp: BoolRef
Alias for field number 1
- index(value, start=0, stop=9223372036854775807, /)
Return first index of value.
Raises ValueError if the value is not present.
- to_expr() ExprRef | QuantifierRef
Convert the rule to a theorem of form forall vs, hyp => conc.
>>> x = smt.Real("x") >>> Rule([x], x > 0, x < 0).to_expr() ForAll(x..., Implies(x... > 0, x... < 0))
- Return type:
ExprRef | QuantifierRef
- vs: list[ExprRef]
Alias for field number 0
- kdrag.rewrite.all_narrow(vs: list[ExprRef], t: ExprRef, lhs: ExprRef, rhs: ExprRef) list[tuple[ExprRef, dict[ExprRef, ExprRef]]]
Look for pattern lhs to unify with a subterm of t. returns a list of all of those lhs -> rhs applied + the substitution resulting from the unification. The substitution is so that we can apply the other t -> s rule once we return.
This helper is asymmettric between t and lhs. You need to call it twice to get all critical pairs.
>>> x,y,z = smt.Reals("x y z") >>> all_narrow([x,y], -(-(-(x))), -(-(y)), y) [(y, {y: -x}), (-y, {x: y}), (--y, {x: -y})]
- Parameters:
vs (list[ExprRef])
t (ExprRef)
lhs (ExprRef)
rhs (ExprRef)
- Return type:
list[tuple[ExprRef, dict[ExprRef, ExprRef]]]
- kdrag.rewrite.apply(goal: BoolRef, vs: list[ExprRef], head: BoolRef, body: BoolRef) BoolRef | None
- Parameters:
goal (BoolRef)
vs (list[ExprRef])
head (BoolRef)
body (BoolRef)
- Return type:
BoolRef | None
- kdrag.rewrite.backward_rule(r: Rule, tgt: BoolRef) tuple[dict[ExprRef, ExprRef], BoolRef] | None
Apply a rule to a target term.
- Parameters:
r (Rule)
tgt (BoolRef)
- Return type:
tuple[dict[ExprRef, ExprRef], BoolRef] | None
- kdrag.rewrite.beta(e: ExprRef) ExprRef
Do one pass of beta normalization.
>>> x = smt.Int("x") >>> y = smt.String("y") >>> f = smt.Function("f", smt.IntSort(), smt.IntSort()) >>> beta(f(x)) f(x) >>> beta(f(smt.Lambda([x], f(x))[1])) f(f(1)) >>> beta(f(smt.Select(smt.Lambda([x,y], x), 1, smt.StringVal("fred")))) f(1)
- Parameters:
e (ExprRef)
- Return type:
ExprRef
- kdrag.rewrite.decl_index(rules: list[RewriteRule]) dict[FuncDeclRef, RewriteRule]
Build a dictionary of rules indexed by their lhs head function declaration.
- Parameters:
rules (list[RewriteRule])
- Return type:
dict[FuncDeclRef, RewriteRule]
- kdrag.rewrite.def_eq(e1: ExprRef, e2: ExprRef, trace=None) bool
A notion of computational equality. Unfold and simp.
>>> import kdrag.theories.nat as nat >>> def_eq(nat.one + nat.one, nat.S(nat.S(nat.Z))) True
- Parameters:
e1 (ExprRef)
e2 (ExprRef)
- Return type:
bool
- kdrag.rewrite.forward_rule(r: Rule, tgt: BoolRef)
Apply a rule to a target term.
- Parameters:
r (Rule)
tgt (BoolRef)
- kdrag.rewrite.full_simp(e: ExprRef, trace=None) ExprRef
Fully simplify using definitions and built in z3 simplifier until no progress is made.
>>> import kdrag.theories.nat as nat >>> full_simp(nat.one + nat.one + nat.S(nat.one)) S(S(S(S(Z))))
>>> p = smt.Bool("p") >>> full_simp(smt.If(p, 42, 3)) If(p, 42, 3)
- Parameters:
e (ExprRef)
- Return type:
ExprRef
- kdrag.rewrite.kbo(vs: list[ExprRef], t1: ExprRef, t2: ExprRef) Order
Knuth Bendix Ordering, naive implementation. All weights are 1. Source: Term Rewriting and All That section 5.4.4
- Parameters:
vs (list[ExprRef])
t1 (ExprRef)
t2 (ExprRef)
- Return type:
- kdrag.rewrite.lpo(vs: list[ExprRef], t1: ExprRef, t2: ExprRef) Order
Lexicographic path ordering. Based on https://www21.in.tum.de/~nipkow/TRaAT/programs/termorders.ML TODO add ordering parameter.
- Parameters:
vs (list[ExprRef])
t1 (ExprRef)
t2 (ExprRef)
- Return type:
- kdrag.rewrite.rewrite(t: ExprRef, rules: Sequence[BoolRef | QuantifierRef | Proof | RewriteRule], trace=None) ExprRef
Repeat rewrite until no more rewrites are possible.
>>> x,y,z = smt.Reals("x y z") >>> unit = kd.prove(smt.ForAll([x], x + 0 == x)) >>> x + 0 + 0 + 0 + 0 x + 0 + 0 + 0 + 0 >>> rewrite(x + 0 + 0 + 0 + 0, [unit]) x
- Parameters:
t (ExprRef)
rules (Sequence[BoolRef | QuantifierRef | Proof | RewriteRule])
- Return type:
ExprRef
- kdrag.rewrite.rewrite1(t: ExprRef, vs: list[ExprRef], lhs: ExprRef, rhs: ExprRef) ExprRef | None
Rewrite at root a single time.
- Parameters:
t (ExprRef)
vs (list[ExprRef])
lhs (ExprRef)
rhs (ExprRef)
- Return type:
ExprRef | None
- kdrag.rewrite.rewrite1_rule(t: ExprRef, rule: RewriteRule, trace: list[tuple[RewriteRule, dict[ExprRef, ExprRef]]] | None = None) ExprRef | None
Rewrite at root a single time.
- Parameters:
t (ExprRef)
rule (RewriteRule)
trace (list[tuple[RewriteRule, dict[ExprRef, ExprRef]]] | None)
- Return type:
ExprRef | None
- kdrag.rewrite.rewrite_of_expr(thm: BoolRef | QuantifierRef | Proof) RewriteRule
Unpack theorem of form forall vs, lhs = rhs into a Rule tuple
>>> x = smt.Real("x") >>> rewrite_of_expr(smt.ForAll([x], x**2 == x*x)) RewriteRule(vs=[X...], lhs=X...**2, rhs=X...*X...)
- Parameters:
thm (BoolRef | QuantifierRef | Proof)
- Return type:
- kdrag.rewrite.rewrite_once(t: ExprRef, rules: list[RewriteRule], trace=None) ExprRef
Sweep through term once performing rewrites.
>>> x = smt.Real("x") >>> rule = RewriteRule([x], x**2, x*x) >>> rewrite_once((x**2)**2, [rule]) x*x*x*x
- Parameters:
t (ExprRef)
rules (list[RewriteRule])
- Return type:
ExprRef
- kdrag.rewrite.rewrite_slow(t: ExprRef, rules: list[BoolRef | QuantifierRef | Proof], trace=None) ExprRef
Repeat rewrite until no more rewrites are possible.
>>> x,y,z = smt.Reals("x y z") >>> unit = kd.prove(smt.ForAll([x], x + 0 == x)) >>> x + 0 + 0 + 0 + 0 x + 0 + 0 + 0 + 0 >>> rewrite(x + 0 + 0 + 0 + 0, [unit]) x
- Parameters:
t (ExprRef)
rules (list[BoolRef | QuantifierRef | Proof])
- Return type:
ExprRef
- kdrag.rewrite.rule_of_expr(pf_or_thm: ExprRef | Proof) Rule
Unpack theorem of form forall vs, body => head into a Rule tuple
>>> x = smt.Real("x") >>> rule_of_expr(smt.ForAll([x], smt.Implies(x**2 == x*x, x > 0))) Rule(vs=[X...], hyp=X...**2 == X...*X..., conc=X... > 0, pf=None) >>> rule_of_expr(x > 0) Rule(vs=[], hyp=True, conc=x > 0, pf=None)
- kdrag.rewrite.simp(e: ExprRef, trace=None, max_iter=3) ExprRef
Simplify using definitions and built in z3 simplifier until no progress is made.
>>> import kdrag.theories.nat as nat >>> simp(nat.one + nat.one + nat.S(nat.one)) S(S(S(S(Z))))
>>> p = smt.Bool("p") >>> simp(smt.If(p, 42, 3)) If(p, 42, 3)
- Parameters:
e (ExprRef)
- Return type:
ExprRef
- kdrag.rewrite.simp1(t: ExprRef) ExprRef
simplify a term using z3 built in simplifier
- Parameters:
t (ExprRef)
- Return type:
ExprRef
- kdrag.rewrite.simp2(t: ExprRef) ExprRef
simplify a term using z3 built in simplifier
- Parameters:
t (ExprRef)
- Return type:
ExprRef
- kdrag.rewrite.unfold(e: ExprRef, decls: Sequence[FuncDeclRef] | None = None, trace=None) ExprRef
>>> x = smt.Int("x") >>> f = kd.define("f", [x], x + 42) >>> trace = [] >>> unfold(f(1), trace=trace) 1 + 42 >>> trace [|= f(1) == 1 + 42]
>>> unfold(smt.Lambda([x], f(x))) Lambda(x, x + 42)
- Parameters:
e (ExprRef)
decls (Sequence[FuncDeclRef] | None)
- Return type:
ExprRef
- kdrag.rewrite.unfold_old(e: ExprRef, decls=None, trace=None) ExprRef
Do a single unfold sweep, unfolding definitions defined by kd.define. The optional trace parameter will record proof along the way. decls is an optional list of declarations to unfold. If None, all definitions are unfolded.
>>> x = smt.Int("x") >>> f = kd.define("f", [x], x + 42) >>> trace = [] >>> unfold_old(f(1), trace=trace) 1 + 42 >>> trace [|= f(1) == 1 + 42]
>>> unfold_old(smt.Lambda([x], f(x))) Lambda(x, x + 42)
- Parameters:
e (ExprRef)
- Return type:
ExprRef