knuckledragger 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. kdrag/__init__.py +191 -0
  2. kdrag/all.py +17 -0
  3. kdrag/config.py +19 -0
  4. kdrag/contrib/__init__.py +0 -0
  5. kdrag/contrib/absint/knownbit.py +138 -0
  6. kdrag/contrib/data_modulo/__init__.py +6 -0
  7. kdrag/contrib/expr/__init__.py +113 -0
  8. kdrag/contrib/fast/.gitignore +1 -0
  9. kdrag/contrib/fast/Makefile +3 -0
  10. kdrag/contrib/fast/__init__.py +74 -0
  11. kdrag/contrib/fast/fast.c +76 -0
  12. kdrag/contrib/fast/fast.h +3 -0
  13. kdrag/contrib/fast/tests.c +47 -0
  14. kdrag/contrib/hoare.py +183 -0
  15. kdrag/contrib/junk_drawer/algebra.py +0 -0
  16. kdrag/contrib/junk_drawer/generic.py +266 -0
  17. kdrag/contrib/junk_drawer/list.py +40 -0
  18. kdrag/contrib/pcode/README.md +49 -0
  19. kdrag/contrib/pcode/__init__.py +726 -0
  20. kdrag/contrib/pcode/__main__.py +113 -0
  21. kdrag/contrib/pcode/asmspec.py +793 -0
  22. kdrag/contrib/yosys/__init__.py +354 -0
  23. kdrag/datatype.py +610 -0
  24. kdrag/hypothesis.py +305 -0
  25. kdrag/kernel.py +693 -0
  26. kdrag/modal.py +123 -0
  27. kdrag/notation.py +549 -0
  28. kdrag/parsers/__init__.py +0 -0
  29. kdrag/parsers/microlean.py +261 -0
  30. kdrag/parsers/sexp.py +121 -0
  31. kdrag/parsers/smtlib.py +62 -0
  32. kdrag/parsers/tptp.py +96 -0
  33. kdrag/parsers/trs.py +45 -0
  34. kdrag/printers/__init__.py +5 -0
  35. kdrag/printers/c.py +241 -0
  36. kdrag/printers/lean.py +182 -0
  37. kdrag/printers/llvm.py +0 -0
  38. kdrag/printers/rust.py +75 -0
  39. kdrag/printers/verilog.py +124 -0
  40. kdrag/property.py +102 -0
  41. kdrag/reflect.py +775 -0
  42. kdrag/rewrite.py +767 -0
  43. kdrag/smt.py +578 -0
  44. kdrag/smt.pyi +8316 -0
  45. kdrag/solvers/.gitignore +19 -0
  46. kdrag/solvers/__init__.py +925 -0
  47. kdrag/solvers/__main__.py +50 -0
  48. kdrag/solvers/aprove.py +41 -0
  49. kdrag/solvers/datalog.py +109 -0
  50. kdrag/solvers/egglog.py +77 -0
  51. kdrag/solvers/egraph.py +371 -0
  52. kdrag/solvers/install.sh +82 -0
  53. kdrag/solvers/kb/__init__.py +173 -0
  54. kdrag/solvers/kb/multiset.py +199 -0
  55. kdrag/solvers/kb/string.py +170 -0
  56. kdrag/solvers/ljt.py +126 -0
  57. kdrag/solvers/prolog.py +193 -0
  58. kdrag/solvers/sympy.py +403 -0
  59. kdrag/tactics.py +1646 -0
  60. kdrag/tele.py +407 -0
  61. kdrag/theories/__init__.py +3 -0
  62. kdrag/theories/algebra/__init__.py +73 -0
  63. kdrag/theories/algebra/category.py +22 -0
  64. kdrag/theories/algebra/filter.py +52 -0
  65. kdrag/theories/algebra/group.py +157 -0
  66. kdrag/theories/algebra/kleene.py +0 -0
  67. kdrag/theories/algebra/lattice.py +34 -0
  68. kdrag/theories/algebra/ordering.py +33 -0
  69. kdrag/theories/algebra/sqmatrix.py +68 -0
  70. kdrag/theories/algebra/topology.py +65 -0
  71. kdrag/theories/algebra/vector.py +144 -0
  72. kdrag/theories/bitvec.py +360 -0
  73. kdrag/theories/bool.py +87 -0
  74. kdrag/theories/fixed.py +27 -0
  75. kdrag/theories/float.py +237 -0
  76. kdrag/theories/fun.py +31 -0
  77. kdrag/theories/int.py +180 -0
  78. kdrag/theories/list.py +69 -0
  79. kdrag/theories/logic/GAT.py +0 -0
  80. kdrag/theories/logic/__init__.py +0 -0
  81. kdrag/theories/logic/axioms.py +288 -0
  82. kdrag/theories/logic/computable.py +45 -0
  83. kdrag/theories/logic/ideas.md +8 -0
  84. kdrag/theories/logic/intuitionistic.py +134 -0
  85. kdrag/theories/logic/nominal.py +31 -0
  86. kdrag/theories/logic/ordinal.py +0 -0
  87. kdrag/theories/logic/peano.py +35 -0
  88. kdrag/theories/logic/robinson.py +36 -0
  89. kdrag/theories/logic/sear.py +0 -0
  90. kdrag/theories/logic/sep.py +135 -0
  91. kdrag/theories/logic/temporal.py +327 -0
  92. kdrag/theories/logic/zf.py +664 -0
  93. kdrag/theories/nat.py +115 -0
  94. kdrag/theories/option.py +50 -0
  95. kdrag/theories/real/__init__.py +425 -0
  96. kdrag/theories/real/analysis.py +50 -0
  97. kdrag/theories/real/arb.py +280 -0
  98. kdrag/theories/real/complex.py +97 -0
  99. kdrag/theories/real/extended.py +85 -0
  100. kdrag/theories/real/geometry.py +22 -0
  101. kdrag/theories/real/interval.py +89 -0
  102. kdrag/theories/real/ndarray.py +32 -0
  103. kdrag/theories/real/seq.py +239 -0
  104. kdrag/theories/real/vec.py +148 -0
  105. kdrag/theories/regex.py +107 -0
  106. kdrag/theories/seq.py +189 -0
  107. kdrag/theories/set.py +397 -0
  108. kdrag/theories/sexp.py +112 -0
  109. kdrag/utils.py +1294 -0
  110. knuckledragger-0.1.3.dist-info/METADATA +267 -0
  111. knuckledragger-0.1.3.dist-info/RECORD +112 -0
  112. knuckledragger-0.1.3.dist-info/WHEEL +4 -0
kdrag/__init__.py ADDED
@@ -0,0 +1,191 @@
1
+ """
2
+ Knuckledragger is an attempt at creating a down to earth,
3
+ highly automated interactive proof assistant in python.
4
+ It is not attempting to be the most interesting, expressive,
5
+ or flexible logic in the world.
6
+
7
+ The goal is to support applications like software/hardware verification,
8
+ calculus, equational reasoning, and numerical bounds.
9
+ """
10
+
11
+ from . import smt
12
+ from . import kernel
13
+ from . import notation
14
+ from . import utils
15
+ from . import datatype
16
+ from . import rewrite
17
+ from . import tactics
18
+ import functools
19
+
20
+
21
+ Proof = kernel.Proof
22
+
23
+
24
+ prove = tactics.prove
25
+
26
+
27
+ axiom = kernel.axiom
28
+
29
+
30
+ define = kernel.define
31
+
32
+ FreshVar = kernel.FreshVar
33
+
34
+ FreshVars = tactics.FreshVars
35
+
36
+ QImplies = notation.QImplies
37
+
38
+ QForAll = notation.QForAll
39
+
40
+ QExists = notation.QExists
41
+
42
+
43
+ cond = notation.cond
44
+
45
+
46
+ Inductive = kernel.Inductive
47
+
48
+
49
+ Struct = datatype.Struct
50
+
51
+
52
+ NewType = datatype.NewType
53
+
54
+
55
+ InductiveRel = datatype.InductiveRel
56
+
57
+
58
+ Enum = datatype.Enum
59
+
60
+
61
+ Calc = tactics.Calc
62
+
63
+
64
+ Lemma = tactics.Lemma
65
+ Theorem = tactics.Theorem
66
+ PTheorem = tactics.PTheorem
67
+
68
+ simp = rewrite.simp
69
+
70
+ search = utils.search
71
+
72
+ # TODO: Remove this
73
+ R = smt.RealSort()
74
+ Z = smt.IntSort()
75
+ RSeq = Z >> R
76
+ RFun = R >> R
77
+
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
+
167
+ __all__ = [
168
+ "prove",
169
+ "axiom",
170
+ "define",
171
+ "Proof",
172
+ "FreshVar",
173
+ "FreshVars",
174
+ "QImplies",
175
+ "QForAll",
176
+ "QExists",
177
+ "cond",
178
+ "Struct",
179
+ "NewType",
180
+ "Inductive",
181
+ "Calc",
182
+ "Lemma",
183
+ "Theorem",
184
+ "PTheorem",
185
+ "R",
186
+ "Z",
187
+ "RSeq",
188
+ "RFun",
189
+ "simp",
190
+ "search",
191
+ ]
kdrag/all.py ADDED
@@ -0,0 +1,17 @@
1
+ """
2
+ A convenience module to import commonly needed other modules as shorthands
3
+ """
4
+
5
+ import kdrag as kd
6
+ import kdrag.smt as smt
7
+
8
+ # import kdrag.theories.real as real
9
+ import kdrag.solvers as solvers
10
+ import kdrag.theories as thy
11
+ import kdrag.rewrite as rw
12
+ import kdrag.tele as tele
13
+
14
+ import kdrag.theories.option as option
15
+ import kdrag.theories.list as list_
16
+ import kdrag.theories.set as set_
17
+ import kdrag.theories.seq as seq
kdrag/config.py ADDED
@@ -0,0 +1,19 @@
1
+ """
2
+ Global configuration of Knuckledragger
3
+ """
4
+
5
+ solver = None
6
+ admit_enabled = True
7
+ # timeout = 1000
8
+ admit_level = 50
9
+
10
+
11
+ # TODO: Someday, when it is annoyingly slow to check built in theories, we can add a flag to disable them
12
+ # check_lib = True
13
+ timing = False
14
+ perf_log = []
15
+
16
+
17
+ def perf_event(tag, data, time):
18
+ if timing:
19
+ perf_log.append((tag, data, time))
File without changes
@@ -0,0 +1,138 @@
1
+ """
2
+ Known Bits Abstract Domain
3
+
4
+ https://pypy.org/posts/2024/08/toy-knownbits.html
5
+ https://arxiv.org/pdf/2105.05398 Sound, Precise, and Fast Abstract Interpretation with Tristate Numbers
6
+ """
7
+
8
+ import kdrag as kd
9
+ import kdrag.smt as smt
10
+ import functools
11
+
12
+
13
+ def Knowns(x):
14
+ return ~x.unknowns
15
+
16
+
17
+ def Zeros(x):
18
+ return ~x.unknowns & ~x.ones
19
+
20
+
21
+ def Concat(a, b):
22
+ """
23
+ >>> a = KB1.const(1) # 1
24
+ >>> b = KB1.const(0) # 0
25
+ >>> Concat(a, b)
26
+ KnownBits_2(Concat(ones(const(1)), ones(const(0))),
27
+ Concat(unknowns(const(1)), unknowns(const(0))))
28
+ """
29
+ sa = a.ones.size()
30
+ sb = b.ones.size()
31
+ return KB(sa + sb).T.mk(
32
+ smt.Concat(a.ones, b.ones), smt.Concat(a.unknowns, b.unknowns)
33
+ )
34
+
35
+
36
+ class KnownBits:
37
+ def __init__(self, W):
38
+ self.W = W
39
+ KnownBits = kd.Struct(
40
+ f"KnownBits_{W}",
41
+ ("ones", smt.BitVecSort(W)),
42
+ ("unknowns", smt.BitVecSort(W)),
43
+ )
44
+ self.T = KnownBits
45
+ x, y, z = smt.Consts("x y z", KnownBits)
46
+ a, b, c = smt.Consts("a b c", smt.BitVecSort(W))
47
+
48
+ setof = kd.define(
49
+ "setof",
50
+ [x],
51
+ smt.Lambda([a], (~x.unknowns & a) == x.ones),
52
+ )
53
+ self.setof = setof
54
+ self.getitem = kd.notation.getitem.register(
55
+ KnownBits, lambda a, idx: setof(a)[idx]
56
+ )
57
+
58
+ kd.prove(KnownBits.mk(0, 0)[0], unfold=1)
59
+
60
+ self.wf = kd.notation.wf.define([x], (x.ones & x.unknowns) == 0)
61
+
62
+ const = kd.define("const", [a], KnownBits.mk(a, 0))
63
+ self.const = const
64
+ is_const = kd.define("is_const", [x], x.unknowns == 0)
65
+ self.is_const = is_const
66
+
67
+ self.set_const = kd.prove(smt.ForAll([a], const(a)[a]), unfold=1)
68
+
69
+ self.is_const_unique = kd.prove(
70
+ kd.QForAll(
71
+ [x], is_const(x), smt.Exists([a], kd.QForAll([b], x[b], a == b))
72
+ ),
73
+ unfold=1,
74
+ )
75
+
76
+ top = KnownBits.mk(0, -1)
77
+ self.set_top = kd.prove(smt.ForAll([a], top[a]), unfold=1)
78
+
79
+ zeros = kd.define("zeros", [x], Zeros(x))
80
+ self.zeros = zeros
81
+
82
+ invert = kd.notation.invert.define([x], KnownBits.mk(Zeros(x), x.unknowns))
83
+ self.invert = invert
84
+
85
+ self.invert_const = kd.prove(smt.ForAll([a], ~const(a) == const(~a)), unfold=1)
86
+ self.invert_top = kd.prove(~top == top, unfold=1)
87
+ self.invert_invol = kd.prove(kd.QForAll([x], invert(invert(x)) == x), unfold=1)
88
+ self.set_invert = kd.prove(kd.QForAll([x, a], x[a], (~x)[~a]), unfold=1)
89
+
90
+ _ones = x.ones & y.ones
91
+ _knowns = Zeros(x) | Zeros(y) | _ones
92
+ self.and_ = kd.notation.and_.define([x, y], KnownBits.mk(_ones, ~_knowns))
93
+
94
+ self.and_const = kd.prove(
95
+ kd.QForAll([a, b], const(a) & const(b) == const(a & b)), unfold=1
96
+ )
97
+ # and_top = kd.prove(kd.QForAll([x], x & top == ?), unfold=1)
98
+ self.and_comm = kd.prove(kd.QForAll([x, y], x & y == y & x), unfold=1)
99
+ self.and_assoc = kd.prove(
100
+ kd.QForAll([x, y, z], (x & y) & z == x & (y & z)), unfold=1
101
+ )
102
+ self.set_and = kd.prove(
103
+ kd.QForAll([x, y, a, b], x[a], y[b], (x & y)[a & b]), unfold=1
104
+ )
105
+
106
+ _ones = x.ones | y.ones
107
+ _zeros = Zeros(x) & Zeros(y)
108
+ _knowns = _ones | _zeros
109
+ self.or_ = kd.notation.or_.define([x, y], KnownBits.mk(_ones, ~_knowns))
110
+
111
+ self.or_const = kd.prove(
112
+ kd.QForAll([a, b], const(a) | const(b) == const(a | b)), unfold=1
113
+ )
114
+ # or_top = kd.prove(kd.QForAll([x], x | top == ?), unfold=1)
115
+ self.or_comm = kd.prove(kd.QForAll([x, y], x | y == y | x), unfold=1)
116
+ self.or_assoc = kd.prove(
117
+ kd.QForAll([x, y, z], (x | y) | z == x | (y | z)), unfold=1
118
+ )
119
+ self.set_or = kd.prove(
120
+ kd.QForAll([x, y, a, b], x[a], y[b], (x | y)[a | b]), unfold=1
121
+ )
122
+
123
+
124
+ @functools.cache
125
+ def KB(W):
126
+ return KnownBits(W)
127
+
128
+
129
+ KB1 = KB(1)
130
+
131
+
132
+ def test():
133
+ """
134
+ >>> True
135
+ True
136
+ >>> KB8 = KnownBits(8)
137
+ >>> KB1 = KnownBits(1)
138
+ """
@@ -0,0 +1,6 @@
1
+ """
2
+ Datastructures with symmetry
3
+ - Sets
4
+ - Multisets
5
+ - Alpha
6
+ """
@@ -0,0 +1,113 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class Context:
6
+ counter = 0
7
+
8
+
9
+ _main_ctx = Context()
10
+
11
+
12
+ def main_ctx():
13
+ return _main_ctx
14
+
15
+
16
+ @dataclass
17
+ class AstRef:
18
+ ctx: Context
19
+
20
+ def eq(self, other):
21
+ return self is other
22
+
23
+ def get_id(self):
24
+ return id(self)
25
+
26
+
27
+ @dataclass
28
+ class SortRef(AstRef):
29
+ _kind: object
30
+ _name: str
31
+
32
+ def kind(self):
33
+ return self._kind
34
+
35
+ def name(self):
36
+ return self._name
37
+
38
+
39
+ @dataclass
40
+ class TypeVarRef(AstRef):
41
+ pass
42
+
43
+
44
+ @dataclass
45
+ class FuncDeclRef(AstRef):
46
+ _name: str
47
+ _domain: tuple[SortRef, ...]
48
+ _range: SortRef
49
+
50
+ def name(self):
51
+ return self._name
52
+
53
+ def arity(self):
54
+ return len(self._domain)
55
+
56
+ def domain(self, i):
57
+ return self._domain[i]
58
+
59
+ def range(self):
60
+ return self._range
61
+
62
+ def __call__(self, *args):
63
+ assert len(args) == len(self._domain)
64
+ return ExprRef(ctx=self.ctx, _decl=self, _args=args)
65
+
66
+ # params. huh
67
+
68
+
69
+ def Function(name, *sig, ctx=None):
70
+ assert len(sig) > 0
71
+ if ctx is None:
72
+ ctx = main_ctx()
73
+ return FuncDeclRef(ctx, name, sig[:-1], sig[-1])
74
+
75
+
76
+ @dataclass
77
+ class ExprRef(AstRef):
78
+ _decl: FuncDeclRef
79
+ _args: tuple[AstRef, ...]
80
+
81
+ def arg(self, i):
82
+ return self._args[i]
83
+
84
+ def children(self):
85
+ return list(self._args)
86
+
87
+ def decl(self):
88
+ return self._decl
89
+
90
+ def num_args(self):
91
+ return len(self._args)
92
+
93
+ def _sort(self):
94
+ return self._decl.range()
95
+
96
+ def __eq__(self, other):
97
+ raise NotImplementedError
98
+
99
+ def __ne__(self, other):
100
+ raise NotImplementedError
101
+
102
+
103
+ def Const(name: str, sort: SortRef, ctx=None) -> ExprRef:
104
+ """ """
105
+ return Function(name, sort, ctx=ctx)()
106
+
107
+
108
+ def Consts(names: str, sort: SortRef) -> list[ExprRef]:
109
+ return [Const(name, sort, ctx=sort.ctx) for name in names.split()]
110
+
111
+
112
+ def FreshConst(sort: SortRef, prefix="c"):
113
+ return Const(prefix + "!" + str(sort.ctx.counter), sort)
@@ -0,0 +1 @@
1
+ test
@@ -0,0 +1,3 @@
1
+ all: tests.c fast.c fast.h
2
+ gcc -Wextra -Wall -Werror -fanalyzer -g -fsanitize=address -fsanitize=undefined fast.c tests.c -l z3 -o test
3
+ ./test
@@ -0,0 +1,74 @@
1
+ from cffi import FFI
2
+ import tempfile
3
+ import os
4
+ import sys
5
+ from pathlib import Path
6
+ import z3
7
+
8
+ ffibuilder = FFI()
9
+
10
+ ffibuilder.cdef("""
11
+ int myadd(int a, int b);
12
+ const char* z3_version();
13
+ typedef struct z3_config *Z3_config;
14
+ typedef struct z3_context *Z3_context;
15
+ typedef void *Z3_ast;
16
+ typedef void *Z3_ast_vector;
17
+ Z3_ast my_mk_true(Z3_context ctx);
18
+ Z3_ast my_mk_and(Z3_context ctx, Z3_ast a, Z3_ast b);
19
+ Z3_ast_vector KDRAG_get_consts(Z3_context ctx, Z3_ast t);
20
+ """)
21
+ z3lib = Path(z3.__file__).parent.absolute() / "lib"
22
+ z3_include = Path(z3.__file__).parent.absolute() / "include"
23
+ ffibuilder.set_source(
24
+ "_fast",
25
+ "",
26
+ sources=[str(Path(__file__).parent.absolute() / "fast.c")],
27
+ library_dirs=[str(z3lib)],
28
+ include_dirs=[str(z3_include)],
29
+ libraries=["z3"],
30
+ )
31
+ # shenangians to build in temp directory
32
+ dir0 = os.getcwd()
33
+ tmpdir = tempfile.mkdtemp()
34
+ os.chdir(tmpdir)
35
+ ffibuilder.compile(verbose=True)
36
+ sys.path.insert(1, tmpdir)
37
+ os.chdir(dir0)
38
+
39
+ from _fast.lib import * # noqa: E402, F403 # type: ignore
40
+
41
+
42
+ def ctxptr(ctx: z3.Context):
43
+ return ffibuilder.cast("void *", ctx.ctx.value) # type: ignore
44
+
45
+
46
+ def astptr(ast: z3.AstRef):
47
+ return ffibuilder.cast("void *", ast.as_ast().value) # type: ignore
48
+
49
+
50
+ def intify(ptr):
51
+ return int(ffibuilder.cast("uintptr_t", ptr))
52
+
53
+
54
+ def test():
55
+ """
56
+ >>> myadd(2, 3)
57
+ 5
58
+ >>> ctx = ffibuilder.cast("void *", z3.main_ctx().ctx.value)
59
+ >>> ast = my_mk_true(ctx)
60
+ >>> value = intify(ast)
61
+ >>> z3.BoolRef(value)
62
+ True
63
+ >>> z3.BoolRef(intify(my_mk_and(ctx, ast, ast)))
64
+ And(True, True)
65
+ >>> z3.AstVector(intify(KDRAG_get_consts(ctx, ast)), z3.main_ctx())
66
+ [True]
67
+ >>> x = z3.Int("x")
68
+ >>> z3.AstVector(intify(KDRAG_get_consts(ctx, astptr(x + x + x))), z3.main_ctx())
69
+ [x]
70
+ """
71
+
72
+ # >>> intify(my_mk_and(ctx, ast, ast))
73
+ # >>> FFI().string(z3_version())
74
+ # >>> my_mk_true(ffibuilder.cast("Z3_context", z3.main_ctx().ctx.value))
@@ -0,0 +1,76 @@
1
+ #include "z3.h"
2
+ #include <stdio.h>
3
+ #include <stdlib.h>
4
+ #include <string.h>
5
+ int myadd(int a, int b) { return a + b; }
6
+
7
+ const char *hello = "hello from fast.c";
8
+ const char *z3_version() {
9
+ puts(Z3_get_full_version());
10
+ char *test = (char *)malloc(sizeof(char) * 10);
11
+ if (!test)
12
+ return NULL;
13
+ test[0] = 'h';
14
+ test[1] = 'e';
15
+ test[2] = 'l';
16
+ test[3] = 'l';
17
+ test[4] = 'o';
18
+ test[5] = '\0';
19
+ strncpy(test, Z3_get_full_version(), 9);
20
+ return test; //
21
+ // return "hello"; // Z3_get_full_version();//hello;
22
+ }
23
+
24
+ Z3_ast my_mk_true(Z3_context ctx) { return Z3_mk_true(ctx); }
25
+
26
+ Z3_ast my_mk_and(Z3_context ctx, Z3_ast a, Z3_ast b) {
27
+ Z3_ast args[2] = {a, b};
28
+ return Z3_mk_and(ctx, 2, args);
29
+ }
30
+
31
+ // https://stackoverflow.com/questions/27200320/maintenance-of-reference-counting-in-z3
32
+ // https://github.com/Z3Prover/z3/blob/master/examples/c/test_capi.c
33
+ Z3_ast_vector KDRAG_get_consts(Z3_context ctx, Z3_ast t) {
34
+ Z3_ast_vector res = Z3_mk_ast_vector(ctx);
35
+ Z3_ast_vector_inc_ref(ctx, res);
36
+ Z3_ast_vector todo = Z3_mk_ast_vector(ctx);
37
+ Z3_ast_vector_inc_ref(ctx, todo);
38
+ // todo: seen set
39
+ // Z3_ast_map seen = Z3_mk_ast_map(ctx);
40
+ // Z3_ast_map_inc_ref(ctx, seen);
41
+
42
+ Z3_ast_vector_push(ctx, todo, t);
43
+ Z3_inc_ref(ctx, t);
44
+ unsigned visited = 0;
45
+ while (visited < Z3_ast_vector_size(ctx, todo)) {
46
+ Z3_ast current = Z3_ast_vector_get(ctx, todo, visited);
47
+ if (Z3_is_app(ctx, current)) {
48
+ Z3_app app = Z3_to_app(ctx, current);
49
+ unsigned num_args = Z3_get_app_num_args(ctx, app);
50
+ if (num_args == 0) { // possible constant
51
+ bool found = false; // already in res?
52
+ for (unsigned i = 0; i < Z3_ast_vector_size(ctx, res); i++) {
53
+ Z3_ast existing = Z3_ast_vector_get(ctx, res, i);
54
+ if (existing == current) {
55
+ found = true;
56
+ break;
57
+ }
58
+ }
59
+ if (!found) {
60
+ Z3_inc_ref(ctx, current);
61
+ Z3_ast_vector_push(ctx, res, current);
62
+ }
63
+ } else { // push args to todo
64
+ for (unsigned j = 0; j < num_args; j++) {
65
+ Z3_ast arg = Z3_get_app_arg(ctx, app, j);
66
+ Z3_inc_ref(ctx, arg);
67
+ Z3_ast_vector_push(ctx, todo, arg);
68
+ }
69
+ }
70
+ }
71
+ Z3_dec_ref(ctx, current);
72
+ visited++;
73
+ }
74
+ Z3_ast_vector_dec_ref(ctx, todo);
75
+ return res;
76
+ }
@@ -0,0 +1,3 @@
1
+ #include "z3.h"
2
+
3
+ Z3_ast_vector KDRAG_get_consts(Z3_context ctx, Z3_ast t);
@@ -0,0 +1,47 @@
1
+ #include "fast.h"
2
+ #include "z3.h"
3
+ #include <assert.h>
4
+ int main() {
5
+ Z3_config cfg = Z3_mk_config();
6
+ Z3_context ctx = Z3_mk_context_rc(cfg);
7
+ Z3_sort sort = Z3_mk_bool_sort(ctx);
8
+ Z3_symbol sym = Z3_mk_string_symbol(ctx, "x");
9
+
10
+ {
11
+ Z3_ast t = Z3_mk_const(ctx, sym, sort);
12
+ Z3_inc_ref(ctx, t);
13
+
14
+ {
15
+ Z3_ast_vector vec = KDRAG_get_consts(ctx, t);
16
+ unsigned size = Z3_ast_vector_size(ctx, vec);
17
+ assert(size == 1 && "there should be one constant");
18
+ for (unsigned i = 0; i < size; i++) {
19
+ Z3_ast ast = Z3_ast_vector_get(ctx, vec, i);
20
+ Z3_dec_ref(ctx, ast);
21
+ }
22
+ Z3_ast_vector_dec_ref(ctx, vec);
23
+ }
24
+
25
+ {
26
+ Z3_ast args[] = {t, t};
27
+ Z3_ast myand = Z3_mk_and(ctx, 2, args);
28
+ // Z3_inc_ref(ctx, myand);
29
+ Z3_ast_vector vec = KDRAG_get_consts(ctx, myand);
30
+ unsigned size = Z3_ast_vector_size(ctx, vec);
31
+ assert(size == 2 && "there should be two constants");
32
+ for (unsigned i = 0; i < size; i++) {
33
+ Z3_ast ast = Z3_ast_vector_get(ctx, vec, i);
34
+ assert(ast == t && "the constant should be t");
35
+ Z3_dec_ref(ctx, ast);
36
+ }
37
+ Z3_dec_ref(ctx, myand);
38
+ Z3_ast_vector_dec_ref(ctx, vec);
39
+ }
40
+
41
+ Z3_dec_ref(ctx, t);
42
+ }
43
+ Z3_del_context(ctx);
44
+ Z3_del_config(cfg);
45
+
46
+ return 0;
47
+ }