Skip to content

Commit d00c4c2

Browse files
committed
rewrite and simplify a fixed-point algorithm.
The new approach has several improvements: - only analyse those constraints that are referenced in terms, - do not compare Sets for the fixed-point, but wait for an empty waitlist.
1 parent f452b34 commit d00c4c2

File tree

4 files changed

+46
-64
lines changed

4 files changed

+46
-64
lines changed

src/org/sosy_lab/java_smt/solvers/bitwuzla/BitwuzlaFloatingPointManager.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,16 @@ protected Term toIeeeBitvectorImpl(Term pNumber) {
212212

213213
Sort bvSort = termManager.mk_bv_sort(sizeExp + sizeSig);
214214

215+
// The following code creates a new variable that is returned as result.
216+
// Additionally, we track constraints about the equality of the new variable and the FP number,
217+
// which is added onto the prover stack whenever the new variable is used as assertion.
218+
219+
// TODO This internal implementation is a technical dept and should be removed.
220+
// The additional constraints are not transparent in all cases, e.g., when visiting a
221+
// formula, creating a model, or transferring the assertions onto another prover stack.
222+
// A better way would be a direct implementation of this in Bitwuzla, without interfering
223+
// with JavaSMT.
224+
215225
// Note that NaN is handled as a special case in this method. This is not strictly necessary,
216226
// but if we just use "fpTerm = to_fp(bvVar)" the NaN will be given a random payload (and
217227
// sign). Since NaN payloads are not preserved here anyway we might as well pick a canonical
@@ -231,7 +241,7 @@ protected Term toIeeeBitvectorImpl(Term pNumber) {
231241
termManager.mk_term(Kind.FP_TO_FP_FROM_BV, bvVar, sizeExp, sizeSig),
232242
pNumber));
233243

234-
bitwuzlaCreator.addVariableCast(newVariable, equal);
244+
bitwuzlaCreator.addConstraintForVariable(newVariable, equal);
235245
return bvVar;
236246
}
237247

src/org/sosy_lab/java_smt/solvers/bitwuzla/BitwuzlaFormulaCreator.java

Lines changed: 25 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,20 @@
99
package org.sosy_lab.java_smt.solvers.bitwuzla;
1010

1111
import static com.google.common.base.Preconditions.checkArgument;
12+
import static org.sosy_lab.common.collect.Collections3.transformedImmutableSetCopy;
1213

1314
import com.google.common.base.Preconditions;
1415
import com.google.common.collect.HashBasedTable;
1516
import com.google.common.collect.ImmutableList;
16-
import com.google.common.collect.ImmutableSet;
17-
import com.google.common.collect.Maps;
18-
import com.google.common.collect.Sets;
1917
import com.google.common.collect.Table;
2018
import java.math.BigInteger;
19+
import java.util.ArrayDeque;
2120
import java.util.ArrayList;
21+
import java.util.Collection;
22+
import java.util.Deque;
2223
import java.util.HashMap;
2324
import java.util.Iterator;
25+
import java.util.LinkedHashSet;
2426
import java.util.List;
2527
import java.util.Map;
2628
import java.util.Map.Entry;
@@ -60,7 +62,8 @@ public class BitwuzlaFormulaCreator extends FormulaCreator<Term, Sort, Void, Bit
6062
private final Table<String, Sort, Term> formulaCache = HashBasedTable.create();
6163

6264
/**
63-
* Maps symbols from fp-to-bv casts to their defining equation.
65+
* This mapping stores symbols and their constraints, such as from fp-to-bv casts with their
66+
* defining equation.
6467
*
6568
* <p>Bitwuzla does not support casts from floating-point to bitvector natively. The reason given
6669
* is that the value is undefined for NaN and that the SMT-LIB standard also does not include such
@@ -72,7 +75,7 @@ public class BitwuzlaFormulaCreator extends FormulaCreator<Term, Sort, Void, Bit
7275
* the newly introduced variable symbols and the values are the defining equations as mentioned
7376
* above.
7477
*/
75-
private final Map<String, Term> variableCasts = new HashMap<>();
78+
private final Map<String, Term> constraintsForVariables = new HashMap<>();
7679

7780
protected BitwuzlaFormulaCreator(TermManager pTermManager) {
7881
super(null, pTermManager.mk_bool_sort(), null, null, null, null);
@@ -593,52 +596,34 @@ public Object convertValue(Term term) {
593596
throw new AssertionError("Unknown value type.");
594597
}
595598

596-
/** Add a side-condition from a fp-to-bv to the set. */
597-
public void addVariableCast(String newVariable, Term equal) {
598-
variableCasts.put(newVariable, equal);
599+
/** Add a constraint that is pushed onto the prover stack whenever the variable is used. */
600+
public void addConstraintForVariable(String variable, Term constraint) {
601+
constraintsForVariables.put(variable, constraint);
599602
}
600603

601604
/**
602-
* Returns a set of side-conditions that are needed to handle the variable casts in the terms.
605+
* Returns a set of additional constraints (side-conditions) that are needed to use some variables
606+
* from the given term, such as utility variables from casts.
603607
*
604608
* <p>Bitwuzla does not support fp-to-bv conversion natively. We have to use side-conditions as a
605609
* workaround. When a term containing fp-to-bv casts is added to the assertion stack these
606610
* side-conditions need to be collected by calling this method and then also adding them to the
607611
* assertion stack.
608612
*/
609-
public Iterable<Term> getVariableCasts(Iterable<Term> pTerms) {
610-
// Build the transition function from the side-conditions. We map the variables on the left
611-
// side of the defining equation to the set of variables on the right side.
612-
// f.ex __CAST_TO_BV_0 -> fp.to_fp(CAST_TO_BV_0) = (+ a b)
613-
// becomes
614-
// Map.of(__CAST_TO_BV, Set.of(__CAST_TO_BV, a b))
615-
Map<String, Set<String>> transitions =
616-
Maps.transformValues(
617-
variableCasts,
618-
term ->
619-
Sets.intersection(
620-
variableCasts.keySet(), extractVariablesAndUFs(term, false).keySet()));
621-
622-
// Calculate the initial set of symbols from the terms in the argument
623-
ImmutableSet.Builder<String> initBuilder = ImmutableSet.builder();
624-
for (Term term : pTerms) {
625-
initBuilder.addAll(extractVariablesAndUFs(term, false).keySet());
626-
}
627-
ImmutableSet<String> initialSet = initBuilder.build();
628-
629-
Set<String> r0 = ImmutableSet.of();
630-
Set<String> r1 = Sets.intersection(initialSet, transitions.keySet());
631-
// Calculate the fixpoint for the transition function
632-
while (!r0.equals(r1)) {
633-
r0 = r1;
634-
// Iterate the transition function
635-
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
636-
for (String var : r0) {
637-
builder.addAll(transitions.get(var));
613+
public Collection<Term> getConstraintsForTerm(Term pTerm) {
614+
final Set<String> usedConstraintVariables = new LinkedHashSet<>();
615+
final Deque<String> waitlist = new ArrayDeque<>(extractVariablesAndUFs(pTerm, false).keySet());
616+
while (!waitlist.isEmpty()) {
617+
String current = waitlist.pop();
618+
if (constraintsForVariables.containsKey(current)) { // ignore variables without constraints
619+
if (usedConstraintVariables.add(current)) {
620+
// if we found a new variable with constraint, get transitive variables from constraint
621+
Term constraint = constraintsForVariables.get(current);
622+
waitlist.addAll(extractVariablesAndUFs(constraint, false).keySet());
623+
}
638624
}
639-
r1 = builder.build();
640625
}
641626

642-
return Maps.filterKeys(variableCasts, r0::contains).values();
627+
return transformedImmutableSetCopy(usedConstraintVariables, constraintsForVariables::get);
643628
}
644629
}

src/org/sosy_lab/java_smt/solvers/bitwuzla/BitwuzlaFormulaManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ public void appendTo(Appendable out) throws IOException {
191191
return;
192192
}
193193
Bitwuzla bitwuzla = new Bitwuzla(creator.getTermManager());
194-
for (Term t : creator.getVariableCasts(ImmutableList.of(pTerm))) {
194+
for (Term t : creator.getConstraintsForTerm(pTerm)) {
195195
bitwuzla.assert_formula(t);
196196
}
197197
bitwuzla.assert_formula(pTerm);

src/org/sosy_lab/java_smt/solvers/bitwuzla/BitwuzlaTheoremProver.java

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@
1010

1111
import com.google.common.base.Preconditions;
1212
import com.google.common.collect.Collections2;
13-
import com.google.common.collect.FluentIterable;
14-
import com.google.common.collect.ImmutableList;
1513
import java.util.ArrayList;
1614
import java.util.Collection;
15+
import java.util.LinkedHashSet;
1716
import java.util.List;
1817
import java.util.Optional;
1918
import java.util.Set;
@@ -26,7 +25,6 @@
2625
import org.sosy_lab.java_smt.api.SolverException;
2726
import org.sosy_lab.java_smt.basicimpl.AbstractProverWithAllSat;
2827
import org.sosy_lab.java_smt.basicimpl.CachingModel;
29-
import org.sosy_lab.java_smt.solvers.bitwuzla.BitwuzlaFormula.BitwuzlaBooleanFormula;
3028
import org.sosy_lab.java_smt.solvers.bitwuzla.api.Bitwuzla;
3129
import org.sosy_lab.java_smt.solvers.bitwuzla.api.Option;
3230
import org.sosy_lab.java_smt.solvers.bitwuzla.api.Options;
@@ -94,19 +92,12 @@ public void popImpl() {
9492

9593
@Override
9694
public @Nullable Void addConstraintImpl(BooleanFormula constraint) throws InterruptedException {
97-
Term formula = ((BitwuzlaBooleanFormula) constraint).getTerm();
98-
99-
// Assert the formula
95+
wasLastSatCheckSat = false;
96+
Term formula = creator.extractInfo(constraint);
10097
env.assert_formula(formula);
101-
102-
// Collect side-conditions for all variable casts and push them onto the stack
103-
for (Term t : creator.getVariableCasts(ImmutableList.of(formula))) {
98+
for (Term t : creator.getConstraintsForTerm(formula)) {
10499
env.assert_formula(t);
105100
}
106-
107-
// Set the state to 'changed'
108-
wasLastSatCheckSat = false;
109-
110101
return null;
111102
}
112103

@@ -156,18 +147,14 @@ public boolean isUnsatWithAssumptions(Collection<BooleanFormula> assumptions)
156147
Preconditions.checkState(!closed);
157148
wasLastSatCheckSat = false;
158149

159-
// Extract Terms from the assumptions
160-
Vector_Term newAssumptions = new Vector_Term();
150+
Collection<Term> newAssumptions = new LinkedHashSet<>();
161151
for (BooleanFormula formula : assumptions) {
162-
BitwuzlaBooleanFormula bitwuzlaFormula = (BitwuzlaBooleanFormula) formula;
163-
newAssumptions.add(bitwuzlaFormula.getTerm());
152+
Term term = creator.extractInfo(formula);
153+
newAssumptions.add(term);
154+
newAssumptions.addAll(creator.getConstraintsForTerm(term));
164155
}
165156

166-
// Collect side condition for any casts and add them to the assumptions
167-
Iterable<Term> allAsserted =
168-
FluentIterable.concat(newAssumptions, creator.getVariableCasts(newAssumptions));
169-
170-
final Result result = env.check_sat(new Vector_Term(allAsserted));
157+
final Result result = env.check_sat(new Vector_Term(newAssumptions));
171158
return readSATResult(result);
172159
}
173160

0 commit comments

Comments
 (0)