我不确定这是否可以使用 SMT-LIB,如果不可能,是否存在可以做到这一点的替代求解器?
考虑方程
a < 10
和a > 5
b < 5
和b > 0
b < c < a
- ,和整数
a
_b
c
存在满足方程 when和的最大模型数的值a
和where 。b
a=9
b=1
SMT-LIB 是否支持以下内容:对于 的每个值,a
计算b
满足公式的模型数量,并给出最大化计数的a
值b
。
我认为您通常无法做到这一点。也就是说,当您可以对任意理论进行任意约束时。您在问一个“元”问题:“最大化模型数量”不是关于问题本身的问题,而是关于问题模型的问题;SMTLib 无法处理的事情。
然而,话虽如此,我认为应该可以针对特定问题对其进行编码。在您给出的示例中,模型空间在最大时最大化a - b
;所以你可以简单地写:
(set-option :produce-models true)
(declare-fun a () Int)
(declare-fun b () Int)
(declare-fun c () Int)
(assert (< 5 a 10))
(assert (< 0 b 5))
(assert (< b c a))
(maximize (- a b))
(check-sat)
(get-value (a b))
z3 回应:
sat
((a 9)
(b 1))
如预期的。或者,您可以使用 Python 绑定:
from z3 import *
a, b, c = Ints('a b c')
o = Optimize()
o.add(And(5 < a, a < 10, 0 < b, b < 5, b < c, c < a))
o.maximize(a - b)
if o.check() == sat:
m = o.model()
print "a = %s, b = %s" % (m[a], m[b])
else:
print "unsatisfiable or unknown"
打印:
a = 9, b = 1
还有针对 C/C++/Java/Scala/Haskell 等的绑定,可以让您在这些主机上或多或少地做同样的事情。
但是这里的关键点是我们必须手动提出最大化a - b
可以解决这里问题的目标。该步骤需要人工干预,因为它适用于您当前的任何问题。(想象一下,您正在使用浮点理论或任意数据类型;想出这样的度量可能是不可能的。)我不认为使用传统的 SMT 求解可以神奇地自动化该部分。(除非帕特里克想出一个聪明的编码,否则他很聪明!)
让我们分解你的目标:
a
和b
(...以及更多)的可能方式一般来说,这是不可能的,因为问题中某些变量的域可能包含无限数量的元素。
即使可以安全地假设每个其他变量的域都包含有限数量的元素,它仍然是非常低效的。例如,如果您的问题中只有布尔变量,那么在搜索过程中您仍然需要考虑指数数量的值组合——因此还有候选模型。
但是,您的实际应用程序在实践中也可能没有那么复杂,因此它可以由SMT Solver处理。
一般的想法可能是使用一些SMT Solver API并按如下方式进行:
assert
整个公式push
回溯点assert
一种特定的值组合,例如a = 8 and b = 2
check
寻求解决方案UNSAT
, 退出最内层循环 SAT
值组合增加模型的计数器a
b
c = 5 and d = 6
assert
要求至少一个“其他”变量更改其值的新约束,例如c != 5 or d != 6
pop
回溯点a
或者,您可以隐式而b
不是显式地枚举可能的分配。想法如下:
assert
整个公式check
寻求解决方案UNSAT
,退出循环SAT
,从模型中获取控制变量的值的组合(例如a = 8 and b = 2
),如果您以前遇到过这种组合,请检查内部映射,如果没有将计数器设置为1
,否则将计数器增加1
。c = 5 and d = 6
assert
请求新解决方案的新约束,例如a != 8 or b != 2 or c != 5 or d != 6
如果您对选择哪个SMT Solver有疑问,我建议您开始使用pysmt解决您的任务,它允许您轻松地在多个SMT 引擎中进行选择。
如果对于您的应用程序,模型的显式枚举太慢而无法实用,那么我建议您查看有关 CSP 计数解决方案的大量文献,其中已经解决了这个问题,并且似乎存在几种近似估计的方法CSP 的解决方案的数量。