99package org .sosy_lab .java_smt .solvers .bitwuzla ;
1010
1111import static com .google .common .base .Preconditions .checkArgument ;
12+ import static org .sosy_lab .common .collect .Collections3 .transformedImmutableSetCopy ;
1213
1314import com .google .common .base .Preconditions ;
1415import com .google .common .collect .HashBasedTable ;
1516import 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 ;
1917import com .google .common .collect .Table ;
2018import java .math .BigInteger ;
19+ import java .util .ArrayDeque ;
2120import java .util .ArrayList ;
21+ import java .util .Collection ;
22+ import java .util .Deque ;
2223import java .util .HashMap ;
2324import java .util .Iterator ;
25+ import java .util .LinkedHashSet ;
2426import java .util .List ;
2527import java .util .Map ;
2628import 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}
0 commit comments