我不确定是否可以使用SMT-LIB做到这一点,如果不可能的话,可以使用替代求解器吗?
考虑方程式
a < 10
和a > 5
b < 5
和b > 0
b < c < a
a
,b
和c
整数存在a
和b
时满足等式的最大模型数量的a=9
和b=1
的值。
SMT-LIB是否支持以下内容:对于a
和b
的每个值,请计算满足公式的模型数量,并为a
和{{1}给出值},从而使计数最大化。
答案 0 :(得分:2)
我认为您通常无法做到这一点;也就是说,当您可以对任意理论施加任意约束时。您在问一个“元”问题:“最大化模型数量”不是关于问题本身的问题,而是关于问题的模型的问题。 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解决方案神奇地使零件自动化。 (除非Patrick提出了聪明的编码,否则他还是很聪明的!)
答案 1 :(得分:1)
让我们打破目标:
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
一个新的约束,要求至少一个“ other” 变量更改其值,例如c != 5 or d != 6
pop
回溯点或者,您可以隐式而不是显式枚举a
和b
上的可能分配。这个想法如下:
assert
整个公式check
寻找解决方案UNSAT
,则退出循环SAT
,采用模型中控制变量值的组合(例如a = 8 and b = 2
),则检查内部映射是否曾经遇到过此组合,如果未将计数器设置为{ {1}},否则将计数器增加1
。1
c = 5 and d = 6
一个新的约束,要求一个新的解决方案,例如assert
如果您不确定要选择哪个 SMT求解器,我建议您使用pysmt开始解决您的任务,该任务可以让您在多个中选择> SMT引擎。
如果对于您的应用程序而言,显式的模型枚举太慢而无法实用,那么我建议您查看有关 CSP计数解决方案的大量文献,其中已经解决了该问题并且似乎存在几种估算CSP解决方案数量的方法。