使用z3中的位向量避免非线性

时间:2015-07-09 15:09:31

标签: z3 smt nonlinear-functions sat

我正在尝试解决包含数千个变量的公式。这些公式的主要部分是线性的,从我的观点来看,z3以令人难以置信的速度咀嚼它们。然而,恰好少数约束引入了一些非线性。然后,计算时间从几分钟增长到经过几天计算后无法得到解决方案。

我认为尝试使用位向量会很有趣,但仅仅是因为那些非线性约束在此过程中会失去一些精度,但这不是我试图解决的问题的问题。所以或多或少,我想通过在需要时切换到数字的位表示来使用小的SAT问题。我在另一个post中看到int2bv和bv2int被视为未解释,因此似乎无法使用这些函数。但是,我仍然不确定为什么他们没有被解释。是否有任何理论问题或出于性能原因?

我还看到z3的最后一个稳定版本可以处理浮点(here)。然而,似乎从FP到Reals引入了非线性。因此,使用浮点仅用于非线性约束并用实数和整数求解其余部分似乎也是不可能的。我还没有尝试过,但我假设所有变量使用浮点数都不会因为我遇到的问题而扩展。 我想出了非常幼稚的函数,它们相当于int2bv和bv2int。显然,即使是非线性的小例子也很慢。以下是在SMT2中用于正整数的8位向量的实现。

(define-fun BitVecToInt ((x (_ BitVec 8))) Int
    (+
        (ite (= #b1 ((_ extract 0 0) x)) 1 0)
        (ite (= #b1 ((_ extract 1 1) x)) 2 0)
        (ite (= #b1 ((_ extract 2 2) x)) 4 0)
        (ite (= #b1 ((_ extract 3 3) x)) 8 0)
        (ite (= #b1 ((_ extract 4 4) x)) 16 0)
        (ite (= #b1 ((_ extract 5 5) x)) 32 0)
        (ite (= #b1 ((_ extract 6 6) x)) 64 0)
        (ite (= #b1 ((_ extract 7 7) x)) 128 0)
    )
)
(define-fun IntToBitVec ((x Int)) (_ BitVec 8)
    (bvor
        #b00000000
        (ite (> (rem x 2) 0) #b00000001 #b00000000)
        (ite (>= (rem x 4) 2) #b00000010 #b00000000)
        (ite (>= (rem x 8) 4) #b00000100 #b00000000)
        (ite (>= (rem x 16) 8) #b00001000 #b00000000)
        (ite (>= (rem x 32) 16) #b00010000 #b00000000)
        (ite (>= (rem x 64) 32) #b00100000 #b00000000)
        (ite (>= (rem x 128) 64) #b01000000 #b00000000)
        (ite (>= x 128) #b10000000 #b00000000)
    )
)

关于解决这个问题的最佳方法的任何想法,还是我错过了z3中的任何内容,这可以让我的生活更轻松?

1 个答案:

答案 0 :(得分:1)

您的BitVecToInt函数隐含假设所表示的数字是无符号数。这当然可能没问题;虽然如果您使用(_ BitVec 8)类型作为2的补充号码,那么您必须明确考虑到这一点。所以,您可能需要UBitVec8ToIntSBitVec8ToInt个变体;要清楚这一点。

我认为int2bvbv2int未被解释的原因恰恰是因为性能影响:想象一下将整数转换为千位长的非常大的位向量。公式会非常大并且会带来性能损失。对于较小的目标尺寸,我认为这个问题很容易处理;就像你在这里有8位。

我在Z3中使用花车的经验(有限)是支持相当不错,前提是您没有与Reals进行转换。一旦你去那里,问题变得棘手。 Z3开发人员就此问题提出了一些评论:https://github.com/Z3Prover/z3/issues/14