Z3:在 z3::expr 上使用比较运算符(<、<=、...)

Z3: using comparison operators (<,<=,...) on z3::expr

我将数字存储为 z3::expr 并想比较它们。我尝试了以下方法:

z3::context c;
z3::expr a = c.real_val("0");
z3::expr b = c.real_val("1");
z3::expr comp = (a < b);
std::cout << comp.is_bool() << std::endl;
std::cout << comp.bool_value() << std::endl;

我有点懵,为什么comp.bool_value()是假的?

如果我使用解算器,一切都会按预期工作:

z3::solver s(c);
s.add(comp);
std::cout << s.check() << std::endl;

我必须相对频繁地比较 z3::exprs,这样做的禁食方法是什么?在我看来,使用求解器的开销很大。

< 运算符(以及几乎所有其他运算符)只是将决定推给求解器:也就是说,它是一个符号表达式,在运行时不会“评估”,而是创建调用求解器时将在任意表达式上进行比较的表达式。

话虽如此,在某些情况下您可以使用简化器来实现您想要的。如果你尝试:

  z3::expr simpComp = comp.simplify();
  std::cout << simpComp.bool_value() << std::endl;

您会看到它会为您打印 1。但是,您不应该指望简化器能够减少这样的任意表达式。对于最简单的情况,它会完成工作,但如果你有更复杂的表达式,它就会放弃。

一般来说,一旦你构建了一个表达式,你必须等到求解器被调用,然后检查生成的模型,如果有的话。

旁注在某些情况下,您可以构建自己的函数来自己做一些常量折叠。这对于 Bool 值是可能的,例如(因为它们可以在 C++ 中完全表示),以及各种大小的位向量(取决于您的机器字大小),浮点数等。但不适用于实数(因为z3 实数是无限精度,你不能直接用 C++ 表示它们)和整数(因为它们是无界的。)但这不是一件小事,除非你非常熟悉 z3 的内部结构,否则我建议不要走那条路。

底线:如果你有很多这样的常量:看看你是否可以重新设计你的程序,这样你就不会首先创建 real_val;并将它们保留为常量,并且仅当您不再可以将它们保留为常量时才将它们转换为 z3-expressions。在某些情况下,您可以依赖 simplify,但也不要指望它会非常高效。