Skip to content

Commit e5a22b2

Browse files
Bitwuzla: Add documentation for getVariableCasts() and the side-conditions in variableCasts
1 parent 43905a8 commit e5a22b2

File tree

1 file changed

+47
-26
lines changed

1 file changed

+47
-26
lines changed

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

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,19 @@ public class BitwuzlaFormulaCreator extends FormulaCreator<Term, Sort, Void, Bit
5959

6060
private final Table<String, Sort, Term> formulaCache = HashBasedTable.create();
6161

62+
/**
63+
* Maps symbols from fp-to-bv casts to their defining equation.
64+
*
65+
* <p>Bitwuzla does not support casts from floating-point to bitvector natively. The reason given
66+
* is that the value is undefined for NaN and that the SMT-LIB standard also does not include such
67+
* an operation. We try to work around this limitation by introducing a fresh variable <code>
68+
* __CAST_FROM_BV_XXX</code>for the result and then adding the constraint <code>
69+
* fp.to_fp(__CAST_FROM_BV_XXX) = &lt;float-term&gt;</code> as a side-condition. This is also what
70+
* is recommended by the SMT-LIB2 standard. The map <code>variableCasts</code> is used to store
71+
* these side-conditions so that they can later be added as assertions. The keys of the map are
72+
* the newly introduced variable symbols and the values are the defining equations as mentioned
73+
* above.
74+
*/
6275
private final Map<String, Term> variableCasts = new HashMap<>();
6376

6477
protected BitwuzlaFormulaCreator(TermManager pTermManager) {
@@ -576,42 +589,50 @@ public Object convertValue(Term term) {
576589
throw new AssertionError("Unknown value type.");
577590
}
578591

592+
/** Add a side-condition from a fp-to-bv to the set. */
579593
public void addVariableCast(String newVariable, Term equal) {
580594
variableCasts.put(newVariable, equal);
581595
}
582596

583-
private Map<String, Set<String>> calculateTransitions(Map<String, Term> pVariableCasts) {
584-
return Maps.transformValues(
585-
pVariableCasts,
586-
term ->
587-
Sets.intersection(
588-
pVariableCasts.keySet(), extractVariablesAndUFs(term, false).keySet()));
589-
}
590-
591-
private Set<String> initialSet(Iterable<Term> pTerms) {
592-
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
597+
/**
598+
* Returns a set of side-conditions that are needed to handle the variable casts in the terms.
599+
*
600+
* <p>Bitwuzla does not support fp-to-bv conversion natively. We have to use side-conditions as a
601+
* workaround. When a term containing fp-to-bv casts is added to the assertion stack these
602+
* side-conditions need to be collected by calling this method and then also adding them to the
603+
* assertion stack.
604+
*/
605+
public Iterable<Term> getVariableCasts(Iterable<Term> pTerms) {
606+
// Build the transition function from the side-conditions. We map the variables on the left
607+
// side of the defining equation to the set of variables on the right side.
608+
// f.ex __CAST_TO_BV_0 -> fp.to_fp(CAST_TO_BV_0) = (+ a b)
609+
// becomes
610+
// Map.of(__CAST_TO_BV, Set.of(__CAST_TO_BV, a b))
611+
Map<String, Set<String>> transitions =
612+
Maps.transformValues(
613+
variableCasts,
614+
term ->
615+
Sets.intersection(
616+
variableCasts.keySet(), extractVariablesAndUFs(term, false).keySet()));
617+
618+
// Calculate the initial set of symbols from the terms in the argument
619+
ImmutableSet.Builder<String> initBuilder = ImmutableSet.builder();
593620
for (Term term : pTerms) {
594-
builder.addAll(extractVariablesAndUFs(term, false).keySet());
595-
}
596-
return builder.build();
597-
}
598-
599-
private Set<String> takeAStep(Map<String, Set<String>> pTransitions, Set<String> pVariables) {
600-
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
601-
for (String var : pVariables) {
602-
builder.addAll(pTransitions.get(var));
621+
initBuilder.addAll(extractVariablesAndUFs(term, false).keySet());
603622
}
604-
return builder.build();
605-
}
606-
607-
public Iterable<Term> getVariableCasts(Iterable<Term> pTerms) {
608-
Map<String, Set<String>> transitions = calculateTransitions(variableCasts);
623+
ImmutableSet<String> initialSet = initBuilder.build();
609624

610625
Set<String> r0 = ImmutableSet.of();
611-
Set<String> r1 = Sets.intersection(initialSet(pTerms), transitions.keySet());
626+
Set<String> r1 = Sets.intersection(initialSet, transitions.keySet());
627+
// Calculate the fixpoint for the transition function
612628
while (!r0.equals(r1)) {
613629
r0 = r1;
614-
r1 = takeAStep(transitions, r0);
630+
// Iterate the transition function
631+
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
632+
for (String var : r0) {
633+
builder.addAll(transitions.get(var));
634+
}
635+
r1 = builder.build();
615636
}
616637

617638
return Maps.filterKeys(variableCasts, r0::contains).values();

0 commit comments

Comments
 (0)