s.add(x > 10, y == x + 2) print s print"Solving constraints in the solver s ..." print s.check()
print"Create a new scope..." s.push() s.add(y < 11) print s print"Solving updated set of constraints..." print s.check() print"Restoring state..." s.pop() print s print"Solving restored set of constraints..." print s.check()
x = Real('x') s = Solver() s.add(2**x == 3) print s.check()
下面的例子展示了如何将声明的约束式传入求解器,以及如何通过check 方法获取求解器状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
x = Real('x') y = Real('y') s = Solver() s.add(x > 1, y > 1, Or(x + y > 3, x - y < 2)) print"asserted constraints..." for c in s.assertions(): print c
print s.check() print"statistics for the last check method..." print s.statistics() # Traversing statistics for k, v in s.statistics(): print"%s : %s" % (k, v)
当求解器找到解时, check 方法返回 sat 。我们称Z3求出满足约束式的解。我们称这个解为所声明的约束式的一个模型。一个模型是指一种解释,能使所有约束式满足。下面的例子展示了查看模型的基本方法。
1 2 3 4 5 6 7 8 9 10 11
x, y, z = Reals('x y z') s = Solver() s.add(x > 1, y > 1, x + y > 3, z - x < 10) print s.check()
m = s.model() print"x = %s" % m[x]
print"traversing model..." for d in m.decls(): print"%s = %s" % (d.name(), m[d])
x = Real('x') y = Int('y') a, b, c = Reals('a b c') s, r = Ints('s r') print x + y + 1 + (a + s) print ToReal(y) + c
函数ToReal 将一个整型表达式转换为实型。
Z3Py支持所有的基本的运算符。
1 2 3 4 5 6
a, b, c = Ints('a b c') d, e = Reals('d e') solve(a > b + 2, a == 2*c + 10, c + b <= 1000, d >= e)
函数simplify 提供了一些方法,可以对Z3表达式进行简单变换。
1 2 3 4 5 6 7
x, y = Reals('x y') # Put expression in sum-of-monomials form t = simplify((x + y)**3, som=True) print t # Use power operator t = simplify(t, mul_to_power=True) print t
x = Int('x') y = Int('y') f = Function('f', IntSort(), IntSort()) s = Solver() s.add(f(f(x)) == x, f(x) == y, x != y) print s.check() m = s.model() print"f(f(x)) =", m.evaluate(f(f(x))) print"f(x) =", m.evaluate(f(x))
###可满足性和有效性
当一个约束式/公式 F的值在任何有效取值下始终为真,称该公式为普遍有效公式(即恒真公式)。当约束式在一些取值下为真则称公式为可满足的。验证有效性时,即需要找出命题为永真的证明。验证可满足性则是求出一个满足式子的集合。考虑一个包含 a 和 b 的公式 F 。F 是否普遍有效即是否在 a 和 b 的所有取值下F 都为真。如果F 是有效的,则Not(F) 为永假的,即Not(F) 在任何取值下都不为真,即,Not(F) 是不可满足的。所以公式F 在Not(F) 不可满足时为永真的。 同样,当且仅当 Not(F) 不为永真时,F 是可满足的。下面的例子证明了德摩根定理 。
x = BitVec('x', 32) powers = [ 2**i for i in range(32) ] fast = And(x != 0, x & (x - 1) == 0) slow = Or([ x == p for p in powers ]) print fast prove(fast == slow)
print"trying to prove buggy version..." fast = x & (x - 1) == 0 prove(fast == slow)
####相反数
下面的技巧用于测试两个数是否互为相反数。
1 2 3 4 5 6 7 8 9 10 11
x = BitVec('x', 32) y = BitVec('y', 32)
# Claim: (x ^ y) < 0 iff x and y have opposite signs trick = (x ^ y) < 0
# Naive way to check if x and y have opposite signs opposite = Or(And(x < 0, y >= 0), And(x >= 0, y < 0))
# Create 3 integer variables dog, cat, mouse = Ints('dog cat mouse') solve(dog >= 1, # at least one dog cat >= 1, # at least one cat mouse >= 1, # at least one mouse # we want to buy 100 animals dog + cat + mouse == 100, # We have 100 dollars (10000 cents): # dogs cost 15 dollars (1500 cents), # cats cost 1 dollar (100 cents), and # mice cost 25 cents 1500 * dog + 100 * cat + 25 * mouse == 10000)
# 9x9 matrix of integer variables X = [ [ Int("x_%s_%s" % (i+1, j+1)) for j in range(9) ] for i in range(9) ]
# each cell contains a value in {1, ..., 9} cells_c = [ And(1 <= X[i][j], X[i][j] <= 9) for i in range(9) for j in range(9) ]
# each row contains a digit at most once rows_c = [ Distinct(X[i]) for i in range(9) ]
# each column contains a digit at most once cols_c = [ Distinct([ X[i][j] for i in range(9) ]) for j in range(9) ]
# each 3x3 square contains a digit at most once sq_c = [ Distinct([ X[3*i0 + i][3*j0 + j] for i in range(3) for j in range(3) ]) for i0 in range(3) for j0 in range(3) ]
sudoku_c = cells_c + rows_c + cols_c + sq_c
# sudoku instance, we use '0' for empty cells instance = ((0,0,0,0,9,4,0,3,0), (0,0,0,5,1,0,0,0,7), (0,8,9,0,0,0,0,4,0), (0,0,0,0,0,0,2,0,8), (0,6,0,2,0,1,0,5,0), (1,0,2,0,0,0,0,0,0), (0,7,0,0,0,0,5,2,0), (9,0,0,0,6,5,0,0,0), (0,4,0,9,7,0,0,0,0))
instance_c = [ If(instance[i][j] == 0, True, X[i][j] == instance[i][j]) for i in range(9) for j in range(9) ]
s = Solver() s.add(sudoku_c + instance_c) if s.check() == sat: m = s.model() r = [ [ m.evaluate(X[i][j]) for j in range(9) ] for i in range(9) ] print_matrix(r) else: print "failed to solve"
# We know each queen must be in a different row. # So, we represent each queen by a single integer: the column position Q = [ Int('Q_%i' % (i + 1)) for i in range(8) ]
# Each queen is in a column {1, ... 8 } val_c = [ And(1 <= Q[i], Q[i] <= 8) for i in range(8) ]
# At most one queen per column col_c = [ Distinct(Q) ]
# Diagonal constraint diag_c = [ If(i == j, True, And(Q[i] - Q[j] != i - j, Q[i] - Q[j] != j - i)) for i in range(8) for j in range(i) ]
defDependsOn(pack, deps): if is_expr(deps): return Implies(pack, deps) else: return And([ Implies(pack, dep) for dep in deps ])
defConflict(*packs): return Or([ Not(pack) for pack in packs ])
a, b, c, d, e, f, g, z = Bools('a b c d e f g z')
definstall_check(*problem): s = Solver() s.add(*problem) if s.check() == sat: m = s.model() r = [] for x in m: if is_true(m[x]): # x is a Z3 declaration # x() returns the Z3 expression # x.name() returns a string r.append(x()) print r else: print"invalid installation profile"