knuckledragger 0.1.3__tar.gz

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. knuckledragger-0.1.3/PKG-INFO +267 -0
  2. knuckledragger-0.1.3/README.md +231 -0
  3. knuckledragger-0.1.3/pyproject.toml +119 -0
  4. knuckledragger-0.1.3/src/kdrag/__init__.py +191 -0
  5. knuckledragger-0.1.3/src/kdrag/all.py +17 -0
  6. knuckledragger-0.1.3/src/kdrag/config.py +19 -0
  7. knuckledragger-0.1.3/src/kdrag/contrib/__init__.py +0 -0
  8. knuckledragger-0.1.3/src/kdrag/contrib/absint/knownbit.py +138 -0
  9. knuckledragger-0.1.3/src/kdrag/contrib/data_modulo/__init__.py +6 -0
  10. knuckledragger-0.1.3/src/kdrag/contrib/expr/__init__.py +113 -0
  11. knuckledragger-0.1.3/src/kdrag/contrib/fast/.gitignore +1 -0
  12. knuckledragger-0.1.3/src/kdrag/contrib/fast/Makefile +3 -0
  13. knuckledragger-0.1.3/src/kdrag/contrib/fast/__init__.py +74 -0
  14. knuckledragger-0.1.3/src/kdrag/contrib/fast/fast.c +76 -0
  15. knuckledragger-0.1.3/src/kdrag/contrib/fast/fast.h +3 -0
  16. knuckledragger-0.1.3/src/kdrag/contrib/fast/tests.c +47 -0
  17. knuckledragger-0.1.3/src/kdrag/contrib/hoare.py +183 -0
  18. knuckledragger-0.1.3/src/kdrag/contrib/junk_drawer/algebra.py +0 -0
  19. knuckledragger-0.1.3/src/kdrag/contrib/junk_drawer/generic.py +266 -0
  20. knuckledragger-0.1.3/src/kdrag/contrib/junk_drawer/list.py +40 -0
  21. knuckledragger-0.1.3/src/kdrag/contrib/pcode/README.md +49 -0
  22. knuckledragger-0.1.3/src/kdrag/contrib/pcode/__init__.py +726 -0
  23. knuckledragger-0.1.3/src/kdrag/contrib/pcode/__main__.py +113 -0
  24. knuckledragger-0.1.3/src/kdrag/contrib/pcode/asmspec.py +793 -0
  25. knuckledragger-0.1.3/src/kdrag/contrib/yosys/__init__.py +354 -0
  26. knuckledragger-0.1.3/src/kdrag/datatype.py +610 -0
  27. knuckledragger-0.1.3/src/kdrag/hypothesis.py +305 -0
  28. knuckledragger-0.1.3/src/kdrag/kernel.py +693 -0
  29. knuckledragger-0.1.3/src/kdrag/modal.py +123 -0
  30. knuckledragger-0.1.3/src/kdrag/notation.py +549 -0
  31. knuckledragger-0.1.3/src/kdrag/parsers/__init__.py +0 -0
  32. knuckledragger-0.1.3/src/kdrag/parsers/microlean.py +261 -0
  33. knuckledragger-0.1.3/src/kdrag/parsers/sexp.py +121 -0
  34. knuckledragger-0.1.3/src/kdrag/parsers/smtlib.py +62 -0
  35. knuckledragger-0.1.3/src/kdrag/parsers/tptp.py +96 -0
  36. knuckledragger-0.1.3/src/kdrag/parsers/trs.py +45 -0
  37. knuckledragger-0.1.3/src/kdrag/printers/__init__.py +5 -0
  38. knuckledragger-0.1.3/src/kdrag/printers/c.py +241 -0
  39. knuckledragger-0.1.3/src/kdrag/printers/lean.py +182 -0
  40. knuckledragger-0.1.3/src/kdrag/printers/llvm.py +0 -0
  41. knuckledragger-0.1.3/src/kdrag/printers/rust.py +75 -0
  42. knuckledragger-0.1.3/src/kdrag/printers/verilog.py +124 -0
  43. knuckledragger-0.1.3/src/kdrag/property.py +102 -0
  44. knuckledragger-0.1.3/src/kdrag/reflect.py +775 -0
  45. knuckledragger-0.1.3/src/kdrag/rewrite.py +767 -0
  46. knuckledragger-0.1.3/src/kdrag/smt.py +578 -0
  47. knuckledragger-0.1.3/src/kdrag/smt.pyi +8316 -0
  48. knuckledragger-0.1.3/src/kdrag/solvers/.gitignore +19 -0
  49. knuckledragger-0.1.3/src/kdrag/solvers/__init__.py +925 -0
  50. knuckledragger-0.1.3/src/kdrag/solvers/__main__.py +50 -0
  51. knuckledragger-0.1.3/src/kdrag/solvers/aprove.py +41 -0
  52. knuckledragger-0.1.3/src/kdrag/solvers/datalog.py +109 -0
  53. knuckledragger-0.1.3/src/kdrag/solvers/egglog.py +77 -0
  54. knuckledragger-0.1.3/src/kdrag/solvers/egraph.py +371 -0
  55. knuckledragger-0.1.3/src/kdrag/solvers/install.sh +82 -0
  56. knuckledragger-0.1.3/src/kdrag/solvers/kb/__init__.py +173 -0
  57. knuckledragger-0.1.3/src/kdrag/solvers/kb/multiset.py +199 -0
  58. knuckledragger-0.1.3/src/kdrag/solvers/kb/string.py +170 -0
  59. knuckledragger-0.1.3/src/kdrag/solvers/ljt.py +126 -0
  60. knuckledragger-0.1.3/src/kdrag/solvers/prolog.py +193 -0
  61. knuckledragger-0.1.3/src/kdrag/solvers/sympy.py +403 -0
  62. knuckledragger-0.1.3/src/kdrag/tactics.py +1646 -0
  63. knuckledragger-0.1.3/src/kdrag/tele.py +407 -0
  64. knuckledragger-0.1.3/src/kdrag/theories/__init__.py +3 -0
  65. knuckledragger-0.1.3/src/kdrag/theories/algebra/__init__.py +73 -0
  66. knuckledragger-0.1.3/src/kdrag/theories/algebra/category.py +22 -0
  67. knuckledragger-0.1.3/src/kdrag/theories/algebra/filter.py +52 -0
  68. knuckledragger-0.1.3/src/kdrag/theories/algebra/group.py +157 -0
  69. knuckledragger-0.1.3/src/kdrag/theories/algebra/kleene.py +0 -0
  70. knuckledragger-0.1.3/src/kdrag/theories/algebra/lattice.py +34 -0
  71. knuckledragger-0.1.3/src/kdrag/theories/algebra/ordering.py +33 -0
  72. knuckledragger-0.1.3/src/kdrag/theories/algebra/sqmatrix.py +68 -0
  73. knuckledragger-0.1.3/src/kdrag/theories/algebra/topology.py +65 -0
  74. knuckledragger-0.1.3/src/kdrag/theories/algebra/vector.py +144 -0
  75. knuckledragger-0.1.3/src/kdrag/theories/bitvec.py +360 -0
  76. knuckledragger-0.1.3/src/kdrag/theories/bool.py +87 -0
  77. knuckledragger-0.1.3/src/kdrag/theories/fixed.py +27 -0
  78. knuckledragger-0.1.3/src/kdrag/theories/float.py +237 -0
  79. knuckledragger-0.1.3/src/kdrag/theories/fun.py +31 -0
  80. knuckledragger-0.1.3/src/kdrag/theories/int.py +180 -0
  81. knuckledragger-0.1.3/src/kdrag/theories/list.py +69 -0
  82. knuckledragger-0.1.3/src/kdrag/theories/logic/GAT.py +0 -0
  83. knuckledragger-0.1.3/src/kdrag/theories/logic/__init__.py +0 -0
  84. knuckledragger-0.1.3/src/kdrag/theories/logic/axioms.py +288 -0
  85. knuckledragger-0.1.3/src/kdrag/theories/logic/computable.py +45 -0
  86. knuckledragger-0.1.3/src/kdrag/theories/logic/ideas.md +8 -0
  87. knuckledragger-0.1.3/src/kdrag/theories/logic/intuitionistic.py +134 -0
  88. knuckledragger-0.1.3/src/kdrag/theories/logic/nominal.py +31 -0
  89. knuckledragger-0.1.3/src/kdrag/theories/logic/ordinal.py +0 -0
  90. knuckledragger-0.1.3/src/kdrag/theories/logic/peano.py +35 -0
  91. knuckledragger-0.1.3/src/kdrag/theories/logic/robinson.py +36 -0
  92. knuckledragger-0.1.3/src/kdrag/theories/logic/sear.py +0 -0
  93. knuckledragger-0.1.3/src/kdrag/theories/logic/sep.py +135 -0
  94. knuckledragger-0.1.3/src/kdrag/theories/logic/temporal.py +327 -0
  95. knuckledragger-0.1.3/src/kdrag/theories/logic/zf.py +664 -0
  96. knuckledragger-0.1.3/src/kdrag/theories/nat.py +115 -0
  97. knuckledragger-0.1.3/src/kdrag/theories/option.py +50 -0
  98. knuckledragger-0.1.3/src/kdrag/theories/real/__init__.py +425 -0
  99. knuckledragger-0.1.3/src/kdrag/theories/real/analysis.py +50 -0
  100. knuckledragger-0.1.3/src/kdrag/theories/real/arb.py +280 -0
  101. knuckledragger-0.1.3/src/kdrag/theories/real/complex.py +97 -0
  102. knuckledragger-0.1.3/src/kdrag/theories/real/extended.py +85 -0
  103. knuckledragger-0.1.3/src/kdrag/theories/real/geometry.py +22 -0
  104. knuckledragger-0.1.3/src/kdrag/theories/real/interval.py +89 -0
  105. knuckledragger-0.1.3/src/kdrag/theories/real/ndarray.py +32 -0
  106. knuckledragger-0.1.3/src/kdrag/theories/real/seq.py +239 -0
  107. knuckledragger-0.1.3/src/kdrag/theories/real/vec.py +148 -0
  108. knuckledragger-0.1.3/src/kdrag/theories/regex.py +107 -0
  109. knuckledragger-0.1.3/src/kdrag/theories/seq.py +189 -0
  110. knuckledragger-0.1.3/src/kdrag/theories/set.py +397 -0
  111. knuckledragger-0.1.3/src/kdrag/theories/sexp.py +112 -0
  112. knuckledragger-0.1.3/src/kdrag/utils.py +1294 -0
@@ -0,0 +1,267 @@
1
+ Metadata-Version: 2.4
2
+ Name: knuckledragger
3
+ Version: 0.1.3
4
+ Summary: Interactive Theorem Prover
5
+ Author: Philip Zucker
6
+ Author-email: Philip Zucker <philzuckerblog@gmail.com>
7
+ License-Expression: MIT
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
11
+ Classifier: Topic :: Software Development :: Disassemblers
12
+ Requires-Dist: z3-solver>=4.15.4
13
+ Requires-Dist: lark>=1.3.1
14
+ Requires-Dist: pytest>=6.0 ; extra == 'dev'
15
+ Requires-Dist: nbclient ; extra == 'dev'
16
+ Requires-Dist: jupyter ; extra == 'dev'
17
+ Requires-Dist: hypothesis>=6.124.1 ; extra == 'dev'
18
+ Requires-Dist: cle>=9.2.148 ; extra == 'pypcode'
19
+ Requires-Dist: pypcode>=3.0.3 ; extra == 'pypcode'
20
+ Requires-Dist: click>=8.1.8 ; extra == 'pypcode'
21
+ Requires-Dist: maturin>=1.8.6 ; extra == 'rust'
22
+ Requires-Dist: egglog>=9.0.0 ; extra == 'solvers'
23
+ Requires-Dist: python-flint ; extra == 'solvers'
24
+ Requires-Dist: sympy ; extra == 'solvers'
25
+ Requires-Dist: cffi>=2.0.0 ; extra == 'solvers'
26
+ Requires-Dist: graphviz>=0.20.3 ; extra == 'solvers'
27
+ Requires-Dist: yowasp-yosys>=0.50.0.0.post858 ; extra == 'yosys'
28
+ Requires-Python: >=3.12
29
+ Project-URL: homepage, https://github.com/philzook58/knuckledragger
30
+ Provides-Extra: dev
31
+ Provides-Extra: pypcode
32
+ Provides-Extra: rust
33
+ Provides-Extra: solvers
34
+ Provides-Extra: yosys
35
+ Description-Content-Type: text/markdown
36
+
37
+ # Knuckledragger
38
+
39
+ <img src="https://raw.githubusercontent.com/philzook58/knuckledragger/main/docs/logo.webp" alt="drawing" width="200" align="left"/>
40
+
41
+ Knuckledragger ([git repo](https://github.com/philzook58/knuckledragger)) is an attempt at creating a down to earth, highly automated interactive proof assistant in python. The goal is to support applications like software/hardware verification, calculus, equational reasoning, and numerical bounds.
42
+
43
+ <br clear="left"/>
44
+
45
+ ## Installation
46
+
47
+ To install run
48
+
49
+ ```bash
50
+ python3 -m pip install git+https://github.com/philzook58/knuckledragger.git
51
+ ```
52
+
53
+ Or to install locally
54
+
55
+ ```bash
56
+ git clone https://github.com/philzook58/knuckledragger.git
57
+ cd knuckledragger
58
+ python3 -m pip install -e .
59
+ ```
60
+
61
+ ## Getting Started
62
+
63
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](http://colab.research.google.com/github/philzook58/knuckledragger/blob/main/tutorial.ipynb)
64
+
65
+ ```python
66
+ import kdrag as kd
67
+ import kdrag.smt as smt # smt is literally a reexporting of z3
68
+
69
+ # Anything Z3 can do on it's own, we can "prove" with no extra work
70
+ p,q = smt.Bools("p q")
71
+ simple_taut = kd.prove(smt.Implies(p, smt.Or(p, q)))
72
+
73
+ # The returned objects are `Proof`, not smt.ExprRef` formulas
74
+ assert isinstance(simple_taut, kd.Proof)
75
+ assert not isinstance(simple_taut, smt.ExprRef)
76
+
77
+ # kd.prove will throw an error if the theorem is not provable
78
+ try:
79
+ false_lemma = kd.prove(smt.Implies(p, smt.And(p, q)), timeout=10)
80
+ print("This will not be reached")
81
+ except kd.kernel.LemmaError as e:
82
+ pass
83
+
84
+ # Z3 also supports things like Reals, Ints, BitVectors and strings
85
+ x = smt.Real("x")
86
+ real_trich = kd.prove(smt.ForAll([x], smt.Or(x < 0, x == 0, 0 < x)))
87
+
88
+ x = smt.BitVec("x", 32)
89
+ or_idem = kd.prove(smt.ForAll([x], x | x == x))
90
+
91
+ ###################################################################
92
+ ###################################################################
93
+
94
+ # But the point of Knuckledragger is really for the things Z3 can't do in one shot
95
+
96
+ # Knuckledragger support algebraic datatypes and induction
97
+ Nat = kd.Inductive("MyNat")
98
+ Zero = Nat.declare("Zero")
99
+ Succ = Nat.declare("Succ", ("pred", Nat))
100
+ Nat = Nat.create()
101
+
102
+ # We can define an addition function by cases
103
+ n,m = smt.Consts("n m", Nat)
104
+ add = smt.Function("add", Nat, Nat, Nat)
105
+ add = kd.define("add", [n,m],
106
+ kd.cond(
107
+ (n.is_Zero, m),
108
+ (n.is_Succ, Nat.Succ(add(n.pred, m)))
109
+ ))
110
+
111
+ # There is a notation overloading mechanism modelled after python's singledispatch
112
+ kd.notation.add.register(Nat, add)
113
+
114
+ # The definitional lemma is not available to the solver unless you give it
115
+ add_zero_x = kd.prove(smt.ForAll([n], Nat.Zero + n == n), by=[add.defn])
116
+ add_succ_x = kd.prove(smt.ForAll([n,m], Nat.Succ(n) + m == Nat.Succ(n + m)), by=[add.defn])
117
+
118
+ # More involved proofs can be more easily done in an interactive tactic
119
+ # Under the hood, this boils down to calls to kd.prove
120
+ # These proofs are best understood by seeing the interactive output in a Jupyter notebook
121
+ l = kd.Lemma(smt.ForAll([n], n + Nat.Zero == n))
122
+ # Output: [] ?|= ForAll(n, add(n, Zero) == n)
123
+
124
+ _n = l.fix()
125
+ # Output: [] ?|= add(n!0, Zero) == n!2213
126
+
127
+ l.induct(_n)
128
+ # Output: [] ?|= add(Zero, Zero) == Zero
129
+
130
+ # Base case
131
+ l.auto(by=[add.defn])
132
+ # Output: [] ?|= ForAll(a!0, Implies(add(a!0, Zero) == a!0, add(Succ(a!0), Zero) == Succ(a!0)))
133
+
134
+ # Inductive case
135
+ l.auto(by=[add.defn])
136
+ # Output: Nothing to do!
137
+
138
+ # Finally the actual Proof is built
139
+ add_x_zero = l.qed()
140
+
141
+ ###################################################################
142
+ ###################################################################
143
+
144
+ # But we can also build our own sorts and axiomatic theories.
145
+ # https://en.wikipedia.org/wiki/Group_(mathematics)
146
+ G = smt.DeclareSort("G")
147
+ mul = smt.Function("mul", G, G, G)
148
+ e = smt.Const("e", G)
149
+ inv = smt.Function("inv", G, G)
150
+
151
+ kd.notation.mul.register(G, mul)
152
+
153
+ x, y, z = smt.Consts("x y z", G)
154
+ mul_assoc = kd.axiom(smt.ForAll([x, y, z], x * (y * z) == (x * y) * z))
155
+ id_left = kd.axiom(smt.ForAll([x], e * x == x))
156
+ inv_left = kd.axiom(smt.ForAll([x], inv(x) * x == e))
157
+
158
+ # The Calc tactic can allow one to write explicit equational proofs
159
+ c = kd.Calc([x], x * inv(x))
160
+ c.eq(e * (x * inv(x)), by=[id_left])
161
+ c.eq((inv(inv(x)) * inv(x)) * (x * inv(x)), by=[inv_left])
162
+ c.eq(inv(inv(x)) * ((inv(x) * x) * inv(x)), by=[mul_assoc])
163
+ c.eq(inv(inv(x)) * (e * inv(x)), by=[inv_left])
164
+ c.eq(inv(inv(x)) * inv(x), by=[id_left])
165
+ c.eq(e, by=[inv_left])
166
+ inv_right = c.qed()
167
+ ```
168
+
169
+ For more on using z3py
170
+
171
+ - <https://ericpony.github.io/z3py-tutorial/guide-examples.htm>
172
+ - The z3 guide <https://microsoft.github.io/z3guide/>
173
+ - The z3py [documentation](https://z3prover.github.io/api/html/namespacez3py.html)
174
+ - <https://github.com/philzook58/z3_tutorial> ([video](https://www.youtube.com/watch?v=56IIrBZy9Rc&feature=youtu.be&ab_channel=BroadInstitute))
175
+
176
+ For more on interactive theorem proving (This is a lot to take in)
177
+
178
+ - [Software Foundations](https://softwarefoundations.cis.upenn.edu/) - Coq
179
+ - [Theorem Proving in Lean 4](https://lean-lang.org/theorem_proving_in_lean4/title_page.html)
180
+ - [Mathematics in Lean](https://leanprover-community.github.io/mathematics_in_lean/)
181
+ - [Isabelle Tutorial](https://isabelle.in.tum.de/documentation.html)
182
+ - [HOL Light Tutorial](https://hol-light.github.io/tutorial.pdf)
183
+
184
+ A recent summary talk of Knuckledragger was presented at NEPLS 2025
185
+
186
+ [![Watch the video](https://img.youtube.com/vi/ENwKBC8dN4M/default.jpg)](https://youtu.be/ENwKBC8dN4M)
187
+
188
+ ## Blog Posts
189
+
190
+ - [ZF style set theory in Knuckledragger I](https://www.philipzucker.com/zf_knuckle1/)
191
+ - [Proving the Infinitude of Primes in Knuckledragger](https://www.philipzucker.com/knuckle_primes/)
192
+ - [Proof Rules for MetaSMT](https://www.philipzucker.com/kdrag_proof_rules/)
193
+ - [A Python CLI for Verifying Assembly](https://www.philipzucker.com/asm_verify3/)
194
+ - [Knuckledragger Analysis Etudes](https://www.philipzucker.com/knuckle_analysis1/)
195
+ - [Semantic Refinement/Dependent Typing for Knuckledragger/SMTLIB Pt 1](https://www.philipzucker.com/refinement_kdrag1/)
196
+ - [Verified Assembly 2: Memory, RISC-V, Cuts for Invariants, and Ghost Code](https://www.philipzucker.com/asm_verify2/)
197
+ - [Semi-Automated Assembly Verification in Python using pypcode Semantics](https://www.philipzucker.com/assembly_verify/)
198
+ - [NEPLS 2025 and a Short Talk on Knuckledragger](https://www.philipzucker.com/nepls_2025/) [video](https://www.youtube.com/watch?v=ENwKBC8dN4M&ab_channel=PhilipZucker)
199
+ - ["Verified" "Compilation" of "Python" with Knuckledragger, GCC, and Ghidra](https://www.philipzucker.com/knuckle_C_pcode/)
200
+ - [A Small Prolog on the Z3 AST](https://www.philipzucker.com/knuck_prolog/)
201
+ - [Shallow Embedding Logics in Z3 pt. I](https://www.philipzucker.com/shallow_logic_knuckle/)
202
+ - [Knuth Bendix Solver on Z3 AST](https://www.philipzucker.com/knuth_bendix_knuck/)
203
+ - [Generics and Typeclasses in Knuckledragger](https://www.philipzucker.com/knuckle_typeclass/)
204
+ - [More Knuckledragger: Simp, Inductive Relations, Sympy NbE, and Software Foundations](https://www.philipzucker.com/knuckle_update_nbe/)
205
+ - [Translating Cody's Lean Sheffer Stroke Proof to Knuckledragger with ChatGPT](https://www.philipzucker.com/cody_sheffer/)
206
+ - ['Lean-style' Tactics in Knuckledragger](https://www.philipzucker.com/knuckle_lemma/)
207
+ - [State of Knuckledragger, a Semi-Automated Python Proof Assistant](https://www.philipzucker.com/state_o_knuck/)
208
+ - [Proving Sum n = n*(n-1)/2 and that 1/n tends to 0](https://www.philipzucker.com/analysis_knuckle/)
209
+ - [Peano Nats in Interactive SMT](https://www.philipzucker.com/sqrt2_2/)
210
+ - [Experiments in the Irrationality of Sqrt 2 with SMT](https://www.philipzucker.com/sqrt2/)
211
+ - [Knuckledragger Update: ATP for Python Interactive Theorem Proving](https://www.philipzucker.com/knuckledrag2/)
212
+ - [Knuckledragger: Experimenting with a Python Proof Assistant](https://www.philipzucker.com/python-itp/)
213
+
214
+ ## Comparison to Other Systems
215
+
216
+ - [Z3](https://github.com/Z3Prover/z3): Knuckledragger has a superset of the capabilities of Z3 since it is built on top of it. Enables rigorous chaining of Z3 calls. Better facilities for higher order and quantifier reasoning.
217
+ - [sympy](https://www.sympy.org/) and sage: More manual manipulation is to be expected, but also more logically sound. Everything is integrated in a cohesive fabric of first order logic.
218
+ - Lean and Coq: No dependent types, larger trusted code base, a higher baseline of automation.
219
+ - [Isabelle](https://isabelle.in.tum.de/) and [HOLpy](https://gitee.com/bhzhan/holpy): Knuckledragger is similar in many respects to the systems. It has a lack of parametric types and weaker higher order reasoning. Knuckledragger is a library, not a framework. Heavy reuse of already existing python things is preferred whenever possible (Jupyter, z3py, sympy, python idioms). It is seamlessly integrated with z3py.
220
+
221
+ ## Design
222
+
223
+ It is not desirable or within my capabilities to build a giant universe in which to live. The goal is to take a subtle blade and bolt together things that already exist.
224
+
225
+ Using widespread and commonly supported languages gives a huge leg up in terms of tooling and audience. Python is the modern lingua franca of computing. It has a first class interactive experience and extensive bindings to projects in other languages.
226
+
227
+ Core functionality comes from [Z3](https://github.com/Z3Prover/z3). The Z3 python api is a de facto standard. The term and formula data structures of knuckledragger are literally z3 python terms and formula. To some degree, Knuckledragger is a metalayer to guide smt through proofs it could perhaps do on its own, but it would get lost.
228
+
229
+ A hope is to be able to use easy access to [Jupyter](https://jupyter.org/), [copilot](https://copilot.microsoft.com/), ML ecosystems, [sympy](https://www.sympy.org/), [cvxpy](https://www.cvxpy.org/), [numpy](https://numpy.org/), [scipy](https://scipy.org/), [egglog](https://egglog-python.readthedocs.io/latest/), [Julia](https://github.com/JuliaPy/PythonCall.jl), [Prolog](https://www.swi-prolog.org/pldoc/man?section=janus-call-prolog), [Maude](https://fadoss.github.io/maude-bindings/), [calcium](https://fredrikj.net/calcium/), [flint](https://fredrikj.net/python-flint/), [Mathematica](https://reference.wolfram.com/language/WolframClientForPython/), and [sage](https://www.sagemath.org/) will make metaprogramming in this system very powerful. I maintain the option to just trust these results but hopefully they can be translated into arguments the kernel can understand.
230
+
231
+ The core logic is more or less multi-sorted first order logic aka [SMT-LIB2](https://smt-lib.org/).
232
+
233
+ Big features that ATPs do not often support are induction, definitions, and other axiom schema. Knuckledragger supports these.
234
+
235
+ Other theorem provers of interest: [cvc5](https://cvc5.github.io/), [Vampire](https://vprover.github.io/), [eprover](https://wwwlehre.dhbw-stuttgart.de/~sschulz/E/E.html), [Twee](https://nick8325.github.io/twee/), [nanoCoP](https://leancop.de/nanocop/).
236
+
237
+ The de Bruijn criterion is going to be bent or broken in certain senses. Attention is paid to what is kernel and what is not. Proof objects are basically trees recording chains of lemmas discharged by Automated Theorem Prover (ATP) calls. Soundness will be attempted, accidental misuse will be made difficult but not impossible.
238
+
239
+ Isabelle and ACL2 are the strongest influences. If you want dependent type theory, you are at a level of investment and sophistication that it behooves you to be in another system. Should there be a strong automated DTT solver someday, I will reconsider.
240
+
241
+ ## FAQ
242
+
243
+ - Is this for proving about properties about python programs?
244
+ - Not directly. Proving properties of general python programs in a highly assured manner is extremely difficult due to its extreme dynamic nature. There are a couple caveats to this answer.
245
+ 1. Knuckledragger does enable you to model your algorithms and extract/interpret them to python.
246
+ 2. A subset of purely-function, strongly-typed python can be reflected directly into the Knuckledragger logic.
247
+ 3. Domain specific modelling of important python ecosystem libraries is a WIP.
248
+ - Is Knuckledragger python specific?
249
+ - Python is a useful and important platform, but the core of the design can be ported to many languages. The design is based around the chaining of calls to z3 which gets you a lot of distance for free.
250
+ - [SBV](https://hackage.haskell.org/package/sbv-11.0/docs/Data-SBV-Tools-KnuckleDragger.html) - Haskell
251
+ - Yours here!
252
+
253
+ ## License & Citation
254
+
255
+ MIT licensed. See LICENSE for more information.
256
+
257
+ Citing this repository is highly appreciated but not required by the license.
258
+
259
+ ```
260
+ @software{knuckledragger2025,
261
+ author = {Philip Zucker},
262
+ title = {{Knuckledragger: A Low Barrier Proof Assistant}},
263
+ url = {https://github.com/philzook58/knuckledragger},
264
+ month = {1},
265
+ year = {2025}
266
+ }
267
+ ```
@@ -0,0 +1,231 @@
1
+ # Knuckledragger
2
+
3
+ <img src="https://raw.githubusercontent.com/philzook58/knuckledragger/main/docs/logo.webp" alt="drawing" width="200" align="left"/>
4
+
5
+ Knuckledragger ([git repo](https://github.com/philzook58/knuckledragger)) is an attempt at creating a down to earth, highly automated interactive proof assistant in python. The goal is to support applications like software/hardware verification, calculus, equational reasoning, and numerical bounds.
6
+
7
+ <br clear="left"/>
8
+
9
+ ## Installation
10
+
11
+ To install run
12
+
13
+ ```bash
14
+ python3 -m pip install git+https://github.com/philzook58/knuckledragger.git
15
+ ```
16
+
17
+ Or to install locally
18
+
19
+ ```bash
20
+ git clone https://github.com/philzook58/knuckledragger.git
21
+ cd knuckledragger
22
+ python3 -m pip install -e .
23
+ ```
24
+
25
+ ## Getting Started
26
+
27
+ [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](http://colab.research.google.com/github/philzook58/knuckledragger/blob/main/tutorial.ipynb)
28
+
29
+ ```python
30
+ import kdrag as kd
31
+ import kdrag.smt as smt # smt is literally a reexporting of z3
32
+
33
+ # Anything Z3 can do on it's own, we can "prove" with no extra work
34
+ p,q = smt.Bools("p q")
35
+ simple_taut = kd.prove(smt.Implies(p, smt.Or(p, q)))
36
+
37
+ # The returned objects are `Proof`, not smt.ExprRef` formulas
38
+ assert isinstance(simple_taut, kd.Proof)
39
+ assert not isinstance(simple_taut, smt.ExprRef)
40
+
41
+ # kd.prove will throw an error if the theorem is not provable
42
+ try:
43
+ false_lemma = kd.prove(smt.Implies(p, smt.And(p, q)), timeout=10)
44
+ print("This will not be reached")
45
+ except kd.kernel.LemmaError as e:
46
+ pass
47
+
48
+ # Z3 also supports things like Reals, Ints, BitVectors and strings
49
+ x = smt.Real("x")
50
+ real_trich = kd.prove(smt.ForAll([x], smt.Or(x < 0, x == 0, 0 < x)))
51
+
52
+ x = smt.BitVec("x", 32)
53
+ or_idem = kd.prove(smt.ForAll([x], x | x == x))
54
+
55
+ ###################################################################
56
+ ###################################################################
57
+
58
+ # But the point of Knuckledragger is really for the things Z3 can't do in one shot
59
+
60
+ # Knuckledragger support algebraic datatypes and induction
61
+ Nat = kd.Inductive("MyNat")
62
+ Zero = Nat.declare("Zero")
63
+ Succ = Nat.declare("Succ", ("pred", Nat))
64
+ Nat = Nat.create()
65
+
66
+ # We can define an addition function by cases
67
+ n,m = smt.Consts("n m", Nat)
68
+ add = smt.Function("add", Nat, Nat, Nat)
69
+ add = kd.define("add", [n,m],
70
+ kd.cond(
71
+ (n.is_Zero, m),
72
+ (n.is_Succ, Nat.Succ(add(n.pred, m)))
73
+ ))
74
+
75
+ # There is a notation overloading mechanism modelled after python's singledispatch
76
+ kd.notation.add.register(Nat, add)
77
+
78
+ # The definitional lemma is not available to the solver unless you give it
79
+ add_zero_x = kd.prove(smt.ForAll([n], Nat.Zero + n == n), by=[add.defn])
80
+ add_succ_x = kd.prove(smt.ForAll([n,m], Nat.Succ(n) + m == Nat.Succ(n + m)), by=[add.defn])
81
+
82
+ # More involved proofs can be more easily done in an interactive tactic
83
+ # Under the hood, this boils down to calls to kd.prove
84
+ # These proofs are best understood by seeing the interactive output in a Jupyter notebook
85
+ l = kd.Lemma(smt.ForAll([n], n + Nat.Zero == n))
86
+ # Output: [] ?|= ForAll(n, add(n, Zero) == n)
87
+
88
+ _n = l.fix()
89
+ # Output: [] ?|= add(n!0, Zero) == n!2213
90
+
91
+ l.induct(_n)
92
+ # Output: [] ?|= add(Zero, Zero) == Zero
93
+
94
+ # Base case
95
+ l.auto(by=[add.defn])
96
+ # Output: [] ?|= ForAll(a!0, Implies(add(a!0, Zero) == a!0, add(Succ(a!0), Zero) == Succ(a!0)))
97
+
98
+ # Inductive case
99
+ l.auto(by=[add.defn])
100
+ # Output: Nothing to do!
101
+
102
+ # Finally the actual Proof is built
103
+ add_x_zero = l.qed()
104
+
105
+ ###################################################################
106
+ ###################################################################
107
+
108
+ # But we can also build our own sorts and axiomatic theories.
109
+ # https://en.wikipedia.org/wiki/Group_(mathematics)
110
+ G = smt.DeclareSort("G")
111
+ mul = smt.Function("mul", G, G, G)
112
+ e = smt.Const("e", G)
113
+ inv = smt.Function("inv", G, G)
114
+
115
+ kd.notation.mul.register(G, mul)
116
+
117
+ x, y, z = smt.Consts("x y z", G)
118
+ mul_assoc = kd.axiom(smt.ForAll([x, y, z], x * (y * z) == (x * y) * z))
119
+ id_left = kd.axiom(smt.ForAll([x], e * x == x))
120
+ inv_left = kd.axiom(smt.ForAll([x], inv(x) * x == e))
121
+
122
+ # The Calc tactic can allow one to write explicit equational proofs
123
+ c = kd.Calc([x], x * inv(x))
124
+ c.eq(e * (x * inv(x)), by=[id_left])
125
+ c.eq((inv(inv(x)) * inv(x)) * (x * inv(x)), by=[inv_left])
126
+ c.eq(inv(inv(x)) * ((inv(x) * x) * inv(x)), by=[mul_assoc])
127
+ c.eq(inv(inv(x)) * (e * inv(x)), by=[inv_left])
128
+ c.eq(inv(inv(x)) * inv(x), by=[id_left])
129
+ c.eq(e, by=[inv_left])
130
+ inv_right = c.qed()
131
+ ```
132
+
133
+ For more on using z3py
134
+
135
+ - <https://ericpony.github.io/z3py-tutorial/guide-examples.htm>
136
+ - The z3 guide <https://microsoft.github.io/z3guide/>
137
+ - The z3py [documentation](https://z3prover.github.io/api/html/namespacez3py.html)
138
+ - <https://github.com/philzook58/z3_tutorial> ([video](https://www.youtube.com/watch?v=56IIrBZy9Rc&feature=youtu.be&ab_channel=BroadInstitute))
139
+
140
+ For more on interactive theorem proving (This is a lot to take in)
141
+
142
+ - [Software Foundations](https://softwarefoundations.cis.upenn.edu/) - Coq
143
+ - [Theorem Proving in Lean 4](https://lean-lang.org/theorem_proving_in_lean4/title_page.html)
144
+ - [Mathematics in Lean](https://leanprover-community.github.io/mathematics_in_lean/)
145
+ - [Isabelle Tutorial](https://isabelle.in.tum.de/documentation.html)
146
+ - [HOL Light Tutorial](https://hol-light.github.io/tutorial.pdf)
147
+
148
+ A recent summary talk of Knuckledragger was presented at NEPLS 2025
149
+
150
+ [![Watch the video](https://img.youtube.com/vi/ENwKBC8dN4M/default.jpg)](https://youtu.be/ENwKBC8dN4M)
151
+
152
+ ## Blog Posts
153
+
154
+ - [ZF style set theory in Knuckledragger I](https://www.philipzucker.com/zf_knuckle1/)
155
+ - [Proving the Infinitude of Primes in Knuckledragger](https://www.philipzucker.com/knuckle_primes/)
156
+ - [Proof Rules for MetaSMT](https://www.philipzucker.com/kdrag_proof_rules/)
157
+ - [A Python CLI for Verifying Assembly](https://www.philipzucker.com/asm_verify3/)
158
+ - [Knuckledragger Analysis Etudes](https://www.philipzucker.com/knuckle_analysis1/)
159
+ - [Semantic Refinement/Dependent Typing for Knuckledragger/SMTLIB Pt 1](https://www.philipzucker.com/refinement_kdrag1/)
160
+ - [Verified Assembly 2: Memory, RISC-V, Cuts for Invariants, and Ghost Code](https://www.philipzucker.com/asm_verify2/)
161
+ - [Semi-Automated Assembly Verification in Python using pypcode Semantics](https://www.philipzucker.com/assembly_verify/)
162
+ - [NEPLS 2025 and a Short Talk on Knuckledragger](https://www.philipzucker.com/nepls_2025/) [video](https://www.youtube.com/watch?v=ENwKBC8dN4M&ab_channel=PhilipZucker)
163
+ - ["Verified" "Compilation" of "Python" with Knuckledragger, GCC, and Ghidra](https://www.philipzucker.com/knuckle_C_pcode/)
164
+ - [A Small Prolog on the Z3 AST](https://www.philipzucker.com/knuck_prolog/)
165
+ - [Shallow Embedding Logics in Z3 pt. I](https://www.philipzucker.com/shallow_logic_knuckle/)
166
+ - [Knuth Bendix Solver on Z3 AST](https://www.philipzucker.com/knuth_bendix_knuck/)
167
+ - [Generics and Typeclasses in Knuckledragger](https://www.philipzucker.com/knuckle_typeclass/)
168
+ - [More Knuckledragger: Simp, Inductive Relations, Sympy NbE, and Software Foundations](https://www.philipzucker.com/knuckle_update_nbe/)
169
+ - [Translating Cody's Lean Sheffer Stroke Proof to Knuckledragger with ChatGPT](https://www.philipzucker.com/cody_sheffer/)
170
+ - ['Lean-style' Tactics in Knuckledragger](https://www.philipzucker.com/knuckle_lemma/)
171
+ - [State of Knuckledragger, a Semi-Automated Python Proof Assistant](https://www.philipzucker.com/state_o_knuck/)
172
+ - [Proving Sum n = n*(n-1)/2 and that 1/n tends to 0](https://www.philipzucker.com/analysis_knuckle/)
173
+ - [Peano Nats in Interactive SMT](https://www.philipzucker.com/sqrt2_2/)
174
+ - [Experiments in the Irrationality of Sqrt 2 with SMT](https://www.philipzucker.com/sqrt2/)
175
+ - [Knuckledragger Update: ATP for Python Interactive Theorem Proving](https://www.philipzucker.com/knuckledrag2/)
176
+ - [Knuckledragger: Experimenting with a Python Proof Assistant](https://www.philipzucker.com/python-itp/)
177
+
178
+ ## Comparison to Other Systems
179
+
180
+ - [Z3](https://github.com/Z3Prover/z3): Knuckledragger has a superset of the capabilities of Z3 since it is built on top of it. Enables rigorous chaining of Z3 calls. Better facilities for higher order and quantifier reasoning.
181
+ - [sympy](https://www.sympy.org/) and sage: More manual manipulation is to be expected, but also more logically sound. Everything is integrated in a cohesive fabric of first order logic.
182
+ - Lean and Coq: No dependent types, larger trusted code base, a higher baseline of automation.
183
+ - [Isabelle](https://isabelle.in.tum.de/) and [HOLpy](https://gitee.com/bhzhan/holpy): Knuckledragger is similar in many respects to the systems. It has a lack of parametric types and weaker higher order reasoning. Knuckledragger is a library, not a framework. Heavy reuse of already existing python things is preferred whenever possible (Jupyter, z3py, sympy, python idioms). It is seamlessly integrated with z3py.
184
+
185
+ ## Design
186
+
187
+ It is not desirable or within my capabilities to build a giant universe in which to live. The goal is to take a subtle blade and bolt together things that already exist.
188
+
189
+ Using widespread and commonly supported languages gives a huge leg up in terms of tooling and audience. Python is the modern lingua franca of computing. It has a first class interactive experience and extensive bindings to projects in other languages.
190
+
191
+ Core functionality comes from [Z3](https://github.com/Z3Prover/z3). The Z3 python api is a de facto standard. The term and formula data structures of knuckledragger are literally z3 python terms and formula. To some degree, Knuckledragger is a metalayer to guide smt through proofs it could perhaps do on its own, but it would get lost.
192
+
193
+ A hope is to be able to use easy access to [Jupyter](https://jupyter.org/), [copilot](https://copilot.microsoft.com/), ML ecosystems, [sympy](https://www.sympy.org/), [cvxpy](https://www.cvxpy.org/), [numpy](https://numpy.org/), [scipy](https://scipy.org/), [egglog](https://egglog-python.readthedocs.io/latest/), [Julia](https://github.com/JuliaPy/PythonCall.jl), [Prolog](https://www.swi-prolog.org/pldoc/man?section=janus-call-prolog), [Maude](https://fadoss.github.io/maude-bindings/), [calcium](https://fredrikj.net/calcium/), [flint](https://fredrikj.net/python-flint/), [Mathematica](https://reference.wolfram.com/language/WolframClientForPython/), and [sage](https://www.sagemath.org/) will make metaprogramming in this system very powerful. I maintain the option to just trust these results but hopefully they can be translated into arguments the kernel can understand.
194
+
195
+ The core logic is more or less multi-sorted first order logic aka [SMT-LIB2](https://smt-lib.org/).
196
+
197
+ Big features that ATPs do not often support are induction, definitions, and other axiom schema. Knuckledragger supports these.
198
+
199
+ Other theorem provers of interest: [cvc5](https://cvc5.github.io/), [Vampire](https://vprover.github.io/), [eprover](https://wwwlehre.dhbw-stuttgart.de/~sschulz/E/E.html), [Twee](https://nick8325.github.io/twee/), [nanoCoP](https://leancop.de/nanocop/).
200
+
201
+ The de Bruijn criterion is going to be bent or broken in certain senses. Attention is paid to what is kernel and what is not. Proof objects are basically trees recording chains of lemmas discharged by Automated Theorem Prover (ATP) calls. Soundness will be attempted, accidental misuse will be made difficult but not impossible.
202
+
203
+ Isabelle and ACL2 are the strongest influences. If you want dependent type theory, you are at a level of investment and sophistication that it behooves you to be in another system. Should there be a strong automated DTT solver someday, I will reconsider.
204
+
205
+ ## FAQ
206
+
207
+ - Is this for proving about properties about python programs?
208
+ - Not directly. Proving properties of general python programs in a highly assured manner is extremely difficult due to its extreme dynamic nature. There are a couple caveats to this answer.
209
+ 1. Knuckledragger does enable you to model your algorithms and extract/interpret them to python.
210
+ 2. A subset of purely-function, strongly-typed python can be reflected directly into the Knuckledragger logic.
211
+ 3. Domain specific modelling of important python ecosystem libraries is a WIP.
212
+ - Is Knuckledragger python specific?
213
+ - Python is a useful and important platform, but the core of the design can be ported to many languages. The design is based around the chaining of calls to z3 which gets you a lot of distance for free.
214
+ - [SBV](https://hackage.haskell.org/package/sbv-11.0/docs/Data-SBV-Tools-KnuckleDragger.html) - Haskell
215
+ - Yours here!
216
+
217
+ ## License & Citation
218
+
219
+ MIT licensed. See LICENSE for more information.
220
+
221
+ Citing this repository is highly appreciated but not required by the license.
222
+
223
+ ```
224
+ @software{knuckledragger2025,
225
+ author = {Philip Zucker},
226
+ title = {{Knuckledragger: A Low Barrier Proof Assistant}},
227
+ url = {https://github.com/philzook58/knuckledragger},
228
+ month = {1},
229
+ year = {2025}
230
+ }
231
+ ```
@@ -0,0 +1,119 @@
1
+ [project]
2
+ name = "knuckledragger"
3
+ version = "0.1.3"
4
+ authors = [{ name = "Philip Zucker", email = "philzuckerblog@gmail.com" }]
5
+ description = "Interactive Theorem Prover"
6
+ readme = "README.md"
7
+ license = "MIT"
8
+ classifiers = [
9
+ "Programming Language :: Python :: 3",
10
+ "Operating System :: OS Independent",
11
+ "Topic :: Scientific/Engineering :: Mathematics",
12
+ "Topic :: Software Development :: Disassemblers",
13
+
14
+ ]
15
+ requires-python = ">= 3.12"
16
+ dependencies = ["z3-solver >= 4.15.4", "lark>=1.3.1"]
17
+ [project.urls]
18
+ homepage = "https://github.com/philzook58/knuckledragger"
19
+
20
+ # For raw pip?
21
+ [project.optional-dependencies]
22
+ dev = ["pytest>=6.0", "nbclient", "jupyter", "hypothesis>=6.124.1"]
23
+ yosys = ["yowasp-yosys>=0.50.0.0.post858"]
24
+ pypcode = ["cle>=9.2.148", "pypcode>=3.0.3", "click>=8.1.8"]
25
+ rust = ["maturin>=1.8.6"]
26
+ solvers = [
27
+ "egglog >= 9.0.0",
28
+ "python-flint",
29
+ "sympy",
30
+ "cffi>=2.0.0",
31
+ "graphviz>=0.20.3",
32
+ ]
33
+
34
+ [build-system]
35
+ requires = ["uv_build>=0.9.9,<0.10.0"]
36
+ build-backend = "uv_build"
37
+ [tool.uv.build-backend]
38
+ source-exclude = [
39
+ "solvers/Prover9",
40
+ "solvers/gappa*",
41
+ "solvers/eprover",
42
+ "solvers/kissat",
43
+ "solvers/TPTP4X",
44
+ "solvers/nanoCoP-i20",
45
+ "solvers/*.zip",
46
+ "solvers/*.tar.gz",
47
+ "solvers/*.jar",
48
+ "solvers/eprover-ho",
49
+ "solvers/twee",
50
+ "solvers/vampire",
51
+ "solvers/vampire-ho",
52
+ "contrib/fast/test",
53
+ ]
54
+ module-name = "kdrag"
55
+
56
+ [tool.setuptools]
57
+ include-package-data = true
58
+ #package-dir = { "" = "kdrag" }
59
+ #packages = ["kdrag"] # automatic discovery is better
60
+ [tool.setuptools.package-data]
61
+ knuckledragger = ["*.sh", "*.c"]
62
+
63
+ [tool.ruff]
64
+ exclude = ["tests"]
65
+
66
+ [tool.ruff.lint]
67
+ ignore = ["E741"]
68
+
69
+ [tool.ruff.lint.per-file-ignores]
70
+ "src/kdrag/smt.py" = ["F405", "F403"]
71
+ "src/kdrag/all.py" = ["F401"]
72
+ "tutorial.ipynb" = ["F811"]
73
+ "examples/**/*.py" = ["F401", "F405", "F403", "E402"]
74
+ "examples/short_talk.ipynb" = ["F401"]
75
+
76
+ [tool.pyright]
77
+ include = ["src"]
78
+ exclude = [
79
+ "src/kdrag/solvers/eprover/*",
80
+ "src/kdrag/solvers/gappa*",
81
+ "src/kdrag/solvers/Prover9/*",
82
+ ]
83
+
84
+ [tool.ty.src]
85
+ include = ["src"]
86
+ exclude = [
87
+ "src/kdrag/solvers/eprover/*",
88
+ "src/kdrag/solvers/gappa*",
89
+ "src/kdrag/solvers/Prover9/*",
90
+ ]
91
+
92
+ [tool.pytest.ini_options]
93
+ norecursedirs = [
94
+ "rust/target",
95
+ "solvers/eprover",
96
+ "solvers/gappa*",
97
+ "solvers/Prover9",
98
+ "examples/converted_notebooks",
99
+ ]
100
+ addopts = "--doctest-modules"
101
+ doctest_optionflags = "ELLIPSIS NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL"
102
+
103
+ markers = ["slow: Marks tests as long-running."]
104
+
105
+ [dependency-groups]
106
+ dev = [
107
+ "jupyter>=1.1.1",
108
+ "nbclient>=0.10.2",
109
+ "pyright>=1.1.392.post0",
110
+ "pytest>=8.3.4",
111
+ "ruff>=0.11.13",
112
+ ]
113
+ rust = ["maturin[patchelf]>=1.8.6"]
114
+
115
+ [[tool.uv.index]]
116
+ name = "testpypi"
117
+ url = "https://test.pypi.org/simple/"
118
+ publish-url = "https://test.pypi.org/legacy/"
119
+ explicit = true