Z3 Java 为什么我需要一个战术?
Z3 Java why do I need a tactic for this?
我有以下 Java 程序可以解决 (not (and (= b false) (= d false)))
。它不适用于开箱即用的 context/solver。当我尝试 model.getConstInterp(d)
.
时,看起来 D 常量从模型中删除了
如果我 运行 这个和 andThen(mkTactic("simplify"), mkTactic("sat"))
它工作正常。如果我尝试 运行 在 z3 二进制文件的 SMT 脚本中使用它,它无需任何特殊策略就可以正常工作。
我错过了什么?我认为这是一个上下文选项。
是的,我意识到谓词 (not (and (= b false) (= d false)))
可以写得更简单,但这是由一些其他代码自动生成的,不太容易追踪和更改。该语句实际上是一个更大的生成程序的一部分。
@Test
void testQuestion() {
var ctx = new Context();
var b = ctx.mkBoolConst("B");
var d = ctx.mkBoolConst("D");
var solver = ctx.mkSolver();
var p4 = ctx.mkNot(
ctx.mkAnd(
ctx.mkEq(b, ctx.mkFalse()),
ctx.mkEq(d, ctx.mkFalse())));
solver.assertAndTrack(p4, ctx.mkBoolConst("P4"));
var result = solver.check();
assertEquals(Status.SATISFIABLE, result);
var model = solver.getModel();
assertEquals("true", model.getConstInterp(b).toString());
// this throws NPE as the cgid_enable declaration is missing
assertEquals("false", model.getConstInterp(d).toString());
}
默认情况下,z3 只会在需要 时才为模型中的变量赋值。不幸的是,“需要”的意思是 z3;如果底层引擎已经显示 sat
没有分配给某些变量的问题,那么它们将保持未分配状态。哪些变量将未分配可以从 run-to-run/version-to-version.
更改
在您的情况下,一旦求解器将 b
指定为 true
,它就会注意到它的工作已完成;因为分配给 d
不再重要。 (当然,通过对称性,它也可以反过来做。)因此,它未分配,稍后会导致您的 NPE。
解决方案是始终要求完成,使用 eval
函数。这是您的代码,未使用测试框架编码,而是使用 eval
来说明问题:
import com.microsoft.z3.*;
class JavaZ3Example {
public static void main(String [] args) {
var ctx = new Context();
var b = ctx.mkBoolConst("B");
var d = ctx.mkBoolConst("D");
var solver = ctx.mkSolver();
var p4 = ctx.mkNot(
ctx.mkAnd(
ctx.mkEq(b, ctx.mkFalse()),
ctx.mkEq(d, ctx.mkFalse())));
solver.assertAndTrack(p4, ctx.mkBoolConst("P4"));
var result = solver.check();
System.out.println(result);
var model = solver.getModel();
System.out.println(model.eval(b, false).toString());
System.out.println(model.eval(d, false).toString());
};
};
如果你运行以上,你会得到:
SATISFIABLE
true
D
这就是最后一行中的告密标志,求解器决定 不 为变量 D
赋值。也就是说,它没有分配;在此上下文中,它仅打印为变量的名称。
您只需将 true
传递给 eval
的第二个参数即可更改此行为。传递 true
作为第二个参数告诉 z3 确保所有变量都被赋值,无论是否需要赋值。即最后两行改为:
System.out.println(model.eval(b, true).toString());
System.out.println(model.eval(d, true).toString());
当您 运行 新程序时,您将获得:
SATISFIABLE
true
false
当然,最后一行也可以显示为 true
,但是当您强制 eval
为每个变量赋值时,该信息将丢失。
长话短说,对于这类需要每个模型值都赋值的问题,不要使用getConstInterp
。相反,使用 eval
,为第二个参数传递 true
。
我有以下 Java 程序可以解决 (not (and (= b false) (= d false)))
。它不适用于开箱即用的 context/solver。当我尝试 model.getConstInterp(d)
.
如果我 运行 这个和 andThen(mkTactic("simplify"), mkTactic("sat"))
它工作正常。如果我尝试 运行 在 z3 二进制文件的 SMT 脚本中使用它,它无需任何特殊策略就可以正常工作。
我错过了什么?我认为这是一个上下文选项。
是的,我意识到谓词 (not (and (= b false) (= d false)))
可以写得更简单,但这是由一些其他代码自动生成的,不太容易追踪和更改。该语句实际上是一个更大的生成程序的一部分。
@Test
void testQuestion() {
var ctx = new Context();
var b = ctx.mkBoolConst("B");
var d = ctx.mkBoolConst("D");
var solver = ctx.mkSolver();
var p4 = ctx.mkNot(
ctx.mkAnd(
ctx.mkEq(b, ctx.mkFalse()),
ctx.mkEq(d, ctx.mkFalse())));
solver.assertAndTrack(p4, ctx.mkBoolConst("P4"));
var result = solver.check();
assertEquals(Status.SATISFIABLE, result);
var model = solver.getModel();
assertEquals("true", model.getConstInterp(b).toString());
// this throws NPE as the cgid_enable declaration is missing
assertEquals("false", model.getConstInterp(d).toString());
}
默认情况下,z3 只会在需要 时才为模型中的变量赋值。不幸的是,“需要”的意思是 z3;如果底层引擎已经显示 sat
没有分配给某些变量的问题,那么它们将保持未分配状态。哪些变量将未分配可以从 run-to-run/version-to-version.
在您的情况下,一旦求解器将 b
指定为 true
,它就会注意到它的工作已完成;因为分配给 d
不再重要。 (当然,通过对称性,它也可以反过来做。)因此,它未分配,稍后会导致您的 NPE。
解决方案是始终要求完成,使用 eval
函数。这是您的代码,未使用测试框架编码,而是使用 eval
来说明问题:
import com.microsoft.z3.*;
class JavaZ3Example {
public static void main(String [] args) {
var ctx = new Context();
var b = ctx.mkBoolConst("B");
var d = ctx.mkBoolConst("D");
var solver = ctx.mkSolver();
var p4 = ctx.mkNot(
ctx.mkAnd(
ctx.mkEq(b, ctx.mkFalse()),
ctx.mkEq(d, ctx.mkFalse())));
solver.assertAndTrack(p4, ctx.mkBoolConst("P4"));
var result = solver.check();
System.out.println(result);
var model = solver.getModel();
System.out.println(model.eval(b, false).toString());
System.out.println(model.eval(d, false).toString());
};
};
如果你运行以上,你会得到:
SATISFIABLE
true
D
这就是最后一行中的告密标志,求解器决定 不 为变量 D
赋值。也就是说,它没有分配;在此上下文中,它仅打印为变量的名称。
您只需将 true
传递给 eval
的第二个参数即可更改此行为。传递 true
作为第二个参数告诉 z3 确保所有变量都被赋值,无论是否需要赋值。即最后两行改为:
System.out.println(model.eval(b, true).toString());
System.out.println(model.eval(d, true).toString());
当您 运行 新程序时,您将获得:
SATISFIABLE
true
false
当然,最后一行也可以显示为 true
,但是当您强制 eval
为每个变量赋值时,该信息将丢失。
长话短说,对于这类需要每个模型值都赋值的问题,不要使用getConstInterp
。相反,使用 eval
,为第二个参数传递 true
。