oxiz 0.1.0__cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.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.
- oxiz/__init__.py +5 -0
- oxiz/oxiz.cpython-313t-aarch64-linux-gnu.so +0 -0
- oxiz-0.1.0.dist-info/METADATA +389 -0
- oxiz-0.1.0.dist-info/RECORD +5 -0
- oxiz-0.1.0.dist-info/WHEEL +5 -0
oxiz/__init__.py
ADDED
|
Binary file
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: oxiz
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Programming Language :: Rust
|
|
5
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
6
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
20
|
+
Summary: Python bindings for OxiZ SMT Solver
|
|
21
|
+
Keywords: smt,solver,sat,verification,logic,theorem-prover
|
|
22
|
+
License: MIT OR Apache-2.0
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
25
|
+
Project-URL: Documentation, https://docs.rs/oxiz
|
|
26
|
+
Project-URL: Homepage, https://github.com/cool-japan/oxiz
|
|
27
|
+
Project-URL: Repository, https://github.com/cool-japan/oxiz
|
|
28
|
+
|
|
29
|
+
# OxiZ Python Bindings
|
|
30
|
+
|
|
31
|
+
Python bindings for the OxiZ SMT (Satisfiability Modulo Theories) solver.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
### From PyPI (when published)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install oxiz
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### From Source
|
|
42
|
+
|
|
43
|
+
Requires [Rust](https://rustup.rs/) and [maturin](https://github.com/PyO3/maturin):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Install maturin
|
|
47
|
+
pip install maturin
|
|
48
|
+
|
|
49
|
+
# Build and install
|
|
50
|
+
cd oxiz-py
|
|
51
|
+
maturin develop --release
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
import oxiz
|
|
58
|
+
|
|
59
|
+
# Create a term manager and solver
|
|
60
|
+
tm = oxiz.TermManager()
|
|
61
|
+
solver = oxiz.Solver()
|
|
62
|
+
|
|
63
|
+
# Create integer variables
|
|
64
|
+
x = tm.mk_var("x", "Int")
|
|
65
|
+
y = tm.mk_var("y", "Int")
|
|
66
|
+
|
|
67
|
+
# Create constants
|
|
68
|
+
ten = tm.mk_int(10)
|
|
69
|
+
five = tm.mk_int(5)
|
|
70
|
+
|
|
71
|
+
# Create constraints: x + y = 10, x > 5
|
|
72
|
+
sum_xy = tm.mk_add([x, y])
|
|
73
|
+
constraint1 = tm.mk_eq(sum_xy, ten)
|
|
74
|
+
constraint2 = tm.mk_gt(x, five)
|
|
75
|
+
|
|
76
|
+
# Assert constraints
|
|
77
|
+
solver.assert_term(constraint1, tm)
|
|
78
|
+
solver.assert_term(constraint2, tm)
|
|
79
|
+
|
|
80
|
+
# Check satisfiability
|
|
81
|
+
result = solver.check_sat(tm)
|
|
82
|
+
print(f"Result: {result}") # sat
|
|
83
|
+
|
|
84
|
+
if result == oxiz.SolverResult.Sat:
|
|
85
|
+
model = solver.get_model(tm)
|
|
86
|
+
print(f"x = {model['x']}, y = {model['y']}")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## API Reference
|
|
90
|
+
|
|
91
|
+
### TermManager
|
|
92
|
+
|
|
93
|
+
The `TermManager` creates and manages terms (expressions).
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
tm = oxiz.TermManager()
|
|
97
|
+
|
|
98
|
+
# Variables
|
|
99
|
+
x = tm.mk_var("x", "Int") # Integer variable
|
|
100
|
+
b = tm.mk_var("b", "Bool") # Boolean variable
|
|
101
|
+
r = tm.mk_var("r", "Real") # Real variable
|
|
102
|
+
|
|
103
|
+
# Constants
|
|
104
|
+
t = tm.mk_bool(True) # Boolean true
|
|
105
|
+
f = tm.mk_bool(False) # Boolean false
|
|
106
|
+
n = tm.mk_int(42) # Integer constant
|
|
107
|
+
q = tm.mk_real(3, 4) # Rational 3/4
|
|
108
|
+
|
|
109
|
+
# Boolean operations
|
|
110
|
+
not_b = tm.mk_not(b)
|
|
111
|
+
and_term = tm.mk_and([b, t])
|
|
112
|
+
or_term = tm.mk_or([b, f])
|
|
113
|
+
implies = tm.mk_implies(b, t)
|
|
114
|
+
|
|
115
|
+
# Arithmetic operations
|
|
116
|
+
sum_term = tm.mk_add([x, n])
|
|
117
|
+
diff = tm.mk_sub(x, n)
|
|
118
|
+
prod = tm.mk_mul([x, n])
|
|
119
|
+
neg = tm.mk_neg(x)
|
|
120
|
+
div = tm.mk_div(x, n)
|
|
121
|
+
mod = tm.mk_mod(x, n)
|
|
122
|
+
|
|
123
|
+
# Comparisons
|
|
124
|
+
eq = tm.mk_eq(x, n) # x = 42
|
|
125
|
+
lt = tm.mk_lt(x, n) # x < 42
|
|
126
|
+
le = tm.mk_le(x, n) # x <= 42
|
|
127
|
+
gt = tm.mk_gt(x, n) # x > 42
|
|
128
|
+
ge = tm.mk_ge(x, n) # x >= 42
|
|
129
|
+
|
|
130
|
+
# Other
|
|
131
|
+
ite = tm.mk_ite(b, x, n) # if b then x else 42
|
|
132
|
+
distinct = tm.mk_distinct([x, n]) # x != 42
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Solver
|
|
136
|
+
|
|
137
|
+
The `Solver` checks satisfiability of constraints.
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
solver = oxiz.Solver()
|
|
141
|
+
|
|
142
|
+
# Set logic (optional)
|
|
143
|
+
solver.set_logic("QF_LIA") # Quantifier-free Linear Integer Arithmetic
|
|
144
|
+
|
|
145
|
+
# Add constraints
|
|
146
|
+
solver.assert_term(constraint, tm)
|
|
147
|
+
|
|
148
|
+
# Check satisfiability
|
|
149
|
+
result = solver.check_sat(tm)
|
|
150
|
+
|
|
151
|
+
# Get model (if sat)
|
|
152
|
+
if result == oxiz.SolverResult.Sat:
|
|
153
|
+
model = solver.get_model(tm)
|
|
154
|
+
|
|
155
|
+
# Push/pop for incremental solving
|
|
156
|
+
solver.push()
|
|
157
|
+
solver.assert_term(additional_constraint, tm)
|
|
158
|
+
result = solver.check_sat(tm)
|
|
159
|
+
solver.pop() # Removes additional_constraint
|
|
160
|
+
|
|
161
|
+
# Reset solver
|
|
162
|
+
solver.reset()
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### SolverResult
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
result = solver.check_sat(tm)
|
|
169
|
+
|
|
170
|
+
# Compare with enum values
|
|
171
|
+
if result == oxiz.SolverResult.Sat:
|
|
172
|
+
print("Satisfiable")
|
|
173
|
+
elif result == oxiz.SolverResult.Unsat:
|
|
174
|
+
print("Unsatisfiable")
|
|
175
|
+
elif result == oxiz.SolverResult.Unknown:
|
|
176
|
+
print("Unknown")
|
|
177
|
+
|
|
178
|
+
# Use properties
|
|
179
|
+
if result.is_sat:
|
|
180
|
+
model = solver.get_model(tm)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Examples
|
|
184
|
+
|
|
185
|
+
### Sudoku Solver
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
import oxiz
|
|
189
|
+
|
|
190
|
+
def solve_sudoku(grid):
|
|
191
|
+
tm = oxiz.TermManager()
|
|
192
|
+
solver = oxiz.Solver()
|
|
193
|
+
|
|
194
|
+
# Create variables for each cell (1-9)
|
|
195
|
+
cells = {}
|
|
196
|
+
for i in range(9):
|
|
197
|
+
for j in range(9):
|
|
198
|
+
cells[(i, j)] = tm.mk_var(f"cell_{i}_{j}", "Int")
|
|
199
|
+
|
|
200
|
+
one = tm.mk_int(1)
|
|
201
|
+
nine = tm.mk_int(9)
|
|
202
|
+
|
|
203
|
+
# Each cell is between 1 and 9
|
|
204
|
+
for (i, j), cell in cells.items():
|
|
205
|
+
solver.assert_term(tm.mk_ge(cell, one), tm)
|
|
206
|
+
solver.assert_term(tm.mk_le(cell, nine), tm)
|
|
207
|
+
|
|
208
|
+
# Row constraints: all different
|
|
209
|
+
for i in range(9):
|
|
210
|
+
row_cells = [cells[(i, j)] for j in range(9)]
|
|
211
|
+
solver.assert_term(tm.mk_distinct(row_cells), tm)
|
|
212
|
+
|
|
213
|
+
# Column constraints: all different
|
|
214
|
+
for j in range(9):
|
|
215
|
+
col_cells = [cells[(i, j)] for i in range(9)]
|
|
216
|
+
solver.assert_term(tm.mk_distinct(col_cells), tm)
|
|
217
|
+
|
|
218
|
+
# 3x3 box constraints: all different
|
|
219
|
+
for box_i in range(3):
|
|
220
|
+
for box_j in range(3):
|
|
221
|
+
box_cells = []
|
|
222
|
+
for i in range(3):
|
|
223
|
+
for j in range(3):
|
|
224
|
+
box_cells.append(cells[(box_i*3 + i, box_j*3 + j)])
|
|
225
|
+
solver.assert_term(tm.mk_distinct(box_cells), tm)
|
|
226
|
+
|
|
227
|
+
# Given values
|
|
228
|
+
for i in range(9):
|
|
229
|
+
for j in range(9):
|
|
230
|
+
if grid[i][j] != 0:
|
|
231
|
+
val = tm.mk_int(grid[i][j])
|
|
232
|
+
solver.assert_term(tm.mk_eq(cells[(i, j)], val), tm)
|
|
233
|
+
|
|
234
|
+
# Solve
|
|
235
|
+
if solver.check_sat(tm) == oxiz.SolverResult.Sat:
|
|
236
|
+
model = solver.get_model(tm)
|
|
237
|
+
result = [[int(model[f"cell_{i}_{j}"]) for j in range(9)] for i in range(9)]
|
|
238
|
+
return result
|
|
239
|
+
return None
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Boolean Satisfiability
|
|
243
|
+
|
|
244
|
+
```python
|
|
245
|
+
import oxiz
|
|
246
|
+
|
|
247
|
+
tm = oxiz.TermManager()
|
|
248
|
+
solver = oxiz.Solver()
|
|
249
|
+
|
|
250
|
+
# Create boolean variables
|
|
251
|
+
p = tm.mk_var("p", "Bool")
|
|
252
|
+
q = tm.mk_var("q", "Bool")
|
|
253
|
+
r = tm.mk_var("r", "Bool")
|
|
254
|
+
|
|
255
|
+
# Assert: (p OR q) AND (NOT p OR r) AND (NOT q OR NOT r)
|
|
256
|
+
clause1 = tm.mk_or([p, q])
|
|
257
|
+
clause2 = tm.mk_or([tm.mk_not(p), r])
|
|
258
|
+
clause3 = tm.mk_or([tm.mk_not(q), tm.mk_not(r)])
|
|
259
|
+
|
|
260
|
+
solver.assert_term(clause1, tm)
|
|
261
|
+
solver.assert_term(clause2, tm)
|
|
262
|
+
solver.assert_term(clause3, tm)
|
|
263
|
+
|
|
264
|
+
result = solver.check_sat(tm)
|
|
265
|
+
if result == oxiz.SolverResult.Sat:
|
|
266
|
+
model = solver.get_model(tm)
|
|
267
|
+
print(f"p={model['p']}, q={model['q']}, r={model['r']}")
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Supported Sorts
|
|
271
|
+
|
|
272
|
+
- `"Bool"` - Boolean values
|
|
273
|
+
- `"Int"` - Arbitrary precision integers
|
|
274
|
+
- `"Real"` - Rational numbers
|
|
275
|
+
- `"BitVec[N]"` - Bit vectors of width N (e.g., `"BitVec[32]"`)
|
|
276
|
+
|
|
277
|
+
## Bitvector Operations
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
tm = oxiz.TermManager()
|
|
281
|
+
|
|
282
|
+
# Create bitvector constants
|
|
283
|
+
bv8 = tm.mk_bv(42, 8) # 8-bit bitvector with value 42
|
|
284
|
+
bv16 = tm.mk_bv(1000, 16) # 16-bit bitvector
|
|
285
|
+
|
|
286
|
+
# Bitwise operations
|
|
287
|
+
not_x = tm.mk_bv_not(x) # Bitwise NOT
|
|
288
|
+
and_xy = tm.mk_bv_and(x, y) # Bitwise AND
|
|
289
|
+
or_xy = tm.mk_bv_or(x, y) # Bitwise OR
|
|
290
|
+
|
|
291
|
+
# Arithmetic operations
|
|
292
|
+
sum_xy = tm.mk_bv_add(x, y) # Addition (modulo 2^width)
|
|
293
|
+
diff_xy = tm.mk_bv_sub(x, y) # Subtraction
|
|
294
|
+
prod_xy = tm.mk_bv_mul(x, y) # Multiplication
|
|
295
|
+
neg_x = tm.mk_bv_neg(x) # Two's complement negation
|
|
296
|
+
|
|
297
|
+
# Comparisons (unsigned)
|
|
298
|
+
ult = tm.mk_bv_ult(x, y) # x <u y (unsigned less than)
|
|
299
|
+
ule = tm.mk_bv_ule(x, y) # x <=u y (unsigned less or equal)
|
|
300
|
+
|
|
301
|
+
# Comparisons (signed)
|
|
302
|
+
slt = tm.mk_bv_slt(x, y) # x <s y (signed less than)
|
|
303
|
+
sle = tm.mk_bv_sle(x, y) # x <=s y (signed less or equal)
|
|
304
|
+
|
|
305
|
+
# Division and remainder
|
|
306
|
+
udiv = tm.mk_bv_udiv(x, y) # Unsigned division
|
|
307
|
+
sdiv = tm.mk_bv_sdiv(x, y) # Signed division
|
|
308
|
+
urem = tm.mk_bv_urem(x, y) # Unsigned remainder
|
|
309
|
+
srem = tm.mk_bv_srem(x, y) # Signed remainder
|
|
310
|
+
|
|
311
|
+
# Bit manipulation
|
|
312
|
+
concat = tm.mk_bv_concat(high, low) # Concatenate bitvectors
|
|
313
|
+
extract = tm.mk_bv_extract(7, 4, x) # Extract bits[7:4]
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Array Operations
|
|
317
|
+
|
|
318
|
+
```python
|
|
319
|
+
tm = oxiz.TermManager()
|
|
320
|
+
|
|
321
|
+
# Array select and store
|
|
322
|
+
value = tm.mk_select(array, index) # array[index]
|
|
323
|
+
new_array = tm.mk_store(array, index, value) # array with array[index] = value
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Optimization
|
|
327
|
+
|
|
328
|
+
OxiZ supports optimization (minimize/maximize) using the `Optimizer` class:
|
|
329
|
+
|
|
330
|
+
```python
|
|
331
|
+
tm = oxiz.TermManager()
|
|
332
|
+
opt = oxiz.Optimizer()
|
|
333
|
+
opt.set_logic("QF_LIA")
|
|
334
|
+
|
|
335
|
+
# Variables
|
|
336
|
+
x = tm.mk_var("x", "Int")
|
|
337
|
+
y = tm.mk_var("y", "Int")
|
|
338
|
+
|
|
339
|
+
# Constraints
|
|
340
|
+
zero = tm.mk_int(0)
|
|
341
|
+
ten = tm.mk_int(10)
|
|
342
|
+
sum_xy = tm.mk_add([x, y])
|
|
343
|
+
|
|
344
|
+
opt.assert_term(tm.mk_ge(sum_xy, ten)) # x + y >= 10
|
|
345
|
+
opt.assert_term(tm.mk_ge(x, zero)) # x >= 0
|
|
346
|
+
opt.assert_term(tm.mk_ge(y, zero)) # y >= 0
|
|
347
|
+
|
|
348
|
+
# Objective: minimize x + y
|
|
349
|
+
opt.minimize(sum_xy)
|
|
350
|
+
|
|
351
|
+
# Solve
|
|
352
|
+
result = opt.optimize(tm)
|
|
353
|
+
if result == oxiz.OptimizationResult.Optimal:
|
|
354
|
+
model = opt.get_model(tm)
|
|
355
|
+
print(f"Optimal: x={model['x']}, y={model['y']}") # Should be x=0, y=10 or x=10, y=0
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Optimization Results
|
|
359
|
+
|
|
360
|
+
- `OptimizationResult.Optimal` - Optimal solution found
|
|
361
|
+
- `OptimizationResult.Unbounded` - Objective is unbounded (no finite optimum)
|
|
362
|
+
- `OptimizationResult.Unsat` - No feasible solution exists
|
|
363
|
+
- `OptimizationResult.Unknown` - Timeout or incomplete
|
|
364
|
+
|
|
365
|
+
## Examples
|
|
366
|
+
|
|
367
|
+
See the `examples/` directory for complete demos:
|
|
368
|
+
|
|
369
|
+
- `basic_sat.py` - Boolean satisfiability
|
|
370
|
+
- `bitvec_example.py` - Bitvector operations
|
|
371
|
+
- `optimization_example.py` - Optimization (min/max)
|
|
372
|
+
- `sudoku.py` - Sudoku solver
|
|
373
|
+
|
|
374
|
+
## Testing
|
|
375
|
+
|
|
376
|
+
Run the test suite with pytest:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
# Install the package in development mode
|
|
380
|
+
maturin develop --release
|
|
381
|
+
|
|
382
|
+
# Run tests
|
|
383
|
+
pytest tests/ -v
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## License
|
|
387
|
+
|
|
388
|
+
MIT OR Apache-2.0
|
|
389
|
+
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
oxiz/__init__.py,sha256=9ko0utkusD-_kIZpOp13oUXOporBdkWntv3s__38hBc,99
|
|
2
|
+
oxiz/oxiz.cpython-313t-aarch64-linux-gnu.so,sha256=Dy4RcOZIY4ujNBe76aB3MOmsUwCV8q2kxyqOzrMoUuY,1180648
|
|
3
|
+
oxiz-0.1.0.dist-info/METADATA,sha256=xRNSA0DfmbrEoZWcu4KwTAown4I9mNVOUXflDRZOUHA,9854
|
|
4
|
+
oxiz-0.1.0.dist-info/WHEEL,sha256=q835leI5tUqUNzGLT6_2V4Cxb6Anw8rRDNKWlUcsVqo,151
|
|
5
|
+
oxiz-0.1.0.dist-info/RECORD,,
|