-
Notifications
You must be signed in to change notification settings - Fork 49
/
Copy pathAbstractProverWithAllSat.java
159 lines (139 loc) · 5.7 KB
/
AbstractProverWithAllSat.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// This file is part of JavaSMT,
// an API wrapper for a collection of SMT solvers:
// https://github.com/sosy-lab/java-smt
//
// SPDX-FileCopyrightText: 2020 Dirk Beyer <https://www.sosy-lab.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.sosy_lab.java_smt.basicimpl;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Set;
import org.sosy_lab.common.ShutdownNotifier;
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.BooleanFormulaManager;
import org.sosy_lab.java_smt.api.Evaluator;
import org.sosy_lab.java_smt.api.SolverContext.ProverOptions;
import org.sosy_lab.java_smt.api.SolverException;
/**
* This class is a utility-class to avoid repeated implementation of the AllSAT computation.
*
* <p>If a solver does not support direct AllSAT computation, please inherit from this class.
*/
public abstract class AbstractProverWithAllSat<T> extends AbstractProver<T> {
protected final ShutdownNotifier shutdownNotifier;
private final BooleanFormulaManager bmgr;
protected AbstractProverWithAllSat(
Set<ProverOptions> pOptions,
BooleanFormulaManager pBmgr,
ShutdownNotifier pShutdownNotifier) {
super(pOptions);
bmgr = pBmgr;
shutdownNotifier = pShutdownNotifier;
}
@Override
public <R> R allSat(AllSatCallback<R> callback, List<BooleanFormula> importantPredicates)
throws InterruptedException, SolverException {
Preconditions.checkState(!closed);
checkGenerateAllSat();
push();
try {
// try model-based computation of ALLSAT
iterateOverAllModels(callback, importantPredicates);
} catch (SolverException e) {
// fallback to direct SAT/UNSAT-based computation of ALLSAT
iterateOverAllPredicateCombinations(callback, importantPredicates, new ArrayDeque<>());
// TODO should we completely switch to the second method?
}
pop();
return callback.getResult();
}
/**
* This method computes all satisfiable assignments for the given predicates by iterating over all
* models. The SMT solver can choose the ordering of variables and shortcut model generation.
*/
private <R> void iterateOverAllModels(
AllSatCallback<R> callback, List<BooleanFormula> importantPredicates)
throws SolverException, InterruptedException {
while (!isUnsat()) {
shutdownNotifier.shutdownIfNecessary();
ImmutableList.Builder<BooleanFormula> valuesOfModel = ImmutableList.builder();
try (Evaluator evaluator = getEvaluatorWithoutChecks()) {
for (BooleanFormula formula : importantPredicates) {
Boolean value = evaluator.evaluate(formula);
if (value == null) {
// This is a legal return value for evaluation.
// The value doesn't matter. We ignore this assignment.
// This step aim for shortcutting the ALLSAT-loop.
} else if (value) {
valuesOfModel.add(formula);
} else {
valuesOfModel.add(bmgr.not(formula));
}
}
}
final ImmutableList<BooleanFormula> values = valuesOfModel.build();
callback.apply(values);
shutdownNotifier.shutdownIfNecessary();
BooleanFormula negatedModel = bmgr.not(bmgr.and(values));
addConstraint(negatedModel);
shutdownNotifier.shutdownIfNecessary();
}
}
/**
* This method computes all satisfiable assignments for the given predicates by (recursively)
* traversing the decision tree over the given variables. The ordering of variables is fixed, and
* we can only ignore unsatisfiable subtrees.
*
* <p>In contrast to {@link #iterateOverAllModels} we do not use model generation here, which is a
* benefit for some solvers or theory combinations.
*
* @param predicates remaining predicates in the decision tree.
* @param valuesOfModel already chosen predicate values, ordered as appearing in the tree.
*/
private <R> void iterateOverAllPredicateCombinations(
AllSatCallback<R> callback,
List<BooleanFormula> predicates,
Deque<BooleanFormula> valuesOfModel)
throws SolverException, InterruptedException {
shutdownNotifier.shutdownIfNecessary();
if (isUnsat()) {
return;
} else if (predicates.isEmpty()) {
// we aim at providing the same order of predicates as given as parameter, thus reverse.
callback.apply(ImmutableList.copyOf(valuesOfModel).reverse());
} else {
// positive predicate
final BooleanFormula predicate = predicates.get(0);
valuesOfModel.push(predicate);
push(predicate);
iterateOverAllPredicateCombinations(
callback, predicates.subList(1, predicates.size()), valuesOfModel);
pop();
valuesOfModel.pop();
// negated predicate
final BooleanFormula notPredicate = bmgr.not(predicates.get(0));
valuesOfModel.push(notPredicate);
push(notPredicate);
iterateOverAllPredicateCombinations(
callback, predicates.subList(1, predicates.size()), valuesOfModel);
pop();
valuesOfModel.pop();
}
}
/**
* Get an evaluator instance for model evaluation without executing checks for prover options.
*
* <p>This method allows model evaluation without explicitly enabling the prover-option {@link
* ProverOptions#GENERATE_MODELS}. We only use this method internally, when we know about a valid
* solver state. The returned evaluator does not have caching or any direct optimization for user
* interaction.
*
* @throws SolverException if model can not be constructed.
*/
protected abstract Evaluator getEvaluatorWithoutChecks()
throws SolverException, InterruptedException;
}