Z3 中的幂和对数
Power and logarithm in Z3
我正在尝试学习 Z3,但以下示例让我感到困惑:
from z3 import *
a = Int("a")
b = Int("b")
print(solve(2**a <= b))
print(solve(a > 0, b > 0, 2**a <= b))
我希望它 returns “[a = 1, b = 2]” 但它 returns “未能解决”。
为什么解决不了?
是否可以在 Z3 中使用幂和对数进行计算?我如何找到一个数字的二进制字符串表示的长度(log base 2)?
长话短说,z3(或一般的 SMT 求解器)无法处理这样的非线性约束。 Exponentiation/Logs 等很难处理,并且没有对它们进行整数判定的程序。即使超过实数,它们也很难处理。也就是说,求解器将应用一些试探法,这些试探法可能有效也可能无效。但是对于这些类型的约束,SMT 求解器并不是合适的工具。
有关 z3 中非线性算术的较早答案,请参阅此答案:
如果您有兴趣,这里有更多详细信息。首先,SMTLib 或 z3 中没有整数的幂运算符。如果查看生成的程序,您会发现它实际上超过了实际值:
from z3 import *
a = Int("a")
b = Int("b")
s = Solver()
s.add(2**a <= b)
print(s.sexpr())
print(s.check())
这会打印:
(declare-fun b () Int)
(declare-fun a () Int)
(assert (<= (^ 2 a) (to_real b)))
unknown
注意转换为 to_real
。 ^
运算符自动创建一个实数。解决这个问题的方法是,如果求解器可以提出一个实数的解决方案,然后检查结果是否为整数。让我们看看如果我们尝试 Real
s:
会发生什么
from z3 import *
a = Real("a")
b = Real("b")
s = Solver()
s.add(2**a <= b)
print(s.check())
print(s.model())
这会打印:
sat
[b = 1, a = 0]
太棒了!但是你也想要 a > 0
, b > 0
;所以让我们补充一下:
from z3 import *
a = Real("a")
b = Real("b")
s = Solver()
s.add(2**a <= b)
s.add(a > 0)
s.add(b > 0)
print(s.check())
这会打印:
unknown
所以,求解器也无法处理这种情况。您可以玩弄战术 (qfnra-nlsat
),但一般情况下不太可能处理此类问题。同样,请参阅 了解详细信息。
我正在尝试学习 Z3,但以下示例让我感到困惑:
from z3 import *
a = Int("a")
b = Int("b")
print(solve(2**a <= b))
print(solve(a > 0, b > 0, 2**a <= b))
我希望它 returns “[a = 1, b = 2]” 但它 returns “未能解决”。
为什么解决不了?
是否可以在 Z3 中使用幂和对数进行计算?我如何找到一个数字的二进制字符串表示的长度(log base 2)?
长话短说,z3(或一般的 SMT 求解器)无法处理这样的非线性约束。 Exponentiation/Logs 等很难处理,并且没有对它们进行整数判定的程序。即使超过实数,它们也很难处理。也就是说,求解器将应用一些试探法,这些试探法可能有效也可能无效。但是对于这些类型的约束,SMT 求解器并不是合适的工具。
有关 z3 中非线性算术的较早答案,请参阅此答案:
如果您有兴趣,这里有更多详细信息。首先,SMTLib 或 z3 中没有整数的幂运算符。如果查看生成的程序,您会发现它实际上超过了实际值:
from z3 import *
a = Int("a")
b = Int("b")
s = Solver()
s.add(2**a <= b)
print(s.sexpr())
print(s.check())
这会打印:
(declare-fun b () Int)
(declare-fun a () Int)
(assert (<= (^ 2 a) (to_real b)))
unknown
注意转换为 to_real
。 ^
运算符自动创建一个实数。解决这个问题的方法是,如果求解器可以提出一个实数的解决方案,然后检查结果是否为整数。让我们看看如果我们尝试 Real
s:
from z3 import *
a = Real("a")
b = Real("b")
s = Solver()
s.add(2**a <= b)
print(s.check())
print(s.model())
这会打印:
sat
[b = 1, a = 0]
太棒了!但是你也想要 a > 0
, b > 0
;所以让我们补充一下:
from z3 import *
a = Real("a")
b = Real("b")
s = Solver()
s.add(2**a <= b)
s.add(a > 0)
s.add(b > 0)
print(s.check())
这会打印:
unknown
所以,求解器也无法处理这种情况。您可以玩弄战术 (qfnra-nlsat
),但一般情况下不太可能处理此类问题。同样,请参阅 了解详细信息。