@@ -59,6 +59,19 @@ public class BitwuzlaFormulaCreator extends FormulaCreator<Term, Sort, Void, Bit
59
59
60
60
private final Table <String , Sort , Term > formulaCache = HashBasedTable .create ();
61
61
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) = <float-term></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
+ */
62
75
private final Map <String , Term > variableCasts = new HashMap <>();
63
76
64
77
protected BitwuzlaFormulaCreator (TermManager pTermManager ) {
@@ -576,42 +589,50 @@ public Object convertValue(Term term) {
576
589
throw new AssertionError ("Unknown value type." );
577
590
}
578
591
592
+ /** Add a side-condition from a fp-to-bv to the set. */
579
593
public void addVariableCast (String newVariable , Term equal ) {
580
594
variableCasts .put (newVariable , equal );
581
595
}
582
596
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 ();
593
620
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 ());
603
622
}
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 ();
609
624
610
625
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
612
628
while (!r0 .equals (r1 )) {
613
629
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 ();
615
636
}
616
637
617
638
return Maps .filterKeys (variableCasts , r0 ::contains ).values ();
0 commit comments