Skip to content

Commit 6c86c56

Browse files
authored
Merge pull request #390 from sosy-lab/389-further-options-for-cvc5
#389: add ConfigurationOption to give CVC5 users the option to define solver specific options directly.
2 parents bf6bda3 + e85c732 commit 6c86c56

File tree

5 files changed

+139
-16
lines changed

5 files changed

+139
-16
lines changed

src/org/sosy_lab/java_smt/solvers/cvc5/CVC5AbstractProver.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.google.common.base.Preconditions;
1212
import com.google.common.collect.Collections2;
1313
import com.google.common.collect.ImmutableList;
14+
import com.google.common.collect.ImmutableMap;
1415
import com.google.errorprone.annotations.CanIgnoreReturnValue;
1516
import io.github.cvc5.CVC5ApiException;
1617
import io.github.cvc5.Result;
@@ -22,6 +23,7 @@
2223
import java.util.Collection;
2324
import java.util.Deque;
2425
import java.util.List;
26+
import java.util.Map.Entry;
2527
import java.util.Optional;
2628
import java.util.Set;
2729
import org.sosy_lab.common.ShutdownNotifier;
@@ -54,7 +56,8 @@ protected CVC5AbstractProver(
5456
ShutdownNotifier pShutdownNotifier,
5557
@SuppressWarnings("unused") int randomSeed,
5658
Set<ProverOptions> pOptions,
57-
FormulaManager pMgr) {
59+
FormulaManager pMgr,
60+
ImmutableMap<String, String> pFurtherOptionsMap) {
5861
super(pOptions, pMgr.getBooleanFormulaManager(), pShutdownNotifier);
5962

6063
mgr = pMgr;
@@ -63,10 +66,14 @@ protected CVC5AbstractProver(
6366
solver = new Solver();
6467
assertedTerms.add(PathCopyingPersistentTreeMap.of());
6568

66-
setSolverOptions(randomSeed, pOptions, solver);
69+
setSolverOptions(randomSeed, pOptions, pFurtherOptionsMap, solver);
6770
}
6871

69-
protected void setSolverOptions(int randomSeed, Set<ProverOptions> pOptions, Solver pSolver) {
72+
protected void setSolverOptions(
73+
int randomSeed,
74+
Set<ProverOptions> pOptions,
75+
ImmutableMap<String, String> pFurtherOptionsMap,
76+
Solver pSolver) {
7077
if (incremental) {
7178
pSolver.setOption("incremental", "true");
7279
}
@@ -86,6 +93,10 @@ protected void setSolverOptions(int randomSeed, Set<ProverOptions> pOptions, Sol
8693

8794
// Enable more complete quantifier solving (for more info see CVC5QuantifiedFormulaManager)
8895
pSolver.setOption("full-saturate-quant", "true");
96+
97+
for (Entry<String, String> option : pFurtherOptionsMap.entrySet()) {
98+
pSolver.setOption(option.getKey(), option.getValue());
99+
}
89100
}
90101

91102
@Override

src/org/sosy_lab/java_smt/solvers/cvc5/CVC5InterpolatingProver.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import static org.sosy_lab.common.collect.Collections3.transformedImmutableSetCopy;
1414

1515
import com.google.common.collect.FluentIterable;
16+
import com.google.common.collect.ImmutableMap;
1617
import com.google.common.collect.ImmutableSet;
1718
import com.google.common.collect.Sets;
1819
import io.github.cvc5.CVC5ApiException;
@@ -35,6 +36,7 @@ public class CVC5InterpolatingProver extends CVC5AbstractProver<String>
3536

3637
private final FormulaManager mgr;
3738
private final Set<ProverOptions> solverOptions;
39+
private final ImmutableMap<String, String> furtherOptionsMap;
3840
private final int seed;
3941
private final CVC5BooleanFormulaManager bmgr;
4042
private final boolean validateInterpolants;
@@ -45,22 +47,28 @@ public class CVC5InterpolatingProver extends CVC5AbstractProver<String>
4547
int randomSeed,
4648
Set<ProverOptions> pOptions,
4749
FormulaManager pMgr,
50+
ImmutableMap<String, String> pFurtherOptionsMap,
4851
boolean pValidateInterpolants) {
49-
super(pFormulaCreator, pShutdownNotifier, randomSeed, pOptions, pMgr);
52+
super(pFormulaCreator, pShutdownNotifier, randomSeed, pOptions, pMgr, pFurtherOptionsMap);
5053
mgr = pMgr;
5154
solverOptions = pOptions;
5255
seed = randomSeed;
5356
bmgr = (CVC5BooleanFormulaManager) mgr.getBooleanFormulaManager();
5457
validateInterpolants = pValidateInterpolants;
58+
furtherOptionsMap = pFurtherOptionsMap;
5559
}
5660

5761
/**
5862
* Sets the same solver Options of the Original Solver to the separate solvertoSet, except for
5963
* produce-interpolants which is set here. From CVC5AbstractProver Line 66
6064
*/
6165
@Override
62-
protected void setSolverOptions(int randomSeed, Set<ProverOptions> pOptions, Solver pSolver) {
63-
super.setSolverOptions(randomSeed, pOptions, pSolver);
66+
protected void setSolverOptions(
67+
int randomSeed,
68+
Set<ProverOptions> pOptions,
69+
ImmutableMap<String, String> pFurtherOptionsMap,
70+
Solver pSolver) {
71+
super.setSolverOptions(randomSeed, pOptions, pFurtherOptionsMap, pSolver);
6472
pSolver.setOption("produce-interpolants", "true");
6573
}
6674

@@ -174,7 +182,7 @@ private Term getCVC5Interpolation(Collection<Term> formulasA, Collection<Term> f
174182

175183
// Uses a separate Solver instance to leave the original solver-context unmodified
176184
Solver itpSolver = new Solver();
177-
setSolverOptions(seed, solverOptions, itpSolver);
185+
setSolverOptions(seed, solverOptions, furtherOptionsMap, itpSolver);
178186

179187
Term interpolant;
180188
try {
@@ -216,7 +224,7 @@ private void checkInterpolationCriteria(Term interpolant, Term phiPlus, Term phi
216224
// build and check both Craig interpolation formulas with the generated interpolant.
217225
Solver validationSolver = new Solver();
218226
// interpolation option is not required for validation
219-
super.setSolverOptions(seed, solverOptions, validationSolver);
227+
super.setSolverOptions(seed, solverOptions, furtherOptionsMap, validationSolver);
220228
try {
221229
validationSolver.push();
222230
validationSolver.assertFormula(validationSolver.mkTerm(Kind.IMPLIES, phiPlus, interpolant));

src/org/sosy_lab/java_smt/solvers/cvc5/CVC5SolverContext.java

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@
22
// an API wrapper for a collection of SMT solvers:
33
// https://github.com/sosy-lab/java-smt
44
//
5-
// SPDX-FileCopyrightText: 2022 Dirk Beyer <https://www.sosy-lab.org>
5+
// SPDX-FileCopyrightText: 2024 Dirk Beyer <https://www.sosy-lab.org>
66
//
77
// SPDX-License-Identifier: Apache-2.0
88

99
package org.sosy_lab.java_smt.solvers.cvc5;
1010

1111
import com.google.common.annotations.VisibleForTesting;
1212
import com.google.common.base.Preconditions;
13+
import com.google.common.base.Splitter;
14+
import com.google.common.base.Splitter.MapSplitter;
15+
import com.google.common.collect.ImmutableMap;
16+
import io.github.cvc5.CVC5ApiRecoverableException;
1317
import io.github.cvc5.Solver;
18+
import java.util.Map.Entry;
1419
import java.util.Set;
1520
import java.util.function.Consumer;
1621
import org.sosy_lab.common.ShutdownNotifier;
@@ -38,8 +43,30 @@ private static class CVC5Settings {
3843
description = "apply additional validation checks for interpolation results")
3944
private boolean validateInterpolants = false;
4045

46+
@Option(
47+
secure = true,
48+
description =
49+
"Further options that will be passed to CVC5 in addition to the default options. "
50+
+ "Format is 'key1=value1,key2=value2'")
51+
private String furtherOptions = "";
52+
53+
private final ImmutableMap<String, String> furtherOptionsMap;
54+
4155
private CVC5Settings(Configuration config) throws InvalidConfigurationException {
4256
config.inject(this);
57+
58+
MapSplitter optionSplitter =
59+
Splitter.on(',')
60+
.trimResults()
61+
.omitEmptyStrings()
62+
.withKeyValueSeparator(Splitter.on('=').limit(2).trimResults());
63+
64+
try {
65+
furtherOptionsMap = ImmutableMap.copyOf(optionSplitter.split(furtherOptions));
66+
} catch (IllegalArgumentException e) {
67+
throw new InvalidConfigurationException(
68+
"Invalid CVC5 option in \"" + furtherOptions + "\": " + e.getMessage(), e);
69+
}
4370
}
4471
}
4572

@@ -94,7 +121,11 @@ public static SolverContext create(
94121
// We keep this instance available until the whole context is closed.
95122
Solver newSolver = new Solver();
96123

97-
setSolverOptions(newSolver, randomSeed);
124+
try {
125+
setSolverOptions(newSolver, randomSeed, settings.furtherOptionsMap);
126+
} catch (CVC5ApiRecoverableException e) { // we do not want to recover after invalid options.
127+
throw new InvalidConfigurationException(e.getMessage(), e);
128+
}
98129

99130
CVC5FormulaCreator pCreator = new CVC5FormulaCreator(newSolver);
100131

@@ -133,11 +164,21 @@ public static SolverContext create(
133164
pCreator, manager, pShutdownNotifier, newSolver, randomSeed, settings);
134165
}
135166

136-
/** Set common options for a CVC5 solver. */
137-
private static void setSolverOptions(Solver pSolver, int randomSeed) {
167+
/**
168+
* Set common options for a CVC5 solver.
169+
*
170+
* @throws CVC5ApiRecoverableException from native code.
171+
*/
172+
private static void setSolverOptions(
173+
Solver pSolver, int randomSeed, ImmutableMap<String, String> furtherOptions)
174+
throws CVC5ApiRecoverableException {
138175
pSolver.setOption("seed", String.valueOf(randomSeed));
139176
pSolver.setOption("output-language", "smtlib2");
140177

178+
for (Entry<String, String> option : furtherOptions.entrySet()) {
179+
pSolver.setOption(option.getKey(), option.getValue());
180+
}
181+
141182
// Set Strings option to enable all String features (such as lessOrEquals).
142183
// This should not have any effect for non-string theories.
143184
// pSolver.setOption("strings-exp", "true");
@@ -182,7 +223,12 @@ public Solvers getSolverName() {
182223
public ProverEnvironment newProverEnvironment0(Set<ProverOptions> pOptions) {
183224
Preconditions.checkState(!closed, "solver context is already closed");
184225
return new CVC5TheoremProver(
185-
creator, shutdownNotifier, randomSeed, pOptions, getFormulaManager());
226+
creator,
227+
shutdownNotifier,
228+
randomSeed,
229+
pOptions,
230+
getFormulaManager(),
231+
settings.furtherOptionsMap);
186232
}
187233

188234
@Override
@@ -200,6 +246,7 @@ protected InterpolatingProverEnvironment<?> newProverEnvironmentWithInterpolatio
200246
randomSeed,
201247
pOptions,
202248
getFormulaManager(),
249+
settings.furtherOptionsMap,
203250
settings.validateInterpolants);
204251
}
205252

src/org/sosy_lab/java_smt/solvers/cvc5/CVC5TheoremProver.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
package org.sosy_lab.java_smt.solvers.cvc5;
1010

11+
import com.google.common.collect.ImmutableMap;
1112
import java.util.Set;
1213
import org.checkerframework.checker.nullness.qual.Nullable;
1314
import org.sosy_lab.common.ShutdownNotifier;
@@ -25,8 +26,9 @@ protected CVC5TheoremProver(
2526
ShutdownNotifier pShutdownNotifier,
2627
@SuppressWarnings("unused") int randomSeed,
2728
Set<ProverOptions> pOptions,
28-
FormulaManager pMgr) {
29-
super(pFormulaCreator, pShutdownNotifier, randomSeed, pOptions, pMgr);
29+
FormulaManager pMgr,
30+
ImmutableMap<String, String> pFurtherOptionsMap) {
31+
super(pFormulaCreator, pShutdownNotifier, randomSeed, pOptions, pMgr, pFurtherOptionsMap);
3032
}
3133

3234
@Override

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

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,25 @@
22
// an API wrapper for a collection of SMT solvers:
33
// https://github.com/sosy-lab/java-smt
44
//
5-
// SPDX-FileCopyrightText: 2020 Dirk Beyer <https://www.sosy-lab.org>
5+
// SPDX-FileCopyrightText: 2024 Dirk Beyer <https://www.sosy-lab.org>
66
//
77
// SPDX-License-Identifier: Apache-2.0
88

99
package org.sosy_lab.java_smt.test;
1010

1111
import static com.google.common.truth.Truth.assertThat;
1212
import static com.google.common.truth.TruthJUnit.assume;
13+
import static org.junit.Assert.assertThrows;
1314

1415
import org.junit.Test;
16+
import org.sosy_lab.common.configuration.InvalidConfigurationException;
17+
import org.sosy_lab.java_smt.SolverContextFactory;
1518
import org.sosy_lab.java_smt.SolverContextFactory.Solvers;
1619
import org.sosy_lab.java_smt.api.BooleanFormula;
20+
import org.sosy_lab.java_smt.api.FormulaManager;
21+
import org.sosy_lab.java_smt.api.ProverEnvironment;
22+
import org.sosy_lab.java_smt.api.SolverContext;
23+
import org.sosy_lab.java_smt.api.SolverException;
1724

1825
public class SolverContextTest extends SolverBasedTest0.ParameterizedSolverBasedTest0 {
1926

@@ -120,4 +127,52 @@ public void testFormulaAccessAfterClose() {
120127
assertThat(bmgr.isTrue(opTerm)).isFalse();
121128
assertThat(bmgr.isFalse(opTerm)).isFalse();
122129
}
130+
131+
@Test
132+
@SuppressWarnings("try")
133+
public void testCVC5WithValidOptions() throws InvalidConfigurationException {
134+
assume().that(solverToUse()).isEqualTo(Solvers.CVC5);
135+
136+
var config2 =
137+
createTestConfigBuilder()
138+
.setOption("solver.cvc5.furtherOptions", "solve-bv-as-int=bitwise")
139+
.build();
140+
var factory2 = new SolverContextFactory(config2, logger, shutdownNotifierToUse());
141+
try (var context2 = factory2.generateContext()) {
142+
// create and ignore
143+
}
144+
}
145+
146+
@Test(timeout = 1000)
147+
@SuppressWarnings({"try", "CheckReturnValue"})
148+
public void testCVC5WithValidOptionsTimeLimit()
149+
throws InvalidConfigurationException, InterruptedException {
150+
assume().that(solverToUse()).isEqualTo(Solvers.CVC5);
151+
152+
// tlimit-per is time limit in ms of wall clock time per query
153+
var configValid =
154+
createTestConfigBuilder().setOption("solver.cvc5.furtherOptions", "tlimit-per=1").build();
155+
var factoryWOption = new SolverContextFactory(configValid, logger, shutdownNotifierToUse());
156+
try (SolverContext contextWTimeLimit = factoryWOption.generateContext()) {
157+
FormulaManager fmgrTimeLimit = contextWTimeLimit.getFormulaManager();
158+
HardIntegerFormulaGenerator hifg =
159+
new HardIntegerFormulaGenerator(
160+
fmgrTimeLimit.getIntegerFormulaManager(), fmgrTimeLimit.getBooleanFormulaManager());
161+
BooleanFormula hardProblem = hifg.generate(100);
162+
try (ProverEnvironment proverTimeLimited = contextWTimeLimit.newProverEnvironment()) {
163+
proverTimeLimited.addConstraint(hardProblem);
164+
assertThrows(SolverException.class, proverTimeLimited::isUnsat);
165+
}
166+
}
167+
}
168+
169+
@Test
170+
public void testCVC5WithInvalidOptions() throws InvalidConfigurationException {
171+
assume().that(solverToUse()).isEqualTo(Solvers.CVC5);
172+
173+
var config2 =
174+
createTestConfigBuilder().setOption("solver.cvc5.furtherOptions", "foo=bar").build();
175+
var factory2 = new SolverContextFactory(config2, logger, shutdownNotifierToUse());
176+
assertThrows(InvalidConfigurationException.class, factory2::generateContext);
177+
}
123178
}

0 commit comments

Comments
 (0)