我在.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文件中的子句提供解算器。
首先,假设与子句具有相同的语法,
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)
的删除方式吗?我需要的是模型数量,真实模型!有没有办法找到确切的模型,同时“删除”某些我们想要通过假设排除的变量(即a
和b
)?
对于这种情况,这是我在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)
}
感谢您的帮助。
答案 0 :(得分:2)
我想补充一点。使用阻止条款。
您可以通过枚举不同的解决方案并获得确切的模型来计算模型。然后你会否定一个解决方案,将其与公式的其余部分合并并再次解决。这个否定的解决方案子句称为阻塞子句。它不会让求解器再次选择相同的解决方案。
现在,在您的情况下,您应该添加一个仅根据您想要的变量的阻止子句。
假设你有CNF公式
x and (y or z)
你得到解x = 1,y = 1,z = 0。
但是,比方说,您只对x
和z
感兴趣。
从这个解决方案中,阻止条款将是
!(x and !z)
这将禁止解决方案
x = 1, y = 1, z = 0
,还有
x = 1, y = 0, z = 0
您将只获得一个解决方案
x = 1, z = 1
(y
并不重要)
希望这有帮助。
如果您正在使用某个模型计数器,请查找添加投影变量的选项(有时也称为自变量)。您基本上希望将所有解决方案都投影到变量子集上。其他变量的不同组合不应影响模型的数量。
答案 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;
}