Skip to content

Commit ad84a68

Browse files
authored
Merge pull request #391 from sosy-lab/257-more-theories-for-princess
Add support for Strings and Rationals to the Princess backend
2 parents ecc8a9c + 0c70424 commit ad84a68

26 files changed

+1241
-175
lines changed

.classpath

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ SPDX-License-Identifier: Apache-2.0
2828
<classpathentry kind="lib" path="lib/java/runtime-princess/scala-library.jar"/>
2929
<classpathentry kind="lib" path="lib/java/runtime-princess/princess-smt-parser_2.13.jar"/>
3030
<classpathentry kind="lib" path="lib/java/runtime-princess/java-cup-runtime.jar"/>
31+
<classpathentry kind="lib" path="lib/java/runtime-princess/automaton.jar"/>
32+
<classpathentry kind="lib" path="lib/java/runtime-princess/org.sat4j.core.jar"/>
33+
<classpathentry kind="lib" path="lib/java/runtime-princess/ostrich_2.13.jar"/>
34+
<classpathentry kind="lib" path="lib/java/runtime-princess/ostrich-ecma2020-parser_2.13.jar"/>
3135
<classpathentry kind="lib" path="lib/java/runtime-z3/com.microsoft.z3.jar" sourcepath="lib/java-contrib/com.microsoft.z3-sources.jar"/>
3236
<classpathentry kind="lib" path="lib/java/runtime-cvc4/CVC4.jar"/>
3337
<classpathentry kind="lib" path="lib/java/runtime-cvc5/cvc5.jar"/>

.idea/JavaSMT.iml

+18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/ivy.xml

+13-6
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ SPDX-License-Identifier: Apache-2.0
9898
<dependency org="org.apache.ivy" name="ivy" rev="${ivy.target_version}" conf="build->default"/>
9999

100100
<!-- Google Auto-Value
101-
Library for auto-generating value types. --><dependency org="com.google.auto.value" name="auto-value" rev="1.11.0" conf="build->default"/>
101+
Library for auto-generating value types. -->
102+
<dependency org="com.google.auto.value" name="auto-value" rev="1.11.0" conf="build->default"/>
102103
<dependency org="com.google.auto.value" name="auto-value-annotations" rev="1.11.0" conf="build->default; contrib->sources"/>
103104

104105
<!-- Annotations we use for @Nullable etc. -->
@@ -149,13 +150,19 @@ SPDX-License-Identifier: Apache-2.0
149150
<dependency org="de.uni-freiburg.informatik.ultimate" name="smtinterpol" rev="2.5-1242-g5c50fb6d" conf="runtime-smtinterpol->master; contrib->sources"/>
150151

151152
<!-- Princess for our Maven release -->
152-
<dependency org="io.github.uuverifiers" name="princess_2.13" rev="2024-01-12" conf="runtime-princess-with-javacup->default; contrib->sources"/>
153-
<!-- Princess for our Ivy release-->
154-
<dependency org="io.github.uuverifiers" name="princess_2.13" rev="2024-01-12" conf="runtime-princess->default; contrib->sources">
155-
<!-- Exclude dependency on java-cup and replace it with java-cup-runtime, which is enough.
153+
<dependency org="io.github.uuverifiers" name="princess_2.13" rev="2024-11-08" conf="runtime-princess-with-javacup->default; contrib->sources"/>
154+
<!-- Princess and Ostrich for our Ivy release -->
155+
<dependency org="io.github.uuverifiers" name="princess_2.13" rev="2024-11-08" conf="runtime-princess->default; contrib->sources">
156+
<!-- Exclude dependency on java-cup and replace it with java-cup-runtime, which is enough.
156157
We use the JAR that is published by us instead of the one from net.sf.squirrel-sql.thirdparty-non-maven
157158
because the latter does not provide a separate JAR for java-cup-runtime. -->
158-
<exclude org="net.sf.squirrel-sql.thirdparty-non-maven" name="java-cup"/>
159+
<exclude org="net.sf.squirrel-sql.thirdparty-non-maven" name="java-cup"/>
160+
</dependency>
161+
<dependency org="io.github.uuverifiers" name="ostrich_2.13" rev="1.4.1" conf="runtime-princess->default; contrib->sources">
162+
<!-- Exclude dependency on java-cup and replace it with java-cup-runtime, which is enough.
163+
We use the JAR that is published by us instead of the one from net.sf.squirrel-sql.thirdparty-non-maven
164+
because the latter does not provide a separate JAR for java-cup-runtime. -->
165+
<exclude org="net.sf.squirrel-sql.thirdparty-non-maven" name="java-cup"/>
159166
</dependency>
160167
<dependency org="edu.tum.cs" name="java-cup" rev="11b-20160615" conf="runtime-princess->runtime"/>
161168

src/org/sosy_lab/java_smt/basicimpl/AbstractBaseFormulaManager.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ protected final FormulaCreator<TFormulaInfo, TType, TEnv, TFuncDecl> getFormulaC
3030
return formulaCreator;
3131
}
3232

33-
final TFormulaInfo extractInfo(Formula pBits) {
33+
protected final TFormulaInfo extractInfo(Formula pBits) {
3434
return getFormulaCreator().extractInfo(pBits);
3535
}
3636

src/org/sosy_lab/java_smt/basicimpl/AbstractProver.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import static com.google.common.base.Preconditions.checkState;
1212

1313
import com.google.common.base.Preconditions;
14+
import com.google.common.collect.ImmutableList;
1415
import com.google.common.collect.ImmutableSet;
1516
import com.google.common.collect.Iterables;
1617
import com.google.common.collect.LinkedHashMultimap;
@@ -149,7 +150,7 @@ protected void unregisterEvaluator(Evaluator pEvaluator) {
149150
}
150151

151152
protected void closeAllEvaluators() {
152-
evaluators.forEach(Evaluator::close);
153+
ImmutableList.copyOf(evaluators).forEach(Evaluator::close);
153154
evaluators.clear();
154155
}
155156

src/org/sosy_lab/java_smt/basicimpl/AbstractStringFormulaManager.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ protected AbstractStringFormulaManager(
3232
super(pCreator);
3333
}
3434

35-
private StringFormula wrapString(TFormulaInfo formulaInfo) {
35+
protected StringFormula wrapString(TFormulaInfo formulaInfo) {
3636
return getFormulaCreator().encapsulateString(formulaInfo);
3737
}
3838

39-
private RegexFormula wrapRegex(TFormulaInfo formulaInfo) {
39+
protected RegexFormula wrapRegex(TFormulaInfo formulaInfo) {
4040
return getFormulaCreator().encapsulateRegex(formulaInfo);
4141
}
4242

src/org/sosy_lab/java_smt/basicimpl/FormulaCreator.java

+34-16
Original file line numberDiff line numberDiff line change
@@ -137,43 +137,59 @@ public final TType getRegexType() {
137137
public abstract TFormulaInfo makeVariable(TType type, String varName);
138138

139139
public BooleanFormula encapsulateBoolean(TFormulaInfo pTerm) {
140-
assert getFormulaType(pTerm).isBooleanType();
140+
checkArgument(
141+
getFormulaType(pTerm).isBooleanType(),
142+
"Boolean formula has unexpected type: %s",
143+
getFormulaType(pTerm));
141144
return new BooleanFormulaImpl<>(pTerm);
142145
}
143146

144147
protected BitvectorFormula encapsulateBitvector(TFormulaInfo pTerm) {
145-
assert getFormulaType(pTerm).isBitvectorType();
148+
checkArgument(
149+
getFormulaType(pTerm).isBitvectorType(),
150+
"Bitvector formula has unexpected type: %s",
151+
getFormulaType(pTerm));
146152
return new BitvectorFormulaImpl<>(pTerm);
147153
}
148154

149155
protected FloatingPointFormula encapsulateFloatingPoint(TFormulaInfo pTerm) {
150-
assert getFormulaType(pTerm).isFloatingPointType();
156+
checkArgument(
157+
getFormulaType(pTerm).isFloatingPointType(),
158+
"Floatingpoint formula has unexpected type: %s",
159+
getFormulaType(pTerm));
151160
return new FloatingPointFormulaImpl<>(pTerm);
152161
}
153162

154163
protected <TI extends Formula, TE extends Formula> ArrayFormula<TI, TE> encapsulateArray(
155164
TFormulaInfo pTerm, FormulaType<TI> pIndexType, FormulaType<TE> pElementType) {
156-
assert getFormulaType(pTerm).equals(FormulaType.getArrayType(pIndexType, pElementType))
157-
: "Expected: "
158-
+ getFormulaType(pTerm)
159-
+ " but found: "
160-
+ FormulaType.getArrayType(pIndexType, pElementType);
161-
165+
checkArgument(
166+
getFormulaType(pTerm).equals(FormulaType.getArrayType(pIndexType, pElementType)),
167+
"Array formula has unexpected type: %s",
168+
getFormulaType(pTerm));
162169
return new ArrayFormulaImpl<>(pTerm, pIndexType, pElementType);
163170
}
164171

165172
protected StringFormula encapsulateString(TFormulaInfo pTerm) {
166-
assert getFormulaType(pTerm).isStringType();
173+
checkArgument(
174+
getFormulaType(pTerm).isStringType(),
175+
"String formula has unexpected type: %s",
176+
getFormulaType(pTerm));
167177
return new StringFormulaImpl<>(pTerm);
168178
}
169179

170180
protected RegexFormula encapsulateRegex(TFormulaInfo pTerm) {
171-
assert getFormulaType(pTerm).isRegexType();
181+
checkArgument(
182+
getFormulaType(pTerm).isRegexType(),
183+
"Regex formula has unexpected type: %s",
184+
getFormulaType(pTerm));
172185
return new RegexFormulaImpl<>(pTerm);
173186
}
174187

175188
protected EnumerationFormula encapsulateEnumeration(TFormulaInfo pTerm) {
176-
assert getFormulaType(pTerm).isEnumerationType();
189+
checkArgument(
190+
getFormulaType(pTerm).isEnumerationType(),
191+
"Enumeration formula has unexpected type: %s",
192+
getFormulaType(pTerm));
177193
return new EnumerationFormulaImpl<>(pTerm);
178194
}
179195

@@ -183,10 +199,12 @@ public Formula encapsulateWithTypeOf(TFormulaInfo pTerm) {
183199

184200
@SuppressWarnings("unchecked")
185201
public <T extends Formula> T encapsulate(FormulaType<T> pType, TFormulaInfo pTerm) {
186-
assert pType.equals(getFormulaType(pTerm))
187-
: String.format(
188-
"Trying to encapsulate formula %s of type %s as %s",
189-
pTerm, getFormulaType(pTerm), pType);
202+
checkArgument(
203+
pType.equals(getFormulaType(pTerm)),
204+
"Trying to encapsulate formula %s of type %s as %s",
205+
pTerm,
206+
getFormulaType(pTerm),
207+
pType);
190208
if (pType.isBooleanType()) {
191209
return (T) new BooleanFormulaImpl<>(pTerm);
192210
} else if (pType.isIntegerType()) {

src/org/sosy_lab/java_smt/solvers/princess/PrincessAbstractProver.java

+35-7
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import java.util.ArrayDeque;
2424
import java.util.ArrayList;
2525
import java.util.Collection;
26+
import java.util.Collections;
2627
import java.util.Deque;
28+
import java.util.LinkedHashSet;
2729
import java.util.List;
2830
import java.util.Optional;
2931
import java.util.Set;
@@ -32,6 +34,7 @@
3234
import org.sosy_lab.common.collect.PathCopyingPersistentTreeMap;
3335
import org.sosy_lab.common.collect.PersistentMap;
3436
import org.sosy_lab.java_smt.api.BooleanFormula;
37+
import org.sosy_lab.java_smt.api.Formula;
3538
import org.sosy_lab.java_smt.api.Model;
3639
import org.sosy_lab.java_smt.api.SolverContext.ProverOptions;
3740
import org.sosy_lab.java_smt.api.SolverException;
@@ -46,6 +49,15 @@ abstract class PrincessAbstractProver<E> extends AbstractProverWithAllSat<E> {
4649
protected final PrincessFormulaManager mgr;
4750
protected final Deque<Level> trackingStack = new ArrayDeque<>(); // symbols on all levels
4851

52+
/**
53+
* Values returned by {@link Model#evaluate(Formula)}.
54+
*
55+
* <p>We need to record these to make sure that the values returned by the evaluator are
56+
* consistant. Calling {@link #isUnsat()} will reset this list as the underlying model has been
57+
* updated.
58+
*/
59+
protected final Set<IFormula> evaluatedTerms = new LinkedHashSet<>();
60+
4961
// assign a unique partition number for eah added constraint, for unsat-core and interpolation.
5062
protected final UniqueIdGenerator idGenerator = new UniqueIdGenerator();
5163
protected final Deque<PersistentMap<Integer, BooleanFormula>> partitions = new ArrayDeque<>();
@@ -76,9 +88,11 @@ protected PrincessAbstractProver(
7688
public boolean isUnsat() throws SolverException {
7789
Preconditions.checkState(!closed);
7890
wasLastSatCheckSat = false;
91+
evaluatedTerms.clear();
7992
final Value result = api.checkSat(true);
8093
if (result.equals(SimpleAPI.ProverStatus$.MODULE$.Sat())) {
8194
wasLastSatCheckSat = true;
95+
evaluatedTerms.add(api.partialModelAsFormula());
8296
return false;
8397
} else if (result.equals(SimpleAPI.ProverStatus$.MODULE$.Unsat())) {
8498
return true;
@@ -121,14 +135,27 @@ protected void popImpl() {
121135
// we have to recreate symbols on lower levels, because JavaSMT assumes "global" symbols.
122136
Level level = trackingStack.pop();
123137
api.addBooleanVariables(asScala(level.booleanSymbols));
124-
api.addConstants(asScala(level.intSymbols));
138+
api.addConstants(asScala(level.theorySymbols));
125139
level.functionSymbols.forEach(api::addFunction);
126140
if (!trackingStack.isEmpty()) {
127141
trackingStack.peek().mergeWithHigher(level);
128142
}
129143
partitions.pop();
130144
}
131145

146+
/**
147+
* Get all terms that have been evaluated in the current model. The formulas are assignments that
148+
* extend the original model.
149+
*/
150+
Collection<IFormula> getEvaluatedTerms() {
151+
return Collections.unmodifiableCollection(evaluatedTerms);
152+
}
153+
154+
/** Track an assignment `term == value` for an evaluated term and its value. */
155+
void addEvaluatedTerm(IFormula pFormula) {
156+
evaluatedTerms.add(pFormula);
157+
}
158+
132159
@SuppressWarnings("resource")
133160
@Override
134161
public Model getModel() throws SolverException {
@@ -138,6 +165,7 @@ public Model getModel() throws SolverException {
138165
return new CachingModel(getEvaluatorWithoutChecks());
139166
}
140167

168+
@SuppressWarnings("resource")
141169
@Override
142170
protected PrincessModel getEvaluatorWithoutChecks() throws SolverException {
143171
final PartialModel partialModel;
@@ -146,7 +174,7 @@ protected PrincessModel getEvaluatorWithoutChecks() throws SolverException {
146174
} catch (SimpleAPIException ex) {
147175
throw new SolverException(ex.getMessage(), ex);
148176
}
149-
return new PrincessModel(this, partialModel, creator, api);
177+
return registerEvaluator(new PrincessModel(this, partialModel, creator, api));
150178
}
151179

152180
/**
@@ -213,12 +241,12 @@ void addSymbol(IFormula f) {
213241
}
214242
}
215243

216-
/** add external definition: integer variable. */
244+
/** add external definition: theory variable (integer, rational, string, etc). */
217245
void addSymbol(ITerm f) {
218246
Preconditions.checkState(!closed);
219247
api.addConstant(f);
220248
if (!trackingStack.isEmpty()) {
221-
trackingStack.peek().intSymbols.add(f);
249+
trackingStack.peek().theorySymbols.add(f);
222250
}
223251
}
224252

@@ -233,21 +261,21 @@ void addSymbol(IFunction f) {
233261

234262
static class Level {
235263
final List<IFormula> booleanSymbols = new ArrayList<>();
236-
final List<ITerm> intSymbols = new ArrayList<>();
264+
final List<ITerm> theorySymbols = new ArrayList<>();
237265
final List<IFunction> functionSymbols = new ArrayList<>();
238266

239267
Level() {}
240268

241269
/** add higher level to current level, we keep the order of creating symbols. */
242270
void mergeWithHigher(Level other) {
243271
this.booleanSymbols.addAll(other.booleanSymbols);
244-
this.intSymbols.addAll(other.intSymbols);
272+
this.theorySymbols.addAll(other.theorySymbols);
245273
this.functionSymbols.addAll(other.functionSymbols);
246274
}
247275

248276
@Override
249277
public String toString() {
250-
return String.format("{%s, %s, %s}", booleanSymbols, intSymbols, functionSymbols);
278+
return String.format("{%s, %s, %s}", booleanSymbols, theorySymbols, functionSymbols);
251279
}
252280
}
253281
}

0 commit comments

Comments
 (0)