Z3枚举所有令人满意的作业

时间:2014-05-13 15:22:36

标签: enumeration z3

我正在尝试解决类似于此处的问题(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)排除了在枚举中使用数组和未解释的函数。我不确定这个问题是主要与实施有关还是更为基础。

1 个答案:

答案 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的范围是否是一个数组排序,然后假设它是一个集合的模型,如果约束混合了数组和集合,它将不起作用。在这些情况下,我们需要检查一个特定的数组是模型集还是实际数组。