Z3 Examples
All examples below come from z3-nim tests
Installing Z3
If you try to run the z3 examples without installing z3 you will
see an error such as could not load libz3.so
(on windows it will mention libz3.dll
).
nim-z3
depends on z3 dynamic library which has to be recovered independently.
Releases with prebuilt libraries are available but being on a Mac M1 I had to build the library myself.
git clone https://github.com/Z3Prover/z3.git
cd z3
then (following instructions in repo's readme)
python scripts/mk_make.py
cd build
make
sudo make install
The last command (sudo make install
) did not work for me and I just copied
the generated libz3.dylib
in the folder from where I am running this script
(a better way - which was what make install
was trying to do - would be
to move it in folder in path, along with z3 executable and header files).
I also had to rename the library to libz3.so
, since this is what z3-nim looks for.
For the examples to work you must first import the library:
import z3
De Morgan
z3:
let x = Bool("x")
let y = Bool("y")
let exp = not (not (x and y )) <-> ((not x) or (not y))
echo exp
let s = Solver()
s.assert (x and y) or (not x and y)
if s.check() == Z3_L_TRUE:
echo s.get_model()
(= (not (not (and x y))) (or (not x) (not y))) y -> true x -> false
tie or shirt?
z3:
let tie = Bool("tie")
let shirt = Bool("shirt")
let s = Solver()
s.assert (not tie) or shirt
s.assert (not tie) or not(shirt)
if s.check() == Z3_L_TRUE:
echo s.get_model()
tie -> false shirt -> false
math school problem
z3:
let x = Int("x")
let y = Int("y")
let z = Int("z")
let s = Solver()
s.assert 3 * x + 2 * y - z == 1
s.assert 2 * x - 2 * y + 4 * z == -2
s.assert x * -1 + y / 2 - z == 0
echo s
if s.check() == Z3_L_TRUE:
echo s.get_model()
(declare-fun z () Int) (declare-fun y () Int) (declare-fun x () Int) (assert (= (- (+ (* 3 x) (* 2 y)) z) 1)) (assert (= (+ (- (* 2 x) (* 2 y)) (* 4 z)) (- 2))) (assert (= (- (+ (* x (- 1)) (div y 2)) z) 0)) z -> (- 2) y -> (- 2) x -> 1
XKCD restaurant order
z3:
let a = Int("a")
let b = Int("b")
let c = Int("c")
let d = Int("d")
let e = Int("e")
let f = Int("f")
let s = Solver()
s.assert a*215 + b*275 + c*335 + d*355 + e*420 + f*580 == 1505
s.assert a<100 and b<100 and c<100 and d<100 and e<100 and f<100
s.assert a>=0 and b>=0 and c>=0 and d>=0 and e>=0 and f>=0
if s.check() == Z3_L_TRUE:
echo s.get_model()
d -> 0 b -> 0 a -> 7 f -> 0 c -> 0 e -> 0
sudoku
# "Extreme" sudoku: http://www.sudokuwiki.org/Weekly_Sudoku.asp?puz=28
let 路 = 0
let sudoku = [
[ 路, 路, 路, 路, 路, 8, 9, 4, 路 ],
[ 9, 路, 路, 路, 路, 6, 1, 路, 路 ],
[ 路, 7, 路, 路, 4, 路, 路, 路, 路 ],
[ 2, 路, 路, 6, 1, 路, 路, 路, 路 ],
[ 路, 路, 路, 路, 路, 路, 2, 路, 路 ],
[ 路, 8, 9, 路, 路, 2, 路, 路, 路 ],
[ 路, 路, 路, 路, 6, 路, 路, 路, 5 ],
[ 路, 路, 路, 路, 路, 路, 路, 3, 路 ],
[ 8, 路, 路, 路, 路, 1, 6, 路, 路 ],
]
z3:
let s = Solver()
var cs: array[9, array[9, Z3_ast_int]]
# Create sudoku cells
for y, row in sudoku.pairs():
for x, v in row.pairs():
let c = Int($x & "," & $y)
cs[y][x] = c
if v != 0:
s.assert c == v
else:
s.assert c >= 1 and c <= 9
# Each row and col contains each digit only once
for row in cs:
s.assert distinc row
for y in 0..8:
var col: seq[Z3_ast_int]
for x in 0..8:
col.add cs[x][y]
s.assert distinc(col)
# Each 3x3 square contains each digit only once
for x in [0, 3, 6]:
for y in [0, 3, 6]:
var sq: seq[Z3_ast_int]
for dx in 0..2:
for dy in 0..2:
sq.add cs[x+dx][y+dy]
s.assert distinc sq
# Get model and print solution
s.check_model:
for row in cs:
for c in row:
stdout.write $eval(c) & " "
stdout.write "\n"
5 6 2 1 7 8 9 4 3 9 4 3 5 2 6 1 8 7 1 7 8 9 4 3 5 6 2 2 5 7 6 1 4 3 9 8 3 1 4 8 9 7 2 5 6 6 8 9 3 5 2 7 1 4 4 3 1 7 6 9 8 2 5 7 9 6 2 8 5 4 3 1 8 2 5 4 3 1 6 7 9
scopes
z3:
let x = Int "x"
let y = Int "y"
let s = Solver()
s.push:
s.assert -x + y == 10
s.assert x + y * 2 == 20
echo s.check
s.push:
s.assert 3 * x + y == 10
s.assert 2 * x + 2 * y == 21
echo s.check
Z3_L_TRUE Z3_L_FALSE
simplify
z3:
let x = Int "x"
let y = Int "y"
let e = x + 2 * y + 3 * x - y - y
echo e
echo simplify e
(- (- (+ x (* 2 y) (* 3 x)) y) y) (* 4 x)
floating point
z3:
let x = Float "x"
let y = Float "y"
let s = Solver()
s.assert x * 2.0 == y
s.assert x == 15.0
if s.check() == Z3_L_TRUE:
let model = s.get_model()
echo eval(x)
(fp #b0 #b10000000010 #xe000000000000)
forall
z3:
let s = Solver()
let x = Int "x"
let y = Int "y"
s.assert y == 1
s.assert forall([x], x * y == x)
if s.check() == Z3_L_TRUE:
echo s.get_model()
y -> 1
exists
z3:
let s = Solver()
let x = Int "x"
let y = Int "y"
s.assert y == 20
s.assert exists([x], x * y == 180)
if s.check() == Z3_L_TRUE:
echo s.get_model()
y -> 20
planetary/epicyclic gear system
# Find the gear tooth count for a planetary gear system with a
# ratio of 1:12
z3:
let R = Int("R") # ring teeth
let S = Int("S") # sun teeth
let P = Int("P") # planet teeth
let Tr = Int("Tr") # ring turns
let Ts = Int("Ts") # sun turns
let Ty = Int("Ty") # carrier turns
let s = Solver()
s.assert Ts == 12 # Sun speed
s.assert Tr == 0 # Ring speed
s.assert Ty == 1 # Y-carrier speed
s.assert R >= 10 # Don't make gears too small
s.assert P >= 10
s.assert S >= 10
# Planetary gears constraints
s.assert (R + S) * Ty == R * Tr + Ts * S
s.assert R == 2 * P + S
s.check_model:
echo model
Ts -> 12 Tr -> 0 Ty -> 1 P -> 50 R -> 110 S -> 10
very simple optimize
z3:
# this does not come from tests
let s = Optimizer()
let n = Int "n"
s.assert n <= 3
s.maximize n
echo s
# this code fails:
# s.check() == Z3_L_TRUE
# echo s.get_model()
# this code does not fail:
echo s.check()
echo s.get_model()
0 (declare-fun n () Int) (assert (<= n 3)) (maximize n) (check-sat) Z3_L_TRUE n -> 3
optimize
# Pablo buys popsicles for his friends. The store sells single popsicles
# for $1 each, 3-popsicle boxes for $2, and 5-popsicle boxes for $3. What
# is the greatest number of popsicles that Pablo can buy with $8?
z3:
let s = Optimizer()
let a = Int "a"
let n = Int "n"
let p1 = Int "p1"
let p3 = Int "p3"
let p5 = Int "p5"
s.assert a == p1 * 1 + p3 * 2 + p5 * 3
s.assert n == p1 * 1 + p3 * 3 + p5 * 5
s.assert p1 >= 0 and p3 >= 0 and p5 >= 0
s.assert a == 8
s.maximize n
echo s
# this code fails:
#if s.check() == Z3_L_TRUE:
# echo s.get_model()
echo s.check()
echo s.get_model()
0 (declare-fun p5 () Int) (declare-fun p3 () Int) (declare-fun p1 () Int) (declare-fun a () Int) (declare-fun n () Int) (assert (= a (+ (* p1 1) (* p3 2) (* p5 3)))) (assert (= n (+ (* p1 1) (* p3 3) (* p5 5)))) (assert (and (>= p1 0) (>= p3 0) (>= p5 0))) (assert (= a 8)) (maximize n) (check-sat) Z3_L_TRUE p5 -> 2 p3 -> 1 a -> 8 n -> 13 p1 -> 0