如何检查 1000+ 个没有重复值的变量?

  • 本文关键字:变量 何检查 1000+ z3
  • 更新时间 :
  • 英文 :


我是Z3的新手,对于开源程序,我想使用z3求解器来提高效率。

我有大约 1000+ 个值

(declare-const a1 Int)
(declare-const a2 Int)
(declare-const a3 Int)
(declare-const a4 Int)
...

结果为

(declare-const x1 Int)
(declare-const x2 Int)
...
(assert (=  (+ a1 a2) x1) // in reality its not "plus" but more sophisticated
(assert (=  (+ a3 a4) x2) // however for simplicity lets keep it at that here.
...

现在我想确保所有 x1 到 x500+ 变量都有不同的值,并且没有重复项。

我当然可以

(assert (not (= x1 x2)))
(assert (not (= x1 x3)))
(assert (not (= x1 x4)))
...
(assert (not (= x2 x3)))
(assert (not (= x2 x4)))
...
(assert (not (= x718 719)))

这将起作用 - 但是有更好的解决方案吗?

多谢!

您可以使用distinct(请参阅此示例(:

(assert (distinct x1 ... x500))

AFAIK,这通常是在一系列不等式中内部扩展的,就像您在示例中介绍的那样。

讨论

接下来是关于这种编码效率的纯理论讨论;z3是一个非常高效的 SMT 求解器,因此您可能不需要尝试比简单地运行该工具更复杂的方法。

对等式的否定(例如(not (= x y))(通常分为一对不等式:

x < y / x > y

假设x < yx > y分别重命名为B1B2,则向 SAT 引擎馈送以下子句:

B1 / B2

现在,鉴于您的问题,您会得到数百个这样的子句。它们都在线性算术级别相互关联,但在 SAT 引擎运行的布尔级别上不相关。因此,SAT 引擎可能会生成(大量(不一致的部分真值分配,这些分配通常违反<运算符的传递性属性,例如

x < y / y < z / z < x

这些冲突将由 LRA 理论求解器在早期修剪调用期间揭示,并通过学习阻止无效赋值的冲突子句在布尔级别解决。

您可以尝试什么:

  • 如果你的问题承认这样的简化(如果x1 ... x500的名称可能被认为是完全任意的,那么之后可以打乱它们..(,你可能会得到更好的结果,对变量x1 ... x500施加严格的总顺序,例如

    x1 < x2 / x2 < x3 / ... / x499 < x500
    
  • 您可以尝试使用z3增加早期修剪调用的频率,如果这是一个可用的选项(注意:我不确定z3多久执行一次此类调用(

  • 您可以尝试在这种约束下很好地发挥作用的mcSAT


编辑:

如果可以分配给变量x_i的值集是有限的,并且大小有限,则可以尝试使用非标准z3扩展来计算具有特定值x_i的变量的数量,以定义基数约束,例如

(assert
((_ at-most 1)
(= x1 0)
(= x2 0)
...
(= x500 0)
)
)
...
% repeat for all possible values 
...

我不确定此更改对性能的影响。在正常情况下,它会对性能产生积极影响,因为它会更早地揭示相互冲突的任务(例如,参见[1](。但是,您正在处理相当多的变量和大量变量x_i候选值域,因此在布尔级别扁平化搜索可能是一种矫枉过正。

最新更新