'''
0
1 2
3 4 5
6 7 8 9
A B C D E
'''
NEIGHBORS = [
[ 0, 1, 3], [0, 2, 5],
[ 1, 3, 6], [1, 4, 8],
[ 2, 4, 7], [2, 5, 9],
[ 3, 4, 5], [3, 6, 10], [3, 7, 12],
[ 4, 7, 11], [4, 8, 13],
[ 5, 8, 12], [5, 9, 14],
[ 6, 7, 8],
[ 7, 8, 9],
[10, 11, 12],
[11, 12, 13],
[12, 13, 14],
]
%%time
import copy
def depth_first_search(board):
def loop(b):
if b.count(True) == 1: loop.winners += 1
else:
can_move = False
for n in NEIGHBORS:
for i, j, k in [n, reversed(n)]:
if b[i] and b[j] and not b[k]: # legal move?
can_move = True
bnew = copy.copy(b)
bnew[i] = bnew[j] = False
bnew[k] = True
loop(bnew)
if not can_move: loop.losers += 1
loop.winners = loop.losers = 0
loop(board)
print(f'winners: {loop.winners}', f'losers: {loop.losers}', sep='\n')
depth_first_search([False, *[True] * 14])
winners: 29760 losers: 538870 Wall time: 11.9 s
from z3 import *
def a_AND_NOTa():
a = Bool('a')
s = Solver()
s.add(a, Not(a))
if s.check() == unsat:
print('Phew! The universe is still sane.')
else:
print('All bets are off.')
a_AND_NOTa()
Phew! The universe is still sane.
from z3 import *
def check_demorgans_theorem():
p, q = Bools('p q')
demorgan1 = And(p, q) == Not( Or(Not(p), Not(q)))
demorgan2 = Or (p, q) == Not(And(Not(p), Not(q)))
s = Solver()
s.add(Or(Not(demorgan1), Not(demorgan2))) # why not?
if s.check() == unsat:
print('DeMorgan’s theorem holds')
else:
print('Oops')
print(s.model())
check_demorgans_theorem()
DeMorgan’s theorem holds
from z3 import *
def system_of_linear_equations():
x, y, z = Reals('x y z')
s = Solver()
# https://en.wikipedia.org/wiki/System_of_linear_equations
s.add(3*x + 2*y - z == 1)
s.add(2*x - 2*y - -4*z == -2)
s.add( -x + y/2 - z == 0)
if s.check() == sat:
print(s.model())
else:
print('No solution')
system_of_linear_equations()
[z = -2, y = -2, x = 1]
from z3 import *
HOLES = 15
Hole = [BitVecVal(1 << i, HOLES) for i in range(HOLES)]
Board = [BitVec(f'board_{i}', HOLES) for i in range(HOLES - 1)]
Board and Hole live in the SMT world¶def used(b, h): return Board[b] & Hole[h] == Hole[h]
# important: capital-N Not, i.e., z3.Not, rather than Python not
def empty(b, h): return Not(used(b, h))
# in future perfect tense: hole h will not have changed from p to q
def unchanged(p, q, h): return used(p, h) == used(q, h)
def valid(p, q, i, j, k):
return And(
used(p, i), empty(q, i),
used(p, j), empty(q, j),
empty(p, k), used(q, k),
*[unchanged(p, q, h) for h in range(HOLES) if h not in [i, j, k]])
def legal_transition(p, q):
return Or(
[valid(p, q, *l)
for n in NEIGHBORS
for l in [n, reversed(n)]])
winning_model = None
smt2 = None
def solve_tricky_triangle():
s = Solver()
for i in range(HOLES - 2):
s.add(legal_transition(i, i+1))
s.add(empty(0, 0))
if s.check() == sat:
global winning_model, smt2
winning_model = s.model()
smt2 = s.to_smt2()
else:
print('Failed to solve')
def show_board(b):
def binary_lsb_first(b):
return f'{{:0{HOLES}b}}'.format(b.as_long())[::-1]
s = binary_lsb_first(b)
j = 0
for i in range(1, 6):
leftpad = ' ' * (5 - i)
print(leftpad, ' '.join(s[j:j + i]), sep='')
j = j + i
solve_tricky_triangle()
if winning_model:
show_board(winning_model[Board[0]])
print()
show_board(winning_model[Board[1]])
0
1 1
1 1 1
1 1 1 1
1 1 1 1 1
1
0 1
0 1 1
1 1 1 1
1 1 1 1 1
if winning_model:
show_board(winning_model[Board[1]])
print()
show_board(winning_model[Board[2]])
1
0 1
0 1 1
1 1 1 1
1 1 1 1 1
1
0 1
1 1 1
1 0 1 1
1 1 0 1 1
if winning_model:
show_board(winning_model[Board[2]])
print()
show_board(winning_model[Board[3]])
1
0 1
1 1 1
1 0 1 1
1 1 0 1 1
1
0 1
1 1 1
1 1 0 0
1 1 0 1 1
if winning_model:
show_board(winning_model[Board[3]])
print()
show_board(winning_model[Board[4]])
1
0 1
1 1 1
1 1 0 0
1 1 0 1 1
1
0 0
1 1 0
1 1 0 1
1 1 0 1 1
if winning_model:
show_board(winning_model[Board[4]])
print()
show_board(winning_model[Board[5]])
1
0 0
1 1 0
1 1 0 1
1 1 0 1 1
1
0 0
1 1 0
1 1 0 1
0 0 1 1 1
if winning_model:
show_board(winning_model[Board[5]])
print()
show_board(winning_model[Board[6]])
1
0 0
1 1 0
1 1 0 1
0 0 1 1 1
1
0 0
1 1 0
1 1 0 1
0 1 0 0 1
if winning_model:
show_board(winning_model[Board[6]])
print()
show_board(winning_model[Board[7]])
1
0 0
1 1 0
1 1 0 1
0 1 0 0 1
1
0 0
0 0 1
1 1 0 1
0 1 0 0 1
if winning_model:
show_board(winning_model[Board[7]])
print()
show_board(winning_model[Board[8]])
1
0 0
0 0 1
1 1 0 1
0 1 0 0 1
1
0 0
0 0 1
0 0 1 1
0 1 0 0 1
if winning_model:
show_board(winning_model[Board[8]])
print()
show_board(winning_model[Board[9]])
1
0 0
0 0 1
0 0 1 1
0 1 0 0 1
1
0 1
0 0 0
0 0 1 0
0 1 0 0 1
if winning_model:
show_board(winning_model[Board[9]])
print()
show_board(winning_model[Board[10]])
1
0 1
0 0 0
0 0 1 0
0 1 0 0 1
0
0 0
0 0 1
0 0 1 0
0 1 0 0 1
if winning_model:
show_board(winning_model[Board[10]])
print()
show_board(winning_model[Board[11]])
0
0 0
0 0 1
0 0 1 0
0 1 0 0 1
0
0 0
0 0 0
0 0 0 0
0 1 1 0 1
if winning_model:
show_board(winning_model[Board[11]])
print()
show_board(winning_model[Board[12]])
0
0 0
0 0 0
0 0 0 0
0 1 1 0 1
0
0 0
0 0 0
0 0 0 0
0 0 0 1 1
if winning_model:
show_board(winning_model[Board[12]])
print()
show_board(winning_model[Board[13]])
0
0 0
0 0 0
0 0 0 0
0 0 0 1 1
0
0 0
0 0 0
0 0 0 0
0 0 1 0 0
smt2_lines = None
if smt2:
smt2_lines = str(smt2).splitlines()
print('\n'.join(smt2_lines[0:25]))
; benchmark generated from python API (set-info :status unknown) (declare-fun board_1 () (_ BitVec 15)) (declare-fun board_0 () (_ BitVec 15)) (declare-fun board_2 () (_ BitVec 15)) (declare-fun board_3 () (_ BitVec 15)) (declare-fun board_4 () (_ BitVec 15)) (declare-fun board_5 () (_ BitVec 15)) (declare-fun board_6 () (_ BitVec 15)) (declare-fun board_7 () (_ BitVec 15)) (declare-fun board_8 () (_ BitVec 15)) (declare-fun board_9 () (_ BitVec 15)) (declare-fun board_10 () (_ BitVec 15)) (declare-fun board_11 () (_ BitVec 15)) (declare-fun board_12 () (_ BitVec 15)) (declare-fun board_13 () (_ BitVec 15)) (assert (let (($x109 (= (_ bv2048 15) (bvand board_1 (_ bv2048 15))))) (let (($x107 (= (_ bv2048 15) (bvand board_0 (_ bv2048 15))))) (let (($x110 (= $x107 $x109))) (let (($x104 (= (_ bv1024 15) (bvand board_1 (_ bv1024 15))))) (let (($x102 (= (_ bv1024 15) (bvand board_0 (_ bv1024 15))))) (let (($x105 (= $x102 $x104))) (let (($x99 (= (_ bv512 15) (bvand board_1 (_ bv512 15))))) (let (($x97 (= (_ bv512 15) (bvand board_0 (_ bv512 15)))))
if smt2_lines: print('\n'.join(smt2_lines[25:50]))
(let (($x100 (= $x97 $x99))) (let (($x88 (= (_ bv256 15) (bvand board_1 (_ bv256 15))))) (let (($x86 (= (_ bv256 15) (bvand board_0 (_ bv256 15))))) (let (($x84 (= $x86 $x88))) (let (($x76 (= (_ bv128 15) (bvand board_1 (_ bv128 15))))) (let (($x83 (= (_ bv128 15) (bvand board_0 (_ bv128 15))))) (let (($x72 (= $x83 $x76))) (let (($x89 (= (_ bv64 15) (bvand board_1 (_ bv64 15))))) (let (($x55 (= (_ bv64 15) (bvand board_0 (_ bv64 15))))) (let (($x90 (= $x55 $x89))) (let (($x69 (= (_ bv32 15) (bvand board_1 (_ bv32 15))))) (let (($x8 (= (_ bv32 15) (bvand board_0 (_ bv32 15))))) (let (($x70 (= $x8 $x69))) (let (($x50 (= (_ bv16 15) (bvand board_1 (_ bv16 15))))) (let (($x53 (= (_ bv16 15) (bvand board_0 (_ bv16 15))))) (let (($x51 (= $x53 $x50))) (let (($x47 (= (_ bv8 15) (bvand board_1 (_ bv8 15))))) (let (($x48 (= (_ bv8 15) (bvand board_0 (_ bv8 15))))) (let (($x133 (= $x48 $x47))) (let (($x67 (= (_ bv4 15) (bvand board_1 (_ bv4 15))))) (let (($x63 (= (_ bv4 15) (bvand board_0 (_ bv4 15))))) (let (($x65 (= $x63 $x67))) (let (($x37 (= (_ bv2 15) (bvand board_1 (_ bv2 15))))) (let (($x33 (= (_ bv2 15) (bvand board_0 (_ bv2 15))))) (let (($x132 (= $x33 $x37)))
if smt2_lines: print('\n'.join(smt2_lines[50:75]))
(let (($x15 (= (_ bv1 15) (bvand board_1 (_ bv1 15))))) (let (($x7 (= (_ bv1 15) (bvand board_0 (_ bv1 15))))) (let (($x138 (= $x7 $x15))) (let (($x114 (= (_ bv4096 15) (bvand board_1 (_ bv4096 15))))) (let (($x112 (= (_ bv4096 15) (bvand board_0 (_ bv4096 15))))) (let (($x163 (not $x112))) (let (($x119 (= (_ bv8192 15) (bvand board_1 (_ bv8192 15))))) (let (($x174 (not $x119))) (let (($x117 (= (_ bv8192 15) (bvand board_0 (_ bv8192 15))))) (let (($x124 (= (_ bv16384 15) (bvand board_1 (_ bv16384 15))))) (let (($x180 (not $x124))) (let (($x122 (= (_ bv16384 15) (bvand board_0 (_ bv16384 15))))) (let (($x191 (and $x122 $x180 $x117 $x174 $x163 $x114 $x138 $x132 $x65 $x133 $x51 $x70 $x90 $x72 $x84 $x100 $x105 $x110))) (let (($x178 (not $x122))) (let (($x165 (not $x114))) (let (($x190 (and $x112 $x165 $x117 $x174 $x178 $x124 $x138 $x132 $x65 $x133 $x51 $x70 $x90 $x72 $x84 $x100 $x105 $x110))) (let (($x125 (= $x122 $x124))) (let (($x167 (not $x107))) (let (($x189 (and $x117 $x174 $x112 $x165 $x167 $x109 $x138 $x132 $x65 $x133 $x51 $x70 $x90 $x72 $x84 $x100 $x105 $x125))) (let (($x172 (not $x117))) (let (($x169 (not $x109))) (let (($x188 (and $x107 $x169 $x112 $x165 $x172 $x119 $x138 $x132 $x65 $x133 $x51 $x70 $x90 $x72 $x84 $x100 $x105 $x125))) (let (($x120 (= $x117 $x119))) (let (($x159 (not $x102))) (let (($x187 (and $x112 $x165 $x107 $x169 $x159 $x104 $x138 $x132 $x65 $x133 $x51 $x70 $x90 $x72 $x84 $x100 $x120 $x125)))
if smt2_lines: print('\n'.join(smt2_lines[1250:1262]))
(let (($x4451 (and $x4023 $x4450 $x4012 $x4440 $x4010 $x4399 $x4448 $x4405 $x4408 $x4411 $x4417 $x4420 $x4423 $x4426 $x4429 $x4432 $x4435 $x4438))) (let (($x4449 (and $x4009 $x4400 $x4012 $x4440 $x4060 $x4413 $x4448 $x4405 $x4408 $x4411 $x4417 $x4420 $x4423 $x4426 $x4429 $x4432 $x4435 $x4438))) (let (($x4007 (not $x4006))) (let (($x4447 (and $x4020 $x4446 $x4014 $x4442 $x4007 $x4396 $x4443 $x4444 $x4408 $x4414 $x4417 $x4420 $x4423 $x4426 $x4429 $x4432 $x4435 $x4438))) (let (($x4397 (not $x4396))) (let (($x4445 (and $x4006 $x4397 $x4014 $x4442 $x4056 $x4410 $x4443 $x4444 $x4408 $x4414 $x4417 $x4420 $x4423 $x4426 $x4429 $x4432 $x4435 $x4438))) (let (($x4441 (and $x4012 $x4440 $x4009 $x4400 $x4007 $x4396 $x4405 $x4408 $x4411 $x4414 $x4417 $x4420 $x4423 $x4426 $x4429 $x4432 $x4435 $x4438))) (let (($x4439 (and $x4006 $x4397 $x4009 $x4400 $x4050 $x4402 $x4405 $x4408 $x4411 $x4414 $x4417 $x4420 $x4423 $x4426 $x4429 $x4432 $x4435 $x4438))) (or $x4439 $x4441 $x4445 $x4447 $x4449 $x4451 $x4453 $x4455 $x4456 $x4458 $x4459 $x4461 $x4462 $x4463 $x4464 $x4466 $x4467 $x4469 $x4470 $x4472 $x4473 $x4475 $x4476 $x4477 $x4478 $x4480 $x4481 $x4482 $x4483 $x4484 $x4485 $x4486 $x4487 $x4488 $x4489 $x4490))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) (assert (let (($x4626 (= (_ bv2048 15) (bvand board_12 (_ bv2048 15))))) (let (($x4428 (= (_ bv2048 15) (bvand board_11 (_ bv2048 15)))))
$\LARGE{M = (Q, \Sigma, q_0, F, \delta)}$
where
$Q$ is a finite set of states
$\Sigma$ is the finite tape alphabet
$q_0$ is the initial state
$F\subseteq Q$ is the set of final states
$\delta\subseteq(Q\times\Sigma)\times(Q\times\Sigma\times\{L,N,R\})$ is the transition function
At each step of the computation:
$\LARGE{M = (Q, \Sigma, \iota, F, \delta)}$
where
$Q$ is a finite set of states
$\Sigma$ is the finite tape alphabet
$\iota\in Q$ is the initial state
$F\subseteq Q$ is the set of accepting states
$\delta\subseteq(Q\times\Sigma)\times(Q\times\Sigma\times\{L,N,R\})$ is the transition relation
z3.Not(A(w)) holds iff $w\not\in\mathcal{L}$Let $S_{s,t}$ be true iff square $s$ is scanned at time $t$. Then
Let $P_{s,t}^i$ be true iff tape square $s$ at step $t$ holds $\sigma_i$. Then
Let $Q^i_t$ by true iff $M$ at step $t$ is in state $q_i$. Then
where $w = \sigma_i\ldots\sigma_n$, $q_0$ is the start state, and $\sigma_1$ is the blank symbol.
Recall:
Let $F$, $G$, and $H$ constrain $P$, $Q$, and $S$ at each step $t$. For example
$$G_{i,j}^t = \bigwedge_{s=1}^{T} (\lnot Q_t^i\lor \lnot S_{s,t}\lor\lnot P_{s,t}^j\lor Q_{t+1}^k)$$requires state $q_i$ scanning $\sigma_j$ to transition to appropriate $q_k$.
where accept states are $F = {q_{f_1},\ldots,q_{f_n}}$.
Stephen A. Cook, Image credit: Jiří JaníčekPokud, CC BY-SA 3.0
plot_complexity_venn()