在我的一个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());
}
然而,它没有用。任何人都可以帮我解决这个问题吗?提前谢谢。
答案 0 :(得分:1)
如果您觉得需要控制实数的“精确度”,那么强烈建议Real
不是您问题的正确域。一些想法,取决于你真正想做的事情:
如果您关心小数点后面的6位数,那么您可能会使用普通Integer
s,将所有内容乘以1e6
并将所有变量限制为小于{ {1}};或其他一些类似的转变。
请记住,Z3目前支持IEEE浮点数,这是有限精度的定义。因此,如果您的域名确实是IEEE-754规定的浮点数,那么您可以使用它们。
如果您尝试生成“连续”结果,即通过解决问题,则添加结果应该与前一个不同的约束,并再次调用Z3;然后你可以考虑添加一个约束,说明新结果应该与旧值不同,绝对值超过1e6
。
这是否适用取决于您尝试解决的确切问题。如果您可以分享更多问题,那么人们可能会想出其他想法。但首要选择应该是确定1e6
是否真的是您想要使用的域名。