kdrag.theories.seq
Built in smtlib theory of finite sequences.
Functions
|
Make sort of Sequences and prove useful lemmas. |
|
Construct a sequence of length 1. |
|
|
|
|
|
Helper to construct sequences. |
- kdrag.theories.seq.Seq(T: SortRef) SeqSortRef
Make sort of Sequences and prove useful lemmas.
>>> BoolSeq = Seq(smt.BoolSort()) >>> x,y,z = smt.Consts("x y z", BoolSeq) >>> x + y Concat(x, y)
- Parameters:
T (SortRef)
- Return type:
SeqSortRef
- kdrag.theories.seq.Unit(x: ExprRef) SeqRef
Construct a sequence of length 1.
- Parameters:
x (ExprRef)
- Return type:
SeqRef
- kdrag.theories.seq.induct_list(x: SeqRef, P)
>>> x = smt.Const("x", Seq(smt.IntSort())) >>> P = smt.Function("P", Seq(smt.IntSort()), smt.BoolSort()) >>> induct_list(x, P) |- Implies(And(P(Empty(Seq(Int))), ForAll([hd!..., tl!...], Implies(P(tl!...), P(Concat(Unit(hd!...), tl!...))))), P(x))
- Parameters:
x (SeqRef)
- kdrag.theories.seq.seq(*args)
Helper to construct sequences. >>> seq(1, 2, 3) Concat(Unit(1), Concat(Unit(2), Unit(3))) >>> seq(1) Unit(1)
"""
Built in smtlib theory of finite sequences.
"""
import kdrag as kd
import kdrag.smt as smt
# induct_list List style induction
# induct_snoc
# concat induction
# Strong induction
def induct_list(x: smt.SeqRef, P):
"""
>>> x = smt.Const("x", Seq(smt.IntSort()))
>>> P = smt.Function("P", Seq(smt.IntSort()), smt.BoolSort())
>>> induct_list(x, P)
|- Implies(And(P(Empty(Seq(Int))),
ForAll([hd!..., tl!...],
Implies(P(tl!...),
P(Concat(Unit(hd!...), tl!...))))),
P(x))
"""
assert isinstance(x, smt.SeqRef)
hd = smt.FreshConst(x.sort().basis(), prefix="hd")
tl = smt.FreshConst(x.sort(), prefix="tl")
return kd.axiom(
smt.Implies(
smt.And(
P(smt.Empty(x.sort())),
kd.QForAll([hd, tl], P(tl), P(smt.Unit(hd) + tl)),
),
P(x),
)
)
def induct(T: smt.SortRef, P) -> kd.kernel.Proof:
z = smt.FreshConst(T, prefix="z")
sort = smt.SeqSort(T)
x, y = smt.FreshConst(sort), smt.FreshConst(sort)
return kd.axiom(
smt.And(
P(smt.Empty(sort)),
kd.QForAll([z], P(smt.Unit(z))),
kd.QForAll([x, y], P(x), P(y), P(smt.Concat(x, y))),
) # -------------------------------------------------
== kd.QForAll([x], P(x))
)
def seq(*args):
"""
Helper to construct sequences.
>>> seq(1, 2, 3)
Concat(Unit(1), Concat(Unit(2), Unit(3)))
>>> seq(1)
Unit(1)
"""
if len(args) == 0:
raise ValueError(
"seq() requires at least one argument. use smt.Empty(sort) instead."
)
elif len(args) == 1:
return smt.Unit(smt._py2expr(args[0]))
else:
return smt.Concat(*[smt.Unit(smt._py2expr(a)) for a in args])
def Seq(T: smt.SortRef) -> smt.SeqSortRef:
"""
Make sort of Sequences and prove useful lemmas.
>>> BoolSeq = Seq(smt.BoolSort())
>>> x,y,z = smt.Consts("x y z", BoolSeq)
>>> x + y
Concat(x, y)
"""
S = smt.SeqSort(T)
x, y, z = smt.Consts("x y z", S)
empty = smt.Empty(S)
S.empty = empty
S.concat_empty = kd.prove(kd.QForAll([x], empty + x == x))
S.empty_concat = kd.prove(kd.QForAll([x], x + empty == x))
S.concat_assoc = kd.prove(
kd.QForAll(
[x, y, z],
(x + y) + z == x + (y + z),
)
)
S.length_empty = kd.prove(kd.QForAll([x], smt.Length(empty) == 0))
S.length_unit = kd.prove(kd.QForAll([x], smt.Length(smt.Unit(x)) == 1))
S.concat_length = kd.prove(
kd.QForAll([x, y], smt.Length(x + y) == smt.Length(x) + smt.Length(y))
)
S.length_zero_unique = kd.prove(
kd.QForAll([x], (smt.Length(x) == 0) == (x == empty))
)
S.concat_head = kd.prove(
kd.QForAll(
[x],
smt.Length(x) > 0,
smt.Unit(x[0]) + smt.SubSeq(x, 1, smt.Length(x) - 1) == x,
)
)
n, m = smt.Ints("n m")
S.subseq_zero = kd.prove(kd.QForAll([x, n], smt.SubSeq(x, n, 0) == empty))
S.subseq_length = kd.prove(
kd.QForAll(
[x, n, m],
m >= 0,
n >= 0,
n + m <= smt.Length(x),
smt.Length(smt.SubSeq(x, n, m)) == m,
)
)
S.subseq_all = kd.prove(kd.QForAll([x], smt.SubSeq(x, 0, smt.Length(x)) == x))
S.subseq_concat = kd.prove(
kd.QForAll(
[x, n],
n >= 0,
n <= smt.Length(x),
smt.SubSeq(x, 0, n) + smt.SubSeq(x, n, smt.Length(x) - n) == x,
)
)
# S.head_length = kd.prove(
# kd.QForAll(
# [x], smt.Length(x) != 0, x[0] + smt.SubSeq(x, 1, smt.Length(x) - 1) == x
# )
# )
S.contains_empty = kd.prove(smt.ForAll([x], smt.Contains(x, empty)))
S.contains_self = kd.prove(smt.ForAll([x], smt.Contains(x, x)))
S.contains_concat_left = kd.prove(
kd.QForAll([x, y, z], smt.Contains(x, z), smt.Contains(x + y, z))
)
S.contains_concat_right = kd.prove(
kd.QForAll([x, y, z], smt.Contains(y, z), smt.Contains(x + y, z))
)
S.contains_subseq = kd.prove(smt.ForAll([x], smt.Contains(x, smt.SubSeq(x, n, m))))
# self.contains_unit = kd.kernel.prove(
# kd.QForAll([x, y], smt.Contains(smt.Unit(x), y) == (smt.Unit(x) == y))
# )
S.empty_contains = kd.kernel.prove(
kd.QForAll([x], smt.Contains(empty, x), (x == empty))
)
# InRe, Extract, IndexOf, LastIndexOf, prefixof, replace, suffixof
# SeqMap, SeqMapI, SeqFoldLeft, SeqFoldLeftI
# Contains
return S
def Unit(x: smt.ExprRef) -> smt.SeqRef:
"""
Construct a sequence of length 1.
"""
return smt.Unit(x)