【问题标题】:Using SMT-LIB to count the number of modules using a formula使用 SMT-LIB 使用公式计算模块数量
【发布时间】:2019-01-07 12:48:07
【问题描述】:

我不确定这是否可以使用 SMT-LIB,如果不可能,是否存在可以做到这一点的替代求解器?

考虑方程式

  • a < 10a > 5
  • b < 5b > 0
  • b < c < a
  • 带有abc 整数

ab 的值,其中存在满足 a=9b=1 时的方程的最大模型数。

SMT-LIB 是否支持以下内容:对于 ab 的每个值,计算满足公式的模型数量,并给出使计数最大化的 ab 的值。

【问题讨论】:

  • “模块”是什么意思?您是否尝试最大化满足的其他一些约束的数量?
  • 打字错误,更新问题,应该是模型

标签: python z3 smt z3py pysmt


【解决方案1】:

我认为一般情况下您无法做到这一点;也就是说,当您可以对任意理论进行任意约束时。您在问一个“元”问题:“最大化模型数量”不是关于问题本身的问题,而是关于问题模型的问题; 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 求解不能神奇地自动化该部分。 (除非帕特里克想出一个聪明的编码,否则他很聪明!)

【讨论】:

  • 文档“The SMT-LIB Standard Version 2.6”不包含maximize,z3是否支持包含关键字maximize的SMT-LIB扩展?
  • 是的,优化(即minimizemaximize 调用)是 z3/OptiMathSAT 扩展。
  • 本质上,只要人们已经知道给定特定的解决方案模式/形状,模型的数量就会最大化,然后只需编写一个将搜索移向所需的目标函数即可任务。我对这种方法的反对意见是,如果我们事先知道如何塑造这个排名函数(它返回每个值组合的模型的 # 或等效的东西),那么我们就不需要执行任何搜索,但只需评估它。它对你也有意义吗?
  • 这正是我的观点,帕特里克!无法在 SMTLib 中对问题进行编码;但个别情况可以解决。 (就像停止问题一般是无法解决的)但是给定一个“特定”功能,您很可能会用半自动化工具证明它停止;定理证明者经常做的事情。)任何基于“计数”的方法对于除了玩具实例之外的任何东西都是难以处理的。
【解决方案2】:

让我们分解你的目标:

  • 您想列举所有可以分配ab 的可能方式(...以及更多)
  • 对于每个组合,您要计算可满足模型的数量

一般来说,这是不可能的,因为问题中某些变量的域可能包含无限数量的元素。

即使可以安全地假设每个其他变量的域都包含有限数量的元素,它仍然非常低效。 例如,如果您的问题中只有布尔变量,那么在搜索过程中您仍然需要考虑指数级的值组合——因此还有候选模型。

但是,您的实际应用也可能在实践中并不那么复杂,因此它可以由 SMT Solver 处理。

一般的想法可能是使用一些SMT Solver API并按照以下步骤进行:

  • assert整个公式
  • 重复直到完成值组合:
    • push回溯点
    • assert 一种特定的值组合,例如a = 8 and b = 2
    • 永远重复:
      • check 寻求解决方案
      • 如果UNSAT,退出最里面的循环
      • 如果SAT,为ab的给定值组合增加模型计数器
      • 取任何其他变量的模型值,例如c = 5 and d = 6
      • assert 一个新的约束,要求至少有一个 "other" 变量更改其值,例如c != 5 or d != 6
    • pop回溯点

或者,您可以隐式而不是显式枚举ab 上的可能分配。思路如下:

  • 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 的解决方案的数量。

【讨论】:

  • 不错的分析帕特里克!但正如我在另一条评论中提到的,你将使用这个“技巧”拨打的 SAT 电话的数量是(在最坏的情况下)d^n;其中n 是变量的数量,d 是域的基数。即使对于小型/有限域,随着n 的增加,这个数字也会非常昂贵。我确实认为 SMTLib 只是解决这个问题的错误媒介。您研究“计算 CSP 的解决方案”的想法可能是最有成效的方法:您是否有一些关于该领域技术/工具的简单阅读的指针?
  • @LeventErkok 有时d^n 问题需要d^n 解决方案,或者被权衡取而代之。我不确定我是否会说 SMT 求解器应该被认为在这项任务上特别糟糕。其他类型的工具——除非接受近似答案——尽管我可以看到 lazy SMT 模式——尤其是没有积极的早期修剪调用——可能没有出色的性能。也许基于模型的 SMT 求解器可能会表现得更好。
  • 关于您的要求,方法取决于问题中的实际约束,OP 省略了这些约束,因此很难说。 Gilles Pesant 的论文“CSP 的计数解决方案:...” 列出了一些解决方案的近似计数示例,并附有适当的引用。这可能是开始浏览文献的正确地方。
  • 感谢指点!我想我们将不得不等待 Johan 进行实验并报告它在实践中的效果! Johan:请务必报告您的发现。
猜你喜欢
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 2021-08-10
  • 1970-01-01
  • 2022-07-04
  • 2013-07-09
相关资源
最近更新 更多