Skip to content

Commit 949069b

Browse files
committed
CVC4: improve implementation of SL.
1 parent 5fc389e commit 949069b

File tree

4 files changed

+67
-70
lines changed

4 files changed

+67
-70
lines changed

src/org/sosy_lab/java_smt/solvers/cvc4/CVC4Model.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ private ImmutableList<ValueAssignment> generateModel() {
7373

7474
// TODO this method is highly recursive and should be rewritten with a proper visitor
7575
private void recursiveAssignmentFinder(ImmutableSet.Builder<ValueAssignment> builder, Expr expr) {
76-
if (expr.isConst() || expr.isNull()) {
76+
if (expr.getKind() == Kind.SEP_NIL || expr.isConst() || expr.isNull()) {
7777
// We don't care about consts.
7878
return;
7979
} else if (expr.isVariable() && expr.getKind() == Kind.BOUND_VARIABLE) {

src/org/sosy_lab/java_smt/solvers/cvc4/CVC4SLFormulaManager.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,6 @@ protected Expr makeEmptyHeap(Type pT1, Type pT2) {
4545

4646
@Override
4747
protected Expr makeNilElement(Type pType) {
48-
// TODO CVC4 bindings for Java do not support creation of SEP_NIL via mkTerm.
49-
// It is unclear whether this method ever worked.
50-
// CVC4 is deprecated and we will not investigate here.
51-
//
52-
// Executing this method will cause the following exception:
53-
// Illegal argument detected: CVC4::Expr CVC4::ExprManager::mkExpr(CVC4::Kind, CVC4::Expr)
54-
// `kind' is a bad argument; ... Only operator-style expressions are made with mkExpr();
55-
// to make variables and constants, see mkVar(), mkBoundVar(), and mkConst().
56-
return exprManager.mkExpr(Kind.SEP_NIL, pType.mkGroundTerm());
48+
return exprManager.mkNullaryOperator(pType, Kind.SEP_NIL);
5749
}
5850
}

src/org/sosy_lab/java_smt/solvers/cvc4/CVC4TheoremProver.java

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class CVC4TheoremProver extends AbstractProverWithAllSat<Void>
4040
implements ProverEnvironment, BasicProverEnvironment<Void> {
4141

4242
private final CVC4FormulaCreator creator;
43+
private final int randomSeed;
4344
SmtEngine smtEngine; // final except for SL theory
4445
private boolean changedSinceLastSatQuery = false;
4546

@@ -50,37 +51,45 @@ class CVC4TheoremProver extends AbstractProverWithAllSat<Void>
5051
* <p>TODO If the overhead of importing/exporting the expressions is too expensive, we can disable
5152
* this behavior. This change would cost us the flexibility of setting options per Prover.
5253
*/
53-
private final ExprManager exprManager = new ExprManager();
54+
private ExprManager exprManager; // final except for SL theory
5455

5556
/** We copy expression between different ExprManagers. The map serves as cache. */
56-
private final ExprManagerMapCollection exportMapping = new ExprManagerMapCollection();
57+
private ExprManagerMapCollection exportMapping; // final except for SL theory
5758

5859
// CVC4 does not support separation logic in incremental mode.
5960
private final boolean incremental;
6061

6162
protected CVC4TheoremProver(
6263
CVC4FormulaCreator pFormulaCreator,
6364
ShutdownNotifier pShutdownNotifier,
64-
int randomSeed,
65+
int pRandomSeed,
6566
Set<ProverOptions> pOptions,
6667
BooleanFormulaManager pBmgr) {
6768
super(pOptions, pBmgr, pShutdownNotifier);
6869

6970
creator = pFormulaCreator;
70-
smtEngine = new SmtEngine(exprManager);
71+
randomSeed = pRandomSeed;
7172
incremental = !enableSL;
7273

73-
setOptions(randomSeed, pOptions);
74+
createNewEngine();
7475
}
7576

76-
private void setOptions(int randomSeed, Set<ProverOptions> pOptions) {
77-
smtEngine.setOption("incremental", new SExpr(incremental));
78-
if (pOptions.contains(ProverOptions.GENERATE_MODELS)) {
79-
smtEngine.setOption("produce-models", new SExpr(true));
77+
private void createNewEngine() {
78+
if (smtEngine != null) {
79+
smtEngine.delete(); // cleanup
80+
}
81+
if (exportMapping != null) {
82+
exportMapping.delete();
8083
}
81-
if (pOptions.contains(ProverOptions.GENERATE_UNSAT_CORE)) {
82-
smtEngine.setOption("produce-unsat-cores", new SExpr(true));
84+
if (exprManager != null) {
85+
exprManager.delete(); // cleanup
8386
}
87+
exprManager = new ExprManager();
88+
smtEngine = new SmtEngine(exprManager);
89+
exportMapping = new ExprManagerMapCollection();
90+
smtEngine.setOption("incremental", new SExpr(incremental));
91+
smtEngine.setOption("produce-models", new SExpr(generateModels));
92+
smtEngine.setOption("produce-unsat-cores", new SExpr(generateUnsatCores));
8493
smtEngine.setOption("produce-assertions", new SExpr(true));
8594
smtEngine.setOption("dump-models", new SExpr(true));
8695
// smtEngine.setOption("produce-unsat-cores", new SExpr(true));
@@ -93,10 +102,6 @@ private void setOptions(int randomSeed, Set<ProverOptions> pOptions) {
93102
smtEngine.setOption("full-saturate-quant", new SExpr(true));
94103
}
95104

96-
protected void setOptionForIncremental() {
97-
smtEngine.setOption("incremental", new SExpr(true));
98-
}
99-
100105
/** import an expression from global context into this prover's context. */
101106
protected Expr importExpr(Expr expr) {
102107
return expr.exportTo(exprManager, exportMapping);
@@ -172,13 +177,9 @@ protected Evaluator getEvaluatorWithoutChecks() {
172177
}
173178

174179
private void setChanged() {
175-
closeAllEvaluators();
176180
if (!changedSinceLastSatQuery) {
177181
changedSinceLastSatQuery = true;
178-
if (!incremental) {
179-
// create a new clean smtEngine
180-
smtEngine = new SmtEngine(exprManager);
181-
}
182+
closeAllEvaluators();
182183
}
183184
}
184185

@@ -196,17 +197,20 @@ public boolean isUnsat() throws InterruptedException, SolverException {
196197
closeAllEvaluators();
197198
changedSinceLastSatQuery = false;
198199
if (!incremental) {
199-
for (BooleanFormula f : getAssertedFormulas()) {
200-
assertFormula(f);
201-
}
200+
// in non-incremental mode, we need to create a new solver instance for each sat check
201+
createNewEngine();
202+
getAssertedFormulas().forEach(this::assertFormula);
202203
}
203204

204205
Result result;
205206
try (ShutdownHook hook = new ShutdownHook(shutdownNotifier, smtEngine::interrupt)) {
206207
shutdownNotifier.shutdownIfNecessary();
207208
result = smtEngine.checkSat();
209+
} catch (Exception e) {
210+
throw new SolverException("CVC4 failed during satisfiability check", e);
211+
} finally {
212+
shutdownNotifier.shutdownIfNecessary();
208213
}
209-
shutdownNotifier.shutdownIfNecessary();
210214
return convertSatResult(result);
211215
}
212216

src/org/sosy_lab/java_smt/test/SLFormulaManagerTest.java

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
package org.sosy_lab.java_smt.test;
1010

1111
import static com.google.common.truth.Truth.assertThat;
12-
import static com.google.common.truth.TruthJUnit.assume;
12+
import static org.junit.Assert.assertThrows;
1313

1414
import com.google.common.collect.ImmutableList;
1515
import com.google.common.collect.ImmutableSet;
@@ -34,21 +34,6 @@ private BooleanFormula makeStarAll(List<BooleanFormula> formulas) {
3434
return formulas.stream().reduce(slmgr::makeStar).orElse(bmgr.makeTrue());
3535
}
3636

37-
protected void requireSepNil() {
38-
assume()
39-
.withMessage("Java bindings for solver %s do not support SEP_NIL", solverToUse())
40-
.that(solverToUse())
41-
.isNotEqualTo(Solvers.CVC4);
42-
}
43-
44-
protected void requireMultipleHeapSorts() {
45-
assume()
46-
.withMessage(
47-
"Java bindings for solver %s do not support multiple heap sorts", solverToUse())
48-
.that(solverToUse())
49-
.isNotEqualTo(Solvers.CVC4);
50-
}
51-
5237
@Before
5338
public void setup() {
5439
requireSeparationLogic();
@@ -70,24 +55,52 @@ public void testMakeEmp() throws InterruptedException, SolverException {
7055
}
7156

7257
@Test
73-
public void testMakeEmptoP2() throws InterruptedException, SolverException {
74-
requireMultipleHeapSorts();
58+
public void testMakeEmpWithMultipleSorts() throws InterruptedException, SolverException {
7559
// Actually, no solver supports multiple heap sorts. However, our bindings for CVC5
76-
// apply non-incremental mode for SL and use distinct solver instances for distinct queries.
60+
// can not detect the heap sort for EMP, so we use a dummy sort (Int->Int) instead.
7761

7862
BooleanFormula emptyHeapInt =
7963
slmgr.makeEmptyHeap(FormulaType.RationalType, FormulaType.BooleanType);
8064
BooleanFormula emptyHeapRat =
8165
slmgr.makeEmptyHeap(FormulaType.IntegerType, FormulaType.IntegerType);
8266
BooleanFormula query = bmgr.and(emptyHeapInt, emptyHeapRat);
8367

84-
assertThatFormula(query).isSatisfiable(ProverOptions.ENABLE_SEPARATION_LOGIC);
68+
try (ProverEnvironment prover =
69+
context.newProverEnvironment(ProverOptions.ENABLE_SEPARATION_LOGIC)) {
70+
prover.push(query);
71+
if (solverToUse() == Solvers.CVC5) {
72+
assertThatEnvironment(prover).isSatisfiable();
73+
} else {
74+
assertThrows(Exception.class, () -> prover.isUnsat());
75+
}
76+
prover.pop();
77+
}
8578
}
8679

8780
@Test
88-
public void testNotNilPtoNil() throws InterruptedException, SolverException {
89-
requireSepNil();
81+
public void testMakeEmpWithMultipleSortsInDistinctQueries()
82+
throws InterruptedException, SolverException {
83+
// Actually, no solver supports multiple heap sorts. However, our bindings for CVC5
84+
// apply non-incremental mode for SL and use distinct solver instances for distinct queries.
85+
86+
BooleanFormula emptyHeapInt =
87+
slmgr.makeEmptyHeap(FormulaType.RationalType, FormulaType.BooleanType);
88+
BooleanFormula emptyHeapRat =
89+
slmgr.makeEmptyHeap(FormulaType.IntegerType, FormulaType.IntegerType);
90+
91+
try (ProverEnvironment prover =
92+
context.newProverEnvironment(ProverOptions.ENABLE_SEPARATION_LOGIC)) {
93+
prover.push(emptyHeapInt);
94+
assertThatEnvironment(prover).isSatisfiable();
95+
prover.pop();
96+
prover.push(emptyHeapRat);
97+
assertThatEnvironment(prover).isSatisfiable();
98+
prover.pop();
99+
}
100+
}
90101

102+
@Test
103+
public void testNotNilPtoNil() throws InterruptedException, SolverException {
91104
IntegerFormula nil = slmgr.makeNilElement(FormulaType.IntegerType);
92105
BooleanFormula nilPtoNil = slmgr.makePointsTo(nil, nil);
93106

@@ -96,8 +109,6 @@ public void testNotNilPtoNil() throws InterruptedException, SolverException {
96109

97110
@Test
98111
public void testNilPtoValue() throws InterruptedException, SolverException {
99-
requireSepNil();
100-
101112
IntegerFormula nil = slmgr.makeNilElement(FormulaType.IntegerType);
102113
IntegerFormula value = imgr.makeNumber(42);
103114
BooleanFormula nilPtoValue = slmgr.makePointsTo(nil, value);
@@ -107,8 +118,6 @@ public void testNilPtoValue() throws InterruptedException, SolverException {
107118

108119
@Test
109120
public void testXPtoNil() throws InterruptedException, SolverException {
110-
requireSepNil();
111-
112121
IntegerFormula ptr = imgr.makeVariable("p");
113122
IntegerFormula nil = slmgr.makeNilElement(FormulaType.IntegerType);
114123
BooleanFormula ptoNil = slmgr.makePointsTo(ptr, nil);
@@ -127,8 +136,6 @@ public void testXPtoValue() throws InterruptedException, SolverException {
127136

128137
@Test
129138
public void testPPtoNilThenPPtoNil() throws SolverException, InterruptedException {
130-
requireSepNil();
131-
132139
IntegerFormula ptr = imgr.makeVariable("p");
133140
IntegerFormula nil = slmgr.makeNilElement(FormulaType.IntegerType);
134141
BooleanFormula ptoNil = slmgr.makePointsTo(ptr, nil);
@@ -141,14 +148,14 @@ public void testPPtoNilThenPPtoNil() throws SolverException, InterruptedExceptio
141148
prover.push(ptoNil);
142149
assertThatEnvironment(prover).isSatisfiable();
143150
assertThatEnvironment(prover).isSatisfiable();
151+
assertThatEnvironment(prover).isSatisfiable();
152+
assertThatEnvironment(prover).isSatisfiable();
144153
prover.pop();
145154
}
146155
}
147156

148157
@Test
149158
public void testPtoNilThenPPto42() throws SolverException, InterruptedException {
150-
requireSepNil();
151-
152159
IntegerFormula ptr = imgr.makeVariable("p");
153160
IntegerFormula nil = slmgr.makeNilElement(FormulaType.IntegerType);
154161
IntegerFormula value = imgr.makeNumber(42);
@@ -210,8 +217,6 @@ public void testStar() throws InterruptedException, SolverException {
210217

211218
@Test
212219
public void testSimpleTreeValid() throws InterruptedException, SolverException {
213-
requireSepNil();
214-
215220
// lets build a tree:
216221
// - each node consists of two integers: left and right
217222
// - each node pointer points to the left integer, the right integer is at pointer+1
@@ -250,8 +255,6 @@ public void testSimpleTreeValid() throws InterruptedException, SolverException {
250255

251256
@Test
252257
public void testSimpleTreeInvalid() throws InterruptedException, SolverException {
253-
requireSepNil();
254-
255258
IntegerFormula nil = slmgr.makeNilElement(FormulaType.IntegerType);
256259
IntegerFormula root = imgr.makeVariable("root");
257260
IntegerFormula left = imgr.makeVariable("left");
@@ -271,8 +274,6 @@ public void testSimpleTreeInvalid() throws InterruptedException, SolverException
271274

272275
@Test
273276
public void testListValid() throws InterruptedException, SolverException {
274-
requireSepNil();
275-
276277
IntegerFormula nil = slmgr.makeNilElement(FormulaType.IntegerType);
277278
List<IntegerFormula> nodes = new ArrayList<>();
278279
for (int i = 0; i <= 10; i++) {

0 commit comments

Comments
 (0)