SAT求解器:SAT4J - 仅评估子句的一部分

时间:2017-01-23 13:49:44

标签: solver sat sat4j

我在.dimacs / .cnf文件中有一个公式,如下所示:

  p cnf 6 9
  1 0
 -2 1 0
 -1 2 0
 -5 1 0
 -6 1 0
 -3 2 0
 -4 2 0
 -3 -4 0
  3 4 -2 0

是否可以在SAT4j中仅提取包含例如变量2,3和4的 那些 ?然后,我需要检查这个新的子句集的一致性,即:

  p cnf 4 6
 -2 1 0
 -1 2 0
 -3 2 0
 -4 2 0
 -3 -4 0
  3 4 -2 0

我尝试使用Assumptions,我试图使用Constraints,但我仍然找不到这样做的方法。

感谢您的任何建议。

修改

我认为有一种类似solver.addClause(clause)的方法,但反向solver.getClause(clause) ...虽然,我正在使用.cnf文件中的子句提供解算器。

编辑2

首先,假设与子句具有相同的语法,

val assumption: IVecInt = new VecInt(Array(1, 2))
val clause: IVecInt = new VecInt(Array(1, 2))

但假设中的变量为conjunctions,子句中的变量为disjunctions。这是一个区别。对?我的测试例子就这么说了。 (我只需要获得额外的批准)。

其次,我使用选择器变量的问题是:

一个简单的公式a V b有三个模型:

(a, b), 
(a, -b), 
(-a, b)

当我添加一个选择器变量,例如s,其假设为-s时,我的模型数量相同,即3个模型:

(a, b, -s),
(a, -b, -s),
(-a, b, -s)

当假设是true时,即s,那么我有4个模型而不是我想要的0:

(a, b, s), 
(a, -b, s), 
(-a, b, s), 
(-a, -b, s)

当然,当s = T,然后是(s V a V b) = (T V a V b) = T时,这是条款(a V b)的删除方式吗?我需要的是模型数量,真实模型!有没有办法找到确切的模型,同时“删除”某些我们想要通过假设排除的变量(即ab)?

对于这种情况,这是我在Scala中的当前代码:

object Example_01 {

  val solver: ISolver = new ModelIterator(SolverFactory.newDefault())
  val reader: DimacsReader = new DimacsReader(solver)
  val problem: IProblem = reader.parseInstance("example_01.cnf")    

  def main(args: Array[String]): Unit = {

    var nrModels: Int = 0
    val assumptions: IVecInt = new VecInt(Array(10))

    try {
      while(solver.isSatisfiable(assumptions)) {
        println(reader.decode(problem.model()))
        nrModels += 1
      }
    } catch {
      case e: ContradictionException => println("UnSAT: ", e)
    }

    println("The number of models is: " + nrModels)
}

感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

我想补充一点。使用阻止条款。

您可以通过枚举不同的解决方案并获得确切的模型来计算模型。然后你会否定一个解决方案,将其与公式的其余部分合并并再次解决。这个否定的解决方案子句称为阻塞子句。它不会让求解器再次选择相同的解决方案。

现在,在您的情况下,您应该添加一个仅根据您想要的变量的阻止子句。

假设你有CNF公式

x and (y or z)

你得到解x = 1,y = 1,z = 0。

但是,比方说,您只对xz感兴趣。

从这个解决方案中,阻止条款将是

!(x and !z)

这将禁止解决方案

x = 1, y = 1, z = 0,还有 x = 1, y = 0, z = 0

您将只获得一个解决方案

x = 1, z = 1y并不重要)

希望这有帮助。

如果您正在使用某个模型计数器,请查找添加投影变量的选项(有时也称为自变量)。您基本上希望将所有解决方案都投影到变量子集上。其他变量的不同组合不应影响模型的数量。

答案 1 :(得分:0)

继续进行的方法是为每个子句添加一个新的选择器变量

p cnf 15 9
7 1 0
8 -2 1 0
9 -1 2 0
10 -5 1 0
11 -6 1 0
12 -3 2 0
13 -4 2 0
14 -3 -4 0
15 3 4 -2 0

然后你只需要将额外变量赋值为true以丢弃一个子句,并将false赋值为假设。在你的情况下,假设是7,-8,-9,10,11,-12,-13,14,-15。

这不是特定于Sat4j,它是一种最初由minisat提出的方法,而且大多数SAT求解器提供。

编辑2:

以下是使用假设和模型计算的方法

    ISolver solver = SolverFactory.newDefault();
    ModelIterator iterator = new ModelIterator(solver);
    iterator.newVar(2); // for a and b
    int selector = iterator.nextFreeVarId(true);
    assert selector == 3;
    IVecInt clause = new VecInt();
    // (a, b),
    clause.push(1).push(2);
    solver.addClause(clause);
    clause.clear();
    // (s, -a, -b)
    clause.push(-1).push(-2).push(3);
    solver.addClause(clause);
    clause.clear();
    IVecInt assumptions = new VecInt();
    // we activate the second clause in the solver
    assumptions.push(-3);
    while (iterator.isSatisfiable(assumptions)) {
        System.out.println("1:>" +new VecInt(iterator.model()));
    }
    assert iterator.numberOfModelsFoundSoFar() == 2;
    // need to reset the solver, since iterating over the model
    // adds new constraints in the solver
    iterator.reset();
    clause = new VecInt();
    // (a, b),
    clause.push(1).push(2);
    solver.addClause(clause);
    clause.clear();
    // (s, -a, -b)
    clause.push(-1).push(-2).push(3);
    solver.addClause(clause);
    clause.clear();
    // we disable the second clause in the solver
    assumptions.clear();
    assumptions.push(3);
    while (iterator.isSatisfiable(assumptions)) {
        System.out.println("2:>" + new VecInt(iterator.model()));
    }
    assert iterator.numberOfModelsFoundSoFar() == 3;
}