我们能否限制Z3中实际项的精度?

时间:2013-08-29 09:22:07

标签: z3

在我的一个SMT计划中,我使用了一个真正的术语。我需要限制实数的精度以提高效率,因为这个数字几乎可以有无数的解,尽管只需要小数点后的5/6位数。例如,实数的可能估值可以如下,但如果我们取小数点后的前七位数,则所有值都相同。

1197325/13631488 = 0.087835238530 ......

19157213/218103808 = 0.087835298134 ......

153257613/1744830464 = 0.087835245980 ......

1226060865/13958643712 = 0.087835243186 ......

我希望SMT求解器将所有这四个数字视为单个数字(以便缩小搜索空间)。有没有办法控制实数的精确度?

我尝试以编程方式(使用Z3 Dot Net API)来解决上述问题,如下所示。这里DelBP [j]是一个真正的术语。

{
    BoolExpr[] _Exprs = new BoolExpr[nBuses];
    for (j = 1; j <= nBuses; j++)
    {
        _Exprs[j - 1] = z3.MkEq(DelBP[j], z3.MkDiv(z3.MkInt2Real(DelBP_A[j]), z3.MkInt2Real(DelBP_B[j])));
    }

    BoolExpr Expr = z3.MkAnd(_Exprs);
    s.Assert(Expr);
    tw.WriteLine("(assert {0})", Expr.ToString());
}

{
    BoolExpr[] _Exprs = new BoolExpr[nBuses];
    for (j = 1; j <= nBuses; j++)
    {
        _Exprs[j - 1] = z3.MkAnd(z3.MkGe(DelBP_A[j], z3.MkInt(1)),
            z3.MkLe(DelBP_A[j], z3.MkInt(10000)));
    }

    BoolExpr Expr = z3.MkAnd(_Exprs);
    s.Assert(Expr);
    tw.WriteLine("(assert {0})", Expr.ToString());
}

{
    BoolExpr[] _Exprs = new BoolExpr[nBuses];
    for (j = 1; j <= nBuses; j++)
    {
        _Exprs[j - 1] = z3.MkAnd(z3.MkGe(DelBP_B[j], z3.MkInt(1)),
            z3.MkLe(DelBP_B[j], z3.MkInt(10000)));
    }

    BoolExpr Expr = z3.MkAnd(_Exprs);
    s.Assert(Expr);
    tw.WriteLine("(assert {0})", Expr.ToString());
}

然而,它没有用。任何人都可以帮我解决这个问题吗?提前谢谢。

1 个答案:

答案 0 :(得分:1)

如果您觉得需要控制实数的“精确度”,那么强烈建议Real不是您问题的正确域。一些想法,取决于你真正想做的事情:

  • 如果您关心小数点后面的6位数,那么您可能会使用普通Integer s,将所有内容乘以1e6并将所有变量限制为小于{ {1}};或其他一些类似的转变。

  • 请记住,Z3目前支持IEEE浮点数,这是有限精度的定义。因此,如果您的域名确实是IEEE-754规定的浮点数,那么您可以使用它们。

  • 如果您尝试生成“连续”结果,即通过解决问题,则添加结果应该与前一个不同的约束,并再次调用Z3;然后你可以考虑添加一个约束,说明新结果应该与旧值不同,绝对值超过1e6

这是否适用取决于您尝试解决的确切问题。如果您可以分享更多问题,那么人们可能会想出其他想法。但首要选择应该是确定1e6是否真的是您想要使用的域名。