z3求解器(SMT)解各类方程各种逻辑题非常简单直观

本文介绍了z3-solver求解器的使用,包括解决二元一次方程、线性多项式约束、非线性多项式约束、高中物理问题、综合性编程问题(如数独、八皇后问题)以及逻辑题。z3能快速找到一个问题的可行解,但不保证找到所有解。此外,还展示了如何通过Python解决安装依赖问题和逻辑推理题。

各位小伙伴大家好,今天我将给大家演示一个非常高级的工具,SMT求解器。应用领域非常广,解各类方程,解各类编程问题(例如解数独),解逻辑题等都不在话下。

今天小小明就将带大家看看这其中的精彩:

🎨z3-solver求解器🎨

🔦简介🔫

z3-solver是由Microsoft Research(微软)开发的SMT求解器,它用于检查逻辑表达式的可满足性,可以找到一组约束中的其中一个可行解,缺点是无法找出所有的可行解(对于规划求解问题可以是scipy)。

z3-solver可应用于软/硬件的验证与测试、约束求解、混合系统的分析、安全、生物,以及几何求解等问题。Z3 主要由 C++ 开发,提供了 .NET、C、C++、Java、Python 等语言调用接口,下面以python接口展开讲解。

z3可直接通过pip安装:

pip install z3-solver

参考示例:https://ericpony.github.io/z3py-tutorial/guide-examples.htm

z3中有3种类型的变量,分别是整型(Int),实型(Real)和向量(BitVec)。

对于整数类型数据,基本API:

  1. Int(name, ctx=None),创建一个整数变量,name是名字
  2. Ints (names, ctx=None),创建多个整数变量,names是空格分隔名字
  3. IntVal (val, ctx=None),创建一个整数常量,有初始值,没名字。

对于实数类型的API与整数类型一致,向量(BitVec)则稍有区别:

  1. Bitvec(name,bv,ctx=None),创建一个位向量,name是他的名字,bv表示大小
  2. BitVecs(name,bv,ctx=None),创建一个有多变量的位向量,name是名字,bv表示大小
  3. BitVecVal(val,bv,ctx=None),创建一个位向量,有初始值,没名字。

simplify(表达式),对可以简化的表达式进行简化。

完整API文档可参考:https://z3prover.github.io/api/html/namespacez3py.html

下面我们看看z3的基本用法:

🔀数学运算🎦

先以一个简单例子入门:

♊️二元一次方程♋️

比如使用z3解二元一次方程:

x − y = 3 x-y = 3 xy=3

3 x − 8 y = 4 3x-8y=4 3x8y=4

solve直接求解:

from z3 import *

x, y = Reals('x y')
solve(x-y == 3, 3*x-8*y == 4)
[y = 1, x = 4]

如果需要取出指定变量的结果,可以使用Solver求解器:

  1. s=solver(),创建一个解的对象。
  2. s.add(条件),为解增加一个限制条件
  3. s.check(),检查解是否存在,如果存在,会返回"sat"
  4. modul(),输出解得结果
x, y = Reals('x y')
solver = Solver()
qs = [x-y == 3, 3*x-8*y == 4]
for q in qs:
    solver.add(q)
if solver.check() == sat:
    result = solver.model()
print(result)
print("x =", result[x], ", y =", result[y])
[y = 1, x = 4]
x = 4 , y = 1

可以通过solver.assertions()查看求解器已经添加的约束和约束的个数:

assertions = solver.assertions()
print(assertions)
print(len(assertions))
[x - y == 3, 3*x - 8*y == 4]
2

如果需要删除约束条件,则需要在添加约束前调用solver.push()方法。

下面我们如下方程为例进行演示:

x > 10 x > 10 x>10

y = x + 2 y = x + 2 y=x+2

获取结果:

x, y = Ints('x y')
solver = Solver()
solver.add(x > 10, y == x + 2)
print("当前约束:", solver.assertions())
if solver.check() == sat:
    print("结果:", solver.model())
else:
    print(solver.check())
当前约束: [x > 10, y == x + 2]
结果: [x = 11, y = 13]

下面我们再增加一个可以被删除的约束y < 11

solver.push()
solver.add(y < 11)
print("当前约束:", solver.assertions())
if solver.check() == sat:
    print("结果:", solver.model())
else:
    print(solver.check())
当前约束: [x > 10, y == x + 2, y < 11]
unsat

可以看到这种约束下,无有效解。

删除约束,再计算一次:

solver.pop()
print("当前约束:", solver.assertions())
if solver.check() == sat:
    print("结果:", solver.model())
else:
    print(solver.check())
当前约束: [x > 10, y == x + 2]
结果: [x = 11, y = 13]

⚠️注意:没有push过的约束条件时直接pop会导致报出Z3Exception: b'index out of bounds'错误。

🚦线性多项式约束🚧

约束条件为:
x > 2 y < 10 x + 2 ∗ y = 7 x > 2 \\ y < 10 \\ x + 2 * y = 7 \\ x>2y<10x+2y=7
上述约束x和y都是整数,我们需要找到其中一个可行解:

x, y = Ints('x y')
solve([x > 2, y < 10, x + 2*y == 7])

结果:

[y = 0, x = 7]

当然,实际可行的解不止这一个,z3只能找到其中一个可行的解。

💧非线性多项式约束🌌

约束条件为:

x 2 + y 2 > 3 x^2 + y^2 > 3 x2+y2

评论 213
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小明-代码实体

喜欢,就关注;爱,就打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值