Skip to content

Commit 442342c

Browse files
committed
Theorem decorator
1 parent d7ae310 commit 442342c

File tree

4 files changed

+60
-20
lines changed

4 files changed

+60
-20
lines changed

src/kdrag/tactics.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,3 +1460,36 @@ def qed(self, **kwargs) -> kd.kernel.Proof:
14601460
if self._parent is not None:
14611461
self._parent.exact(pf)
14621462
return pf
1463+
1464+
1465+
def Theorem(
1466+
goal: smt.BoolRef,
1467+
) -> Callable[[Callable[[ProofState], None]], kd.kernel.Proof]:
1468+
"""
1469+
A decorator to create a theorem from a function that takes a `ProofState` as argument.
1470+
1471+
>>> x = smt.Int("x")
1472+
>>> @Theorem(x + 1 > x)
1473+
... def mytheorem(l: ProofState):
1474+
... "An example theorem"
1475+
... l.auto()
1476+
>>> mytheorem
1477+
|= x + 1 > x
1478+
>>> mytheorem.__doc__
1479+
'An example theorem'
1480+
"""
1481+
1482+
def res(f: Callable[[ProofState], None]) -> kd.kernel.Proof:
1483+
l = kd.Lemma(goal)
1484+
f(l)
1485+
pf = l.qed()
1486+
# To override metadata of the returned proof
1487+
# Proof is frozen, so this is a bit fishy
1488+
# @functools.update_wrapper had assumptions about return type being a function
1489+
object.__setattr__(pf, "__doc__", getattr(f, "__doc__", None))
1490+
object.__setattr__(pf, "__module__", getattr(f, "__module__", None))
1491+
object.__setattr__(pf, "__name__", getattr(f, "__name__", None))
1492+
object.__setattr__(pf, "__qualname__", getattr(f, "__qualname__", None))
1493+
return pf
1494+
1495+
return res

src/kdrag/theories/logic/__init__.py

Whitespace-only changes.

src/kdrag/theories/logic/zf.py

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -59,25 +59,30 @@ def slemma(thm, by=[], **kwargs):
5959
)
6060
)
6161

62-
l = kd.Lemma(smt.ForAll([A], (A == emp) == smt.Not(smt.Exists([x], elem(x, A)))))
63-
_A = l.fix()
64-
l.split()
65-
with l.sub() as l1:
66-
l1.intros()
67-
l1.intros()
68-
_x = l1.obtain(-1)
69-
l1.show(smt.BoolVal(False), by=[ext_ax, elem_emp])
70-
with l.sub() as l2:
71-
l2.intros()
72-
l2.rw(ext_ax)
73-
_x = l2.fix()
74-
l2.apply(0)
75-
l2.exists(_x)
76-
l2.have(elem(_x, emp) == smt.BoolVal(False), by=[elem_emp(_x)])
77-
l2.have(elem(_x, _A), by=[])
78-
79-
l2.auto()
80-
emp_exists_elem = l.qed()
62+
63+
# l = kd.Lemma(smt.ForAll([A], (A == emp) == smt.Not(smt.Exists([x], elem(x, A)))))
64+
@kd.tactics.Theorem(smt.ForAll([A], (A == emp) == smt.Not(smt.Exists([x], elem(x, A)))))
65+
def emp_exists_elem(l):
66+
_A = l.fix()
67+
l.split()
68+
with l.sub() as l1:
69+
l1.intros()
70+
l1.intros()
71+
_x = l1.obtain(-1)
72+
l1.show(smt.BoolVal(False), by=[ext_ax, elem_emp])
73+
with l.sub() as l2:
74+
l2.intros()
75+
l2.rw(ext_ax)
76+
_x = l2.fix()
77+
l2.apply(0)
78+
l2.exists(_x)
79+
l2.have(elem(_x, emp) == smt.BoolVal(False), by=[elem_emp(_x)])
80+
l2.have(elem(_x, _A), by=[])
81+
82+
l2.auto()
83+
84+
85+
# emp_exists_elem = l.qed()
8186

8287

8388
l = kd.Lemma(smt.ForAll([A], smt.Implies((A != emp), smt.Exists([x], elem(x, A)))))

tests/test_kernel.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,4 +376,6 @@ def test_smart_prove():
376376
#with pytest.raises(Exception) as _:
377377
# kd.prove(smt.ForAll([x], f(x) == g(x)), unfold=[g])
378378
with pytest.raises(kd.kernel.LemmaError):
379-
kd.prove(smt.ForAll([x], d(x) == x+1), unfold=1)
379+
kd.prove(smt.ForAll([x], d(x) == x+1), unfold=1)
380+
381+

0 commit comments

Comments
 (0)