我正在尝试解决类似于此处的问题(Z3: finding all satisfying models),我需要找到包含设置变量的SMT公式的所有令人满意的赋值。我理解链接中的想法,因为它类似于一些SAT求解器迭代解决方案所做的事情:添加解决方案的否定以获得不同的解决方案。但是,当我使用set变量(在Z3中实现为数组)时,事情变得有点复杂,或者我想念一些东西。假设我有两个约束添加到求解器中,如下所示:
EnumSort rSort = ctx.mkEnumSort(ctx.mkSymbol("res"), ctx.mkSymbol("res1"));
SetSort rSet = ctx.mkSetSort(rSort);
Expr rID = ctx.mkConst("rID", rSet);
BoolExpr c1 = (BoolExpr)ctx.mkSetMembership(rSort.getConsts()[0], rID);
BoolExpr c2 = ctx.mkGt(ctx.mkIntConst("x"), ctx.mkInt(10));
Solver s = ctx.mkSolver();
s.add(ctx.mkAnd(c1,c2));
现在我想在Z3中为我的公式找到所有令人满意的作业。从理论上讲,我会在迭代中有一个if块来添加变量和它们当前值之间的不等式,并一直持续到UNSAT:
while (s.check() == Status.SATISFIABLE){
Model m = s.getModel()
//for each decl in m
//if (funcDecl) getValue and add negation for the declaration
//if (consDecl) getValue and add negation for the declaration
//add disjunction of negation formulae to s
}
然而,由于我无法构造变量的否定子公式,所以我无法使其工作。有没有一种简单的方法来枚举类似于上面Z3中的SMT公式的所有令人满意的赋值?是否有任何示例代码可以执行类似的操作?
[编辑]我意识到这里的帖子((Z3Py) checking all solutions for equation)排除了在枚举中使用数组和未解释的函数。我不确定这个问题是主要与实施有关还是更为基础。
答案 0 :(得分:1)
我怀疑这里的一个问题是如何获得数组的模型并不明显。这个问题之前已经得到了解答,所以对于那部分我参考了之前的答案:Read func interp of a z3 array from the z3 model
对于这里给出的具体例子,我们可以沿着这些方向做点什么:
while (s.check() == Status.SATISFIABLE) {
Model m = s.getModel();
FuncDecl const_decls [] = m.getConstDecls();
BoolExpr ncs = ctx.mkFalse();
for (int i = 0; i < m.getNumConsts(); i++) {
FuncDecl fd = const_decls[i];
if (fd.getRange().getSortKind()==Z3_sort_kind.Z3_ARRAY_SORT) {
FuncInterp fi = m.getFuncInterp(const_decls[i]);
Entry [] entries = fi.getEntries();
BoolExpr [] new_es = new BoolExpr[fi.getNumEntries()];
for (int j = 0; j < fi.getNumEntries(); j++) {
Expr as = entries[j].getArgs()[0];
if (entries[j].getValue().isTrue())
new_es[j] = ctx.mkNot((BoolExpr) ctx.mkSetMembership(as, rID));
else
new_es[j] = (BoolExpr) ctx.mkSetMembership(as, rID);
}
BoolExpr nc = (new_es.length == 1) ? new_es[0] : ctx.mkOr(new_es);
ncs = ctx.mkOr(nc, ncs);
} else if (fd.getArity() == 0) {
Expr cnst = ctx.mkApp(fd);
Expr mv = m.getConstInterp(const_decls[i]);
BoolExpr nc = ctx.mkNot(ctx.mkEq(cnst, mv));
ncs = ctx.mkOr(nc, ncs);
}
}
s.add(ncs);
}
这段代码只是检查fd
的范围是否是一个数组排序,然后假设它是一个集合的模型,如果约束混合了数组和集合,它将不起作用。在这些情况下,我们需要检查一个特定的数组是模型集还是实际数组。