Z3求解器简介以及特定约束条件下求出所有可行解

Z3求解器

1.Z3求解器简介:

Z3是微软研究院开发的高性能定理证明器。Z3用于许多应用,如:软件/硬件验证和测试,约束解决,混合系统的分析,安全,生物学(在硅分析),和几何问题。

2.Z3求解器ubuntu下安装:

git clone https://github.com/Z3Prover/z3.git
cd z3
python scripts/mk_make.py
cd build
make
sudo make install

3.Z3示例解析:

**例1:**函数Int(‘x’)在Z3中创建了一个名为x的整型变量。下面的例子使用了两个变量x和y,以及三个约束条件。Z3Py像Python一样使用=进行赋值。操作符<, <=, >, >=, ==和!=用于比较。在下面的例子中,表达式x + 2*y == 7是一个Z3约束。Z3可以解决和计算公式。

x = Int('x')
y = Int('y')
solve(x > 2, y < 10, x + 2*y == 7)

**例2:**遍历表达式的函数

x = Int('x')
y = Int('y')
n = x + y >= 3
print "num args: ", n.num_args()
print "children: ", n.children()
print "1st child:", n.arg(0)
print "2nd child:", n.arg(1)
print "operator: ", n.decl()
print "op name:  ", n.decl().name()

**例3:**下面的例子演示了一个常见的错误。表达式3/2是一个Python整数而不是Z3有理数。该示例还展示了在Z3Py中创建有理数的不同方法。过程Q(num, den)创建了一个Z3有理函数,其中num是分子,den是分母。RealVal(1)创建一个Z3实数,表示数字1。

print 1/3
print RealVal(1)/3
print Q(1,3)
x = Real('x')
print x + 1/3
print x + Q(1,3)
print x + "1/3"
print x + 0.25

4.布尔逻辑

Z3支持布尔运算符:And, Or, Not, Implies (implication), If (If -then-else)。使用equal ==表示双含义。下面的示例演示如何解决一组简单的布尔约束。

p = Bool('p')
q = Bool('q')
r = Bool('r')
solve(Implies(p, q), r == Not(q), Or(Not(p), r))

**例1:**使用多项式和布尔约束的组合

p = Bool('p')
x = Real('x')
solve(Or(x < 5, x > 10), Or(p, x**2 == 2), Not(p))

5.求解器(Solvers)

Z3提供了不同的求解器。前面示例中使用的solve命令是使用Z3求解器API实现的。可以在Z3发行版中的文件Z3 .py中找到该实现。

**例1.**下面的示例演示了基本的Solver API。

x = Int('x')
y = Int('y')
s = Solver()
print s
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()

代码解析:命令Solver()创建一个通用解算器。约束可以使用add方法添加。我们说约束已经在求解器中断言。方法check()解决了断言的约束。如果找到了解,结果是满意的。如果不存在解,结果就是不满意的。我们也可以说,断言约束的系统是不可行的。最后,求解器可能无法求解约束系统并返回未知。在某些应用程序中,我们希望探索几个具有相同约束条件的类似问题。我们可以使用命令push和pop来实现这一点。每个求解器维护一个断言堆栈。push命令通过保存当前堆栈大小来创建一个新的作用域。命令弹出窗口pop将删除在它和匹配的推送之间执行的任何断言。检查方法总是对求解器断言堆栈的内容进行操作。

例2.下面的示例展示了如何遍历求解器中断言的约束,以及如何为检查方法收集性能统计信息。

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)

当Z3为断言的约束集找到一个解时,命令check返回sat。我们说Z3满足约束集。我们说这个解是一个断言约束集的模型。模型是一种解释,它使每个断言的约束成立。下面的例子展示了检查模型的基本方法。

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])

在上面的例子中,函数Reals(‘x y z’)创建变量。x y z,它可以简写为:

x = Real('x')
y = Real('y')
z = Real('z')

表达式m [x]返回x的解释模型中m。表达“% s = % s“% (d.name (), m [d])返回一个字符串第一个% s被替换为d的名称(例如,d.name()),第二个文本表示的% s d的解释(即m [d])。Z3Py在需要时自动将Z3对象转换为文本表示。

6.算法(Arithmetic)

Z3支持实变量和整型变量。它们可以混合在一个问题中。与大多数编程语言一样,Z3Py会在需要时自动添加强制变量,将整数表达式转换为实际表达式。下面的示例演示了声明整型变量和实型变量的不同方法。

例1:

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将一个整数表达式强制转换为实表达式。

7.可满足性和有效性

公式/约束F是有效的,如果F对其未解释符号的任何适当值赋值始终为真。一个公式/约束F是满足的,如果对其未解释的符号赋适当的值,在此条件下F计算为真。有效性是关于找到一个陈述的证明;可满足性是关于找到一组约束的解。考虑一个包含a和b公式F。我们可以问F是否有效,是否总是这样任意组合为a和b的值。如果F总是正确的,那么不是(F)永远是假的,然后不是(F)不会有任何令人满意的作业(例如,解决方案);也就是说,Not(F)是不可满足的。也就是说,F恰好在Not(F)不可满足时有效。另外,当且仅当Not(F)无效(无效)时F是可满足的。下面的例子证明了德摩根定律。

下面的示例重新定义Z3Py函数,该函数将公式作为参数接收。这个函数创建一个求解器,添加/断言公式的否定,并检查否定是否不可满足。这个函数的实现是Z3Py命令prove的一个更简单的版本。

p, q = Bools('p q')
demorgan = And(p, q) == Not(Or(Not(p), Not(q)))
print demorgan
def prove(f):
    s = Solver()
    s.add(Not(f))
    if s.check() == unsat:
        print "proved"
    else:
        print "failed to prove"
print "Proving demorgan..."
prove(demorgan)

8.数独

数独是一种非常流行的益智游戏。目标是在方框中插入数字以满足一个条件:每行、每列和3x3方框中必须恰好包含1到9的数字一次。

下面的例子编码了Z3中的数独问题。不同的数独实例可以通过修改矩阵实例来解决。这个例子大量使用了Python编程语言中的列表推导式。

# 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"

因为model()方法只能输出最后一个check()方法的模型,导致我们无法直接获取到全部符合条件的模型
因此,借助while循环和Or语句来添加条件,实现全部符合条件的模型结果的获取,下面使用while循环以求出满足约束条件的所有解为例:

a = Int('a')
b = Int('b')
s = Solver()
s.add(1 <= a)
s.add(a <= 20)
s.add(1 <= b)
s.add(b <= 20)
s.add(a >= 2*b)
while s.check() == sat:
  print (s.model())
  s.add(Or(a != s.model()[a], b != s.model()[b]))
  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值