Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
fc74781
Add incomplete (crude) implementation for CVC5 parser
Oct 27, 2025
2fa2ea6
Enable CVC5 parser tests
Oct 27, 2025
a5a90b7
Disable a slow test for CVC5
Oct 27, 2025
844b362
CVC5 parser: add substitution to known (cached) terms for the final t…
Oct 28, 2025
3b58ca2
CVC5 parser: add some assertions before substituting terms at the end
Oct 28, 2025
025f97a
CVC5 parser: add UF parsing with additional assertions (TODO: Quantif…
Oct 28, 2025
71dee39
CVC5 parser: add info about quantifier/bound variable handling and ad…
Oct 28, 2025
13e130d
CVC5 parser: refactor UF handling and unpack applied UFs before caching
Oct 28, 2025
69cafaf
CVC5: improve retrieval method for free vars from cache for bound vars
Oct 28, 2025
95d1de5
CVC5: only use static imports for the 3 precondition methods to make …
Oct 28, 2025
da72300
CVC5: refactor return in creator method getFreeVariableFromCache()
Oct 28, 2025
4900b2f
CVC5: use a custom visitor to visit all bound variables after parsing…
Oct 28, 2025
55e572e
Add tests for multi-dimensional arrays not based on parsing SMTLIB2 (…
Oct 28, 2025
d13c807
CVC5 parser: apply checkstyle suggestion
Oct 28, 2025
df00d8d
CVC5 Model: add improved array evaluation from Daniel Raffler with mi…
Oct 28, 2025
20be8ed
Merge branch 'fix_cvc5_array_model' into use_new_cvc5_parser
Oct 28, 2025
c7f8be3
CVC5 Parser: clean up error messages and add more doc for them
Oct 28, 2025
fd562b3
CVC5 Model: format
Oct 28, 2025
d8f934a
Merge branch 'fix_cvc5_array_model' into use_new_cvc5_parser
Oct 28, 2025
8cbd003
CVC5 parser: improve doc location and text for an error
Oct 28, 2025
d56b3e9
CVC5 parser: replace all expressions using dot (e.g .def_ ) as first …
Oct 28, 2025
de7bddd
CVC5 parser: use substring method with less arguments
Oct 29, 2025
81add68
CVC5 parser: throw IllegalArgumentException instead of AssertionError…
Oct 29, 2025
baf5458
CVC5 parser: catch CVC5ParseExeception and rethrow as IllegalArgument…
Oct 29, 2025
3d2d434
CVC5 parser: disallow multiple sorts for the same term name
Oct 29, 2025
f6fd8ea
CVC5 parser: properly track number of actually parsed assertions + re…
Oct 29, 2025
06800de
CVC5 dump: refactor collecting and transformation of variables and UF…
Oct 29, 2025
0591f8e
CVC5: add creator method to get all cached variables and UFs
Oct 29, 2025
3db56cf
CVC5: allow parsing to skip double declarations and add constants to …
Oct 29, 2025
37cab0d
CVC5 parser: only add declarations from the cache if they are really …
Oct 29, 2025
3b3b1e7
CVC5: add CVC5 to more strict test category for parsing test
Oct 29, 2025
2689404
CVC5: move newly added set of internal UF names and add doc
Oct 29, 2025
686ef7f
CVC5: refactor parsing to be more readable and understandable
Oct 29, 2025
ad5ab63
CVC5 parser: remove allowed invoke error msg, as it fails later (vari…
Oct 29, 2025
3ae018b
CVC5 parser: also check for present declarations present with declare…
Oct 29, 2025
93c5582
CVC5 parser: add to more strict test branch in SolverFormulaIODeclara…
Oct 29, 2025
c7b57bd
Use (_.getKey(), _.getValue()) when building new map instead of the e…
Oct 29, 2025
3d0c1e5
Simplify usage of stream in CVC5FormulaManager.java
Oct 29, 2025
0e114e3
CVC5 Parser: don't use replace(), but substring() to remove newline f…
Oct 31, 2025
3651299
CVC5 Parser: improve named term TODO w infos from Daniel Raffler
Oct 31, 2025
7ec9162
CVC5 Parser: remove unneeded check for push/pop and add a note instead
Oct 31, 2025
0e1e957
CVC5 Parser: switch parser tests for CVC5 into lenient category that …
Nov 1, 2025
d77198f
CVC5 Parser: rework implementation by using CVC5s options to allow mo…
Nov 1, 2025
bb41939
CVC5FormulaManager reorder methods
Nov 1, 2025
98ff665
CVC5FormulaCreator clean up unused methods and consts
Nov 1, 2025
a94d613
CVC5FormulaManager simplify used methods and doc
Nov 1, 2025
43a2413
CVC5FormulaManager improve JavaDoc for generation of declarations fro…
Nov 1, 2025
55de80f
CVC5 parser: add more doc for options used
Nov 2, 2025
b8b6483
CVC5 parser: make JavaDoc of parser creation more descriptive
Nov 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 114 additions & 15 deletions src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
package org.sosy_lab.java_smt.solvers.cvc5;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashBasedTable;
Expand All @@ -32,10 +32,14 @@
import io.github.cvc5.Term;
import io.github.cvc5.TermManager;
import java.math.BigInteger;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.sosy_lab.common.rationals.Rational;
import org.sosy_lab.java_smt.api.ArrayFormula;
Expand All @@ -48,11 +52,13 @@
import org.sosy_lab.java_smt.api.FormulaType;
import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType;
import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType;
import org.sosy_lab.java_smt.api.FunctionDeclaration;
import org.sosy_lab.java_smt.api.FunctionDeclarationKind;
import org.sosy_lab.java_smt.api.QuantifiedFormulaManager.Quantifier;
import org.sosy_lab.java_smt.api.RegexFormula;
import org.sosy_lab.java_smt.api.StringFormula;
import org.sosy_lab.java_smt.api.visitors.FormulaVisitor;
import org.sosy_lab.java_smt.api.visitors.TraversalProcess;
import org.sosy_lab.java_smt.basicimpl.FormulaCreator;
import org.sosy_lab.java_smt.basicimpl.FunctionDeclarationImpl;
import org.sosy_lab.java_smt.solvers.cvc5.CVC5Formula.CVC5ArrayFormula;
Expand All @@ -76,8 +82,9 @@ public class CVC5FormulaCreator extends FormulaCreator<Term, Sort, TermManager,

// <Name, Sort.toString, Term> because CVC5 returns distinct pointers for types, while the
// String representation is equal (and they are equal)
private final Table<String, String, Term> variablesCache = HashBasedTable.create();
private final Map<String, Term> functionsCache = new HashMap<>();
protected final Table<String, String, Term> variablesCache = HashBasedTable.create();
protected final Map<String, Term> functionsCache = new HashMap<>();
protected boolean registerUnknownBoundVariables = false;
private final TermManager termManager;
private final Solver solver;

Expand All @@ -103,7 +110,7 @@ public Term makeVariable(Sort sort, String name) {
if (existingVar != null) {
return existingVar;
}
Preconditions.checkArgument(
checkArgument(
!variablesCache.containsRow(name),
"Symbol %s requested with type %s, but already used with type %s",
name,
Expand Down Expand Up @@ -417,7 +424,7 @@ public <R> R visit(FormulaVisitor<R> visitor, Formula formula, final Term f) {
// BOUND vars are used for all vars that are bound to a quantifier in CVC5.
// We resubstitute them back to the original free.
// CVC5 doesn't give you the de-brujin index
Term originalVar = accessVariablesCache(formula.toString(), sort);
Term originalVar = getFreeVariableFromCache(formula.toString(), sort, visitor);
return visitor.visitBoundVariable(encapsulate(originalVar), 0);

} else if (f.getKind() == Kind.FORALL || f.getKind() == Kind.EXISTS) {
Expand All @@ -427,7 +434,7 @@ public <R> R visit(FormulaVisitor<R> visitor, Formula formula, final Term f) {
List<Formula> freeVars = new ArrayList<>();
for (Term boundVar : f.getChild(0)) { // unpack grand-children of f.
String name = getName(boundVar);
Term freeVar = Preconditions.checkNotNull(accessVariablesCache(name, boundVar.getSort()));
Term freeVar = getFreeVariableFromCache(name, boundVar.getSort(), visitor);
body = body.substitute(boundVar, freeVar);
freeVars.add(encapsulate(freeVar));
}
Expand All @@ -439,7 +446,7 @@ public <R> R visit(FormulaVisitor<R> visitor, Formula formula, final Term f) {
return visitor.visitFreeVariable(formula, dequote(f.toString()));

} else if (f.getKind() == Kind.APPLY_CONSTRUCTOR) {
Preconditions.checkState(
checkState(
f.getNumChildren() == 1, "Unexpected formula '%s' with sort '%s'", f, f.getSort());
return visitor.visitConstant(formula, f.getChild(0).getSymbol());

Expand Down Expand Up @@ -768,15 +775,15 @@ public Term declareUFImpl(String pName, Sort pReturnType, List<Sort> pArgTypes)
functionsCache.put(pName, exp);

} else {
Preconditions.checkArgument(
checkArgument(
exp.getSort().equals(exp.getSort()),
"Symbol %s already in use for different return type %s",
exp,
exp.getSort());
for (int i = 1; i < exp.getNumChildren(); i++) {
// CVC5s first argument in a function/Uf is the declaration, we don't need that here
try {
Preconditions.checkArgument(
checkArgument(
pArgTypes.get(i).equals(exp.getChild(i).getSort()),
"Argument %s with type %s does not match expected type %s",
i - 1,
Expand Down Expand Up @@ -843,19 +850,111 @@ private FloatingPointNumber convertFloatingPoint(Term value) throws CVC5ApiExcep
final var expWidth = Ints.checkedCast(fpValue.first);
final var mantWidth = Ints.checkedCast(fpValue.second - 1); // without sign bit
final var bvValue = fpValue.third;
Preconditions.checkState(bvValue.isBitVectorValue());
checkState(bvValue.isBitVectorValue());
final var bits = bvValue.getBitVectorValue();
return FloatingPointNumber.of(bits, expWidth, mantWidth);
}

private Term accessVariablesCache(String name, Sort sort) {
/**
* Returns the free variable for the given name and sort of a bound variable from the variables
* cache. Will throw a {@link NullPointerException} if no variable is known for the input!
*/
private Term getFreeVariableFromCache(String name, Sort sort, FormulaVisitor<?> visitor) {
if (visitor instanceof BoundVariablesRegisteringRecursiveVisitor) {
((BoundVariablesRegisteringRecursiveVisitor) visitor).registerBoundVariable(name, sort);
}
Term existingVar = variablesCache.get(name, sort.toString());
Preconditions.checkNotNull(
return checkNotNull(
existingVar,
"Symbol %s requested with type %s, but already used with type %s",
"Symbol %s requested with type %s, but %s",
name,
sort,
variablesCache.row(name).keySet());
return existingVar;
variablesCache.containsRow(name)
? "the used symbol is already registered with type " + variablesCache.row(name).keySet()
: "the used symbol is unknown to the variables cache");
}

/**
* Caches all bound variables nested in the boolean input term that are unknown to the variable
* cache with a free variable copy in it.
*/
protected void registerBoundVariablesWithVisitor(Term input) {
checkArgument(
input.getSort().isBoolean(),
"Only boolean terms can be used to register " + "bound variables as free variables!");

BoundVariablesRegisteringRecursiveVisitor boundVariablesRegisteringRecursiveVisitor =
new BoundVariablesRegisteringRecursiveVisitor(this);

boundVariablesRegisteringRecursiveVisitor.addToQueue(encapsulateBoolean(input));
while (!boundVariablesRegisteringRecursiveVisitor.isQueueEmpty()) {
Formula tt = boundVariablesRegisteringRecursiveVisitor.pop();
TraversalProcess process = visit(tt, boundVariablesRegisteringRecursiveVisitor);
if (process == TraversalProcess.ABORT) {
return;
}
}
}

private static final class BoundVariablesRegisteringRecursiveVisitor
implements FormulaVisitor<TraversalProcess> {

private final Set<Formula> seen = new HashSet<>();
private final Deque<Formula> toVisit = new ArrayDeque<>();

private final CVC5FormulaCreator usedCreator;

BoundVariablesRegisteringRecursiveVisitor(CVC5FormulaCreator pCreator) {
usedCreator = checkNotNull(pCreator);
}

private void registerBoundVariable(String boundVariableName, Sort boundVarSort) {
String boundSort = boundVarSort.toString();
Term existingVar = usedCreator.variablesCache.get(boundVariableName, boundSort);
if (existingVar == null) {
existingVar = usedCreator.makeVariable(boundVarSort, boundVariableName);
usedCreator.variablesCache.put(boundVariableName, boundSort, existingVar);
}
}

void addToQueue(Formula f) {
if (seen.add(f)) {
toVisit.push(f);
}
}

boolean isQueueEmpty() {
return toVisit.isEmpty();
}

Formula pop() {
return toVisit.pop();
}

@Override
public TraversalProcess visitFreeVariable(Formula pF, String pName) {
return TraversalProcess.CONTINUE;
}

@Override
public TraversalProcess visitConstant(Formula pF, Object pValue) {
return TraversalProcess.CONTINUE;
}

@Override
public TraversalProcess visitFunction(
Formula pF, List<Formula> pArgs, FunctionDeclaration<?> pFunctionDeclaration) {
for (Formula f : pArgs) {
addToQueue(f);
}
return TraversalProcess.CONTINUE;
}

@Override
public TraversalProcess visitQuantifier(
BooleanFormula pF, Quantifier pQuantifier, List<Formula> boundVars, BooleanFormula pBody) {
addToQueue(pBody);
return TraversalProcess.CONTINUE;
}
}
}
Loading