diff --git a/src/org/sosy_lab/java_smt/api/FloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/api/FloatingPointFormulaManager.java index 62bb3afbe4..5820a8593e 100644 --- a/src/org/sosy_lab/java_smt/api/FloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/api/FloatingPointFormulaManager.java @@ -34,6 +34,9 @@ */ public interface FloatingPointFormulaManager { + /** Creates a formula for the given floating point rounding mode. */ + FloatingPointRoundingModeFormula makeRoundingMode(FloatingPointRoundingMode pRoundingMode); + /** * Creates a floating point formula representing the given double value with the specified type. */ diff --git a/src/org/sosy_lab/java_smt/api/FloatingPointRoundingModeFormula.java b/src/org/sosy_lab/java_smt/api/FloatingPointRoundingModeFormula.java index ead8fc04af..b9fb69fd73 100644 --- a/src/org/sosy_lab/java_smt/api/FloatingPointRoundingModeFormula.java +++ b/src/org/sosy_lab/java_smt/api/FloatingPointRoundingModeFormula.java @@ -11,8 +11,11 @@ import com.google.errorprone.annotations.Immutable; /** - * Formula representing a rounding mode for floating-point operations. This is currently unused by - * the API but necessary for traversal of formulas with such terms. + * Formula representing a rounding mode for floating-point operations. + * + *

Rounding mode formulas are used by floating-point formulas to select the rounding mode for the + * operation. Use {@link FloatingPointFormulaManager#makeRoundingMode(FloatingPointRoundingMode)} to + * wrap a {@link org.sosy_lab.java_smt.api.FloatingPointRoundingMode} value inside a new formula. */ @Immutable public interface FloatingPointRoundingModeFormula extends Formula {} diff --git a/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java b/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java index a203fa1f2d..bb8a3929ba 100644 --- a/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java +++ b/src/org/sosy_lab/java_smt/api/FunctionDeclarationKind.java @@ -252,21 +252,6 @@ public enum FunctionDeclarationKind { /** Equal over floating points. */ FP_EQ, - /** Rounding over floating points. */ - FP_ROUND_EVEN, - - /** Rounding over floating points. */ - FP_ROUND_AWAY, - - /** Rounding over floating points. */ - FP_ROUND_POSITIVE, - - /** Rounding over floating points. */ - FP_ROUND_NEGATIVE, - - /** Rounding over floating points. */ - FP_ROUND_ZERO, - /** Rounding over floating points. */ FP_ROUND_TO_INTEGRAL, diff --git a/src/org/sosy_lab/java_smt/basicimpl/AbstractFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/basicimpl/AbstractFloatingPointFormulaManager.java index 47c847afe2..a653948bb3 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/AbstractFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/basicimpl/AbstractFloatingPointFormulaManager.java @@ -22,6 +22,7 @@ import org.sosy_lab.java_smt.api.FloatingPointFormulaManager; import org.sosy_lab.java_smt.api.FloatingPointNumber.Sign; import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; @@ -60,6 +61,12 @@ private TFormulaInfo getRoundingMode(FloatingPointRoundingMode pFloatingPointRou return roundingModes.computeIfAbsent(pFloatingPointRoundingMode, this::getRoundingModeImpl); } + @Override + public FloatingPointRoundingModeFormula makeRoundingMode( + FloatingPointRoundingMode pRoundingMode) { + return getFormulaCreator().encapsulateRoundingMode(getRoundingMode(pRoundingMode)); + } + protected FloatingPointFormula wrap(TFormulaInfo pTerm) { return getFormulaCreator().encapsulateFloatingPoint(pTerm); } diff --git a/src/org/sosy_lab/java_smt/basicimpl/FormulaCreator.java b/src/org/sosy_lab/java_smt/basicimpl/FormulaCreator.java index 748fdd7b3b..cf383fde5a 100644 --- a/src/org/sosy_lab/java_smt/basicimpl/FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/basicimpl/FormulaCreator.java @@ -160,6 +160,14 @@ protected FloatingPointFormula encapsulateFloatingPoint(TFormulaInfo pTerm) { return new FloatingPointFormulaImpl<>(pTerm); } + protected FloatingPointRoundingModeFormula encapsulateRoundingMode(TFormulaInfo pTerm) { + checkArgument( + getFormulaType(pTerm).isFloatingPointRoundingModeType(), + "Floatingpoint rounding mode formula has unexpected type: %s", + getFormulaType(pTerm)); + return new FloatingPointRoundingModeFormulaImpl<>(pTerm); + } + protected ArrayFormula encapsulateArray( TFormulaInfo pTerm, FormulaType pIndexType, FormulaType pElementType) { checkArgument( diff --git a/src/org/sosy_lab/java_smt/delegate/debugging/DebuggingFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/debugging/DebuggingFloatingPointFormulaManager.java index 74b1677375..817fb05ff1 100644 --- a/src/org/sosy_lab/java_smt/delegate/debugging/DebuggingFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/debugging/DebuggingFloatingPointFormulaManager.java @@ -17,6 +17,7 @@ import org.sosy_lab.java_smt.api.FloatingPointFormulaManager; import org.sosy_lab.java_smt.api.FloatingPointNumber.Sign; import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; @@ -31,6 +32,15 @@ public class DebuggingFloatingPointFormulaManager implements FloatingPointFormul debugging = pDebugging; } + @Override + public FloatingPointRoundingModeFormula makeRoundingMode( + FloatingPointRoundingMode pRoundingMode) { + debugging.assertThreadLocal(); + FloatingPointRoundingModeFormula result = delegate.makeRoundingMode(pRoundingMode); + debugging.addFormulaTerm(result); + return result; + } + @Override public FloatingPointFormula makeNumber(double n, FloatingPointType type) { debugging.assertThreadLocal(); diff --git a/src/org/sosy_lab/java_smt/delegate/statistics/StatisticsFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/statistics/StatisticsFloatingPointFormulaManager.java index 415b7cb00f..f1669369c8 100644 --- a/src/org/sosy_lab/java_smt/delegate/statistics/StatisticsFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/statistics/StatisticsFloatingPointFormulaManager.java @@ -19,6 +19,7 @@ import org.sosy_lab.java_smt.api.FloatingPointFormulaManager; import org.sosy_lab.java_smt.api.FloatingPointNumber.Sign; import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; @@ -34,6 +35,13 @@ class StatisticsFloatingPointFormulaManager implements FloatingPointFormulaManag stats = checkNotNull(pStats); } + @Override + public FloatingPointRoundingModeFormula makeRoundingMode( + FloatingPointRoundingMode pRoundingMode) { + stats.fpOperations.getAndIncrement(); + return delegate.makeRoundingMode(pRoundingMode); + } + @Override public FloatingPointFormula makeNumber(double pN, FloatingPointType pType) { stats.fpOperations.getAndIncrement(); diff --git a/src/org/sosy_lab/java_smt/delegate/synchronize/SynchronizedFloatingPointFormulaManager.java b/src/org/sosy_lab/java_smt/delegate/synchronize/SynchronizedFloatingPointFormulaManager.java index 3d922f71a8..f0e1049c75 100644 --- a/src/org/sosy_lab/java_smt/delegate/synchronize/SynchronizedFloatingPointFormulaManager.java +++ b/src/org/sosy_lab/java_smt/delegate/synchronize/SynchronizedFloatingPointFormulaManager.java @@ -19,6 +19,7 @@ import org.sosy_lab.java_smt.api.FloatingPointFormulaManager; import org.sosy_lab.java_smt.api.FloatingPointNumber.Sign; import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; @@ -35,6 +36,14 @@ class SynchronizedFloatingPointFormulaManager implements FloatingPointFormulaMan sync = checkNotNull(pSync); } + @Override + public FloatingPointRoundingModeFormula makeRoundingMode( + FloatingPointRoundingMode pRoundingMode) { + synchronized (sync) { + return delegate.makeRoundingMode(pRoundingMode); + } + } + @Override public FloatingPointFormula makeNumber(double pN, FloatingPointType pType) { synchronized (sync) { diff --git a/src/org/sosy_lab/java_smt/solvers/bitwuzla/BitwuzlaFormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/bitwuzla/BitwuzlaFormulaCreator.java index f946331319..f9fa6e30e7 100644 --- a/src/org/sosy_lab/java_smt/solvers/bitwuzla/BitwuzlaFormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/bitwuzla/BitwuzlaFormulaCreator.java @@ -33,6 +33,8 @@ import org.sosy_lab.java_smt.api.BooleanFormula; import org.sosy_lab.java_smt.api.FloatingPointFormula; import org.sosy_lab.java_smt.api.FloatingPointNumber; +import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType; @@ -131,6 +133,14 @@ assert getFormulaType(pTerm).isFloatingPointType() return new BitwuzlaFloatingPointFormula(pTerm); } + @Override + protected FloatingPointRoundingModeFormula encapsulateRoundingMode(Term pTerm) { + assert getFormulaType(pTerm).isFloatingPointRoundingModeType() + : String.format( + "%s is no FP rounding mode, but %s (%s)", pTerm, pTerm.sort(), getFormulaType(pTerm)); + return new BitwuzlaFloatingPointRoundingModeFormula(pTerm); + } + @Override @SuppressWarnings("MethodTypeParameterName") protected ArrayFormula encapsulateArray( @@ -584,7 +594,19 @@ public Object convertValue(Term term) { return term.to_bool(); } if (sort.is_rm()) { - return term.to_rm(); + if (term.is_rm_value_rna()) { + return FloatingPointRoundingMode.NEAREST_TIES_AWAY; + } else if (term.is_rm_value_rne()) { + return FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN; + } else if (term.is_rm_value_rtn()) { + return FloatingPointRoundingMode.TOWARD_NEGATIVE; + } else if (term.is_rm_value_rtp()) { + return FloatingPointRoundingMode.TOWARD_POSITIVE; + } else if (term.is_rm_value_rtz()) { + return FloatingPointRoundingMode.TOWARD_ZERO; + } else { + throw new IllegalArgumentException(String.format("Unknown rounding mode: %s", term)); + } } if (sort.is_bv()) { return new BigInteger(term.to_bv(), 2); diff --git a/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java index 23e7328956..875cce7bef 100644 --- a/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/cvc4/CVC4FormulaCreator.java @@ -26,6 +26,7 @@ import edu.stanford.CVC4.Integer; import edu.stanford.CVC4.Kind; import edu.stanford.CVC4.Rational; +import edu.stanford.CVC4.RoundingMode; import edu.stanford.CVC4.Type; import edu.stanford.CVC4.vectorExpr; import edu.stanford.CVC4.vectorType; @@ -41,6 +42,8 @@ import org.sosy_lab.java_smt.api.FloatingPointFormula; import org.sosy_lab.java_smt.api.FloatingPointNumber; import org.sosy_lab.java_smt.api.FloatingPointNumber.Sign; +import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType; @@ -264,6 +267,15 @@ assert getFormulaType(pTerm).isFloatingPointType() return new CVC4FloatingPointFormula(pTerm); } + @Override + protected FloatingPointRoundingModeFormula encapsulateRoundingMode(Expr pTerm) { + assert getFormulaType(pTerm).isFloatingPointRoundingModeType() + : String.format( + "%s is no FP rounding mode, but %s (%s)", + pTerm, pTerm.getType(), getFormulaType(pTerm)); + return new CVC4FloatingPointRoundingModeFormula(pTerm); + } + @Override @SuppressWarnings("MethodTypeParameterName") protected ArrayFormula encapsulateArray( @@ -323,8 +335,7 @@ public R visit(FormulaVisitor visitor, Formula formula, final Expr f) { } else if (type.isFloatingPoint()) { return visitor.visitConstant(formula, convertFloatingPoint(f)); } else if (type.isRoundingMode()) { - // TODO is this correct? - return visitor.visitConstant(formula, f.getConstRoundingMode()); + return visitor.visitConstant(formula, convertRoundingMode(f)); } else if (type.isString()) { return visitor.visitConstant(formula, f.getConstString()); } else if (type.isArray()) { @@ -613,6 +624,9 @@ public Object convertValue(Expr expForType, Expr value) { } else if (valueType.isFloatingPoint()) { return convertFloatingPoint(value); + } else if (valueType.isRoundingMode()) { + return convertRoundingMode(value); + } else if (valueType.isString()) { return unescapeUnicodeForSmtlib(value.getConstString().toString()); @@ -648,4 +662,21 @@ private FloatingPointNumber convertFloatingPoint(Expr fpExpr) { expWidth, mantWidth); } + + private FloatingPointRoundingMode convertRoundingMode(Expr pExpr) { + RoundingMode rm = pExpr.getConstRoundingMode(); + if (rm.equals(RoundingMode.roundNearestTiesToAway)) { + return FloatingPointRoundingMode.NEAREST_TIES_AWAY; + } else if (rm.equals(RoundingMode.roundNearestTiesToEven)) { + return FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN; + } else if (rm.equals(RoundingMode.roundTowardNegative)) { + return FloatingPointRoundingMode.TOWARD_NEGATIVE; + } else if (rm.equals(RoundingMode.roundTowardPositive)) { + return FloatingPointRoundingMode.TOWARD_POSITIVE; + } else if (rm.equals(RoundingMode.roundTowardZero)) { + return FloatingPointRoundingMode.TOWARD_ZERO; + } else { + throw new IllegalArgumentException(String.format("Unknown rounding mode: %s", pExpr)); + } + } } diff --git a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java index 946b6be069..f326da1590 100644 --- a/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/cvc5/CVC5FormulaCreator.java @@ -27,6 +27,7 @@ import io.github.cvc5.Kind; import io.github.cvc5.Op; import io.github.cvc5.Pair; +import io.github.cvc5.RoundingMode; import io.github.cvc5.Solver; import io.github.cvc5.Sort; import io.github.cvc5.Term; @@ -44,6 +45,8 @@ import org.sosy_lab.java_smt.api.EnumerationFormula; import org.sosy_lab.java_smt.api.FloatingPointFormula; import org.sosy_lab.java_smt.api.FloatingPointNumber; +import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType; @@ -315,6 +318,15 @@ assert getFormulaType(pTerm).isFloatingPointType() return new CVC5FloatingPointFormula(pTerm); } + @Override + protected FloatingPointRoundingModeFormula encapsulateRoundingMode(Term pTerm) { + assert getFormulaType(pTerm).isFloatingPointRoundingModeType() + : String.format( + "%s is no FP rounding mode, but %s (%s)", + pTerm, pTerm.getSort(), getFormulaType(pTerm)); + return new CVC5FloatingPointRoundingModeFormula(pTerm); + } + @Override @SuppressWarnings("MethodTypeParameterName") protected ArrayFormula encapsulateArray( @@ -399,7 +411,7 @@ public R visit(FormulaVisitor visitor, Formula formula, final Term f) { return visitor.visitConstant(formula, convertFloatingPoint(f)); } else if (f.isRoundingModeValue()) { - return visitor.visitConstant(formula, f.getRoundingModeValue()); + return visitor.visitConstant(formula, convertRoundingMode(f)); } else if (f.isConstArray()) { Term constant = f.getConstArrayBase(); @@ -816,6 +828,9 @@ public Object convertValue(Term expForType, Term value) { } else if (value.isFloatingPointValue()) { return convertFloatingPoint(value); + } else if (value.isRoundingModeValue()) { + return convertRoundingMode(value); + } else if (value.isBooleanValue()) { return value.getBooleanValue(); @@ -845,6 +860,23 @@ private FloatingPointNumber convertFloatingPoint(Term value) throws CVC5ApiExcep return FloatingPointNumber.of(bits, expWidth, mantWidth); } + private FloatingPointRoundingMode convertRoundingMode(Term pTerm) throws CVC5ApiException { + RoundingMode rm = pTerm.getRoundingModeValue(); + if (rm.equals(RoundingMode.ROUND_NEAREST_TIES_TO_AWAY)) { + return FloatingPointRoundingMode.NEAREST_TIES_AWAY; + } else if (rm.equals(RoundingMode.ROUND_NEAREST_TIES_TO_EVEN)) { + return FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN; + } else if (rm.equals(RoundingMode.ROUND_TOWARD_NEGATIVE)) { + return FloatingPointRoundingMode.TOWARD_NEGATIVE; + } else if (rm.equals(RoundingMode.ROUND_TOWARD_POSITIVE)) { + return FloatingPointRoundingMode.TOWARD_POSITIVE; + } else if (rm.equals(RoundingMode.ROUND_TOWARD_ZERO)) { + return FloatingPointRoundingMode.TOWARD_ZERO; + } else { + throw new IllegalArgumentException(String.format("Unknown rounding mode: %s", pTerm)); + } + } + private Term accessVariablesCache(String name, Sort sort) { Term existingVar = variablesCache.get(name, sort.toString()); Preconditions.checkNotNull( diff --git a/src/org/sosy_lab/java_smt/solvers/mathsat5/Mathsat5FormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/mathsat5/Mathsat5FormulaCreator.java index ff35694c4a..276cb236b8 100644 --- a/src/org/sosy_lab/java_smt/solvers/mathsat5/Mathsat5FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/mathsat5/Mathsat5FormulaCreator.java @@ -71,7 +71,6 @@ import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_OR; import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_PLUS; import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_TIMES; -import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_UNKNOWN; import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_decl_get_arg_type; import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_decl_get_name; import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_decl_get_tag; @@ -105,6 +104,10 @@ import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_get_type; import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_constant; import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_false; +import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_fp_roundingmode_minus_inf; +import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_fp_roundingmode_nearest_even; +import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_fp_roundingmode_plus_inf; +import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_fp_roundingmode_zero; import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_number; import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_true; import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_uf; @@ -127,6 +130,8 @@ import org.sosy_lab.java_smt.api.FloatingPointFormula; import org.sosy_lab.java_smt.api.FloatingPointNumber; import org.sosy_lab.java_smt.api.FloatingPointNumber.Sign; +import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType; @@ -291,6 +296,12 @@ protected FloatingPointFormula encapsulateFloatingPoint(Long pTerm) { return new Mathsat5FloatingPointFormula(pTerm); } + @Override + protected FloatingPointRoundingModeFormula encapsulateRoundingMode(Long pTerm) { + assert getFormulaType(pTerm).isFloatingPointRoundingModeType(); + return new Mathsat5FloatingPointRoundingModeFormula(pTerm); + } + @Override @SuppressWarnings("MethodTypeParameterName") protected ArrayFormula encapsulateArray( @@ -333,6 +344,19 @@ public R visit(FormulaVisitor visitor, Formula formula, final Long f) { return visitor.visitConstant(formula, true); } else if (msat_term_is_false(environment, f)) { return visitor.visitConstant(formula, false); + } else if (msat_is_fp_roundingmode_type(environment, msat_term_get_type(f))) { + if (msat_term_is_fp_roundingmode_nearest_even(environment, f)) { + return visitor.visitConstant(formula, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } else if (msat_term_is_fp_roundingmode_plus_inf(environment, f)) { + return visitor.visitConstant(formula, FloatingPointRoundingMode.TOWARD_POSITIVE); + } else if (msat_term_is_fp_roundingmode_minus_inf(environment, f)) { + return visitor.visitConstant(formula, FloatingPointRoundingMode.TOWARD_NEGATIVE); + } else if (msat_term_is_fp_roundingmode_zero(environment, f)) { + return visitor.visitConstant(formula, FloatingPointRoundingMode.TOWARD_ZERO); + } else { + throw new IllegalArgumentException( + "Unknown rounding mode " + msat_decl_get_name(msat_term_get_decl(f))); + } } else if (msat_term_is_constant(environment, f)) { return visitor.visitFreeVariable(formula, msat_term_repr(f)); } else if (msat_is_enum_type(environment, msat_term_get_type(f))) { @@ -516,22 +540,6 @@ private FunctionDeclarationKind getDeclarationKind(long pF) { return FunctionDeclarationKind.FP_IS_SUBNORMAL; case MSAT_TAG_FP_ISNORMAL: return FunctionDeclarationKind.FP_IS_NORMAL; - - case MSAT_TAG_UNKNOWN: - switch (msat_decl_get_name(decl)) { - case "`fprounding_even`": - return FunctionDeclarationKind.FP_ROUND_EVEN; - case "`fprounding_plus_inf`": - return FunctionDeclarationKind.FP_ROUND_POSITIVE; - case "`fprounding_minus_inf`": - return FunctionDeclarationKind.FP_ROUND_NEGATIVE; - case "`fprounding_zero`": - return FunctionDeclarationKind.FP_ROUND_ZERO; - - default: - return FunctionDeclarationKind.OTHER; - } - case MSAT_TAG_FLOOR: return FunctionDeclarationKind.FLOOR; diff --git a/src/org/sosy_lab/java_smt/solvers/mathsat5/Mathsat5NativeApi.java b/src/org/sosy_lab/java_smt/solvers/mathsat5/Mathsat5NativeApi.java index f0862ddaf8..aa8556f983 100644 --- a/src/org/sosy_lab/java_smt/solvers/mathsat5/Mathsat5NativeApi.java +++ b/src/org/sosy_lab/java_smt/solvers/mathsat5/Mathsat5NativeApi.java @@ -652,6 +652,14 @@ public static native long msat_simplify( public static native boolean msat_term_is_bv_comp(long e, long t); + public static native boolean msat_term_is_fp_roundingmode_nearest_even(long e, long t); + + public static native boolean msat_term_is_fp_roundingmode_zero(long e, long t); + + public static native boolean msat_term_is_fp_roundingmode_plus_inf(long e, long t); + + public static native boolean msat_term_is_fp_roundingmode_minus_inf(long e, long t); + public static native boolean msat_term_is_quantifier(long e, long t); public static native boolean msat_term_is_forall(long e, long t); diff --git a/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java b/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java index bde94b3e5f..f38c6837aa 100644 --- a/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java +++ b/src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java @@ -47,6 +47,7 @@ import org.sosy_lab.java_smt.api.FloatingPointNumber; import org.sosy_lab.java_smt.api.FloatingPointNumber.Sign; import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType; @@ -366,6 +367,13 @@ protected FloatingPointFormula encapsulateFloatingPoint(Long pTerm) { return storePhantomReference(new Z3FloatingPointFormula(getEnv(), pTerm), pTerm); } + @Override + protected FloatingPointRoundingModeFormula encapsulateRoundingMode(Long pTerm) { + assert getFormulaType(pTerm).isFloatingPointRoundingModeType(); + cleanupReferences(); + return storePhantomReference(new Z3FloatingPointRoundingModeFormula(getEnv(), pTerm), pTerm); + } + @Override protected StringFormula encapsulateString(Long pTerm) { assert getFormulaType(pTerm).isStringType() @@ -791,16 +799,6 @@ private FunctionDeclarationKind getDeclarationKind(long f) { return FunctionDeclarationKind.FP_GT; case Z3_OP_FPA_EQ: return FunctionDeclarationKind.FP_EQ; - case Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN: - return FunctionDeclarationKind.FP_ROUND_EVEN; - case Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY: - return FunctionDeclarationKind.FP_ROUND_AWAY; - case Z3_OP_FPA_RM_TOWARD_POSITIVE: - return FunctionDeclarationKind.FP_ROUND_POSITIVE; - case Z3_OP_FPA_RM_TOWARD_NEGATIVE: - return FunctionDeclarationKind.FP_ROUND_NEGATIVE; - case Z3_OP_FPA_RM_TOWARD_ZERO: - return FunctionDeclarationKind.FP_ROUND_ZERO; case Z3_OP_FPA_ROUND_TO_INTEGRAL: return FunctionDeclarationKind.FP_ROUND_TO_INTEGRAL; case Z3_OP_FPA_TO_FP_UNSIGNED: diff --git a/src/org/sosy_lab/java_smt/test/FloatingPointFormulaManagerTest.java b/src/org/sosy_lab/java_smt/test/FloatingPointFormulaManagerTest.java index 74390241cf..3f87193507 100644 --- a/src/org/sosy_lab/java_smt/test/FloatingPointFormulaManagerTest.java +++ b/src/org/sosy_lab/java_smt/test/FloatingPointFormulaManagerTest.java @@ -32,15 +32,21 @@ import org.sosy_lab.java_smt.api.FloatingPointNumber; import org.sosy_lab.java_smt.api.FloatingPointNumber.Sign; import org.sosy_lab.java_smt.api.FloatingPointRoundingMode; +import org.sosy_lab.java_smt.api.FloatingPointRoundingModeFormula; +import org.sosy_lab.java_smt.api.Formula; import org.sosy_lab.java_smt.api.FormulaType; import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; +import org.sosy_lab.java_smt.api.FunctionDeclaration; +import org.sosy_lab.java_smt.api.FunctionDeclarationKind; import org.sosy_lab.java_smt.api.InterpolatingProverEnvironment; import org.sosy_lab.java_smt.api.Model; import org.sosy_lab.java_smt.api.Model.ValueAssignment; import org.sosy_lab.java_smt.api.NumeralFormula; import org.sosy_lab.java_smt.api.ProverEnvironment; +import org.sosy_lab.java_smt.api.QuantifiedFormulaManager.Quantifier; import org.sosy_lab.java_smt.api.SolverContext.ProverOptions; import org.sosy_lab.java_smt.api.SolverException; +import org.sosy_lab.java_smt.api.visitors.FormulaVisitor; public class FloatingPointFormulaManagerTest extends SolverBasedTest0.ParameterizedSolverBasedTest0 { @@ -87,6 +93,67 @@ public void floatingPointType() { .isEqualTo(type.getMantissaSize()); } + @Test + public void roundingModeVisitor() { + FloatingPointFormula variable = + fpmgr.makeVariable("a", FormulaType.getSinglePrecisionFloatingPointType()); + FloatingPointFormula original = + fpmgr.sqrt(variable, FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + + for (FloatingPointRoundingMode rm : FloatingPointRoundingMode.values()) { + if (solver == Solvers.MATHSAT5 && rm == FloatingPointRoundingMode.NEAREST_TIES_AWAY) { + // SKIP MathSAT does not support rounding mode "nearest-ties-away" + continue; + } + // Build a term with a different rounding mode, then replace it in the visitor + FloatingPointFormula substituted = + (FloatingPointFormula) + mgr.visit( + fpmgr.sqrt(variable, rm), + new FormulaVisitor() { + @Override + public Formula visitFreeVariable(Formula f, String name) { + return f; + } + + @Override + public Formula visitConstant(Formula f, Object value) { + assertThat(f).isInstanceOf(FloatingPointRoundingModeFormula.class); + assertThat(value).isInstanceOf(FloatingPointRoundingMode.class); + assertThat(value).isEqualTo(rm); + + // Return the default rounding mode + return fpmgr.makeRoundingMode(FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN); + } + + @Override + public Formula visitFunction( + Formula f, List args, FunctionDeclaration functionDeclaration) { + assertThat(functionDeclaration.getKind()) + .isEqualTo(FunctionDeclarationKind.FP_SQRT); + assertThat(args).hasSize(2); + return mgr.makeApplication( + functionDeclaration, + mgr.visit(args.get(0), this), + mgr.visit(args.get(1), this)); + } + + @Override + public Formula visitQuantifier( + BooleanFormula f, + Quantifier quantifier, + List boundVariables, + BooleanFormula body) { + throw new IllegalArgumentException( + String.format("Unexpected quantifier %s", quantifier)); + } + }); + + // Check that after the substitution the rounding mode is the default again + assertThat(original).isEqualTo(substituted); + } + } + @Test public void negative() throws SolverException, InterruptedException { for (double d : new double[] {-1, -2, -0.0, Double.NEGATIVE_INFINITY}) {