-
Notifications
You must be signed in to change notification settings - Fork 56
Add IEEE-754 Floating Point to Bitvector Conversion Fallback #512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 41 commits
6a91ebf
5c86496
06e365f
d00e534
bc5a5e3
6e6ec7e
f584f6b
9df8f21
105e7f2
4ec7107
97c1fe4
fdaabcc
3ecd133
52dbeb5
353b12c
6c554d0
9603aa6
1f09a65
43ee2a0
a27cc7e
de90781
b652b7f
11926f1
17227ac
31ffd68
3cc3a99
cd3a9c1
2fbe5bd
b789362
2fc661c
7b2b1de
dbacf94
2d27890
15efd20
ba26c93
9c72a5b
85a5b4e
edf028d
567e120
87a90df
6fa0b35
68aa184
de440e1
8973957
bfe56ac
aae26af
95bd69b
638472c
faca8c9
8f3a60e
7b2b45b
ddfac9d
2fc367e
275802e
e5e0c81
10df745
9a27db3
1b6a671
24230d9
76ffa33
41c0784
f805aeb
a824dac
2ada968
2f98439
9e0eee4
f7ac283
1b227a2
9f63898
72ad0e3
1a5e5dc
86c4ab8
914d367
dba1560
31d23af
45e6c92
e424dfd
9230799
a9a111f
6b97afc
37d5fce
955c029
ddc38ce
2405704
a669c12
5501179
81a928c
4ffac52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,9 +13,11 @@ | |
|
|
||
| import java.math.BigDecimal; | ||
| import java.math.BigInteger; | ||
| import java.util.Map; | ||
| import org.sosy_lab.common.rationals.Rational; | ||
| import org.sosy_lab.java_smt.api.FloatingPointNumber.Sign; | ||
| import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; | ||
| import org.sosy_lab.java_smt.basicimpl.AbstractFloatingPointFormulaManager.BitvectorFormulaAndBooleanFormula; | ||
|
|
||
| /** | ||
| * Floating point operations. | ||
|
|
@@ -305,6 +307,71 @@ FloatingPointFormula castFrom( | |
| */ | ||
| BitvectorFormula toIeeeBitvector(FloatingPointFormula number); | ||
|
|
||
| /** | ||
| * Create a formula that produces a representation of the given floating-point value as a | ||
| * bitvector conforming to the IEEE 754-2008 format. The size of the resulting bitvector is the | ||
| * sum of the sizes of the exponent and mantissa of the input formula plus 1 (for the sign bit). | ||
| * This implementation can be used independently of {@link | ||
| * #toIeeeBitvector(FloatingPointFormula)}, as it does not rely on an SMT solvers support for | ||
| * {@link #toIeeeBitvector(FloatingPointFormula)}. Behavior for special FP values (NaN, Inf, etc.) | ||
| * is not defined, and returned values are solver dependent. In case you want to define how to | ||
| * handle those values, please use {@link #toIeeeBitvector(FloatingPointFormula, String, Map)}. | ||
| * This method is based on a suggestion in the SMTLib2 standard (<a | ||
| * href="https://smt-lib.org/theories-FloatingPoint.shtml">source</a>) implementation: | ||
| * | ||
| * <p>(declare-fun b () (_ BitVec m)) | ||
| * | ||
| * <p>(assert (= ((_ to_fp eb sb) b) f)) | ||
| * | ||
| * <p>Note: SMTLIB2 output of this method uses the SMTLIB2 keyword 'to_fp' as described above and | ||
| * no keyword variation for floating-point to bitvector conversion like 'fp.as_ieee_bv'. | ||
| * | ||
| * @param number the {@link FloatingPointFormula} to be converted into an IEEE bitvector. | ||
| * @param bitvectorConstantName the name of the returned {@link BitvectorFormula}. | ||
|
PhilippWendler marked this conversation as resolved.
Outdated
|
||
| * @return {@link BitvectorFormulaAndBooleanFormula} consisting of the transformed input | ||
| * floating-point as a {@link BitvectorFormula} and the additional constraint as {@link | ||
| * BooleanFormula}. | ||
| */ | ||
| BitvectorFormulaAndBooleanFormula toIeeeBitvector( | ||
| FloatingPointFormula number, String bitvectorConstantName); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Overloading methods can be confusing and error prone, and should be used only in cases where the semantics are clear and it is obvious what the differences are from the differing parameters. But here this is clearly not the case. We have an operation (converting from float to bv) that has the obvious signature So I recommend to reconsider the choice for an overload here and suggest renaming the new methods such that their names explain what they do.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason i named it like this is that this is how the SMTLIB2 standard actually recommends this operation to be implemented. It performs the same operation as The main advantage is that users familiar with Note: i now removed the 2
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just noticed the following: It seems one can use the currently proposed method symmetrically, both for converting from a float to a bitvector and vice versa. After all it creates only an equality between a bv and a float, so I could use it to create an equality between a bitvector constant and a nondet float variable, right? That would mean that the name Then the method should also be referenced in the JavaDoc of the current inverse of Btw.: Are there tests for something like I mentioned above? |
||
|
|
||
| /** | ||
| * Create a formula that produces a representation of the given floating-point value as a | ||
| * bitvector conforming to the IEEE 754-2008 format. The size of the resulting bitvector is the | ||
| * sum of the sizes of the exponent and mantissa of the input formula plus 1 (for the sign bit). | ||
| * This implementation can be used independently of {@link | ||
| * #toIeeeBitvector(FloatingPointFormula)}, as it does not rely on an SMT solvers support for | ||
| * {@link #toIeeeBitvector(FloatingPointFormula)}. Behavior for special FP values (NaN, Inf, etc.) | ||
| * can be defined using the specialFPConstantHandling parameter. This method is based on a | ||
| * suggestion in the SMTLib2 standard (<a | ||
| * href="https://smt-lib.org/theories-FloatingPoint.shtml">source</a>) implementation: | ||
| * | ||
| * <p>(declare-fun b () (_ BitVec m)) | ||
| * | ||
| * <p>(assert (= ((_ to_fp eb sb) b) f)) | ||
| * | ||
| * <p>Note: SMTLIB2 output of this method uses the SMTLIB2 keyword 'to_fp' as described above and | ||
| * no keyword variation for floating-point to bitvector conversion like 'fp.as_ieee_bv'. | ||
| * | ||
| * @param number the {@link FloatingPointFormula} to be converted into an IEEE bitvector. | ||
| * @param bitvectorConstantName the name of the returned {@link BitvectorFormula}. | ||
| * @param specialFPConstantHandling a {@link Map} defining the returned {@link BitvectorFormula} | ||
| * for special {@link FloatingPointFormula} constant numbers. You are only allowed to specify | ||
| * a mapping for special FP numbers with more than one well-defined bitvector representation, | ||
| * i.e. NaN and +/- Infinity. The width of the mapped bitvector values has to match the | ||
|
PhilippWendler marked this conversation as resolved.
Outdated
|
||
| * expected width of the bitvector return value. The {@link FloatingPointType}, i.e. | ||
| * precision, of the key FP numbers has to match the {@link FloatingPointType} of the | ||
| * parameter {@code number}. For an empty {@link Map}, or missing mappings, this method | ||
| * behaves like {@link #toIeeeBitvector(FloatingPointFormula, String)}. | ||
| * @return {@link BitvectorFormulaAndBooleanFormula} consisting of the transformed input | ||
| * floating-point as a {@link BitvectorFormula} and the additional constraint as {@link | ||
| * BooleanFormula}. | ||
| */ | ||
| BitvectorFormulaAndBooleanFormula toIeeeBitvector( | ||
| FloatingPointFormula number, | ||
| String bitvectorConstantName, | ||
| Map<FloatingPointFormula, BitvectorFormula> specialFPConstantHandling); | ||
|
|
||
| FloatingPointFormula round(FloatingPointFormula formula, FloatingPointRoundingMode roundingMode); | ||
|
|
||
| // ----------------- Arithmetic relations, return type NumeralFormula ----------------- | ||
|
|
@@ -482,4 +549,13 @@ FloatingPointFormula multiply( | |
| * </ul> | ||
| */ | ||
| BooleanFormula isNegative(FloatingPointFormula number); | ||
|
|
||
| /** | ||
| * Returns the size of the mantissa (also called a coefficient or significant), including the sign | ||
| * bit, for the given {@link FloatingPointFormula}. | ||
| */ | ||
| int getMantissaSizeWithSignBit(FloatingPointFormula number); | ||
|
|
||
| /** Returns the size of the exponent for the given {@link FloatingPointFormula}. */ | ||
| int getExponentSize(FloatingPointFormula number); | ||
|
kfriedberger marked this conversation as resolved.
Outdated
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,13 +8,19 @@ | |
|
|
||
| package org.sosy_lab.java_smt.basicimpl; | ||
|
|
||
| import static com.google.common.base.Preconditions.checkArgument; | ||
| import static com.google.common.base.Preconditions.checkNotNull; | ||
| import static org.sosy_lab.java_smt.api.FormulaType.getFloatingPointTypeFromSizesWithoutHiddenBit; | ||
| import static org.sosy_lab.java_smt.basicimpl.AbstractFormulaManager.checkVariableName; | ||
|
|
||
| import com.google.common.base.Preconditions; | ||
| import com.google.common.collect.ImmutableMap; | ||
| import com.google.common.collect.ImmutableSet; | ||
| import java.math.BigDecimal; | ||
| import java.math.BigInteger; | ||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import java.util.Map.Entry; | ||
| import java.util.Set; | ||
| import org.sosy_lab.common.MoreStrings; | ||
| import org.sosy_lab.common.rationals.Rational; | ||
| import org.sosy_lab.java_smt.api.BitvectorFormula; | ||
|
|
@@ -48,10 +54,18 @@ public abstract class AbstractFloatingPointFormulaManager<TFormulaInfo, TType, T | |
|
|
||
| private final Map<FloatingPointRoundingMode, TFormulaInfo> roundingModes; | ||
|
|
||
| private final AbstractBitvectorFormulaManager<TFormulaInfo, TType, TEnv, TFuncDecl> bvMgr; | ||
|
|
||
| private final AbstractBooleanFormulaManager<TFormulaInfo, TType, TEnv, TFuncDecl> bMgr; | ||
|
|
||
| protected AbstractFloatingPointFormulaManager( | ||
| FormulaCreator<TFormulaInfo, TType, TEnv, TFuncDecl> pCreator) { | ||
| FormulaCreator<TFormulaInfo, TType, TEnv, TFuncDecl> pCreator, | ||
| AbstractBitvectorFormulaManager<TFormulaInfo, TType, TEnv, TFuncDecl> pBvMgr, | ||
| AbstractBooleanFormulaManager<TFormulaInfo, TType, TEnv, TFuncDecl> pBMgr) { | ||
| super(pCreator); | ||
| roundingModes = new HashMap<>(); | ||
| bvMgr = pBvMgr; | ||
| bMgr = pBMgr; | ||
| } | ||
|
|
||
| protected abstract TFormulaInfo getDefaultRoundingMode(); | ||
|
|
@@ -160,7 +174,7 @@ protected abstract TFormulaInfo makeNumberImpl( | |
| BigInteger exponent, BigInteger mantissa, Sign sign, FloatingPointType type); | ||
|
|
||
| protected static boolean isNegativeZero(Double pN) { | ||
| Preconditions.checkNotNull(pN); | ||
| checkNotNull(pN); | ||
| return Double.valueOf("-0.0").equals(pN); | ||
| } | ||
|
|
||
|
|
@@ -261,7 +275,7 @@ protected abstract TFormulaInfo castFromImpl( | |
| public FloatingPointFormula fromIeeeBitvector( | ||
| BitvectorFormula pNumber, FloatingPointType pTargetType) { | ||
| BitvectorType bvType = (BitvectorType) formulaCreator.getFormulaType(pNumber); | ||
| Preconditions.checkArgument( | ||
| checkArgument( | ||
| bvType.getSize() == pTargetType.getTotalSize(), | ||
| MoreStrings.lazyString( | ||
| () -> | ||
|
|
@@ -279,7 +293,99 @@ public BitvectorFormula toIeeeBitvector(FloatingPointFormula pNumber) { | |
| return getFormulaCreator().encapsulateBitvector(toIeeeBitvectorImpl(extractInfo(pNumber))); | ||
| } | ||
|
|
||
| protected abstract TFormulaInfo toIeeeBitvectorImpl(TFormulaInfo pNumber); | ||
| @SuppressWarnings("unused") | ||
| protected TFormulaInfo toIeeeBitvectorImpl(TFormulaInfo pNumber) { | ||
| throw new UnsupportedOperationException( | ||
| "The chosen solver does not support transforming " | ||
| + "FloatingPointFormula to IEEE bitvectors. Try using the fallback " | ||
| + "methods toIeeeBitvector" | ||
| + "(FloatingPointFormula, String) and/or " | ||
| + "toIeeeBitvector(FloatingPointFormula, String, Map)"); | ||
| } | ||
|
kfriedberger marked this conversation as resolved.
|
||
|
|
||
| @Override | ||
| public BitvectorFormulaAndBooleanFormula toIeeeBitvector( | ||
| FloatingPointFormula f, String bitvectorConstantName) { | ||
| return toIeeeBitvector(f, bitvectorConstantName, ImmutableMap.of()); | ||
| } | ||
|
|
||
| @Override | ||
| public BitvectorFormulaAndBooleanFormula toIeeeBitvector( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method is weird. Does is really handle NaN as expected?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SMTLIB2 does not define a default NaN beyond its representation in SMTLIB2. But it warns that there are multiple possible binary representations. It states that: Hence i thought it might be beneficial to have 2 methods; one that handles NaN simply the way the solver handles it, the other in such a way that you can configure it (and other special values, as infinity suffers from a similar problem as NaN). If a user decides to use a distinct encoding of NaN that is not used by the solver per default, it is possible with this method. However, we can easily make the argument that every user can wrap the Do you think we should just remove the marked method and add some info in the JavaDoc?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: i replaced the 2 methods with a single one taking only a FP and a BV formula. The behavior is the same as in this method. |
||
| FloatingPointFormula f, | ||
| String bitvectorConstantName, | ||
| Map<FloatingPointFormula, BitvectorFormula> specialFPConstantHandling) { | ||
|
|
||
| FormulaType.FloatingPointType fpType = | ||
| (FloatingPointType) getFormulaCreator().getFormulaType(f); | ||
| // The BV is sign bit + exponent + mantissa without hidden bit | ||
| int mantissaSizeWithoutHiddenBit = fpType.getMantissaSizeWithoutHiddenBit(); | ||
| int exponentSize = fpType.getExponentSize(); | ||
| BitvectorFormula bvFormula = | ||
| bvMgr.makeVariable(1 + exponentSize + mantissaSizeWithoutHiddenBit, bitvectorConstantName); | ||
|
PhilippWendler marked this conversation as resolved.
Outdated
|
||
|
|
||
| // When building new Fp types, we don't include the sign bit | ||
| FloatingPointFormula fromIeeeBitvector = | ||
| fromIeeeBitvector( | ||
| bvFormula, | ||
| getFloatingPointTypeFromSizesWithoutHiddenBit( | ||
| exponentSize, mantissaSizeWithoutHiddenBit)); | ||
|
PhilippWendler marked this conversation as resolved.
Outdated
|
||
|
|
||
| // assignment() allows a value to be NaN etc. | ||
| // Note: All fp.to_* functions are unspecified for NaN and infinity input values in the | ||
| // standard, what solvers return might be distinct. | ||
| BooleanFormula additionalConstraint = assignment(fromIeeeBitvector, f); | ||
|
|
||
| // Build special numbers so that we can compare them in the map | ||
| FloatingPointType precision = | ||
| getFloatingPointTypeFromSizesWithoutHiddenBit(exponentSize, mantissaSizeWithoutHiddenBit); | ||
|
PhilippWendler marked this conversation as resolved.
Outdated
|
||
| Set<FloatingPointFormula> specialNumbers = | ||
| ImmutableSet.of( | ||
| makeNaN(precision), makePlusInfinity(precision), makeMinusInfinity(precision)); | ||
|
|
||
| BitvectorFormula toIeeeBv = bvFormula; | ||
| for (Entry<FloatingPointFormula, BitvectorFormula> entry : | ||
| specialFPConstantHandling.entrySet()) { | ||
| FloatingPointFormula fpConst = entry.getKey(); | ||
|
|
||
| // We check that FP const special numbers are used (info from SMTLib2-standard) | ||
| // NaN has multiple possible definitions. | ||
| // +/- Infinity each has 2; e.g., +infinity for sort (_ FloatingPoint 2 3) is represented | ||
| // equivalently by (_ +oo 2 3) and (fp #b0 #b11 #b00). | ||
| // -0 only has one representation; i.e. (_ -zero 3 2) abbreviates (fp #b1 #b000 #b0), and | ||
| // is therefore disallowed. | ||
| // This automatically checks the correct precision as well! | ||
| checkArgument( | ||
| specialNumbers.contains(fpConst), | ||
| "You are only allowed to specify a mapping for special FP numbers with more than one" | ||
| + " well-defined bitvector representation, i.e. NaN and +/- Infinity. Their precision" | ||
| + " has to match the precision of the formula to be represented as bitvector."); | ||
|
|
||
| BitvectorFormula bvTerm = entry.getValue(); | ||
| checkArgument( | ||
| bvMgr.getLength(bvTerm) == bvMgr.getLength(bvFormula), | ||
| "The size of the bitvector terms used as mapped values needs to be equal to the size of" | ||
| + " the bitvector returned by this method"); | ||
|
|
||
| BooleanFormula assumption = assignment(fpConst, f); | ||
| toIeeeBv = bMgr.ifThenElse(assumption, bvTerm, toIeeeBv); | ||
| } | ||
|
|
||
| return BitvectorFormulaAndBooleanFormula.of(toIeeeBv, additionalConstraint); | ||
| } | ||
|
|
||
| @Override | ||
| public int getMantissaSizeWithSignBit(FloatingPointFormula f) { | ||
| return getMantissaSizeWithSignBitImpl(extractInfo(f)); | ||
| } | ||
|
|
||
| protected abstract int getMantissaSizeWithSignBitImpl(TFormulaInfo f); | ||
|
|
||
| @Override | ||
| public int getExponentSize(FloatingPointFormula f) { | ||
| return getExponentSizeImpl(extractInfo(f)); | ||
| } | ||
|
|
||
| protected abstract int getExponentSizeImpl(TFormulaInfo f); | ||
|
|
||
| @Override | ||
| public FloatingPointFormula negate(FloatingPointFormula pNumber) { | ||
|
|
@@ -542,4 +648,28 @@ protected static String getBvRepresentation(BigInteger integer, int size) { | |
| } | ||
| return String.copyValueOf(values); | ||
| } | ||
|
|
||
| public static final class BitvectorFormulaAndBooleanFormula { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not just use a Google-Auto-class? In the future this might be a record.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is clearly a record once we update. I didn't think about auto-classes while writing. But i would prefer to switch to records once we update. (Which is 100% personal preference. I don't mind if we go with auto-classes.)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to make this a record in the future, you should already now design the (non-private parts of the) API such that making it a record will be compatible.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The class has been removed. |
||
| private final BitvectorFormula bitvectorFormula; | ||
| private final BooleanFormula booleanFormula; | ||
|
|
||
| private BitvectorFormulaAndBooleanFormula( | ||
| BitvectorFormula pBitvectorFormula, BooleanFormula pBooleanFormula) { | ||
| bitvectorFormula = checkNotNull(pBitvectorFormula); | ||
| booleanFormula = checkNotNull(pBooleanFormula); | ||
| } | ||
|
|
||
| private static BitvectorFormulaAndBooleanFormula of( | ||
|
PhilippWendler marked this conversation as resolved.
Outdated
|
||
| BitvectorFormula pBitvectorFormula, BooleanFormula pBooleanFormula) { | ||
| return new BitvectorFormulaAndBooleanFormula(pBitvectorFormula, pBooleanFormula); | ||
| } | ||
|
|
||
| public BitvectorFormula getBitvectorFormula() { | ||
| return bitvectorFormula; | ||
| } | ||
|
|
||
| public BooleanFormula getBooleanFormula() { | ||
| return booleanFormula; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -412,7 +412,23 @@ private String sanitize(String formulaStr) { | |
|
|
||
| @Override | ||
| public BooleanFormula parse(String formulaStr) throws IllegalArgumentException { | ||
| return formulaCreator.encapsulateBoolean(parseImpl(sanitize(formulaStr))); | ||
| try { | ||
| return formulaCreator.encapsulateBoolean(parseImpl(sanitize(formulaStr))); | ||
| } catch (IllegalArgumentException illegalArgumentException) { | ||
| if (illegalArgumentException.getMessage().contains("fp.as_ieee_bv")) { | ||
| String additionalMessage = | ||
| "; Note: operation 'fp.as_ieee_bv' is not supported in most SMT solvers. Instead, try" | ||
| + " utilizing the SMTLIB2 keyword 'to_fp' which is supported in most SMT solvers" | ||
| + " with Bitvector and Floating-Point support. In case the SMTLIB2 output has been" | ||
| + " created using JavaSMT, try replacing the FloatingPointFormulaManager method" | ||
| + " toIeeeBitvector(FloatingPointFormula), with either" | ||
| + " toIeeeBitvector(FloatingPointFormula, String) or" | ||
| + " toIeeeBitvector(FloatingPointFormula, String, Map)."; | ||
| throw new IllegalArgumentException( | ||
| illegalArgumentException.getMessage() + additionalMessage, illegalArgumentException); | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 4x getMessage --> maybe use a variable for that.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done! Thanks for noticing! I also extracted it into a method and moved the call due to how parsing was changed in |
||
| throw illegalArgumentException; | ||
| } | ||
| } | ||
|
|
||
| protected abstract String dumpFormulaImpl(TFormulaInfo t) throws IOException; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.