Skip to content

Commit 113e298

Browse files
committed
eunify and putting more in prelude
1 parent 1914963 commit 113e298

File tree

10 files changed

+205
-100
lines changed

10 files changed

+205
-100
lines changed

src/kdrag/__init__.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from . import datatype
1616
from . import rewrite
1717
from . import tactics
18+
import functools
1819

1920

2021
Proof = kernel.Proof
@@ -74,6 +75,95 @@
7475
RSeq = Z >> R
7576
RFun = R >> R
7677

78+
79+
def seq(*args):
80+
"""
81+
Helper to construct sequences.
82+
>>> seq(1, 2, 3)
83+
Concat(Unit(1), Concat(Unit(2), Unit(3)))
84+
>>> seq(1)
85+
Unit(1)
86+
"""
87+
if len(args) == 0:
88+
raise ValueError(
89+
"seq() requires at least one argument. use smt.Empty(sort) instead."
90+
)
91+
elif len(args) == 1:
92+
return smt.Unit(smt._py2expr(args[0]))
93+
else:
94+
return smt.Concat(*[smt.Unit(smt._py2expr(a)) for a in args])
95+
96+
97+
Nat = Inductive("Nat")
98+
Nat.declare("Z")
99+
Nat.declare("S", ("pred", Nat))
100+
Nat = Nat.create()
101+
102+
103+
def NatSort() -> smt.DatatypeSortRef:
104+
global Nat
105+
assert isinstance(Nat, smt.DatatypeSortRef)
106+
return Nat
107+
108+
109+
@functools.cache
110+
def ListSort(Elt: smt.SortRef) -> smt.DatatypeSortRef:
111+
"""
112+
>>> ListSort(smt.IntSort())
113+
List_Int...
114+
"""
115+
T = Inductive("List_" + Elt.name())
116+
T.declare("Nil")
117+
T.declare("Cons", ("head", Elt), ("tail", T))
118+
return T.create()
119+
120+
121+
def list(*args: smt.ExprRef) -> smt.DatatypeRef:
122+
"""
123+
Helper to construct List values
124+
>>> list(1, 2, 3)
125+
Cons(1, Cons(2, Cons(3, Nil)))
126+
"""
127+
if len(args) == 0:
128+
raise ValueError("list() requires at least one argument")
129+
LT = ListSort(smt._py2expr(args[0]).sort())
130+
acc = LT.Nil
131+
for a in reversed(args):
132+
acc = LT.Cons(a, acc)
133+
return acc
134+
135+
136+
@functools.cache
137+
def OptionSort(T: smt.SortRef) -> smt.DatatypeSortRef:
138+
"""
139+
Define an Option type for a given type T
140+
>>> OInt = OptionSort(smt.IntSort())
141+
>>> OInt.Some(1)
142+
Some(1)
143+
>>> OInt.None_
144+
None_
145+
>>> OInt.Some(1).val
146+
val(Some(1))
147+
"""
148+
Option = Inductive("Option_" + T.name())
149+
Option.declare("None_")
150+
Option.declare("Some", ("val", T))
151+
return Option.create()
152+
153+
154+
# I guess I could make this a SortDispatch for regularity. I just don't see why I'd need to overload in any way but the default
155+
def Some(x: smt.ExprRef) -> smt.DatatypeRef:
156+
"""
157+
Helper to create Option values
158+
>>> Some(42)
159+
Some(42)
160+
>>> Some(42).sort()
161+
Option_Int
162+
"""
163+
x = smt._py2expr(x)
164+
return OptionSort(x.sort()).Some(x)
165+
166+
77167
__all__ = [
78168
"prove",
79169
"axiom",

src/kdrag/contrib/junk_drawer/list.py

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,16 @@
55
"""
66

77
import kdrag as kd
8-
import functools
98
import kdrag.smt as smt
109

1110

12-
@functools.cache
13-
def List(sort: smt.SortRef) -> smt.DatatypeSortRef:
14-
"""
15-
Build List sort
16-
>>> IntList = List(smt.IntSort())
17-
>>> IntList.Cons(1, IntList.Nil)
18-
Cons(1, Nil)
19-
"""
20-
dt = kd.Inductive("List_" + sort.name())
21-
dt.declare("Nil")
22-
dt.declare("Cons", ("head", sort), ("tail", dt))
23-
return dt.create()
24-
25-
26-
def list(*args: smt.ExprRef) -> smt.DatatypeRef:
27-
"""
28-
Helper to construct List values
29-
>>> list(1, 2, 3)
30-
Cons(1, Cons(2, Cons(3, Nil)))
31-
"""
32-
if len(args) == 0:
33-
raise ValueError("list() requires at least one argument")
34-
LT = List(smt._py2expr(args[0]).sort())
35-
acc = LT.Nil
36-
for a in reversed(args):
37-
acc = LT.Cons(a, acc)
38-
return acc
39-
40-
4111
def Cons(x: smt.ExprRef, xs: smt.DatatypeRef) -> smt.DatatypeRef:
4212
"""
4313
Helper to construct Cons values
4414
>>> Cons(1, Nil(smt.IntSort()))
4515
Cons(1, Nil)
4616
"""
47-
LT = List(smt._py2expr(x).sort())
17+
LT = kd.ListSort(smt._py2expr(x).sort())
4818
return LT.Cons(x, xs)
4919

5020

@@ -54,7 +24,7 @@ def Nil(sort: smt.SortRef) -> smt.DatatypeRef:
5424
>>> Nil(smt.IntSort())
5525
Nil
5626
"""
57-
return List(sort).Nil
27+
return kd.ListSort(sort).Nil
5828

5929

6030
def Unit(x: smt.ExprRef) -> smt.DatatypeRef:
@@ -66,5 +36,5 @@ def Unit(x: smt.ExprRef) -> smt.DatatypeRef:
6636
List_Int
6737
"""
6838
x = smt._py2expr(x)
69-
LT = List(x.sort())
39+
LT = kd.ListSort(x.sort())
7040
return LT.Cons(x, LT.Nil)

src/kdrag/kernel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ def Inductive(name: str) -> smt.Datatype:
564564
dt = smt.Datatype(name)
565565
oldcreate = dt.create
566566

567-
def create():
567+
def create() -> smt.DatatypeSortRef:
568568
dt = oldcreate()
569569
# Sanity check no duplicate names. Causes confusion.
570570
names = set()

src/kdrag/notation.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,45 @@ def GenericDispatch(default_factory) -> SortDispatch:
300300
"""Sort based dispatch for `Exists` quantifier."""
301301
# smt.ExprRef.exists = lambda vs, body: exists(vs, body)
302302

303-
induct = SortDispatch(name="induct")
303+
304+
def induct_seq(a: smt.SeqRef, P) -> kd.kernel.Proof:
305+
"""
306+
>>> x = smt.Const("x", smt.SeqSort(smt.IntSort()))
307+
>>> induct(x, lambda s: smt.Length(s) >= 0)
308+
|= Implies(And(Length(Empty(Seq(Int))) >= 0,
309+
ForAll(z!..., Length(Unit(z!...)) >= 0),
310+
ForAll([x!..., y!...],
311+
Implies(And(Length(x!...) >= 0,
312+
Length(y!...) >= 0),
313+
Length(Concat(x!..., y!...)) >= 0))),
314+
Length(x) >= 0)
315+
"""
316+
assert isinstance(a, smt.SeqRef)
317+
sort = a.sort()
318+
T = sort.basis()
319+
z = smt.FreshConst(T, prefix="z")
320+
x, y = smt.FreshConst(sort, prefix="x"), smt.FreshConst(sort, prefix="y")
321+
return kd.axiom(
322+
smt.Implies(
323+
smt.And(
324+
P(smt.Empty(sort)),
325+
QForAll([z], P(smt.Unit(z))),
326+
QForAll([x, y], P(x), P(y), P(smt.Concat(x, y))),
327+
),
328+
# -------------------------------------------------
329+
P(a),
330+
)
331+
)
332+
333+
334+
def induct_default(x, P):
335+
if isinstance(x, smt.SeqRef):
336+
return induct_seq(x, P)
337+
else:
338+
raise NotImplementedError("No default induct implementation for sort", x.sort())
339+
340+
341+
induct = SortDispatch(name="induct", default=induct_default)
304342
"""Sort based dispatch for induction principles. Should instantiate an induction scheme for variable x and predicate P"""
305343
smt.ExprRef.induct = lambda x, P: induct(x, P) # type: ignore
306344

src/kdrag/theories/list.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,9 @@
66

77
import kdrag as kd
88
import kdrag.smt as smt
9-
import functools
109

1110

12-
@functools.cache
13-
def ListSort(Elt: smt.SortRef) -> smt.DatatypeSortRef:
14-
"""
15-
>>> ListSort(smt.IntSort())
16-
List_Int...
17-
"""
18-
T = kd.Inductive("List_" + Elt.name())
19-
T.declare("Nil")
20-
T.declare("Cons", ("head", Elt), ("tail", T))
21-
return T.create()
11+
ListSort = kd.ListSort
2212

2313

2414
class List:

src/kdrag/theories/nat.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66
import kdrag.smt as smt
77
import kdrag.theories.int as int_ # int is more primitive. We import it's induction principle here.
88

9-
Nat = kd.Inductive("Nat")
10-
Nat.declare("Z")
11-
Nat.declare("S", ("pred", Nat))
12-
Nat = Nat.create()
9+
Nat = kd.Nat
1310

1411

1512
S = Nat.S

src/kdrag/theories/option.py

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,29 @@
33
44
"""
55

6-
import functools
76
import kdrag.smt as smt
87
import kdrag as kd
98

109

11-
@functools.cache
12-
def OptionSort(T: smt.SortRef) -> smt.DatatypeSortRef:
13-
"""
14-
Define an Option type for a given type T
15-
>>> OInt = OptionSort(smt.IntSort())
16-
>>> OInt.Some(1)
17-
Some(1)
18-
>>> OInt.None_
19-
None_
20-
>>> OInt.Some(1).val
21-
val(Some(1))
22-
"""
23-
Option = kd.Inductive("Option_" + T.name())
24-
Option.declare("None_")
25-
Option.declare("Some", ("val", T))
26-
return Option.create()
10+
OptionSort = kd.OptionSort
2711

2812

2913
def is_option(x: smt.DatatypeRef) -> bool:
3014
"""
3115
Check if a value is an Option
32-
>>> is_option(Some(42))
16+
>>> is_option(kd.Some(42))
3317
True
3418
>>> is_option(42)
3519
False
3620
"""
37-
return smt._py2expr(x).sort().name().startswith("Option_")
21+
return isinstance(x, smt.DatatypeRef) and x.sort().name().startswith("Option_")
3822

3923

4024
# This should also perhaps be a SortDispatch
4125
def get(x: smt.DatatypeRef, default: smt.ExprRef) -> smt.ExprRef:
4226
"""
4327
Get the value of an Option, or a default value if it is None_
44-
>>> get(Some(42), 0)
28+
>>> get(kd.Some(42), 0)
4529
If(is(Some, Some(42)), val(Some(42)), 0)
4630
"""
4731
default = smt._py2expr(default)
@@ -54,23 +38,13 @@ def get(x: smt.DatatypeRef, default: smt.ExprRef) -> smt.ExprRef:
5438
return smt.If(x.is_Some, x.val, default)
5539

5640

57-
# I guess I could make this a SortDispatch for regularity. I just don't see why I'd need to overload in any way but the default
58-
def Some(x: smt.ExprRef) -> smt.DatatypeRef:
59-
"""
60-
Helper to create Option values
61-
>>> Some(42)
62-
Some(42)
63-
>>> Some(42).sort()
64-
Option_Int
65-
"""
66-
x = smt._py2expr(x)
67-
return OptionSort(x.sort()).Some(x)
68-
69-
7041
def None_(T: smt.SortRef) -> smt.DatatypeRef:
7142
"""
7243
Helper to create Option None_ values
7344
>>> None_(smt.IntSort())
7445
None_
7546
"""
7647
return OptionSort(T).None_
48+
49+
50+
Some = kd.Some

src/kdrag/theories/seq.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def induct_list(x: smt.SeqRef, P):
3838
)
3939

4040

41+
"""
4142
def induct(T: smt.SortRef, P) -> kd.kernel.Proof:
4243
z = smt.FreshConst(T, prefix="z")
4344
sort = smt.SeqSort(T)
@@ -50,24 +51,11 @@ def induct(T: smt.SortRef, P) -> kd.kernel.Proof:
5051
) # -------------------------------------------------
5152
== kd.QForAll([x], P(x))
5253
)
54+
"""
5355

56+
induct = kd.notation.induct_seq
5457

55-
def seq(*args):
56-
"""
57-
Helper to construct sequences.
58-
>>> seq(1, 2, 3)
59-
Concat(Unit(1), Concat(Unit(2), Unit(3)))
60-
>>> seq(1)
61-
Unit(1)
62-
"""
63-
if len(args) == 0:
64-
raise ValueError(
65-
"seq() requires at least one argument. use smt.Empty(sort) instead."
66-
)
67-
elif len(args) == 1:
68-
return smt.Unit(smt._py2expr(args[0]))
69-
else:
70-
return smt.Concat(*[smt.Unit(smt._py2expr(a)) for a in args])
58+
seq = kd.seq
7159

7260

7361
def Cons(x: smt.ExprRef, tl: smt.SeqSortRef):

0 commit comments

Comments
 (0)