【问题标题】:Is it possible to get a legit range info when using a SMT constraint with Z3使用带有 Z3 的 SMT 约束时是否可以获得合法的范围信息
【发布时间】:2023-03-15 03:14:01
【问题描述】:

所以基本上我正在尝试使用像 Z3 这样的通用约束求解器来解决以下 SMT 约束:

>>> from z3 import *
>>> a = BitVec("a", 32)
>>> b = BitVec("b", 32)
>>> c1 = (a + 32) & (b & 0xff)
>>> c2 = (b & 0xff)
>>> s = Solver()
>>> s.add(c1 == c2)
>>> s.check()
sat
>>> s.model()
[b = 0, a = 4294967199]

注意,很明显,只要b 落在[0x00000000, 0xffffff00] 的范围内,约束就应该是sat

所以这是我的问题,对于像Z3 这样的 SMT 求解器来说,提供可满足约束的“范围”信息通常是否可行?谢谢。

【问题讨论】:

    标签: python constraints z3 smt z3py


    【解决方案1】:

    如果您要求一个有效的“最宽”值范围,以便您的属性满足该范围内的所有数字,那将是一个量化的优化问题。 (此外,在这种情况下,“最宽”的含义很难表达。)不幸的是,目前,z3 和我所知道的任何其他 SMT 求解器都无法处理此类问题。

    但是,如果您正在寻找 b 的最小值和最大值以使您的属性保持不变,那么您可以为此使用 Optimize 类:

    from z3 import *
    
    a = BitVec("a", 32)
    b = BitVec("b", 32)
    c1 = (a + 32) & (b & 0xff)
    c2 = (b & 0xff)
    
    s = Optimize()
    s.add(c1 == c2)
    
    min_b = s.minimize(b)
    max_b = s.maximize(b)
    s.set('priority', 'box')
    s.check()
    
    print "min b = %s" % format(min_b.value().as_long(), '#x')
    print "max b = %s" % format(max_b.value().as_long(), '#x')
    

    打印出来:

    min b = 0x0
    max b = 0xffffffff
    

    [旁白:b 的最大值与您预测的不同。但是 z3 所说的对我来说看起来不错:如果您选择 a0x7fffffdf,那么 a+32 将是 0x7fffffff,这都是 1s;因此c1c2 将等效于b 的任何值。所以这里没有什么能以任何方式真正限制b。也许你有不同的约束?]

    但更重要的是,请注意,这意味着您的属性对于b 在此范围内的所有值都是正确的:它所说的只是b 的所有值满足您的属性,这些是b 可以假设的最小值和最大值。 (在这种特殊情况下,结果表明该范围内的所有值都满足它,但这是我们自己推断出来的。)例如,如果您添加一个约束 bnot 5 ,你仍然会得到这些界限。我希望这很清楚!

    【讨论】:

    • 从技术上讲,在有限大小位向量的情况下,不需要执行任何量化优化,因为在问题的表述中扩展所有可能的情况就足够了。因此,从技术上讲,z3OptiMathSAT 都已经拥有“所需要的一切” 来解决问题。话虽如此,对于32-bit-sized Bit-Vectors,这肯定看起来不切实际,所以+1 给你的答案。 @llllllllllllll
    【解决方案2】:

    Levent Erkok 提供的答案总体上是有效的,并且在大多数实际情况下,它是唯一值得考虑的答案。

    但是,从技术上讲,这并不是一个完全超出 OMT 求解器范围的问题,至少在考虑的值域是有限时,并且,可能,。在这种情况下,可以简单地枚举问题表述中的所有可能值。自然,不应期望这种方法能够很好地扩展。


    示例。

    此模型的目标是找到包含在[low, upp] 中的最大区间delta,这样对于区间内的所有值,某个布尔属性Prop 都成立。

    文件: test.smt2

    (set-option :produce-models true)
    
    (declare-fun low () (_ BitVec 4))
    (declare-fun upp () (_ BitVec 4))
    (declare-fun delta () (_ BitVec 4))
    
    (declare-fun Prop () Bool)
    
    (assert (bvule low upp))
    (assert (= delta (bvadd upp (bvneg low) (_ bv1 4))))
    
    ; Put in relation a domain value with the desired Property
    (assert (=> (and (bvule low (_ bv0 4)) (bvule (_ bv0 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv1 4)) (bvule (_ bv1 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv2 4)) (bvule (_ bv2 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv3 4)) (bvule (_ bv3 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv4 4)) (bvule (_ bv4 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv5 4)) (bvule (_ bv5 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv6 4)) (bvule (_ bv6 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv7 4)) (bvule (_ bv7 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv8 4)) (bvule (_ bv8 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv9 4)) (bvule (_ bv9 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv10 4)) (bvule (_ bv10 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv11 4)) (bvule (_ bv11 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv12 4)) (bvule (_ bv12 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv13 4)) (bvule (_ bv13 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv14 4)) (bvule (_ bv14 4) upp)) Prop))
    (assert (=> (and (bvule low (_ bv15 4)) (bvule (_ bv15 4) upp)) Prop))
    
    ; These are just to make the solution "interesting"
    ; Your problem should already entail some values bvX for
    ; which Prop is false
    (assert (=> (and (bvule low (_ bv5 4)) (bvule (_ bv5 4) upp)) (not Prop)))
    (assert (=> (and (bvule low (_ bv6 4)) (bvule (_ bv6 4) upp)) (not Prop)))
    (assert (=> (and (bvule low (_ bv13 4)) (bvule (_ bv13 4) upp)) (not Prop)))
    
    (maximize delta)
    
    (check-sat)
    (get-objectives)
    (get-model)
    

    简短的解释。目标函数的目标是最大化区间[low, upp] 的大小,该区间由delta 衡量。 delta的最大值为2^N,对应区间[0, 2^N - 1]

    约束:

    (assert (=> (and (bvule low (_ bv0 4)) (bvule (_ bv0 4) upp)) Prop))
    

    表示,如果值bv0 包含在当前区间[low, upp] 中,那么属性Prop 必须成立。

    约束:

    (assert (=> (and (bvule low (_ bv5 4)) (bvule (_ bv5 4) upp)) (not Prop)))
    

    表示,对于值bv5,属性Prop 不成立。 bv6bv13 相同。这些约束只是为了使解决方案变得有趣。您的问题应该已经包含一些值bvX,而属性Prop 不能为true

    最优解匹配期望值:

    ~$ time ./optimathsat test.smt2 
    sat
    
    (objectives
     (delta (_ bv6 4))
    )
    ( (low (_ bv7 4))
      (upp (_ bv12 4))
      (delta (_ bv6 4))
      (Prop true) )
    
    real    0m0,042s
    user    0m0,029s
    sys     0m0,013s
    

    当然,同样的公式也可以用z3解。

    【讨论】:

    • 确实,规模是这里的问题。可以为在大多数情况下表现良好的单个变量设计基于二分搜索的算法。但是当你有多个变量时你会怎么做?甚至“最大间隔”的概念也变得相当成问题。对于具体问题,Nikolaj 指出了以下论文:microsoft.com/en-us/research/wp-content/uploads/2016/02/… 我还没有详细阅读它,但是如果您有一个明确定义的问题(例如“以太网地址匹配”),似乎可以有效地解决问题。绝对值得一试!
    • @LeventErkok 是的,我完全同意 :)
    • @PatrickTrentin 非常感谢帕特里克。您也可以发布 test.smt2 吗?确实,我有点难以理解你的代码 sn-p.. 非常感谢。
    • @llllllllllllll 我更新了答案。使用 32 位 BV 时要注意可伸缩性问题。在我看来,使用较小尺寸的 BV(例如 8 位)并不是不合理的,因为没有什么特别的——从算术上讲——大约 32 位 BV。在这种情况下,常数值也需要按比例缩小。正如 Levent Erkok 巧妙地指出的那样,如果您想跟踪多个域间隔,您首先必须决定如何为您的应用程序定义 “最大间隔”。您也可以考虑使用盒装/独立优化或帕累托优化。
    • @PatrickTrentin 谢谢帕特里克!更新的答案对我来说更有意义。不确定在我的设置中它会变得多慢(32 位位向量的约束)。我想我可以先试一试。我也在考虑为这个问题探索一些“次最大”范围。如果您有时间并且有兴趣,如果您能对it 有所了解,我将不胜感激。保重!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 2017-10-13
    • 2013-01-18
    • 1970-01-01
    相关资源
    最近更新 更多