Z3 中的代数数

Algebraic numbers in Z3

以下代码为 x,y 设置了一些(仅)满足的 Z3 约束: x = sqrt(2) 和 y = -sqrt(2).

x, y = Reals('x y')
s = Solver()
s.add( x*x == 2 )
s.add( x>0)
s.add( y*y == 2 )
s.add( y<0)
s.check()
m = s.model()
val_x = m.get_interp(x)
val_y = m.get_interp(y)

print(f"The solutions are: x={val_x} and y={val_y}")
print(f"The defining polynomial of x has integer coefficients", val_x.poly(), " and root index ", val_x.index())
print(f"The defining polynomial of y has integer coefficients", val_y.poly(), " and root index ", val_y.index())

输出为:

The solutions are: x=1.4142135623? and y=-1.4142135623?

the defining polynomial of x has integer coefficients [-2, 0, 1]  and root index  0

the defining polynomial of y has integer coefficients [-2, 0, 1]  and root index  0

因此,似乎 .index() 函数(应该提取代数数的索引)不起作用:给出了 $sqrt(2)$ 和 $- sqrt(2)$相同的索引。

我已经在 Z3 github (link) 中报告了这个问题,但不幸的是开发者没有足够的带宽来解决这个问题。

我查看了 .index() 函数的 python 代码(路径 z3/lib.z3.py):

def index(self):
    return Z3_algebraic_get_i(self.ctx_ref(), self.as_ast())

它只是调用:

def Z3_algebraic_get_i(a0, a1, _elems=Elementaries(_lib.Z3_algebraic_get_i)):
  r = _elems.f(a0, a1)
  _elems.Check(a0)
  return r

这基本上(?)调用了 C 语言中 Z3 库的方法 Z3_algebraic_get_i

本人对C不熟悉,求助:

QUESTION 是 C Z3 库的 Z3_algebraic_get_i 函数实际工作,还是只是 Python?

谢谢


编辑:这是来自 here

的 C 函数的源代码
    unsigned Z3_API Z3_algebraic_get_i(Z3_context c, Z3_ast a) {
        Z3_TRY;
        LOG_Z3_algebraic_get_i(c, a);
        RESET_ERROR_CODE();
        CHECK_IS_ALGEBRAIC(a, 0);
        algebraic_numbers::manager & _am = am(c);
        algebraic_numbers::anum const & av = get_irrational(c, a);
        return _am.get_i(av);
        Z3_CATCH_RETURN(0);
    }

这似乎确实是 z3py 中的一个错误;我强烈怀疑仅在 python 绑定中。然而,修复它需要对 code-base 有深入的了解,即使最后这可能是一件简单的事情。您向开发人员报告是正确的做法。不幸的是,他们没有带宽来解决这个问题。

但是,我可以提供一个 hack,它可以提供一个解决方法,直到有一个适当的修复,如果有的话。定义:

def get_root_obj_index(ar):
    return Int(ar.sexpr().split()[-1][:-1])

现在您可以将程序的最后两行更改为:

print(f"The defining polynomial of x has integer coefficients", val_x.poly(), " and root index ", get_root_obj_index(val_x))
print(f"The defining polynomial of y has integer coefficients", val_y.poly(), " and root index ", get_root_obj_index(val_y))

这会打印:

The defining polynomial of x has integer coefficients [-2, 0, 1]  and root index  2
The defining polynomial of y has integer coefficients [-2, 0, 1]  and root index  1

这对您的 特定 示例做了正确的事情,我认为它通常会做正确的事情;只要结果是 root-object。技巧是将对象打印为 s-expr,显示为 root-object 并提取索引值。当然,您可能要小心并首先检查 sexpr() 的结果以确保它确实看起来像 root-object,如果不是,则抛出错误或 return 一些默认值。

我应该强调这是一个 hack,应该谨慎使用并且小心使用;但如果没有人站出来修复 z3py 中的相应错误,它可以帮助你。