diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c
index 27bf6de2c..920fdeb8c 100644
--- a/examples/c/test_capi.c
+++ b/examples/c/test_capi.c
@@ -2595,6 +2595,100 @@ void substitute_vars_example() {
Z3_del_context(ctx);
}
+/**
+ \brief Demonstrates some basic features of the FloatingPoint theory.
+*/
+
+void fpa_example() {
+ Z3_config cfg;
+ Z3_context ctx;
+ Z3_sort double_sort, rm_sort;
+ Z3_symbol s_rm, s_x, s_y, s_x_plus_y;
+ Z3_ast rm, x, y, n, x_plus_y, c1, c2, c3, c4, c5, c6;
+
+ printf("\nFPA-example\n");
+ LOG_MSG("FPA-example");
+
+ cfg = Z3_mk_config();
+ ctx = Z3_mk_context(cfg);
+ Z3_del_config(cfg);
+
+ double_sort = Z3_mk_fpa_sort(ctx, 11, 53);
+ rm_sort = Z3_mk_fpa_rounding_mode_sort(ctx);
+
+ {
+ // Show that there are x, y s.t. (x + y) = 42.0 (with rounding mode).
+ s_rm = Z3_mk_string_symbol(ctx, "rm");
+ rm = Z3_mk_const(ctx, s_rm, rm_sort);
+ s_x = Z3_mk_string_symbol(ctx, "x");
+ s_y = Z3_mk_string_symbol(ctx, "y");
+ x = Z3_mk_const(ctx, s_x, double_sort);
+ y = Z3_mk_const(ctx, s_y, double_sort);
+ n = Z3_mk_fpa_numeral_double(ctx, 42.0, double_sort);
+
+ s_x_plus_y = Z3_mk_string_symbol(ctx, "x_plus_y");
+ x_plus_y = Z3_mk_const(ctx, s_x_plus_y, double_sort);
+ c1 = Z3_mk_eq(ctx, x_plus_y, Z3_mk_fpa_add(ctx, rm, x, y));
+
+ Z3_ast args[2] = { c1, Z3_mk_eq(ctx, x_plus_y, n) };
+ c2 = Z3_mk_and(ctx, 2, (Z3_ast*)&args);
+
+ Z3_ast args2[2] = { c2, Z3_mk_not(ctx, Z3_mk_eq(ctx, rm, Z3_mk_fpa_rtz(ctx))) };
+ c3 = Z3_mk_and(ctx, 2, (Z3_ast*)&args2);
+
+ Z3_ast and_args[3] = {
+ Z3_mk_not(ctx, Z3_mk_fpa_is_zero(ctx, y)),
+ Z3_mk_not(ctx, Z3_mk_fpa_is_nan(ctx, y)),
+ Z3_mk_not(ctx, Z3_mk_fpa_is_infinite(ctx, y)) };
+ Z3_ast args3[2] = { c3, Z3_mk_and(ctx, 3, and_args) };
+ c4 = Z3_mk_and(ctx, 2, (Z3_ast*)&args3);
+
+ printf("c4: %s\n", Z3_ast_to_string(ctx, c4));
+ Z3_push(ctx);
+ Z3_assert_cnstr(ctx, c4);
+ check(ctx, Z3_L_TRUE);
+ Z3_pop(ctx, 1);
+ }
+
+
+ {
+ // Show that the following are equal:
+ // (fp #b0 #b10000000001 #xc000000000000)
+ // ((_ to_fp 11 53) #x401c000000000000))
+ // ((_ to_fp 11 53) RTZ 1.75 2)))
+ // ((_ to_fp 11 53) RTZ 7.0)))
+ Z3_ast args3[3];
+
+ Z3_push(ctx);
+ c1 = Z3_mk_fpa_fp(ctx,
+ Z3_mk_numeral(ctx, "0", Z3_mk_bv_sort(ctx, 1)),
+ Z3_mk_numeral(ctx, "1025", Z3_mk_bv_sort(ctx, 11)),
+ Z3_mk_numeral(ctx, "3377699720527872", Z3_mk_bv_sort(ctx, 52)));
+ c2 = Z3_mk_fpa_to_fp_bv(ctx,
+ Z3_mk_numeral(ctx, "4619567317775286272", Z3_mk_bv_sort(ctx, 64)),
+ Z3_mk_fpa_sort(ctx, 11, 53));
+ c3 = Z3_mk_fpa_to_fp_real_int(ctx,
+ Z3_mk_fpa_rtz(ctx),
+ Z3_mk_numeral(ctx, "1.75", Z3_mk_real_sort(ctx)),
+ Z3_mk_numeral(ctx, "2", Z3_mk_int_sort(ctx)),
+ Z3_mk_fpa_sort(ctx, 11, 53));
+ c4 = Z3_mk_fpa_to_fp_real(ctx,
+ Z3_mk_fpa_rtz(ctx),
+ Z3_mk_numeral(ctx, "7.0", Z3_mk_real_sort(ctx)),
+ Z3_mk_fpa_sort(ctx, 11, 53));
+ args3[0] = Z3_mk_eq(ctx, c1, c2);
+ args3[1] = Z3_mk_eq(ctx, c1, c3);
+ args3[2] = Z3_mk_eq(ctx, c1, c4);
+ c5 = Z3_mk_and(ctx, 3, args3);
+
+ printf("c5: %s\n", Z3_ast_to_string(ctx, c5));
+ Z3_assert_cnstr(ctx, c5);
+ check(ctx, Z3_L_TRUE);
+ Z3_pop(ctx, 1);
+ }
+
+ Z3_del_context(ctx);
+}
/*@}*/
/*@}*/
@@ -2640,5 +2734,6 @@ int main() {
smt2parser_example();
substitute_example();
substitute_vars_example();
+ fpa_example();
return 0;
}
diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs
index 4361cab96..0c33d6793 100644
--- a/examples/dotnet/Program.cs
+++ b/examples/dotnet/Program.cs
@@ -2028,6 +2028,84 @@ namespace test_mapi
// Console.WriteLine("{0}", ctx.MkEq(s1, t1));
}
+ public static void FloatingPointExample1(Context ctx)
+ {
+ Console.WriteLine("FloatingPointExample1");
+
+ FPSort s = ctx.MkFPSort(11, 53);
+ Console.WriteLine("Sort: {0}", s);
+
+ FPNum x = (FPNum)ctx.MkNumeral("-1e1", s); /* -1 * 10^1 = -10 */
+ FPNum y = (FPNum)ctx.MkNumeral("-10", s); /* -10 */
+ FPNum z = (FPNum)ctx.MkNumeral("-1.25p3", s); /* -1.25 * 2^3 = -1.25 * 8 = -10 */
+ Console.WriteLine("x={0}; y={1}; z={2}", x.ToString(), y.ToString(), z.ToString());
+
+ BoolExpr a = ctx.MkAnd(ctx.MkFPEq(x, y), ctx.MkFPEq(y, z));
+ Check(ctx, ctx.MkNot(a), Status.UNSATISFIABLE);
+
+ /* nothing is equal to NaN according to floating-point
+ * equality, so NaN == k should be unsatisfiable. */
+ FPExpr k = (FPExpr)ctx.MkConst("x", s);
+ FPExpr nan = ctx.MkFPNaN(s);
+
+ /* solver that runs the default tactic for QF_FP. */
+ Solver slvr = ctx.MkSolver("QF_FP");
+ slvr.Add(ctx.MkFPEq(nan, k));
+ if (slvr.Check() != Status.UNSATISFIABLE)
+ throw new TestFailedException();
+ Console.WriteLine("OK, unsat:" + Environment.NewLine + slvr);
+
+ /* NaN is equal to NaN according to normal equality. */
+ slvr = ctx.MkSolver("QF_FP");
+ slvr.Add(ctx.MkEq(nan, nan));
+ if (slvr.Check() != Status.SATISFIABLE)
+ throw new TestFailedException();
+ Console.WriteLine("OK, sat:" + Environment.NewLine + slvr);
+
+ /* Let's prove -1e1 * -1.25e3 == +100 */
+ x = (FPNum)ctx.MkNumeral("-1e1", s);
+ y = (FPNum)ctx.MkNumeral("-1.25p3", s);
+ FPExpr x_plus_y = (FPExpr)ctx.MkConst("x_plus_y", s);
+ FPNum r = (FPNum)ctx.MkNumeral("100", s);
+ slvr = ctx.MkSolver("QF_FP");
+
+ slvr.Add(ctx.MkEq(x_plus_y, ctx.MkFPMul(ctx.MkFPRoundNearestTiesToAway(), x, y)));
+ slvr.Add(ctx.MkNot(ctx.MkFPEq(x_plus_y, r)));
+ if (slvr.Check() != Status.UNSATISFIABLE)
+ throw new TestFailedException();
+ Console.WriteLine("OK, unsat:" + Environment.NewLine + slvr);
+ }
+
+ public static void FloatingPointExample2(Context ctx)
+ {
+ Console.WriteLine("FloatingPointExample2");
+ FPSort double_sort = ctx.MkFPSort(11, 53);
+ FPRMSort rm_sort = ctx.MkFPRoundingModeSort();
+
+ FPRMExpr rm = (FPRMExpr)ctx.MkConst(ctx.MkSymbol("rm"), rm_sort);
+ BitVecExpr x = (BitVecExpr)ctx.MkConst(ctx.MkSymbol("x"), ctx.MkBitVecSort(64));
+ FPExpr y = (FPExpr)ctx.MkConst(ctx.MkSymbol("y"), double_sort);
+ FPExpr fp_val = ctx.MkFP(42, double_sort);
+
+ BoolExpr c1 = ctx.MkEq(y, fp_val);
+ BoolExpr c2 = ctx.MkEq(x, ctx.MkFPToBV(rm, y, 64, false));
+ BoolExpr c3 = ctx.MkEq(x, ctx.MkBV(42, 64));
+ BoolExpr c4 = ctx.MkEq(ctx.MkNumeral(42, ctx.RealSort), ctx.MkFPToReal(fp_val));
+ BoolExpr c5 = ctx.MkAnd(c1, c2, c3, c4);
+ Console.WriteLine("c5 = " + c5);
+
+ /* Generic solver */
+ Solver s = ctx.MkSolver();
+ s.Assert(c5);
+
+ Console.WriteLine(s);
+
+ if (s.Check() != Status.SATISFIABLE)
+ throw new TestFailedException();
+
+ Console.WriteLine("OK, model: {0}", s.Model.ToString());
+ }
+
static void Main(string[] args)
{
try
@@ -2069,6 +2147,8 @@ namespace test_mapi
FindSmallModelExample(ctx);
SimplifierExample(ctx);
FiniteDomainExample(ctx);
+ FloatingPointExample1(ctx);
+ FloatingPointExample2(ctx);
}
// These examples need proof generation turned on.
diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java
index 48395d8c2..af8662700 100644
--- a/examples/java/JavaExample.java
+++ b/examples/java/JavaExample.java
@@ -1095,7 +1095,7 @@ class JavaExample
// / Shows how to use Solver(logic)
- // /
+ // / @param ctx
void logicExample(Context ctx) throws Z3Exception, TestFailedException
{
System.out.println("LogicTest");
@@ -2157,6 +2157,86 @@ class JavaExample
// System.out.println(ctx.mkEq(s1, t1));
}
+ public void floatingPointExample1(Context ctx) throws Z3Exception, TestFailedException
+ {
+ System.out.println("FloatingPointExample1");
+ Log.append("FloatingPointExample1");
+
+ FPSort s = ctx.mkFPSort(11, 53);
+ System.out.println("Sort: " + s);
+
+ FPNum x = (FPNum)ctx.mkNumeral("-1e1", s); /* -1 * 10^1 = -10 */
+ FPNum y = (FPNum)ctx.mkNumeral("-10", s); /* -10 */
+ FPNum z = (FPNum)ctx.mkNumeral("-1.25p3", s); /* -1.25 * 2^3 = -1.25 * 8 = -10 */
+ System.out.println("x=" + x.toString() +
+ "; y=" + y.toString() +
+ "; z=" + z.toString());
+
+ BoolExpr a = ctx.mkAnd(ctx.mkFPEq(x, y), ctx.mkFPEq(y, z));
+ check(ctx, ctx.mkNot(a), Status.UNSATISFIABLE);
+
+ /* nothing is equal to NaN according to floating-point
+ * equality, so NaN == k should be unsatisfiable. */
+ FPExpr k = (FPExpr)ctx.mkConst("x", s);
+ FPExpr nan = ctx.mkFPNaN(s);
+
+ /* solver that runs the default tactic for QF_FP. */
+ Solver slvr = ctx.mkSolver("QF_FP");
+ slvr.add(ctx.mkFPEq(nan, k));
+ if (slvr.check() != Status.UNSATISFIABLE)
+ throw new TestFailedException();
+ System.out.println("OK, unsat:" + System.getProperty("line.separator") + slvr);
+
+ /* NaN is equal to NaN according to normal equality. */
+ slvr = ctx.mkSolver("QF_FP");
+ slvr.add(ctx.mkEq(nan, nan));
+ if (slvr.check() != Status.SATISFIABLE)
+ throw new TestFailedException();
+ System.out.println("OK, sat:" + System.getProperty("line.separator") + slvr);
+
+ /* Let's prove -1e1 * -1.25e3 == +100 */
+ x = (FPNum)ctx.mkNumeral("-1e1", s);
+ y = (FPNum)ctx.mkNumeral("-1.25p3", s);
+ FPExpr x_plus_y = (FPExpr)ctx.mkConst("x_plus_y", s);
+ FPNum r = (FPNum)ctx.mkNumeral("100", s);
+ slvr = ctx.mkSolver("QF_FP");
+
+ slvr.add(ctx.mkEq(x_plus_y, ctx.mkFPMul(ctx.mkFPRoundNearestTiesToAway(), x, y)));
+ slvr.add(ctx.mkNot(ctx.mkFPEq(x_plus_y, r)));
+ if (slvr.check() != Status.UNSATISFIABLE)
+ throw new TestFailedException();
+ System.out.println("OK, unsat:" + System.getProperty("line.separator") + slvr);
+ }
+
+ public void floatingPointExample2(Context ctx) throws Z3Exception, TestFailedException
+ {
+ System.out.println("FloatingPointExample2");
+ Log.append("FloatingPointExample2");
+ FPSort double_sort = ctx.mkFPSort(11, 53);
+ FPRMSort rm_sort = ctx.mkFPRoundingModeSort();
+
+ FPRMExpr rm = (FPRMExpr)ctx.mkConst(ctx.mkSymbol("rm"), rm_sort);
+ BitVecExpr x = (BitVecExpr)ctx.mkConst(ctx.mkSymbol("x"), ctx.mkBitVecSort(64));
+ FPExpr y = (FPExpr)ctx.mkConst(ctx.mkSymbol("y"), double_sort);
+ FPExpr fp_val = ctx.mkFP(42, double_sort);
+
+ BoolExpr c1 = ctx.mkEq(y, fp_val);
+ BoolExpr c2 = ctx.mkEq(x, ctx.mkFPToBV(rm, y, 64, false));
+ BoolExpr c3 = ctx.mkEq(x, ctx.mkBV(42, 64));
+ BoolExpr c4 = ctx.mkEq(ctx.mkNumeral(42, ctx.getRealSort()), ctx.mkFPToReal(fp_val));
+ BoolExpr c5 = ctx.mkAnd(c1, c2, c3, c4);
+ System.out.println("c5 = " + c5);
+
+ /* Generic solver */
+ Solver s = ctx.mkSolver();
+ s.add(c5);
+
+ if (s.check() != Status.SATISFIABLE)
+ throw new TestFailedException();
+
+ System.out.println("OK, model: " + s.getModel().toString());
+ }
+
public static void main(String[] args)
{
JavaExample p = new JavaExample();
@@ -2200,6 +2280,8 @@ class JavaExample
p.findSmallModelExample(ctx);
p.simplifierExample(ctx);
p.finiteDomainExample(ctx);
+ p.floatingPointExample1(ctx);
+ p.floatingPointExample2(ctx);
}
{ // These examples need proof generation turned on.
diff --git a/scripts/mk_project.py b/scripts/mk_project.py
index 225ef6413..bdc395f14 100644
--- a/scripts/mk_project.py
+++ b/scripts/mk_project.py
@@ -53,8 +53,8 @@ def init_project_def():
add_lib('user_plugin', ['smt'], 'smt/user_plugin')
add_lib('bv_tactics', ['tactic', 'bit_blaster'], 'tactic/bv')
add_lib('fuzzing', ['ast'], 'test/fuzzing')
- add_lib('fpa_tactics', ['fpa', 'core_tactics', 'bv_tactics', 'sat_tactic'], 'tactic/fpa')
add_lib('smt_tactic', ['smt'], 'smt/tactic')
+ add_lib('fpa_tactics', ['fpa', 'core_tactics', 'bv_tactics', 'sat_tactic', 'smt_tactic'], 'tactic/fpa')
add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls')
add_lib('qe', ['smt','sat'], 'qe')
add_lib('duality', ['smt', 'interp', 'qe'])
@@ -75,7 +75,7 @@ def init_project_def():
# dll_name='foci2',
# export_files=['foci2stub.cpp'])
# add_lib('interp', ['solver','foci2'])
- API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_interp.h']
+ API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_interp.h', 'z3_fpa.h']
add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure', 'interp'],
includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files)
add_exe('shell', ['api', 'sat', 'extra_cmds'], exe_name='z3')
diff --git a/scripts/update_api.py b/scripts/update_api.py
index d53bc5de3..499cc1a32 100644
--- a/scripts/update_api.py
+++ b/scripts/update_api.py
@@ -124,6 +124,7 @@ SYMBOL = 9
PRINT_MODE = 10
ERROR_CODE = 11
DOUBLE = 12
+FLOAT = 13
FIRST_OBJ_ID = 100
@@ -131,28 +132,28 @@ def is_obj(ty):
return ty >= FIRST_OBJ_ID
Type2Str = { VOID : 'void', VOID_PTR : 'void*', INT : 'int', UINT : 'unsigned', INT64 : '__int64', UINT64 : '__uint64', DOUBLE : 'double',
- STRING : 'Z3_string', STRING_PTR : 'Z3_string_ptr', BOOL : 'Z3_bool', SYMBOL : 'Z3_symbol',
+ FLOAT : 'float', STRING : 'Z3_string', STRING_PTR : 'Z3_string_ptr', BOOL : 'Z3_bool', SYMBOL : 'Z3_symbol',
PRINT_MODE : 'Z3_ast_print_mode', ERROR_CODE : 'Z3_error_code'
}
Type2PyStr = { VOID_PTR : 'ctypes.c_void_p', INT : 'ctypes.c_int', UINT : 'ctypes.c_uint', INT64 : 'ctypes.c_longlong',
- UINT64 : 'ctypes.c_ulonglong', DOUBLE : 'ctypes.c_double',
+ UINT64 : 'ctypes.c_ulonglong', DOUBLE : 'ctypes.c_double', FLOAT : 'ctypes.c_float',
STRING : 'ctypes.c_char_p', STRING_PTR : 'ctypes.POINTER(ctypes.c_char_p)', BOOL : 'ctypes.c_bool', SYMBOL : 'Symbol',
PRINT_MODE : 'ctypes.c_uint', ERROR_CODE : 'ctypes.c_uint'
}
# Mapping to .NET types
Type2Dotnet = { VOID : 'void', VOID_PTR : 'IntPtr', INT : 'int', UINT : 'uint', INT64 : 'Int64', UINT64 : 'UInt64', DOUBLE : 'double',
- STRING : 'string', STRING_PTR : 'byte**', BOOL : 'int', SYMBOL : 'IntPtr',
+ FLOAT : 'float', STRING : 'string', STRING_PTR : 'byte**', BOOL : 'int', SYMBOL : 'IntPtr',
PRINT_MODE : 'uint', ERROR_CODE : 'uint' }
# Mapping to Java types
Type2Java = { VOID : 'void', VOID_PTR : 'long', INT : 'int', UINT : 'int', INT64 : 'long', UINT64 : 'long', DOUBLE : 'double',
- STRING : 'String', STRING_PTR : 'StringPtr',
+ FLOAT : 'float', STRING : 'String', STRING_PTR : 'StringPtr',
BOOL : 'boolean', SYMBOL : 'long', PRINT_MODE : 'int', ERROR_CODE : 'int'}
Type2JavaW = { VOID : 'void', VOID_PTR : 'jlong', INT : 'jint', UINT : 'jint', INT64 : 'jlong', UINT64 : 'jlong', DOUBLE : 'jdouble',
- STRING : 'jstring', STRING_PTR : 'jobject',
+ FLOAT : 'jfloat', STRING : 'jstring', STRING_PTR : 'jobject',
BOOL : 'jboolean', SYMBOL : 'jlong', PRINT_MODE : 'jint', ERROR_CODE : 'jint'}
@@ -927,6 +928,9 @@ def def_API(name, result, params):
elif ty == DOUBLE:
log_c.write(" D(a%s);\n" % i)
exe_c.write("in.get_double(%s)" % i)
+ elif ty == FLOAT:
+ log_c.write(" D(a%s);\n" % i)
+ exe_c.write("in.get_float(%s)" % i)
elif ty == BOOL:
log_c.write(" I(a%s);\n" % i)
exe_c.write("in.get_bool(%s)" % i)
diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp
index c2864ca2d..b9c6230b7 100644
--- a/src/api/api_ast.cpp
+++ b/src/api/api_ast.cpp
@@ -648,6 +648,12 @@ extern "C" {
else if (fid == mk_c(c)->get_datalog_fid() && k == datalog::DL_FINITE_SORT) {
return Z3_FINITE_DOMAIN_SORT;
}
+ else if (fid == mk_c(c)->get_fpa_fid() && k == FLOATING_POINT_SORT) {
+ return Z3_FLOATING_POINT_SORT;
+ }
+ else if (fid == mk_c(c)->get_fpa_fid() && k == ROUNDING_MODE_SORT) {
+ return Z3_ROUNDING_MODE_SORT;
+ }
else {
return Z3_UNKNOWN_SORT;
}
@@ -1113,6 +1119,62 @@ extern "C" {
return Z3_OP_UNINTERPRETED;
}
}
+
+ if (mk_c(c)->get_fpa_fid() == _d->get_family_id()) {
+ switch (_d->get_decl_kind()) {
+ case OP_FPA_RM_NEAREST_TIES_TO_EVEN: return Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN;
+ case OP_FPA_RM_NEAREST_TIES_TO_AWAY: return Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY;
+ case OP_FPA_RM_TOWARD_POSITIVE: return Z3_OP_FPA_RM_TOWARD_POSITIVE;
+ case OP_FPA_RM_TOWARD_NEGATIVE: return Z3_OP_FPA_RM_TOWARD_NEGATIVE;
+ case OP_FPA_RM_TOWARD_ZERO: return Z3_OP_FPA_RM_TOWARD_ZERO;
+ case OP_FPA_NUM: return Z3_OP_FPA_NUM;
+ case OP_FPA_PLUS_INF: return Z3_OP_FPA_PLUS_INF;
+ case OP_FPA_MINUS_INF: return Z3_OP_FPA_MINUS_INF;
+ case OP_FPA_NAN: return Z3_OP_FPA_NAN;
+ case OP_FPA_MINUS_ZERO: return Z3_OP_FPA_MINUS_ZERO;
+ case OP_FPA_PLUS_ZERO: return Z3_OP_FPA_PLUS_ZERO;
+ case OP_FPA_ADD: return Z3_OP_FPA_ADD;
+ case OP_FPA_SUB: return Z3_OP_FPA_SUB;
+ case OP_FPA_NEG: return Z3_OP_FPA_NEG;
+ case OP_FPA_MUL: return Z3_OP_FPA_MUL;
+ case OP_FPA_DIV: return Z3_OP_FPA_DIV;
+ case OP_FPA_REM: return Z3_OP_FPA_REM;
+ case OP_FPA_ABS: return Z3_OP_FPA_ABS;
+ case OP_FPA_MIN: return Z3_OP_FPA_MIN;
+ case OP_FPA_MAX: return Z3_OP_FPA_MAX;
+ case OP_FPA_FMA: return Z3_OP_FPA_FMA;
+ case OP_FPA_SQRT: return Z3_OP_FPA_SQRT;
+ case OP_FPA_EQ: return Z3_OP_FPA_EQ;
+ case OP_FPA_ROUND_TO_INTEGRAL: return Z3_OP_FPA_ROUND_TO_INTEGRAL;
+ case OP_FPA_LT: return Z3_OP_FPA_LT;
+ case OP_FPA_GT: return Z3_OP_FPA_GT;
+ case OP_FPA_LE: return Z3_OP_FPA_LE;
+ case OP_FPA_GE: return Z3_OP_FPA_GE;
+ case OP_FPA_IS_NAN: return Z3_OP_FPA_IS_NAN;
+ case OP_FPA_IS_INF: return Z3_OP_FPA_IS_INF;
+ case OP_FPA_IS_ZERO: return Z3_OP_FPA_IS_ZERO;
+ case OP_FPA_IS_NORMAL: return Z3_OP_FPA_IS_NORMAL;
+ case OP_FPA_IS_SUBNORMAL: return Z3_OP_FPA_IS_SUBNORMAL;
+ case OP_FPA_IS_NEGATIVE: return Z3_OP_FPA_IS_NEGATIVE;
+ case OP_FPA_IS_POSITIVE: return Z3_OP_FPA_IS_POSITIVE;
+ case OP_FPA_FP: return Z3_OP_FPA_FP;
+ case OP_FPA_TO_FP: return Z3_OP_FPA_TO_FP;
+ case OP_FPA_TO_FP_UNSIGNED: return Z3_OP_FPA_TO_FP_UNSIGNED;
+ case OP_FPA_TO_UBV: return Z3_OP_FPA_TO_UBV;
+ case OP_FPA_TO_SBV: return Z3_OP_FPA_TO_SBV;
+ case OP_FPA_TO_REAL: return Z3_OP_FPA_TO_REAL;
+ case OP_FPA_TO_IEEE_BV: return Z3_OP_FPA_TO_IEEE_BV;
+ case OP_FPA_INTERNAL_BVWRAP:
+ case OP_FPA_INTERNAL_BVUNWRAP:
+ case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
+ case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
+ case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
+ return Z3_OP_UNINTERPRETED;
+ default:
+ UNREACHABLE();
+ return Z3_OP_UNINTERPRETED;
+ }
+ }
if (mk_c(c)->m().get_label_family_id() == _d->get_family_id()) {
switch(_d->get_decl_kind()) {
diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp
index b10621d43..3408cdf3c 100644
--- a/src/api/api_context.cpp
+++ b/src/api/api_context.cpp
@@ -88,6 +88,7 @@ namespace api {
m_arith_util(m()),
m_bv_util(m()),
m_datalog_util(m()),
+ m_fpa_util(m()),
m_last_result(m()),
m_ast_trail(m()),
m_replay_stack() {
@@ -112,6 +113,7 @@ namespace api {
m_array_fid = m().mk_family_id("array");
m_dt_fid = m().mk_family_id("datatype");
m_datalog_fid = m().mk_family_id("datalog_relation");
+ m_fpa_fid = m().mk_family_id("fpa");
m_dt_plugin = static_cast(m().get_plugin(m_dt_fid));
if (!m_user_ref_count) {
diff --git a/src/api/api_context.h b/src/api/api_context.h
index e0c95b07b..6312b3f69 100644
--- a/src/api/api_context.h
+++ b/src/api/api_context.h
@@ -27,6 +27,7 @@ Revision History:
#include"bv_decl_plugin.h"
#include"datatype_decl_plugin.h"
#include"dl_decl_plugin.h"
+#include"fpa_decl_plugin.h"
#include"smt_kernel.h"
#include"smt_params.h"
#include"event_handler.h"
@@ -56,6 +57,7 @@ namespace api {
arith_util m_arith_util;
bv_util m_bv_util;
datalog::dl_decl_util m_datalog_util;
+ fpa_util m_fpa_util;
// Support for old solver API
smt_params m_fparams;
@@ -75,6 +77,7 @@ namespace api {
family_id m_bv_fid;
family_id m_dt_fid;
family_id m_datalog_fid;
+ family_id m_fpa_fid;
datatype_decl_plugin * m_dt_plugin;
std::string m_string_buffer; // temporary buffer used to cache strings sent to the "external" world.
@@ -115,12 +118,14 @@ namespace api {
arith_util & autil() { return m_arith_util; }
bv_util & bvutil() { return m_bv_util; }
datalog::dl_decl_util & datalog_util() { return m_datalog_util; }
+ fpa_util & fpa_util() { return m_fpa_util; }
family_id get_basic_fid() const { return m_basic_fid; }
family_id get_array_fid() const { return m_array_fid; }
family_id get_arith_fid() const { return m_arith_fid; }
family_id get_bv_fid() const { return m_bv_fid; }
family_id get_dt_fid() const { return m_dt_fid; }
family_id get_datalog_fid() const { return m_datalog_fid; }
+ family_id get_fpa_fid() const { return m_fpa_fid; }
datatype_decl_plugin * get_dt_plugin() const { return m_dt_plugin; }
Z3_error_code get_error_code() const { return m_error_code; }
diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp
new file mode 100644
index 000000000..67ffe12d9
--- /dev/null
+++ b/src/api/api_fpa.cpp
@@ -0,0 +1,793 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ api_fpa.cpp
+
+Abstract:
+
+ Additional APIs for floating-point arithmetic (FP).
+
+Author:
+
+ Christoph M. Wintersteiger (cwinter) 2013-06-05
+
+Notes:
+
+--*/
+#include
+#include"z3.h"
+#include"api_log_macros.h"
+#include"api_context.h"
+#include"fpa_decl_plugin.h"
+
+extern "C" {
+
+ Z3_sort Z3_API Z3_mk_fpa_rounding_mode_sort(Z3_context c) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_rounding_mode_sort(c);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_sort r = of_sort(ctx->fpa_util().mk_rm_sort());
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_even(Z3_context c)
+ {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_round_nearest_ties_to_even(c);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_round_nearest_ties_to_even());
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_rne(Z3_context c) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_rne(c);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_round_nearest_ties_to_even());
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_away(Z3_context c)
+ {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_round_nearest_ties_to_away(c);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_round_nearest_ties_to_away());
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_rna(Z3_context c) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_rna(c);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_round_nearest_ties_to_away());
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_round_toward_positive(Z3_context c)
+ {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_round_toward_positive(c);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_positive());
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_rtp(Z3_context c) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_rtp(c);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_positive());
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_round_toward_negative(Z3_context c)
+ {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_round_toward_negative(c);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_negative());
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_rtn(Z3_context c) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_rtn(c);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_negative());
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_round_toward_zero(Z3_context c)
+ {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_round_toward_zero(c);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_zero());
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_rtz(Z3_context c) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_rtz(c);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_zero());
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+
+ Z3_sort Z3_API Z3_mk_fpa_sort(Z3_context c, unsigned ebits, unsigned sbits) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_sort(c, ebits, sbits);
+ RESET_ERROR_CODE();
+ if (ebits < 2 || sbits < 3) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ }
+ api::context * ctx = mk_c(c);
+ Z3_sort r = of_sort(ctx->fpa_util().mk_float_sort(ebits, sbits));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_sort Z3_API Z3_mk_fpa_sort_half(Z3_context c) {
+ return Z3_mk_fpa_sort(c, 5, 11);
+ }
+
+ Z3_sort Z3_API Z3_mk_fpa_sort_16(Z3_context c) {
+ return Z3_mk_fpa_sort(c, 5, 11);
+ }
+
+ Z3_sort Z3_API Z3_mk_fpa_sort_single(Z3_context c) {
+ return Z3_mk_fpa_sort(c, 8, 24);
+ }
+
+ Z3_sort Z3_API Z3_mk_fpa_sort_32(Z3_context c) {
+ return Z3_mk_fpa_sort(c, 8, 24);
+ }
+
+ Z3_sort Z3_API Z3_mk_fpa_sort_double(Z3_context c) {
+ return Z3_mk_fpa_sort(c, 11, 53);
+ }
+
+ Z3_sort Z3_API Z3_mk_fpa_sort_64(Z3_context c) {
+ return Z3_mk_fpa_sort(c, 11, 53);
+ }
+
+ Z3_sort Z3_API Z3_mk_fpa_sort_quadruple(Z3_context c) {
+ return Z3_mk_fpa_sort(c, 15, 113);
+ }
+
+ Z3_sort Z3_API Z3_mk_fpa_sort_128(Z3_context c) {
+ return Z3_mk_fpa_sort(c, 15, 113);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_nan(Z3_context c, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_nan(c, s);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_nan(to_sort(s)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_inf(Z3_context c, Z3_sort s, Z3_bool negative) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_inf(c, s, negative);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(negative != 0 ? ctx->fpa_util().mk_ninf(to_sort(s)) :
+ ctx->fpa_util().mk_pinf(to_sort(s)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_zero(Z3_context c, Z3_sort s, Z3_bool negative) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_inf(c, s, negative);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(negative != 0 ? ctx->fpa_util().mk_nzero(to_sort(s)) :
+ ctx->fpa_util().mk_pzero(to_sort(s)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_fp(Z3_context c, Z3_ast sgn, Z3_ast exp, Z3_ast sig) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_fp(c, sgn, sig, exp);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_fp(to_expr(sgn), to_expr(sig), to_expr(exp)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_numeral_float(Z3_context c, float v, Z3_sort ty) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_numeral_float(c, v, ty);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ scoped_mpf tmp(ctx->fpa_util().fm());
+ ctx->fpa_util().fm().set(tmp,
+ ctx->fpa_util().get_ebits(to_sort(ty)),
+ ctx->fpa_util().get_sbits(to_sort(ty)),
+ v);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_value(tmp));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_numeral_double(Z3_context c, double v, Z3_sort ty) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_numeral_double(c, v, ty);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ scoped_mpf tmp(ctx->fpa_util().fm());
+ ctx->fpa_util().fm().set(tmp, ctx->fpa_util().get_ebits(to_sort(ty)), ctx->fpa_util().get_sbits(to_sort(ty)), v);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_value(tmp));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_numeral_int(Z3_context c, signed v, Z3_sort ty) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_numeral_int(c, v, ty);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ scoped_mpf tmp(ctx->fpa_util().fm());
+ ctx->fpa_util().fm().set(tmp,
+ ctx->fpa_util().get_ebits(to_sort(ty)),
+ ctx->fpa_util().get_sbits(to_sort(ty)),
+ v);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_value(tmp));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_numeral_uint_int(Z3_context c, Z3_bool sgn, unsigned sig, signed exp, Z3_sort ty) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_numeral_uint64_int64(c, sgn, sig, exp, ty);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ scoped_mpf tmp(ctx->fpa_util().fm());
+ ctx->fpa_util().fm().set(tmp,
+ ctx->fpa_util().get_ebits(to_sort(ty)),
+ ctx->fpa_util().get_sbits(to_sort(ty)),
+ sgn != 0, sig, exp);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_value(tmp));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_numeral_uint64_int64(Z3_context c, Z3_bool sgn, __uint64 sig, __int64 exp, Z3_sort ty) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_numeral_uint64_int64(c, sgn, sig, exp, ty);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ scoped_mpf tmp(ctx->fpa_util().fm());
+ ctx->fpa_util().fm().set(tmp,
+ ctx->fpa_util().get_ebits(to_sort(ty)),
+ ctx->fpa_util().get_sbits(to_sort(ty)),
+ sgn != 0, sig, exp);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_value(tmp));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_abs(Z3_context c, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_abs(c, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_abs(to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_neg(Z3_context c, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_neg(c, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_neg(to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_add(Z3_context c, Z3_ast rm, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_add(c, rm, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_add(to_expr(rm), to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_sub(Z3_context c, Z3_ast rm, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_add(c, rm, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_sub(to_expr(rm), to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_mul(Z3_context c, Z3_ast rm, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_add(c, rm, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_mul(to_expr(rm), to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_div(Z3_context c, Z3_ast rm, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_add(c, rm, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_div(to_expr(rm), to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_fma(Z3_context c, Z3_ast rm, Z3_ast t1, Z3_ast t2, Z3_ast t3) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_fma(c, rm, t1, t2, t3);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_fma(to_expr(rm), to_expr(t1), to_expr(t2), to_expr(t3)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_sqrt(Z3_context c, Z3_ast rm, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_sqrt(c, rm, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_sqrt(to_expr(rm), to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_rem(Z3_context c, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_rem(c, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_rem(to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_round_to_integral(Z3_context c, Z3_ast rm, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_round_to_integral(c, rm, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_round_to_integral(to_expr(rm), to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_min(Z3_context c, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_min(c, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_min(to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_max(Z3_context c, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_max(c, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_max(to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_leq(Z3_context c, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_leq(c, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_le(to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_lt(Z3_context c, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_lt(c, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_lt(to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_geq(Z3_context c, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_geq(c, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_ge(to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_gt(Z3_context c, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_gt(c, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_gt(to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_eq(Z3_context c, Z3_ast t1, Z3_ast t2) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_eq(c, t1, t2);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_float_eq(to_expr(t1), to_expr(t2)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_is_normal(Z3_context c, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_is_normal(c, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_is_normal(to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_is_subnormal(Z3_context c, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_is_subnormal(c, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_is_subnormal(to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_is_zero(Z3_context c, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_is_zero(c, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_is_zero(to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_is_infinite(Z3_context c, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_is_infinite(c, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_is_inf(to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_is_nan(Z3_context c, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_is_nan(c, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_is_nan(to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_is_negative(Z3_context c, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_is_negative(c, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_is_negative(to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_is_positive(Z3_context c, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_is_positive(c, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_is_positive(to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_bv(Z3_context c, Z3_ast bv, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_to_fp_bv(c, bv, s);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ fpa_util & fu = ctx->fpa_util();
+ if (!ctx->bvutil().is_bv(to_expr(bv)) ||
+ !fu.is_float(to_sort(s))) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ Z3_ast r = of_ast(fu.mk_to_fp(to_sort(s), to_expr(bv)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_float(Z3_context c, Z3_ast rm, Z3_ast t, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_to_fp_float(c, rm, t, s);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ fpa_util & fu = ctx->fpa_util();
+ if (!fu.is_rm(to_expr(rm)) ||
+ !fu.is_float(to_expr(t)) ||
+ !fu.is_float(to_sort(s))) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ Z3_ast r = of_ast(fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_real(Z3_context c, Z3_ast rm, Z3_ast t, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_to_fp_real(c, rm, t, s);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ fpa_util & fu = ctx->fpa_util();
+ if (!fu.is_rm(to_expr(rm)) ||
+ !ctx->autil().is_real(to_expr(t)) ||
+ !fu.is_float(to_sort(s))) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ Z3_ast r = of_ast(fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_signed(Z3_context c, Z3_ast rm, Z3_ast t, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_to_fp_signed(c, rm, t, s);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ fpa_util & fu = ctx->fpa_util();
+ if (!fu.is_rm(to_expr(rm)) ||
+ !ctx->bvutil().is_bv(to_expr(t)) ||
+ !fu.is_float(to_sort(s))) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ Z3_ast r = of_ast(fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_unsigned(Z3_context c, Z3_ast rm, Z3_ast t, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_to_fp_unsigned(c, rm, t, s);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ fpa_util & fu = ctx->fpa_util();
+ if (!fu.is_rm(to_expr(rm)) ||
+ !ctx->bvutil().is_bv(to_expr(t)) ||
+ !fu.is_float(to_sort(s))) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ Z3_ast r = of_ast(fu.mk_to_fp_unsigned(to_sort(s), to_expr(rm), to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_to_ubv(Z3_context c, Z3_ast rm, Z3_ast t, unsigned sz) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_to_ubv(c, rm, t, sz);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_to_ubv(to_expr(rm), to_expr(t), sz));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_to_sbv(Z3_context c, Z3_ast rm, Z3_ast t, unsigned sz) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_to_sbv(c, rm, t, sz);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_to_sbv(to_expr(rm), to_expr(t), sz));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_to_real(Z3_context c, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_to_real(c, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_to_real(to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ unsigned Z3_API Z3_fpa_get_ebits(Z3_context c, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_fpa_get_ebits(c, s);
+ RESET_ERROR_CODE();
+ CHECK_NON_NULL(s, 0);
+ return mk_c(c)->fpa_util().get_ebits(to_sort(s));
+ Z3_CATCH_RETURN(0);
+ }
+
+ unsigned Z3_API Z3_fpa_get_sbits(Z3_context c, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_fpa_get_ebits(c, s);
+ RESET_ERROR_CODE();
+ CHECK_NON_NULL(s, 0);
+ return mk_c(c)->fpa_util().get_sbits(to_sort(s));
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_bool Z3_API Z3_fpa_get_numeral_sign(Z3_context c, Z3_ast t, int * sgn) {
+ Z3_TRY;
+ LOG_Z3_fpa_get_numeral_sign(c, t, sgn);
+ RESET_ERROR_CODE();
+ ast_manager & m = mk_c(c)->m();
+ mpf_manager & mpfm = mk_c(c)->fpa_util().fm();
+ fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid());
+ scoped_mpf val(mpfm);
+ bool r = plugin->is_numeral(to_expr(t), val);
+ if (!r || mpfm.is_nan(val)) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ *sgn = (mpfm.is_nan(val)) ? 0 : mpfm.sgn(val);
+ return r;
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_string Z3_API Z3_fpa_get_numeral_significand_string(__in Z3_context c, __in Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_fpa_get_numeral_significand_string(c, t);
+ RESET_ERROR_CODE();
+ ast_manager & m = mk_c(c)->m();
+ mpf_manager & mpfm = mk_c(c)->fpa_util().fm();
+ unsynch_mpq_manager & mpqm = mpfm.mpq_manager();
+ fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid());
+ scoped_mpf val(mpfm);
+ if (!plugin->is_numeral(to_expr(t), val)) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return "";
+ }
+ else if (!mpfm.is_regular(val)) {
+ SET_ERROR_CODE(Z3_INVALID_ARG)
+ return "";
+ }
+ unsigned sbits = val.get().get_sbits();
+ scoped_mpq q(mpqm);
+ mpqm.set(q, mpfm.sig_normalized(val));
+ mpqm.div(q, mpfm.m_powers2(sbits - 1), q);
+ std::stringstream ss;
+ mpqm.display_decimal(ss, q, sbits);
+ return mk_c(c)->mk_external_string(ss.str());
+ Z3_CATCH_RETURN("");
+
+ }
+
+ Z3_string Z3_API Z3_fpa_get_numeral_exponent_string(__in Z3_context c, __in Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_fpa_get_numeral_exponent_string(c, t);
+ RESET_ERROR_CODE();
+ ast_manager & m = mk_c(c)->m();
+ mpf_manager & mpfm = mk_c(c)->fpa_util().fm();
+ unsynch_mpq_manager & mpqm = mpfm.mpq_manager();
+ fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid());
+ scoped_mpf val(mpfm);
+ bool r = plugin->is_numeral(to_expr(t), val);
+ if (!r) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return "";
+ }
+ else if (!mpfm.is_normal(val) && !mpfm.is_denormal(val)) {
+ SET_ERROR_CODE(Z3_INVALID_ARG)
+ return "";
+ }
+ mpf_exp_t exp = mpfm.exp_normalized(val);
+ std::stringstream ss;
+ ss << exp;
+ return mk_c(c)->mk_external_string(ss.str());
+ Z3_CATCH_RETURN("");
+ }
+
+ Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(__in Z3_context c, __in Z3_ast t, __out __int64 * n) {
+ Z3_TRY;
+ LOG_Z3_fpa_get_numeral_exponent_string(c, t);
+ RESET_ERROR_CODE();
+ ast_manager & m = mk_c(c)->m();
+ mpf_manager & mpfm = mk_c(c)->fpa_util().fm();
+ unsynch_mpq_manager & mpqm = mpfm.mpq_manager();
+ fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid());
+ scoped_mpf val(mpfm);
+ bool r = plugin->is_numeral(to_expr(t), val);
+ if (!r) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ *n = mpfm.exp(val);
+ return 1;
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_to_ieee_bv(Z3_context c, Z3_ast t) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_to_ieee_bv(c, t);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ Z3_ast r = of_ast(ctx->fpa_util().mk_float_to_ieee_bv(to_expr(t)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_real_int(Z3_context c, Z3_ast rm, Z3_ast sig, Z3_ast exp, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_mk_fpa_to_fp_real_int(c, rm, sig, exp, s);
+ RESET_ERROR_CODE();
+ api::context * ctx = mk_c(c);
+ fpa_util & fu = ctx->fpa_util();
+ if (!fu.is_rm(to_expr(rm)) ||
+ !ctx->autil().is_real(to_expr(sig)) ||
+ !ctx->autil().is_int(to_expr(exp)) ||
+ !fu.is_float(to_sort(s))) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return 0;
+ }
+ Z3_ast r = of_ast(fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(sig), to_expr(exp)));
+ RETURN_Z3(r);
+ Z3_CATCH_RETURN(0);
+ }
+
+};
diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp
index d4a6587bc..d5a25dfc2 100644
--- a/src/api/api_numeral.cpp
+++ b/src/api/api_numeral.cpp
@@ -23,13 +23,15 @@ Revision History:
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"algebraic_numbers.h"
+#include"fpa_decl_plugin.h"
bool is_numeral_sort(Z3_context c, Z3_sort ty) {
sort * _ty = to_sort(ty);
family_id fid = _ty->get_family_id();
if (fid != mk_c(c)->get_arith_fid() &&
fid != mk_c(c)->get_bv_fid() &&
- fid != mk_c(c)->get_datalog_fid()) {
+ fid != mk_c(c)->get_datalog_fid() &&
+ fid != mk_c(c)->get_fpa_fid()) {
return false;
}
return true;
@@ -48,7 +50,7 @@ extern "C" {
Z3_ast Z3_API Z3_mk_numeral(Z3_context c, const char* n, Z3_sort ty) {
Z3_TRY;
LOG_Z3_mk_numeral(c, n, ty);
- RESET_ERROR_CODE();
+ RESET_ERROR_CODE();
if (!check_numeral_sort(c, ty)) {
RETURN_Z3(0);
}
@@ -56,40 +58,42 @@ extern "C" {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
+ sort * _ty = to_sort(ty);
+ bool is_float = mk_c(c)->fpa_util().is_float(_ty);
std::string fixed_num;
char const* m = n;
while (*m) {
if (!(('0' <= *m && *m <= '9') ||
- ('/' == *m) || ('-' == *m) ||
- (' ' == *m) || ('\n' == *m) ||
- ('.' == *m) || ('e' == *m) ||
- ('E' == *m))) {
+ ('/' == *m) || ('-' == *m) ||
+ (' ' == *m) || ('\n' == *m) ||
+ ('.' == *m) || ('e' == *m) ||
+ ('E' == *m) ||
+ (('p' == *m) && is_float) ||
+ (('P' == *m)) && is_float)) {
SET_ERROR_CODE(Z3_PARSER_ERROR);
return 0;
}
++m;
}
- ast * a = mk_c(c)->mk_numeral_core(rational(n), to_sort(ty));
+ ast * a = 0;
+ if (_ty->get_family_id() == mk_c(c)->get_fpa_fid()) {
+ // avoid expanding floats into huge rationals.
+ fpa_util & fu = mk_c(c)->fpa_util();
+ scoped_mpf t(fu.fm());
+ fu.fm().set(t, fu.get_ebits(_ty), fu.get_sbits(_ty), MPF_ROUND_TOWARD_ZERO, n);
+ a = fu.mk_value(t);
+ mk_c(c)->save_ast_trail(a);
+ }
+ else
+ a = mk_c(c)->mk_numeral_core(rational(n), _ty);
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(0);
}
-
+
Z3_ast Z3_API Z3_mk_int(Z3_context c, int value, Z3_sort ty) {
Z3_TRY;
LOG_Z3_mk_int(c, value, ty);
- RESET_ERROR_CODE();
- if (!check_numeral_sort(c, ty)) {
- RETURN_Z3(0);
- }
- ast * a = mk_c(c)->mk_numeral_core(rational(value), to_sort(ty));
- RETURN_Z3(of_ast(a));
- Z3_CATCH_RETURN(0);
- }
-
- Z3_ast Z3_API Z3_mk_unsigned_int(Z3_context c, unsigned value, Z3_sort ty) {
- Z3_TRY;
- LOG_Z3_mk_unsigned_int(c, value, ty);
- RESET_ERROR_CODE();
+ RESET_ERROR_CODE();
if (!check_numeral_sort(c, ty)) {
RETURN_Z3(0);
}
@@ -97,11 +101,23 @@ extern "C" {
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(0);
}
-
+
+ Z3_ast Z3_API Z3_mk_unsigned_int(Z3_context c, unsigned value, Z3_sort ty) {
+ Z3_TRY;
+ LOG_Z3_mk_unsigned_int(c, value, ty);
+ RESET_ERROR_CODE();
+ if (!check_numeral_sort(c, ty)) {
+ RETURN_Z3(0);
+ }
+ ast * a = mk_c(c)->mk_numeral_core(rational(value), to_sort(ty));
+ RETURN_Z3(of_ast(a));
+ Z3_CATCH_RETURN(0);
+ }
+
Z3_ast Z3_API Z3_mk_int64(Z3_context c, long long value, Z3_sort ty) {
Z3_TRY;
LOG_Z3_mk_int64(c, value, ty);
- RESET_ERROR_CODE();
+ RESET_ERROR_CODE();
if (!check_numeral_sort(c, ty)) {
RETURN_Z3(0);
}
@@ -110,11 +126,11 @@ extern "C" {
RETURN_Z3(of_ast(a));
Z3_CATCH_RETURN(0);
}
-
+
Z3_ast Z3_API Z3_mk_unsigned_int64(Z3_context c, unsigned long long value, Z3_sort ty) {
Z3_TRY;
LOG_Z3_mk_unsigned_int64(c, value, ty);
- RESET_ERROR_CODE();
+ RESET_ERROR_CODE();
if (!check_numeral_sort(c, ty)) {
RETURN_Z3(0);
}
@@ -129,9 +145,11 @@ extern "C" {
LOG_Z3_is_numeral_ast(c, a);
RESET_ERROR_CODE();
expr* e = to_expr(a);
- return
+ return
mk_c(c)->autil().is_numeral(e) ||
- mk_c(c)->bvutil().is_numeral(e);
+ mk_c(c)->bvutil().is_numeral(e) ||
+ mk_c(c)->fpa_util().is_numeral(e) ||
+ mk_c(c)->fpa_util().is_rm_numeral(e);
Z3_CATCH_RETURN(Z3_FALSE);
}
@@ -172,8 +190,37 @@ extern "C" {
return mk_c(c)->mk_external_string(r.to_string());
}
else {
- SET_ERROR_CODE(Z3_INVALID_ARG);
- return "";
+ // floats are separated from all others to avoid huge rationals.
+ fpa_util & fu = mk_c(c)->fpa_util();
+ scoped_mpf tmp(fu.fm());
+ mpf_rounding_mode rm;
+ if (mk_c(c)->fpa_util().is_rm_numeral(to_expr(a), rm)) {
+ switch (rm) {
+ case OP_FPA_RM_NEAREST_TIES_TO_EVEN:
+ return mk_c(c)->mk_external_string("roundNearestTiesToEven");
+ break;
+ case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
+ return mk_c(c)->mk_external_string("roundNearestTiesToAway");
+ break;
+ case OP_FPA_RM_TOWARD_POSITIVE:
+ return mk_c(c)->mk_external_string("roundTowardPositive");
+ break;
+ case OP_FPA_RM_TOWARD_NEGATIVE:
+ return mk_c(c)->mk_external_string("roundTowardNegative");
+ break;
+ case OP_FPA_RM_TOWARD_ZERO:
+ default:
+ return mk_c(c)->mk_external_string("roundTowardZero");
+ break;
+ }
+ }
+ else if (mk_c(c)->fpa_util().is_numeral(to_expr(a), tmp)) {
+ return mk_c(c)->mk_external_string(fu.fm().to_string(tmp));
+ }
+ else {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return "";
+ }
}
Z3_CATCH_RETURN("");
}
diff --git a/src/api/dotnet/AST.cs b/src/api/dotnet/AST.cs
index 7bc4f6dfb..d3b31a325 100644
--- a/src/api/dotnet/AST.cs
+++ b/src/api/dotnet/AST.cs
@@ -227,10 +227,8 @@ namespace Microsoft.Z3
internal override void IncRef(IntPtr o)
{
// Console.WriteLine("AST IncRef()");
- if (Context == null)
- throw new Z3Exception("inc() called on null context");
- if (o == IntPtr.Zero)
- throw new Z3Exception("inc() called on null AST");
+ if (Context == null || o == IntPtr.Zero)
+ return;
Context.AST_DRQ.IncAndClear(Context, o);
base.IncRef(o);
}
@@ -238,10 +236,8 @@ namespace Microsoft.Z3
internal override void DecRef(IntPtr o)
{
// Console.WriteLine("AST DecRef()");
- if (Context == null)
- throw new Z3Exception("dec() called on null context");
- if (o == IntPtr.Zero)
- throw new Z3Exception("dec() called on null AST");
+ if (Context == null || o == IntPtr.Zero)
+ return;
Context.AST_DRQ.Add(o);
base.DecRef(o);
}
diff --git a/src/api/dotnet/ArithExpr.cs b/src/api/dotnet/ArithExpr.cs
index bdfa7a3f0..7858ff3e1 100644
--- a/src/api/dotnet/ArithExpr.cs
+++ b/src/api/dotnet/ArithExpr.cs
@@ -32,11 +32,6 @@ namespace Microsoft.Z3
{
#region Internal
/// Constructor for ArithExpr
- internal protected ArithExpr(Context ctx)
- : base(ctx)
- {
- Contract.Requires(ctx != null);
- }
internal ArithExpr(Context ctx, IntPtr obj)
: base(ctx, obj)
{
diff --git a/src/api/dotnet/ArrayExpr.cs b/src/api/dotnet/ArrayExpr.cs
index 915bfd0f1..e14bb1083 100644
--- a/src/api/dotnet/ArrayExpr.cs
+++ b/src/api/dotnet/ArrayExpr.cs
@@ -32,11 +32,6 @@ namespace Microsoft.Z3
{
#region Internal
/// Constructor for ArrayExpr
- internal protected ArrayExpr(Context ctx)
- : base(ctx)
- {
- Contract.Requires(ctx != null);
- }
internal ArrayExpr(Context ctx, IntPtr obj)
: base(ctx, obj)
{
diff --git a/src/api/dotnet/BitVecExpr.cs b/src/api/dotnet/BitVecExpr.cs
index a146e7a19..b019f8845 100644
--- a/src/api/dotnet/BitVecExpr.cs
+++ b/src/api/dotnet/BitVecExpr.cs
@@ -41,7 +41,6 @@ namespace Microsoft.Z3
#region Internal
/// Constructor for BitVecExpr
- internal protected BitVecExpr(Context ctx) : base(ctx) { Contract.Requires(ctx != null); }
internal BitVecExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); }
#endregion
}
diff --git a/src/api/dotnet/BoolExpr.cs b/src/api/dotnet/BoolExpr.cs
index cbe3b1868..a9a15e4dc 100644
--- a/src/api/dotnet/BoolExpr.cs
+++ b/src/api/dotnet/BoolExpr.cs
@@ -32,8 +32,6 @@ namespace Microsoft.Z3
{
#region Internal
/// Constructor for BoolExpr
- internal protected BoolExpr(Context ctx) : base(ctx) { Contract.Requires(ctx != null); }
- /// Constructor for BoolExpr
internal BoolExpr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); }
#endregion
}
diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs
index 1c03d76b6..1a36a35dc 100644
--- a/src/api/dotnet/Context.cs
+++ b/src/api/dotnet/Context.cs
@@ -3438,6 +3438,805 @@ namespace Microsoft.Z3
}
#endregion
+ #region Floating-Point Arithmetic
+
+ #region Rounding Modes
+ #region RoundingMode Sort
+ ///
+ /// Create the floating-point RoundingMode sort.
+ ///
+ public FPRMSort MkFPRoundingModeSort()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPRMSort(this);
+ }
+ #endregion
+
+ #region Numerals
+ ///
+ /// Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode.
+ ///
+ public FPRMExpr MkFPRoundNearestTiesToEven()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPRMExpr(this, Native.Z3_mk_fpa_round_nearest_ties_to_even(nCtx));
+ }
+
+ ///
+ /// Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode.
+ ///
+ public FPRMNum MkFPRNE()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPRMNum(this, Native.Z3_mk_fpa_rne(nCtx));
+ }
+
+ ///
+ /// Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode.
+ ///
+ public FPRMNum MkFPRoundNearestTiesToAway()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPRMNum(this, Native.Z3_mk_fpa_round_nearest_ties_to_away(nCtx));
+ }
+
+ ///
+ /// Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode.
+ ///
+ public FPRMNum MkFPRNA()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPRMNum(this, Native.Z3_mk_fpa_rna(nCtx));
+ }
+
+ ///
+ /// Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode.
+ ///
+ public FPRMNum MkFPRoundTowardPositive()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_positive(nCtx));
+ }
+
+ ///
+ /// Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode.
+ ///
+ public FPRMNum MkFPRTP()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPRMNum(this, Native.Z3_mk_fpa_rtp(nCtx));
+ }
+
+ ///
+ /// Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode.
+ ///
+ public FPRMNum MkFPRoundTowardNegative()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_negative(nCtx));
+ }
+
+ ///
+ /// Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode.
+ ///
+ public FPRMNum MkFPRTN()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPRMNum(this, Native.Z3_mk_fpa_rtn(nCtx));
+ }
+
+ ///
+ /// Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode.
+ ///
+ public FPRMNum MkFPRoundTowardZero()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_zero(nCtx));
+ }
+
+ ///
+ /// Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode.
+ ///
+ public FPRMNum MkFPRTZ()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPRMNum(this, Native.Z3_mk_fpa_rtz(nCtx));
+ }
+ #endregion
+ #endregion
+
+ #region FloatingPoint Sorts
+ ///
+ /// Create a FloatingPoint sort.
+ ///
+ /// exponent bits in the FloatingPoint sort.
+ /// significand bits in the FloatingPoint sort.
+ public FPSort MkFPSort(uint ebits, uint sbits)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPSort(this, ebits, sbits);
+ }
+
+ ///
+ /// Create the half-precision (16-bit) FloatingPoint sort.
+ ///
+ public FPSort MkFPSortHalf()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPSort(this, Native.Z3_mk_fpa_sort_half(nCtx));
+ }
+
+ ///
+ /// Create the half-precision (16-bit) FloatingPoint sort.
+ ///
+ public FPSort MkFPSort16()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPSort(this, Native.Z3_mk_fpa_sort_16(nCtx));
+ }
+
+ ///
+ /// Create the single-precision (32-bit) FloatingPoint sort.
+ ///
+ public FPSort MkFPSortSingle()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPSort(this, Native.Z3_mk_fpa_sort_single(nCtx));
+ }
+
+ ///
+ /// Create the single-precision (32-bit) FloatingPoint sort.
+ ///
+ public FPSort MkFPSort32()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPSort(this, Native.Z3_mk_fpa_sort_32(nCtx));
+ }
+
+ ///
+ /// Create the double-precision (64-bit) FloatingPoint sort.
+ ///
+ public FPSort MkFPSortDouble()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPSort(this, Native.Z3_mk_fpa_sort_double(nCtx));
+ }
+
+ ///
+ /// Create the double-precision (64-bit) FloatingPoint sort.
+ ///
+ public FPSort MkFPSort64()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPSort(this, Native.Z3_mk_fpa_sort_64(nCtx));
+ }
+
+ ///
+ /// Create the quadruple-precision (128-bit) FloatingPoint sort.
+ ///
+ public FPSort MkFPSortQuadruple()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPSort(this, Native.Z3_mk_fpa_sort_quadruple(nCtx));
+ }
+
+ ///
+ /// Create the quadruple-precision (128-bit) FloatingPoint sort.
+ ///
+ public FPSort MkFPSort128()
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPSort(this, Native.Z3_mk_fpa_sort_128(nCtx));
+ }
+ #endregion
+
+ #region Numerals
+ ///
+ /// Create a NaN of sort s.
+ ///
+ /// FloatingPoint sort.
+ public FPNum MkFPNaN(FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPNum(this, Native.Z3_mk_fpa_nan(nCtx, s.NativeObject));
+ }
+
+ ///
+ /// Create a floating-point infinity of sort s.
+ ///
+ /// FloatingPoint sort.
+ /// indicates whether the result should be negative.
+ public FPNum MkFPInf(FPSort s, bool negative)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPNum(this, Native.Z3_mk_fpa_inf(nCtx, s.NativeObject, negative ? 1 : 0));
+ }
+
+ ///
+ /// Create a floating-point zero of sort s.
+ ///
+ /// FloatingPoint sort.
+ /// indicates whether the result should be negative.
+ public FPNum MkFPZero(FPSort s, bool negative)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPNum(this, Native.Z3_mk_fpa_zero(nCtx, s.NativeObject, negative ? 1 : 0));
+ }
+
+ ///
+ /// Create a numeral of FloatingPoint sort from a float.
+ ///
+ /// numeral value.
+ /// FloatingPoint sort.
+ public FPNum MkFPNumeral(float v, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPNum(this, Native.Z3_mk_fpa_numeral_float(nCtx, v, s.NativeObject));
+ }
+
+ ///
+ /// Create a numeral of FloatingPoint sort from a float.
+ ///
+ /// numeral value.
+ /// FloatingPoint sort.
+ public FPNum MkFPNumeral(double v, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPNum(this, Native.Z3_mk_fpa_numeral_double(nCtx, v, s.NativeObject));
+ }
+
+ ///
+ /// Create a numeral of FloatingPoint sort from an int.
+ ///
+ /// numeral value.
+ /// FloatingPoint sort.
+ public FPNum MkFPNumeral(int v, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPNum(this, Native.Z3_mk_fpa_numeral_int(nCtx, v, s.NativeObject));
+ }
+
+ ///
+ /// Create a numeral of FloatingPoint sort from a sign bit and two integers.
+ ///
+ /// the sign.
+ /// the significand.
+ /// the exponent.
+ /// FloatingPoint sort.
+ public FPNum MkFPNumeral(bool sgn, uint sig, int exp, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPNum(this, Native.Z3_mk_fpa_numeral_uint_int(nCtx, sgn ? 1 : 0, sig, exp, s.NativeObject));
+ }
+
+ ///
+ /// Create a numeral of FloatingPoint sort from a sign bit and two 64-bit integers.
+ ///
+ /// the sign.
+ /// the significand.
+ /// the exponent.
+ /// FloatingPoint sort.
+ public FPNum MkFPNumeral(bool sgn, UInt64 sig, Int64 exp, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPNum(this, Native.Z3_mk_fpa_numeral_uint64_int64(nCtx, sgn ? 1 : 0, sig, exp, s.NativeObject));
+ }
+
+ ///
+ /// Create a numeral of FloatingPoint sort from a float.
+ ///
+ /// numeral value.
+ /// FloatingPoint sort.
+ public FPNum MkFP(float v, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return MkFPNumeral(v, s);
+ }
+
+ ///
+ /// Create a numeral of FloatingPoint sort from a float.
+ ///
+ /// numeral value.
+ /// FloatingPoint sort.
+ public FPNum MkFP(double v, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return MkFPNumeral(v, s);
+ }
+
+ ///
+ /// Create a numeral of FloatingPoint sort from an int.
+ ///
+ /// numeral value.
+ /// FloatingPoint sort.
+ public FPNum MkFP(int v, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return MkFPNumeral(v, s);
+ }
+
+ ///
+ /// Create a numeral of FloatingPoint sort from a sign bit and two integers.
+ ///
+ /// the sign.
+ /// the exponent.
+ /// the significand.
+ /// FloatingPoint sort.
+ public FPNum MkFP(bool sgn, int exp, uint sig, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return MkFPNumeral(sgn, sig, exp, s);
+ }
+
+ ///
+ /// Create a numeral of FloatingPoint sort from a sign bit and two 64-bit integers.
+ ///
+ /// the sign.
+ /// the exponent.
+ /// the significand.
+ /// FloatingPoint sort.
+ public FPNum MkFP(bool sgn, Int64 exp, UInt64 sig, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return MkFPNumeral(sgn, sig, exp, s);
+ }
+
+ #endregion
+
+ #region Operators
+ ///
+ /// Floating-point absolute value
+ ///
+ /// floating-point term
+ public FPExpr MkFPAbs(FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_abs(this.nCtx, t.NativeObject));
+ }
+
+ ///
+ /// Floating-point negation
+ ///
+ /// floating-point term
+ public FPExpr MkFPNeg(FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_neg(this.nCtx, t.NativeObject));
+ }
+
+ ///
+ /// Floating-point addition
+ ///
+ /// rounding mode term
+ /// floating-point term
+ /// floating-point term
+ public FPExpr MkFPAdd(FPRMExpr rm, FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_add(this.nCtx, rm.NativeObject, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Floating-point subtraction
+ ///
+ /// rounding mode term
+ /// floating-point term
+ /// floating-point term
+ public FPExpr MkFPSub(FPRMExpr rm, FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_sub(this.nCtx, rm.NativeObject, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Floating-point multiplication
+ ///
+ /// rounding mode term
+ /// floating-point term
+ /// floating-point term
+ public FPExpr MkFPMul(FPRMExpr rm, FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_mul(this.nCtx, rm.NativeObject, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Floating-point division
+ ///
+ /// rounding mode term
+ /// floating-point term
+ /// floating-point term
+ public FPExpr MkFPDiv(FPRMExpr rm, FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_div(this.nCtx, rm.NativeObject, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Floating-point fused multiply-add
+ ///
+ ///
+ /// The result is round((t1 * t2) + t3)
+ ///
+ /// rounding mode term
+ /// floating-point term
+ /// floating-point term
+ /// floating-point term
+ public FPExpr MkFPFMA(FPRMExpr rm, FPExpr t1, FPExpr t2, FPExpr t3)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_fma(this.nCtx, rm.NativeObject, t1.NativeObject, t2.NativeObject, t3.NativeObject));
+ }
+
+ ///
+ /// Floating-point square root
+ ///
+ /// rounding mode term
+ /// floating-point term
+ public FPExpr MkFPSqrt(FPRMExpr rm, FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_sqrt(this.nCtx, rm.NativeObject, t.NativeObject));
+ }
+
+ ///
+ /// Floating-point remainder
+ ///
+ /// floating-point term
+ /// floating-point term
+ public FPExpr MkFPRem(FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_rem(this.nCtx, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Floating-point roundToIntegral. Rounds a floating-point number to
+ /// the closest integer, again represented as a floating-point number.
+ ///
+ /// term of RoundingMode sort
+ /// floating-point term
+ public FPExpr MkFPRoundToIntegral(FPRMExpr rm, FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_round_to_integral(this.nCtx, rm.NativeObject, t.NativeObject));
+ }
+
+ ///
+ /// Minimum of floating-point numbers.
+ ///
+ /// floating-point term
+ /// floating-point term
+ public FPExpr MkFPMin(FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_min(this.nCtx, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Maximum of floating-point numbers.
+ ///
+ /// floating-point term
+ /// floating-point term
+ public FPExpr MkFPMax(FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_max(this.nCtx, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Floating-point less than or equal.
+ ///
+ /// floating-point term
+ /// floating-point term
+ public BoolExpr MkFPLEq(FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_leq(this.nCtx, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Floating-point less than.
+ ///
+ /// floating-point term
+ /// floating-point term
+ public BoolExpr MkFPLt(FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_lt(this.nCtx, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Floating-point greater than or equal.
+ ///
+ /// floating-point term
+ /// floating-point term
+ public BoolExpr MkFPGEq(FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_geq(this.nCtx, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Floating-point greater than.
+ ///
+ /// floating-point term
+ /// floating-point term
+ public BoolExpr MkFPGt(FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_gt(this.nCtx, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Floating-point equality.
+ ///
+ ///
+ /// Note that this is IEEE 754 equality (as opposed to standard =).
+ ///
+ /// floating-point term
+ /// floating-point term
+ public BoolExpr MkFPEq(FPExpr t1, FPExpr t2)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_eq(this.nCtx, t1.NativeObject, t2.NativeObject));
+ }
+
+ ///
+ /// Predicate indicating whether t is a normal floating-point number.
+ ///
+ /// floating-point term
+ public BoolExpr MkFPIsNormal(FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_is_normal(this.nCtx, t.NativeObject));
+ }
+
+ ///
+ /// Predicate indicating whether t is a subnormal floating-point number.
+ ///
+ /// floating-point term
+ public BoolExpr MkFPIsSubnormal(FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_is_subnormal(this.nCtx, t.NativeObject));
+ }
+
+ ///
+ /// Predicate indicating whether t is a floating-point number with zero value, i.e., +0 or -0.
+ ///
+ /// floating-point term
+ public BoolExpr MkFPIsZero(FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_is_zero(this.nCtx, t.NativeObject));
+ }
+
+ ///
+ /// Predicate indicating whether t is a floating-point number representing +oo or -oo.
+ ///
+ /// floating-point term
+ public BoolExpr MkFPIsInfinite(FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_is_infinite(this.nCtx, t.NativeObject));
+ }
+
+ ///
+ /// Predicate indicating whether t is a NaN.
+ ///
+ /// floating-point term
+ public BoolExpr MkFPIsNaN(FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_is_nan(this.nCtx, t.NativeObject));
+ }
+
+ ///
+ /// Predicate indicating whether t is a negative floating-point number.
+ ///
+ /// floating-point term
+ public BoolExpr MkFPIsNegative(FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_is_negative(this.nCtx, t.NativeObject));
+ }
+
+ ///
+ /// Predicate indicating whether t is a positive floating-point number.
+ ///
+ /// floating-point term
+ public BoolExpr MkFPIsPositive(FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BoolExpr(this, Native.Z3_mk_fpa_is_positive(this.nCtx, t.NativeObject));
+ }
+ #endregion
+
+ #region Conversions to FloatingPoint terms
+ ///
+ /// Create an expression of FloatingPoint sort from three bit-vector expressions.
+ ///
+ ///
+ /// This is the operator named `fp' in the SMT FP theory definition.
+ /// Note that sgn is required to be a bit-vector of size 1. Significand and exponent
+ /// are required to be greater than 1 and 2 respectively. The FloatingPoint sort
+ /// of the resulting expression is automatically determined from the bit-vector sizes
+ /// of the arguments.
+ ///
+ /// bit-vector term (of size 1) representing the sign.
+ /// bit-vector term representing the significand.
+ /// bit-vector term representing the exponent.
+ public FPExpr MkFP(BitVecExpr sgn, BitVecExpr sig, BitVecExpr exp)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_fp(this.nCtx, sgn.NativeObject, sig.NativeObject, exp.NativeObject));
+ }
+
+ ///
+ /// Conversion of a single IEEE 754-2008 bit-vector into a floating-point number.
+ ///
+ ///
+ /// Produces a term that represents the conversion of a bit-vector term bv to a
+ /// floating-point term of sort s. The bit-vector size of bv (m) must be equal
+ /// to ebits+sbits of s. The format of the bit-vector is as defined by the
+ /// IEEE 754-2008 interchange format.
+ ///
+ /// bit-vector value (of size m).
+ /// FloatingPoint sort (ebits+sbits == m)
+ public FPExpr MkFPToFP(BitVecExpr bv, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_to_fp_bv(this.nCtx, bv.NativeObject, s.NativeObject));
+ }
+
+ ///
+ /// Conversion of a FloatingPoint term into another term of different FloatingPoint sort.
+ ///
+ ///
+ /// Produces a term that represents the conversion of a floating-point term t to a
+ /// floating-point term of sort s. If necessary, the result will be rounded according
+ /// to rounding mode rm.
+ ///
+ /// RoundingMode term.
+ /// FloatingPoint term.
+ /// FloatingPoint sort.
+ public FPExpr MkFPToFP(FPRMExpr rm, FPExpr t, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_to_fp_float(this.nCtx, rm.NativeObject, t.NativeObject, s.NativeObject));
+ }
+
+ ///
+ /// Conversion of a term of real sort into a term of FloatingPoint sort.
+ ///
+ ///
+ /// Produces a term that represents the conversion of term t of real sort into a
+ /// floating-point term of sort s. If necessary, the result will be rounded according
+ /// to rounding mode rm.
+ ///
+ /// RoundingMode term.
+ /// term of Real sort.
+ /// FloatingPoint sort.
+ public FPExpr MkFPToFP(FPRMExpr rm, RealExpr t, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_to_fp_real(this.nCtx, rm.NativeObject, t.NativeObject, s.NativeObject));
+ }
+
+ ///
+ /// Conversion of a 2's complement signed bit-vector term into a term of FloatingPoint sort.
+ ///
+ ///
+ /// Produces a term that represents the conversion of the bit-vector term t into a
+ /// floating-point term of sort s. The bit-vector t is taken to be in signed
+ /// 2's complement format (when signed==true, otherwise unsigned). If necessary, the
+ /// result will be rounded according to rounding mode rm.
+ ///
+ /// RoundingMode term.
+ /// term of bit-vector sort.
+ /// FloatingPoint sort.
+ /// flag indicating whether t is interpreted as signed or unsigned bit-vector.
+ public FPExpr MkFPToFP(FPRMExpr rm, BitVecExpr t, FPSort s, bool signed)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ if (signed)
+ return new FPExpr(this, Native.Z3_mk_fpa_to_fp_signed(this.nCtx, rm.NativeObject, t.NativeObject, s.NativeObject));
+ else
+ return new FPExpr(this, Native.Z3_mk_fpa_to_fp_unsigned(this.nCtx, rm.NativeObject, t.NativeObject, s.NativeObject));
+ }
+
+ ///
+ /// Conversion of a floating-point number to another FloatingPoint sort s.
+ ///
+ ///
+ /// Produces a term that represents the conversion of a floating-point term t to a different
+ /// FloatingPoint sort s. If necessary, rounding according to rm is applied.
+ ///
+ /// FloatingPoint sort
+ /// floating-point rounding mode term
+ /// floating-point term
+ public FPExpr MkFPToFP(FPSort s, FPRMExpr rm, FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new FPExpr(this, Native.Z3_mk_fpa_to_fp_float(this.nCtx, s.NativeObject, rm.NativeObject, t.NativeObject));
+ }
+ #endregion
+
+ #region Conversions from FloatingPoint terms
+ ///
+ /// Conversion of a floating-point term into a bit-vector.
+ ///
+ ///
+ /// Produces a term that represents the conversion of the floating-poiunt term t into a
+ /// bit-vector term of size sz in 2's complement format (signed when signed==true). If necessary,
+ /// the result will be rounded according to rounding mode rm.
+ ///
+ /// RoundingMode term.
+ /// FloatingPoint term
+ /// Size of the resulting bit-vector.
+ /// Indicates whether the result is a signed or unsigned bit-vector.
+ public BitVecExpr MkFPToBV(FPRMExpr rm, FPExpr t, uint sz, bool signed)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ if (signed)
+ return new BitVecExpr(this, Native.Z3_mk_fpa_to_sbv(this.nCtx, rm.NativeObject, t.NativeObject, sz));
+ else
+ return new BitVecExpr(this, Native.Z3_mk_fpa_to_ubv(this.nCtx, rm.NativeObject, t.NativeObject, sz));
+ }
+
+ ///
+ /// Conversion of a floating-point term into a real-numbered term.
+ ///
+ ///
+ /// Produces a term that represents the conversion of the floating-poiunt term t into a
+ /// real number. Note that this type of conversion will often result in non-linear
+ /// constraints over real terms.
+ ///
+ /// FloatingPoint term
+ public RealExpr MkFPToReal(FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new RealExpr(this, Native.Z3_mk_fpa_to_real(this.nCtx, t.NativeObject));
+ }
+ #endregion
+
+ #region Z3-specific extensions
+ ///
+ /// Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format.
+ ///
+ ///
+ /// The size of the resulting bit-vector is automatically determined. Note that
+ /// IEEE 754-2008 allows multiple different representations of NaN. This conversion
+ /// knows only one NaN and it will always produce the same bit-vector represenatation of
+ /// that NaN.
+ ///
+ /// FloatingPoint term.
+ public BitVecExpr MkFPToIEEEBV(FPExpr t)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BitVecExpr(this, Native.Z3_mk_fpa_to_ieee_bv(this.nCtx, t.NativeObject));
+ }
+
+ ///
+ /// Conversion of a real-sorted significand and an integer-sorted exponent into a term of FloatingPoint sort.
+ ///
+ ///
+ /// Produces a term that represents the conversion of sig * 2^exp into a
+ /// floating-point term of sort s. If necessary, the result will be rounded
+ /// according to rounding mode rm.
+ ///
+ /// RoundingMode term.
+ /// Significand term of Real sort.
+ /// Exponent term of Int sort.
+ /// FloatingPoint sort.
+ public BitVecExpr MkFPToFP(FPRMExpr rm, RealExpr sig, IntExpr exp, FPSort s)
+ {
+ Contract.Ensures(Contract.Result() != null);
+ return new BitVecExpr(this, Native.Z3_mk_fpa_to_fp_real_int(this.nCtx, rm.NativeObject, sig.NativeObject, exp.NativeObject, s.NativeObject));
+ }
+ #endregion
+ #endregion // Floating-point Arithmetic
#region Miscellaneous
///
diff --git a/src/api/dotnet/DatatypeExpr.cs b/src/api/dotnet/DatatypeExpr.cs
index 93cea54f5..ba3a9d478 100644
--- a/src/api/dotnet/DatatypeExpr.cs
+++ b/src/api/dotnet/DatatypeExpr.cs
@@ -32,11 +32,6 @@ namespace Microsoft.Z3
{
#region Internal
/// Constructor for DatatypeExpr
- internal protected DatatypeExpr(Context ctx)
- : base(ctx)
- {
- Contract.Requires(ctx != null);
- }
internal DatatypeExpr(Context ctx, IntPtr obj)
: base(ctx, obj)
{
diff --git a/src/api/dotnet/EnumSort.cs b/src/api/dotnet/EnumSort.cs
index e62043078..f7ba98222 100644
--- a/src/api/dotnet/EnumSort.cs
+++ b/src/api/dotnet/EnumSort.cs
@@ -78,7 +78,7 @@ namespace Microsoft.Z3
#region Internal
internal EnumSort(Context ctx, Symbol name, Symbol[] enumNames)
- : base(ctx)
+ : base(ctx, IntPtr.Zero)
{
Contract.Requires(ctx != null);
Contract.Requires(name != null);
diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs
index f4a63a61b..e3ff27da1 100644
--- a/src/api/dotnet/Expr.cs
+++ b/src/api/dotnet/Expr.cs
@@ -1448,6 +1448,281 @@ namespace Microsoft.Z3
/// Indicates whether the term is a less than predicate over a finite domain.
///
public bool IsFiniteDomainLT { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FD_LT; } }
+ #endregion
+
+ #region Floating-point terms
+ ///
+ /// Indicates whether the terms is of floating-point sort.
+ ///
+ public bool IsFP
+ {
+ get { return Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_sort(Context.nCtx, NativeObject)) == (uint)Z3_sort_kind.Z3_FLOATING_POINT_SORT; }
+ }
+
+ ///
+ /// Indicates whether the terms is of floating-point rounding mode sort.
+ ///
+ public bool IsFPRM
+ {
+ get { return Native.Z3_get_sort_kind(Context.nCtx, Native.Z3_get_sort(Context.nCtx, NativeObject)) == (uint)Z3_sort_kind.Z3_ROUNDING_MODE_SORT; }
+ }
+
+ ///
+ /// Indicates whether the term is a floating-point numeral
+ ///
+ public bool IsFPNumeral { get { return IsFP && IsNumeral; } }
+
+ ///
+ /// Indicates whether the term is a floating-point rounding mode numeral
+ ///
+ public bool IsFPRMNumeral { get { return IsFPRM && IsNumeral; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundNearestTiesToEven
+ ///
+ public bool IsFPRMRoundNearestTiesToEven{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundNearestTiesToAway
+ ///
+ public bool IsFPRMRoundNearestTiesToAway{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardNegative
+ ///
+ public bool IsFPRMRoundTowardNegative{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardPositive
+ ///
+ public bool IsFPRMRoundTowardPositive{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardZero
+ ///
+ public bool IsFPRMRoundTowardZero{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundNearestTiesToEven
+ ///
+ public bool IsFPRMExprRNE{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundNearestTiesToAway
+ ///
+ public bool IsFPRMExprRNA { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardNegative
+ ///
+ public bool IsFPRMExprRTN { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardPositive
+ ///
+ public bool IsFPRMExprRTP { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardZero
+ ///
+ public bool IsFPRMExprRTZ { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; } }
+
+ ///
+ /// Indicates whether the term is a floating-point rounding mode numeral
+ ///
+ public bool IsFPRMExpr {
+ get {
+ return IsApp &&
+ (FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY||
+ FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN ||
+ FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE ||
+ FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE ||
+ FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO);
+ }
+ }
+
+ ///
+ /// Indicates whether the term is a floating-point +oo
+ ///
+ public bool IsFPPlusInfinity{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_PLUS_INF; } }
+
+ ///
+ /// Indicates whether the term is a floating-point -oo
+ ///
+ public bool IsFPMinusInfinity{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_MINUS_INF; } }
+
+ ///
+ /// Indicates whether the term is a floating-point NaN
+ ///
+ public bool IsFPNaN { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_NAN; } }
+
+ ///
+ /// Indicates whether the term is a floating-point +zero
+ ///
+ public bool IsFPPlusZero { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_PLUS_ZERO; } }
+
+ ///
+ /// Indicates whether the term is a floating-point -zero
+ ///
+ public bool IsFPMinusZero { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_MINUS_ZERO; } }
+
+ ///
+ /// Indicates whether the term is a floating-point addition term
+ ///
+ public bool IsFPAdd { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_ADD; } }
+
+
+ ///
+ /// Indicates whether the term is a floating-point subtraction term
+ ///
+ public bool IsFPSub { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_SUB; } }
+
+ ///
+ /// Indicates whether the term is a floating-point negation term
+ ///
+ public bool IsFPNeg { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_NEG; } }
+
+ ///
+ /// Indicates whether the term is a floating-point multiplication term
+ ///
+ public bool IsFPMul { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_MUL; } }
+
+ ///
+ /// Indicates whether the term is a floating-point divison term
+ ///
+ public bool IsFPDiv { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_DIV; } }
+
+ ///
+ /// Indicates whether the term is a floating-point remainder term
+ ///
+ public bool IsFPRem { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_REM; } }
+
+ ///
+ /// Indicates whether the term is a floating-point term absolute value term
+ ///
+ public bool IsFPAbs { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_ABS; } }
+
+ ///
+ /// Indicates whether the term is a floating-point minimum term
+ ///
+ public bool IsFPMin { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_MIN; } }
+
+ ///
+ /// Indicates whether the term is a floating-point maximum term
+ ///
+ public bool IsFPMax { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_MAX; } }
+
+ ///
+ /// Indicates whether the term is a floating-point fused multiply-add term
+ ///
+ public bool IsFPFMA { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_FMA; } }
+
+ ///
+ /// Indicates whether the term is a floating-point square root term
+ ///
+ public bool IsFPSqrt { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_SQRT; } }
+
+ ///
+ /// Indicates whether the term is a floating-point roundToIntegral term
+ ///
+ public bool IsFPRoundToIntegral { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_ROUND_TO_INTEGRAL; } }
+
+ ///
+ /// Indicates whether the term is a floating-point equality term
+ ///
+ public bool IsFPEq { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_EQ; } }
+
+ ///
+ /// Indicates whether the term is a floating-point less-than term
+ ///
+ public bool IsFPLt { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_LT; } }
+
+ ///
+ /// Indicates whether the term is a floating-point greater-than term
+ ///
+ public bool IsFPGt { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_GT; } }
+
+ ///
+ /// Indicates whether the term is a floating-point less-than or equal term
+ ///
+ public bool IsFPLe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_LE; } }
+
+ ///
+ /// Indicates whether the term is a floating-point greater-than or erqual term
+ ///
+ public bool IsFPGe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_GE; } }
+
+ ///
+ /// Indicates whether the term is a floating-point isNaN predicate term
+ ///
+ public bool IsFPisNaN { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_IS_NAN; } }
+
+ ///
+ /// Indicates whether the term is a floating-point isInf predicate term
+ ///
+ public bool IsFPisInf { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_IS_INF; } }
+
+ ///
+ /// Indicates whether the term is a floating-point isZero predicate term
+ ///
+ public bool IsFPisZero { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_IS_ZERO; } }
+
+ ///
+ /// Indicates whether the term is a floating-point isNormal term
+ ///
+ public bool IsFPisNormal { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_IS_NORMAL; } }
+
+ ///
+ /// Indicates whether the term is a floating-point isSubnormal predicate term
+ ///
+ public bool IsFPisSubnormal { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_IS_SUBNORMAL; } }
+
+ ///
+ /// Indicates whether the term is a floating-point isNegative predicate term
+ ///
+ public bool IsFPisNegative { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_IS_NEGATIVE; } }
+
+ ///
+ /// Indicates whether the term is a floating-point isPositive predicate term
+ ///
+ public bool IsFPisPositive { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_IS_POSITIVE; } }
+
+ ///
+ /// Indicates whether the term is a floating-point constructor term
+ ///
+ public bool IsFPFP { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_FP; } }
+
+ ///
+ /// Indicates whether the term is a floating-point conversion term
+ ///
+ public bool IsFPToFp { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_TO_FP; } }
+
+ ///
+ /// Indicates whether the term is a floating-point conversion from unsigned bit-vector term
+ ///
+ public bool IsFPToFpUnsigned { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_TO_FP_UNSIGNED; } }
+
+ ///
+ /// Indicates whether the term is a floating-point conversion to unsigned bit-vector term
+ ///
+ public bool IsFPToUBV { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_TO_UBV; } }
+
+ ///
+ /// Indicates whether the term is a floating-point conversion to signed bit-vector term
+ ///
+ public bool IsFPToSBV { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_TO_SBV; } }
+
+ ///
+ /// Indicates whether the term is a floating-point conversion to real term
+ ///
+ public bool IsFPToReal { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_TO_REAL; } }
+
+
+ ///
+ /// Indicates whether the term is a floating-point conversion to IEEE-754 bit-vector term
+ ///
+ public bool IsFPToIEEEBV { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_TO_IEEE_BV; } }
+
#endregion
#endregion
@@ -1489,10 +1764,6 @@ namespace Microsoft.Z3
///
/// Constructor for Expr
///
- internal protected Expr(Context ctx) : base(ctx) { Contract.Requires(ctx != null); }
- ///
- /// Constructor for Expr
- ///
internal protected Expr(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); }
#if DEBUG
@@ -1541,7 +1812,9 @@ namespace Microsoft.Z3
{
case Z3_sort_kind.Z3_INT_SORT: return new IntNum(ctx, obj);
case Z3_sort_kind.Z3_REAL_SORT: return new RatNum(ctx, obj);
- case Z3_sort_kind.Z3_BV_SORT: return new BitVecNum(ctx, obj);
+ case Z3_sort_kind.Z3_BV_SORT: return new BitVecNum(ctx, obj);
+ case Z3_sort_kind.Z3_FLOATING_POINT_SORT: return new FPNum(ctx, obj);
+ case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMNum(ctx, obj);
}
}
@@ -1552,7 +1825,9 @@ namespace Microsoft.Z3
case Z3_sort_kind.Z3_REAL_SORT: return new RealExpr(ctx, obj);
case Z3_sort_kind.Z3_BV_SORT: return new BitVecExpr(ctx, obj);
case Z3_sort_kind.Z3_ARRAY_SORT: return new ArrayExpr(ctx, obj);
- case Z3_sort_kind.Z3_DATATYPE_SORT: return new DatatypeExpr(ctx, obj);
+ case Z3_sort_kind.Z3_DATATYPE_SORT: return new DatatypeExpr(ctx, obj);
+ case Z3_sort_kind.Z3_FLOATING_POINT_SORT: return new FPExpr(ctx, obj);
+ case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMExpr(ctx, obj);
}
return new Expr(ctx, obj);
diff --git a/src/api/dotnet/FPExpr.cs b/src/api/dotnet/FPExpr.cs
new file mode 100644
index 000000000..85fdf2603
--- /dev/null
+++ b/src/api/dotnet/FPExpr.cs
@@ -0,0 +1,52 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPExpr.cs
+
+Abstract:
+
+ Z3 Managed API: Floating Point Expressions
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Z3
+{
+ ///
+ /// FloatingPoint Expressions
+ ///
+ public class FPExpr : Expr
+ {
+ ///
+ /// The number of exponent bits.
+ ///
+ public uint EBits { get { return ((FPSort)Sort).EBits; } }
+
+ ///
+ /// The number of significand bits.
+ ///
+ public uint SBits { get { return ((FPSort)Sort).EBits; } }
+
+ #region Internal
+ /// Constructor for FPExpr
+ internal FPExpr(Context ctx, IntPtr obj)
+ : base(ctx, obj)
+ {
+ Contract.Requires(ctx != null);
+ }
+ #endregion
+ }
+}
diff --git a/src/api/dotnet/FPNum.cs b/src/api/dotnet/FPNum.cs
new file mode 100644
index 000000000..e85687ccf
--- /dev/null
+++ b/src/api/dotnet/FPNum.cs
@@ -0,0 +1,103 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPNum.cs
+
+Abstract:
+
+ Z3 Managed API: Floating Point Numerals
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+using System;
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Z3
+{
+ ///
+ /// FloatiungPoint Numerals
+ ///
+ [ContractVerification(true)]
+ public class FPNum : FPExpr
+ {
+ ///
+ /// Retrieves the sign of a floating-point literal
+ ///
+ ///
+ /// Remarks: returns true if the numeral is negative
+ ///
+ public bool Sign
+ {
+ get
+ {
+ int res = 0;
+ if (Native.Z3_fpa_get_numeral_sign(Context.nCtx, NativeObject, ref res) == 0)
+ throw new Z3Exception("Sign is not a Boolean value");
+ return res != 0;
+ }
+ }
+
+ ///
+ /// The significand value of a floating-point numeral as a string
+ ///
+ ///
+ /// The significand s is always 0 < s < 2.0; the resulting string is long
+ /// enough to represent the real significand precisely.
+ ///
+ public string Significand
+ {
+ get
+ {
+ return Native.Z3_fpa_get_numeral_significand_string(Context.nCtx, NativeObject);
+ }
+ }
+
+ ///
+ /// Return the exponent value of a floating-point numeral as a string
+ ///
+ public string Exponent
+ {
+ get
+ {
+ return Native.Z3_fpa_get_numeral_exponent_string(Context.nCtx, NativeObject);
+ }
+ }
+
+ ///
+ /// Return the exponent value of a floating-point numeral as a signed 64-bit integer
+ ///
+ public Int64 ExponentInt64
+ {
+ get
+ {
+ Int64 result = 0;
+ if (Native.Z3_fpa_get_numeral_exponent_int64(Context.nCtx, NativeObject, ref result) == 0)
+ throw new Z3Exception("Exponent is not a 64 bit integer");
+ return result;
+ }
+ }
+
+ #region Internal
+ internal FPNum(Context ctx, IntPtr obj)
+ : base(ctx, obj)
+ {
+ Contract.Requires(ctx != null);
+ }
+ #endregion
+
+ ///
+ /// Returns a string representation of the numeral.
+ ///
+ public override string ToString()
+ {
+ return Native.Z3_get_numeral_string(Context.nCtx, NativeObject);
+ }
+ }
+}
diff --git a/src/api/dotnet/FPRMExpr.cs b/src/api/dotnet/FPRMExpr.cs
new file mode 100644
index 000000000..896c3e6b9
--- /dev/null
+++ b/src/api/dotnet/FPRMExpr.cs
@@ -0,0 +1,42 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPRMExpr.cs
+
+Abstract:
+
+ Z3 Managed API: Floating Point Expressions over Rounding Modes
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Z3
+{
+ ///
+ /// FloatingPoint RoundingMode Expressions
+ ///
+ public class FPRMExpr : Expr
+ {
+ #region Internal
+ /// Constructor for FPRMExpr
+ internal FPRMExpr(Context ctx, IntPtr obj)
+ : base(ctx, obj)
+ {
+ Contract.Requires(ctx != null);
+ }
+ #endregion
+ }
+}
diff --git a/src/api/dotnet/FPRMNum.cs b/src/api/dotnet/FPRMNum.cs
new file mode 100644
index 000000000..81cff167e
--- /dev/null
+++ b/src/api/dotnet/FPRMNum.cs
@@ -0,0 +1,100 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPRMExpr.cs
+
+Abstract:
+
+ Z3 Managed API: Floating Point Rounding Mode Numerals
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Z3
+{
+ ///
+ /// Floating-point rounding mode numerals
+ ///
+ public class FPRMNum : FPRMExpr
+ {
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundNearestTiesToEven
+ ///
+ public bool isRoundNearestTiesToEven { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundNearestTiesToEven
+ ///
+ public bool isRNE { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundNearestTiesToAway
+ ///
+ public bool isRoundNearestTiesToAway { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundNearestTiesToAway
+ ///
+ public bool isRNA { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardPositive
+ ///
+ public bool isRoundTowardPositive { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardPositive
+ ///
+ public bool isRTP { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardNegative
+ ///
+ public bool isRoundTowardNegative { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardNegative
+ ///
+ public bool isRTN { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardZero
+ ///
+ public bool isRoundTowardZero { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; } }
+
+ ///
+ /// Indicates whether the term is the floating-point rounding numeral roundTowardZero
+ ///
+ public bool isRTZ { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; } }
+
+ ///
+ /// Returns a string representation of the numeral.
+ ///
+ public override string ToString()
+ {
+ return Native.Z3_get_numeral_string(Context.nCtx, NativeObject);
+ }
+
+ #region Internal
+ /// Constructor for FPRMNum
+ internal FPRMNum(Context ctx, IntPtr obj)
+ : base(ctx, obj)
+ {
+ Contract.Requires(ctx != null);
+ }
+ #endregion
+ }
+}
diff --git a/src/api/dotnet/FPRMSort.cs b/src/api/dotnet/FPRMSort.cs
new file mode 100644
index 000000000..1d8334eb5
--- /dev/null
+++ b/src/api/dotnet/FPRMSort.cs
@@ -0,0 +1,43 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPRMSort.cs
+
+Abstract:
+
+ Z3 Managed API: Rounding Mode Sort
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Z3
+{
+ ///
+ /// The FloatingPoint RoundingMode sort
+ ///
+ public class FPRMSort : Sort
+ {
+ #region Internal
+ internal FPRMSort(Context ctx, IntPtr obj)
+ : base(ctx, obj)
+ {
+ Contract.Requires(ctx != null);
+ }
+ internal FPRMSort(Context ctx)
+ : base(ctx, Native.Z3_mk_fpa_rounding_mode_sort(ctx.nCtx))
+ {
+ Contract.Requires(ctx != null);
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/api/dotnet/FPSort.cs b/src/api/dotnet/FPSort.cs
new file mode 100644
index 000000000..e1ad62d49
--- /dev/null
+++ b/src/api/dotnet/FPSort.cs
@@ -0,0 +1,52 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPSort.cs
+
+Abstract:
+
+ Z3 Managed API: Floating Point Sorts
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+using System;
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Z3
+{
+ ///
+ /// FloatingPoint sort
+ ///
+ public class FPSort : Sort
+ {
+ ///
+ /// The number of exponent bits.
+ ///
+ public uint EBits { get { return Native.Z3_fpa_get_ebits(Context.nCtx, NativeObject); } }
+
+ ///
+ /// The number of significand bits.
+ ///
+ public uint SBits { get { return Native.Z3_fpa_get_sbits(Context.nCtx, NativeObject); } }
+
+ #region Internal
+ internal FPSort(Context ctx, IntPtr obj)
+ : base(ctx, obj)
+ {
+ Contract.Requires(ctx != null);
+ }
+ internal FPSort(Context ctx, uint ebits, uint sbits)
+ : base(ctx, Native.Z3_mk_fpa_sort(ctx.nCtx, ebits, sbits))
+ {
+ Contract.Requires(ctx != null);
+ }
+ #endregion
+ }
+}
diff --git a/src/api/dotnet/IntExpr.cs b/src/api/dotnet/IntExpr.cs
index 4c52ec79f..622be7bd5 100644
--- a/src/api/dotnet/IntExpr.cs
+++ b/src/api/dotnet/IntExpr.cs
@@ -1,5 +1,5 @@
/*++
-Copyright () 2012 Microsoft Corporation
+Copyright (c) 2012 Microsoft Corporation
Module Name:
@@ -32,11 +32,6 @@ namespace Microsoft.Z3
{
#region Internal
/// Constructor for IntExpr
- internal protected IntExpr(Context ctx)
- : base(ctx)
- {
- Contract.Requires(ctx != null);
- }
internal IntExpr(Context ctx, IntPtr obj)
: base(ctx, obj)
{
diff --git a/src/api/dotnet/ListSort.cs b/src/api/dotnet/ListSort.cs
index 7dbafb385..e860e4d4b 100644
--- a/src/api/dotnet/ListSort.cs
+++ b/src/api/dotnet/ListSort.cs
@@ -113,9 +113,9 @@ namespace Microsoft.Z3
}
}
- #region Internal
+ #region Internal
internal ListSort(Context ctx, Symbol name, Sort elemSort)
- : base(ctx)
+ : base(ctx, IntPtr.Zero)
{
Contract.Requires(ctx != null);
Contract.Requires(name != null);
diff --git a/src/api/dotnet/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj
index 36bd6ad02..2b5e08173 100644
--- a/src/api/dotnet/Microsoft.Z3.csproj
+++ b/src/api/dotnet/Microsoft.Z3.csproj
@@ -342,6 +342,12 @@
+
+
+
+
+
+
diff --git a/src/api/dotnet/Quantifier.cs b/src/api/dotnet/Quantifier.cs
index f59d0bda2..38e435309 100644
--- a/src/api/dotnet/Quantifier.cs
+++ b/src/api/dotnet/Quantifier.cs
@@ -160,7 +160,7 @@ namespace Microsoft.Z3
#region Internal
[ContractVerification(false)] // F: Clousot ForAll decompilation gets confused below. Setting verification off until I fixed the bug
internal Quantifier(Context ctx, bool isForall, Sort[] sorts, Symbol[] names, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null)
- : base(ctx)
+ : base(ctx, IntPtr.Zero)
{
Contract.Requires(ctx != null);
Contract.Requires(sorts != null);
@@ -203,7 +203,7 @@ namespace Microsoft.Z3
[ContractVerification(false)] // F: Clousot ForAll decompilation gets confused below. Setting verification off until I fixed the bug
internal Quantifier(Context ctx, bool isForall, Expr[] bound, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null)
- : base(ctx)
+ : base(ctx, IntPtr.Zero)
{
Contract.Requires(ctx != null);
Contract.Requires(body != null);
diff --git a/src/api/dotnet/RealExpr.cs b/src/api/dotnet/RealExpr.cs
index 26adc1fc6..8ee8c8e76 100644
--- a/src/api/dotnet/RealExpr.cs
+++ b/src/api/dotnet/RealExpr.cs
@@ -32,11 +32,6 @@ namespace Microsoft.Z3
{
#region Internal
/// Constructor for RealExpr
- internal protected RealExpr(Context ctx)
- : base(ctx)
- {
- Contract.Requires(ctx != null);
- }
internal RealExpr(Context ctx, IntPtr obj)
: base(ctx, obj)
{
diff --git a/src/api/dotnet/Sort.cs b/src/api/dotnet/Sort.cs
index 9dc23ea09..412398ddd 100644
--- a/src/api/dotnet/Sort.cs
+++ b/src/api/dotnet/Sort.cs
@@ -116,8 +116,7 @@ namespace Microsoft.Z3
#region Internal
///
/// Sort constructor
- ///
- internal protected Sort(Context ctx) : base(ctx) { Contract.Requires(ctx != null); }
+ ///
internal Sort(Context ctx, IntPtr obj) : base(ctx, obj) { Contract.Requires(ctx != null); }
#if DEBUG
@@ -146,6 +145,8 @@ namespace Microsoft.Z3
case Z3_sort_kind.Z3_UNINTERPRETED_SORT: return new UninterpretedSort(ctx, obj);
case Z3_sort_kind.Z3_FINITE_DOMAIN_SORT: return new FiniteDomainSort(ctx, obj);
case Z3_sort_kind.Z3_RELATION_SORT: return new RelationSort(ctx, obj);
+ case Z3_sort_kind.Z3_FLOATING_POINT_SORT: return new FPSort(ctx, obj);
+ case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMSort(ctx, obj);
default:
throw new Z3Exception("Unknown sort kind");
}
diff --git a/src/api/dotnet/TupleSort.cs b/src/api/dotnet/TupleSort.cs
index 81a0eaf60..ea99f3855 100644
--- a/src/api/dotnet/TupleSort.cs
+++ b/src/api/dotnet/TupleSort.cs
@@ -68,7 +68,7 @@ namespace Microsoft.Z3
#region Internal
internal TupleSort(Context ctx, Symbol name, uint numFields, Symbol[] fieldNames, Sort[] fieldSorts)
- : base(ctx)
+ : base(ctx, IntPtr.Zero)
{
Contract.Requires(ctx != null);
Contract.Requires(name != null);
diff --git a/src/api/java/ArithExpr.java b/src/api/java/ArithExpr.java
index a788fda35..996b98afc 100644
--- a/src/api/java/ArithExpr.java
+++ b/src/api/java/ArithExpr.java
@@ -25,11 +25,6 @@ public class ArithExpr extends Expr
/**
* Constructor for ArithExpr
**/
- protected ArithExpr(Context ctx)
- {
- super(ctx);
- }
-
ArithExpr(Context ctx, long obj) throws Z3Exception
{
super(ctx, obj);
diff --git a/src/api/java/ArrayExpr.java b/src/api/java/ArrayExpr.java
index 34d04693f..154a56af4 100644
--- a/src/api/java/ArrayExpr.java
+++ b/src/api/java/ArrayExpr.java
@@ -26,11 +26,6 @@ public class ArrayExpr extends Expr
/**
* Constructor for ArrayExpr
**/
- protected ArrayExpr(Context ctx)
- {
- super(ctx);
- }
-
ArrayExpr(Context ctx, long obj) throws Z3Exception
{
super(ctx, obj);
diff --git a/src/api/java/BitVecExpr.java b/src/api/java/BitVecExpr.java
index c410e33a6..69a97de40 100644
--- a/src/api/java/BitVecExpr.java
+++ b/src/api/java/BitVecExpr.java
@@ -37,11 +37,6 @@ public class BitVecExpr extends Expr
/**
* Constructor for BitVecExpr
**/
- BitVecExpr(Context ctx)
- {
- super(ctx);
- }
-
BitVecExpr(Context ctx, long obj) throws Z3Exception
{
super(ctx, obj);
diff --git a/src/api/java/DatatypeExpr.java b/src/api/java/DatatypeExpr.java
index 805784642..c0f247b7a 100644
--- a/src/api/java/DatatypeExpr.java
+++ b/src/api/java/DatatypeExpr.java
@@ -25,11 +25,6 @@ public class DatatypeExpr extends Expr
/**
* Constructor for DatatypeExpr
**/
- protected DatatypeExpr(Context ctx)
- {
- super(ctx);
- }
-
DatatypeExpr(Context ctx, long obj) throws Z3Exception
{
super(ctx, obj);
diff --git a/src/api/java/EnumSort.java b/src/api/java/EnumSort.java
index 6176f020a..06e1ade73 100644
--- a/src/api/java/EnumSort.java
+++ b/src/api/java/EnumSort.java
@@ -64,7 +64,7 @@ public class EnumSort extends Sort
EnumSort(Context ctx, Symbol name, Symbol[] enumNames) throws Z3Exception
{
- super(ctx);
+ super(ctx, 0);
int n = enumNames.length;
long[] n_constdecls = new long[n];
diff --git a/src/api/java/FPExpr.java b/src/api/java/FPExpr.java
new file mode 100644
index 000000000..e5193a042
--- /dev/null
+++ b/src/api/java/FPExpr.java
@@ -0,0 +1,41 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPExpr.java
+
+Abstract:
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+package com.microsoft.z3;
+
+/**
+ * FloatingPoint Expressions
+ */
+public class FPExpr extends Expr
+{
+ /**
+ * The number of exponent bits.
+ * @throws Z3Exception
+ */
+ public int getEBits() throws Z3Exception { return ((FPSort)getSort()).getEBits(); }
+
+ /**
+ * The number of significand bits.
+ * @throws Z3Exception
+ */
+ public int getSBits() throws Z3Exception { return ((FPSort)getSort()).getSBits(); }
+
+ public FPExpr(Context ctx, long obj) throws Z3Exception
+ {
+ super(ctx, obj);
+ }
+
+}
diff --git a/src/api/java/FPNum.java b/src/api/java/FPNum.java
new file mode 100644
index 000000000..f2c9b7f98
--- /dev/null
+++ b/src/api/java/FPNum.java
@@ -0,0 +1,86 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPNum.java
+
+Abstract:
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+package com.microsoft.z3;
+
+/**
+ * FloatingPoint Numerals
+ */
+public class FPNum extends FPExpr
+{
+ /**
+ * Retrieves the sign of a floating-point literal
+ * Remarks: returns true if the numeral is negative
+ * @throws Z3Exception
+ */
+ public boolean getSign() throws Z3Exception {
+ Native.IntPtr res = new Native.IntPtr();
+ if (Native.fpaGetNumeralSign(getContext().nCtx(), getNativeObject(), res) ^ true)
+ throw new Z3Exception("Sign is not a Boolean value");
+ return res.value != 0;
+
+
+ }
+
+ /**
+ * The significand value of a floating-point numeral as a string
+ * Remarks: The significand s is always 0 < s < 2.0; the resulting string is long
+ * enough to represent the real significand precisely.
+ * @throws Z3Exception
+ **/
+ public String getSignificand() throws Z3Exception {
+ return Native.fpaGetNumeralSignificandString(getContext().nCtx(), getNativeObject());
+ }
+
+ /**
+ * Return the exponent value of a floating-point numeral as a string
+ * @throws Z3Exception
+ */
+ public String getExponent() throws Z3Exception {
+ return Native.fpaGetNumeralExponentString(getContext().nCtx(), getNativeObject());
+ }
+
+ /**
+ * Return the exponent value of a floating-point numeral as a signed 64-bit integer
+ * @throws Z3Exception
+ */
+ public long getExponentInt64() throws Z3Exception {
+ Native.LongPtr res = new Native.LongPtr();
+ if (Native.fpaGetNumeralExponentInt64(getContext().nCtx(), getNativeObject(), res) ^ true)
+ throw new Z3Exception("Exponent is not a 64 bit integer");
+ return res.value;
+ }
+
+ public FPNum(Context ctx, long obj) throws Z3Exception
+ {
+ super(ctx, obj);
+ }
+
+ /**
+ * Returns a string representation of the numeral.
+ */
+ public String toString()
+ {
+ try
+ {
+ return Native.getNumeralString(getContext().nCtx(), getNativeObject());
+ } catch (Z3Exception e)
+ {
+ return "Z3Exception: " + e.getMessage();
+ }
+ }
+
+}
diff --git a/src/api/java/FPRMExpr.java b/src/api/java/FPRMExpr.java
new file mode 100644
index 000000000..482c3b899
--- /dev/null
+++ b/src/api/java/FPRMExpr.java
@@ -0,0 +1,29 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPRMExpr.java
+
+Abstract:
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+package com.microsoft.z3;
+
+/**
+ * FloatingPoint RoundingMode Expressions
+ */
+public class FPRMExpr extends Expr
+{
+ public FPRMExpr(Context ctx, long obj) throws Z3Exception
+ {
+ super(ctx, obj);
+ }
+
+}
diff --git a/src/api/java/FPRMNum.java b/src/api/java/FPRMNum.java
new file mode 100644
index 000000000..04e7727e2
--- /dev/null
+++ b/src/api/java/FPRMNum.java
@@ -0,0 +1,90 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPRMNum.java
+
+Abstract:
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+package com.microsoft.z3;
+
+import com.microsoft.z3.enumerations.Z3_decl_kind;
+
+/**
+ * FloatingPoint RoundingMode Numerals
+ */
+public class FPRMNum extends FPRMExpr {
+
+ /**
+ * Indicates whether the term is the floating-point rounding numeral roundNearestTiesToEven
+ * @throws Z3Exception
+ * **/
+ public boolean isRoundNearestTiesToEven() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN; }
+
+ /**
+ * Indicates whether the term is the floating-point rounding numeral roundNearestTiesToEven
+ * @throws Z3Exception
+ */
+ public boolean isRNE() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN; }
+
+ /**
+ * Indicates whether the term is the floating-point rounding numeral roundNearestTiesToAway
+ * @throws Z3Exception
+ */
+ public boolean isRoundNearestTiesToAway() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY; }
+
+ /**
+ * Indicates whether the term is the floating-point rounding numeral roundNearestTiesToAway
+ * @throws Z3Exception
+ */
+ public boolean isRNA() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY; }
+
+ /**
+ * Indicates whether the term is the floating-point rounding numeral roundTowardPositive
+ * @throws Z3Exception
+ */
+ public boolean isRoundTowardPositive() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE; }
+
+ /**
+ * Indicates whether the term is the floating-point rounding numeral roundTowardPositive
+ * @throws Z3Exception
+ */
+ public boolean isRTP() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE; }
+
+ /**
+ * Indicates whether the term is the floating-point rounding numeral roundTowardNegative
+ * @throws Z3Exception
+ */
+ public boolean isRoundTowardNegative() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE; }
+
+ /**
+ * Indicates whether the term is the floating-point rounding numeral roundTowardNegative
+ * @throws Z3Exception
+ */
+ public boolean isRTN() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE; }
+
+ /**
+ * Indicates whether the term is the floating-point rounding numeral roundTowardZero
+ * @throws Z3Exception
+ */
+ public boolean isRoundTowardZero() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; }
+
+ /**
+ * Indicates whether the term is the floating-point rounding numeral roundTowardZero
+ * @throws Z3Exception
+ */
+ public boolean isRTZ() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; }
+
+ public FPRMNum(Context ctx, long obj) throws Z3Exception {
+ super(ctx, obj);
+ }
+
+}
diff --git a/src/api/java/FPRMSort.java b/src/api/java/FPRMSort.java
new file mode 100644
index 000000000..ff6422ef6
--- /dev/null
+++ b/src/api/java/FPRMSort.java
@@ -0,0 +1,35 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPRMExpr.java
+
+Abstract:
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+package com.microsoft.z3;
+
+/**
+ * The FloatingPoint RoundingMode sort
+ **/
+public class FPRMSort extends Sort
+{
+
+ public FPRMSort(Context ctx) throws Z3Exception
+ {
+ super(ctx, Native.mkFpaRoundingModeSort(ctx.nCtx()));
+ }
+
+ public FPRMSort(Context ctx, long obj) throws Z3Exception
+ {
+ super(ctx, obj);
+ }
+
+}
\ No newline at end of file
diff --git a/src/api/java/FPSort.java b/src/api/java/FPSort.java
new file mode 100644
index 000000000..284979524
--- /dev/null
+++ b/src/api/java/FPSort.java
@@ -0,0 +1,49 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ FPSort.java
+
+Abstract:
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2013-06-10
+
+Notes:
+
+--*/
+package com.microsoft.z3;
+
+/**
+ * A FloatingPoint sort
+ **/
+public class FPSort extends Sort
+{
+
+ public FPSort(Context ctx, long obj) throws Z3Exception
+ {
+ super(ctx, obj);
+ }
+
+ public FPSort(Context ctx, int ebits, int sbits) throws Z3Exception
+ {
+ super(ctx, Native.mkFpaSort(ctx.nCtx(), ebits, sbits));
+ }
+
+ /**
+ * The number of exponent bits.
+ */
+ public int getEBits() throws Z3Exception {
+ return Native.fpaGetEbits(getContext().nCtx(), getNativeObject());
+ }
+
+ /**
+ * The number of significand bits.
+ */
+ public int getSBits() throws Z3Exception {
+ return Native.fpaGetEbits(getContext().nCtx(), getNativeObject());
+ }
+
+}
diff --git a/src/api/java/IntExpr.java b/src/api/java/IntExpr.java
index 712b950aa..642a58a54 100644
--- a/src/api/java/IntExpr.java
+++ b/src/api/java/IntExpr.java
@@ -26,11 +26,6 @@ public class IntExpr extends ArithExpr
* Constructor for IntExpr
* @throws Z3Exception on error
**/
- protected IntExpr(Context ctx) throws Z3Exception
- {
- super(ctx);
- }
-
IntExpr(Context ctx, long obj) throws Z3Exception
{
super(ctx, obj);
diff --git a/src/api/java/ListSort.java b/src/api/java/ListSort.java
index 52cb1a179..a7ad0403b 100644
--- a/src/api/java/ListSort.java
+++ b/src/api/java/ListSort.java
@@ -88,7 +88,7 @@ public class ListSort extends Sort
ListSort(Context ctx, Symbol name, Sort elemSort) throws Z3Exception
{
- super(ctx);
+ super(ctx, 0);
Native.LongPtr inil = new Native.LongPtr(), iisnil = new Native.LongPtr();
Native.LongPtr icons = new Native.LongPtr(), iiscons = new Native.LongPtr();
diff --git a/src/api/java/Quantifier.java b/src/api/java/Quantifier.java
index e9aeefcca..58245d723 100644
--- a/src/api/java/Quantifier.java
+++ b/src/api/java/Quantifier.java
@@ -149,7 +149,7 @@ public class Quantifier extends BoolExpr
Expr body, int weight, Pattern[] patterns, Expr[] noPatterns,
Symbol quantifierID, Symbol skolemID) throws Z3Exception
{
- super(ctx);
+ super(ctx, 0);
getContext().checkContextMatch(patterns);
getContext().checkContextMatch(noPatterns);
@@ -185,7 +185,7 @@ public class Quantifier extends BoolExpr
int weight, Pattern[] patterns, Expr[] noPatterns,
Symbol quantifierID, Symbol skolemID) throws Z3Exception
{
- super(ctx);
+ super(ctx, 0);
getContext().checkContextMatch(noPatterns);
getContext().checkContextMatch(patterns);
diff --git a/src/api/java/RealExpr.java b/src/api/java/RealExpr.java
index 3352639bf..579d344e1 100644
--- a/src/api/java/RealExpr.java
+++ b/src/api/java/RealExpr.java
@@ -25,11 +25,6 @@ public class RealExpr extends ArithExpr
/**
* Constructor for RealExpr
**/
- protected RealExpr(Context ctx)
- {
- super(ctx);
- }
-
RealExpr(Context ctx, long obj) throws Z3Exception
{
super(ctx, obj);
diff --git a/src/api/java/Sort.java b/src/api/java/Sort.java
index e8043b193..270abd43f 100644
--- a/src/api/java/Sort.java
+++ b/src/api/java/Sort.java
@@ -98,18 +98,9 @@ public class Sort extends AST
/**
* Sort constructor
**/
- protected Sort(Context ctx) throws Z3Exception
- {
- super(ctx);
- {
- }
- }
-
Sort(Context ctx, long obj) throws Z3Exception
{
super(ctx, obj);
- {
- }
}
void checkNativeObject(long obj) throws Z3Exception
@@ -143,6 +134,10 @@ public class Sort extends AST
return new FiniteDomainSort(ctx, obj);
case Z3_RELATION_SORT:
return new RelationSort(ctx, obj);
+ case Z3_FLOATING_POINT_SORT:
+ return new FPSort(ctx, obj);
+ case Z3_ROUNDING_MODE_SORT:
+ return new FPRMSort(ctx, obj);
default:
throw new Z3Exception("Unknown sort kind");
}
diff --git a/src/api/java/TupleSort.java b/src/api/java/TupleSort.java
index 523f8d676..87572b9ee 100644
--- a/src/api/java/TupleSort.java
+++ b/src/api/java/TupleSort.java
@@ -59,7 +59,7 @@ public class TupleSort extends Sort
TupleSort(Context ctx, Symbol name, int numFields, Symbol[] fieldNames,
Sort[] fieldSorts) throws Z3Exception
{
- super(ctx);
+ super(ctx, 0);
Native.LongPtr t = new Native.LongPtr();
setNativeObject(Native.mkTupleSort(ctx.nCtx(), name.getNativeObject(),
diff --git a/src/api/python/z3.py b/src/api/python/z3.py
index bbc9b03ad..fd3d1bdc8 100644
--- a/src/api/python/z3.py
+++ b/src/api/python/z3.py
@@ -555,6 +555,10 @@ def _to_sort_ref(s, ctx):
return ArraySortRef(s, ctx)
elif k == Z3_DATATYPE_SORT:
return DatatypeSortRef(s, ctx)
+ elif k == Z3_FLOATING_POINT_SORT:
+ return FPSortRef(s, ctx)
+ elif k == Z3_ROUNDING_MODE_SORT:
+ return FPRMSortRef(s, ctx)
return SortRef(s, ctx)
def _sort(ctx, a):
@@ -899,6 +903,13 @@ def _to_expr_ref(a, ctx):
return ArrayRef(a, ctx)
if sk == Z3_DATATYPE_SORT:
return DatatypeRef(a, ctx)
+ if sk == Z3_FLOATING_POINT_SORT:
+ if k == Z3_APP_AST and _is_numeral(ctx, a):
+ return FPNumRef(a, ctx)
+ else:
+ return FPRef(a, ctx)
+ if sk == Z3_ROUNDING_MODE_SORT:
+ return FPRMRef(a, ctx)
return ExprRef(a, ctx)
def _coerce_expr_merge(s, a):
@@ -7429,3 +7440,901 @@ def sequence_interpolant(v,p=None,ctx=None):
f = And(Interpolant(f),v[i])
return tree_interpolant(f,p,ctx)
+#########################################
+#
+# Floating-Point Arithmetic
+#
+#########################################
+
+
+# Global default rounding mode
+_dflt_rounding_mode = Z3_OP_FPA_RM_TOWARD_ZERO
+_dflt_fpsort_ebits = 11
+_dflt_fpsort_sbits = 53
+
+def get_default_rounding_mode(ctx=None):
+ """Retrieves the global default rounding mode."""
+ global _dflt_rounding_mode
+ if _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_ZERO:
+ return RTZ(ctx)
+ elif _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_NEGATIVE:
+ return RTN(ctx)
+ elif _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_POSITIVE:
+ return RTP(ctx)
+ elif _dflt_rounding_mode == Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN:
+ return RNE(ctx)
+ elif _dflt_rounding_mode == Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY:
+ return RNA(ctx)
+
+def set_default_rounding_mode(rm, ctx=None):
+ global _dflt_rounding_mode
+ if is_fprm_value(rm):
+ _dflt_rounding_mode = rm.decl().kind()
+ else:
+ _z3_assert(_dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_ZERO or
+ _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_NEGATIVE or
+ _dflt_rounding_mode == Z3_OP_FPA_RM_TOWARD_POSITIVE or
+ _dflt_rounding_mode == Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN or
+ _dflt_rounding_mode == Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY,
+ "illegal rounding mode")
+ _dflt_rounding_mode = rm
+
+def get_default_fp_sort(ctx=None):
+ return FPSort(_dflt_fpsort_ebits, _dflt_fpsort_sbits, ctx)
+
+def set_default_fp_sort(ebits, sbits, ctx=None):
+ global _dflt_fpsort_ebits
+ global _dflt_fpsort_sbits
+ _dflt_fpsort_ebits = ebits
+ _dflt_fpsort_sbits = sbits
+
+def _dflt_rm(ctx=None):
+ return get_default_rounding_mode(ctx)
+
+def _dflt_fps(ctx=None):
+ return get_default_fp_sort(ctx)
+
+### FP Sorts
+
+class FPSortRef(SortRef):
+ """Floating-point sort."""
+
+ def ebits(self):
+ """Retrieves the number of bits reserved for the exponent in the FloatingPoint sort `self`.
+ >>> b = FPSort(8, 24)
+ >>> b.ebits()
+ 8
+ """
+ return int(Z3_fpa_get_ebits(self.ctx_ref(), self.ast))
+
+ def sbits(self):
+ """Retrieves the number of bits reserved for the exponent in the FloatingPoint sort `self`.
+ >>> b = FloatingPointSort(8, 24)
+ >>> b.sbits()
+ 24
+ """
+ return int(Z3_fpa_get_sbits(self.ctx_ref(), self.ast))
+
+ def cast(self, val):
+ """Try to cast `val` as a Floating-point expression
+
+ >>> b = FPSort(8, 24)
+ >>> b.cast(1.0)
+ 1.0
+ >>> b.cast(1.0).sexpr()
+ '1.0'
+ """
+ if is_expr(val):
+ if __debug__:
+ _z3_assert(self.ctx == val.ctx, "Context mismatch")
+ return val
+ else:
+ return FPVal(val, None, self, self.ctx)
+
+
+def Float16(ctx=None):
+ """Floating-point 16-bit (half) sort."""
+ ctx = _get_ctx(ctx)
+ return FPSortRef(Z3_mk_fpa_sort_16(ctx.ref()), ctx)
+
+def FloatHalf(ctx=None):
+ """Floating-point 16-bit (half) sort."""
+ ctx = _get_ctx(ctx)
+ return FPSortRef(Z3_mk_fpa_sort_half(ctx.ref()), ctx)
+
+def Float32(ctx=None):
+ """Floating-point 32-bit (single) sort."""
+ ctx = _get_ctx(ctx)
+ return FPSortRef(Z3_mk_fpa_sort_32(ctx.ref()), ctx)
+
+def FloatSingle(ctx=None):
+ """Floating-point 32-bit (single) sort."""
+ ctx = _get_ctx(ctx)
+ return FPSortRef(Z3_mk_fpa_sort_single(ctx.ref()), ctx)
+
+def Float64(ctx=None):
+ """Floating-point 64-bit (double) sort."""
+ ctx = _get_ctx(ctx)
+ return FPSortRef(Z3_mk_fpa_sort_64(ctx.ref()), ctx)
+
+def FloatSingle(ctx=None):
+ """Floating-point 64-bit (double) sort."""
+ ctx = _get_ctx(ctx)
+ return FPSortRef(Z3_mk_fpa_sort_double(ctx.ref()), ctx)
+
+def Float128(ctx=None):
+ """Floating-point 128-bit (quadruple) sort."""
+ ctx = _get_ctx(ctx)
+ return FPSortRef(Z3_mk_fpa_sort_128(ctx.ref()), ctx)
+
+def FloatSingle(ctx=None):
+ """Floating-point 128-bit (quadruple) sort."""
+ ctx = _get_ctx(ctx)
+ return FPSortRef(Z3_mk_fpa_sort_quadruple(ctx.ref()), ctx)
+
+class FPRMSortRef(SortRef):
+ """"Floating-point rounding mode sort."""
+
+
+def is_fp_sort(s):
+ """Return True if `s` is a Z3 floating-point sort.
+
+ >>> is_fp_sort(FloatingPointSort(8, 24))
+ True
+ >>> is_fp_sort(IntSort())
+ False
+ """
+ return isinstance(s, FPSortRef)
+
+def is_fprm_sort(s):
+ """Return True if `s` is a Z3 floating-point rounding mode sort.
+
+ >>> is_fprm_sort(FPSort(8, 24))
+ False
+ >>> is_fprm_sort()
+ False
+ """
+ return isinstance(s, FPSortRef)
+
+### FP Expressions
+
+class FPRef(ExprRef):
+ """Floating-point expressions."""
+
+ def sort(self):
+ """Return the sort of the floating-point expression `self`.
+
+ >>> x = FP('1.0', FPSort(8, 24))
+ >>> x.sort()
+ (_ FloatingPoint 8 24)
+ >>> x.sort() == FloatingPointSort(8, 24)
+ True
+ """
+ return FPSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx)
+
+ def ebits(self):
+ """Retrieves the number of bits reserved for the exponent in the FloatingPoint expression `self`.
+ >>> b = FloatingPointSort(8, 24)
+ >>> b.ebits()
+ 8
+ """
+ return self.sort().ebits();
+
+ def sbits(self):
+ """Retrieves the number of bits reserved for the exponent in the FloatingPoint expression `self`.
+ >>> b = FloatingPointSort(8, 24)
+ >>> b.sbits()
+ 24
+ """
+ return self.sort().sbits();
+
+ def as_string(self):
+ """Return a Z3 floating point expression as a Python string."""
+ return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
+
+ def __le__(self, other):
+ return fpLEQ(self, other)
+
+ def __lt__(self, other):
+ return fpLEQ(self, other)
+
+ def __ge__(self, other):
+ return fpGEQ(self, other)
+
+ def __gt__(self, other):
+ return fpGT(self, other)
+
+ def __ne__(self, other):
+ return fpNEQ(self, other)
+
+
+ def __add__(self, other):
+ """Create the Z3 expression `self + other`.
+
+ >>> x = FP('x', 8, 24)
+ >>> y = FP('y', 8, 24)
+ >>> x + y
+ x + y
+ >>> (x + y).sort()
+ FloatingPoint(8 24)
+ """
+ a, b = z3._coerce_exprs(self, other)
+ return fpAdd(_dflt_rm(), self, other)
+
+ def __radd__(self, other):
+ """Create the Z3 expression `other + self`.
+
+ >>> x = FP('x', FPSort(8, 24))
+ >>> 10 + x
+ 10 + x
+ """
+ a, b = _coerce_exprs(self, other)
+ return fpAdd(_dflt_rm(), other, self)
+
+ def __sub__(self, other):
+ """Create the Z3 expression `self - other`.
+
+ >>> x = FP('x', 8, 24)
+ >>> y = FP('y', 8, 24)
+ >>> x - y
+ x - y
+ >>> (x - y).sort()
+ FloatingPoint(8 24)
+ """
+ a, b = z3._coerce_exprs(self, other)
+ return fpSub(_dflt_rm(), self, other)
+
+ def __rsub__(self, other):
+ """Create the Z3 expression `other - self`.
+
+ >>> x = FP('x', FPSort(8, 24))
+ >>> 10 - x
+ 10 - x
+ """
+ a, b = _coerce_exprs(self, other)
+ return fpSub(_dflt_rm(), other, self)
+
+ def __mul__(self, other):
+ """Create the Z3 expression `self * other`.
+
+ >>> x = FP('x', 8, 24)
+ >>> y = FP('y', 8, 24)
+ >>> x * y
+ x * y
+ >>> (x * y).sort()
+ FloatingPoint(8 24)
+ """
+ a, b = z3._coerce_exprs(self, other)
+ return fpMul(_dflt_rm(), self, other)
+
+ def __rmul_(self, other):
+ """Create the Z3 expression `other * self`.
+
+ >>> x = FP('x', FPSort(8, 24))
+ >>> 10 * x
+ 10 * x
+ """
+ a, b = _coerce_exprs(self, other)
+ return fpMul(_dflt_rm(), other, self)
+
+ def __pos__(self):
+ """Create the Z3 expression `+self`."""
+ return self
+
+ def __neg__(self):
+ """Create the Z3 expression `-self`."""
+ return FPRef(fpNeg(self))
+
+ def __truediv__(self, other):
+ """Create the Z3 expression division `self / other`."""
+ return self.__div__(other)
+
+ def __rtruediv__(self, other):
+ """Create the Z3 expression division `other / self`."""
+ return self.__rdiv__(other)
+
+ def __mod__(self, other):
+ """Create the Z3 expression mod `self % other`."""
+ return fpRem(self, other)
+
+ def __rmod__(self, other):
+ """Create the Z3 expression mod `other % self`."""
+ return fpRem(other, self)
+
+class FPRMRef(ExprRef):
+ """Floating-point rounding mode expressions"""
+
+ def as_string(self):
+ """Return a Z3 floating point expression as a Python string."""
+ return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
+
+
+def RoundNearestTiesToEven(ctx=None):
+ ctx = _get_ctx(ctx)
+ return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_even(ctx.ref()), ctx)
+
+def RNE (ctx=None):
+ ctx = _get_ctx(ctx)
+ return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_even(ctx.ref()), ctx)
+
+def RoundNearestTiesToAway(ctx=None):
+ ctx = _get_ctx(ctx)
+ return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_away(ctx.ref()), ctx)
+
+def RNA (ctx=None):
+ ctx = _get_ctx(ctx)
+ return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_away(ctx.ref()), ctx)
+
+def RoundTowardPositive(ctx=None):
+ ctx = _get_ctx(ctx)
+ return FPRMRef(Z3_mk_fpa_round_toward_positive(ctx.ref()), ctx)
+
+def RTP(ctx=None):
+ ctx = _get_ctx(ctx)
+ return FPRMRef(Z3_mk_fpa_round_toward_positive(ctx.ref()), ctx)
+
+def RoundTowardNegative(ctx=None):
+ ctx = _get_ctx(ctx)
+ return FPRMRef(Z3_mk_fpa_round_toward_negative(ctx.ref()), ctx)
+
+def RTN(ctx=None):
+ ctx = _get_ctx(ctx)
+ return FPRMRef(Z3_mk_fpa_round_toward_negative(ctx.ref()), ctx)
+
+def RoundTowardZero(ctx=None):
+ ctx = _get_ctx(ctx)
+ return FPRMRef(Z3_mk_fpa_round_toward_zero(ctx.ref()), ctx)
+
+def RTZ(ctx=None):
+ ctx = _get_ctx(ctx)
+ return FPRMRef(Z3_mk_fpa_round_toward_zero(ctx.ref()), ctx)
+
+def is_fprm(a):
+ """Return `True` if `a` is a Z3 floating-point rounding mode expression.
+
+ >>> rm = ?
+ """
+ return isinstance(a, FPRMRef)
+
+def is_fprm_value(a):
+ """Return `True` if `a` is a Z3 floating-point rounding mode numeral value."""
+ return is_fprm(a) and _is_numeral(a.ctx, a.ast)
+
+### FP Numerals
+
+class FPNumRef(FPRef):
+ def isNaN(self):
+ return self.decl().kind() == Z3_OP_FPA_NAN
+
+ def isInf(self):
+ return self.decl().kind() == Z3_OP_FPA_PLUS_INF or self.decl().kind() == Z3_OP_FPA_MINUS_INF
+
+ def isZero(self):
+ return self.decl().kind() == Z3_OP_FPA_PLUS_ZERO or self.decl().kind() == Z3_OP_FPA_MINUS_ZERO
+
+ def isNegative(self):
+ k = self.decl().kind()
+ return (self.num_args() == 0 and (k == Z3_OP_FPA_MINUS_INF or k == Z3_OP_FPA_MINUS_ZERO)) or (self.num_args() == 3 and self.arg(0) == BitVecVal(1))
+
+def _to_fpnum(num, ctx=None):
+ if isinstance(num, FPNum):
+ return num
+ else:
+ return FPNum(num, ctx)
+
+def is_fp(a):
+ """Return `True` if `a` is a Z3 floating-point expression.
+
+ >>> b = FP('b', FPSort(8, 24))
+ >>> is_fp(b)
+ True
+ >>> is_fp(b + 1.0)
+ True
+ >>> is_fp(Int('x'))
+ False
+ """
+ return isinstance(a, FPRef)
+
+def is_fp_value(a):
+ """Return `True` if `a` is a Z3 floating-point numeral value.
+
+ >>> b = FP('b', FPSort(8, 24))
+ >>> is_fp_value(b)
+ False
+ >>> b = FPVal(1.0, FPSort(8, 24))
+ >>> b
+ 1.0p0
+ >>> is_fp_value(b)
+ True
+ """
+ return is_fp(a) and _is_numeral(a.ctx, a.ast)
+
+def FPSort(ebits, sbits, ctx=None):
+ """Return a Z3 floating-point sort of the given sizes. If `ctx=None`, then the global context is used.
+
+ >>> Single = FPSort(8, 24)
+ >>> Double = FPSort(11, 53)
+ >>> Single
+ (_ FloatingPoint 8 24)
+ >>> x = Const('x', Single)
+ >>> eq(x, FP('x', 8, 24))
+ True
+ """
+ ctx = z3._get_ctx(ctx)
+ return FPSortRef(Z3_mk_fpa_sort(ctx.ref(), ebits, sbits), ctx)
+
+def _to_float_str(val):
+ if isinstance(val, float):
+ return str(val)
+ elif isinstance(val, bool):
+ if val:
+ return "1.0"
+ else:
+ return "0.0"
+ elif _is_int(val):
+ return str(val)
+ elif isinstance(val, str):
+ return val
+ if __debug__:
+ _z3_assert(False, "Python value cannot be used as a double")
+
+def fpNaN(s):
+ _z3_assert(isinstance(s, FPSortRef), "sort mismatch")
+ return FPNumRef(Z3_mk_fpa_nan(s.ctx_ref(), s.ast), s.ctx)
+
+def fpPlusInfinity(s):
+ _z3_assert(isinstance(s, FPSortRef), "sort mismatch")
+ return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, False), s.ctx)
+
+def fpMinusInfinity(s):
+ _z3_assert(isinstance(s, FPSortRef), "sort mismatch")
+ return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, True), s.ctx)
+
+def fpInfinity(s, negative):
+ _z3_assert(isinstance(s, FPSortRef), "sort mismatch")
+ _z3_assert(isinstance(negative, bool), "expected Boolean flag")
+ return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, negative), s.ctx)
+
+def fpPlusZero(s):
+ _z3_assert(isinstance(s, FPSortRef), "sort mismatch")
+ return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, False), s.ctx)
+
+def fpMinusZero(s):
+ _z3_assert(isinstance(s, FPSortRef), "sort mismatch")
+ return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, True), s.ctx)
+
+def fpZero(s, negative):
+ _z3_assert(isinstance(s, FPSortRef), "sort mismatch")
+ _z3_assert(isinstance(negative, bool), "expected Boolean flag")
+ return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, negative), s.ctx)
+
+def FPVal(sig, exp=None, fps=None, ctx=None):
+ """Return a floating-point value of value `val` and sort `fps`. If `ctx=None`, then the global context is used.
+
+ >>> v = FPVal(1.0, FPSort(8, 24)))
+ >>> v
+ 1.0
+ >>> print("0x%.8x" % v.as_long())
+ 0x0000000a
+ """
+ ctx = _get_ctx(ctx)
+ if is_fp_sort(exp):
+ fps = exp
+ exp = None
+ elif fps == None:
+ fps = _dflt_fps(ctx)
+ _z3_assert(is_fp_sort(fps), "sort mismatch")
+ if exp == None:
+ exp = 0
+ val = _to_float_str(sig)
+ val = val + 'p'
+ val = val + _to_int_str(exp)
+ return FPNumRef(Z3_mk_numeral(ctx.ref(), val, fps.ast), ctx)
+
+def FP(name, fpsort, ctx=None):
+ """Return a floating-point constant named `name`.
+ `fpsort` is the floating-point sort.
+ If `ctx=None`, then the global context is used.
+
+ >>> x = FP('x', FPSort(8, 24))
+ >>> is_fp(x)
+ True
+ >>> x.ebits()
+ 8
+ >>> x.sort()
+ (_ FloatingPoint 8 24)
+ >>> word = FPSort(8, 24)
+ >>> x2 = FP('x', word)
+ >>> eq(x, x2)
+ True
+ """
+ ctx = fpsort.ctx
+ return FPRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), fpsort.ast), ctx)
+
+def FPs(names, fpsort, ctx=None):
+ """Return an array of floating-point constants.
+
+ >>> x, y, z = BitVecs('x y z', 16)
+ >>> x.size()
+ 16
+ >>> x.sort()
+ BitVec(16)
+ >>> Sum(x, y, z)
+ 0 + x + y + z
+ >>> Product(x, y, z)
+ 1*x*y*z
+ >>> simplify(Product(x, y, z))
+ x*y*z
+ """
+ ctx = z3._get_ctx(ctx)
+ if isinstance(names, str):
+ names = names.split(" ")
+ return [FP(name, fpsort, ctx) for name in names]
+
+def fpAbs(a):
+ """Create a Z3 floating-point absolute value expression.
+
+ >>> s = FPSort(8, 24)
+ >>> rm = FPRM.RNE
+ >>> x = FPVal(1.0, s)
+ >>> fpAbs(x)
+ 1.0
+ >>> x = FPVal(-1.0, s)
+ >>> fpAbs(x)
+ 1.0
+ >>> fpAbs(x).sort()
+ FloatingPoint(8, 24)
+ """
+ if __debug__:
+ _z3_assert(is_fp(a), "First argument must be Z3 floating-point expression")
+ return FPRef(Z3_mk_fpa_abs(a.ctx_ref(), a.as_ast()), a.ctx)
+
+def fpNeg(a):
+ """Create a Z3 floating-point addition expression.
+
+ >>> s = FPSort(8, 24)
+ >>> rm = FPRM.RNE
+ >>> x = FP('x', s)
+ >>> y = FP('y', s)
+ fp.add(rm, x, y)
+ >>> fp.add(rm, x, y).sort()
+ FloatingPoint(8, 24)
+ """
+ if __debug__:
+ _z3_assert(is_fp(a), "First argument must be Z3 floating-point expression")
+ return FPRef(Z3_mk_fpa_neg(a.ctx_ref(), a.as_ast()), a.ctx)
+
+def fpAdd(rm, a, b):
+ """Create a Z3 floating-point addition expression.
+
+ >>> s = FPSort(8, 24)
+ >>> rm = FPRM.RNE
+ >>> x = FP('x', s)
+ >>> y = FP('y', s)
+ fp.add(rm, x, y)
+ >>> fp.add(rm, x, y).sort()
+ FloatingPoint(8, 24)
+ """
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(a) and is_fp(b), "Second and third argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_add(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx)
+
+def fpSub(rm, a, b):
+ """Create a Z3 floating-point subtraction expression.
+
+ >>> s = FPSort(8, 24)
+ >>> rm = FPRM.RNE
+ >>> x = FP('x', s)
+ >>> y = FP('y', s)
+ fp.add(rm, x, y)
+ >>> fp.add(rm, x, y).sort()
+ FloatingPoint(8, 24)
+ """
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(a) and is_fp(b), "Second and third argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_sub(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx)
+
+def fpMul(rm, a, b):
+ """Create a Z3 floating-point multiplication expression.
+
+ >>> s = FPSort(8, 24)
+ >>> rm = FPRM.RNE
+ >>> x = FP('x', s)
+ >>> y = FP('y', s)
+ fp.add(rm, x, y)
+ >>> fp.add(rm, x, y).sort()
+ FloatingPoint(8, 24)
+ """
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(a) and is_fp(b), "Second and third argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_mul(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx)
+
+def fpDiv(rm, a, b):
+ """Create a Z3 floating-point divison expression.
+
+ >>> s = FPSort(8, 24)
+ >>> rm = FPRM.RNE
+ >>> x = FP('x', s)
+ >>> y = FP('y', s)
+ fpAdd(rm, x, y)
+ >>> fp.add(rm, x, y).sort()
+ FloatingPoint(8, 24)
+ """
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(a) and is_fp(b), "Second and third argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_div(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx)
+
+def fpRem(a, b):
+ """Create a Z3 floating-point remainder expression.
+
+ >>> s = FPSort(8, 24)
+ >>> rm = RNE()
+ >>> x = FP('x', s)
+ >>> y = FP('y', s)
+ fpRem(x, y)
+ >>> fpRem(rm, x, y).sort()
+ FloatingPoint(8, 24)
+ """
+ if __debug__:
+ _z3_assert(is_fp(a) and is_fp(b), "Both arguments must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_rem(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
+def fpMin(a, b):
+ """Create a Z3 floating-point minimium expression.
+
+ >>> s = FPSort(8, 24)
+ >>> rm = RNE()
+ >>> x = FP('x', s)
+ >>> y = FP('y', s)
+ fpMin(x, y)
+ >>> fpMin(rm, x, y).sort()
+ FloatingPoint(8, 24)
+ """
+ if __debug__:
+ _z3_assert(is_fp(a) and is_fp(b), "Both arguments must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_min(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
+def fpMax(a, b):
+ """Create a Z3 floating-point maximum expression.
+
+ >>> s = FPSort(8, 24)
+ >>> rm = RNE()
+ >>> x = FP('x', s)
+ >>> y = FP('y', s)
+ fpMin(x, y)
+ >>> fpMin(rm, x, y).sort()
+ FloatingPoint(8, 24)
+ """
+ if __debug__:
+ _z3_assert(is_fp(a) and is_fp(b), "Both arguments must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_max(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
+def fpFMA(rm, a, b, c):
+ """Create a Z3 floating-point fused multiply-add expression.
+ """
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(a) and is_fp(b) and is_fp(c), "Second, third, and fourth argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_fma(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast(), c.as_ast()), rm.ctx)
+
+def fpSqrt(rm, a):
+ """Create a Z3 floating-point square root expression.
+ """
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(a), "Second argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_sqrt(rm.ctx_ref(), rm.as_ast(), a.as_ast()), rm.ctx)
+
+def fpRoundToIntegral(rm, a):
+ """Create a Z3 floating-point roundToIntegral expression.
+ """
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(a), "Second argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_round_to_integral(rm.ctx_ref(), rm.as_ast(), a.as_ast()), rm.ctx)
+
+def fpIsNaN(a):
+ """Create a Z3 floating-point isNaN expression.
+ """
+ if __debug__:
+ _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_is_nan(a.ctx_ref(), a.as_ast()), a.ctx)
+
+def fpIsInfinite(a):
+ """Create a Z3 floating-point isNaN expression.
+ """
+ if __debug__:
+ _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_is_infinite(a.ctx_ref(), a.as_ast()), a.ctx)
+
+def fpIsZero(a):
+ """Create a Z3 floating-point isNaN expression.
+ """
+ if __debug__:
+ _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_is_zero(a.ctx_ref(), a.as_ast()), a.ctx)
+
+def fpIsNormal(a):
+ """Create a Z3 floating-point isNaN expression.
+ """
+ if __debug__:
+ _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_is_normal(a.ctx_ref(), a.as_ast()), a.ctx)
+
+def fpIsSubnormal(a):
+ """Create a Z3 floating-point isNaN expression.
+ """
+ if __debug__:
+ _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_is_subnormal(a.ctx_ref(), a.as_ast()), a.ctx)
+
+def fpIsNegative(a):
+ """Create a Z3 floating-point isNaN expression.
+ """
+ if __debug__:
+ _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_is_negative(a.ctx_ref(), a.as_ast()), a.ctx)
+
+def fpIsPositive(a):
+ """Create a Z3 floating-point isNaN expression.
+ """
+ if __debug__:
+ _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
+ return FPRef(Z3_mk_fpa_is_positive(a.ctx_ref(), a.as_ast()), a.ctx)
+
+def _check_fp_args(a, b):
+ if __debug__:
+ _z3_assert(is_fp(a) or is_fp(b), "At least one of the arguments must be a Z3 floating-point expression")
+
+def fpLT(a, b):
+ """Create the Z3 floating-point expression `other <= self`.
+
+ >>> x, y = FPs('x y', FPSort(8, 24))
+ >>> fpLT(x, y)
+ x <= y
+ >>> (x <= y).sexpr()
+ '?'
+ >>> fpLT(x, y).sexpr()
+ '?'
+ """
+ _check_fp_args(a, b)
+ a, b = _coerce_exprs(a, b)
+ return BoolRef(Z3_mk_fpa_lt(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
+def fpLEQ(a, b):
+ """Create the Z3 floating-point expression `other <= self`.
+
+ >>> x, y = FPs('x y', FPSort(8, 24))
+ >>> fpLEQ(x, y)
+ x <= y
+ >>> (x <= y).sexpr()
+ '?'
+ >>> fpLEQ(x, y).sexpr()
+ '?'
+ """
+ _check_fp_args(a, b)
+ a, b = _coerce_exprs(a, b)
+ return BoolRef(Z3_mk_fpa_leq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
+def fpGT(a, b):
+ """Create the Z3 floating-point expression `other <= self`.
+
+ >>> x, y = FPs('x y', FPSort(8, 24))
+ >>> fpGT(x, y)
+ x <= y
+ >>> (x <= y).sexpr()
+ '?'
+ >>> fpGT(x, y).sexpr()
+ '?'
+ """
+ _check_fp_args(a, b)
+ a, b = _coerce_exprs(a, b)
+ return BoolRef(Z3_mk_fpa_gt(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
+
+def fpGEQ(a, b):
+ """Create the Z3 floating-point expression `other <= self`.
+
+ >>> x, y = FPs('x y', FPSort(8, 24))
+ >>> fp_geq(x, y)
+ x <= y
+ >>> (x <= y).sexpr()
+ '?'
+ >>> fp_geq(x, y).sexpr()
+ '?'
+ """
+ _check_fp_args(a, b)
+ a, b = _coerce_exprs(a, b)
+ return BoolRef(Z3_mk_fpa_geq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
+def fpEQ(a, b):
+ """Create the Z3 floating-point expression `other <= self`.
+
+ >>> x, y = FPs('x y', FPSort(8, 24))
+ >>> fpEQ(x, y)
+ x <= y
+ >>> (x <= y).sexpr()
+ '?'
+ >>> fpEQ(x, y).sexpr()
+ '?'
+ """
+ _check_fp_args(a, b)
+ a, b = _coerce_exprs(a, b)
+ return BoolRef(Z3_mk_fpa_eq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
+def fpNEQ(a, b):
+ """Create the Z3 floating-point expression `other <= self`.
+
+ >>> x, y = FPs('x y', FPSort(8, 24))
+ >>> fpNEQ(x, y)
+ x <= y
+ >>> (x <= y).sexpr()
+ '?'
+ >>> fpNEQ(x, y).sexpr()
+ '?'
+ """
+ _check_fp_args(a, b)
+ a, b = _coerce_exprs(a, b)
+ return Not(BoolRef(Z3_mk_fpa_eq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx), a.ctx)
+
+
+
+def fpFP(sgn, exp, sig):
+ """Create the Z3 floating-point value `fpFP(sgn, sig, exp)` from the three bit-vectorssgn, sig, and exp."""
+ _z3_assert(is_bv(sgn) and is_bv(exp) and is_bv(sig), "sort mismatch")
+ _z3_assert(sgn.sort().size() == 1, "sort mismatch")
+ return FPRef(Z3_mk_fpa_fp(sgn.ctx_ref(), sgn.ast, exp.ast, sig.ast), sgn.ctx)
+
+
+def fpToFP(a1, a2=None, a3=None):
+ """Create a Z3 floating-point conversion expression from other terms."""
+ if is_bv(a1) and is_fp_sort(a2):
+ return FPRef(Z3_mk_fpa_to_fp_bv(a1.ctx_ref(), a1.ast, a2.ast), a1.ctx)
+ elif is_fprm(a1) and is_fp(a2) and is_fp_sort(a3):
+ return FPRef(Z3_mk_fpa_to_fp_float(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx)
+ elif is_fprm(a1) and is_real(a2) and is_fp_sort(a3):
+ return FPRef(Z3_mk_fpa_to_fp_real(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx)
+ elif is_fprm(a1) and is_bv(a2) and is_fp_sort(a3):
+ return FPRef(Z3_mk_fpa_to_fp_signed(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx)
+ else:
+ raise Z3Exception("Unsupported combination of arguments for conversion to floating-point term.")
+
+def fpToFPUnsigned(rm, x, s):
+ """Create a Z3 floating-point conversion expression, from unsigned bit-vector to floating-point expression."""
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_bv(x), "Second argument must be a Z3 bit-vector expression")
+ _z3_assert(is_fp_sort(s), "Third argument must be Z3 floating-point sort")
+ return FPRef(Z3_mk_fpa_to_fp_unsigned(rm.ctx_ref(), rm.ast, x.ast, s.ast), rm.ctx)
+
+def fpToSBV(rm, x, s):
+ """Create a Z3 floating-point conversion expression, from floating-point expression to signed bit-vector."""
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(x), "Second argument must be a Z3 floating-point expression")
+ _z3_assert(is_bv_sort(s), "Third argument must be Z3 bit-vector sort")
+ return FPRef(Z3_mk_fpa_to_sbv(rm.ctx_ref(), rm.ast, x.ast, s.size()), rm.ctx)
+
+def fpToUBV(rm, x, s):
+ """Create a Z3 floating-point conversion expression, from floating-point expression to unsigned bit-vector."""
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(x), "Second argument must be a Z3 floating-point expression")
+ _z3_assert(is_bv_sort(s), "Third argument must be Z3 bit-vector sort")
+ return FPRef(Z3_mk_fpa_to_ubv(rm.ctx_ref(), rm.ast, x.ast, s.size()), rm.ctx)
+
+def fpToReal(x):
+ """Create a Z3 floating-point conversion expression, from floating-point expression to real."""
+ if __debug__:
+ _z3_assert(is_fp(x), "First argument must be a Z3 floating-point expression")
+ return FPRef(Z3_mk_fpa_to_real(x.ctx_ref(), x.ast), x.ctx)
+
+def fpToIEEEBV(x):
+ """Create a Z3 floating-point conversion expression, from floating-point expression to IEEE bit-vector."""
+ if __debug__:
+ _z3_assert(is_fp(x), "First argument must be a Z3 floating-point expression")
+ return FPRef(Z3_mk_fpa_to_ieee_bv(x.ctx_ref(), x.ast), x.ctx)
diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py
index d1d85d30e..ac1607dda 100644
--- a/src/api/python/z3printer.py
+++ b/src/api/python/z3printer.py
@@ -8,6 +8,7 @@
import sys, io, z3
from z3consts import *
from z3core import *
+from ctypes import *
##############################
#
@@ -30,7 +31,7 @@ _z3_op_to_str = {
Z3_OP_BASHR : '>>', Z3_OP_BSHL : '<<', Z3_OP_BLSHR : 'LShR',
Z3_OP_CONCAT : 'Concat', Z3_OP_EXTRACT : 'Extract', Z3_OP_BV2INT : 'BV2Int',
Z3_OP_ARRAY_MAP : 'Map', Z3_OP_SELECT : 'Select', Z3_OP_STORE : 'Store',
- Z3_OP_CONST_ARRAY : 'K'
+ Z3_OP_CONST_ARRAY : 'K'
}
# List of infix operators
@@ -45,17 +46,64 @@ _z3_unary = [ Z3_OP_UMINUS, Z3_OP_BNOT, Z3_OP_BNEG ]
# Precedence
_z3_precedence = {
Z3_OP_POWER : 0,
- Z3_OP_UMINUS : 1, Z3_OP_BNEG : 1, Z3_OP_BNOT : 1,
+ Z3_OP_UMINUS : 1, Z3_OP_BNEG : 1, Z3_OP_BNOT : 1,
Z3_OP_MUL : 2, Z3_OP_DIV : 2, Z3_OP_IDIV : 2, Z3_OP_MOD : 2, Z3_OP_BMUL : 2, Z3_OP_BSDIV : 2, Z3_OP_BSMOD : 2,
- Z3_OP_ADD : 3, Z3_OP_SUB : 3, Z3_OP_BADD : 3, Z3_OP_BSUB : 3,
+ Z3_OP_ADD : 3, Z3_OP_SUB : 3, Z3_OP_BADD : 3, Z3_OP_BSUB : 3,
Z3_OP_BASHR : 4, Z3_OP_BSHL : 4,
Z3_OP_BAND : 5,
Z3_OP_BXOR : 6,
Z3_OP_BOR : 7,
Z3_OP_LE : 8, Z3_OP_LT : 8, Z3_OP_GE : 8, Z3_OP_GT : 8, Z3_OP_EQ : 8, Z3_OP_SLEQ : 8, Z3_OP_SLT : 8, Z3_OP_SGEQ : 8, Z3_OP_SGT : 8,
- Z3_OP_IFF : 8
+ Z3_OP_IFF : 8,
+
+ Z3_OP_FPA_NEG : 1,
+ Z3_OP_FPA_MUL : 2, Z3_OP_FPA_DIV : 2, Z3_OP_FPA_REM : 2, Z3_OP_FPA_FMA : 2,
+ Z3_OP_FPA_ADD: 3, Z3_OP_FPA_SUB : 3,
+ Z3_OP_FPA_LE : 8, Z3_OP_FPA_LT : 8, Z3_OP_FPA_GE : 8, Z3_OP_FPA_GT : 8, Z3_OP_FPA_EQ : 8
}
+# FPA operators
+_z3_op_to_fpa_normal_str = {
+ Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN : 'RoundNearestTiesToEven()', Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY : 'RoundNearestTiesToAway()',
+ Z3_OP_FPA_RM_TOWARD_POSITIVE : 'RoundTowardPositive()', Z3_OP_FPA_RM_TOWARD_NEGATIVE : 'RoundTowardNegative()',
+ Z3_OP_FPA_RM_TOWARD_ZERO : 'RoundTowardZero()',
+ Z3_OP_FPA_PLUS_INF : '+oo', Z3_OP_FPA_MINUS_INF : '-oo',
+ Z3_OP_FPA_NAN : 'NaN', Z3_OP_FPA_PLUS_ZERO : 'PZero', Z3_OP_FPA_MINUS_ZERO : 'NZero',
+ Z3_OP_FPA_ADD : 'fpAdd', Z3_OP_FPA_SUB : 'fpSub', Z3_OP_FPA_NEG : 'fpNeg', Z3_OP_FPA_MUL : 'fpMul',
+ Z3_OP_FPA_DIV : 'fpDiv', Z3_OP_FPA_REM : 'fpRem', Z3_OP_FPA_ABS : 'fpAbs',
+ Z3_OP_FPA_MIN : 'fpMin', Z3_OP_FPA_MAX : 'fpMax',
+ Z3_OP_FPA_FMA : 'fpFMA', Z3_OP_FPA_SQRT : 'fpSqrt', Z3_OP_FPA_ROUND_TO_INTEGRAL : 'fpRoundToIntegral',
+
+ Z3_OP_FPA_EQ : 'fpEQ', Z3_OP_FPA_LT : 'fpLT', Z3_OP_FPA_GT : 'fpGT', Z3_OP_FPA_LE : 'fpLEQ',
+ Z3_OP_FPA_GE : 'fpGEQ',
+
+ Z3_OP_FPA_IS_NAN : 'fpIsNaN', Z3_OP_FPA_IS_INF : 'fpIsInf', Z3_OP_FPA_IS_ZERO : 'fpIsZero',
+ Z3_OP_FPA_IS_NORMAL : 'fpIsNormal', Z3_OP_FPA_IS_SUBNORMAL : 'fpIsSubnormal',
+ Z3_OP_FPA_IS_NEGATIVE : 'fpIsNegative', Z3_OP_FPA_IS_POSITIVE : 'fpIsPositive',
+
+ Z3_OP_FPA_FP : 'fpFP', Z3_OP_FPA_TO_FP : 'fpToFP', Z3_OP_FPA_TO_FP_UNSIGNED: 'fpToFPUnsigned',
+ Z3_OP_FPA_TO_UBV : 'fpToUBV', Z3_OP_FPA_TO_SBV : 'fpToSBV', Z3_OP_FPA_TO_REAL: 'fpToReal',
+ Z3_OP_FPA_TO_IEEE_BV : 'fpToIEEEBV'
+ }
+
+_z3_op_to_fpa_pretty_str = {
+ Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN : 'RNE()', Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY : 'RNA()',
+ Z3_OP_FPA_RM_TOWARD_POSITIVE : 'RTP()', Z3_OP_FPA_RM_TOWARD_NEGATIVE : 'RTN()',
+ Z3_OP_FPA_RM_TOWARD_ZERO : 'RTZ()',
+ Z3_OP_FPA_PLUS_INF : '+oo', Z3_OP_FPA_MINUS_INF : '-oo',
+ Z3_OP_FPA_NAN : 'NaN', Z3_OP_FPA_PLUS_ZERO : '+0.0', Z3_OP_FPA_MINUS_ZERO : '-0.0',
+
+ Z3_OP_FPA_ADD : '+', Z3_OP_FPA_SUB : '-', Z3_OP_FPA_MUL : '*', Z3_OP_FPA_DIV : '/',
+ Z3_OP_FPA_REM : '%', Z3_OP_FPA_NEG : '-',
+
+ Z3_OP_FPA_EQ : 'fpEQ', Z3_OP_FPA_LT : '<', Z3_OP_FPA_GT : '>', Z3_OP_FPA_LE : '<=', Z3_OP_FPA_GE : '>='
+}
+
+_z3_fpa_infix = [
+ Z3_OP_FPA_ADD, Z3_OP_FPA_SUB, Z3_OP_FPA_MUL, Z3_OP_FPA_DIV, Z3_OP_FPA_REM,
+ Z3_OP_FPA_LT, Z3_OP_FPA_GT, Z3_OP_FPA_LE, Z3_OP_FPA_GE
+]
+
def _is_assoc(k):
return k == Z3_OP_BOR or k == Z3_OP_BXOR or k == Z3_OP_BAND or k == Z3_OP_ADD or k == Z3_OP_BADD or k == Z3_OP_MUL or k == Z3_OP_BMUL
@@ -134,10 +182,14 @@ _infix_map = {}
_unary_map = {}
_infix_compact_map = {}
+for (_k,_v) in _z3_op_to_fpa_normal_str.items():
+ _z3_op_to_str[_k] = _v
+
for _k in _z3_infix:
_infix_map[_k] = True
for _k in _z3_unary:
_unary_map[_k] = True
+
for _k in _z3_infix_compact:
_infix_compact_map[_k] = True
@@ -463,6 +515,7 @@ class Formatter:
self.precision = 10
self.ellipses = to_format(_ellipses)
self.max_visited = 10000
+ self.fpa_pretty = False
def pp_ellipses(self):
return self.ellipses
@@ -499,6 +552,8 @@ class Formatter:
return seq1('Array', (self.pp_sort(s.domain()), self.pp_sort(s.range())))
elif isinstance(s, z3.BitVecSortRef):
return seq1('BitVec', (to_format(s.size()), ))
+ elif isinstance(s, z3.FPSortRef):
+ return seq1('FPSort', (to_format(s.ebits()), to_format(s.sbits())))
else:
return to_format(s.name())
@@ -520,6 +575,123 @@ class Formatter:
def pp_bv(self, a):
return to_format(a.as_string())
+ def pp_fprm_value(self, a):
+ z3._z3_assert(z3.is_fprm_value(a), 'expected FPRMNumRef')
+ if self.fpa_pretty and a.decl().kind() in _z3_op_to_fpa_pretty_str:
+ return to_format(_z3_op_to_fpa_pretty_str.get(a.decl().kind()))
+ else:
+ return to_format(_z3_op_to_fpa_normal_str.get(a.decl().kind()))
+
+ def pp_fp_value(self, a):
+ z3._z3_assert(isinstance(a, z3.FPNumRef), 'type mismatch')
+ if not self.fpa_pretty:
+ if (a.isNaN()):
+ return to_format('NaN')
+ elif (a.isInf()):
+ if (a.isNegative()):
+ return to_format('-oo')
+ else:
+ return to_format('+oo')
+ elif (a.isZero()):
+ if (a.isNegative()):
+ return to_format('-zero')
+ else:
+ return to_format('+zero')
+ else:
+ z3._z3_assert(z3.is_fp_value(a), 'expecting FP num ast')
+ r = []
+ sgn = c_long(0)
+ sgnb = Z3_fpa_get_numeral_sign(a.ctx_ref(), a.ast, byref(sgn))
+ sig = Z3_fpa_get_numeral_significand_string(a.ctx_ref(), a.ast)
+ exp = Z3_fpa_get_numeral_exponent_string(a.ctx_ref(), a.ast)
+ r.append(to_format('FPVal('))
+ if not sgnb and sgn:
+ r.append(to_format('-'))
+ r.append(to_format(sig))
+ r.append(to_format('*(2**'))
+ r.append(to_format(exp))
+ r.append(to_format(', '))
+ r.append(to_format(a.sort()))
+ r.append(to_format('))'))
+ return compose(r)
+ else:
+ if (a.isNaN()):
+ return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_FPA_NAN])
+ elif (a.isInf()):
+ if (a.isNegative()):
+ return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_FPA_MINUS_INF])
+ else:
+ return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_FPA_PLUS_INF])
+ elif (a.isZero()):
+ if (a.isNegative()):
+ return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_FPA_MINUS_ZERO])
+ else:
+ return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_FPA_PLUS_ZERO])
+ else:
+ z3._z3_assert(z3.is_fp_value(a), 'expecting FP num ast')
+ r = []
+ sgn = c_long(0)
+ sgnb = Z3_fpa_get_numeral_sign(a.ctx_ref(), a.ast, byref(sgn))
+ sig = Z3_fpa_get_numeral_significand_string(a.ctx_ref(), a.ast)
+ exp = Z3_fpa_get_numeral_exponent_string(a.ctx_ref(), a.ast)
+ if not sgnb and sgn != 0:
+ r.append(to_format('-'))
+ r.append(to_format(sig))
+ if (exp != '0'):
+ r.append(to_format('*(2**'))
+ r.append(to_format(exp))
+ r.append(to_format(')'))
+ return compose(r)
+
+
+ def pp_fp(self, a, d, xs):
+ z3._z3_assert(isinstance(a, z3.FPRef), "type mismatch")
+ k = a.decl().kind()
+ op = '?'
+ if (self.fpa_pretty and k in _z3_op_to_fpa_pretty_str):
+ op = _z3_op_to_fpa_pretty_str[k]
+ elif k in _z3_op_to_fpa_normal_str:
+ op = _z3_op_to_fpa_normal_str[k]
+ elif k in _z3_op_to_str:
+ op = _z3_op_to_str[k]
+
+ n = a.num_args()
+
+ if self.fpa_pretty:
+ if self.is_infix(k) and n >= 3:
+ rm = a.arg(0)
+ if z3.is_fprm_value(rm) and z3._dflt_rm(a.ctx).eq(rm):
+ arg1 = to_format(self.pp_expr(a.arg(1), d+1, xs))
+ arg2 = to_format(self.pp_expr(a.arg(2), d+1, xs))
+ r = []
+ r.append(arg1)
+ r.append(to_format(' '))
+ r.append(to_format(op))
+ r.append(to_format(' '))
+ r.append(arg2)
+ return compose(r)
+ elif k == Z3_OP_FPA_NEG:
+ return compose([to_format('-') , to_format(self.pp_expr(a.arg(0), d+1, xs))])
+
+ if k in _z3_op_to_fpa_normal_str:
+ op = _z3_op_to_fpa_normal_str[k]
+
+ r = []
+ r.append(to_format(op))
+ if not z3.is_const(a):
+ r.append(to_format('('))
+ first = True
+ for c in a.children():
+ if first:
+ first = False
+ else:
+ r.append(to_format(', '))
+ r.append(self.pp_expr(c, d+1, xs))
+ r.append(to_format(')'))
+ return compose(r)
+ else:
+ return to_format(a.as_string())
+
def pp_prefix(self, a, d, xs):
r = []
sz = 0
@@ -678,9 +850,15 @@ class Formatter:
elif z3.is_rational_value(a):
return self.pp_rational(a)
elif z3.is_algebraic_value(a):
- return self.pp_algebraic(a)
+ return self.pp_algebraic(a)
elif z3.is_bv_value(a):
return self.pp_bv(a)
+ elif z3.is_fprm_value(a):
+ return self.pp_fprm_value(a)
+ elif z3.is_fp_value(a):
+ return self.pp_fp_value(a)
+ elif z3.is_fp(a):
+ return self.pp_fp(a, d, xs)
elif z3.is_const(a):
return self.pp_const(a)
else:
@@ -939,6 +1117,12 @@ def set_pp_option(k, v):
else:
set_html_mode(False)
return True
+ if k == 'fpa_pretty':
+ if v:
+ set_fpa_pretty(True)
+ else:
+ set_fpa_pretty(False)
+ return True
val = getattr(_PP, k, None)
if val != None:
z3._z3_assert(type(v) == type(val), "Invalid pretty print option value")
@@ -965,6 +1149,23 @@ def set_html_mode(flag=True):
else:
_Formatter = Formatter()
+def set_fpa_pretty(flag=True):
+ global _Formatter
+ global _z3_op_to_str
+ _Formatter.fpa_pretty = flag
+ if flag:
+ for (_k,_v) in _z3_op_to_fpa_pretty_str.items():
+ _z3_op_to_str[_k] = _v
+ for _k in _z3_fpa_infix:
+ _infix_map[_k] = True
+ else:
+ for (_k,_v) in _z3_op_to_fpa_normal_str.items():
+ _z3_op_to_str[_k] = _v
+ for _k in _z3_fpa_infix:
+ _infix_map[_k] = False
+
+
+
def in_html_mode():
return isinstance(_Formatter, HTMLFormatter)
diff --git a/src/api/z3.h b/src/api/z3.h
index 2ebc20977..bb7611030 100644
--- a/src/api/z3.h
+++ b/src/api/z3.h
@@ -28,6 +28,7 @@ Notes:
#include"z3_polynomial.h"
#include"z3_rcf.h"
#include"z3_interp.h"
+#include"z3_fpa.h"
#undef __in
#undef __out
diff --git a/src/api/z3_api.h b/src/api/z3_api.h
index 71a6dde2b..a4ad8d90d 100644
--- a/src/api/z3_api.h
+++ b/src/api/z3_api.h
@@ -194,6 +194,8 @@ typedef enum
Z3_DATATYPE_SORT,
Z3_RELATION_SORT,
Z3_FINITE_DOMAIN_SORT,
+ Z3_FLOATING_POINT_SORT,
+ Z3_ROUNDING_MODE_SORT,
Z3_UNKNOWN_SORT = 1000
} Z3_sort_kind;
@@ -875,6 +877,90 @@ typedef enum
- Z3_OP_DT_ACCESSOR: datatype accessor.
+ - Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN: Floating-point rounding mode RNE
+
+ - Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY: Floating-point rounding mode RNA
+
+ - Z3_OP_FPA_RM_TOWARD_POSITIVE: Floating-point rounding mode RTP
+
+ - Z3_OP_FPA_RM_TOWARD_NEGATIVE: Floating-point rounding mode RTN
+
+ - Z3_OP_FPA_RM_TOWARD_ZERO: Floating-point rounding mode RTZ
+
+ - Z3_OP_FPA_NUM: Floating-point value
+
+ - Z3_OP_FPA_PLUS_INF: Floating-point +oo
+
+ - Z3_OP_FPA_MINUS_INF: Floating-point -oo
+
+ - Z3_OP_FPA_NAN: Floating-point NaN
+
+ - Z3_OP_FPA_PLUS_ZERO: Floating-point +zero
+
+ - Z3_OP_FPA_MINUS_ZERO: Floating-point -zero
+
+ - Z3_OP_FPA_ADD: Floating-point addition
+
+ - Z3_OP_FPA_SUB: Floating-point subtraction
+
+ - Z3_OP_FPA_NEG: Floating-point negation
+
+ - Z3_OP_FPA_MUL: Floating-point multiplication
+
+ - Z3_OP_FPA_DIV: Floating-point division
+
+ - Z3_OP_FPA_REM: Floating-point remainder
+
+ - Z3_OP_FPA_ABS: Floating-point absolute value
+
+ - Z3_OP_FPA_MIN: Floating-point minimum
+
+ - Z3_OP_FPA_MAX: Floating-point maximum
+
+ - Z3_OP_FPA_FMA: Floating-point fused multiply-add
+
+ - Z3_OP_FPA_SQRT: Floating-point square root
+
+ - Z3_OP_FPA_ROUND_TO_INTEGRAL: Floating-point round to integral
+
+ - Z3_OP_FPA_EQ: Floating-point equality
+
+ - Z3_OP_FPA_LT: Floating-point less than
+
+ - Z3_OP_FPA_GT: Floating-point greater than
+
+ - Z3_OP_FPA_LE: Floating-point less than or equal
+
+ - Z3_OP_FPA_GE: Floating-point greater than or equal
+
+ - Z3_OP_FPA_IS_NAN: Floating-point isNaN
+
+ - Z3_OP_FPA_IS_INF: Floating-point isInfinite
+
+ - Z3_OP_FPA_IS_ZERO: Floating-point isZero
+
+ - Z3_OP_FPA_IS_NORMAL: Floating-point isNormal
+
+ - Z3_OP_FPA_IS_SUBNORMAL: Floating-point isSubnormal
+
+ - Z3_OP_FPA_IS_NEGATIVE: Floating-point isNegative
+
+ - Z3_OP_FPA_IS_POSITIVE: Floating-point isPositive
+
+ - Z3_OP_FPA_FP: Floating-point constructor from 3 bit-vectors
+
+ - Z3_OP_FPA_TO_FP: Floating-point conversion (various)
+
+ - Z3_OP_FPA_TO_FP_UNSIGNED: Floating-point conversion from unsigend bit-vector
+
+ - Z3_OP_FPA_TO_UBV: Floating-point conversion to unsigned bit-vector
+
+ - Z3_OP_FPA_TO_SBV: Floating-point conversion to signed bit-vector
+
+ - Z3_OP_FPA_TO_REAL: Floating-point conversion to real number
+
+ - Z3_OP_FPA_TO_IEEE_BV: Floating-point conversion to IEEE-754 bit-vector
+
- Z3_OP_UNINTERPRETED: kind used for uninterpreted symbols.
*/
typedef enum {
@@ -1056,6 +1142,55 @@ typedef enum {
Z3_OP_DT_RECOGNISER,
Z3_OP_DT_ACCESSOR,
+ // Floating-Point Arithmetic
+ Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN,
+ Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY,
+ Z3_OP_FPA_RM_TOWARD_POSITIVE,
+ Z3_OP_FPA_RM_TOWARD_NEGATIVE,
+ Z3_OP_FPA_RM_TOWARD_ZERO,
+
+ Z3_OP_FPA_NUM,
+ Z3_OP_FPA_PLUS_INF,
+ Z3_OP_FPA_MINUS_INF,
+ Z3_OP_FPA_NAN,
+ Z3_OP_FPA_PLUS_ZERO,
+ Z3_OP_FPA_MINUS_ZERO,
+
+ Z3_OP_FPA_ADD,
+ Z3_OP_FPA_SUB,
+ Z3_OP_FPA_NEG,
+ Z3_OP_FPA_MUL,
+ Z3_OP_FPA_DIV,
+ Z3_OP_FPA_REM,
+ Z3_OP_FPA_ABS,
+ Z3_OP_FPA_MIN,
+ Z3_OP_FPA_MAX,
+ Z3_OP_FPA_FMA,
+ Z3_OP_FPA_SQRT,
+ Z3_OP_FPA_ROUND_TO_INTEGRAL,
+
+ Z3_OP_FPA_EQ,
+ Z3_OP_FPA_LT,
+ Z3_OP_FPA_GT,
+ Z3_OP_FPA_LE,
+ Z3_OP_FPA_GE,
+ Z3_OP_FPA_IS_NAN,
+ Z3_OP_FPA_IS_INF,
+ Z3_OP_FPA_IS_ZERO,
+ Z3_OP_FPA_IS_NORMAL,
+ Z3_OP_FPA_IS_SUBNORMAL,
+ Z3_OP_FPA_IS_NEGATIVE,
+ Z3_OP_FPA_IS_POSITIVE,
+
+ Z3_OP_FPA_FP,
+ Z3_OP_FPA_TO_FP,
+ Z3_OP_FPA_TO_FP_UNSIGNED,
+ Z3_OP_FPA_TO_UBV,
+ Z3_OP_FPA_TO_SBV,
+ Z3_OP_FPA_TO_REAL,
+
+ Z3_OP_FPA_TO_IEEE_BV,
+
Z3_OP_UNINTERPRETED
} Z3_decl_kind;
@@ -1698,8 +1833,7 @@ extern "C" {
/**
\brief Create the real type.
- This type is not a floating point number.
- Z3 does not have support for floating point numbers yet.
+ Note that this type is not a floating point number.
def_API('Z3_mk_real_sort', SORT, (_in(CONTEXT), ))
*/
diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h
new file mode 100644
index 000000000..75002e1a5
--- /dev/null
+++ b/src/api/z3_fpa.h
@@ -0,0 +1,923 @@
+/*++
+Copyright (c) 2013 Microsoft Corporation
+
+Module Name:
+
+ z3_fpa.h
+
+Abstract:
+
+ Additional APIs for floating-point arithmetic (FP).
+
+Author:
+
+ Christoph M. Wintersteiger (cwinter) 2013-06-05
+
+Notes:
+
+--*/
+#ifndef _Z3_FPA_H_
+#define _Z3_FPA_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+ /**
+ \defgroup capi C API
+
+ */
+
+ /*@{*/
+
+ /**
+ @name Floating-Point API
+ */
+ /*@{*/
+
+ /**
+ \brief Create the RoundingMode sort.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_rounding_mode_sort', SORT, (_in(CONTEXT),))
+ */
+ Z3_sort Z3_API Z3_mk_fpa_rounding_mode_sort(__in Z3_context c);
+
+ /**
+ \brief Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_round_nearest_ties_to_even', AST, (_in(CONTEXT),))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_even(__in Z3_context c);
+
+ /**
+ \brief Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_rne', AST, (_in(CONTEXT),))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_rne(__in Z3_context c);
+
+ /**
+ \brief Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_round_nearest_ties_to_away', AST, (_in(CONTEXT),))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_away(__in Z3_context c);
+
+ /**
+ \brief Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_rna', AST, (_in(CONTEXT),))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_rna(__in Z3_context c);
+
+ /**
+ \brief Create a numeral of RoundingMode sort which represents the TowardPositive rounding mode.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_round_toward_positive', AST, (_in(CONTEXT),))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_round_toward_positive(__in Z3_context c);
+
+ /**
+ \brief Create a numeral of RoundingMode sort which represents the TowardPositive rounding mode.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_rtp', AST, (_in(CONTEXT),))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_rtp(__in Z3_context c);
+
+ /**
+ \brief Create a numeral of RoundingMode sort which represents the TowardNegative rounding mode.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_round_toward_negative', AST, (_in(CONTEXT),))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_round_toward_negative(__in Z3_context c);
+
+ /**
+ \brief Create a numeral of RoundingMode sort which represents the TowardNegative rounding mode.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_rtn', AST, (_in(CONTEXT),))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_rtn(__in Z3_context c);
+
+ /**
+ \brief Create a numeral of RoundingMode sort which represents the TowardZero rounding mode.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_round_toward_zero', AST, (_in(CONTEXT),))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_round_toward_zero(__in Z3_context c);
+
+ /**
+ \brief Create a numeral of RoundingMode sort which represents the TowardZero rounding mode.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_rtz', AST, (_in(CONTEXT),))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_rtz(__in Z3_context c);
+
+ /**
+ \brief Create a FloatingPoint sort.
+
+ \param c logical context.
+ \param ebits number of exponent bits.
+ \param sbits number of significand bits.
+
+ \remark ebits must be larger than 1 and sbits must be larger than 2.
+
+ def_API('Z3_mk_fpa_sort', SORT, (_in(CONTEXT), _in(UINT), _in(UINT)))
+ */
+ Z3_sort Z3_API Z3_mk_fpa_sort(__in Z3_context c, __in unsigned ebits, __in unsigned sbits);
+
+ /**
+ \brief Create the half-precision (16-bit) FloatingPoint sort.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_sort_half', SORT, (_in(CONTEXT),))
+ */
+ Z3_sort Z3_API Z3_mk_fpa_sort_half(__in Z3_context c);
+
+ /**
+ \brief Create the half-precision (16-bit) FloatingPoint sort.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_sort_16', SORT, (_in(CONTEXT),))
+ */
+ Z3_sort Z3_API Z3_mk_fpa_sort_16(__in Z3_context c);
+
+ /**
+ \brief Create the single-precision (32-bit) FloatingPoint sort.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_sort_single', SORT, (_in(CONTEXT),))
+ */
+ Z3_sort Z3_API Z3_mk_fpa_sort_single(__in Z3_context c);
+
+ /**
+ \brief Create the single-precision (32-bit) FloatingPoint sort.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_sort_32', SORT, (_in(CONTEXT),))
+ */
+ Z3_sort Z3_API Z3_mk_fpa_sort_32(__in Z3_context c);
+
+ /**
+ \brief Create the double-precision (64-bit) FloatingPoint sort.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_sort_double', SORT, (_in(CONTEXT),))
+ */
+ Z3_sort Z3_API Z3_mk_fpa_sort_double(__in Z3_context c);
+
+ /**
+ \brief Create the double-precision (64-bit) FloatingPoint sort.
+
+ \param c logical context.
+
+ def_API('Z3_mk_fpa_sort_64', SORT, (_in(CONTEXT),))
+ */
+ Z3_sort Z3_API Z3_mk_fpa_sort_64(__in Z3_context c);
+
+ /**
+ \brief Create the quadruple-precision (128-bit) FloatingPoint sort.
+
+ \param c logical context.
+ \param ebits number of exponent bits
+ \param sbits number of significand bits
+
+ \remark ebits must be larger than 1 and sbits must be larger than 2.
+
+ def_API('Z3_mk_fpa_sort_quadruple', SORT, (_in(CONTEXT),))
+ */
+ Z3_sort Z3_API Z3_mk_fpa_sort_quadruple(__in Z3_context c);
+
+ /**
+ \brief Create the quadruple-precision (128-bit) FloatingPoint sort.
+
+ \param c logical context.
+ \param ebits number of exponent bits
+ \param sbits number of significand bits
+
+ \remark ebits must be larger than 1 and sbits must be larger than 2.
+
+ def_API('Z3_mk_fpa_sort_128', SORT, (_in(CONTEXT),))
+ */
+ Z3_sort Z3_API Z3_mk_fpa_sort_128(__in Z3_context c);
+
+ /**
+ \brief Create a floating-point NaN of sort s.
+
+ \param c logical context.
+ \param s target sort
+
+ def_API('Z3_mk_fpa_nan', AST, (_in(CONTEXT),_in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_nan(__in Z3_context c, __in Z3_sort s);
+
+ /**
+ \brief Create a floating-point infinity of sort s.
+
+ \param c logical context.
+ \param s target sort
+ \param negative indicates whether the result should be negative
+
+ When \c negative is true, -oo will be generated instead of +oo.
+
+ def_API('Z3_mk_fpa_inf', AST, (_in(CONTEXT),_in(SORT),_in(BOOL)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_inf(__in Z3_context c, __in Z3_sort s, __in Z3_bool negative);
+
+ /**
+ \brief Create a floating-point zero of sort s.
+
+ \param c logical context.
+ \param s target sort
+ \param negative indicates whether the result should be negative
+
+ When \c negative is true, -zero will be generated instead of +zero.
+
+ def_API('Z3_mk_fpa_zero', AST, (_in(CONTEXT),_in(SORT),_in(BOOL)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_zero(__in Z3_context c, __in Z3_sort s, __in Z3_bool negative);
+
+ /**
+ \brief Create an expression of FloatingPoint sort from three bit-vector expressions.
+
+ This is the operator named `fp' in the SMT FP theory definition.
+ Note that \c sign is required to be a bit-vector of size 1. Significand and exponent
+ are required to be greater than 1 and 2 respectively. The FloatingPoint sort
+ of the resulting expression is automatically determined from the bit-vector sizes
+ of the arguments.
+
+ \params c logical context.
+ \params sgn sign
+ \params exp exponent
+ \params sig significand
+
+ def_API('Z3_mk_fpa_fp', AST, (_in(CONTEXT), _in(AST), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_fp(__in Z3_context c, __in Z3_ast sgn, __in Z3_ast exp, __in Z3_ast sig);
+
+ /**
+ \brief Create a numeral of FloatingPoint sort from a float.
+
+ This function is used to create numerals that fit in a float value.
+ It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string.
+
+ \params c logical context.
+ \params v value.
+ \params ty sort.
+
+ ty must be a FloatingPoint sort
+
+ \sa Z3_mk_numeral
+
+ def_API('Z3_mk_fpa_numeral_float', AST, (_in(CONTEXT), _in(FLOAT), _in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_numeral_float(__in Z3_context c, __in float v, __in Z3_sort ty);
+
+ /**
+ \brief Create a numeral of FloatingPoint sort from a double.
+
+ This function is used to create numerals that fit in a double value.
+ It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string.
+
+ \params c logical context.
+ \params v value.
+ \params ty sort.
+
+ ty must be a FloatingPoint sort
+
+ \sa Z3_mk_numeral
+
+ def_API('Z3_mk_fpa_numeral_double', AST, (_in(CONTEXT), _in(DOUBLE), _in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_numeral_double(__in Z3_context c, __in double v, __in Z3_sort ty);
+
+ /**
+ \brief Create a numeral of FloatingPoint sort from a signed integer.
+
+ \params c logical context.
+ \params v value.
+
+ ty must be a FloatingPoint sort
+
+ \sa Z3_mk_numeral
+
+ def_API('Z3_mk_fpa_numeral_int', AST, (_in(CONTEXT), _in(INT), _in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_numeral_int(__in Z3_context c, __in signed v, Z3_sort ty);
+
+ /**
+ \brief Create a numeral of FloatingPoint sort from a sign bit and two integers.
+
+ \params c logical context.
+ \params sgn sign bit (true == negative).
+ \params sig significand.
+ \params exp exponent.
+
+ ty must be a FloatingPoint sort
+
+ \sa Z3_mk_numeral
+
+ def_API('Z3_mk_fpa_numeral_uint_int', AST, (_in(CONTEXT), _in(BOOL), _in(UINT), _in(INT), _in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_numeral_uint_int(__in Z3_context c, __in Z3_bool sgn, __in unsigned sig, __in signed exp, Z3_sort ty);
+
+ /**
+ \brief Create a numeral of FloatingPoint sort from a sign bit and two 64-bit integers.
+
+ \params c logical context.
+ \params sgn sign bit (true == negative).
+ \params sig significand.
+ \params exp exponent.
+
+ ty must be a FloatingPoint sort
+
+ \sa Z3_mk_numeral
+
+ def_API('Z3_mk_fpa_numeral_uint64_int64', AST, (_in(CONTEXT), _in(BOOL), _in(UINT64), _in(INT64), _in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_numeral_uint64_int64(__in Z3_context c, __in Z3_bool sgn, __in __uint64 sig, __in __int64 exp, Z3_sort ty);
+
+ /**
+ \brief Floating-point absolute value
+
+ \param c logical context.
+ \param t term of FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_abs', AST, (_in(CONTEXT),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_abs(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Floating-point negation
+
+ \param c logical context.
+ \param t term of FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_neg', AST, (_in(CONTEXT),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_neg(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Floating-point addition
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ rm must be of RoundingMode sort, t1 and t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_add', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_add(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Floating-point subtraction
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ rm must be of RoundingMode sort, t1 and t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_sub', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_sub(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Floating-point multiplication
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ rm must be of RoundingMode sort, t1 and t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_mul', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_mul(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Floating-point division
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ The nodes rm must be of RoundingMode sort t1 and t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_div', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_div(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Floating-point fused multiply-add.
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ The result is round((t1 * t2) + t3)
+
+ rm must be of RoundingMode sort, t1, t2, and t3 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_fma', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_fma(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t1, __in Z3_ast t2, __in Z3_ast t3);
+
+ /**
+ \brief Floating-point square root
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t term of FloatingPoint sort.
+
+ rm must be of RoundingMode sort, t must have FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_sqrt', AST, (_in(CONTEXT),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_sqrt(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t);
+
+ /**
+ \brief Floating-point remainder
+
+ \param c logical context.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ t1 and t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_rem', AST, (_in(CONTEXT),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_rem(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Floating-point roundToIntegral. Rounds a floating-point number to
+ the closest integer, again represented as a floating-point number.
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t term of FloatingPoint sort.
+
+ t must be of FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_round_to_integral', AST, (_in(CONTEXT),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_round_to_integral(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t);
+
+ /**
+ \brief Minimum of floating-point numbers.
+
+ \param c logical context.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ t1, t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_min', AST, (_in(CONTEXT),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_min(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Maximum of floating-point numbers.
+
+ \param c logical context.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ t1, t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_max', AST, (_in(CONTEXT),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_max(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Floating-point less than or equal.
+
+ \param c logical context.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ t1 and t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_leq', AST, (_in(CONTEXT),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_leq(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Floating-point less than.
+
+ \param c logical context.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ t1 and t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_lt', AST, (_in(CONTEXT),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_lt(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Floating-point greater than or equal.
+
+ \param c logical context.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ t1 and t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_geq', AST, (_in(CONTEXT),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_geq(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Floating-point greater than.
+
+ \param c logical context.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ t1 and t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_gt', AST, (_in(CONTEXT),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_gt(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Floating-point equality.
+
+ \param c logical context.
+ \param t1 term of FloatingPoint sort.
+ \param t2 term of FloatingPoint sort.
+
+ Note that this is IEEE 754 equality (as opposed to SMT-LIB =).
+
+ t1 and t2 must have the same FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_eq', AST, (_in(CONTEXT),_in(AST),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_eq(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2);
+
+ /**
+ \brief Predicate indicating whether t is a normal floating-point number.
+
+ \param c logical context.
+ \param t term of FloatingPoint sort.
+
+ t must have FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_is_normal', AST, (_in(CONTEXT),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_is_normal(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Predicate indicating whether t is a subnormal floating-point number.
+
+ \param c logical context.
+ \param t term of FloatingPoint sort.
+
+ t must have FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_is_subnormal', AST, (_in(CONTEXT),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_is_subnormal(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Predicate indicating whether t is a floating-point number with zero value, i.e., +zero or -zero.
+
+ \param c logical context.
+ \param t term of FloatingPoint sort.
+
+ t must have FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_is_zero', AST, (_in(CONTEXT),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_is_zero(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Predicate indicating whether t is a floating-point number representing +oo or -oo.
+
+ \param c logical context.
+ \param t term of FloatingPoint sort.
+
+ t must have FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_is_infinite', AST, (_in(CONTEXT),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_is_infinite(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Predicate indicating whether t is a NaN.
+
+ \param c logical context.
+ \param t term of FloatingPoint sort.
+
+ t must have FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_is_nan', AST, (_in(CONTEXT),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_is_nan(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Predicate indicating whether t is a negative floating-point number.
+
+ \param c logical context.
+ \param t term of FloatingPoint sort.
+
+ t must have FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_is_negative', AST, (_in(CONTEXT),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_is_negative(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Predicate indicating whether t is a positive floating-point number.
+
+ \param c logical context.
+ \param t term of FloatingPoint sort.
+
+ t must have FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_is_positive', AST, (_in(CONTEXT),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_is_positive(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Conversion of a single IEEE 754-2008 bit-vector into a floating-point number.
+
+ Produces a term that represents the conversion of a bit-vector term bv to a
+ floating-point term of sort s.
+
+ \param c logical context.
+ \param bv a bit-vector term.
+ \param s floating-point sort.
+
+ s must be a FloatingPoint sort, t must be of bit-vector sort, and the bit-vector
+ size of bv must be equal to ebits+sbits of s. The format of the bit-vector is
+ as defined by the IEEE 754-2008 interchange format.
+
+ def_API('Z3_mk_fpa_to_fp_bv', AST, (_in(CONTEXT),_in(AST),_in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_bv(__in Z3_context c, __in Z3_ast bv, __in Z3_sort s);
+
+ /**
+ \brief Conversion of a FloatingPoint term into another term of different FloatingPoint sort.
+
+ Produces a term that represents the conversion of a floating-point term t to a
+ floating-point term of sort s. If necessary, the result will be rounded according
+ to rounding mode rm.
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t term of FloatingPoint sort.
+ \param s floating-point sort.
+
+ s must be a FloatingPoint sort, rm must be of RoundingMode sort, t must be of floating-point sort.
+
+ def_API('Z3_mk_fpa_to_fp_float', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_float(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t, __in Z3_sort s);
+
+ /**
+ \brief Conversion of a term of real sort into a term of FloatingPoint sort.
+
+ Produces a term that represents the conversion of term t of real sort into a
+ floating-point term of sort s. If necessary, the result will be rounded according
+ to rounding mode rm.
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t term of Real sort.
+ \param s floating-point sort.
+
+ s must be a FloatingPoint sort, rm must be of RoundingMode sort, t must be of real sort.
+
+ def_API('Z3_mk_fpa_to_fp_real', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_real(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t, __in Z3_sort s);
+
+ /**
+ \brief Conversion of a 2's complement signed bit-vector term into a term of FloatingPoint sort.
+
+ Produces a term that represents the conversion of the bit-vector term t into a
+ floating-point term of sort s. The bit-vector t is taken to be in signed
+ 2's complement format. If necessary, the result will be rounded according
+ to rounding mode rm.
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t term of bit-vector sort.
+ \param s floating-point sort.
+
+ s must be a FloatingPoint sort, rm must be of RoundingMode sort, t must be of bit-vector sort.
+
+ def_API('Z3_mk_fpa_to_fp_signed', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_signed(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t, __in Z3_sort s);
+
+ /**
+ \brief Conversion of a 2's complement unsigned bit-vector term into a term of FloatingPoint sort.
+
+ Produces a term that represents the conversion of the bit-vector term t into a
+ floating-point term of sort s. The bit-vector t is taken to be in unsigned
+ 2's complement format. If necessary, the result will be rounded according
+ to rounding mode rm.
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t term of bit-vector sort.
+ \param s floating-point sort.
+
+ s must be a FloatingPoint sort, rm must be of RoundingMode sort, t must be of bit-vector sort.
+
+ def_API('Z3_mk_fpa_to_fp_unsigned', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_unsigned(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t, __in Z3_sort s);
+
+ /**
+ \brief Conversion of a floating-point term into an unsigned bit-vector.
+
+ Produces a term that represents the conversion of the floating-poiunt term t into a
+ bit-vector term of size sz in unsigned 2's complement format. If necessary, the result
+ will be rounded according to rounding mode rm.
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t term of FloatingPoint sort.
+ \param sz size of the resulting bit-vector.
+
+ def_API('Z3_mk_fpa_to_ubv', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(UINT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_to_ubv(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t, __in unsigned sz);
+
+ /**
+ \brief Conversion of a floating-point term into a signed bit-vector.
+
+ Produces a term that represents the conversion of the floating-poiunt term t into a
+ bit-vector term of size sz in signed 2's complement format. If necessary, the result
+ will be rounded according to rounding mode rm.
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param t term of FloatingPoint sort.
+ \param sz size of the resulting bit-vector.
+
+ def_API('Z3_mk_fpa_to_sbv', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(UINT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_to_sbv(__in Z3_context c, __in Z3_ast rm, __in Z3_ast t, __in unsigned sz);
+
+ /**
+ \brief Conversion of a floating-point term into a real-numbered term.
+
+ Produces a term that represents the conversion of the floating-poiunt term t into a
+ real number. Note that this type of conversion will often result in non-linear
+ constraints over real terms.
+
+ \param c logical context.
+ \param t term of FloatingPoint sort.
+
+ def_API('Z3_mk_fpa_to_real', AST, (_in(CONTEXT),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_to_real(__in Z3_context c, __in Z3_ast t);
+
+
+ /**
+ @name Z3-specific extensions
+ */
+ /*@{*/
+
+ /**
+ \brief Retrieves the number of bits reserved for the exponent in a FloatingPoint sort.
+
+ \param s FloatingPoint sort.
+
+ def_API('Z3_fpa_get_ebits', UINT, (_in(CONTEXT),_in(SORT)))
+ */
+ unsigned Z3_API Z3_fpa_get_ebits(__in Z3_context c, __in Z3_sort s);
+
+ /**
+ \brief Retrieves the number of bits reserved for the significand in a FloatingPoint sort.
+
+ \param s FloatingPoint sort.
+
+ def_API('Z3_fpa_get_sbits', UINT, (_in(CONTEXT),_in(SORT)))
+ */
+ unsigned Z3_API Z3_fpa_get_sbits(__in Z3_context c, __in Z3_sort s);
+
+ /**
+ \brief Retrieves the sign of a floating-point literal
+
+ Remarks: sets \c sgn to 0 if the literal is NaN or positive and to 1 otherwise.
+
+ \param t a floating-point numeral.
+
+ def_API('Z3_fpa_get_numeral_sign', BOOL, (_in(CONTEXT), _in(AST), _out(INT)))
+ */
+ Z3_bool Z3_API Z3_fpa_get_numeral_sign(__in Z3_context c, __in Z3_ast t, __out int * sgn);
+
+ /**
+ \brief Return the significand value of a floating-point numeral as a string
+
+ Remarks: The significand s is always 0 < s < 2.0; the resulting string is long
+ enough to represent the real significand precisely.
+
+ \param t a floating-point numeral.
+
+ def_API('Z3_fpa_get_numeral_significand_string', STRING, (_in(CONTEXT), _in(AST)))
+ */
+ Z3_string Z3_API Z3_fpa_get_numeral_significand_string(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Return the exponent value of a floating-point numeral as a string
+
+ \param t a floating-point numeral.
+
+ def_API('Z3_fpa_get_numeral_exponent_string', STRING, (_in(CONTEXT), _in(AST)))
+ */
+ Z3_string Z3_API Z3_fpa_get_numeral_exponent_string(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Return the exponent value of a floating-point numeral as a signed 64-bit integer
+
+ \param t a floating-point numeral.
+
+ def_API('Z3_fpa_get_numeral_exponent_int64', BOOL, (_in(CONTEXT), _in(AST), _out(INT64)))
+ */
+ Z3_bool Z3_API Z3_fpa_get_numeral_exponent_int64(__in Z3_context c, __in Z3_ast t, __out __int64 * n);
+
+ /**
+ \brief Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format.
+
+ \param c logical context.
+ \param t term of FloatingPoint sort.
+
+ t must have FloatingPoint sort. The size of the resulting bit-vector is automatically
+ determined.
+
+ Note that IEEE 754-2008 allows multiple different representations of NaN. This conversion
+ knows only one NaN and it will always produce the same bit-vector represenatation of
+ that NaN.
+
+ def_API('Z3_mk_fpa_to_ieee_bv', AST, (_in(CONTEXT),_in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_to_ieee_bv(__in Z3_context c, __in Z3_ast t);
+
+ /**
+ \brief Conversion of a real-sorted significand and an integer-sorted exponent into a term of FloatingPoint sort.
+
+ Produces a term that represents the conversion of sig * 2^exp into a
+ floating-point term of sort s. If necessary, the result will be rounded
+ according to rounding mode rm.
+
+ \param c logical context.
+ \param rm term of RoundingMode sort.
+ \param sig significand term of Real sort.
+ \param exp exponent term of Int sort.
+ \param s FloatingPoint sort.
+
+ s must be a FloatingPoint sort, rm must be of RoundingMode sort, t must be of real sort.
+
+ def_API('Z3_mk_fpa_to_fp_real_int', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST),_in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_fpa_to_fp_real_int(__in Z3_context c, __in Z3_ast rm, __in Z3_ast sig, __in Z3_ast exp, __in Z3_sort s);
+
+ /*@}*/
+
+ /*@}*/
+ /*@}*/
+
+#ifdef __cplusplus
+};
+#endif // __cplusplus
+
+#endif
diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp
index acdb10bf6..cfd022124 100644
--- a/src/api/z3_replayer.cpp
+++ b/src/api/z3_replayer.cpp
@@ -40,11 +40,12 @@ struct z3_replayer::imp {
__int64 m_int64;
__uint64 m_uint64;
double m_double;
+ float m_float;
size_t m_ptr;
size_t_map m_heap;
svector m_cmds;
- enum value_kind { INT64, UINT64, DOUBLE, STRING, SYMBOL, OBJECT, UINT_ARRAY, SYMBOL_ARRAY, OBJECT_ARRAY };
+ enum value_kind { INT64, UINT64, DOUBLE, STRING, SYMBOL, OBJECT, UINT_ARRAY, SYMBOL_ARRAY, OBJECT_ARRAY, FLOAT };
struct value {
value_kind m_kind;
@@ -54,6 +55,7 @@ struct z3_replayer::imp {
double m_double;
char const * m_str;
void * m_obj;
+ float m_float;
};
value():m_kind(OBJECT), m_int(0) {}
value(void * obj):m_kind(OBJECT), m_obj(obj) {}
@@ -61,6 +63,7 @@ struct z3_replayer::imp {
value(value_kind k, __uint64 u):m_kind(k), m_uint(u) {}
value(value_kind k, __int64 i):m_kind(k), m_int(i) {}
value(value_kind k, double d):m_kind(k), m_double(d) {}
+ value(value_kind k, float f):m_kind(k), m_float(f) {}
};
svector m_args;
@@ -85,9 +88,12 @@ struct z3_replayer::imp {
case UINT64:
out << v.m_uint;
break;
+ case FLOAT:
+ out << v.m_float;
+ break;
case DOUBLE:
out << v.m_double;
- break;
+ break;
case STRING:
out << v.m_str;
break;
@@ -219,6 +225,26 @@ struct z3_replayer::imp {
return curr() == '-' || curr() == '.' || ('0' <= curr() && curr() <= '9') || curr() == 'e' || curr() == 'E';
}
+#if (!defined(strtof))
+ float strtof(const char * str, char ** end_ptr) {
+ // Note: This may introduce a double-rounding problem.
+ return (float)strtod(str, end_ptr);
+ }
+#endif
+
+ void read_float() {
+ m_string.reset();
+ while (is_double_char()) {
+ m_string.push_back(curr());
+ next();
+ }
+ if (m_string.empty())
+ throw z3_replayer_exception("invalid float");
+ m_string.push_back(0);
+ char * ptr;
+ m_float = strtof(m_string.begin(), &ptr);
+ }
+
void read_double() {
m_string.reset();
while (is_double_char()) {
@@ -407,12 +433,18 @@ struct z3_replayer::imp {
TRACE("z3_replayer", tout << "[" << m_line << "] " << "U " << m_uint64 << "\n";);
m_args.push_back(value(UINT64, m_uint64));
break;
+ case 'F':
+ // push float
+ next(); skip_blank(); read_float();
+ TRACE("z3_replayer", tout << "[" << m_line << "] " << "F " << m_float << "\n";);
+ m_args.push_back(value(FLOAT, m_float));
+ break;
case 'D':
// push double
next(); skip_blank(); read_double();
TRACE("z3_replayer", tout << "[" << m_line << "] " << "D " << m_double << "\n";);
m_args.push_back(value(DOUBLE, m_double));
- break;
+ break;
case 'p':
case 's':
case 'u':
@@ -516,6 +548,12 @@ struct z3_replayer::imp {
return m_args[pos].m_uint;
}
+ float get_float(unsigned pos) const {
+ if (pos >= m_args.size() || m_args[pos].m_kind != FLOAT)
+ throw_invalid_reference();
+ return m_args[pos].m_float;
+ }
+
double get_double(unsigned pos) const {
if (pos >= m_args.size() || m_args[pos].m_kind != DOUBLE)
throw_invalid_reference();
@@ -653,6 +691,10 @@ __uint64 z3_replayer::get_uint64(unsigned pos) const {
return m_imp->get_uint64(pos);
}
+float z3_replayer::get_float(unsigned pos) const {
+ return m_imp->get_float(pos);
+}
+
double z3_replayer::get_double(unsigned pos) const {
return m_imp->get_double(pos);
}
diff --git a/src/api/z3_replayer.h b/src/api/z3_replayer.h
index 6de4bdb39..6320068ad 100644
--- a/src/api/z3_replayer.h
+++ b/src/api/z3_replayer.h
@@ -42,6 +42,7 @@ public:
unsigned get_uint(unsigned pos) const;
__int64 get_int64(unsigned pos) const;
__uint64 get_uint64(unsigned pos) const;
+ float get_float(unsigned pos) const;
double get_double(unsigned pos) const;
bool get_bool(unsigned pos) const;
Z3_string get_str(unsigned pos) const;
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index 09965be85..b134d38cb 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -413,16 +413,16 @@ sort * get_sort(expr const * n) {
//
// -----------------------------------
-unsigned get_node_size(ast const * n) {
- switch(n->get_kind()) {
- case AST_SORT: return to_sort(n)->get_size();
- case AST_FUNC_DECL: return to_func_decl(n)->get_size();
- case AST_APP: return to_app(n)->get_size();
- case AST_VAR: return to_var(n)->get_size();
- case AST_QUANTIFIER: return to_quantifier(n)->get_size();
- default: UNREACHABLE();
- }
- return 0;
+unsigned get_node_size(ast const * n) {
+ switch(n->get_kind()) {
+ case AST_SORT: return to_sort(n)->get_size();
+ case AST_FUNC_DECL: return to_func_decl(n)->get_size();
+ case AST_APP: return to_app(n)->get_size();
+ case AST_VAR: return to_var(n)->get_size();
+ case AST_QUANTIFIER: return to_quantifier(n)->get_size();
+ default: UNREACHABLE();
+ }
+ return 0;
}
bool compare_nodes(ast const * n1, ast const * n2) {
@@ -737,7 +737,7 @@ func_decl * basic_decl_plugin::mk_proof_decl(
for (unsigned i = 0; i < num_parents; i++)
domain.push_back(m_proof_sort);
domain.push_back(m_bool_sort);
- func_decl_info info(m_family_id, k, num_parameters, params);
+ func_decl_info info(m_family_id, k, num_parameters, params);
return m_manager->mk_func_decl(symbol(name), num_parents+1, domain.c_ptr(), m_proof_sort, info);
}
@@ -1643,12 +1643,12 @@ ast * ast_manager::register_node_core(ast * n) {
to_func_decl(n)->m_info = alloc(func_decl_info, *(to_func_decl(n)->get_info()));
to_func_decl(n)->m_info->init_eh(*this);
}
- inc_array_ref(to_func_decl(n)->get_arity(), to_func_decl(n)->get_domain());
- inc_ref(to_func_decl(n)->get_range());
- break;
+ inc_array_ref(to_func_decl(n)->get_arity(), to_func_decl(n)->get_domain());
+ inc_ref(to_func_decl(n)->get_range());
+ break;
case AST_APP: {
app * t = to_app(n);
- inc_ref(t->get_decl());
+ inc_ref(t->get_decl());
unsigned num_args = t->get_num_args();
if (num_args > 0) {
app_flags * f = t->flags();
@@ -1696,19 +1696,19 @@ ast * ast_manager::register_node_core(ast * n) {
f->m_depth = depth;
SASSERT(t->get_depth() == depth);
}
- break;
+ break;
}
case AST_VAR:
inc_ref(to_var(n)->get_sort());
break;
case AST_QUANTIFIER:
- inc_array_ref(to_quantifier(n)->get_num_decls(), to_quantifier(n)->get_decl_sorts());
- inc_ref(to_quantifier(n)->get_expr());
+ inc_array_ref(to_quantifier(n)->get_num_decls(), to_quantifier(n)->get_decl_sorts());
+ inc_ref(to_quantifier(n)->get_expr());
inc_array_ref(to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns());
inc_array_ref(to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns());
- break;
+ break;
default:
- break;
+ break;
}
return n;
}
@@ -1721,7 +1721,7 @@ void ast_manager::delete_node(ast * n) {
while (!worklist.empty()) {
n = worklist.back();
worklist.pop_back();
-
+
TRACE("ast", tout << "Deleting object " << n->m_id << " " << n << "\n";);
CTRACE("del_quantifier", is_quantifier(n), tout << "deleting quantifier " << n->m_id << " " << n << "\n";);
TRACE("mk_var_bug", tout << "del_ast: " << n->m_id << "\n";);
@@ -1770,8 +1770,8 @@ void ast_manager::delete_node(ast * n) {
dec_array_ref(worklist, to_quantifier(n)->get_num_patterns(), to_quantifier(n)->get_patterns());
dec_array_ref(worklist, to_quantifier(n)->get_num_no_patterns(), to_quantifier(n)->get_no_patterns());
break;
- default:
- break;
+ default:
+ break;
}
if (m_debug_ref_count) {
m_debug_free_indices.insert(n->m_id,0);
@@ -2567,9 +2567,9 @@ proof * ast_manager::mk_transitivity(proof * p1, proof * p2) {
(is_eq(get_fact(p2)) || is_oeq(get_fact(p2)))));
CTRACE("mk_transitivity", to_app(get_fact(p1))->get_arg(1) != to_app(get_fact(p2))->get_arg(0),
tout << mk_pp(get_fact(p1), *this) << "\n\n" << mk_pp(get_fact(p2), *this) << "\n";
- tout << mk_bounded_pp(p1, *this, 5) << "\n\n";
- tout << mk_bounded_pp(p2, *this, 5) << "\n\n";
- );
+ tout << mk_bounded_pp(p1, *this, 5) << "\n\n";
+ tout << mk_bounded_pp(p2, *this, 5) << "\n\n";
+ );
SASSERT(to_app(get_fact(p1))->get_arg(1) == to_app(get_fact(p2))->get_arg(0));
if (is_reflexivity(p1))
return p2;
@@ -2848,7 +2848,7 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro
SASSERT(is_or(f1));
app * cls = to_app(f1);
unsigned cls_sz = cls->get_num_args();
- CTRACE("cunit_bug", !(num_proofs == cls_sz || (num_proofs == cls_sz + 1 && is_false(new_fact))),
+ CTRACE("cunit_bug", !(num_proofs == cls_sz || (num_proofs == cls_sz + 1 && is_false(new_fact))),
for (unsigned i = 0; i < num_proofs; i++) tout << mk_pp(get_fact(proofs[i]), *this) << "\n";
tout << "===>\n";
tout << mk_pp(new_fact, *this) << "\n";);
diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp
index 77c8ac58f..035e228fb 100644
--- a/src/ast/ast_smt2_pp.cpp
+++ b/src/ast/ast_smt2_pp.cpp
@@ -222,34 +222,65 @@ format * smt2_pp_environment::pp_bv_literal(app * t, bool use_bv_lits, bool bv_n
return vf;
}
-format * smt2_pp_environment::pp_float_literal(app * t) {
+format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits, bool use_float_real_lits) {
mpf_manager & fm = get_futil().fm();
scoped_mpf v(fm);
+ ast_manager & m = get_manager();
format * body = 0;
- VERIFY(get_futil().is_value(t, v));
+ string_buffer<> buf;
+ VERIFY(get_futil().is_numeral(t, v));
if (fm.is_nan(v)) {
- body = mk_string(get_manager(), "NaN");
+ buf << "(_ NaN " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
+ return mk_string(m, buf.c_str());
}
else if (fm.is_pinf(v)) {
- body = mk_string(get_manager(), "plusInfinity");
+ buf << "(_ +oo " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
+ return mk_string(m, buf.c_str());
}
else if (fm.is_ninf(v)) {
- body = mk_string(get_manager(), "minusInfinity");
+ buf << "(_ -oo " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
+ return mk_string(m, buf.c_str());
}
- else if (fm.is_pzero(v)) {
- // TODO: make it SMT 2.0 compatible
- body = mk_string(get_manager(), "+0.0");
+ else if (fm.is_pzero(v)) {
+ buf << "(_ +zero " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
+ return mk_string(m, buf.c_str());
}
else if (fm.is_nzero(v)) {
- // TODO: make it SMT 2.0 compatible
- body = mk_string(get_manager(), "-0.0");
+ buf << "(_ -zero " << v.get().get_ebits() << " " << v.get().get_sbits() << ")";
+ return mk_string(m, buf.c_str());
+ }
+ else if (use_float_real_lits)
+ {
+ buf << "((_ to_fp " << v.get().get_ebits() << " " <<
+ v.get().get_sbits() << ") RTZ " <<
+ fm.to_string(v).c_str() << ")";
+ return mk_string(m, buf.c_str());
}
else {
- // TODO: make it SMT 2.0 compatible
- std::string val = fm.to_string(v);
- body = mk_string(get_manager(), val.c_str());
+ if (use_bv_lits)
+ buf << "(fp #b" << (fm.sgn(v) ? 1 : 0);
+ else
+ buf << "(fp (_ bv" << (fm.sgn(v) ? 1 : 0) << " 1)";
+ body = mk_string(m, buf.c_str());
+ body = mk_compose(m, body, mk_string(m, " "));
+
+ mpf_exp_t exp = fm.exp(v);
+ const mpz & bias = fm.m_powers2.m1(v.get().get_ebits() - 1);
+ mpf_exp_t biased_exp = exp + fm.mpz_manager().get_int64(bias);
+ app_ref e_biased_exp(m);
+ e_biased_exp = get_bvutil().mk_numeral(biased_exp, v.get().get_ebits());
+ body = mk_compose(m, body, pp_bv_literal(e_biased_exp, use_bv_lits, false));
+ body = mk_compose(m, body, mk_string(m, " "));
+
+ scoped_mpz sig(fm.mpz_manager());
+ sig = fm.sig(v);
+ app_ref e_sig(m);
+ e_sig = get_bvutil().mk_numeral(rational(sig), v.get().get_sbits() - 1);
+ body = mk_compose(m, body, pp_bv_literal(e_sig, use_bv_lits, false));
+
+ body = mk_compose(m, body, mk_string(m, ")"));
+ return body;
}
- return pp_as(body, get_manager().get_sort(t));
}
// generate (- f)
@@ -365,7 +396,7 @@ format_ns::format * smt2_pp_environment::pp_sort(sort * s) {
unsigned ebits = get_futil().get_ebits(s);
unsigned sbits = get_futil().get_sbits(s);
ptr_buffer fs;
- fs.push_back(mk_string(m, "FP"));
+ fs.push_back(mk_string(m, "FloatingPoint"));
fs.push_back(mk_unsigned(m, ebits));
fs.push_back(mk_unsigned(m, sbits));
return mk_seq1(m, fs.begin(), fs.end(), f2f(), "_");
@@ -425,6 +456,7 @@ class smt2_printer {
bool m_pp_decimal;
unsigned m_pp_decimal_precision;
bool m_pp_bv_lits;
+ bool m_pp_float_real_lits;
bool m_pp_bv_neg;
unsigned m_pp_max_depth;
unsigned m_pp_min_alias_size;
@@ -543,8 +575,8 @@ class smt2_printer {
else if (m_env.get_bvutil().is_numeral(c)) {
f = m_env.pp_bv_literal(c, m_pp_bv_lits, m_pp_bv_neg);
}
- else if (m_env.get_futil().is_value(c)) {
- f = m_env.pp_float_literal(c);
+ else if (m_env.get_futil().is_numeral(c)) {
+ f = m_env.pp_float_literal(c, m_pp_bv_lits, m_pp_float_real_lits);
}
else if (m_env.get_dlutil().is_numeral(c)) {
f = m_env.pp_datalog_literal(c);
@@ -987,6 +1019,7 @@ public:
m_pp_decimal = p.decimal();
m_pp_decimal_precision = p.decimal_precision();
m_pp_bv_lits = p.bv_literals();
+ m_pp_float_real_lits = p.fp_real_literals();
m_pp_bv_neg = p.bv_neg();
m_pp_max_depth = p.max_depth();
m_pp_min_alias_size = p.min_alias_size();
diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h
index aa84d6e03..8aac71b8c 100644
--- a/src/ast/ast_smt2_pp.h
+++ b/src/ast/ast_smt2_pp.h
@@ -27,7 +27,7 @@ Revision History:
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"array_decl_plugin.h"
-#include"float_decl_plugin.h"
+#include"fpa_decl_plugin.h"
#include"dl_decl_plugin.h"
#include"smt2_util.h"
@@ -46,13 +46,13 @@ public:
virtual arith_util & get_autil() = 0;
virtual bv_util & get_bvutil() = 0;
virtual array_util & get_arutil() = 0;
- virtual float_util & get_futil() = 0;
+ virtual fpa_util & get_futil() = 0;
virtual datalog::dl_decl_util& get_dlutil() = 0;
virtual bool uses(symbol const & s) const = 0;
virtual format_ns::format * pp_fdecl(func_decl * f, unsigned & len);
virtual format_ns::format * pp_bv_literal(app * t, bool use_bv_lits, bool bv_neg);
virtual format_ns::format * pp_arith_literal(app * t, bool decimal, unsigned prec);
- virtual format_ns::format * pp_float_literal(app * t);
+ virtual format_ns::format * pp_float_literal(app * t, bool use_bv_lits, bool use_float_real_lits);
virtual format_ns::format * pp_datalog_literal(app * t);
virtual format_ns::format * pp_sort(sort * s);
virtual format_ns::format * pp_fdecl_ref(func_decl * f);
@@ -69,7 +69,7 @@ class smt2_pp_environment_dbg : public smt2_pp_environment {
arith_util m_autil;
bv_util m_bvutil;
array_util m_arutil;
- float_util m_futil;
+ fpa_util m_futil;
datalog::dl_decl_util m_dlutil;
public:
smt2_pp_environment_dbg(ast_manager & m):m_manager(m), m_autil(m), m_bvutil(m), m_arutil(m), m_futil(m), m_dlutil(m) {}
@@ -77,7 +77,7 @@ public:
virtual arith_util & get_autil() { return m_autil; }
virtual bv_util & get_bvutil() { return m_bvutil; }
virtual array_util & get_arutil() { return m_arutil; }
- virtual float_util & get_futil() { return m_futil; }
+ virtual fpa_util & get_futil() { return m_futil; }
virtual datalog::dl_decl_util& get_dlutil() { return m_dlutil; }
virtual bool uses(symbol const & s) const { return false; }
};
diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp
index 59e5c04b9..b28b640bb 100644
--- a/src/ast/ast_smt_pp.cpp
+++ b/src/ast/ast_smt_pp.cpp
@@ -1003,7 +1003,7 @@ public:
visit_sort(d->get_domain(i), true);
}
m_out << ")";
- }
+ }
};
diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp
index f1c61619a..b056ded36 100644
--- a/src/ast/bv_decl_plugin.cpp
+++ b/src/ast/bv_decl_plugin.cpp
@@ -136,7 +136,7 @@ void bv_decl_plugin::finalize() {
for (; it != end; ++it) {
ptr_vector & ds = *it;
DEC_REF(ds);
- }
+ }
DEC_REF(m_mkbv);
}
@@ -157,13 +157,13 @@ void bv_decl_plugin::mk_bv_sort(unsigned bv_size) {
}
inline sort * bv_decl_plugin::get_bv_sort(unsigned bv_size) {
- if (bv_size < (1 << 12)) {
- mk_bv_sort(bv_size);
+ if (bv_size < (1 << 12)) {
+ mk_bv_sort(bv_size);
return m_bv_sorts[bv_size];
- }
- parameter p(bv_size);
- sort_size sz(sort_size::mk_very_big());
- return m_manager->mk_sort(symbol("bv"), sort_info(m_family_id, BV_SORT, sz, 1, &p));
+ }
+ parameter p(bv_size);
+ sort_size sz(sort_size::mk_very_big());
+ return m_manager->mk_sort(symbol("bv"), sort_info(m_family_id, BV_SORT, sz, 1, &p));
}
sort * bv_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp
index ee3271b9b..00f026f55 100644
--- a/src/ast/datatype_decl_plugin.cpp
+++ b/src/ast/datatype_decl_plugin.cpp
@@ -919,9 +919,9 @@ void datatype_util::display_datatype(sort *s0, std::ostream& strm) {
todo.push_back(s0);
mark.mark(s0, true);
while (!todo.empty()) {
- sort* s = todo.back();
+ sort* s = todo.back();
todo.pop_back();
- strm << s->get_name() << " =\n";
+ strm << s->get_name() << " =\n";
ptr_vector const * cnstrs = get_datatype_constructors(s);
for (unsigned i = 0; i < cnstrs->size(); ++i) {
@@ -931,14 +931,14 @@ void datatype_util::display_datatype(sort *s0, std::ostream& strm) {
ptr_vector const * accs = get_constructor_accessors(cns);
for (unsigned j = 0; j < accs->size(); ++j) {
func_decl* acc = (*accs)[j];
- sort* s1 = acc->get_range();
+ sort* s1 = acc->get_range();
strm << "(" << acc->get_name() << ": " << s1->get_name() << ") ";
if (is_datatype(s1) && are_siblings(s1, s0) && !mark.is_marked(s1)) {
mark.mark(s1, true);
todo.push_back(s1);
}
}
- strm << "\n";
+ strm << "\n";
}
}
diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp
deleted file mode 100644
index f51101d79..000000000
--- a/src/ast/float_decl_plugin.cpp
+++ /dev/null
@@ -1,746 +0,0 @@
-/*++
-Copyright (c) 2012 Microsoft Corporation
-
-Module Name:
-
- float_decl_plugin.cpp
-
-Abstract:
-
- Floating point decl plugin
-
-Author:
-
- Leonardo de Moura (leonardo) 2012-01-15.
-
-Revision History:
-
---*/
-#include"float_decl_plugin.h"
-#include"arith_decl_plugin.h"
-#include"bv_decl_plugin.h"
-
-float_decl_plugin::float_decl_plugin():
- m_values(m_fm),
- m_value_table(mpf_hash_proc(m_values), mpf_eq_proc(m_values)) {
- m_real_sort = 0;
- m_int_sort = 0;
- m_bv_plugin = 0;
-}
-
-void float_decl_plugin::set_manager(ast_manager * m, family_id id) {
- decl_plugin::set_manager(m, id);
-
- family_id aid = m_manager->mk_family_id("arith");
- m_real_sort = m_manager->mk_sort(aid, REAL_SORT);
- SASSERT(m_real_sort != 0); // arith_decl_plugin must be installed before float_decl_plugin.
- m_manager->inc_ref(m_real_sort);
-
- m_int_sort = m_manager->mk_sort(aid, INT_SORT);
- SASSERT(m_int_sort != 0); // arith_decl_plugin must be installed before float_decl_plugin.
- m_manager->inc_ref(m_int_sort);
-
- // BV is not optional anymore.
- SASSERT(m_manager->has_plugin(symbol("bv")));
- m_bv_fid = m_manager->mk_family_id("bv");
- m_bv_plugin = static_cast(m_manager->get_plugin(m_bv_fid));
-}
-
-float_decl_plugin::~float_decl_plugin() {
-}
-
-unsigned float_decl_plugin::mk_id(mpf const & v) {
- unsigned new_id = m_id_gen.mk();
- m_values.reserve(new_id+1);
- m_fm.set(m_values[new_id], v);
- unsigned old_id = m_value_table.insert_if_not_there(new_id);
- if (old_id != new_id) {
- m_id_gen.recycle(new_id);
- m_fm.del(m_values[new_id]);
- }
- return old_id;
-}
-
-void float_decl_plugin::recycled_id(unsigned id) {
- SASSERT(m_value_table.contains(id));
- m_value_table.erase(id);
- m_id_gen.recycle(id);
- m_fm.del(m_values[id]);
-}
-
-func_decl * float_decl_plugin::mk_value_decl(mpf const & v) {
- parameter p(mk_id(v), true);
- SASSERT(p.is_external());
- sort * s = mk_float_sort(v.get_ebits(), v.get_sbits());
- return m_manager->mk_const_decl(symbol("float"), s, func_decl_info(m_family_id, OP_FLOAT_VALUE, 1, &p));
-}
-
-app * float_decl_plugin::mk_value(mpf const & v) {
- return m_manager->mk_const(mk_value_decl(v));
-}
-
-bool float_decl_plugin::is_value(expr * n, mpf & val) {
- if (is_app_of(n, m_family_id, OP_FLOAT_VALUE)) {
- m_fm.set(val, m_values[to_app(n)->get_decl()->get_parameter(0).get_ext_id()]);
- return true;
- }
- else if (is_app_of(n, m_family_id, OP_FLOAT_MINUS_INF)) {
- unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
- unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
- m_fm.mk_ninf(ebits, sbits, val);
- return true;
- }
- else if (is_app_of(n, m_family_id, OP_FLOAT_PLUS_INF)) {
- unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
- unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
- m_fm.mk_pinf(ebits, sbits, val);
- return true;
- }
- else if (is_app_of(n, m_family_id, OP_FLOAT_NAN)) {
- unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
- unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
- m_fm.mk_nan(ebits, sbits, val);
- return true;
- }
- else if (is_app_of(n, m_family_id, OP_FLOAT_PLUS_ZERO)) {
- unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
- unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
- m_fm.mk_pzero(ebits, sbits, val);
- return true;
- }
- else if (is_app_of(n, m_family_id, OP_FLOAT_MINUS_ZERO)) {
- unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
- unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
- m_fm.mk_nzero(ebits, sbits, val);
- return true;
- }
- return false;
-}
-
-bool float_decl_plugin::is_rm_value(expr * n, mpf_rounding_mode & val) {
- if (is_app_of(n, m_family_id, OP_RM_NEAREST_TIES_TO_AWAY)) {
- val = MPF_ROUND_NEAREST_TAWAY;
- return true;
- }
- else if (is_app_of(n, m_family_id, OP_RM_NEAREST_TIES_TO_EVEN)) {
- val = MPF_ROUND_NEAREST_TEVEN;
- return true;
- }
- else if (is_app_of(n, m_family_id, OP_RM_TOWARD_NEGATIVE)) {
- val = MPF_ROUND_TOWARD_NEGATIVE;
- return true;
- }
- else if (is_app_of(n, m_family_id, OP_RM_TOWARD_POSITIVE)) {
- val = MPF_ROUND_TOWARD_POSITIVE;
- return true;
- }
- else if (is_app_of(n, m_family_id, OP_RM_TOWARD_ZERO)) {
- val = MPF_ROUND_TOWARD_ZERO;
- return true;
- }
-
- return 0;
-}
-
-void float_decl_plugin::del(parameter const & p) {
- SASSERT(p.is_external());
- recycled_id(p.get_ext_id());
-}
-
-parameter float_decl_plugin::translate(parameter const & p, decl_plugin & target) {
- SASSERT(p.is_external());
- float_decl_plugin & _target = static_cast(target);
- return parameter(_target.mk_id(m_values[p.get_ext_id()]), true);
-}
-
-void float_decl_plugin::finalize() {
- if (m_real_sort) { m_manager->dec_ref(m_real_sort); }
- if (m_int_sort) { m_manager->dec_ref(m_int_sort); }
-}
-
-decl_plugin * float_decl_plugin::mk_fresh() {
- return alloc(float_decl_plugin);
-}
-
-sort * float_decl_plugin::mk_float_sort(unsigned ebits, unsigned sbits) {
- parameter p1(ebits), p2(sbits);
- parameter ps[2] = { p1, p2 };
- sort_size sz;
- sz = sort_size::mk_very_big(); // TODO: refine
- return m_manager->mk_sort(symbol("FloatingPoint"), sort_info(m_family_id, FLOAT_SORT, sz, 2, ps));
-}
-
-sort * float_decl_plugin::mk_rm_sort() {
- return m_manager->mk_sort(symbol("RoundingMode"), sort_info(m_family_id, ROUNDING_MODE_SORT));
-}
-
-sort * float_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
- switch (k) {
- case FLOAT_SORT:
- if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) {
- m_manager->raise_exception("expecting two integer parameters to floating point sort");
- }
- if (parameters[0].get_int() <= 1 || parameters[1].get_int() <= 1)
- m_manager->raise_exception("floating point sorts need parameters > 1");
- if (parameters[0].get_int() > parameters[1].get_int())
- m_manager->raise_exception("floating point sorts with ebits > sbits are currently not supported");
- return mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
- case ROUNDING_MODE_SORT:
- return mk_rm_sort();
- case FLOAT16_SORT:
- return mk_float_sort(5, 11);
- case FLOAT32_SORT:
- return mk_float_sort(8, 24);
- case FLOAT64_SORT:
- return mk_float_sort(11, 53);
- case FLOAT128_SORT:
- return mk_float_sort(15, 133);
- default:
- m_manager->raise_exception("unknown floating point theory sort");
- return 0;
- }
-}
-
-func_decl * float_decl_plugin::mk_rm_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (num_parameters != 0)
- m_manager->raise_exception("rounding mode constant does not have parameters");
- if (arity != 0)
- m_manager->raise_exception("rounding mode is a constant");
- sort * s = mk_rm_sort();
- func_decl_info finfo(m_family_id, k);
- switch (k) {
- case OP_RM_NEAREST_TIES_TO_EVEN:
- return m_manager->mk_const_decl(symbol("roundNearestTiesToEven"), s, finfo);
- case OP_RM_NEAREST_TIES_TO_AWAY:
- return m_manager->mk_const_decl(symbol("roundNearestTiesToAway"), s, finfo);
- case OP_RM_TOWARD_POSITIVE:
- return m_manager->mk_const_decl(symbol("roundTowardPositive"), s, finfo);
- case OP_RM_TOWARD_NEGATIVE:
- return m_manager->mk_const_decl(symbol("roundTowardNegative"), s, finfo);
- case OP_RM_TOWARD_ZERO:
- return m_manager->mk_const_decl(symbol("roundTowardZero"), s, finfo);
- default:
- UNREACHABLE();
- return 0;
- }
-}
-
-func_decl * float_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- sort * s;
- if (num_parameters == 1 && parameters[0].is_ast() && is_sort(parameters[0].get_ast()) && is_float_sort(to_sort(parameters[0].get_ast()))) {
- s = to_sort(parameters[0].get_ast());
- }
- else if (num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()) {
- s = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
- }
- else if (range != 0 && is_float_sort(range)) {
- s = range;
- }
- else {
- m_manager->raise_exception("sort of floating point constant was not specified");
- UNREACHABLE();
- }
-
- SASSERT(is_sort_of(s, m_family_id, FLOAT_SORT));
-
- unsigned ebits = s->get_parameter(0).get_int();
- unsigned sbits = s->get_parameter(1).get_int();
- scoped_mpf val(m_fm);
-
- switch (k)
- {
- case OP_FLOAT_NAN: m_fm.mk_nan(ebits, sbits, val);
- SASSERT(m_fm.is_nan(val));
- break;
- case OP_FLOAT_MINUS_INF: m_fm.mk_ninf(ebits, sbits, val); break;
- case OP_FLOAT_PLUS_INF: m_fm.mk_pinf(ebits, sbits, val); break;
- case OP_FLOAT_MINUS_ZERO: m_fm.mk_nzero(ebits, sbits, val); break;
- case OP_FLOAT_PLUS_ZERO: m_fm.mk_pzero(ebits, sbits, val); break;
- }
-
- return mk_value_decl(val);
-}
-
-func_decl * float_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (arity != 2)
- m_manager->raise_exception("invalid number of arguments to floating point relation");
- if (domain[0] != domain[1] || !is_float_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected equal FloatingPoint sorts as arguments");
- symbol name;
- switch (k) {
- case OP_FLOAT_EQ: name = "fp.eq"; break;
- case OP_FLOAT_LT: name = "fp.lt"; break;
- case OP_FLOAT_GT: name = "fp.gt"; break;
- case OP_FLOAT_LE: name = "fp.lte"; break;
- case OP_FLOAT_GE: name = "fp.gte"; break;
- default:
- UNREACHABLE();
- break;
- }
- func_decl_info finfo(m_family_id, k);
- finfo.set_chainable(true);
- return m_manager->mk_func_decl(name, arity, domain, m_manager->mk_bool_sort(), finfo);
-}
-
-func_decl * float_decl_plugin::mk_unary_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (arity != 1)
- m_manager->raise_exception("invalid number of arguments to floating point relation");
- if (!is_float_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
- symbol name;
- switch (k) {
- case OP_FLOAT_IS_ZERO: name = "fp.isZero"; break;
- case OP_FLOAT_IS_NZERO: name = "fp.isNZero"; break;
- case OP_FLOAT_IS_PZERO: name = "fp.isPZero"; break;
- case OP_FLOAT_IS_NEGATIVE: name = "fp.isNegative"; break;
- case OP_FLOAT_IS_POSITIVE: name = "fp.isPositive"; break;
- case OP_FLOAT_IS_NAN: name = "fp.isNaN"; break;
- case OP_FLOAT_IS_INF: name = "fp.isInfinite"; break;
- case OP_FLOAT_IS_NORMAL: name = "fp.isNormal"; break;
- case OP_FLOAT_IS_SUBNORMAL: name = "fp.isSubnormal"; break;
- default:
- UNREACHABLE();
- break;
- }
- return m_manager->mk_func_decl(name, arity, domain, m_manager->mk_bool_sort(), func_decl_info(m_family_id, k));
-}
-
-func_decl * float_decl_plugin::mk_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (arity != 1)
- m_manager->raise_exception("invalid number of arguments to floating point operator");
- if (!is_float_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
- symbol name;
- switch (k) {
- case OP_FLOAT_ABS: name = "fp.abs"; break;
- case OP_FLOAT_NEG: name = "fp.neg"; break;
- default:
- UNREACHABLE();
- break;
- }
- return m_manager->mk_func_decl(name, arity, domain, domain[0], func_decl_info(m_family_id, k));
-}
-
-func_decl * float_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (arity != 2)
- m_manager->raise_exception("invalid number of arguments to floating point operator");
- if (domain[0] != domain[1] || !is_float_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected arguments of equal FloatingPoint sorts");
- symbol name;
- switch (k) {
- case OP_FLOAT_REM: name = "fp.rem"; break;
- case OP_FLOAT_MIN: name = "fp.min"; break;
- case OP_FLOAT_MAX: name = "fp.max"; break;
- default:
- UNREACHABLE();
- break;
- }
- return m_manager->mk_func_decl(name, arity, domain, domain[0], func_decl_info(m_family_id, k));
-}
-
-func_decl * float_decl_plugin::mk_rm_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (arity != 3)
- m_manager->raise_exception("invalid number of arguments to floating point operator");
- if (!is_rm_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort");
- if (domain[1] != domain[2] || !is_float_sort(domain[1]))
- m_manager->raise_exception("sort mismatch, expected arguments 1 and 2 of equal FloatingPoint sorts");
- symbol name;
- switch (k) {
- case OP_FLOAT_ADD: name = "fp.add"; break;
- case OP_FLOAT_SUB: name = "fp.sub"; break;
- case OP_FLOAT_MUL: name = "fp.mul"; break;
- case OP_FLOAT_DIV: name = "fp.div"; break;
- default:
- UNREACHABLE();
- break;
- }
- return m_manager->mk_func_decl(name, arity, domain, domain[1], func_decl_info(m_family_id, k));
-}
-
-func_decl * float_decl_plugin::mk_rm_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (arity != 2)
- m_manager->raise_exception("invalid number of arguments to floating point operator");
- if (!is_rm_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected RoundingMode as first argument");
- if (!is_float_sort(domain[1]))
- m_manager->raise_exception("sort mismatch, expected FloatingPoint as second argument");
- symbol name;
- switch (k) {
- case OP_FLOAT_SQRT: name = "fp.sqrt"; break;
- case OP_FLOAT_ROUND_TO_INTEGRAL: name = "fp.roundToIntegral"; break;
- default:
- UNREACHABLE();
- break;
- }
- return m_manager->mk_func_decl(name, arity, domain, domain[1], func_decl_info(m_family_id, k));
-}
-
-func_decl * float_decl_plugin::mk_fma(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (arity != 4)
- m_manager->raise_exception("invalid number of arguments to fused_ma operator");
- if (!is_rm_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected RoundingMode as first argument");
- if (domain[1] != domain[2] || domain[1] != domain[3] || !is_float_sort(domain[1]))
- m_manager->raise_exception("sort mismatch, expected arguments 1,2,3 of equal FloatingPoint sort");
- symbol name("fp.fma");
- return m_manager->mk_func_decl(name, arity, domain, domain[1], func_decl_info(m_family_id, k));
-}
-
-func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (m_bv_plugin && arity == 3 &&
- is_sort_of(domain[0], m_bv_fid, BV_SORT) &&
- is_sort_of(domain[1], m_bv_fid, BV_SORT) &&
- is_sort_of(domain[2], m_bv_fid, BV_SORT)) {
- // 3 BVs -> 1 FP
- sort * fp = mk_float_sort(domain[2]->get_parameter(0).get_int(), domain[1]->get_parameter(0).get_int()+1);
- symbol name("fp");
- return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
- }
- else if (m_bv_plugin && arity == 1 && is_sort_of(domain[0], m_bv_fid, BV_SORT)) {
- // 1 BV -> 1 FP
- if (num_parameters != 2)
- m_manager->raise_exception("invalid number of parameters to to_fp");
- if (!parameters[0].is_int() || !parameters[1].is_int())
- m_manager->raise_exception("invalid parameter type to to_fp");
- int ebits = parameters[0].get_int();
- int sbits = parameters[1].get_int();
-
- sort * fp = mk_float_sort(ebits, sbits);
- symbol name("to_fp");
- return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
- }
- else if (m_bv_plugin && arity == 2 &&
- is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) &&
- is_sort_of(domain[1], m_bv_fid, BV_SORT)) {
- // Rounding + 1 BV -> 1 FP
- if (num_parameters != 2)
- m_manager->raise_exception("invalid number of parameters to to_fp");
- if (!parameters[0].is_int() || !parameters[1].is_int())
- m_manager->raise_exception("invalid parameter type to to_fp");
- int ebits = parameters[0].get_int();
- int sbits = parameters[1].get_int();
-
- sort * fp = mk_float_sort(ebits, sbits);
- symbol name("to_fp");
- return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
- }
- else if (arity == 2 &&
- is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) &&
- is_sort_of(domain[1], m_family_id, FLOAT_SORT)) {
- // Rounding + 1 FP -> 1 FP
- if (num_parameters != 2)
- m_manager->raise_exception("invalid number of parameters to to_fp");
- if (!parameters[0].is_int() || !parameters[1].is_int())
- m_manager->raise_exception("invalid parameter type to to_fp");
- int ebits = parameters[0].get_int();
- int sbits = parameters[1].get_int();
- if (!is_rm_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort");
- if (!is_sort_of(domain[1], m_family_id, FLOAT_SORT))
- m_manager->raise_exception("sort mismatch, expected second argument of FloatingPoint sort");
-
- sort * fp = mk_float_sort(ebits, sbits);
- symbol name("to_fp");
- return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
- }
- else {
- // 1 Real -> 1 FP
- if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()))
- m_manager->raise_exception("expecting two integer parameters to to_fp");
- if (arity != 2 && arity != 3)
- m_manager->raise_exception("invalid number of arguments to to_fp operator");
- if (arity == 3 && domain[2] != m_int_sort)
- m_manager->raise_exception("sort mismatch, expected second argument of Int sort");
- if (domain[1] != m_real_sort)
- m_manager->raise_exception("sort mismatch, expected second argument of Real sort");
-
- sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
- symbol name("to_fp");
- return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
- }
-}
-
-func_decl * float_decl_plugin::mk_float_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (arity != 1)
- m_manager->raise_exception("invalid number of arguments to asIEEEBV");
- if (!is_float_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
-
- unsigned float_sz = domain[0]->get_parameter(0).get_int() + domain[0]->get_parameter(1).get_int();
- parameter ps[] = { parameter(float_sz) };
- sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps);
- symbol name("asIEEEBV");
- return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
-}
-
-func_decl * float_decl_plugin::mk_from3bv(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (arity != 3)
- m_manager->raise_exception("invalid number of arguments to fp");
- if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) ||
- !is_sort_of(domain[1], m_bv_fid, BV_SORT) ||
- !is_sort_of(domain[2], m_bv_fid, BV_SORT))
- m_manager->raise_exception("sort mismatch");
-
- sort * fp = mk_float_sort(domain[1]->get_parameter(0).get_int(), domain[2]->get_parameter(0).get_int() + 1);
- symbol name("fp");
- return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k));
-}
-
-func_decl * float_decl_plugin::mk_to_ubv(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (!m_bv_plugin)
- m_manager->raise_exception("to_fp_unsigned unsupported; use a logic with BV support");
- if (arity != 2)
- m_manager->raise_exception("invalid number of arguments to to_fp_unsigned");
- if (is_rm_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort");
- if (!is_sort_of(domain[1], m_bv_fid, BV_SORT))
- m_manager->raise_exception("sort mismatch, expected second argument of BV sort");
-
- sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
- symbol name("fp.t_ubv");
- return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k));
-}
-
-func_decl * float_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- NOT_IMPLEMENTED_YET();
-}
-
-func_decl * float_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- NOT_IMPLEMENTED_YET();
-}
-
-func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- switch (k) {
- case OP_TO_FLOAT:
- return mk_to_float(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_MINUS_INF:
- case OP_FLOAT_PLUS_INF:
- case OP_FLOAT_NAN:
- return mk_float_const_decl(k, num_parameters, parameters, arity, domain, range);
- case OP_RM_NEAREST_TIES_TO_EVEN:
- case OP_RM_NEAREST_TIES_TO_AWAY:
- case OP_RM_TOWARD_POSITIVE:
- case OP_RM_TOWARD_NEGATIVE:
- case OP_RM_TOWARD_ZERO:
- return mk_rm_const_decl(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_EQ:
- case OP_FLOAT_LT:
- case OP_FLOAT_GT:
- case OP_FLOAT_LE:
- case OP_FLOAT_GE:
- return mk_bin_rel_decl(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_IS_ZERO:
- case OP_FLOAT_IS_NZERO:
- case OP_FLOAT_IS_PZERO:
- case OP_FLOAT_IS_NEGATIVE:
- case OP_FLOAT_IS_POSITIVE:
- case OP_FLOAT_IS_NAN:
- case OP_FLOAT_IS_INF:
- case OP_FLOAT_IS_NORMAL:
- case OP_FLOAT_IS_SUBNORMAL:
- return mk_unary_rel_decl(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_ABS:
- case OP_FLOAT_NEG:
- return mk_unary_decl(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_REM:
- case OP_FLOAT_MIN:
- case OP_FLOAT_MAX:
- return mk_binary_decl(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_ADD:
- case OP_FLOAT_MUL:
- case OP_FLOAT_DIV:
- return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_SUB:
- if (arity == 1)
- return mk_unary_decl(OP_FLOAT_NEG, num_parameters, parameters, arity, domain, range);
- else
- return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_SQRT:
- case OP_FLOAT_ROUND_TO_INTEGRAL:
- return mk_rm_unary_decl(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_FMA:
- return mk_fma(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_TO_IEEE_BV:
- return mk_float_to_ieee_bv(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_FP:
- return mk_from3bv(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_TO_UBV:
- return mk_to_ubv(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_TO_SBV:
- return mk_to_sbv(k, num_parameters, parameters, arity, domain, range);
- case OP_FLOAT_TO_REAL:
- return mk_to_real(k, num_parameters, parameters, arity, domain, range);
- default:
- m_manager->raise_exception("unsupported floating point operator");
- return 0;
- }
-}
-
-void float_decl_plugin::get_op_names(svector & op_names, symbol const & logic) {
- // These are the operators from the final draft of the SMT FloatingPoint standard
- op_names.push_back(builtin_name("+oo", OP_FLOAT_PLUS_INF));
- op_names.push_back(builtin_name("-oo", OP_FLOAT_MINUS_INF));
- op_names.push_back(builtin_name("+zero", OP_FLOAT_PLUS_ZERO));
- op_names.push_back(builtin_name("-zero", OP_FLOAT_MINUS_ZERO));
- op_names.push_back(builtin_name("NaN", OP_FLOAT_NAN));
-
- op_names.push_back(builtin_name("roundNearestTiesToEven", OP_RM_NEAREST_TIES_TO_EVEN));
- op_names.push_back(builtin_name("roundNearestTiesToAway", OP_RM_NEAREST_TIES_TO_AWAY));
- op_names.push_back(builtin_name("roundTowardPositive", OP_RM_TOWARD_POSITIVE));
- op_names.push_back(builtin_name("roundTowardNegative", OP_RM_TOWARD_NEGATIVE));
- op_names.push_back(builtin_name("roundTowardZero", OP_RM_TOWARD_ZERO));
-
- op_names.push_back(builtin_name("RNE", OP_RM_NEAREST_TIES_TO_EVEN));
- op_names.push_back(builtin_name("RNA", OP_RM_NEAREST_TIES_TO_AWAY));
- op_names.push_back(builtin_name("RTP", OP_RM_TOWARD_POSITIVE));
- op_names.push_back(builtin_name("RTN", OP_RM_TOWARD_NEGATIVE));
- op_names.push_back(builtin_name("RTZ", OP_RM_TOWARD_ZERO));
-
- op_names.push_back(builtin_name("fp.abs", OP_FLOAT_ABS));
- op_names.push_back(builtin_name("fp.neg", OP_FLOAT_NEG));
- op_names.push_back(builtin_name("fp.add", OP_FLOAT_ADD));
- op_names.push_back(builtin_name("fp.sub", OP_FLOAT_SUB));
- op_names.push_back(builtin_name("fp.mul", OP_FLOAT_MUL));
- op_names.push_back(builtin_name("fp.div", OP_FLOAT_DIV));
- op_names.push_back(builtin_name("fp.fma", OP_FLOAT_FMA));
- op_names.push_back(builtin_name("fp.sqrt", OP_FLOAT_SQRT));
- op_names.push_back(builtin_name("fp.rem", OP_FLOAT_REM));
- op_names.push_back(builtin_name("fp.roundToIntegral", OP_FLOAT_ROUND_TO_INTEGRAL));
- op_names.push_back(builtin_name("fp.min", OP_FLOAT_MIN));
- op_names.push_back(builtin_name("fp.max", OP_FLOAT_MAX));
- op_names.push_back(builtin_name("fp.leq", OP_FLOAT_LE));
- op_names.push_back(builtin_name("fp.lt", OP_FLOAT_LT));
- op_names.push_back(builtin_name("fp.geq", OP_FLOAT_GE));
- op_names.push_back(builtin_name("fp.gt", OP_FLOAT_GT));
- op_names.push_back(builtin_name("fp.eq", OP_FLOAT_EQ));
-
- op_names.push_back(builtin_name("fp.isNormal", OP_FLOAT_IS_NORMAL));
- op_names.push_back(builtin_name("fp.isSubnormal", OP_FLOAT_IS_SUBNORMAL));
- op_names.push_back(builtin_name("fp.isZero", OP_FLOAT_IS_ZERO));
- op_names.push_back(builtin_name("fp.isInfinite", OP_FLOAT_IS_INF));
- op_names.push_back(builtin_name("fp.isNaN", OP_FLOAT_IS_NAN));
- op_names.push_back(builtin_name("fp.isNegative", OP_FLOAT_IS_NEGATIVE));
- op_names.push_back(builtin_name("fp.isPositive", OP_FLOAT_IS_POSITIVE));
-
- op_names.push_back(builtin_name("fp", OP_FLOAT_FP));
- op_names.push_back(builtin_name("fp.to_ubv", OP_FLOAT_TO_UBV));
- op_names.push_back(builtin_name("fp.to_sbv", OP_FLOAT_TO_SBV));
-
- op_names.push_back(builtin_name("to_fp", OP_TO_FLOAT));
-}
-
-void float_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) {
- sort_names.push_back(builtin_name("FloatingPoint", FLOAT_SORT));
- sort_names.push_back(builtin_name("RoundingMode", ROUNDING_MODE_SORT));
-
- // The final theory supports three common FloatingPoint sorts
- sort_names.push_back(builtin_name("Float16", FLOAT16_SORT));
- sort_names.push_back(builtin_name("Float32", FLOAT32_SORT));
- sort_names.push_back(builtin_name("Float64", FLOAT64_SORT));
- sort_names.push_back(builtin_name("Float128", FLOAT128_SORT));
-}
-
-expr * float_decl_plugin::get_some_value(sort * s) {
- SASSERT(s->is_sort_of(m_family_id, FLOAT_SORT));
- mpf tmp;
- m_fm.mk_nan(s->get_parameter(0).get_int(), s->get_parameter(1).get_int(), tmp);
- expr * res = this->mk_value(tmp);
- m_fm.del(tmp);
- return res;
-}
-
-bool float_decl_plugin::is_value(app * e) const {
- if (e->get_family_id() != m_family_id)
- return false;
- switch (e->get_decl_kind()) {
- case OP_RM_NEAREST_TIES_TO_EVEN:
- case OP_RM_NEAREST_TIES_TO_AWAY:
- case OP_RM_TOWARD_POSITIVE:
- case OP_RM_TOWARD_NEGATIVE:
- case OP_RM_TOWARD_ZERO:
- case OP_FLOAT_VALUE:
- case OP_FLOAT_PLUS_INF:
- case OP_FLOAT_MINUS_INF:
- case OP_FLOAT_PLUS_ZERO:
- case OP_FLOAT_MINUS_ZERO:
- case OP_FLOAT_NAN:
- return true;
- case OP_TO_FLOAT:
- return m_manager->is_value(e->get_arg(0));
- default:
- return false;
- }
-}
-
-float_util::float_util(ast_manager & m):
- m_manager(m),
- m_fid(m.mk_family_id("float")),
- m_a_util(m) {
- m_plugin = static_cast(m.get_plugin(m_fid));
-}
-
-float_util::~float_util() {
-}
-
-sort * float_util::mk_float_sort(unsigned ebits, unsigned sbits) {
- parameter ps[2] = { parameter(ebits), parameter(sbits) };
- return m().mk_sort(m_fid, FLOAT_SORT, 2, ps);
-}
-
-unsigned float_util::get_ebits(sort * s) {
- SASSERT(is_float(s));
- return static_cast(s->get_parameter(0).get_int());
-}
-
-unsigned float_util::get_sbits(sort * s) {
- SASSERT(is_float(s));
- return static_cast(s->get_parameter(1).get_int());
-}
-
-app * float_util::mk_nan(unsigned ebits, unsigned sbits) {
- scoped_mpf v(fm());
- fm().mk_nan(ebits, sbits, v);
- return mk_value(v);
-}
-
-app * float_util::mk_plus_inf(unsigned ebits, unsigned sbits) {
- scoped_mpf v(fm());
- fm().mk_pinf(ebits, sbits, v);
- return mk_value(v);
-}
-
-app * float_util::mk_minus_inf(unsigned ebits, unsigned sbits) {
- scoped_mpf v(fm());
- fm().mk_ninf(ebits, sbits, v);
- return mk_value(v);
-}
-
-app * float_util::mk_pzero(unsigned ebits, unsigned sbits) {
- scoped_mpf v(fm());
- fm().mk_pzero(ebits, sbits, v);
- return mk_value(v);
-}
-
-app * float_util::mk_nzero(unsigned ebits, unsigned sbits) {
- scoped_mpf v(fm());
- fm().mk_nzero(ebits, sbits, v);
- return mk_value(v);
-}
-
diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h
deleted file mode 100644
index c7ec04932..000000000
--- a/src/ast/float_decl_plugin.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/*++
-Copyright (c) 2012 Microsoft Corporation
-
-Module Name:
-
- float_decl_plugin.h
-
-Abstract:
-
- Floating point decl plugin
-
-Author:
-
- Leonardo de Moura (leonardo) 2012-01-15.
-
-Revision History:
-
---*/
-#ifndef _FLOAT_DECL_PLUGIN_H_
-#define _FLOAT_DECL_PLUGIN_H_
-
-#include"ast.h"
-#include"id_gen.h"
-#include"arith_decl_plugin.h"
-#include"bv_decl_plugin.h"
-#include"mpf.h"
-
-enum float_sort_kind {
- FLOAT_SORT,
- ROUNDING_MODE_SORT,
- FLOAT16_SORT,
- FLOAT32_SORT,
- FLOAT64_SORT,
- FLOAT128_SORT
-};
-
-enum float_op_kind {
- OP_RM_NEAREST_TIES_TO_EVEN,
- OP_RM_NEAREST_TIES_TO_AWAY,
- OP_RM_TOWARD_POSITIVE,
- OP_RM_TOWARD_NEGATIVE,
- OP_RM_TOWARD_ZERO,
-
- OP_FLOAT_VALUE,
- OP_FLOAT_PLUS_INF,
- OP_FLOAT_MINUS_INF,
- OP_FLOAT_NAN,
- OP_FLOAT_PLUS_ZERO,
- OP_FLOAT_MINUS_ZERO,
-
- OP_FLOAT_ADD,
- OP_FLOAT_SUB,
- OP_FLOAT_NEG,
- OP_FLOAT_MUL,
- OP_FLOAT_DIV,
- OP_FLOAT_REM,
- OP_FLOAT_ABS,
- OP_FLOAT_MIN,
- OP_FLOAT_MAX,
- OP_FLOAT_FMA, // x*y + z
- OP_FLOAT_SQRT,
- OP_FLOAT_ROUND_TO_INTEGRAL,
-
- OP_FLOAT_EQ,
- OP_FLOAT_LT,
- OP_FLOAT_GT,
- OP_FLOAT_LE,
- OP_FLOAT_GE,
- OP_FLOAT_IS_NAN,
- OP_FLOAT_IS_INF,
- OP_FLOAT_IS_ZERO,
- OP_FLOAT_IS_NORMAL,
- OP_FLOAT_IS_SUBNORMAL,
- OP_FLOAT_IS_PZERO,
- OP_FLOAT_IS_NZERO,
- OP_FLOAT_IS_NEGATIVE,
- OP_FLOAT_IS_POSITIVE,
-
- OP_TO_FLOAT,
- OP_FLOAT_TO_IEEE_BV,
-
- OP_FLOAT_FP,
- OP_FLOAT_TO_FP,
- OP_FLOAT_TO_UBV,
- OP_FLOAT_TO_SBV,
- OP_FLOAT_TO_REAL,
-
- LAST_FLOAT_OP
-};
-
-class float_decl_plugin : public decl_plugin {
- struct mpf_hash_proc {
- scoped_mpf_vector const & m_values;
- mpf_hash_proc(scoped_mpf_vector const & values):m_values(values) {}
- unsigned operator()(unsigned id) const { return m_values.m().hash(m_values[id]); }
- };
-
- struct mpf_eq_proc {
- scoped_mpf_vector const & m_values;
- mpf_eq_proc(scoped_mpf_vector const & values):m_values(values) {}
- bool operator()(unsigned id1, unsigned id2) const { return m_values.m().eq_core(m_values[id1], m_values[id2]); }
- };
-
- typedef chashtable value_table;
-
-
- mpf_manager m_fm;
- id_gen m_id_gen;
- scoped_mpf_vector m_values;
- value_table m_value_table;
- sort * m_real_sort;
- sort * m_int_sort;
- family_id m_bv_fid;
- bv_decl_plugin * m_bv_plugin;
-
- sort * mk_float_sort(unsigned ebits, unsigned sbits);
- sort * mk_rm_sort();
- func_decl * mk_rm_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_float_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_bin_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_unary_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_rm_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_rm_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_fma(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_to_float(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_float_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_from3bv(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_to_ubv(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_to_sbv(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- func_decl * mk_to_real(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
-
- virtual void set_manager(ast_manager * m, family_id id);
- unsigned mk_id(mpf const & v);
- void recycled_id(unsigned id);
-public:
- float_decl_plugin();
-
- bool is_float_sort(sort * s) const { return is_sort_of(s, m_family_id, FLOAT_SORT); }
- bool is_rm_sort(sort * s) const { return is_sort_of(s, m_family_id, ROUNDING_MODE_SORT); }
-
- virtual ~float_decl_plugin();
- virtual void finalize();
-
- virtual decl_plugin * mk_fresh();
- virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
- virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
- virtual void get_op_names(svector & op_names, symbol const & logic);
- virtual void get_sort_names(svector & sort_names, symbol const & logic);
- virtual expr * get_some_value(sort * s);
- virtual bool is_value(app* e) const;
- virtual bool is_unique_value(app* e) const { return is_value(e); }
-
- mpf_manager & fm() { return m_fm; }
- func_decl * mk_value_decl(mpf const & v);
- app * mk_value(mpf const & v);
- bool is_value(expr * n) { return is_app_of(n, m_family_id, OP_FLOAT_VALUE); }
- bool is_value(expr * n, mpf & val);
- bool is_rm_value(expr * n, mpf_rounding_mode & val);
- bool is_rm_value(expr * n) { mpf_rounding_mode t; return is_rm_value(n, t); }
-
- mpf const & get_value(unsigned id) const {
- SASSERT(m_value_table.contains(id));
- return m_values[id];
- }
-
- virtual void del(parameter const & p);
- virtual parameter translate(parameter const & p, decl_plugin & target);
-};
-
-class float_util {
- ast_manager & m_manager;
- float_decl_plugin * m_plugin;
- family_id m_fid;
- arith_util m_a_util;
-public:
- float_util(ast_manager & m);
- ~float_util();
-
- ast_manager & m() const { return m_manager; }
- mpf_manager & fm() const { return m_plugin->fm(); }
- family_id get_fid() const { return m_fid; }
- family_id get_family_id() const { return m_fid; }
- arith_util & au() { return m_a_util; }
- float_decl_plugin & plugin() { return *m_plugin; }
-
- sort * mk_float_sort(unsigned ebits, unsigned sbits);
- sort * mk_rm_sort() { return m().mk_sort(m_fid, ROUNDING_MODE_SORT); }
- bool is_float(sort * s) { return is_sort_of(s, m_fid, FLOAT_SORT); }
- bool is_rm(sort * s) { return is_sort_of(s, m_fid, ROUNDING_MODE_SORT); }
- bool is_float(expr * e) { return is_float(m_manager.get_sort(e)); }
- bool is_rm(expr * e) { return is_rm(m_manager.get_sort(e)); }
- unsigned get_ebits(sort * s);
- unsigned get_sbits(sort * s);
-
- app * mk_round_nearest_ties_to_even() { return m().mk_const(m_fid, OP_RM_NEAREST_TIES_TO_EVEN); }
- app * mk_round_nearest_ties_to_away() { return m().mk_const(m_fid, OP_RM_NEAREST_TIES_TO_AWAY); }
- app * mk_round_toward_positive() { return m().mk_const(m_fid, OP_RM_TOWARD_POSITIVE); }
- app * mk_round_toward_negative() { return m().mk_const(m_fid, OP_RM_TOWARD_NEGATIVE); }
- app * mk_round_toward_zero() { return m().mk_const(m_fid, OP_RM_TOWARD_ZERO); }
-
- app * mk_nan(unsigned ebits, unsigned sbits);
- app * mk_plus_inf(unsigned ebits, unsigned sbits);
- app * mk_minus_inf(unsigned ebits, unsigned sbits);
- app * mk_nan(sort * s) { return mk_nan(get_ebits(s), get_sbits(s)); }
- app * mk_plus_inf(sort * s) { return mk_plus_inf(get_ebits(s), get_sbits(s)); }
- app * mk_minus_inf(sort * s) { return mk_minus_inf(get_ebits(s), get_sbits(s)); }
-
- app * mk_value(mpf const & v) { return m_plugin->mk_value(v); }
- bool is_value(expr * n) { return m_plugin->is_value(n); }
- bool is_value(expr * n, mpf & v) { return m_plugin->is_value(n, v); }
- bool is_rm_value(expr * n, mpf_rounding_mode & v) { return m_plugin->is_rm_value(n, v); }
-
- app * mk_pzero(unsigned ebits, unsigned sbits);
- app * mk_nzero(unsigned ebits, unsigned sbits);
- app * mk_pzero(sort * s) { return mk_pzero(get_ebits(s), get_sbits(s)); }
- app * mk_nzero(sort * s) { return mk_nzero(get_ebits(s), get_sbits(s)); }
-
- bool is_nan(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_nan(v); }
- bool is_plus_inf(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_pinf(v); }
- bool is_minus_inf(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_ninf(v); }
- bool is_zero(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_zero(v); }
- bool is_pzero(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_pzero(v); }
- bool is_nzero(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_nzero(v); }
-
- bool is_to_float(expr * n) { return is_app_of(n, m_fid, OP_TO_FLOAT); }
-
- app * mk_to_float(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_TO_FLOAT, arg1, arg2); }
- app * mk_add(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FLOAT_ADD, arg1, arg2, arg3); }
- app * mk_mul(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FLOAT_MUL, arg1, arg2, arg3); }
- app * mk_sub(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FLOAT_SUB, arg1, arg2, arg3); }
- app * mk_div(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FLOAT_DIV, arg1, arg2, arg3); }
- app * mk_neg(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_NEG, arg1); }
- app * mk_rem(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_REM, arg1, arg2); }
- app * mk_max(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_MAX, arg1, arg2); }
- app * mk_min(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_MIN, arg1, arg2); }
- app * mk_abs(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_ABS, arg1); }
- app * mk_sqrt(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_SQRT, arg1, arg2); }
- app * mk_round(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_ROUND_TO_INTEGRAL, arg1, arg2); }
- app * mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg4) {
- expr * args[4] = { arg1, arg2, arg3, arg4 };
- return m().mk_app(m_fid, OP_FLOAT_FMA, 4, args);
- }
-
- app * mk_float_eq(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_EQ, arg1, arg2); }
- app * mk_lt(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_LT, arg1, arg2); }
- app * mk_gt(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_GT, arg1, arg2); }
- app * mk_le(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_LE, arg1, arg2); }
- app * mk_ge(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_GE, arg1, arg2); }
-
- app * mk_is_nan(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_NAN, arg1); }
- app * mk_is_inf(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_INF, arg1); }
- app * mk_is_zero(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_ZERO, arg1); }
- app * mk_is_normal(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_NORMAL, arg1); }
- app * mk_is_subnormal(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_SUBNORMAL, arg1); }
- app * mk_is_nzero(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_NZERO, arg1); }
- app * mk_is_pzero(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_PZERO, arg1); }
- app * mk_is_sign_minus(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_NEGATIVE, arg1); }
- app * mk_is_positive(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_POSITIVE, arg1); }
- app * mk_is_negative(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_NEGATIVE, arg1); }
-
- bool is_neg(expr * a) { return is_app_of(a, m_fid, OP_FLOAT_NEG); }
-
- app * mk_float_to_ieee_bv(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_TO_IEEE_BV, arg1); }
-};
-
-#endif
diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp
index c23de3bfa..110311c4c 100644
--- a/src/ast/fpa/fpa2bv_converter.cpp
+++ b/src/ast/fpa/fpa2bv_converter.cpp
@@ -16,8 +16,10 @@ Author:
Notes:
--*/
+#include
#include"ast_smt2_pp.h"
#include"well_sorted.h"
+#include"th_rewriter.h"
#include"fpa2bv_converter.h"
@@ -32,34 +34,23 @@ fpa2bv_converter::fpa2bv_converter(ast_manager & m) :
m_arith_util(m),
m_mpf_manager(m_util.fm()),
m_mpz_manager(m_mpf_manager.mpz_manager()),
- extra_assertions(m) {
- m_plugin = static_cast(m.get_plugin(m.mk_family_id("float")));
+ m_hi_fp_unspecified(true),
+ m_extra_assertions(m) {
+ m_plugin = static_cast(m.get_plugin(m.mk_family_id("fpa")));
}
fpa2bv_converter::~fpa2bv_converter() {
- dec_ref_map_key_values(m, m_const2bv);
- dec_ref_map_key_values(m, m_rm_const2bv);
- dec_ref_map_key_values(m, m_uf2bvuf);
-
- obj_map::iterator it = m_uf23bvuf.begin();
- obj_map::iterator end = m_uf23bvuf.end();
- for (; it != end; ++it) {
- m.dec_ref(it->m_key);
- m.dec_ref(it->m_value.f_sgn);
- m.dec_ref(it->m_value.f_sig);
- m.dec_ref(it->m_value.f_exp);
- }
- m_uf23bvuf.reset();
+ reset();
}
void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) {
- SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_TO_FLOAT));
- SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_TO_FLOAT));
+ SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_FPA_FP));
+ SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FPA_FP));
expr_ref sgn(m), s(m), e(m);
m_simp.mk_eq(to_app(a)->get_arg(0), to_app(b)->get_arg(0), sgn);
- m_simp.mk_eq(to_app(a)->get_arg(1), to_app(b)->get_arg(1), s);
- m_simp.mk_eq(to_app(a)->get_arg(2), to_app(b)->get_arg(2), e);
+ m_simp.mk_eq(to_app(a)->get_arg(1), to_app(b)->get_arg(1), e);
+ m_simp.mk_eq(to_app(a)->get_arg(2), to_app(b)->get_arg(2), s);
// The SMT FPA theory asks for _one_ NaN value, but the bit-blasting
// has many, like IEEE754. This encoding of equality makes it look like
@@ -73,18 +64,23 @@ void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) {
}
void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) {
- SASSERT(is_app_of(t, m_plugin->get_family_id(), OP_TO_FLOAT));
- SASSERT(is_app_of(f, m_plugin->get_family_id(), OP_TO_FLOAT));
+ SASSERT(is_app_of(t, m_plugin->get_family_id(), OP_FPA_FP));
+ SASSERT(is_app_of(f, m_plugin->get_family_id(), OP_FPA_FP));
+
+ expr *t_sgn, *t_sig, *t_exp;
+ expr *f_sgn, *f_sig, *f_exp;
+ split_fp(t, t_sgn, t_exp, t_sig);
+ split_fp(f, f_sgn, f_exp, f_sig);
expr_ref sgn(m), s(m), e(m);
- m_simp.mk_ite(c, to_app(t)->get_arg(0), to_app(f)->get_arg(0), sgn);
- m_simp.mk_ite(c, to_app(t)->get_arg(1), to_app(f)->get_arg(1), s);
- m_simp.mk_ite(c, to_app(t)->get_arg(2), to_app(f)->get_arg(2), e);
+ m_simp.mk_ite(c, t_sgn, f_sgn, sgn);
+ m_simp.mk_ite(c, t_sig, f_sig, s);
+ m_simp.mk_ite(c, t_exp, f_exp, e);
- mk_triple(sgn, s, e, result);
+ mk_fp(sgn, e, s, result);
}
-void fpa2bv_converter::mk_value(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
+void fpa2bv_converter::mk_numeral(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 0);
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_external());
@@ -103,9 +99,9 @@ void fpa2bv_converter::mk_value(func_decl * f, unsigned num, expr * const * args
mk_nan(f, result);
else if (m_util.fm().is_inf(v)) {
if (m_util.fm().sgn(v))
- mk_minus_inf(f, result);
+ mk_ninf(f, result);
else
- mk_plus_inf(f, result);
+ mk_pinf(f, result);
}
else {
expr_ref bv_sgn(m), bv_sig(m), e(m), biased_exp(m);
@@ -115,13 +111,17 @@ void fpa2bv_converter::mk_value(func_decl * f, unsigned num, expr * const * args
mk_bias(e, biased_exp);
- mk_triple(bv_sgn, bv_sig, biased_exp, result);
+ mk_fp(bv_sgn, biased_exp, bv_sig, result);
TRACE("fpa2bv_dbg", tout << "value of [" << sign << " " << m_mpz_manager.to_string(sig) << " " << exp << "] is "
<< mk_ismt2_pp(result, m) << std::endl;);
}
}
+app * fpa2bv_converter::mk_fresh_const(char const * prefix, unsigned sz) {
+ return m.mk_fresh_const(prefix, m_bv_util.mk_sort(sz));
+}
+
void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) {
SASSERT(f->get_family_id() == null_family_id);
SASSERT(f->get_arity() == 0);
@@ -134,25 +134,20 @@ void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) {
SASSERT(is_float(srt));
unsigned ebits = m_util.get_ebits(srt);
unsigned sbits = m_util.get_sbits(srt);
-
- expr_ref sgn(m), s(m), e(m);
+
+ app_ref sgn(m), s(m), e(m);
#ifdef Z3DEBUG
- sort_ref s_sgn(m), s_sig(m), s_exp(m);
- s_sgn = m_bv_util.mk_sort(1);
- s_sig = m_bv_util.mk_sort(sbits - 1);
- s_exp = m_bv_util.mk_sort(ebits);
-
std::string p("fpa2bv");
std::string name = f->get_name().str();
-
- sgn = m.mk_fresh_const((p + "_sgn_" + name).c_str(), s_sgn);
- s = m.mk_fresh_const((p + "_sig_" + name).c_str(), s_sig);
- e = m.mk_fresh_const((p + "_exp_" + name).c_str(), s_exp);
+
+ sgn = mk_fresh_const((p + "_sgn_" + name).c_str(), 1);
+ s = mk_fresh_const((p + "_sig_" + name).c_str(), sbits - 1);
+ e = mk_fresh_const((p + "_exp_" + name).c_str(), ebits);
#else
- expr_ref bv(m);
+ app_ref bv(m);
unsigned bv_sz = 1 + ebits + (sbits - 1);
- bv = m.mk_fresh_const(0, m_bv_util.mk_sort(bv_sz));
+ bv = mk_fresh_const(0, bv_sz);
sgn = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv);
e = m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv);
@@ -163,7 +158,7 @@ void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) {
SASSERT(m_bv_util.get_bv_size(e) == ebits);
#endif
- mk_triple(sgn, s, e, result);
+ mk_fp(sgn, e, s, result);
m_const2bv.insert(f, result);
m.inc_ref(f);
@@ -182,7 +177,7 @@ void fpa2bv_converter::mk_var(unsigned base_inx, sort * srt, expr_ref & result)
s = m.mk_var(base_inx + 1, m_bv_util.mk_sort(sbits-1));
e = m.mk_var(base_inx + 2, m_bv_util.mk_sort(ebits));
- mk_triple(sgn, s, e, result);
+ mk_fp(sgn, e, s, result);
}
void fpa2bv_converter::mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result)
@@ -196,7 +191,7 @@ void fpa2bv_converter::mk_uninterpreted_function(func_decl * f, unsigned num, ex
if (is_float(args[i]))
{
expr * sgn, * sig, * exp;
- split(args[i], sgn, sig, exp);
+ split_fp(args[i], sgn, exp, sig);
new_args.push_back(sgn);
new_args.push_back(sig);
new_args.push_back(exp);
@@ -215,7 +210,7 @@ void fpa2bv_converter::mk_uninterpreted_function(func_decl * f, unsigned num, ex
a_sgn = m.mk_app(fd3.f_sgn, new_args.size(), new_args.c_ptr());
a_sig = m.mk_app(fd3.f_sig, new_args.size(), new_args.c_ptr());
a_exp = m.mk_app(fd3.f_exp, new_args.size(), new_args.c_ptr());
- mk_triple(a_sgn, a_sig, a_exp, result);
+ mk_fp(a_sgn, a_exp, a_sig, result);
}
else {
sort_ref_buffer new_domain(m);
@@ -261,7 +256,7 @@ void fpa2bv_converter::mk_uninterpreted_function(func_decl * f, unsigned num, ex
m.inc_ref(f_sgn);
m.inc_ref(f_sig);
m.inc_ref(f_exp);
- mk_triple(a_sgn, a_sig, a_exp, result);
+ mk_fp(a_sgn, a_exp, a_sig, result);
}
}
@@ -294,34 +289,34 @@ void fpa2bv_converter::mk_rm_const(func_decl * f, expr_ref & result) {
expr_ref rcc(m);
rcc = bu().mk_ule(result, bu().mk_numeral(4, 3));
- extra_assertions.push_back(rcc);
+ m_extra_assertions.push_back(rcc);
}
}
-void fpa2bv_converter::mk_plus_inf(func_decl * f, expr_ref & result) {
+void fpa2bv_converter::mk_pinf(func_decl * f, expr_ref & result) {
sort * srt = f->get_range();
SASSERT(is_float(srt));
unsigned sbits = m_util.get_sbits(srt);
unsigned ebits = m_util.get_ebits(srt);
expr_ref top_exp(m);
mk_top_exp(ebits, top_exp);
- mk_triple(m_bv_util.mk_numeral(0, 1),
- m_bv_util.mk_numeral(0, sbits-1),
- top_exp,
- result);
+ mk_fp(m_bv_util.mk_numeral(0, 1),
+ top_exp,
+ m_bv_util.mk_numeral(0, sbits-1),
+ result);
}
-void fpa2bv_converter::mk_minus_inf(func_decl * f, expr_ref & result) {
+void fpa2bv_converter::mk_ninf(func_decl * f, expr_ref & result) {
sort * srt = f->get_range();
SASSERT(is_float(srt));
unsigned sbits = m_util.get_sbits(srt);
unsigned ebits = m_util.get_ebits(srt);
expr_ref top_exp(m);
mk_top_exp(ebits, top_exp);
- mk_triple(m_bv_util.mk_numeral(1, 1),
- m_bv_util.mk_numeral(0, sbits-1),
- top_exp,
- result);
+ mk_fp(m_bv_util.mk_numeral(1, 1),
+ top_exp,
+ m_bv_util.mk_numeral(0, sbits-1),
+ result);
}
void fpa2bv_converter::mk_nan(func_decl * f, expr_ref & result) {
@@ -331,10 +326,10 @@ void fpa2bv_converter::mk_nan(func_decl * f, expr_ref & result) {
unsigned ebits = m_util.get_ebits(srt);
expr_ref top_exp(m);
mk_top_exp(ebits, top_exp);
- mk_triple(m_bv_util.mk_numeral(0, 1),
- m_bv_util.mk_numeral(1, sbits-1),
- top_exp,
- result);
+ mk_fp(m_bv_util.mk_numeral(0, 1),
+ top_exp,
+ m_bv_util.mk_numeral(1, sbits-1),
+ result);
}
void fpa2bv_converter::mk_nzero(func_decl *f, expr_ref & result) {
@@ -344,10 +339,10 @@ void fpa2bv_converter::mk_nzero(func_decl *f, expr_ref & result) {
unsigned ebits = m_util.get_ebits(srt);
expr_ref bot_exp(m);
mk_bot_exp(ebits, bot_exp);
- mk_triple(m_bv_util.mk_numeral(1, 1),
- m_bv_util.mk_numeral(0, sbits-1),
- bot_exp,
- result);
+ mk_fp(m_bv_util.mk_numeral(1, 1),
+ bot_exp,
+ m_bv_util.mk_numeral(0, sbits - 1),
+ result);
}
void fpa2bv_converter::mk_pzero(func_decl *f, expr_ref & result) {
@@ -357,10 +352,10 @@ void fpa2bv_converter::mk_pzero(func_decl *f, expr_ref & result) {
unsigned ebits = m_util.get_ebits(srt);
expr_ref bot_exp(m);
mk_bot_exp(ebits, bot_exp);
- mk_triple(m_bv_util.mk_numeral(0, 1),
- m_bv_util.mk_numeral(0, sbits-1),
- bot_exp,
- result);
+ mk_fp(m_bv_util.mk_numeral(0, 1),
+ bot_exp,
+ m_bv_util.mk_numeral(0, sbits-1),
+ result);
}
void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, expr_ref & rm,
@@ -612,13 +607,13 @@ void fpa2bv_converter::mk_sub(func_decl * f, unsigned num, expr * const * args,
void fpa2bv_converter::mk_neg(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 1);
expr * sgn, * s, * e;
- split(args[0], sgn, s, e);
+ split_fp(args[0], sgn, e, s);
expr_ref c(m), nsgn(m);
mk_is_nan(args[0], c);
nsgn = m_bv_util.mk_bv_not(sgn);
expr_ref r_sgn(m);
m_simp.mk_ite(c, sgn, nsgn, r_sgn);
- mk_triple(r_sgn, s, e, result);
+ mk_fp(r_sgn, e, s, result);
}
void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
@@ -633,8 +628,8 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args,
mk_nan(f, nan);
mk_nzero(f, nzero);
mk_pzero(f, pzero);
- mk_minus_inf(f, ninf);
- mk_plus_inf(f, pinf);
+ mk_ninf(f, ninf);
+ mk_pinf(f, pinf);
expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m);
expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m);
@@ -695,8 +690,7 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args,
// else comes the actual multiplication.
unsigned ebits = m_util.get_ebits(f->get_range());
- unsigned sbits = m_util.get_sbits(f->get_range());
- SASSERT(ebits <= sbits);
+ unsigned sbits = m_util.get_sbits(f->get_range());
expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m);
unpack(x, a_sgn, a_sig, a_exp, a_lz, true);
@@ -781,8 +775,8 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args,
mk_nan(f, nan);
mk_nzero(f, nzero);
mk_pzero(f, pzero);
- mk_minus_inf(f, ninf);
- mk_plus_inf(f, pinf);
+ mk_ninf(f, ninf);
+ mk_pinf(f, pinf);
expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m);
expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m);
@@ -927,8 +921,8 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args,
mk_nan(f, nan);
mk_nzero(f, nzero);
mk_pzero(f, pzero);
- mk_minus_inf(f, ninf);
- mk_plus_inf(f, pinf);
+ mk_ninf(f, ninf);
+ mk_pinf(f, pinf);
expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m);
expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m);
@@ -1033,8 +1027,8 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args,
void fpa2bv_converter::mk_abs(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 1);
expr * sgn, * s, * e;
- split(args[0], sgn, s, e);
- mk_triple(m_bv_util.mk_numeral(0, 1), s, e, result);
+ split_fp(args[0], sgn, e, s);
+ mk_fp(m_bv_util.mk_numeral(0, 1), e, s, result);
}
void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
@@ -1044,8 +1038,8 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args,
expr * x_sgn, * x_sig, * x_exp;
expr * y_sgn, * y_sig, * y_exp;
- split(x, x_sgn, x_sig, x_exp);
- split(y, y_sgn, y_sig, y_exp);
+ split_fp(x, x_sgn, x_exp, x_sig);
+ split_fp(y, y_sgn, y_exp, y_sig);
expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), c1_and(m);
mk_is_zero(x, x_is_zero);
@@ -1077,7 +1071,7 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args,
m_simp.mk_ite(c2, x_exp, c3xy_exp, c2c3_exp);
m_simp.mk_ite(c1, y_exp, c2c3_exp, r_exp);
- mk_triple(r_sgn, r_sig, r_exp, result);
+ mk_fp(r_sgn, r_exp, r_sig, result);
}
void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
@@ -1087,8 +1081,8 @@ void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args,
expr * x_sgn, * x_sig, * x_exp;
expr * y_sgn, * y_sig, * y_exp;
- split(x, x_sgn, x_sig, x_exp);
- split(y, y_sgn, y_sig, y_exp);
+ split_fp(x, x_sgn, x_exp, x_sig);
+ split_fp(y, y_sgn, y_exp, y_sig);
expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), y_is_zero(m), x_is_zero(m), c1_and(m);
mk_is_zero(y, y_is_zero);
@@ -1120,7 +1114,7 @@ void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args,
m_simp.mk_ite(c2, x_exp, c3xy_exp, c2c3_exp);
m_simp.mk_ite(c1, y_exp, c2c3_exp, r_exp);
- mk_triple(r_sgn, r_sig, r_exp, result);
+ mk_fp(r_sgn, r_exp, r_sig, result);
}
void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
@@ -1137,8 +1131,8 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
mk_nan(f, nan);
mk_nzero(f, nzero);
mk_pzero(f, pzero);
- mk_minus_inf(f, ninf);
- mk_plus_inf(f, pinf);
+ mk_ninf(f, ninf);
+ mk_pinf(f, pinf);
expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_neg(m), x_is_inf(m);
expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_neg(m), y_is_inf(m);
@@ -1225,11 +1219,9 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
m_simp.mk_and(z_is_zero, m.mk_not(rm_is_to_neg), ite_c);
mk_ite(ite_c, pzero, z, v7);
-
// else comes the fused multiplication.
unsigned ebits = m_util.get_ebits(f->get_range());
unsigned sbits = m_util.get_sbits(f->get_range());
- SASSERT(ebits <= sbits);
expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m);
expr_ref b_sgn(m), b_sig(m), b_exp(m), b_lz(m);
@@ -1447,8 +1439,8 @@ void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args,
mk_nan(f, nan);
mk_nzero(f, nzero);
mk_pzero(f, pzero);
- mk_minus_inf(f, ninf);
- mk_plus_inf(f, pinf);
+ mk_ninf(f, ninf);
+ mk_pinf(f, pinf);
expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m);
mk_is_nan(x, x_is_nan);
@@ -1482,7 +1474,6 @@ void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args,
// else comes the actual square root.
unsigned ebits = m_util.get_ebits(f->get_range());
unsigned sbits = m_util.get_sbits(f->get_range());
- SASSERT(ebits <= sbits);
expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m);
unpack(x, a_sgn, a_sig, a_exp, a_lz, true);
@@ -1698,8 +1689,8 @@ void fpa2bv_converter::mk_float_eq(func_decl * f, unsigned num, expr * const * a
expr * x_sgn, * x_sig, * x_exp;
expr * y_sgn, * y_sig, * y_exp;
- split(x, x_sgn, x_sig, x_exp);
- split(y, y_sgn, y_sig, y_exp);
+ split_fp(x, x_sgn, x_exp, x_sig);
+ split_fp(y, y_sgn, y_exp, y_sig);
expr_ref x_eq_y_sgn(m), x_eq_y_exp(m), x_eq_y_sig(m);
m_simp.mk_eq(x_sgn, y_sgn, x_eq_y_sgn);
@@ -1734,8 +1725,8 @@ void fpa2bv_converter::mk_float_lt(func_decl * f, unsigned num, expr * const * a
expr * x_sgn, * x_sig, * x_exp;
expr * y_sgn, * y_sig, * y_exp;
- split(x, x_sgn, x_sig, x_exp);
- split(y, y_sgn, y_sig, y_exp);
+ split_fp(x, x_sgn, x_exp, x_sig);
+ split_fp(y, y_sgn, y_exp, y_sig);
expr_ref c3(m), t3(m), t4(m), one_1(m), nil_1(m);
one_1 = m_bv_util.mk_numeral(1, 1);
@@ -1858,68 +1849,12 @@ void fpa2bv_converter::mk_is_positive(func_decl * f, unsigned num, expr * const
result = m.mk_and(m.mk_not(t1), t2);
}
-void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
- TRACE("fpa2bv_to_float", for (unsigned i=0; i < num; i++)
- tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl; );
+void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
+ TRACE("fpa2bv_to_fp", for (unsigned i=0; i < num; i++)
+ tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl; );
- if (num == 3 &&
- m_bv_util.is_bv(args[0]) &&
- m_bv_util.is_bv(args[1]) &&
- m_bv_util.is_bv(args[2])) {
- // Theoretically, the user could have thrown in it's own triple of bit-vectors.
- // Just keep it here, as there will be something else that uses it.
- mk_triple(args[0], args[1], args[2], result);
- }
- else if (num == 3 &&
- m_bv_util.is_bv(args[0]) &&
- m_arith_util.is_numeral(args[1]) &&
- m_arith_util.is_numeral(args[2]))
- {
- // Three arguments, some of them are not numerals.
- SASSERT(m_util.is_float(f->get_range()));
- unsigned ebits = m_util.get_ebits(f->get_range());
- unsigned sbits = m_util.get_sbits(f->get_range());
-
- expr * rm = args[0];
-
- rational q;
- if (!m_arith_util.is_numeral(args[1], q))
- NOT_IMPLEMENTED_YET();
-
- rational e;
- if (!m_arith_util.is_numeral(args[2], e))
- NOT_IMPLEMENTED_YET();
-
- SASSERT(e.is_int64());
- SASSERT(m_mpz_manager.eq(e.to_mpq().denominator(), 1));
-
- mpf nte, nta, tp, tn, tz;
- m_mpf_manager.set(nte, ebits, sbits, MPF_ROUND_NEAREST_TEVEN, q.to_mpq(), e.to_mpq().numerator());
- m_mpf_manager.set(nta, ebits, sbits, MPF_ROUND_NEAREST_TAWAY, q.to_mpq(), e.to_mpq().numerator());
- m_mpf_manager.set(tp, ebits, sbits, MPF_ROUND_TOWARD_POSITIVE, q.to_mpq(), e.to_mpq().numerator());
- m_mpf_manager.set(tn, ebits, sbits, MPF_ROUND_TOWARD_NEGATIVE, q.to_mpq(), e.to_mpq().numerator());
- m_mpf_manager.set(tz, ebits, sbits, MPF_ROUND_TOWARD_ZERO, q.to_mpq(), e.to_mpq().numerator());
-
- app_ref a_nte(m), a_nta(m), a_tp(m), a_tn(m), a_tz(m);
- a_nte = m_plugin->mk_value(nte);
- a_nta = m_plugin->mk_value(nta);
- a_tp = m_plugin->mk_value(tp);
- a_tn = m_plugin->mk_value(tn);
- a_tz = m_plugin->mk_value(tz);
-
- expr_ref bv_nte(m), bv_nta(m), bv_tp(m), bv_tn(m), bv_tz(m);
- mk_value(a_nte->get_decl(), 0, 0, bv_nte);
- mk_value(a_nta->get_decl(), 0, 0, bv_nta);
- mk_value(a_tp->get_decl(), 0, 0, bv_tp);
- mk_value(a_tn->get_decl(), 0, 0, bv_tn);
- mk_value(a_tz->get_decl(), 0, 0, bv_tz);
-
- mk_ite(m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3)), bv_tn, bv_tz, result);
- mk_ite(m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3)), bv_tp, result, result);
- mk_ite(m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3)), bv_nta, result, result);
- mk_ite(m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3)), bv_nte, result, result);
- }
- else if (num == 1 && m_bv_util.is_bv(args[0])) {
+ if (num == 1 &&
+ m_bv_util.is_bv(args[0])) {
sort * s = f->get_range();
unsigned to_sbits = m_util.get_sbits(s);
unsigned to_ebits = m_util.get_ebits(s);
@@ -1928,186 +1863,218 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a
int sz = m_bv_util.get_bv_size(bv);
SASSERT((unsigned)sz == to_sbits + to_ebits);
- m_bv_util.mk_extract(sz - 1, sz - 1, bv);
- mk_triple(m_bv_util.mk_extract(sz - 1, sz - 1, bv),
- m_bv_util.mk_extract(sz - to_ebits - 2, 0, bv),
- m_bv_util.mk_extract(sz - 2, sz - to_ebits - 1, bv),
- result);
+ mk_fp(m_bv_util.mk_extract(sz - 1, sz - 1, bv),
+ m_bv_util.mk_extract(sz - 2, sz - to_ebits - 1, bv),
+ m_bv_util.mk_extract(sz - to_ebits - 2, 0, bv),
+ result);
}
- else if (num == 2 &&
- is_app(args[1]) &&
- m_util.is_float(m.get_sort(args[1]))) {
- // We also support float to float conversion
- sort * s = f->get_range();
- expr_ref rm(m), x(m);
- rm = args[0];
- x = args[1];
-
- unsigned from_sbits = m_util.get_sbits(m.get_sort(x));
- unsigned from_ebits = m_util.get_ebits(m.get_sort(x));
- unsigned to_sbits = m_util.get_sbits(s);
- unsigned to_ebits = m_util.get_ebits(s);
-
- if (from_sbits == to_sbits && from_ebits == to_ebits)
- result = x;
- else {
- expr_ref c1(m), c2(m), c3(m), c4(m), c5(m);
- expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m);
- expr_ref one1(m);
-
- one1 = m_bv_util.mk_numeral(1, 1);
- expr_ref ninf(m), pinf(m);
- mk_plus_inf(f, pinf);
- mk_minus_inf(f, ninf);
-
- // NaN -> NaN
- mk_is_nan(x, c1);
- mk_nan(f, v1);
-
- // +0 -> +0
- mk_is_pzero(x, c2);
- mk_pzero(f, v2);
-
- // -0 -> -0
- mk_is_nzero(x, c3);
- mk_nzero(f, v3);
-
- // +oo -> +oo
- mk_is_pinf(x, c4);
- v4 = pinf;
-
- // -oo -> -oo
- mk_is_ninf(x, c5);
- v5 = ninf;
-
- // otherwise: the actual conversion with rounding.
- expr_ref sgn(m), sig(m), exp(m), lz(m);
- unpack(x, sgn, sig, exp, lz, true);
-
- dbg_decouple("fpa2bv_to_float_x_sig", sig);
- dbg_decouple("fpa2bv_to_float_x_exp", exp);
- dbg_decouple("fpa2bv_to_float_lz", lz);
-
- expr_ref res_sgn(m), res_sig(m), res_exp(m);
-
- res_sgn = sgn;
-
- SASSERT(m_bv_util.get_bv_size(sgn) == 1);
- SASSERT(m_bv_util.get_bv_size(sig) == from_sbits);
- SASSERT(m_bv_util.get_bv_size(exp) == from_ebits);
- SASSERT(m_bv_util.get_bv_size(lz) == from_ebits);
-
- if (from_sbits < (to_sbits + 3))
- {
- // make sure that sig has at least to_sbits + 3
- res_sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, to_sbits+3-from_sbits));
- }
- else if (from_sbits > (to_sbits + 3))
- {
- // collapse the extra bits into a sticky bit.
- expr_ref sticky(m), low(m), high(m);
- low = m_bv_util.mk_extract(from_sbits - to_sbits - 3, 0, sig);
- high = m_bv_util.mk_extract(from_sbits - 1, from_sbits - to_sbits - 2, sig);
- sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, low.get());
- res_sig = m_bv_util.mk_concat(high, sticky);
- }
- else
- res_sig = sig;
-
- res_sig = m_bv_util.mk_zero_extend(1, res_sig); // extra zero in the front for the rounder.
- unsigned sig_sz = m_bv_util.get_bv_size(res_sig);
- SASSERT(sig_sz == to_sbits+4);
-
- expr_ref exponent_overflow(m);
- exponent_overflow = m.mk_false();
-
- if (from_ebits < (to_ebits + 2))
- {
- res_exp = m_bv_util.mk_sign_extend(to_ebits-from_ebits+2, exp);
-
- // subtract lz for subnormal numbers.
- expr_ref lz_ext(m);
- lz_ext = m_bv_util.mk_zero_extend(to_ebits-from_ebits+2, lz);
- res_exp = m_bv_util.mk_bv_sub(res_exp, lz_ext);
- }
- else if (from_ebits > (to_ebits + 2))
- {
- expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), h_or_eq(m), h_and_eq(m);
- expr_ref no_ovf(m), zero1(m), s_is_one(m), s_is_zero(m);
- high = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, exp);
- low = m_bv_util.mk_extract(to_ebits+1, 0, exp);
- lows = m_bv_util.mk_extract(to_ebits+1, to_ebits+1, low);
-
- high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high.get());
- high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high.get());
-
- zero1 = m_bv_util.mk_numeral(0, 1);
- m_simp.mk_eq(high_red_and, one1, h_and_eq);
- m_simp.mk_eq(high_red_or, zero1, h_or_eq);
- m_simp.mk_eq(lows, zero1, s_is_zero);
- m_simp.mk_eq(lows, one1, s_is_one);
-
- expr_ref c2(m);
- m_simp.mk_ite(h_or_eq, s_is_one, m.mk_false(), c2);
- m_simp.mk_ite(h_and_eq, s_is_zero, c2, exponent_overflow);
-
- // Note: Upon overflow, we _could_ try to shift the significand around...
-
- // subtract lz for subnormal numbers.
- expr_ref lz_ext(m), lz_rest(m), lz_redor(m), lz_redor_bool(m);
- lz_ext = m_bv_util.mk_extract(to_ebits+1, 0, lz);
- lz_rest = m_bv_util.mk_extract(from_ebits-1, to_ebits+2, lz);
- lz_redor = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, lz_rest.get());
- m_simp.mk_eq(lz_redor, one1, lz_redor_bool);
- m_simp.mk_or(exponent_overflow, lz_redor_bool, exponent_overflow);
-
- res_exp = m_bv_util.mk_bv_sub(low, lz_ext);
- }
- else // from_ebits == (to_ebits + 2)
- res_exp = m_bv_util.mk_bv_sub(exp, lz);
-
- SASSERT(m_bv_util.get_bv_size(res_exp) == to_ebits+2);
- SASSERT(is_well_sorted(m, res_exp));
-
- dbg_decouple("fpa2bv_to_float_res_sig", res_sig);
- dbg_decouple("fpa2bv_to_float_res_exp", res_exp);
-
- expr_ref rounded(m);
- round(s, rm, res_sgn, res_sig, res_exp, rounded);
-
- expr_ref is_neg(m), sig_inf(m);
- m_simp.mk_eq(sgn, one1, is_neg);
- mk_ite(is_neg, ninf, pinf, sig_inf);
-
- dbg_decouple("fpa2bv_to_float_exp_ovf", exponent_overflow);
- mk_ite(exponent_overflow, sig_inf, rounded, v6);
-
- // And finally, we tie them together.
- mk_ite(c5, v5, v6, result);
- mk_ite(c4, v4, result, result);
- mk_ite(c3, v3, result, result);
- mk_ite(c2, v2, result, result);
- mk_ite(c1, v1, result, result);
- }
- }
- else if (num == 2 &&
- m_util.is_rm(args[0]),
+ else if (num == 2 &&
+ m_bv_util.is_bv(args[0]) &&
+ m_bv_util.get_bv_size(args[0]) == 3 &&
+ m_util.is_float(m.get_sort(args[1]))) {
+ // float -> float conversion
+ mk_to_fp_float(f, f->get_range(), args[0], args[1], result);
+ }
+ else if (num == 2 &&
+ m_bv_util.is_bv(args[0]) &&
+ m_bv_util.get_bv_size(args[0]) == 3 &&
m_arith_util.is_real(args[1])) {
- // .. other than that, we only support rationals for asFloat
- SASSERT(m_util.is_float(f->get_range()));
- unsigned ebits = m_util.get_ebits(f->get_range());
- unsigned sbits = m_util.get_sbits(f->get_range());
+ // rm + real -> float
+ mk_to_fp_real(f, f->get_range(), args[0], args[1], result);
+ }
+ else if (num == 2 &&
+ m_bv_util.is_bv(args[0]) &&
+ m_bv_util.get_bv_size(args[0]) == 3 &&
+ m_bv_util.is_bv(args[1])) {
+ mk_to_fp_signed(f, num, args, result);
+ }
+ else if (num == 3 &&
+ m_bv_util.is_bv(args[0]) &&
+ m_bv_util.is_bv(args[1]) &&
+ m_bv_util.is_bv(args[2])) {
+ SASSERT(m_bv_util.get_bv_size(args[0]) == 1);
+ SASSERT(m_util.get_ebits(f->get_range()) == m_bv_util.get_bv_size(args[1]));
+ SASSERT(m_util.get_sbits(f->get_range()) == m_bv_util.get_bv_size(args[2])+1);
+ mk_fp(args[0], args[1], args[2], result);
+ }
+ else if (num == 3 &&
+ m_bv_util.is_bv(args[0]) &&
+ m_arith_util.is_numeral(args[1]) &&
+ m_arith_util.is_numeral(args[2]))
+ {
+ mk_to_fp_real_int(f, num, args, result);
+ }
+ else
+ UNREACHABLE();
- SASSERT(m_bv_util.is_numeral(args[0]));
+ SASSERT(is_well_sorted(m, result));
+}
+
+void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result) {
+ unsigned from_sbits = m_util.get_sbits(m.get_sort(x));
+ unsigned from_ebits = m_util.get_ebits(m.get_sort(x));
+ unsigned to_sbits = m_util.get_sbits(s);
+ unsigned to_ebits = m_util.get_ebits(s);
+
+ if (from_sbits == to_sbits && from_ebits == to_ebits)
+ result = x;
+ else {
+ expr_ref c1(m), c2(m), c3(m), c4(m), c5(m);
+ expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m);
+ expr_ref one1(m);
+
+ one1 = m_bv_util.mk_numeral(1, 1);
+ expr_ref ninf(m), pinf(m);
+ mk_pinf(f, pinf);
+ mk_ninf(f, ninf);
+
+ // NaN -> NaN
+ mk_is_nan(x, c1);
+ mk_nan(f, v1);
+
+ // +0 -> +0
+ mk_is_pzero(x, c2);
+ mk_pzero(f, v2);
+
+ // -0 -> -0
+ mk_is_nzero(x, c3);
+ mk_nzero(f, v3);
+
+ // +oo -> +oo
+ mk_is_pinf(x, c4);
+ v4 = pinf;
+
+ // -oo -> -oo
+ mk_is_ninf(x, c5);
+ v5 = ninf;
+
+ // otherwise: the actual conversion with rounding.
+ expr_ref sgn(m), sig(m), exp(m), lz(m);
+ unpack(x, sgn, sig, exp, lz, true);
+
+ dbg_decouple("fpa2bv_to_float_x_sig", sig);
+ dbg_decouple("fpa2bv_to_float_x_exp", exp);
+ dbg_decouple("fpa2bv_to_float_lz", lz);
+
+ expr_ref res_sgn(m), res_sig(m), res_exp(m);
+
+ res_sgn = sgn;
+
+ SASSERT(m_bv_util.get_bv_size(sgn) == 1);
+ SASSERT(m_bv_util.get_bv_size(sig) == from_sbits);
+ SASSERT(m_bv_util.get_bv_size(exp) == from_ebits);
+ SASSERT(m_bv_util.get_bv_size(lz) == from_ebits);
+
+ if (from_sbits < (to_sbits + 3)) {
+ // make sure that sig has at least to_sbits + 3
+ res_sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, to_sbits + 3 - from_sbits));
+ }
+ else if (from_sbits >(to_sbits + 3)) {
+ // collapse the extra bits into a sticky bit.
+ expr_ref sticky(m), low(m), high(m);
+ low = m_bv_util.mk_extract(from_sbits - to_sbits - 3, 0, sig);
+ high = m_bv_util.mk_extract(from_sbits - 1, from_sbits - to_sbits - 2, sig);
+ sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, low.get());
+ res_sig = m_bv_util.mk_concat(high, sticky);
+ }
+ else
+ res_sig = sig;
+
+ res_sig = m_bv_util.mk_zero_extend(1, res_sig); // extra zero in the front for the rounder.
+ unsigned sig_sz = m_bv_util.get_bv_size(res_sig);
+ SASSERT(sig_sz == to_sbits + 4);
+
+ expr_ref exponent_overflow(m);
+ exponent_overflow = m.mk_false();
+
+ if (from_ebits < (to_ebits + 2)) {
+ res_exp = m_bv_util.mk_sign_extend(to_ebits - from_ebits + 2, exp);
+
+ // subtract lz for subnormal numbers.
+ expr_ref lz_ext(m);
+ lz_ext = m_bv_util.mk_zero_extend(to_ebits - from_ebits + 2, lz);
+ res_exp = m_bv_util.mk_bv_sub(res_exp, lz_ext);
+ }
+ else if (from_ebits >(to_ebits + 2)) {
+ expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), h_or_eq(m), h_and_eq(m);
+ expr_ref no_ovf(m), zero1(m), s_is_one(m), s_is_zero(m);
+ high = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, exp);
+ low = m_bv_util.mk_extract(to_ebits + 1, 0, exp);
+ lows = m_bv_util.mk_extract(to_ebits + 1, to_ebits + 1, low);
+
+ high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high.get());
+ high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high.get());
+
+ zero1 = m_bv_util.mk_numeral(0, 1);
+ m_simp.mk_eq(high_red_and, one1, h_and_eq);
+ m_simp.mk_eq(high_red_or, zero1, h_or_eq);
+ m_simp.mk_eq(lows, zero1, s_is_zero);
+ m_simp.mk_eq(lows, one1, s_is_one);
+
+ expr_ref c2(m);
+ m_simp.mk_ite(h_or_eq, s_is_one, m.mk_false(), c2);
+ m_simp.mk_ite(h_and_eq, s_is_zero, c2, exponent_overflow);
+
+ // Note: Upon overflow, we _could_ try to shift the significand around...
+
+ // subtract lz for subnormal numbers.
+ expr_ref lz_ext(m), lz_rest(m), lz_redor(m), lz_redor_bool(m);
+ lz_ext = m_bv_util.mk_extract(to_ebits + 1, 0, lz);
+ lz_rest = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, lz);
+ lz_redor = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, lz_rest.get());
+ m_simp.mk_eq(lz_redor, one1, lz_redor_bool);
+ m_simp.mk_or(exponent_overflow, lz_redor_bool, exponent_overflow);
+
+ res_exp = m_bv_util.mk_bv_sub(low, lz_ext);
+ }
+ else // from_ebits == (to_ebits + 2)
+ res_exp = m_bv_util.mk_bv_sub(exp, lz);
+
+ SASSERT(m_bv_util.get_bv_size(res_exp) == to_ebits + 2);
+ SASSERT(is_well_sorted(m, res_exp));
+
+ dbg_decouple("fpa2bv_to_float_res_sig", res_sig);
+ dbg_decouple("fpa2bv_to_float_res_exp", res_exp);
+
+ expr_ref rounded(m);
+ round(s, expr_ref (rm, m), res_sgn, res_sig, res_exp, rounded);
+
+ expr_ref is_neg(m), sig_inf(m);
+ m_simp.mk_eq(sgn, one1, is_neg);
+ mk_ite(is_neg, ninf, pinf, sig_inf);
+
+ dbg_decouple("fpa2bv_to_float_exp_ovf", exponent_overflow);
+ mk_ite(exponent_overflow, sig_inf, rounded, v6);
+
+ // And finally, we tie them together.
+ mk_ite(c5, v5, v6, result);
+ mk_ite(c4, v4, result, result);
+ mk_ite(c3, v3, result, result);
+ mk_ite(c2, v2, result, result);
+ mk_ite(c1, v1, result, result);
+ }
+
+ SASSERT(is_well_sorted(m, result));
+}
+
+void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result) {
+ TRACE("fpa2bv_to_fp_real", tout << "rm: " << mk_ismt2_pp(rm, m) << std::endl <<
+ "x: " << mk_ismt2_pp(x, m) << std::endl;);
+ SASSERT(m_util.is_float(s));
+ SASSERT(au().is_real(x));
+
+ unsigned ebits = m_util.get_ebits(s);
+ unsigned sbits = m_util.get_sbits(s);
+
+ if (m_bv_util.is_numeral(rm) && m_util.au().is_numeral(x)) {
rational tmp_rat; unsigned sz;
- m_bv_util.is_numeral(to_expr(args[0]), tmp_rat, sz);
+ m_bv_util.is_numeral(to_expr(rm), tmp_rat, sz);
SASSERT(tmp_rat.is_int32());
SASSERT(sz == 3);
BV_RM_VAL bv_rm = (BV_RM_VAL)tmp_rat.get_unsigned();
mpf_rounding_mode rm;
- switch (bv_rm)
- {
+ switch (bv_rm) {
case BV_RM_TIES_TO_AWAY: rm = MPF_ROUND_NEAREST_TAWAY; break;
case BV_RM_TIES_TO_EVEN: rm = MPF_ROUND_NEAREST_TEVEN; break;
case BV_RM_TO_NEGATIVE: rm = MPF_ROUND_TOWARD_NEGATIVE; break;
@@ -2116,104 +2083,787 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a
default: UNREACHABLE();
}
- SASSERT(m_util.au().is_numeral(args[1]));
-
rational q;
- m_util.au().is_numeral(args[1], q);
+ m_util.au().is_numeral(x, q);
- mpf v;
+ scoped_mpf v(m_mpf_manager);
m_util.fm().set(v, ebits, sbits, rm, q.to_mpq());
- expr * sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v)) ? 1 : 0, 1);
- expr * s = m_bv_util.mk_numeral(m_util.fm().sig(v), sbits - 1);
- expr * e = m_bv_util.mk_numeral(m_util.fm().exp(v), ebits);
+ expr_ref sgn(m), s(m), e(m), unbiased_exp(m);
+ sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v)) ? 1 : 0, 1);
+ s = m_bv_util.mk_numeral(m_util.fm().sig(v), sbits - 1);
+ unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v), ebits);
+ mk_bias(unbiased_exp, e);
- mk_triple(sgn, s, e, result);
-
- m_util.fm().del(v);
+ mk_fp(sgn, e, s, result);
}
- else
+ else {
+ mpf_manager & fm = fu().fm();
+ bv_util & bu = m_bv_util;
+ arith_util & au = m_arith_util;
+
+ expr_ref bv0(m), bv1(m), zero(m), two(m);
+ bv0 = bu.mk_numeral(0, 1);
+ bv1 = bu.mk_numeral(1, 1);
+ zero = au.mk_numeral(rational(0), false);
+ two = au.mk_numeral(rational(2), false);
+
+ expr_ref sgn(m), sig(m), exp(m);
+ sgn = mk_fresh_const("fpa2bv_to_fp_real_sgn", 1);
+ sig = mk_fresh_const("fpa2bv_to_fp_real_sig", sbits + 4);
+ exp = mk_fresh_const("fpa2bv_to_fp_real_exp", ebits + 2);
+
+ expr_ref rme(rm, m);
+ round(s, rme, sgn, sig, exp, result);
+
+ expr * e = m.mk_eq(m_util.mk_to_real(result), x);
+ m_extra_assertions.push_back(e);
+ }
+
+ SASSERT(is_well_sorted(m, result));
+}
+
+void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
+ // rm + real + int -> float
+ SASSERT(m_util.is_float(f->get_range()));
+ unsigned ebits = m_util.get_ebits(f->get_range());
+ unsigned sbits = m_util.get_sbits(f->get_range());
+
+ expr * rm = args[0];
+
+ rational q;
+ if (!m_arith_util.is_numeral(args[1], q))
UNREACHABLE();
- SASSERT(is_well_sorted(m, result));
+ rational e;
+ if (!m_arith_util.is_numeral(args[2], e))
+ UNREACHABLE();
+
+ SASSERT(e.is_int64());
+ SASSERT(m_mpz_manager.eq(e.to_mpq().denominator(), 1));
+
+ scoped_mpf nte(m_mpf_manager), nta(m_mpf_manager), tp(m_mpf_manager), tn(m_mpf_manager), tz(m_mpf_manager);
+ m_mpf_manager.set(nte, ebits, sbits, MPF_ROUND_NEAREST_TEVEN, q.to_mpq(), e.to_mpq().numerator());
+ m_mpf_manager.set(nta, ebits, sbits, MPF_ROUND_NEAREST_TAWAY, q.to_mpq(), e.to_mpq().numerator());
+ m_mpf_manager.set(tp, ebits, sbits, MPF_ROUND_TOWARD_POSITIVE, q.to_mpq(), e.to_mpq().numerator());
+ m_mpf_manager.set(tn, ebits, sbits, MPF_ROUND_TOWARD_NEGATIVE, q.to_mpq(), e.to_mpq().numerator());
+ m_mpf_manager.set(tz, ebits, sbits, MPF_ROUND_TOWARD_ZERO, q.to_mpq(), e.to_mpq().numerator());
+
+ app_ref a_nte(m), a_nta(m), a_tp(m), a_tn(m), a_tz(m);
+ a_nte = m_plugin->mk_numeral(nte);
+ a_nta = m_plugin->mk_numeral(nta);
+ a_tp = m_plugin->mk_numeral(tp);
+ a_tn = m_plugin->mk_numeral(tn);
+ a_tz = m_plugin->mk_numeral(tz);
+
+ expr_ref bv_nte(m), bv_nta(m), bv_tp(m), bv_tn(m), bv_tz(m);
+ mk_numeral(a_nte->get_decl(), 0, 0, bv_nte);
+ mk_numeral(a_nta->get_decl(), 0, 0, bv_nta);
+ mk_numeral(a_tp->get_decl(), 0, 0, bv_tp);
+ mk_numeral(a_tn->get_decl(), 0, 0, bv_tn);
+ mk_numeral(a_tz->get_decl(), 0, 0, bv_tz);
+
+ expr_ref c1(m), c2(m), c3(m), c4(m);
+ c1 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3));
+ c2 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3));
+ c3 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3));
+ c4 = m.mk_eq(rm, m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3));
+
+ mk_ite(c1, bv_tn, bv_tz, result);
+ mk_ite(c2, bv_tp, result, result);
+ mk_ite(c3, bv_nta, result, result);
+ mk_ite(c4, bv_nte, result, result);
+}
+void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
+ TRACE("fpa2bv_to_real", for (unsigned i = 0; i < num; i++)
+ tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;);
+ SASSERT(num == 1);
+ SASSERT(f->get_num_parameters() == 0);
+ SASSERT(is_app_of(args[0], m_plugin->get_family_id(), OP_FPA_FP));
+
+ expr * x = args[0];
+ sort * s = m.get_sort(x);
+ unsigned ebits = m_util.get_ebits(s);
+ unsigned sbits = m_util.get_sbits(s);
+
+ sort * rs = m_arith_util.mk_real();
+ expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m);
+ mk_is_nan(x, x_is_nan);
+ mk_is_inf(x, x_is_inf);
+ mk_is_zero(x, x_is_zero);
+
+ expr_ref sgn(m), sig(m), exp(m), lz(m);
+ unpack(x, sgn, sig, exp, lz, true);
+ // sig is of the form [1].[sigbits]
+
+ SASSERT(m_bv_util.get_bv_size(sgn) == 1);
+ SASSERT(m_bv_util.get_bv_size(sig) == sbits);
+ SASSERT(m_bv_util.get_bv_size(exp) == ebits);
+
+ expr_ref rsig(m), bit(m), zero(m), one(m), two(m), bv0(m), bv1(m);
+ zero = m_arith_util.mk_numeral(rational(0), rs);
+ one = m_arith_util.mk_numeral(rational(1), rs);
+ two = m_arith_util.mk_numeral(rational(2), rs);
+ bv0 = m_bv_util.mk_numeral(0, 1);
+ bv1 = m_bv_util.mk_numeral(1, 1);
+ rsig = one;
+ for (unsigned i = sbits - 2; i != (unsigned)-1; i--) {
+ bit = m_bv_util.mk_extract(i, i, sig);
+ rsig = m_arith_util.mk_add(m_arith_util.mk_mul(rsig, two),
+ m.mk_ite(m.mk_eq(bit, bv1), one, zero));
+ }
+
+ const mpz & p2 = fu().fm().m_powers2(sbits - 1);
+ expr_ref ep2(m);
+ ep2 = m_arith_util.mk_numeral(rational(p2), false);
+ rsig = m_arith_util.mk_div(rsig, ep2);
+ dbg_decouple("fpa2bv_to_real_ep2", ep2);
+ dbg_decouple("fpa2bv_to_real_rsig", rsig);
+
+ expr_ref exp_n(m), exp_p(m), exp_is_neg(m), exp_abs(m);
+ exp_is_neg = m.mk_eq(m_bv_util.mk_extract(ebits - 1, ebits - 1, exp), bv1);
+ dbg_decouple("fpa2bv_to_real_exp_is_neg", exp_is_neg);
+ exp_p = m_bv_util.mk_sign_extend(1, exp);
+ exp_n = m_bv_util.mk_bv_neg(exp_p);
+ exp_abs = m.mk_ite(exp_is_neg, exp_n, exp_p);
+ dbg_decouple("fpa2bv_to_real_exp_abs", exp);
+ SASSERT(m_bv_util.get_bv_size(exp_abs) == ebits + 1);
+
+ expr_ref exp2(m), prev_bit(m);
+ exp2 = zero;
+ for (unsigned i = ebits; i != (unsigned)-1; i--) {
+ bit = m_bv_util.mk_extract(i, i, exp_abs);
+ exp2 = m_arith_util.mk_add(m_arith_util.mk_mul(exp2, two),
+ m.mk_ite(m.mk_eq(bit, bv1), one, zero));
+ prev_bit = bit;
+ }
+
+ exp2 = m.mk_ite(exp_is_neg, m_arith_util.mk_div(one, exp2), exp2);
+ dbg_decouple("fpa2bv_to_real_exp2", exp2);
+
+ expr_ref res(m), two_exp2(m);
+ two_exp2 = m_arith_util.mk_power(two, exp2);
+ res = m_arith_util.mk_mul(rsig, two_exp2);
+ res = m.mk_ite(m.mk_eq(sgn, bv1), m_arith_util.mk_uminus(res), res);
+ dbg_decouple("fpa2bv_to_real_sig_times_exp2", res);
+
+ TRACE("fpa2bv_to_real", tout << "rsig = " << mk_ismt2_pp(rsig, m) << std::endl;
+ tout << "exp2 = " << mk_ismt2_pp(exp2, m) << std::endl;);
+
+ result = m.mk_ite(x_is_zero, zero, res);
+ result = m.mk_ite(x_is_inf, mk_to_real_unspecified(), result);
+ result = m.mk_ite(x_is_nan, mk_to_real_unspecified(), result);
+
+ SASSERT(is_well_sorted(m, result));
+}
+
+void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
+ TRACE("fpa2bv_to_fp_signed", for (unsigned i = 0; i < num; i++)
+ tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;);
+
+ // This is a conversion from signed bitvector to float:
+ // ; from signed machine integer, represented as a 2's complement bit vector
+ // ((_ to_fp eb sb) RoundingMode (_ BitVec m) (_ FloatingPoint eb sb))
+ // Semantics:
+ // Let b in[[(_ BitVec m)]] and let n be the signed integer represented by b (in 2's complement format).
+ // [[(_ to_fp eb sb)]](r, b) = +/ -infinity if n is too large / too small to be represented as a finite
+ // number of [[(_ FloatingPoint eb sb)]]; [[(_ to_fp eb sb)]](r, x) = y otherwise, where y is the finite
+ // number such that [[fp.to_real]](y) is closest to n according to rounding mode r.
+
+ SASSERT(num == 2);
+ SASSERT(m_util.is_float(f->get_range()));
+ SASSERT(m_bv_util.is_bv(args[0]));
+ SASSERT(m_bv_util.is_bv(args[1]));
+
+ expr_ref rm(m), x(m);
+ rm = args[0];
+ x = args[1];
+
+ dbg_decouple("fpa2bv_to_fp_signed_x", x);
+
+ unsigned ebits = m_util.get_ebits(f->get_range());
+ unsigned sbits = m_util.get_sbits(f->get_range());
+ unsigned f_sz = sbits + ebits;
+ unsigned bv_sz = m_bv_util.get_bv_size(x);
+ SASSERT(m_bv_util.get_bv_size(rm) == 3);
+
+ expr_ref bv0_1(m), bv1_1(m), bv0_sz(m), bv1_sz(m);
+ bv0_1 = m_bv_util.mk_numeral(0, 1);
+ bv1_1 = m_bv_util.mk_numeral(1, 1);
+ bv0_sz = m_bv_util.mk_numeral(0, bv_sz);
+ bv1_sz = m_bv_util.mk_numeral(1, bv_sz);
+
+ expr_ref is_zero(m), nzero(m), pzero(m), ninf(m), pinf(m);
+ is_zero = m.mk_eq(x, bv0_sz);
+ mk_nzero(f, nzero);
+ mk_pzero(f, pzero);
+ mk_ninf(f, ninf);
+ mk_pinf(f, pinf);
+
+ // Special case: x == 0 -> p/n zero
+ expr_ref c1(m), v1(m), rm_is_to_neg(m);
+ c1 = is_zero;
+ mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
+ mk_ite(rm_is_to_neg, nzero, pzero, v1);
+
+ // Special case: x != 0
+ expr_ref is_neg_bit(m), exp_too_large(m), sig_4(m), exp_2(m);
+ expr_ref is_neg(m), x_abs(m);
+ is_neg_bit = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, x);
+ is_neg = m.mk_eq(is_neg_bit, bv1_1);
+ x_abs = m.mk_ite(is_neg, m_bv_util.mk_bv_neg(x), x);
+ dbg_decouple("fpa2bv_to_fp_signed_is_neg", is_neg);
+ // x_abs has an extra bit in the front.
+ // x_abs is [bv_sz-1, bv_sz-2] . [bv_sz-3 ... 0] * 2^(bv_sz-2)
+ // bv_sz-2 is the "1.0" bit for the rounder.
+
+ expr_ref lz(m), e_bv_sz(m), e_rest_sz(m);
+ mk_leading_zeros(x_abs, bv_sz, lz);
+ e_bv_sz = m_bv_util.mk_numeral(bv_sz, bv_sz);
+ e_rest_sz = m_bv_util.mk_bv_sub(e_bv_sz, lz);
+ SASSERT(m_bv_util.get_bv_size(lz) == m_bv_util.get_bv_size(e_bv_sz));
+ dbg_decouple("fpa2bv_to_fp_signed_lz", lz);
+ expr_ref shifted_sig(m);
+ shifted_sig = m_bv_util.mk_bv_shl(x_abs, lz);
+
+ expr_ref sticky(m);
+ // shifted_sig is [bv_sz-1, bv_sz-2] . [bv_sz-3 ... 0] * 2^(bv_sz-2) * 2^(-lz)
+ unsigned sig_sz = sbits + 4; // we want extra rounding bits.
+ if (sig_sz <= bv_sz) {
+ expr_ref sig_rest(m);
+ sig_4 = m_bv_util.mk_extract(bv_sz - 1, bv_sz - sig_sz + 1, shifted_sig); // one short
+ sig_rest = m_bv_util.mk_extract(bv_sz - sig_sz, 0, shifted_sig);
+ sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sig_rest);
+ sig_4 = m_bv_util.mk_concat(sig_4, sticky);
+ }
+ else {
+ unsigned extra_bits = sig_sz - bv_sz;
+ expr_ref extra_zeros(m);
+ extra_zeros = m_bv_util.mk_numeral(0, extra_bits);
+ sig_4 = m_bv_util.mk_concat(shifted_sig, extra_zeros);
+ lz = m_bv_util.mk_bv_add(m_bv_util.mk_concat(extra_zeros, lz),
+ m_bv_util.mk_numeral(extra_bits, sig_sz));
+ bv_sz = bv_sz + extra_bits;
+ SASSERT(is_well_sorted(m, lz));
+ }
+ SASSERT(m_bv_util.get_bv_size(sig_4) == sig_sz);
+
+ expr_ref s_exp(m), exp_rest(m);
+ s_exp = m_bv_util.mk_bv_sub(m_bv_util.mk_numeral(bv_sz - 2, bv_sz), lz);
+ // s_exp = (bv_sz-2) + (-lz) signed
+ SASSERT(m_bv_util.get_bv_size(s_exp) == bv_sz);
+
+ unsigned exp_sz = ebits + 2; // (+2 for rounder)
+ exp_2 = m_bv_util.mk_extract(exp_sz - 1, 0, s_exp);
+ // the remaining bits are 0 if ebits is large enough.
+ exp_too_large = m.mk_false();
+
+ // The exponent is at most bv_sz, i.e., we need ld(bv_sz)+1 ebits.
+ // exp < bv_sz (+sign bit which is [0])
+ unsigned exp_worst_case_sz = (unsigned)((log((double)bv_sz) / log((double)2)) + 1.0);
+
+ TRACE("fpa2bv_to_fp_signed", tout << "exp worst case sz: " << exp_worst_case_sz << std::endl;);
+
+ if (exp_sz < exp_worst_case_sz) {
+ // exp_sz < exp_worst_case_sz and exp >= 0.
+ // Take the maximum legal exponent; this
+ // allows us to keep the most precision.
+ expr_ref max_exp(m), max_exp_bvsz(m);
+ mk_max_exp(exp_sz, max_exp);
+ max_exp_bvsz = m_bv_util.mk_zero_extend(bv_sz - exp_sz, max_exp);
+
+ exp_too_large = m_bv_util.mk_ule(m_bv_util.mk_bv_add(
+ max_exp_bvsz,
+ m_bv_util.mk_numeral(1, bv_sz)),
+ s_exp);
+ sig_4 = m.mk_ite(exp_too_large, m_bv_util.mk_numeral(0, sig_sz), sig_4);
+ exp_2 = m.mk_ite(exp_too_large, max_exp, exp_2);
+ }
+ dbg_decouple("fpa2bv_to_fp_signed_exp_too_large", exp_too_large);
+
+ expr_ref sgn(m), sig(m), exp(m);
+ sgn = is_neg_bit;
+ sig = sig_4;
+ exp = exp_2;
+
+ dbg_decouple("fpa2bv_to_fp_signed_sgn", sgn);
+ dbg_decouple("fpa2bv_to_fp_signed_sig", sig);
+ dbg_decouple("fpa2bv_to_fp_signed_exp", exp);
+
+ SASSERT(m_bv_util.get_bv_size(sig) == sbits + 4);
+ SASSERT(m_bv_util.get_bv_size(exp) == ebits + 2);
+
+ expr_ref v2(m);
+ round(f->get_range(), rm, sgn, sig, exp, v2);
+
+ mk_ite(c1, v1, v2, result);
+}
+
+void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
+ TRACE("fpa2bv_to_fp_unsigned", for (unsigned i = 0; i < num; i++)
+ tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;);
+
+ // This is a conversion from unsigned bitvector to float:
+ // ((_ to_fp_unsigned eb sb) RoundingMode (_ BitVec m) (_ FloatingPoint eb sb))
+ // Semantics:
+ // Let b in[[(_ BitVec m)]] and let n be the unsigned integer represented by b.
+ // [[(_ to_fp_unsigned eb sb)]](r, x) = +infinity if n is too large to be
+ // represented as a finite number of[[(_ FloatingPoint eb sb)]];
+ // [[(_ to_fp_unsigned eb sb)]](r, x) = y otherwise, where y is the finite number
+ // such that[[fp.to_real]](y) is closest to n according to rounding mode r.
+
+ SASSERT(num == 2);
+ SASSERT(m_util.is_float(f->get_range()));
+ SASSERT(m_bv_util.is_bv(args[0]));
+ SASSERT(m_bv_util.is_bv(args[1]));
+
+ expr_ref rm(m), x(m);
+ rm = args[0];
+ x = args[1];
+
+ dbg_decouple("fpa2bv_to_fp_unsigned_x", x);
+
+ unsigned ebits = m_util.get_ebits(f->get_range());
+ unsigned sbits = m_util.get_sbits(f->get_range());
+ unsigned f_sz = sbits + ebits;
+ unsigned bv_sz = m_bv_util.get_bv_size(x);
+ SASSERT(m_bv_util.get_bv_size(rm) == 3);
+
+ expr_ref bv0_1(m), bv1_1(m), bv0_sz(m), bv1_sz(m);
+ bv0_1 = m_bv_util.mk_numeral(0, 1);
+ bv1_1 = m_bv_util.mk_numeral(1, 1);
+ bv0_sz = m_bv_util.mk_numeral(0, bv_sz);
+ bv1_sz = m_bv_util.mk_numeral(1, bv_sz);
+
+ expr_ref is_zero(m), nzero(m), pzero(m), ninf(m), pinf(m);
+ is_zero = m.mk_eq(x, bv0_sz);
+ mk_nzero(f, nzero);
+ mk_pzero(f, pzero);
+ mk_ninf(f, ninf);
+ mk_pinf(f, pinf);
+
+ // Special case: x == 0 -> p/n zero
+ expr_ref c1(m), v1(m), rm_is_to_neg(m);
+ c1 = is_zero;
+ mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
+ mk_ite(rm_is_to_neg, nzero, pzero, v1);
+
+ // Special case: x != 0
+ expr_ref exp_too_large(m), sig_4(m), exp_2(m);
+ // x is [bv_sz-1] . [bv_sz-2 ... 0] * 2^(bv_sz-1)
+ // bv_sz-1 is the "1.0" bit for the rounder.
+
+ expr_ref lz(m), e_bv_sz(m), e_rest_sz(m);
+ mk_leading_zeros(x, bv_sz, lz);
+ e_bv_sz = m_bv_util.mk_numeral(bv_sz, bv_sz);
+ e_rest_sz = m_bv_util.mk_bv_sub(e_bv_sz, lz);
+ SASSERT(m_bv_util.get_bv_size(lz) == m_bv_util.get_bv_size(e_bv_sz));
+ dbg_decouple("fpa2bv_to_fp_unsigned_lz", lz);
+ expr_ref shifted_sig(m);
+ shifted_sig = m_bv_util.mk_bv_shl(x, lz);
+
+ expr_ref sticky(m);
+ // shifted_sig is [bv_sz-1] . [bv_sz-2 ... 0] * 2^(bv_sz-1) * 2^(-lz)
+ unsigned sig_sz = sbits + 4; // we want extra rounding bits.
+ if (sig_sz <= bv_sz) {
+ expr_ref sig_rest(m);
+ sig_4 = m_bv_util.mk_extract(bv_sz - 1, bv_sz - sig_sz + 1, shifted_sig); // one short
+ sig_rest = m_bv_util.mk_extract(bv_sz - sig_sz, 0, shifted_sig);
+ sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sig_rest);
+ sig_4 = m_bv_util.mk_concat(sig_4, sticky);
+ }
+ else {
+ unsigned extra_bits = sig_sz - bv_sz;
+ expr_ref extra_zeros(m);
+ extra_zeros = m_bv_util.mk_numeral(0, extra_bits);
+ sig_4 = m_bv_util.mk_concat(shifted_sig, extra_zeros);
+ lz = m_bv_util.mk_bv_add(m_bv_util.mk_concat(extra_zeros, lz),
+ m_bv_util.mk_numeral(extra_bits, sig_sz));
+ bv_sz = bv_sz + extra_bits;
+ SASSERT(is_well_sorted(m, lz));
+ }
+ SASSERT(m_bv_util.get_bv_size(sig_4) == sig_sz);
+
+ expr_ref s_exp(m), exp_rest(m);
+ s_exp = m_bv_util.mk_bv_sub(m_bv_util.mk_numeral(bv_sz - 2, bv_sz), lz);
+ // s_exp = (bv_sz-2) + (-lz) signed
+ SASSERT(m_bv_util.get_bv_size(s_exp) == bv_sz);
+
+ unsigned exp_sz = ebits + 2; // (+2 for rounder)
+ exp_2 = m_bv_util.mk_extract(exp_sz - 1, 0, s_exp);
+ // the remaining bits are 0 if ebits is large enough.
+ exp_too_large = m.mk_false(); // This is always in range.
+
+ // The exponent is at most bv_sz, i.e., we need ld(bv_sz)+1 ebits.
+ // exp < bv_sz (+sign bit which is [0])
+ unsigned exp_worst_case_sz = (unsigned)((log((double)bv_sz) / log((double)2)) + 1.0);
+
+ if (exp_sz < exp_worst_case_sz) {
+ // exp_sz < exp_worst_case_sz and exp >= 0.
+ // Take the maximum legal exponent; this
+ // allows us to keep the most precision.
+ expr_ref max_exp(m), max_exp_bvsz(m);
+ mk_max_exp(exp_sz, max_exp);
+ max_exp_bvsz = m_bv_util.mk_zero_extend(bv_sz - exp_sz, max_exp);
+
+ exp_too_large = m_bv_util.mk_ule(m_bv_util.mk_bv_add(
+ max_exp_bvsz,
+ m_bv_util.mk_numeral(1, bv_sz)),
+ s_exp);
+ sig_4 = m.mk_ite(exp_too_large, m_bv_util.mk_numeral(0, sig_sz), sig_4);
+ exp_2 = m.mk_ite(exp_too_large, max_exp, exp_2);
+ }
+ dbg_decouple("fpa2bv_to_fp_unsigned_exp_too_large", exp_too_large);
+
+ expr_ref sgn(m), sig(m), exp(m);
+ sgn = bv0_1;
+ sig = sig_4;
+ exp = exp_2;
+
+ dbg_decouple("fpa2bv_to_fp_unsigned_sgn", sgn);
+ dbg_decouple("fpa2bv_to_fp_unsigned_sig", sig);
+ dbg_decouple("fpa2bv_to_fp_unsigned_exp", exp);
+
+ SASSERT(m_bv_util.get_bv_size(sig) == sbits + 4);
+ SASSERT(m_bv_util.get_bv_size(exp) == ebits + 2);
+
+ expr_ref v2(m);
+ round(f->get_range(), rm, sgn, sig, exp, v2);
+
+ mk_ite(c1, v1, v2, result);
}
void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 1);
expr * sgn, * s, * e;
- split(args[0], sgn, s, e);
+ split_fp(args[0], sgn, e, s);
result = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s);
}
+void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
+ TRACE("fpa2bv_to_ubv", for (unsigned i = 0; i < num; i++)
+ tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;);
+
+ SASSERT(f->get_num_parameters() == 1);
+ SASSERT(f->get_parameter(0).is_int());
+ SASSERT(num == 2);
+ SASSERT(m_bv_util.get_bv_size(args[0]) == 3);
+ SASSERT(m_util.is_float(args[1]));
+
+ expr * rm = args[0];
+ expr * x = args[1];
+ sort * xs = m.get_sort(x);
+ sort * bv_srt = f->get_range();
+
+ unsigned ebits = m_util.get_ebits(xs);
+ unsigned sbits = m_util.get_sbits(xs);
+ unsigned bv_sz = (unsigned)f->get_parameter(0).get_int();
+ unsigned rounding_sz = bv_sz + 3;
+
+ expr_ref bv0(m), bv1(m);
+ bv0 = m_bv_util.mk_numeral(0, 1);
+ bv1 = m_bv_util.mk_numeral(1, 1);
+
+ expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m), x_is_neg(m), x_is_nzero(m);
+ mk_is_nan(x, x_is_nan);
+ mk_is_inf(x, x_is_inf);
+ mk_is_zero(x, x_is_zero);
+ mk_is_neg(x, x_is_neg);
+ mk_is_nzero(x, x_is_nzero);
+
+ // NaN, Inf, or negative (except -0) -> unspecified
+ expr_ref c1(m), v1(m);
+ c1 = m.mk_or(x_is_nan, x_is_inf, m.mk_and(x_is_neg, m.mk_not(x_is_nzero)));
+ v1 = mk_to_ubv_unspecified(bv_sz);
+ dbg_decouple("fpa2bv_to_ubv_c1", c1);
+
+ // +-Zero -> 0
+ expr_ref c2(m), v2(m);
+ c2 = x_is_zero;
+ v2 = m_bv_util.mk_numeral(rational(0), bv_srt);
+ dbg_decouple("fpa2bv_to_ubv_c2", c2);
+
+ // Otherwise...
+ expr_ref sgn(m), sig(m), exp(m), lz(m);
+ unpack(x, sgn, sig, exp, lz, true);
+
+ // sig is of the form +- [1].[sig] * 2^(exp-lz)
+ SASSERT(m_bv_util.get_bv_size(sgn) == 1);
+ SASSERT(m_bv_util.get_bv_size(sig) == sbits);
+ SASSERT(m_bv_util.get_bv_size(exp) == ebits);
+ SASSERT(m_bv_util.get_bv_size(lz) == ebits);
+ dbg_decouple("fpa2bv_to_ubv_sig", sig);
+ unsigned sig_sz = m_bv_util.get_bv_size(sig);
+ SASSERT(sig_sz == sbits);
+ if (sig_sz < (bv_sz + 3))
+ sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, bv_sz - sig_sz + 3));
+ sig_sz = m_bv_util.get_bv_size(sig);
+ SASSERT(sig_sz >= (bv_sz + 3));
+
+ expr_ref exp_m_lz(m), shift(m), shift_neg(m), bv0_e2(m), shift_abs(m);
+ exp_m_lz = m_bv_util.mk_bv_sub(m_bv_util.mk_sign_extend(2, exp),
+ m_bv_util.mk_zero_extend(2, lz));
+ shift = m_bv_util.mk_bv_sub(exp_m_lz,
+ m_bv_util.mk_numeral(bv_sz - 1, ebits + 2));
+ shift_neg = m_bv_util.mk_bv_neg(shift);
+ bv0_e2 = m_bv_util.mk_numeral(0, ebits + 2);
+ shift_abs = m.mk_ite(m_bv_util.mk_sle(shift, bv0_e2), shift_neg, shift);
+ SASSERT(m_bv_util.get_bv_size(shift) == ebits + 2);
+ SASSERT(m_bv_util.get_bv_size(shift_neg) == ebits + 2);
+ SASSERT(m_bv_util.get_bv_size(shift_abs) == ebits + 2);
+ dbg_decouple("fpa2bv_to_ubv_shift", shift);
+ dbg_decouple("fpa2bv_to_ubv_shift_abs", shift_abs);
+
+ // x is of the form +- [1].[sig][r][g][s] ... and at least bv_sz + 3 long
+ // [1][ ... sig ... ][r][g][ ... s ...]
+ // [ ... ubv ... ][r][g][ ... s ... ]
+ expr_ref max_shift(m);
+ max_shift = m_bv_util.mk_numeral(sig_sz, sig_sz);
+ shift_abs = m_bv_util.mk_zero_extend(sig_sz - ebits - 2, shift_abs);
+ SASSERT(m_bv_util.get_bv_size(shift_abs) == sig_sz);
+
+ expr_ref c_in_limits(m);
+ c_in_limits = m_bv_util.mk_sle(shift, m_bv_util.mk_numeral(0, ebits + 2));
+ dbg_decouple("fpa2bv_to_ubv_in_limits", c_in_limits);
+
+ expr_ref shifted_sig(m);
+ shifted_sig = m_bv_util.mk_bv_lshr(sig, shift_abs);
+ dbg_decouple("fpa2bv_to_ubv_shifted_sig", shifted_sig);
+
+ expr_ref last(m), round(m), sticky(m);
+ last = m_bv_util.mk_extract(sig_sz - bv_sz - 0, sig_sz - bv_sz - 0, shifted_sig);
+ round = m_bv_util.mk_extract(sig_sz - bv_sz - 1, sig_sz - bv_sz - 1, shifted_sig);
+ sticky = m.mk_ite(m.mk_eq(m_bv_util.mk_extract(sig_sz - bv_sz - 2, 0, shifted_sig),
+ m_bv_util.mk_numeral(0, sig_sz - (bv_sz + 3) + 2)),
+ bv0,
+ bv1);
+ dbg_decouple("fpa2bv_to_ubv_last", last);
+ dbg_decouple("fpa2bv_to_ubv_round", round);
+ dbg_decouple("fpa2bv_to_ubv_sticky", sticky);
+
+ expr_ref rounding_decision(m);
+ rounding_decision = mk_rounding_decision(rm, sgn, last, round, sticky);
+ SASSERT(m_bv_util.get_bv_size(rounding_decision) == 1);
+ dbg_decouple("fpa2bv_to_ubv_rounding_decision", rounding_decision);
+
+ expr_ref unrounded_sig(m), pre_rounded(m), inc(m);
+ unrounded_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_extract(sig_sz - 1, sig_sz - bv_sz, shifted_sig));
+ inc = m_bv_util.mk_zero_extend(1, m_bv_util.mk_zero_extend(bv_sz - 1, rounding_decision));
+ pre_rounded = m_bv_util.mk_bv_add(unrounded_sig, inc);
+
+ expr_ref rnd_overflow(m), rnd(m), rnd_has_overflown(m);
+ rnd_overflow = m_bv_util.mk_extract(bv_sz, bv_sz, pre_rounded);
+ rnd = m_bv_util.mk_extract(bv_sz - 1, 0, pre_rounded);
+ rnd_has_overflown = m.mk_eq(rnd_overflow, bv1);
+ dbg_decouple("fpa2bv_to_ubv_rnd_has_overflown", rnd_has_overflown);
+
+ result = m.mk_ite(rnd_has_overflown, mk_to_ubv_unspecified(bv_sz), rnd);
+ result = m.mk_ite(c_in_limits, result, mk_to_ubv_unspecified(bv_sz));
+ result = m.mk_ite(c2, v2, result);
+ result = m.mk_ite(c1, v1, result);
+
+ SASSERT(is_well_sorted(m, result));
+}
+
+void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
+ TRACE("fpa2bv_to_sbv", for (unsigned i = 0; i < num; i++)
+ tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;);
+
+ SASSERT(f->get_num_parameters() == 1);
+ SASSERT(f->get_parameter(0).is_int());
+ SASSERT(num == 2);
+ SASSERT(m_bv_util.get_bv_size(args[0]) == 3);
+ SASSERT(m_util.is_float(args[1]));
+
+ expr * rm = args[0];
+ expr * x = args[1];
+ sort * xs = m.get_sort(x);
+ sort * bv_srt = f->get_range();
+
+ unsigned ebits = m_util.get_ebits(xs);
+ unsigned sbits = m_util.get_sbits(xs);
+ unsigned bv_sz = (unsigned)f->get_parameter(0).get_int();
+ unsigned rounding_sz = bv_sz + 3;
+
+ expr_ref bv0(m), bv1(m), bv0_2(m), bv1_2(m), bv3_2(m);
+ bv0 = m_bv_util.mk_numeral(0, 1);
+ bv1 = m_bv_util.mk_numeral(1, 1);
+ bv0_2 = m_bv_util.mk_numeral(0, 2);
+ bv1_2 = m_bv_util.mk_numeral(1, 2);
+ bv3_2 = m_bv_util.mk_numeral(3, 2);
+
+ expr_ref x_is_nan(m), x_is_inf(m), x_is_zero(m), x_is_neg(m), x_is_nzero(m);
+ mk_is_nan(x, x_is_nan);
+ mk_is_inf(x, x_is_inf);
+ mk_is_zero(x, x_is_zero);
+ mk_is_neg(x, x_is_neg);
+ mk_is_nzero(x, x_is_nzero);
+
+ // NaN, Inf -> unspecified
+ expr_ref c1(m), v1(m);
+ c1 = m.mk_or(x_is_nan, x_is_inf);
+ v1 = mk_to_sbv_unspecified(bv_sz);
+ dbg_decouple("fpa2bv_to_sbv_c1", c1);
+
+ // +-Zero -> 0
+ expr_ref c2(m), v2(m);
+ c2 = x_is_zero;
+ v2 = m_bv_util.mk_numeral(rational(0), bv_srt);
+ dbg_decouple("fpa2bv_to_sbv_c2", c2);
+
+ // Otherwise...
+ expr_ref sgn(m), sig(m), exp(m), lz(m);
+ unpack(x, sgn, sig, exp, lz, true);
+
+ dbg_decouple("fpa2bv_to_sbv_sgn", sgn);
+ dbg_decouple("fpa2bv_to_sbv_sig", sig);
+ dbg_decouple("fpa2bv_to_sbv_exp", exp);
+
+ // x is of the form +- [1].[sig] * 2^(exp-lz)
+ SASSERT(m_bv_util.get_bv_size(sgn) == 1);
+ SASSERT(m_bv_util.get_bv_size(sig) == sbits);
+ SASSERT(m_bv_util.get_bv_size(exp) == ebits);
+ SASSERT(m_bv_util.get_bv_size(lz) == ebits);
+ dbg_decouple("fpa2bv_to_sbv_sig", sig);
+ unsigned sig_sz = m_bv_util.get_bv_size(sig);
+ SASSERT(sig_sz == sbits);
+ if (sig_sz < (bv_sz + 3))
+ sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, bv_sz - sig_sz + 3));
+ sig_sz = m_bv_util.get_bv_size(sig);
+ SASSERT(sig_sz >= (bv_sz + 3));
+
+ expr_ref exp_m_lz(m), shift(m), shift_neg(m), bv0_e2(m), shift_abs(m);
+ exp_m_lz = m_bv_util.mk_bv_sub(m_bv_util.mk_sign_extend(2, exp),
+ m_bv_util.mk_zero_extend(2, lz));
+ shift = m_bv_util.mk_bv_sub(exp_m_lz,
+ m_bv_util.mk_numeral(bv_sz - 1, ebits + 2));
+ shift_neg = m_bv_util.mk_bv_neg(shift);
+ bv0_e2 = m_bv_util.mk_numeral(0, ebits + 2);
+ shift_abs = m.mk_ite(m_bv_util.mk_sle(shift, bv0_e2), shift_neg, shift);
+ SASSERT(m_bv_util.get_bv_size(shift) == ebits + 2);
+ SASSERT(m_bv_util.get_bv_size(shift_neg) == ebits + 2);
+ SASSERT(m_bv_util.get_bv_size(shift_abs) == ebits + 2);
+ dbg_decouple("fpa2bv_to_sbv_shift", shift);
+ dbg_decouple("fpa2bv_to_sbv_shift_abs", shift_abs);
+
+ // sig is of the form +- [1].[sig][r][g][s] ... and at least bv_sz + 3 long
+ // [1][ ... sig ... ][r][g][ ... s ...]
+ // [ ... ubv ... ][r][g][ ... s ... ]
+ expr_ref max_shift(m);
+ max_shift = m_bv_util.mk_numeral(sig_sz, sig_sz);
+ shift_abs = m_bv_util.mk_zero_extend(sig_sz - ebits - 2, shift_abs);
+ SASSERT(m_bv_util.get_bv_size(shift_abs) == sig_sz);
+
+ expr_ref c_in_limits(m);
+ c_in_limits = m_bv_util.mk_sle(shift, m_bv_util.mk_numeral(0, ebits + 2));
+ dbg_decouple("fpa2bv_to_sbv_in_limits", c_in_limits);
+
+ expr_ref shifted_sig(m);
+ shifted_sig = m_bv_util.mk_bv_lshr(sig, shift_abs);
+ dbg_decouple("fpa2bv_to_sbv_shifted_sig", shifted_sig);
+
+ expr_ref last(m), round(m), sticky(m);
+ last = m_bv_util.mk_extract(sig_sz - bv_sz - 0, sig_sz - bv_sz - 0, shifted_sig);
+ round = m_bv_util.mk_extract(sig_sz - bv_sz - 1, sig_sz - bv_sz - 1, shifted_sig);
+ sticky = m.mk_ite(m.mk_eq(m_bv_util.mk_extract(sig_sz - bv_sz - 2, 0, shifted_sig),
+ m_bv_util.mk_numeral(0, sig_sz - (bv_sz + 3) + 2)),
+ bv0,
+ bv1);
+ dbg_decouple("fpa2bv_to_sbv_last", last);
+ dbg_decouple("fpa2bv_to_sbv_round", round);
+ dbg_decouple("fpa2bv_to_sbv_sticky", sticky);
+
+ expr_ref rounding_decision(m);
+ rounding_decision = mk_rounding_decision(rm, sgn, last, round, sticky);
+ SASSERT(m_bv_util.get_bv_size(rounding_decision) == 1);
+ dbg_decouple("fpa2bv_to_sbv_rounding_decision", rounding_decision);
+
+ expr_ref unrounded_sig(m), pre_rounded(m), inc(m);
+ unrounded_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_extract(sig_sz - 1, sig_sz - bv_sz, shifted_sig));
+ inc = m_bv_util.mk_zero_extend(1, m_bv_util.mk_zero_extend(bv_sz - 1, rounding_decision));
+ pre_rounded = m_bv_util.mk_bv_add(unrounded_sig, inc);
+ dbg_decouple("fpa2bv_to_sbv_inc", inc);
+ dbg_decouple("fpa2bv_to_sbv_unrounded_sig", unrounded_sig);
+ dbg_decouple("fpa2bv_to_sbv_pre_rounded", pre_rounded);
+
+ expr_ref rnd_overflow(m), rnd_abs(m), rnd_signed(m), rnd_has_overflown(m), extra_neg(m);
+ rnd_overflow = m_bv_util.mk_extract(bv_sz, bv_sz - 1, pre_rounded);
+ rnd_abs = m_bv_util.mk_extract(bv_sz - 1, 0, pre_rounded);
+ rnd_signed = m.mk_ite(m.mk_eq(sgn, bv1), m_bv_util.mk_bv_neg(rnd_abs), rnd_abs);
+ extra_neg = m_bv_util.mk_numeral(fu().fm().m_powers2(bv_sz-1), bv_sz+1);
+ rnd_has_overflown = m.mk_and(m.mk_not(m.mk_eq(rnd_overflow, bv0_2)),
+ m.mk_not(m.mk_and(m.mk_eq(sgn, bv1), m.mk_eq(pre_rounded, extra_neg))));
+ dbg_decouple("fpa2bv_to_sbv_extra_neg", extra_neg);
+ dbg_decouple("fpa2bv_to_sbv_rnd_overflow", rnd_overflow);
+ dbg_decouple("fpa2bv_to_sbv_rnd_abs", rnd_abs);
+ dbg_decouple("fpa2bv_to_sbv_rnd_has_overflown", rnd_has_overflown);
+
+ result = m.mk_ite(rnd_has_overflown, mk_to_sbv_unspecified(bv_sz), rnd_signed);
+ result = m.mk_ite(c_in_limits, result, mk_to_sbv_unspecified(bv_sz));
+ result = m.mk_ite(c2, v2, result);
+ result = m.mk_ite(c1, v1, result);
+
+ SASSERT(is_well_sorted(m, result));
+}
+
+expr_ref fpa2bv_converter::mk_to_ubv_unspecified(unsigned width) {
+ if (m_hi_fp_unspecified)
+ return expr_ref(m_bv_util.mk_numeral(0, width), m);
+ else
+ return expr_ref(m_util.mk_internal_to_ubv_unspecified(width), m);
+}
+
+expr_ref fpa2bv_converter::mk_to_sbv_unspecified(unsigned width) {
+ if (m_hi_fp_unspecified)
+ return expr_ref(m_bv_util.mk_numeral(0, width), m);
+ else
+ return expr_ref(m_util.mk_internal_to_sbv_unspecified(width), m);
+}
+
+expr_ref fpa2bv_converter::mk_to_real_unspecified() {
+ if (m_hi_fp_unspecified)
+ return expr_ref(m_arith_util.mk_numeral(rational(0), false), m);
+ else
+ return expr_ref(m_util.mk_internal_to_real_unspecified(), m);
+}
+
+void fpa2bv_converter::mk_fp(expr * sign, expr * exponent, expr * significand, expr_ref & result) {
+ SASSERT(m_bv_util.is_bv(sign) && m_bv_util.get_bv_size(sign) == 1);
+ SASSERT(m_bv_util.is_bv(significand));
+ SASSERT(m_bv_util.is_bv(exponent));
+ result = m.mk_app(m_util.get_family_id(), OP_FPA_FP, sign, exponent, significand);
+}
+
void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
SASSERT(num == 3);
- mk_triple(args[0], args[2], args[1], result);
+ SASSERT(m_bv_util.get_bv_size(args[0]) == 1);
+ SASSERT(m_util.get_sbits(f->get_range()) == m_bv_util.get_bv_size(args[2]) + 1);
+ SASSERT(m_util.get_ebits(f->get_range()) == m_bv_util.get_bv_size(args[1]));
+ mk_fp(args[0], args[1], args[2], result);
+ TRACE("fpa2bv_mk_fp", tout << "mk_fp result = " << mk_ismt2_pp(result, m) << std::endl;);
}
-void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
- SASSERT(num == 2);
- SASSERT(f->get_num_parameters() == 1);
- SASSERT(f->get_parameter(0).is_int());
-
- //unsigned ebits = m_util.get_ebits(f->get_range());
- //unsigned sbits = m_util.get_sbits(f->get_range());
- //int width = f->get_parameter(0).get_int();
-
- //expr * rm = args[0];
- //expr * x = args[1];
-
- //expr * sgn, *s, *e;
- //split(x, sgn, s, e);
-
- NOT_IMPLEMENTED_YET();
+void fpa2bv_converter::split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const {
+ SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP));
+ SASSERT(to_app(e)->get_num_args() == 3);
+ sgn = to_app(e)->get_arg(0);
+ exp = to_app(e)->get_arg(1);
+ sig = to_app(e)->get_arg(2);
}
-void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
- SASSERT(num == 2);
- SASSERT(f->get_num_parameters() == 1);
- SASSERT(f->get_parameter(0).is_int());
-
- //unsigned ebits = m_util.get_ebits(f->get_range());
- //unsigned sbits = m_util.get_sbits(f->get_range());
- //int width = f->get_parameter(0).get_int();
-
- //expr * rm = args[0];
- //expr * x = args[1];
-
- //expr * sgn, *s, *e;
- //split(x, sgn, s, e);
-
- NOT_IMPLEMENTED_YET();
-}
-
-void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
- SASSERT(num == 1);
-
- //unsigned ebits = m_util.get_ebits(f->get_range());
- //unsigned sbits = m_util.get_sbits(f->get_range());
- //int width = f->get_parameter(0).get_int();
-
- //expr * rm = args[0];
- //expr * x = args[1];
-
- //expr * sgn, *s, *e;
- //split(x, sgn, s, e);
-
- NOT_IMPLEMENTED_YET();
-}
-
-void fpa2bv_converter::split(expr * e, expr * & sgn, expr * & sig, expr * & exp) const {
- SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_TO_FLOAT));
+void fpa2bv_converter::split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_ref & sig) const {
+ SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP));
SASSERT(to_app(e)->get_num_args() == 3);
-
- sgn = to_app(e)->get_arg(0);
- sig = to_app(e)->get_arg(1);
- exp = to_app(e)->get_arg(2);
+ expr *e_sgn, *e_sig, *e_exp;
+ split_fp(e, e_sgn, e_exp, e_sig);
+ sgn = e_sgn;
+ exp = e_exp;
+ sig = e_sig;
}
void fpa2bv_converter::mk_is_nan(expr * e, expr_ref & result) {
expr * sgn, * sig, * exp;
- split(e, sgn, sig, exp);
+ split_fp(e, sgn, exp, sig);
// exp == 1^n , sig != 0
expr_ref sig_is_zero(m), sig_is_not_zero(m), exp_is_top(m), top_exp(m), zero(m);
@@ -2228,7 +2878,7 @@ void fpa2bv_converter::mk_is_nan(expr * e, expr_ref & result) {
void fpa2bv_converter::mk_is_inf(expr * e, expr_ref & result) {
expr * sgn, * sig, * exp;
- split(e, sgn, sig, exp);
+ split_fp(e, sgn, exp, sig);
expr_ref eq1(m), eq2(m), top_exp(m), zero(m);
mk_top_exp(m_bv_util.get_bv_size(exp), top_exp);
zero = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(sig));
@@ -2252,7 +2902,7 @@ void fpa2bv_converter::mk_is_ninf(expr * e, expr_ref & result) {
}
void fpa2bv_converter::mk_is_pos(expr * e, expr_ref & result) {
- SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_TO_FLOAT));
+ SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP));
SASSERT(to_app(e)->get_num_args() == 3);
expr * a0 = to_app(e)->get_arg(0);
expr_ref zero(m);
@@ -2261,7 +2911,7 @@ void fpa2bv_converter::mk_is_pos(expr * e, expr_ref & result) {
}
void fpa2bv_converter::mk_is_neg(expr * e, expr_ref & result) {
- SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_TO_FLOAT));
+ SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP));
SASSERT(to_app(e)->get_num_args() == 3);
expr * a0 = to_app(e)->get_arg(0);
expr_ref one(m);
@@ -2271,7 +2921,7 @@ void fpa2bv_converter::mk_is_neg(expr * e, expr_ref & result) {
void fpa2bv_converter::mk_is_zero(expr * e, expr_ref & result) {
expr * sgn, * sig, * exp;
- split(e, sgn, sig, exp);
+ split_fp(e, sgn, exp, sig);
expr_ref eq1(m), eq2(m), bot_exp(m), zero(m);
mk_bot_exp(m_bv_util.get_bv_size(exp), bot_exp);
zero = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(sig));
@@ -2282,7 +2932,7 @@ void fpa2bv_converter::mk_is_zero(expr * e, expr_ref & result) {
void fpa2bv_converter::mk_is_nzero(expr * e, expr_ref & result) {
expr * sgn, * sig, * exp;
- split(e, sgn, sig, exp);
+ split_fp(e, sgn, exp, sig);
expr_ref e_is_zero(m), eq(m), one_1(m);
mk_is_zero(e, e_is_zero);
one_1 = m_bv_util.mk_numeral(1, 1);
@@ -2292,7 +2942,7 @@ void fpa2bv_converter::mk_is_nzero(expr * e, expr_ref & result) {
void fpa2bv_converter::mk_is_pzero(expr * e, expr_ref & result) {
expr * sgn, * sig, * exp;
- split(e, sgn, sig, exp);
+ split_fp(e, sgn, exp, sig);
expr_ref e_is_zero(m), eq(m), nil_1(m);
mk_is_zero(e, e_is_zero);
nil_1 = m_bv_util.mk_numeral(0, 1);
@@ -2302,7 +2952,7 @@ void fpa2bv_converter::mk_is_pzero(expr * e, expr_ref & result) {
void fpa2bv_converter::mk_is_denormal(expr * e, expr_ref & result) {
expr * sgn, * sig, * exp;
- split(e, sgn, sig, exp);
+ split_fp(e, sgn, exp, sig);
expr_ref zero(m);
zero = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(exp));
m_simp.mk_eq(exp, zero, result);
@@ -2310,7 +2960,7 @@ void fpa2bv_converter::mk_is_denormal(expr * e, expr_ref & result) {
void fpa2bv_converter::mk_is_normal(expr * e, expr_ref & result) {
expr * sgn, * sig, * exp;
- split(e, sgn, sig, exp);
+ split_fp(e, sgn, exp, sig);
expr_ref is_special(m), is_denormal(m), p(m);
mk_is_denormal(e, is_denormal);
@@ -2332,12 +2982,11 @@ void fpa2bv_converter::mk_is_rm(expr * e, BV_RM_VAL rm, expr_ref & result) {
case BV_RM_TIES_TO_AWAY:
case BV_RM_TIES_TO_EVEN:
case BV_RM_TO_NEGATIVE:
- case BV_RM_TO_POSITIVE: return m_simp.mk_eq(e, rm_num, result);
+ case BV_RM_TO_POSITIVE:
case BV_RM_TO_ZERO:
+ return m_simp.mk_eq(e, rm_num, result);
default:
- rm_num = m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3);
- expr_ref r(m); r = m_bv_util.mk_ule(e, rm_num);
- return m_simp.mk_not(r, result);
+ UNREACHABLE();
}
}
@@ -2410,7 +3059,7 @@ void fpa2bv_converter::mk_bias(expr * e, expr_ref & result) {
void fpa2bv_converter::mk_unbias(expr * e, expr_ref & result) {
unsigned ebits = m_bv_util.get_bv_size(e);
- SASSERT(ebits >= 3);
+ SASSERT(ebits >= 2);
expr_ref e_plus_one(m);
e_plus_one = m_bv_util.mk_bv_add(e, m_bv_util.mk_numeral(1, ebits));
@@ -2424,7 +3073,7 @@ void fpa2bv_converter::mk_unbias(expr * e, expr_ref & result) {
}
void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & lz, bool normalize) {
- SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_TO_FLOAT));
+ SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP));
SASSERT(to_app(e)->get_num_args() == 3);
sort * srt = to_app(e)->get_decl()->get_range();
@@ -2432,9 +3081,11 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref
unsigned sbits = m_util.get_sbits(srt);
unsigned ebits = m_util.get_ebits(srt);
- sgn = to_app(e)->get_arg(0);
- sig = to_app(e)->get_arg(1);
- exp = to_app(e)->get_arg(2);
+ split_fp(e, sgn, exp, sig);
+
+ SASSERT(m_bv_util.get_bv_size(sgn) == 1);
+ SASSERT(m_bv_util.get_bv_size(exp) == ebits);
+ SASSERT(m_bv_util.get_bv_size(sig) == sbits-1);
expr_ref is_normal(m);
mk_is_normal(e, is_normal);
@@ -2446,7 +3097,7 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref
expr_ref denormal_sig(m), denormal_exp(m);
denormal_sig = m_bv_util.mk_zero_extend(1, sig);
- SASSERT(ebits >= 3); // Note: when ebits=2 there is no 1-exponent, so mk_unbias will produce a 0.
+ // SASSERT(ebits >= 3); // Note: when ebits=2 there is no 1-exponent, so mk_unbias will produce a 0.
denormal_exp = m_bv_util.mk_numeral(1, ebits);
mk_unbias(denormal_exp, denormal_exp);
dbg_decouple("fpa2bv_unpack_denormal_exp", denormal_exp);
@@ -2467,7 +3118,7 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref
expr_ref shift(m);
m_simp.mk_ite(is_sig_zero, zero_e, lz, shift);
dbg_decouple("fpa2bv_unpack_shift", shift);
- SASSERT(is_well_sorted(m, is_sig_zero));
+ SASSERT(is_well_sorted(m, is_sig_zero));
SASSERT(is_well_sorted(m, shift));
SASSERT(m_bv_util.get_bv_size(shift) == ebits);
if (ebits <= sbits) {
@@ -2518,27 +3169,68 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref
void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result)
{
switch(f->get_decl_kind())
- {
- case OP_RM_NEAREST_TIES_TO_AWAY: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3); break;
- case OP_RM_NEAREST_TIES_TO_EVEN: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); break;
- case OP_RM_TOWARD_NEGATIVE: result = m_bv_util.mk_numeral(BV_RM_TO_NEGATIVE, 3); break;
- case OP_RM_TOWARD_POSITIVE: result = m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3); break;
- case OP_RM_TOWARD_ZERO: result = m_bv_util.mk_numeral(BV_RM_TO_ZERO, 3); break;
+ {
+ case OP_FPA_RM_NEAREST_TIES_TO_EVEN: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); break;
+ case OP_FPA_RM_NEAREST_TIES_TO_AWAY: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3); break;
+ case OP_FPA_RM_TOWARD_POSITIVE: result = m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3); break;
+ case OP_FPA_RM_TOWARD_NEGATIVE: result = m_bv_util.mk_numeral(BV_RM_TO_NEGATIVE, 3); break;
+ case OP_FPA_RM_TOWARD_ZERO: result = m_bv_util.mk_numeral(BV_RM_TO_ZERO, 3); break;
default: UNREACHABLE();
}
}
void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) {
#ifdef Z3DEBUG
- return;
+ // return;
// CMW: This works only for quantifier-free formulas.
expr_ref new_e(m);
new_e = m.mk_fresh_const(prefix, m.get_sort(e));
- extra_assertions.push_back(m.mk_eq(new_e, e));
+ m_extra_assertions.push_back(m.mk_eq(new_e, e));
e = new_e;
#endif
}
+expr_ref fpa2bv_converter::mk_rounding_decision(expr * rm, expr * sgn, expr * last, expr * round, expr * sticky) {
+ expr_ref last_or_sticky(m), round_or_sticky(m), not_last(m), not_round(m), not_sticky(m), not_lors(m), not_rors(m), not_sgn(m);
+ expr * last_sticky[2] = { last, sticky };
+ expr * round_sticky[2] = { round, sticky };
+ last_or_sticky = m_bv_util.mk_bv_or(2, last_sticky);
+ round_or_sticky = m_bv_util.mk_bv_or(2, round_sticky);
+ not_last= m_bv_util.mk_bv_not(last);
+ not_round = m_bv_util.mk_bv_not(round);
+ not_sticky = m_bv_util.mk_bv_not(sticky);
+ not_lors = m_bv_util.mk_bv_not(last_or_sticky);
+ not_rors = m_bv_util.mk_bv_not(round_or_sticky);
+ not_sgn = m_bv_util.mk_bv_not(sgn);
+ expr * nround_lors[2] = { not_round, not_lors };
+ expr * pos_args[2] = { sgn, not_rors };
+ expr * neg_args[2] = { not_sgn, not_rors };
+ expr * nl_r[2] = { last, not_round };
+ expr * nl_nr_sn[3] = { not_last, not_round, not_sticky };
+
+ expr_ref inc_teven(m), inc_taway(m), inc_pos(m), inc_neg(m);
+ inc_teven = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, nround_lors));
+ expr *taway_args[2] = { m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, nl_r)),
+ m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(3, nl_nr_sn)) };
+ inc_taway = m_bv_util.mk_bv_or(2, taway_args);
+ inc_pos = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, pos_args));
+ inc_neg = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, neg_args));
+
+ expr_ref res(m), inc_c2(m), inc_c3(m), inc_c4(m);
+ expr_ref rm_is_to_neg(m), rm_is_to_pos(m), rm_is_away(m), rm_is_even(m), nil_1(m);
+ nil_1 = m_bv_util.mk_numeral(0, 1);
+ mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
+ mk_is_rm(rm, BV_RM_TO_POSITIVE, rm_is_to_pos);
+ mk_is_rm(rm, BV_RM_TIES_TO_AWAY, rm_is_away);
+ mk_is_rm(rm, BV_RM_TIES_TO_EVEN, rm_is_even);
+ m_simp.mk_ite(rm_is_to_neg, inc_neg, nil_1, inc_c4);
+ m_simp.mk_ite(rm_is_to_pos, inc_pos, inc_c4, inc_c3);
+ m_simp.mk_ite(rm_is_away, inc_taway, inc_c3, inc_c2);
+ m_simp.mk_ite(rm_is_even, inc_teven, inc_c2, res);
+
+ return res;
+}
+
void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & result) {
unsigned ebits = m_util.get_ebits(s);
unsigned sbits = m_util.get_sbits(s);
@@ -2564,7 +3256,6 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
// i.e., it has 2 + (sbits-1) + 3 = sbits + 4 bits, where the first one is in sgn.
// Furthermore, note that sig is an unsigned bit-vector, while exp is signed.
- SASSERT(ebits <= sbits);
SASSERT(m_bv_util.is_bv(rm) && m_bv_util.get_bv_size(rm) == 3);
SASSERT(m_bv_util.is_bv(sgn) && m_bv_util.get_bv_size(sgn) == 1);
SASSERT(m_bv_util.is_bv(sig) && m_bv_util.get_bv_size(sig) >= 5);
@@ -2634,7 +3325,6 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
SASSERT(is_well_sorted(m, beta));
dbg_decouple("fpa2bv_rnd_beta", beta);
-
dbg_decouple("fpa2bv_rnd_e_min", e_min);
dbg_decouple("fpa2bv_rnd_e_max", e_max);
@@ -2715,36 +3405,8 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
sig = m_bv_util.mk_extract(sbits+1, 2, sig);
- expr_ref last_or_sticky(m), round_or_sticky(m), not_round(m), not_lors(m), not_rors(m), not_sgn(m);
- expr * last_sticky[2] = { last, sticky };
- expr * round_sticky[2] = { round, sticky };
- last_or_sticky = m_bv_util.mk_bv_or(2, last_sticky);
- round_or_sticky = m_bv_util.mk_bv_or(2, round_sticky);
- not_round = m_bv_util.mk_bv_not(round);
- not_lors = m_bv_util.mk_bv_not(last_or_sticky);
- not_rors = m_bv_util.mk_bv_not(round_or_sticky);
- not_sgn = m_bv_util.mk_bv_not(sgn);
- expr * round_lors[2] = { not_round, not_lors};
- expr * pos_args[2] = { sgn, not_rors };
- expr * neg_args[2] = { not_sgn, not_rors };
-
- expr_ref inc_teven(m), inc_taway(m), inc_pos(m), inc_neg(m);
- inc_teven = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, round_lors));
- inc_taway = round;
- inc_pos = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, pos_args));
- inc_neg = m_bv_util.mk_bv_not(m_bv_util.mk_bv_or(2, neg_args));
-
- expr_ref inc(m), inc_c2(m), inc_c3(m), inc_c4(m);
- expr_ref rm_is_to_neg(m), rm_is_to_pos(m), rm_is_away(m), rm_is_even(m), nil_1(m);
- nil_1 = m_bv_util.mk_numeral(0, 1);
- mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
- mk_is_rm(rm, BV_RM_TO_POSITIVE, rm_is_to_pos);
- mk_is_rm(rm, BV_RM_TIES_TO_AWAY, rm_is_away);
- mk_is_rm(rm, BV_RM_TIES_TO_EVEN, rm_is_even);
- m_simp.mk_ite(rm_is_to_neg, inc_neg, nil_1, inc_c4);
- m_simp.mk_ite(rm_is_to_pos, inc_pos, inc_c4, inc_c3);
- m_simp.mk_ite(rm_is_away, inc_taway, inc_c3, inc_c2);
- m_simp.mk_ite(rm_is_even, inc_teven, inc_c2, inc);
+ expr_ref inc(m);
+ inc = mk_rounding_decision(rm, sgn, last, round, sticky);
SASSERT(m_bv_util.get_bv_size(inc) == 1 && is_well_sorted(m, inc));
dbg_decouple("fpa2bv_rnd_inc", inc);
@@ -2813,13 +3475,23 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
mk_top_exp(ebits, top_exp);
mk_bot_exp(ebits, bot_exp);
- expr_ref rm_is_to_zero(m), rm_zero_or_neg(m), rm_zero_or_pos(m);
+ expr_ref nil_1(m);
+ nil_1 = m_bv_util.mk_numeral(0, 1);
+
+ expr_ref rm_is_to_zero(m), rm_is_to_neg(m), rm_is_to_pos(m), rm_zero_or_neg(m), rm_zero_or_pos(m);
mk_is_rm(rm, BV_RM_TO_ZERO, rm_is_to_zero);
+ mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
+ mk_is_rm(rm, BV_RM_TO_POSITIVE, rm_is_to_pos);
m_simp.mk_or(rm_is_to_zero, rm_is_to_neg, rm_zero_or_neg);
m_simp.mk_or(rm_is_to_zero, rm_is_to_pos, rm_zero_or_pos);
+ dbg_decouple("fpa2bv_rnd_rm_is_to_zero", rm_is_to_zero);
+ dbg_decouple("fpa2bv_rnd_rm_is_to_neg", rm_is_to_neg);
+ dbg_decouple("fpa2bv_rnd_rm_is_to_pos", rm_is_to_pos);
+
expr_ref sgn_is_zero(m);
m_simp.mk_eq(sgn, m_bv_util.mk_numeral(0, 1), sgn_is_zero);
+ dbg_decouple("fpa2bv_rnd_sgn_is_zero", sgn_is_zero);
expr_ref max_sig(m), max_exp(m), inf_sig(m), inf_exp(m);
max_sig = m_bv_util.mk_numeral(fu().fm().m_powers2.m1(sbits-1, false), sbits-1);
@@ -2829,22 +3501,30 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
inf_exp = top_exp;
dbg_decouple("fpa2bv_rnd_max_exp", max_exp);
+ dbg_decouple("fpa2bv_rnd_max_sig", max_sig);
+ dbg_decouple("fpa2bv_rnd_inf_sig", inf_sig);
+ dbg_decouple("fpa2bv_rnd_inf_exp", inf_exp);
- expr_ref ovfl_exp(m), max_inf_exp_neg(m), max_inf_exp_pos(m), n_d_check(m), n_d_exp(m);
- m_simp.mk_ite(rm_zero_or_neg, max_exp, inf_exp, max_inf_exp_neg);
- m_simp.mk_ite(rm_zero_or_pos, max_exp, inf_exp, max_inf_exp_pos);
- m_simp.mk_ite(sgn_is_zero, max_inf_exp_neg, max_inf_exp_pos, ovfl_exp);
+ expr_ref ovfl_exp(m), max_inf_exp_neg(m), max_inf_exp_pos(m), n_d_check(m), n_d_exp(m);
+ m_simp.mk_ite(rm_zero_or_pos, max_exp, inf_exp, max_inf_exp_neg);
+ m_simp.mk_ite(rm_zero_or_neg, max_exp, inf_exp, max_inf_exp_pos);
+ m_simp.mk_ite(sgn_is_zero, max_inf_exp_pos, max_inf_exp_neg, ovfl_exp);
t_sig = m_bv_util.mk_extract(sbits-1, sbits-1, sig);
m_simp.mk_eq(t_sig, nil_1, n_d_check);
m_simp.mk_ite(n_d_check, bot_exp /* denormal */, biased_exp, n_d_exp);
m_simp.mk_ite(OVF, ovfl_exp, n_d_exp, exp);
expr_ref max_inf_sig_neg(m), max_inf_sig_pos(m), ovfl_sig(m), rest_sig(m);
- m_simp.mk_ite(rm_zero_or_neg, max_sig, inf_sig, max_inf_sig_neg);
- m_simp.mk_ite(rm_zero_or_pos, max_sig, inf_sig, max_inf_sig_pos);
- m_simp.mk_ite(sgn_is_zero, max_inf_sig_neg, max_inf_sig_pos, ovfl_sig);
+ m_simp.mk_ite(rm_zero_or_pos, max_sig, inf_sig, max_inf_sig_neg);
+ m_simp.mk_ite(rm_zero_or_neg, max_sig, inf_sig, max_inf_sig_pos);
+ m_simp.mk_ite(sgn_is_zero, max_inf_sig_pos, max_inf_sig_neg, ovfl_sig);
rest_sig = m_bv_util.mk_extract(sbits-2, 0, sig);
m_simp.mk_ite(OVF, ovfl_sig, rest_sig, sig);
+
+ dbg_decouple("fpa2bv_rnd_max_inf_sig_neg", max_inf_sig_neg);
+ dbg_decouple("fpa2bv_rnd_max_inf_sig_pos", max_inf_sig_pos);
+ dbg_decouple("fpa2bv_rnd_rm_zero_or_neg", rm_zero_or_neg);
+ dbg_decouple("fpa2bv_rnd_rm_zero_or_pos", rm_zero_or_pos);
dbg_decouple("fpa2bv_rnd_sgn_final", sgn);
dbg_decouple("fpa2bv_rnd_sig_final", sig);
@@ -2862,7 +3542,26 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref &
SASSERT(m_bv_util.get_bv_size(res_exp) == ebits);
SASSERT(is_well_sorted(m, res_exp));
- mk_triple(res_sgn, res_sig, res_exp, result);
+ mk_fp(res_sgn, res_exp, res_sig, result);
TRACE("fpa2bv_round", tout << "ROUND = " << mk_ismt2_pp(result, m) << std::endl; );
}
+
+
+void fpa2bv_converter::reset(void) {
+ dec_ref_map_key_values(m, m_const2bv);
+ dec_ref_map_key_values(m, m_rm_const2bv);
+ dec_ref_map_key_values(m, m_uf2bvuf);
+
+ obj_map::iterator it = m_uf23bvuf.begin();
+ obj_map::iterator end = m_uf23bvuf.end();
+ for (; it != end; ++it) {
+ m.dec_ref(it->m_key);
+ m.dec_ref(it->m_value.f_sgn);
+ m.dec_ref(it->m_value.f_sig);
+ m.dec_ref(it->m_value.f_exp);
+ }
+ m_uf23bvuf.reset();
+
+ m_extra_assertions.reset();
+}
\ No newline at end of file
diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h
index eb539d8ae..fa797b610 100644
--- a/src/ast/fpa/fpa2bv_converter.h
+++ b/src/ast/fpa/fpa2bv_converter.h
@@ -22,11 +22,11 @@ Notes:
#include"ast.h"
#include"obj_hashtable.h"
#include"ref_util.h"
-#include"float_decl_plugin.h"
+#include"fpa_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"basic_simplifier_plugin.h"
-typedef enum { BV_RM_TIES_TO_AWAY=0, BV_RM_TIES_TO_EVEN=1, BV_RM_TO_NEGATIVE=2, BV_RM_TO_POSITIVE=3, BV_RM_TO_ZERO=4 } BV_RM_VAL;
+typedef enum { BV_RM_TIES_TO_EVEN, BV_RM_TIES_TO_AWAY, BV_RM_TO_POSITIVE, BV_RM_TO_NEGATIVE, BV_RM_TO_ZERO = 4 } BV_RM_VAL;
struct func_decl_triple {
func_decl_triple () { f_sgn = 0; f_sig = 0; f_exp = 0; }
@@ -42,14 +42,16 @@ struct func_decl_triple {
};
class fpa2bv_converter {
+protected:
ast_manager & m;
basic_simplifier_plugin m_simp;
- float_util m_util;
+ fpa_util m_util;
bv_util m_bv_util;
arith_util m_arith_util;
mpf_manager & m_mpf_manager;
unsynch_mpz_manager & m_mpz_manager;
- float_decl_plugin * m_plugin;
+ fpa_decl_plugin * m_plugin;
+ bool m_hi_fp_unspecified;
obj_map m_const2bv;
obj_map m_rm_const2bv;
@@ -60,8 +62,9 @@ public:
fpa2bv_converter(ast_manager & m);
~fpa2bv_converter();
- float_util & fu() { return m_util; }
+ fpa_util & fu() { return m_util; }
bv_util & bu() { return m_bv_util; }
+ arith_util & au() { return m_arith_util; }
bool is_float(sort * s) { return m_util.is_float(s); }
bool is_float(expr * e) { return is_app(e) && m_util.is_float(to_app(e)->get_decl()->get_range()); }
@@ -69,25 +72,24 @@ public:
bool is_rm(sort * s) { return m_util.is_rm(s); }
bool is_float_family(func_decl * f) { return f->get_family_id() == m_util.get_family_id(); }
- void mk_triple(expr * sign, expr * significand, expr * exponent, expr_ref & result) {
- SASSERT(m_bv_util.is_bv(sign) && m_bv_util.get_bv_size(sign) == 1);
- SASSERT(m_bv_util.is_bv(significand));
- SASSERT(m_bv_util.is_bv(exponent));
- result = m.mk_app(m_util.get_family_id(), OP_TO_FLOAT, sign, significand, exponent);
- }
+ void mk_fp(expr * sign, expr * exponent, expr * significand, expr_ref & result);
+ void mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
+
+ void split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const;
+ void split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_ref & sig) const;
void mk_eq(expr * a, expr * b, expr_ref & result);
void mk_ite(expr * c, expr * t, expr * f, expr_ref & result);
void mk_rounding_mode(func_decl * f, expr_ref & result);
- void mk_value(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
- void mk_const(func_decl * f, expr_ref & result);
- void mk_rm_const(func_decl * f, expr_ref & result);
+ void mk_numeral(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
+ virtual void mk_const(func_decl * f, expr_ref & result);
+ virtual void mk_rm_const(func_decl * f, expr_ref & result);
void mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_var(unsigned base_inx, sort * srt, expr_ref & result);
- void mk_plus_inf(func_decl * f, expr_ref & result);
- void mk_minus_inf(func_decl * f, expr_ref & result);
+ void mk_pinf(func_decl * f, expr_ref & result);
+ void mk_ninf(func_decl * f, expr_ref & result);
void mk_nan(func_decl * f, expr_ref & result);
void mk_nzero(func_decl *f, expr_ref & result);
void mk_pzero(func_decl *f, expr_ref & result);
@@ -119,28 +121,36 @@ public:
void mk_is_nan(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_is_inf(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_is_normal(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
- void mk_is_subnormal(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
+ void mk_is_subnormal(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
- void mk_to_float(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
- void mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
-
- void mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
+ void mk_to_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
+ void mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result);
+ void mk_to_fp_signed(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_fp_unsigned(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
+ void mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
+ void mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result);
+ void mk_to_fp_real_int(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
+
void mk_to_ubv(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
void mk_to_sbv(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
- void mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
+ void mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result);
+
+ void set_unspecified_fp_hi(bool v) { m_hi_fp_unspecified = v; }
+ expr_ref mk_to_ubv_unspecified(unsigned width);
+ expr_ref mk_to_sbv_unspecified(unsigned width);
+ expr_ref mk_to_real_unspecified();
obj_map const & const2bv() const { return m_const2bv; }
obj_map const & rm_const2bv() const { return m_rm_const2bv; }
obj_map const & uf2bvuf() const { return m_uf2bvuf; }
obj_map const & uf23bvuf() const { return m_uf23bvuf; }
+ void reset(void);
+
void dbg_decouple(const char * prefix, expr_ref & e);
- expr_ref_vector extra_assertions;
+ expr_ref_vector m_extra_assertions;
protected:
- void split(expr * e, expr * & sgn, expr * & sig, expr * & exp) const;
-
void mk_is_nan(expr * e, expr_ref & result);
void mk_is_inf(expr * e, expr_ref & result);
void mk_is_pinf(expr * e, expr_ref & result);
@@ -167,10 +177,13 @@ protected:
void unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & lz, bool normalize);
void round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & result);
+ expr_ref mk_rounding_decision(expr * rm, expr * sgn, expr * last, expr * round, expr * sticky);
void add_core(unsigned sbits, unsigned ebits, expr_ref & rm,
expr_ref & c_sgn, expr_ref & c_sig, expr_ref & c_exp, expr_ref & d_sgn, expr_ref & d_sig, expr_ref & d_exp,
expr_ref & res_sgn, expr_ref & res_sig, expr_ref & res_exp);
+
+ app * mk_fresh_const(char const * prefix, unsigned sz);
};
#endif
diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h
index 7a245b71a..ed885a4cc 100644
--- a/src/ast/fpa/fpa2bv_rewriter.h
+++ b/src/ast/fpa/fpa2bv_rewriter.h
@@ -24,6 +24,7 @@ Notes:
#include"rewriter_def.h"
#include"bv_decl_plugin.h"
#include"fpa2bv_converter.h"
+#include"fpa2bv_rewriter_params.hpp"
struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
ast_manager & m_manager;
@@ -36,7 +37,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
ast_manager & m() const { return m_manager; }
- fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c, params_ref const & p):
+ fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c, params_ref const & p) :
m_manager(m),
m_out(m),
m_conv(c),
@@ -58,9 +59,16 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
void reset() {
}
+ void updt_local_params(params_ref const & _p) {
+ fpa2bv_rewriter_params p(_p);
+ bool v = p.hi_fp_unspecified();
+ m_conv.set_unspecified_fp_hi(v);
+ }
+
void updt_params(params_ref const & p) {
- m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
- m_max_steps = p.get_uint("max_steps", UINT_MAX);
+ m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
+ m_max_steps = p.get_uint("max_steps", UINT_MAX);
+ updt_local_params(p);
}
bool max_steps_exceeded(unsigned num_steps) const {
@@ -107,49 +115,53 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
if (m_conv.is_float_family(f)) {
switch (f->get_decl_kind()) {
- case OP_RM_NEAREST_TIES_TO_AWAY:
- case OP_RM_NEAREST_TIES_TO_EVEN:
- case OP_RM_TOWARD_NEGATIVE:
- case OP_RM_TOWARD_POSITIVE:
- case OP_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f, result); return BR_DONE;
- case OP_FLOAT_VALUE: m_conv.mk_value(f, num, args, result); return BR_DONE;
- case OP_FLOAT_PLUS_INF: m_conv.mk_plus_inf(f, result); return BR_DONE;
- case OP_FLOAT_MINUS_INF: m_conv.mk_minus_inf(f, result); return BR_DONE;
- case OP_FLOAT_PLUS_ZERO: m_conv.mk_pzero(f, result); return BR_DONE;
- case OP_FLOAT_MINUS_ZERO: m_conv.mk_nzero(f, result); return BR_DONE;
- case OP_FLOAT_NAN: m_conv.mk_nan(f, result); return BR_DONE;
- case OP_FLOAT_ADD: m_conv.mk_add(f, num, args, result); return BR_DONE;
- case OP_FLOAT_SUB: m_conv.mk_sub(f, num, args, result); return BR_DONE;
- case OP_FLOAT_NEG: m_conv.mk_neg(f, num, args, result); return BR_DONE;
- case OP_FLOAT_MUL: m_conv.mk_mul(f, num, args, result); return BR_DONE;
- case OP_FLOAT_DIV: m_conv.mk_div(f, num, args, result); return BR_DONE;
- case OP_FLOAT_REM: m_conv.mk_rem(f, num, args, result); return BR_DONE;
- case OP_FLOAT_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE;
- case OP_FLOAT_MIN: m_conv.mk_min(f, num, args, result); return BR_DONE;
- case OP_FLOAT_MAX: m_conv.mk_max(f, num, args, result); return BR_DONE;
- case OP_FLOAT_FMA: m_conv.mk_fma(f, num, args, result); return BR_DONE;
- case OP_FLOAT_SQRT: m_conv.mk_sqrt(f, num, args, result); return BR_DONE;
- case OP_FLOAT_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, num, args, result); return BR_DONE;
- case OP_FLOAT_EQ: m_conv.mk_float_eq(f, num, args, result); return BR_DONE;
- case OP_FLOAT_LT: m_conv.mk_float_lt(f, num, args, result); return BR_DONE;
- case OP_FLOAT_GT: m_conv.mk_float_gt(f, num, args, result); return BR_DONE;
- case OP_FLOAT_LE: m_conv.mk_float_le(f, num, args, result); return BR_DONE;
- case OP_FLOAT_GE: m_conv.mk_float_ge(f, num, args, result); return BR_DONE;
- case OP_FLOAT_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE;
- case OP_FLOAT_IS_NZERO: m_conv.mk_is_nzero(f, num, args, result); return BR_DONE;
- case OP_FLOAT_IS_PZERO: m_conv.mk_is_pzero(f, num, args, result); return BR_DONE;
- case OP_FLOAT_IS_NAN: m_conv.mk_is_nan(f, num, args, result); return BR_DONE;
- case OP_FLOAT_IS_INF: m_conv.mk_is_inf(f, num, args, result); return BR_DONE;
- case OP_FLOAT_IS_NORMAL: m_conv.mk_is_normal(f, num, args, result); return BR_DONE;
- case OP_FLOAT_IS_SUBNORMAL: m_conv.mk_is_subnormal(f, num, args, result); return BR_DONE;
- case OP_FLOAT_IS_POSITIVE: m_conv.mk_is_positive(f, num, args, result); return BR_DONE;
- case OP_FLOAT_IS_NEGATIVE: m_conv.mk_is_negative(f, num, args, result); return BR_DONE;
- case OP_TO_FLOAT: m_conv.mk_to_float(f, num, args, result); return BR_DONE;
- case OP_FLOAT_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE;
- case OP_FLOAT_FP: m_conv.mk_fp(f, num, args, result); return BR_DONE;
- case OP_FLOAT_TO_UBV: m_conv.mk_to_ubv(f, num, args, result); return BR_DONE;
- case OP_FLOAT_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE;
- case OP_FLOAT_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE;
+ case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
+ case OP_FPA_RM_NEAREST_TIES_TO_EVEN:
+ case OP_FPA_RM_TOWARD_NEGATIVE:
+ case OP_FPA_RM_TOWARD_POSITIVE:
+ case OP_FPA_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f, result); return BR_DONE;
+ case OP_FPA_NUM: m_conv.mk_numeral(f, num, args, result); return BR_DONE;
+ case OP_FPA_PLUS_INF: m_conv.mk_pinf(f, result); return BR_DONE;
+ case OP_FPA_MINUS_INF: m_conv.mk_ninf(f, result); return BR_DONE;
+ case OP_FPA_PLUS_ZERO: m_conv.mk_pzero(f, result); return BR_DONE;
+ case OP_FPA_MINUS_ZERO: m_conv.mk_nzero(f, result); return BR_DONE;
+ case OP_FPA_NAN: m_conv.mk_nan(f, result); return BR_DONE;
+ case OP_FPA_ADD: m_conv.mk_add(f, num, args, result); return BR_DONE;
+ case OP_FPA_SUB: m_conv.mk_sub(f, num, args, result); return BR_DONE;
+ case OP_FPA_NEG: m_conv.mk_neg(f, num, args, result); return BR_DONE;
+ case OP_FPA_MUL: m_conv.mk_mul(f, num, args, result); return BR_DONE;
+ case OP_FPA_DIV: m_conv.mk_div(f, num, args, result); return BR_DONE;
+ case OP_FPA_REM: m_conv.mk_rem(f, num, args, result); return BR_DONE;
+ case OP_FPA_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE;
+ case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_DONE;
+ case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_DONE;
+ case OP_FPA_FMA: m_conv.mk_fma(f, num, args, result); return BR_DONE;
+ case OP_FPA_SQRT: m_conv.mk_sqrt(f, num, args, result); return BR_DONE;
+ case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, num, args, result); return BR_DONE;
+ case OP_FPA_EQ: m_conv.mk_float_eq(f, num, args, result); return BR_DONE;
+ case OP_FPA_LT: m_conv.mk_float_lt(f, num, args, result); return BR_DONE;
+ case OP_FPA_GT: m_conv.mk_float_gt(f, num, args, result); return BR_DONE;
+ case OP_FPA_LE: m_conv.mk_float_le(f, num, args, result); return BR_DONE;
+ case OP_FPA_GE: m_conv.mk_float_ge(f, num, args, result); return BR_DONE;
+ case OP_FPA_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE;
+ case OP_FPA_IS_NAN: m_conv.mk_is_nan(f, num, args, result); return BR_DONE;
+ case OP_FPA_IS_INF: m_conv.mk_is_inf(f, num, args, result); return BR_DONE;
+ case OP_FPA_IS_NORMAL: m_conv.mk_is_normal(f, num, args, result); return BR_DONE;
+ case OP_FPA_IS_SUBNORMAL: m_conv.mk_is_subnormal(f, num, args, result); return BR_DONE;
+ case OP_FPA_IS_POSITIVE: m_conv.mk_is_positive(f, num, args, result); return BR_DONE;
+ case OP_FPA_IS_NEGATIVE: m_conv.mk_is_negative(f, num, args, result); return BR_DONE;
+ case OP_FPA_TO_FP: m_conv.mk_to_fp(f, num, args, result); return BR_DONE;
+ case OP_FPA_TO_FP_UNSIGNED: m_conv.mk_to_fp_unsigned(f, num, args, result); return BR_DONE;
+ case OP_FPA_FP: m_conv.mk_fp(f, num, args, result); return BR_DONE;
+ case OP_FPA_TO_UBV: m_conv.mk_to_ubv(f, num, args, result); return BR_DONE;
+ case OP_FPA_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE;
+ case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE;
+ case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE;
+ case OP_FPA_INTERNAL_BVWRAP:
+ case OP_FPA_INTERNAL_BVUNWRAP:
+ case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
+ case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
+ case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: return BR_FAILED;
default:
TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n";
for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;);
@@ -247,13 +259,13 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
unsigned ebits = m_conv.fu().get_ebits(s);
unsigned sbits = m_conv.fu().get_sbits(s);
new_var = m().mk_var(t->get_idx(), m_conv.bu().mk_sort(sbits+ebits));
- m_conv.mk_triple(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var),
- m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var),
- m_conv.bu().mk_extract(ebits-1, 0, new_var),
- new_exp);
+ m_conv.mk_fp(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var),
+ m_conv.bu().mk_extract(ebits - 1, 0, new_var),
+ m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var),
+ new_exp);
}
else
- new_exp = m().mk_var(t->get_idx(), s);
+ new_exp = m().mk_var(t->get_idx(), s);
result = new_exp;
result_pr = 0;
diff --git a/src/ast/fpa/fpa2bv_rewriter_params.pyg b/src/ast/fpa/fpa2bv_rewriter_params.pyg
new file mode 100644
index 000000000..42df0fa0e
--- /dev/null
+++ b/src/ast/fpa/fpa2bv_rewriter_params.pyg
@@ -0,0 +1,5 @@
+def_module_params(module_name='rewriter',
+ class_name='fpa2bv_rewriter_params',
+ export=True,
+ params=(("hi_fp_unspecified", BOOL, True, "use the 'hardware interpretation' for unspecified values in fp.to_ubv, fp.to_sbv, and fp.to_real)"),
+ ))
diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp
new file mode 100644
index 000000000..8cf158604
--- /dev/null
+++ b/src/ast/fpa_decl_plugin.cpp
@@ -0,0 +1,1000 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ fpa_decl_plugin.cpp
+
+Abstract:
+
+ Floating point decl plugin
+
+Author:
+
+ Leonardo de Moura (leonardo) 2012-01-15.
+
+Revision History:
+
+--*/
+#include"fpa_decl_plugin.h"
+#include"arith_decl_plugin.h"
+#include"bv_decl_plugin.h"
+
+fpa_decl_plugin::fpa_decl_plugin():
+ m_values(m_fm),
+ m_value_table(mpf_hash_proc(m_values), mpf_eq_proc(m_values)) {
+ m_real_sort = 0;
+ m_int_sort = 0;
+ m_bv_plugin = 0;
+}
+
+void fpa_decl_plugin::set_manager(ast_manager * m, family_id id) {
+ decl_plugin::set_manager(m, id);
+
+ m_arith_fid = m_manager->mk_family_id("arith");
+ m_real_sort = m_manager->mk_sort(m_arith_fid, REAL_SORT);
+ SASSERT(m_real_sort != 0); // arith_decl_plugin must be installed before fpa_decl_plugin.
+ m_manager->inc_ref(m_real_sort);
+
+ m_int_sort = m_manager->mk_sort(m_arith_fid, INT_SORT);
+ SASSERT(m_int_sort != 0); // arith_decl_plugin must be installed before fpa_decl_plugin.
+ m_manager->inc_ref(m_int_sort);
+
+ // BV is not optional anymore.
+ SASSERT(m_manager->has_plugin(symbol("bv")));
+ m_bv_fid = m_manager->mk_family_id("bv");
+ m_bv_plugin = static_cast(m_manager->get_plugin(m_bv_fid));
+}
+
+fpa_decl_plugin::~fpa_decl_plugin() {
+}
+
+unsigned fpa_decl_plugin::mk_id(mpf const & v) {
+ unsigned new_id = m_id_gen.mk();
+ m_values.reserve(new_id+1);
+ m_fm.set(m_values[new_id], v);
+ unsigned old_id = m_value_table.insert_if_not_there(new_id);
+ if (old_id != new_id) {
+ m_id_gen.recycle(new_id);
+ m_fm.del(m_values[new_id]);
+ }
+ return old_id;
+}
+
+void fpa_decl_plugin::recycled_id(unsigned id) {
+ SASSERT(m_value_table.contains(id));
+ m_value_table.erase(id);
+ m_id_gen.recycle(id);
+ m_fm.del(m_values[id]);
+}
+
+func_decl * fpa_decl_plugin::mk_numeral_decl(mpf const & v) {
+ parameter p(mk_id(v), true);
+ SASSERT(p.is_external());
+ sort * s = mk_float_sort(v.get_ebits(), v.get_sbits());
+ return m_manager->mk_const_decl(symbol("fp.numeral"), s, func_decl_info(m_family_id, OP_FPA_NUM, 1, &p));
+}
+
+app * fpa_decl_plugin::mk_numeral(mpf const & v) {
+ sort * s = mk_float_sort(v.get_ebits(), v.get_sbits());
+ func_decl * d;
+ if (m_fm.is_nan(v))
+ d = m_manager->mk_const_decl(symbol("NaN"), s, func_decl_info(m_family_id, OP_FPA_NAN));
+ else if (m_fm.is_pinf(v))
+ d = m_manager->mk_const_decl(symbol("+oo"), s, func_decl_info(m_family_id, OP_FPA_PLUS_INF));
+ else if (m_fm.is_ninf(v))
+ d = m_manager->mk_const_decl(symbol("-oo"), s, func_decl_info(m_family_id, OP_FPA_MINUS_INF));
+ else if (m_fm.is_pzero(v))
+ d = m_manager->mk_const_decl(symbol("+zero"), s, func_decl_info(m_family_id, OP_FPA_PLUS_ZERO));
+ else if (m_fm.is_nzero(v))
+ d = m_manager->mk_const_decl(symbol("-zero"), s, func_decl_info(m_family_id, OP_FPA_MINUS_ZERO));
+ else
+ d = mk_numeral_decl(v);
+ return m_manager->mk_const(d);
+}
+
+bool fpa_decl_plugin::is_numeral(expr * n, mpf & val) {
+ if (is_app_of(n, m_family_id, OP_FPA_NUM)) {
+ m_fm.set(val, m_values[to_app(n)->get_decl()->get_parameter(0).get_ext_id()]);
+ return true;
+ }
+ else if (is_app_of(n, m_family_id, OP_FPA_MINUS_INF)) {
+ unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
+ unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
+ m_fm.mk_ninf(ebits, sbits, val);
+ return true;
+ }
+ else if (is_app_of(n, m_family_id, OP_FPA_PLUS_INF)) {
+ unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
+ unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
+ m_fm.mk_pinf(ebits, sbits, val);
+ return true;
+ }
+ else if (is_app_of(n, m_family_id, OP_FPA_NAN)) {
+ unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
+ unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
+ m_fm.mk_nan(ebits, sbits, val);
+ return true;
+ }
+ else if (is_app_of(n, m_family_id, OP_FPA_PLUS_ZERO)) {
+ unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
+ unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
+ m_fm.mk_pzero(ebits, sbits, val);
+ return true;
+ }
+ else if (is_app_of(n, m_family_id, OP_FPA_MINUS_ZERO)) {
+ unsigned ebits = to_app(n)->get_decl()->get_range()->get_parameter(0).get_int();
+ unsigned sbits = to_app(n)->get_decl()->get_range()->get_parameter(1).get_int();
+ m_fm.mk_nzero(ebits, sbits, val);
+ return true;
+ }
+ return false;
+}
+
+bool fpa_decl_plugin::is_numeral(expr * n) {
+ scoped_mpf v(m_fm);
+ return is_numeral(n, v);
+}
+
+bool fpa_decl_plugin::is_rm_numeral(expr * n, mpf_rounding_mode & val) {
+ if (is_app_of(n, m_family_id, OP_FPA_RM_NEAREST_TIES_TO_AWAY)) {
+ val = MPF_ROUND_NEAREST_TAWAY;
+ return true;
+ }
+ else if (is_app_of(n, m_family_id, OP_FPA_RM_NEAREST_TIES_TO_EVEN)) {
+ val = MPF_ROUND_NEAREST_TEVEN;
+ return true;
+ }
+ else if (is_app_of(n, m_family_id, OP_FPA_RM_TOWARD_NEGATIVE)) {
+ val = MPF_ROUND_TOWARD_NEGATIVE;
+ return true;
+ }
+ else if (is_app_of(n, m_family_id, OP_FPA_RM_TOWARD_POSITIVE)) {
+ val = MPF_ROUND_TOWARD_POSITIVE;
+ return true;
+ }
+ else if (is_app_of(n, m_family_id, OP_FPA_RM_TOWARD_ZERO)) {
+ val = MPF_ROUND_TOWARD_ZERO;
+ return true;
+ }
+
+ return 0;
+}
+
+bool fpa_decl_plugin::is_rm_numeral(expr * n) {
+ mpf_rounding_mode t;
+ return is_rm_numeral(n, t);
+}
+
+void fpa_decl_plugin::del(parameter const & p) {
+ SASSERT(p.is_external());
+ recycled_id(p.get_ext_id());
+}
+
+parameter fpa_decl_plugin::translate(parameter const & p, decl_plugin & target) {
+ SASSERT(p.is_external());
+ fpa_decl_plugin & _target = static_cast(target);
+ return parameter(_target.mk_id(m_values[p.get_ext_id()]), true);
+}
+
+void fpa_decl_plugin::finalize() {
+ if (m_real_sort) { m_manager->dec_ref(m_real_sort); }
+ if (m_int_sort) { m_manager->dec_ref(m_int_sort); }
+}
+
+decl_plugin * fpa_decl_plugin::mk_fresh() {
+ return alloc(fpa_decl_plugin);
+}
+
+sort * fpa_decl_plugin::mk_float_sort(unsigned ebits, unsigned sbits) {
+ if (sbits < 2)
+ m_manager->raise_exception("minimum number of significand bits is 1");
+ if (ebits < 2)
+ m_manager->raise_exception("minimum number of exponent bits is 2");
+
+ parameter p1(ebits), p2(sbits);
+ parameter ps[2] = { p1, p2 };
+ sort_size sz;
+ sz = sort_size::mk_very_big(); // TODO: refine
+ return m_manager->mk_sort(symbol("FloatingPoint"), sort_info(m_family_id, FLOATING_POINT_SORT, sz, 2, ps));
+}
+
+sort * fpa_decl_plugin::mk_rm_sort() {
+ return m_manager->mk_sort(symbol("RoundingMode"), sort_info(m_family_id, ROUNDING_MODE_SORT));
+}
+
+sort * fpa_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
+ switch (k) {
+ case FLOATING_POINT_SORT:
+ if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()))
+ m_manager->raise_exception("expecting two integer parameters to floating point sort (ebits, sbits)");
+ return mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
+ case ROUNDING_MODE_SORT:
+ return mk_rm_sort();
+ case FLOAT16_SORT:
+ return mk_float_sort(5, 11);
+ case FLOAT32_SORT:
+ return mk_float_sort(8, 24);
+ case FLOAT64_SORT:
+ return mk_float_sort(11, 53);
+ case FLOAT128_SORT:
+ return mk_float_sort(15, 113);
+ default:
+ m_manager->raise_exception("unknown floating point theory sort");
+ return 0;
+ }
+}
+
+func_decl * fpa_decl_plugin::mk_rm_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (num_parameters != 0)
+ m_manager->raise_exception("rounding mode constant does not have parameters");
+ if (arity != 0)
+ m_manager->raise_exception("rounding mode is a constant");
+ sort * s = mk_rm_sort();
+ func_decl_info finfo(m_family_id, k);
+ switch (k) {
+ case OP_FPA_RM_NEAREST_TIES_TO_EVEN:
+ return m_manager->mk_const_decl(symbol("roundNearestTiesToEven"), s, finfo);
+ case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
+ return m_manager->mk_const_decl(symbol("roundNearestTiesToAway"), s, finfo);
+ case OP_FPA_RM_TOWARD_POSITIVE:
+ return m_manager->mk_const_decl(symbol("roundTowardPositive"), s, finfo);
+ case OP_FPA_RM_TOWARD_NEGATIVE:
+ return m_manager->mk_const_decl(symbol("roundTowardNegative"), s, finfo);
+ case OP_FPA_RM_TOWARD_ZERO:
+ return m_manager->mk_const_decl(symbol("roundTowardZero"), s, finfo);
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+}
+
+func_decl * fpa_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ sort * s;
+ if (num_parameters == 1 && parameters[0].is_ast() && is_sort(parameters[0].get_ast()) && is_float_sort(to_sort(parameters[0].get_ast()))) {
+ s = to_sort(parameters[0].get_ast());
+ }
+ else if (num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()) {
+ s = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
+ }
+ else if (range != 0 && is_float_sort(range)) {
+ s = range;
+ }
+ else {
+ m_manager->raise_exception("sort of floating point constant was not specified");
+ UNREACHABLE();
+ }
+
+ SASSERT(is_sort_of(s, m_family_id, FLOATING_POINT_SORT));
+
+ unsigned ebits = s->get_parameter(0).get_int();
+ unsigned sbits = s->get_parameter(1).get_int();
+ scoped_mpf val(m_fm);
+
+ switch (k)
+ {
+ case OP_FPA_NAN: m_fm.mk_nan(ebits, sbits, val);
+ SASSERT(m_fm.is_nan(val));
+ break;
+ case OP_FPA_MINUS_INF: m_fm.mk_ninf(ebits, sbits, val); break;
+ case OP_FPA_PLUS_INF: m_fm.mk_pinf(ebits, sbits, val); break;
+ case OP_FPA_MINUS_ZERO: m_fm.mk_nzero(ebits, sbits, val); break;
+ case OP_FPA_PLUS_ZERO: m_fm.mk_pzero(ebits, sbits, val); break;
+ }
+
+ return mk_numeral_decl(val);
+}
+
+func_decl * fpa_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 2)
+ m_manager->raise_exception("invalid number of arguments to floating point relation");
+ if (domain[0] != domain[1] || !is_float_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected equal FloatingPoint sorts as arguments");
+ symbol name;
+ switch (k) {
+ case OP_FPA_EQ: name = "fp.eq"; break;
+ case OP_FPA_LT: name = "fp.lt"; break;
+ case OP_FPA_GT: name = "fp.gt"; break;
+ case OP_FPA_LE: name = "fp.leq"; break;
+ case OP_FPA_GE: name = "fp.geq"; break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ func_decl_info finfo(m_family_id, k);
+ finfo.set_chainable(true);
+ return m_manager->mk_func_decl(name, arity, domain, m_manager->mk_bool_sort(), finfo);
+}
+
+func_decl * fpa_decl_plugin::mk_unary_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 1)
+ m_manager->raise_exception("invalid number of arguments to floating point relation");
+ if (!is_float_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
+ symbol name;
+ switch (k) {
+ case OP_FPA_IS_ZERO: name = "fp.isZero"; break;
+ case OP_FPA_IS_NEGATIVE: name = "fp.isNegative"; break;
+ case OP_FPA_IS_POSITIVE: name = "fp.isPositive"; break;
+ case OP_FPA_IS_NAN: name = "fp.isNaN"; break;
+ case OP_FPA_IS_INF: name = "fp.isInfinite"; break;
+ case OP_FPA_IS_NORMAL: name = "fp.isNormal"; break;
+ case OP_FPA_IS_SUBNORMAL: name = "fp.isSubnormal"; break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return m_manager->mk_func_decl(name, arity, domain, m_manager->mk_bool_sort(), func_decl_info(m_family_id, k));
+}
+
+func_decl * fpa_decl_plugin::mk_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 1)
+ m_manager->raise_exception("invalid number of arguments to floating point operator");
+ if (!is_float_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
+ symbol name;
+ switch (k) {
+ case OP_FPA_ABS: name = "fp.abs"; break;
+ case OP_FPA_NEG: name = "fp.neg"; break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return m_manager->mk_func_decl(name, arity, domain, domain[0], func_decl_info(m_family_id, k));
+}
+
+func_decl * fpa_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 2)
+ m_manager->raise_exception("invalid number of arguments to floating point operator");
+ if (domain[0] != domain[1] || !is_float_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected arguments of equal FloatingPoint sorts");
+ symbol name;
+ switch (k) {
+ case OP_FPA_REM: name = "fp.rem"; break;
+ case OP_FPA_MIN: name = "fp.min"; break;
+ case OP_FPA_MAX: name = "fp.max"; break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return m_manager->mk_func_decl(name, arity, domain, domain[0], func_decl_info(m_family_id, k));
+}
+
+func_decl * fpa_decl_plugin::mk_rm_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 3)
+ m_manager->raise_exception("invalid number of arguments to floating point operator");
+ if (!is_rm_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort");
+ if (domain[1] != domain[2] || !is_float_sort(domain[1]))
+ m_manager->raise_exception("sort mismatch, expected arguments 1 and 2 of equal FloatingPoint sorts");
+ symbol name;
+ switch (k) {
+ case OP_FPA_ADD: name = "fp.add"; break;
+ case OP_FPA_SUB: name = "fp.sub"; break;
+ case OP_FPA_MUL: name = "fp.mul"; break;
+ case OP_FPA_DIV: name = "fp.div"; break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return m_manager->mk_func_decl(name, arity, domain, domain[1], func_decl_info(m_family_id, k));
+}
+
+func_decl * fpa_decl_plugin::mk_rm_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 2)
+ m_manager->raise_exception("invalid number of arguments to floating point operator");
+ if (!is_rm_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected RoundingMode as first argument");
+ if (!is_float_sort(domain[1]))
+ m_manager->raise_exception("sort mismatch, expected FloatingPoint as second argument");
+ symbol name;
+ switch (k) {
+ case OP_FPA_SQRT: name = "fp.sqrt"; break;
+ case OP_FPA_ROUND_TO_INTEGRAL: name = "fp.roundToIntegral"; break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ return m_manager->mk_func_decl(name, arity, domain, domain[1], func_decl_info(m_family_id, k));
+}
+
+func_decl * fpa_decl_plugin::mk_fma(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 4)
+ m_manager->raise_exception("invalid number of arguments to fused_ma operator");
+ if (!is_rm_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected RoundingMode as first argument");
+ if (domain[1] != domain[2] || domain[1] != domain[3] || !is_float_sort(domain[1]))
+ m_manager->raise_exception("sort mismatch, expected arguments 1,2,3 of equal FloatingPoint sort");
+ symbol name("fp.fma");
+ return m_manager->mk_func_decl(name, arity, domain, domain[1], func_decl_info(m_family_id, k));
+}
+
+func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (m_bv_plugin && arity == 3 &&
+ is_sort_of(domain[0], m_bv_fid, BV_SORT) &&
+ is_sort_of(domain[1], m_bv_fid, BV_SORT) &&
+ is_sort_of(domain[2], m_bv_fid, BV_SORT)) {
+ // 3 BVs -> 1 FP
+ unsigned ebits = domain[1]->get_parameter(0).get_int();
+ unsigned sbits = domain[2]->get_parameter(0).get_int() + 1;
+ parameter ps[] = { parameter(ebits), parameter(sbits) };
+ sort * fp = mk_float_sort(ebits, sbits);
+ symbol name("to_fp");
+ return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, 2, ps));
+ }
+ else if (m_bv_plugin && arity == 1 && is_sort_of(domain[0], m_bv_fid, BV_SORT)) {
+ // 1 BV -> 1 FP
+ if (num_parameters != 2)
+ m_manager->raise_exception("invalid number of parameters to to_fp");
+ if (!parameters[0].is_int() || !parameters[1].is_int())
+ m_manager->raise_exception("invalid parameter type to to_fp");
+
+ int ebits = parameters[0].get_int();
+ int sbits = parameters[1].get_int();
+
+ if (domain[0]->get_parameter(0).get_int() != (ebits + sbits))
+ m_manager->raise_exception("sort mismatch; invalid bit-vector size, expected bitvector of size (ebits+sbits)");
+
+ sort * fp = mk_float_sort(ebits, sbits);
+ symbol name("to_fp");
+ return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
+ }
+ else if (m_bv_plugin && arity == 2 &&
+ is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) &&
+ is_sort_of(domain[1], m_bv_fid, BV_SORT)) {
+ // RoundingMode + 1 BV -> 1 FP
+ if (num_parameters != 2)
+ m_manager->raise_exception("invalid number of parameters to to_fp");
+ if (!parameters[0].is_int() || !parameters[1].is_int())
+ m_manager->raise_exception("invalid parameter type to to_fp");
+ int ebits = parameters[0].get_int();
+ int sbits = parameters[1].get_int();
+
+ sort * fp = mk_float_sort(ebits, sbits);
+ symbol name("to_fp");
+ return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
+ }
+ else if (arity == 2 &&
+ is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) &&
+ is_sort_of(domain[1], m_family_id, FLOATING_POINT_SORT)) {
+ // Rounding + 1 FP -> 1 FP
+ if (num_parameters != 2)
+ m_manager->raise_exception("invalid number of parameters to to_fp");
+ if (!parameters[0].is_int() || !parameters[1].is_int())
+ m_manager->raise_exception("invalid parameter type to to_fp");
+ int ebits = parameters[0].get_int();
+ int sbits = parameters[1].get_int();
+ if (!is_rm_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort");
+ if (!is_sort_of(domain[1], m_family_id, FLOATING_POINT_SORT))
+ m_manager->raise_exception("sort mismatch, expected second argument of FloatingPoint sort");
+
+ sort * fp = mk_float_sort(ebits, sbits);
+ symbol name("to_fp");
+ return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
+ }
+ else if (arity == 3 &&
+ is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) &&
+ is_sort_of(domain[1], m_arith_fid, REAL_SORT) &&
+ is_sort_of(domain[2], m_arith_fid, INT_SORT))
+ {
+ // Rounding + 1 Real + 1 Int -> 1 FP
+ if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()))
+ m_manager->raise_exception("expecting two integer parameters to to_fp");
+
+ sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
+ symbol name("to_fp");
+ return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
+ }
+ else if (arity == 1 &&
+ is_sort_of(domain[0], m_arith_fid, REAL_SORT))
+ {
+ // 1 Real -> 1 FP
+ if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()))
+ m_manager->raise_exception("expecting two integer parameters to to_fp");
+ if (domain[1] != m_real_sort)
+ m_manager->raise_exception("sort mismatch, expected one argument of Real sort");
+
+ sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
+ symbol name("to_fp");
+ return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
+ }
+ else if (arity == 2 &&
+ is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) &&
+ is_sort_of(domain[1], m_arith_fid, REAL_SORT))
+ {
+ // Rounding + 1 Real -> 1 FP
+ if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()))
+ m_manager->raise_exception("expecting two integer parameters to to_fp");
+
+ sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
+ symbol name("to_fp");
+ return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
+ }
+ else {
+ m_manager->raise_exception("Unexpected argument combination for (_ to_fp eb sb). Supported argument combinations are: "
+ "((_ BitVec 1) (_ BitVec eb) (_ BitVec sb-1)),"
+ "(_ BitVec (eb+sb)),"
+ "(Real),"
+ "(RoundingMode (_ BitVec (eb+sb))),"
+ "(RoundingMode (_ FloatingPoint eb' sb')),"
+ "(RoundingMode Real Int), and"
+ "(RoundingMode Real)."
+ );
+ }
+
+ return 0;
+}
+
+func_decl * fpa_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ SASSERT(m_bv_plugin);
+ if (arity != 2)
+ m_manager->raise_exception("invalid number of arguments to to_fp_unsigned");
+ if (!is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT))
+ m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort");
+ if (!is_sort_of(domain[1], m_bv_fid, BV_SORT))
+ m_manager->raise_exception("sort mismatch, expected second argument of bit-vector sort");
+
+ // RoundingMode + 1 BV -> 1 FP
+ if (num_parameters != 2)
+ m_manager->raise_exception("invalid number of parameters to to_fp_unsigned");
+ if (!parameters[0].is_int() || !parameters[1].is_int())
+ m_manager->raise_exception("invalid parameter type to to_fp_unsigned");
+
+ int ebits = parameters[0].get_int();
+ int sbits = parameters[1].get_int();
+
+ sort * fp = mk_float_sort(ebits, sbits);
+ symbol name("to_fp_unsigned");
+ return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
+}
+
+func_decl * fpa_decl_plugin::mk_fp(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 3)
+ m_manager->raise_exception("invalid number of arguments to fp");
+ if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) ||
+ (domain[0]->get_parameter(0).get_int() != 1) ||
+ !is_sort_of(domain[1], m_bv_fid, BV_SORT) ||
+ !is_sort_of(domain[2], m_bv_fid, BV_SORT))
+ m_manager->raise_exception("sort mismatch, expected three bit-vectors, the first one of size 1.");
+
+ int eb = (domain[1])->get_parameter(0).get_int();
+ int sb = (domain[2])->get_parameter(0).get_int() + 1;
+ symbol name("fp");
+ sort * fp = mk_float_sort(eb, sb);
+ return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k));
+}
+
+func_decl * fpa_decl_plugin::mk_to_ubv(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ SASSERT(m_bv_plugin);
+ if (arity != 2)
+ m_manager->raise_exception("invalid number of arguments to fp.to_ubv");
+ if (num_parameters != 1)
+ m_manager->raise_exception("invalid number of parameters to fp.to_ubv");
+ if (!parameters[0].is_int())
+ m_manager->raise_exception("invalid parameter type; fp.to_ubv expects an int parameter");
+ if (!is_rm_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort");
+ if (!is_sort_of(domain[1], m_family_id, FLOATING_POINT_SORT))
+ m_manager->raise_exception("sort mismatch, expected second argument of FloatingPoint sort");
+ if (parameters[0].get_int() <= 0)
+ m_manager->raise_exception("invalid parameter value; fp.to_ubv expects a parameter larger than 0");
+
+ symbol name("fp.to_ubv");
+ sort * bvs = m_bv_plugin->mk_sort(BV_SORT, 1, parameters);
+ return m_manager->mk_func_decl(name, arity, domain, bvs, func_decl_info(m_family_id, k, num_parameters, parameters));
+}
+
+func_decl * fpa_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ SASSERT(m_bv_plugin);
+ if (arity != 2)
+ m_manager->raise_exception("invalid number of arguments to fp.to_sbv");
+ if (num_parameters != 1)
+ m_manager->raise_exception("invalid number of parameters to fp.to_sbv");
+ if (!parameters[0].is_int())
+ m_manager->raise_exception("invalid parameter type; fp.to_sbv expects an int parameter");
+ if (!is_rm_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort");
+ if (!is_sort_of(domain[1], m_family_id, FLOATING_POINT_SORT))
+ m_manager->raise_exception("sort mismatch, expected second argument of FloatingPoint sort");
+ if (parameters[0].get_int() <= 0)
+ m_manager->raise_exception("invalid parameter value; fp.to_sbv expects a parameter larger than 0");
+
+ symbol name("fp.to_sbv");
+ sort * bvs = m_bv_plugin->mk_sort(BV_SORT, 1, parameters);
+ return m_manager->mk_func_decl(name, arity, domain, bvs, func_decl_info(m_family_id, k, num_parameters, parameters));
+
+}
+
+func_decl * fpa_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 1)
+ m_manager->raise_exception("invalid number of arguments to fp.to_real");
+ if (!is_float_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
+
+ symbol name("fp.to_real");
+ return m_manager->mk_func_decl(name, 1, domain, m_real_sort, func_decl_info(m_family_id, k));
+}
+
+func_decl * fpa_decl_plugin::mk_float_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 1)
+ m_manager->raise_exception("invalid number of arguments to asIEEEBV");
+ if (!is_float_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
+
+ unsigned float_sz = domain[0]->get_parameter(0).get_int() + domain[0]->get_parameter(1).get_int();
+ parameter ps[] = { parameter(float_sz) };
+ sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps);
+ symbol name("to_ieee_bv");
+ return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
+}
+
+func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 1)
+ m_manager->raise_exception("invalid number of arguments to internal_bv_wrap");
+ if (!is_float_sort(domain[0]) && !is_rm_sort(domain[0]))
+ m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint or RoundingMode sort");
+
+ if (is_float_sort(domain[0]))
+ {
+ unsigned float_sz = domain[0]->get_parameter(0).get_int() + domain[0]->get_parameter(1).get_int();
+ parameter ps[] = { parameter(float_sz) };
+ sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps);
+ return m_manager->mk_func_decl(symbol("bv_wrap"), 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
+ }
+ else {
+ parameter ps[] = { parameter(3) };
+ sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps);
+ return m_manager->mk_func_decl(symbol("bv_wrap"), 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
+ }
+}
+
+func_decl * fpa_decl_plugin::mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 1)
+ m_manager->raise_exception("invalid number of arguments to internal_bv_unwrap");
+ if (!is_sort_of(domain[0], m_bv_fid, BV_SORT))
+ m_manager->raise_exception("sort mismatch, expected argument of bitvector sort");
+ if (!is_float_sort(range) && !is_rm_sort(range))
+ m_manager->raise_exception("sort mismatch, expected range of FloatingPoint sort");
+
+ return m_manager->mk_func_decl(symbol("bv_unwrap"), 1, domain, range, func_decl_info(m_family_id, k, num_parameters, parameters));
+}
+
+func_decl * fpa_decl_plugin::mk_internal_to_ubv_unspecified(
+ decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 0)
+ m_manager->raise_exception("invalid number of arguments to fp.to_ubv_unspecified");
+ if (num_parameters != 1)
+ m_manager->raise_exception("invalid number of parameters to fp.to_ubv_unspecified; expecting 1");
+ if (!parameters[0].is_int())
+ m_manager->raise_exception("invalid parameters type provided to fp.to_ubv_unspecified; expecting an integer");
+
+ sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, parameters);
+ return m_manager->mk_func_decl(symbol("fp.to_ubv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
+}
+
+func_decl * fpa_decl_plugin::mk_internal_to_sbv_unspecified(
+ decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 0)
+ m_manager->raise_exception("invalid number of arguments to internal_to_sbv_unspecified");
+ if (num_parameters != 1)
+ m_manager->raise_exception("invalid number of parameters to fp.to_sbv_unspecified; expecting 1");
+ if (!parameters[0].is_int())
+ m_manager->raise_exception("invalid parameters type provided to fp.to_sbv_unspecified; expecting an integer");
+ sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, parameters);
+ return m_manager->mk_func_decl(symbol("fp.to_sbv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
+}
+
+func_decl * fpa_decl_plugin::mk_internal_to_real_unspecified(
+ decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ if (arity != 0)
+ m_manager->raise_exception("invalid number of arguments to internal_to_real_unspecified");
+ if (!is_sort_of(range, m_arith_fid, REAL_SORT))
+ m_manager->raise_exception("sort mismatch, expected range of FloatingPoint sort");
+
+ return m_manager->mk_func_decl(symbol("fp.to_real_unspecified"), 0, domain, m_real_sort, func_decl_info(m_family_id, k, num_parameters, parameters));
+}
+
+
+func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range) {
+ switch (k) {
+ case OP_FPA_MINUS_INF:
+ case OP_FPA_PLUS_INF:
+ case OP_FPA_NAN:
+ case OP_FPA_MINUS_ZERO:
+ case OP_FPA_PLUS_ZERO:
+ return mk_float_const_decl(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_RM_NEAREST_TIES_TO_EVEN:
+ case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
+ case OP_FPA_RM_TOWARD_POSITIVE:
+ case OP_FPA_RM_TOWARD_NEGATIVE:
+ case OP_FPA_RM_TOWARD_ZERO:
+ return mk_rm_const_decl(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_EQ:
+ case OP_FPA_LT:
+ case OP_FPA_GT:
+ case OP_FPA_LE:
+ case OP_FPA_GE:
+ return mk_bin_rel_decl(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_IS_ZERO:
+ case OP_FPA_IS_NEGATIVE:
+ case OP_FPA_IS_POSITIVE:
+ case OP_FPA_IS_NAN:
+ case OP_FPA_IS_INF:
+ case OP_FPA_IS_NORMAL:
+ case OP_FPA_IS_SUBNORMAL:
+ return mk_unary_rel_decl(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_ABS:
+ case OP_FPA_NEG:
+ return mk_unary_decl(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_REM:
+ case OP_FPA_MIN:
+ case OP_FPA_MAX:
+ return mk_binary_decl(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_ADD:
+ case OP_FPA_MUL:
+ case OP_FPA_DIV:
+ return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_SUB:
+ if (arity == 1)
+ return mk_unary_decl(OP_FPA_NEG, num_parameters, parameters, arity, domain, range);
+ else
+ return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_SQRT:
+ case OP_FPA_ROUND_TO_INTEGRAL:
+ return mk_rm_unary_decl(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_FMA:
+ return mk_fma(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_FP:
+ return mk_fp(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_TO_UBV:
+ return mk_to_ubv(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_TO_SBV:
+ return mk_to_sbv(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_TO_REAL:
+ return mk_to_real(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_TO_FP:
+ return mk_to_fp(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_TO_FP_UNSIGNED:
+ return mk_to_fp_unsigned(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_TO_IEEE_BV:
+ return mk_float_to_ieee_bv(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_INTERNAL_BVWRAP:
+ return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_INTERNAL_BVUNWRAP:
+ return mk_internal_bv_unwrap(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
+ return mk_internal_to_ubv_unspecified(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
+ return mk_internal_to_sbv_unspecified(k, num_parameters, parameters, arity, domain, range);
+ case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
+ return mk_internal_to_real_unspecified(k, num_parameters, parameters, arity, domain, range);
+ default:
+ m_manager->raise_exception("unsupported floating point operator");
+ return 0;
+ }
+}
+
+void fpa_decl_plugin::get_op_names(svector & op_names, symbol const & logic) {
+ // These are the operators from the final draft of the SMT FloatingPoint standard
+ op_names.push_back(builtin_name("+oo", OP_FPA_PLUS_INF));
+ op_names.push_back(builtin_name("-oo", OP_FPA_MINUS_INF));
+ op_names.push_back(builtin_name("+zero", OP_FPA_PLUS_ZERO));
+ op_names.push_back(builtin_name("-zero", OP_FPA_MINUS_ZERO));
+ op_names.push_back(builtin_name("NaN", OP_FPA_NAN));
+
+ op_names.push_back(builtin_name("roundNearestTiesToEven", OP_FPA_RM_NEAREST_TIES_TO_EVEN));
+ op_names.push_back(builtin_name("roundNearestTiesToAway", OP_FPA_RM_NEAREST_TIES_TO_AWAY));
+ op_names.push_back(builtin_name("roundTowardPositive", OP_FPA_RM_TOWARD_POSITIVE));
+ op_names.push_back(builtin_name("roundTowardNegative", OP_FPA_RM_TOWARD_NEGATIVE));
+ op_names.push_back(builtin_name("roundTowardZero", OP_FPA_RM_TOWARD_ZERO));
+
+ op_names.push_back(builtin_name("RNE", OP_FPA_RM_NEAREST_TIES_TO_EVEN));
+ op_names.push_back(builtin_name("RNA", OP_FPA_RM_NEAREST_TIES_TO_AWAY));
+ op_names.push_back(builtin_name("RTP", OP_FPA_RM_TOWARD_POSITIVE));
+ op_names.push_back(builtin_name("RTN", OP_FPA_RM_TOWARD_NEGATIVE));
+ op_names.push_back(builtin_name("RTZ", OP_FPA_RM_TOWARD_ZERO));
+
+ op_names.push_back(builtin_name("fp.abs", OP_FPA_ABS));
+ op_names.push_back(builtin_name("fp.neg", OP_FPA_NEG));
+ op_names.push_back(builtin_name("fp.add", OP_FPA_ADD));
+ op_names.push_back(builtin_name("fp.sub", OP_FPA_SUB));
+ op_names.push_back(builtin_name("fp.mul", OP_FPA_MUL));
+ op_names.push_back(builtin_name("fp.div", OP_FPA_DIV));
+ op_names.push_back(builtin_name("fp.fma", OP_FPA_FMA));
+ op_names.push_back(builtin_name("fp.sqrt", OP_FPA_SQRT));
+ op_names.push_back(builtin_name("fp.rem", OP_FPA_REM));
+ op_names.push_back(builtin_name("fp.roundToIntegral", OP_FPA_ROUND_TO_INTEGRAL));
+ op_names.push_back(builtin_name("fp.min", OP_FPA_MIN));
+ op_names.push_back(builtin_name("fp.max", OP_FPA_MAX));
+ op_names.push_back(builtin_name("fp.leq", OP_FPA_LE));
+ op_names.push_back(builtin_name("fp.lt", OP_FPA_LT));
+ op_names.push_back(builtin_name("fp.geq", OP_FPA_GE));
+ op_names.push_back(builtin_name("fp.gt", OP_FPA_GT));
+ op_names.push_back(builtin_name("fp.eq", OP_FPA_EQ));
+
+ op_names.push_back(builtin_name("fp.isNormal", OP_FPA_IS_NORMAL));
+ op_names.push_back(builtin_name("fp.isSubnormal", OP_FPA_IS_SUBNORMAL));
+ op_names.push_back(builtin_name("fp.isZero", OP_FPA_IS_ZERO));
+ op_names.push_back(builtin_name("fp.isInfinite", OP_FPA_IS_INF));
+ op_names.push_back(builtin_name("fp.isNaN", OP_FPA_IS_NAN));
+ op_names.push_back(builtin_name("fp.isNegative", OP_FPA_IS_NEGATIVE));
+ op_names.push_back(builtin_name("fp.isPositive", OP_FPA_IS_POSITIVE));
+
+ op_names.push_back(builtin_name("fp", OP_FPA_FP));
+ op_names.push_back(builtin_name("fp.to_ubv", OP_FPA_TO_UBV));
+ op_names.push_back(builtin_name("fp.to_sbv", OP_FPA_TO_SBV));
+ op_names.push_back(builtin_name("fp.to_real", OP_FPA_TO_REAL));
+
+ op_names.push_back(builtin_name("to_fp", OP_FPA_TO_FP));
+ op_names.push_back(builtin_name("to_fp_unsigned", OP_FPA_TO_FP_UNSIGNED));
+
+ /* Extensions */
+ op_names.push_back(builtin_name("to_ieee_bv", OP_FPA_TO_IEEE_BV));
+}
+
+void fpa_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) {
+ sort_names.push_back(builtin_name("FloatingPoint", FLOATING_POINT_SORT));
+ sort_names.push_back(builtin_name("RoundingMode", ROUNDING_MODE_SORT));
+
+ // The final theory supports three common FloatingPoint sorts
+ sort_names.push_back(builtin_name("Float16", FLOAT16_SORT));
+ sort_names.push_back(builtin_name("Float32", FLOAT32_SORT));
+ sort_names.push_back(builtin_name("Float64", FLOAT64_SORT));
+ sort_names.push_back(builtin_name("Float128", FLOAT128_SORT));
+}
+
+expr * fpa_decl_plugin::get_some_value(sort * s) {
+ SASSERT(s->is_sort_of(m_family_id, FLOATING_POINT_SORT));
+ mpf tmp;
+ m_fm.mk_nan(s->get_parameter(0).get_int(), s->get_parameter(1).get_int(), tmp);
+ expr * res = this->mk_numeral(tmp);
+ m_fm.del(tmp);
+ return res;
+}
+
+bool fpa_decl_plugin::is_value(app * e) const {
+ if (e->get_family_id() != m_family_id)
+ return false;
+ switch (e->get_decl_kind()) {
+ case OP_FPA_RM_NEAREST_TIES_TO_EVEN:
+ case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
+ case OP_FPA_RM_TOWARD_POSITIVE:
+ case OP_FPA_RM_TOWARD_NEGATIVE:
+ case OP_FPA_RM_TOWARD_ZERO:
+ case OP_FPA_NUM:
+ case OP_FPA_PLUS_INF:
+ case OP_FPA_MINUS_INF:
+ case OP_FPA_PLUS_ZERO:
+ case OP_FPA_MINUS_ZERO:
+ case OP_FPA_NAN:
+ return true;
+ case OP_FPA_FP:
+ return m_manager->is_value(e->get_arg(0)) &&
+ m_manager->is_value(e->get_arg(1)) &&
+ m_manager->is_value(e->get_arg(2));
+ default:
+ return false;
+ }
+}
+
+bool fpa_decl_plugin::is_unique_value(app* e) const {
+ if (e->get_family_id() != m_family_id)
+ return false;
+ switch (e->get_decl_kind()) {
+ case OP_FPA_RM_NEAREST_TIES_TO_EVEN:
+ case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
+ case OP_FPA_RM_TOWARD_POSITIVE:
+ case OP_FPA_RM_TOWARD_NEGATIVE:
+ case OP_FPA_RM_TOWARD_ZERO:
+ return true;
+ case OP_FPA_PLUS_INF: /* No; +oo == fp(#b0 #b11 #b00) */
+ case OP_FPA_MINUS_INF: /* No; -oo == fp #b1 #b11 #b00) */
+ case OP_FPA_PLUS_ZERO: /* No; +zero == fp #b0 #b00 #b000) */
+ case OP_FPA_MINUS_ZERO: /* No; -zero == fp #b1 #b00 #b000) */
+ case OP_FPA_NAN: /* No; NaN == (fp #b0 #b111111 #b0000001) */
+ case OP_FPA_NUM: /* see NaN */
+ return false;
+ case OP_FPA_FP:
+ return m_manager->is_unique_value(e->get_arg(0)) &&
+ m_manager->is_unique_value(e->get_arg(1)) &&
+ m_manager->is_unique_value(e->get_arg(2));
+ default:
+ return false;
+ }
+}
+
+fpa_util::fpa_util(ast_manager & m):
+ m_manager(m),
+ m_fid(m.mk_family_id("fpa")),
+ m_a_util(m),
+ m_bv_util(m) {
+ m_plugin = static_cast(m.get_plugin(m_fid));
+}
+
+fpa_util::~fpa_util() {
+}
+
+sort * fpa_util::mk_float_sort(unsigned ebits, unsigned sbits) {
+ parameter ps[2] = { parameter(ebits), parameter(sbits) };
+ return m().mk_sort(m_fid, FLOATING_POINT_SORT, 2, ps);
+}
+
+unsigned fpa_util::get_ebits(sort * s) {
+ SASSERT(is_float(s));
+ return static_cast(s->get_parameter(0).get_int());
+}
+
+unsigned fpa_util::get_sbits(sort * s) {
+ SASSERT(is_float(s));
+ return static_cast(s->get_parameter(1).get_int());
+}
+
+app * fpa_util::mk_nan(unsigned ebits, unsigned sbits) {
+ scoped_mpf v(fm());
+ fm().mk_nan(ebits, sbits, v);
+ return mk_value(v);
+}
+
+app * fpa_util::mk_pinf(unsigned ebits, unsigned sbits) {
+ scoped_mpf v(fm());
+ fm().mk_pinf(ebits, sbits, v);
+ return mk_value(v);
+}
+
+app * fpa_util::mk_ninf(unsigned ebits, unsigned sbits) {
+ scoped_mpf v(fm());
+ fm().mk_ninf(ebits, sbits, v);
+ return mk_value(v);
+}
+
+app * fpa_util::mk_pzero(unsigned ebits, unsigned sbits) {
+ scoped_mpf v(fm());
+ fm().mk_pzero(ebits, sbits, v);
+ return mk_value(v);
+}
+
+app * fpa_util::mk_nzero(unsigned ebits, unsigned sbits) {
+ scoped_mpf v(fm());
+ fm().mk_nzero(ebits, sbits, v);
+ return mk_value(v);
+}
+
+app * fpa_util::mk_internal_to_ubv_unspecified(unsigned width) {
+ parameter ps[] = { parameter(width) };
+ sort * range = m_bv_util.mk_sort(width);
+ return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 1, ps, 0, 0, range);
+}
+
+app * fpa_util::mk_internal_to_sbv_unspecified(unsigned width) {
+ parameter ps[] = { parameter(width) };
+ sort * range = m_bv_util.mk_sort(width);
+ return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, 1, ps, 0, 0, range);
+}
+
+app * fpa_util::mk_internal_to_real_unspecified() {
+ sort * range = m_a_util.mk_real();
+ return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, 0, 0, 0, 0, range);
+}
\ No newline at end of file
diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h
new file mode 100644
index 000000000..fc1521456
--- /dev/null
+++ b/src/ast/fpa_decl_plugin.h
@@ -0,0 +1,341 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ fpa_decl_plugin.h
+
+Abstract:
+
+ Floating point decl plugin
+
+Author:
+
+ Leonardo de Moura (leonardo) 2012-01-15.
+
+Revision History:
+
+--*/
+#ifndef _fpa_decl_plugin_H_
+#define _fpa_decl_plugin_H_
+
+#include"ast.h"
+#include"id_gen.h"
+#include"arith_decl_plugin.h"
+#include"bv_decl_plugin.h"
+#include"mpf.h"
+
+enum fpa_sort_kind {
+ FLOATING_POINT_SORT,
+ ROUNDING_MODE_SORT,
+ FLOAT16_SORT,
+ FLOAT32_SORT,
+ FLOAT64_SORT,
+ FLOAT128_SORT
+};
+
+enum fpa_op_kind {
+ OP_FPA_RM_NEAREST_TIES_TO_EVEN,
+ OP_FPA_RM_NEAREST_TIES_TO_AWAY,
+ OP_FPA_RM_TOWARD_POSITIVE,
+ OP_FPA_RM_TOWARD_NEGATIVE,
+ OP_FPA_RM_TOWARD_ZERO,
+
+ OP_FPA_NUM,
+ OP_FPA_PLUS_INF,
+ OP_FPA_MINUS_INF,
+ OP_FPA_NAN,
+ OP_FPA_PLUS_ZERO,
+ OP_FPA_MINUS_ZERO,
+
+ OP_FPA_ADD,
+ OP_FPA_SUB,
+ OP_FPA_NEG,
+ OP_FPA_MUL,
+ OP_FPA_DIV,
+ OP_FPA_REM,
+ OP_FPA_ABS,
+ OP_FPA_MIN,
+ OP_FPA_MAX,
+ OP_FPA_FMA, // x*y + z
+ OP_FPA_SQRT,
+ OP_FPA_ROUND_TO_INTEGRAL,
+
+ OP_FPA_EQ,
+ OP_FPA_LT,
+ OP_FPA_GT,
+ OP_FPA_LE,
+ OP_FPA_GE,
+ OP_FPA_IS_NAN,
+ OP_FPA_IS_INF,
+ OP_FPA_IS_ZERO,
+ OP_FPA_IS_NORMAL,
+ OP_FPA_IS_SUBNORMAL,
+ OP_FPA_IS_NEGATIVE,
+ OP_FPA_IS_POSITIVE,
+
+ OP_FPA_FP,
+ OP_FPA_TO_FP,
+ OP_FPA_TO_FP_UNSIGNED,
+ OP_FPA_TO_UBV,
+ OP_FPA_TO_SBV,
+ OP_FPA_TO_REAL,
+
+ /* Extensions */
+ OP_FPA_TO_IEEE_BV,
+
+ /* Internal use only */
+ OP_FPA_INTERNAL_BVWRAP,
+ OP_FPA_INTERNAL_BVUNWRAP,
+ OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED,
+ OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED,
+ OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED,
+
+ LAST_FLOAT_OP
+};
+
+class fpa_decl_plugin : public decl_plugin {
+ struct mpf_hash_proc {
+ scoped_mpf_vector const & m_values;
+ mpf_hash_proc(scoped_mpf_vector const & values):m_values(values) {}
+ unsigned operator()(unsigned id) const { return m_values.m().hash(m_values[id]); }
+ };
+
+ struct mpf_eq_proc {
+ scoped_mpf_vector const & m_values;
+ mpf_eq_proc(scoped_mpf_vector const & values):m_values(values) {}
+ bool operator()(unsigned id1, unsigned id2) const { return m_values.m().eq_core(m_values[id1], m_values[id2]); }
+ };
+
+ typedef chashtable value_table;
+
+
+ mpf_manager m_fm;
+ id_gen m_id_gen;
+ scoped_mpf_vector m_values;
+ value_table m_value_table;
+ sort * m_real_sort;
+ sort * m_int_sort;
+ family_id m_arith_fid;
+ family_id m_bv_fid;
+ bv_decl_plugin * m_bv_plugin;
+
+ sort * mk_float_sort(unsigned ebits, unsigned sbits);
+ sort * mk_rm_sort();
+ func_decl * mk_rm_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_float_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_bin_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_unary_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_rm_binary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_rm_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_fma(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_fp(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_to_fp(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_to_fp_unsigned(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_to_ubv(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_to_sbv(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_to_real(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_float_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+
+ func_decl * mk_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_internal_to_ubv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_internal_to_sbv_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ func_decl * mk_internal_to_real_unspecified(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+
+ virtual void set_manager(ast_manager * m, family_id id);
+ unsigned mk_id(mpf const & v);
+ void recycled_id(unsigned id);
+public:
+ fpa_decl_plugin();
+
+ bool is_float_sort(sort * s) const { return is_sort_of(s, m_family_id, FLOATING_POINT_SORT); }
+ bool is_rm_sort(sort * s) const { return is_sort_of(s, m_family_id, ROUNDING_MODE_SORT); }
+
+ virtual ~fpa_decl_plugin();
+ virtual void finalize();
+
+ virtual decl_plugin * mk_fresh();
+ virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
+ virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ unsigned arity, sort * const * domain, sort * range);
+ virtual void get_op_names(svector & op_names, symbol const & logic);
+ virtual void get_sort_names(svector & sort_names, symbol const & logic);
+ virtual expr * get_some_value(sort * s);
+ virtual bool is_value(app* e) const;
+ virtual bool is_unique_value(app* e) const;
+
+ mpf_manager & fm() { return m_fm; }
+ func_decl * mk_numeral_decl(mpf const & v);
+ app * mk_numeral(mpf const & v);
+ bool is_numeral(expr * n);
+ bool is_numeral(expr * n, mpf & val);
+ bool is_rm_numeral(expr * n, mpf_rounding_mode & val);
+ bool is_rm_numeral(expr * n);
+
+ mpf const & get_value(unsigned id) const {
+ SASSERT(m_value_table.contains(id));
+ return m_values[id];
+ }
+
+ virtual void del(parameter const & p);
+ virtual parameter translate(parameter const & p, decl_plugin & target);
+};
+
+class fpa_util {
+ ast_manager & m_manager;
+ fpa_decl_plugin * m_plugin;
+ family_id m_fid;
+ arith_util m_a_util;
+ bv_util m_bv_util;
+public:
+ fpa_util(ast_manager & m);
+ ~fpa_util();
+
+ ast_manager & m() const { return m_manager; }
+ mpf_manager & fm() const { return m_plugin->fm(); }
+ family_id get_fid() const { return m_fid; }
+ family_id get_family_id() const { return m_fid; }
+ arith_util & au() { return m_a_util; }
+ fpa_decl_plugin & plugin() { return *m_plugin; }
+
+ sort * mk_float_sort(unsigned ebits, unsigned sbits);
+ sort * mk_rm_sort() { return m().mk_sort(m_fid, ROUNDING_MODE_SORT); }
+ bool is_float(sort * s) { return is_sort_of(s, m_fid, FLOATING_POINT_SORT); }
+ bool is_rm(sort * s) { return is_sort_of(s, m_fid, ROUNDING_MODE_SORT); }
+ bool is_float(expr * e) { return is_float(m_manager.get_sort(e)); }
+ bool is_rm(expr * e) { return is_rm(m_manager.get_sort(e)); }
+ unsigned get_ebits(sort * s);
+ unsigned get_sbits(sort * s);
+
+ app * mk_round_nearest_ties_to_even() { return m().mk_const(m_fid, OP_FPA_RM_NEAREST_TIES_TO_EVEN); }
+ app * mk_round_nearest_ties_to_away() { return m().mk_const(m_fid, OP_FPA_RM_NEAREST_TIES_TO_AWAY); }
+ app * mk_round_toward_positive() { return m().mk_const(m_fid, OP_FPA_RM_TOWARD_POSITIVE); }
+ app * mk_round_toward_negative() { return m().mk_const(m_fid, OP_FPA_RM_TOWARD_NEGATIVE); }
+ app * mk_round_toward_zero() { return m().mk_const(m_fid, OP_FPA_RM_TOWARD_ZERO); }
+
+ app * mk_nan(unsigned ebits, unsigned sbits);
+ app * mk_pinf(unsigned ebits, unsigned sbits);
+ app * mk_ninf(unsigned ebits, unsigned sbits);
+ app * mk_nan(sort * s) { return mk_nan(get_ebits(s), get_sbits(s)); }
+ app * mk_pinf(sort * s) { return mk_pinf(get_ebits(s), get_sbits(s)); }
+ app * mk_ninf(sort * s) { return mk_ninf(get_ebits(s), get_sbits(s)); }
+
+ app * mk_value(mpf const & v) { return m_plugin->mk_numeral(v); }
+ bool is_numeral(expr * n) { return m_plugin->is_numeral(n); }
+ bool is_numeral(expr * n, mpf & v) { return m_plugin->is_numeral(n, v); }
+ bool is_rm_numeral(expr * n) { return m_plugin->is_rm_numeral(n); }
+ bool is_rm_numeral(expr * n, mpf_rounding_mode & v) { return m_plugin->is_rm_numeral(n, v); }
+
+ app * mk_pzero(unsigned ebits, unsigned sbits);
+ app * mk_nzero(unsigned ebits, unsigned sbits);
+ app * mk_pzero(sort * s) { return mk_pzero(get_ebits(s), get_sbits(s)); }
+ app * mk_nzero(sort * s) { return mk_nzero(get_ebits(s), get_sbits(s)); }
+
+ bool is_nan(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nan(v); }
+ bool is_pinf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pinf(v); }
+ bool is_ninf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_ninf(v); }
+ bool is_zero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_zero(v); }
+ bool is_pzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pzero(v); }
+ bool is_nzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nzero(v); }
+
+ app * mk_fp(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FPA_FP, arg1, arg2, arg3); }
+ app * mk_to_fp(sort * s, expr * bv_t) {
+ SASSERT(is_float(s) && s->get_num_parameters() == 2);
+ return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 1, &bv_t);
+ }
+ app * mk_to_fp(sort * s, expr * rm, expr * t) {
+ SASSERT(is_float(s) && s->get_num_parameters() == 2);
+ expr * args[] = { rm, t };
+ return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 2, args);
+ }
+ app * mk_to_fp(sort * s, expr * rm, expr * sig, expr * exp) {
+ SASSERT(is_float(s) && s->get_num_parameters() == 2);
+ expr * args[] = { rm, sig, exp };
+ return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 3, args);
+ }
+ app * mk_to_fp_unsigned(sort * s, expr * rm, expr * t) {
+ SASSERT(is_float(s) && s->get_num_parameters() == 2);
+ expr * args[] = { rm, t };
+ return m().mk_app(m_fid, OP_FPA_TO_FP_UNSIGNED, 2, s->get_parameters(), 2, args);
+ }
+
+ bool is_to_fp(expr * n) { return is_app_of(n, m_fid, OP_FPA_TO_FP); }
+
+ app * mk_to_ubv(expr * rm, expr * t, unsigned sz) {
+ parameter ps[] = { parameter(sz) };
+ expr * args[] = { rm, t };
+ return m().mk_app(m_fid, OP_FPA_TO_UBV, 1, ps, 2, args); }
+ app * mk_to_sbv(expr * rm, expr * t, unsigned sz) {
+ parameter ps[] = { parameter(sz) };
+ expr * args[] = { rm, t };
+ return m().mk_app(m_fid, OP_FPA_TO_SBV, 1, ps, 2, args);
+ }
+ app * mk_to_real(expr * t) { return m().mk_app(m_fid, OP_FPA_TO_REAL, t); }
+
+ app * mk_add(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FPA_ADD, arg1, arg2, arg3); }
+ app * mk_mul(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FPA_MUL, arg1, arg2, arg3); }
+ app * mk_sub(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FPA_SUB, arg1, arg2, arg3); }
+ app * mk_div(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FPA_DIV, arg1, arg2, arg3); }
+ app * mk_neg(expr * arg1) { return m().mk_app(m_fid, OP_FPA_NEG, arg1); }
+ app * mk_rem(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FPA_REM, arg1, arg2); }
+ app * mk_max(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FPA_MAX, arg1, arg2); }
+ app * mk_min(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FPA_MIN, arg1, arg2); }
+ app * mk_abs(expr * arg1) { return m().mk_app(m_fid, OP_FPA_ABS, arg1); }
+ app * mk_sqrt(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FPA_SQRT, arg1, arg2); }
+ app * mk_round_to_integral(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FPA_ROUND_TO_INTEGRAL, arg1, arg2); }
+ app * mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg4) {
+ expr * args[4] = { arg1, arg2, arg3, arg4 };
+ return m().mk_app(m_fid, OP_FPA_FMA, 4, args);
+ }
+
+ app * mk_float_eq(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FPA_EQ, arg1, arg2); }
+ app * mk_lt(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FPA_LT, arg1, arg2); }
+ app * mk_gt(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FPA_GT, arg1, arg2); }
+ app * mk_le(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FPA_LE, arg1, arg2); }
+ app * mk_ge(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FPA_GE, arg1, arg2); }
+
+ app * mk_is_nan(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NAN, arg1); }
+ app * mk_is_inf(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_INF, arg1); }
+ app * mk_is_zero(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_ZERO, arg1); }
+ app * mk_is_normal(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NORMAL, arg1); }
+ app * mk_is_subnormal(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_SUBNORMAL, arg1); }
+ app * mk_is_positive(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_POSITIVE, arg1); }
+ app * mk_is_negative(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NEGATIVE, arg1); }
+
+ bool is_neg(expr * a) { return is_app_of(a, m_fid, OP_FPA_NEG); }
+
+ app * mk_float_to_ieee_bv(expr * arg1) { return m().mk_app(m_fid, OP_FPA_TO_IEEE_BV, arg1); }
+
+ app * mk_internal_to_ubv_unspecified(unsigned width);
+ app * mk_internal_to_sbv_unspecified(unsigned width);
+ app * mk_internal_to_real_unspecified();
+
+ bool is_wrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); }
+ bool is_unwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVUNWRAP); }
+};
+
+#endif
diff --git a/src/ast/pp_params.pyg b/src/ast/pp_params.pyg
index 75b2baddd..7424b516f 100644
--- a/src/ast/pp_params.pyg
+++ b/src/ast/pp_params.pyg
@@ -10,6 +10,7 @@ def_module_params('pp',
('decimal', BOOL, False, 'pretty print real numbers using decimal notation (the output may be truncated). Z3 adds a ? if the value is not precise'),
('decimal_precision', UINT, 10, 'maximum number of decimal places to be used when pp.decimal=true'),
('bv_literals', BOOL, True, 'use Bit-Vector literals (e.g, #x0F and #b0101) during pretty printing'),
+ ('fp_real_literals', BOOL, False, 'use real-numbered floating point literals (e.g, +1.0p-1) during pretty printing'),
('bv_neg', BOOL, False, 'use bvneg when displaying Bit-Vector literals where the most significant bit is 1'),
('flat_assoc', BOOL, True, 'flat associative operators (when pretty printing SMT2 terms/formulas)'),
('fixed_indent', BOOL, False, 'use a fixed indentation for applications'),
diff --git a/src/ast/reg_decl_plugins.cpp b/src/ast/reg_decl_plugins.cpp
index ab1844e07..f46dd76d4 100644
--- a/src/ast/reg_decl_plugins.cpp
+++ b/src/ast/reg_decl_plugins.cpp
@@ -24,7 +24,7 @@ Revision History:
#include"datatype_decl_plugin.h"
#include"dl_decl_plugin.h"
#include"seq_decl_plugin.h"
-#include"float_decl_plugin.h"
+#include"fpa_decl_plugin.h"
void reg_decl_plugins(ast_manager & m) {
if (!m.get_plugin(m.mk_family_id(symbol("arith")))) {
@@ -45,7 +45,7 @@ void reg_decl_plugins(ast_manager & m) {
if (!m.get_plugin(m.mk_family_id(symbol("seq")))) {
m.register_plugin(symbol("seq"), alloc(seq_decl_plugin));
}
- if (!m.get_plugin(m.mk_family_id(symbol("float")))) {
- m.register_plugin(symbol("float"), alloc(float_decl_plugin));
+ if (!m.get_plugin(m.mk_family_id(symbol("fpa")))) {
+ m.register_plugin(symbol("fpa"), alloc(fpa_decl_plugin));
}
}
diff --git a/src/ast/rewriter/dl_rewriter.cpp b/src/ast/rewriter/dl_rewriter.cpp
index 9b79775d5..ddae6c9eb 100644
--- a/src/ast/rewriter/dl_rewriter.cpp
+++ b/src/ast/rewriter/dl_rewriter.cpp
@@ -24,31 +24,31 @@ Revision History:
ast_manager& m = result.get_manager();
uint64 v1, v2;
switch(f->get_decl_kind()) {
- case datalog::OP_DL_LT:
- if (m_util.is_numeral_ext(args[0], v1) &&
- m_util.is_numeral_ext(args[1], v2)) {
- result = (v1 < v2)?m.mk_true():m.mk_false();
- return BR_DONE;
- }
- // x < x <=> false
- if (args[0] == args[1]) {
- result = m.mk_false();
- return BR_DONE;
- }
- // x < 0 <=> false
- if (m_util.is_numeral_ext(args[1], v2) && v2 == 0) {
- result = m.mk_false();
- return BR_DONE;
- }
- // 0 < x <=> 0 != x
- if (m_util.is_numeral_ext(args[1], v1) && v1 == 0) {
- result = m.mk_not(m.mk_eq(args[0], args[1]));
- return BR_DONE;
- }
- break;
+ case datalog::OP_DL_LT:
+ if (m_util.is_numeral_ext(args[0], v1) &&
+ m_util.is_numeral_ext(args[1], v2)) {
+ result = (v1 < v2)?m.mk_true():m.mk_false();
+ return BR_DONE;
+ }
+ // x < x <=> false
+ if (args[0] == args[1]) {
+ result = m.mk_false();
+ return BR_DONE;
+ }
+ // x < 0 <=> false
+ if (m_util.is_numeral_ext(args[1], v2) && v2 == 0) {
+ result = m.mk_false();
+ return BR_DONE;
+ }
+ // 0 < x <=> 0 != x
+ if (m_util.is_numeral_ext(args[1], v1) && v1 == 0) {
+ result = m.mk_not(m.mk_eq(args[0], args[1]));
+ return BR_DONE;
+ }
+ break;
- default:
- break;
+ default:
+ break;
}
return BR_FAILED;
}
diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp
deleted file mode 100644
index 7dc34dd11..000000000
--- a/src/ast/rewriter/float_rewriter.cpp
+++ /dev/null
@@ -1,556 +0,0 @@
-/*++
-Copyright (c) 2012 Microsoft Corporation
-
-Module Name:
-
- float_rewriter.cpp
-
-Abstract:
-
- Basic rewriting rules for floating point numbers.
-
-Author:
-
- Leonardo (leonardo) 2012-02-02
-
-Notes:
-
---*/
-#include"float_rewriter.h"
-
-float_rewriter::float_rewriter(ast_manager & m, params_ref const & p):
- m_util(m) {
- updt_params(p);
-}
-
-float_rewriter::~float_rewriter() {
-}
-
-void float_rewriter::updt_params(params_ref const & p) {
-}
-
-void float_rewriter::get_param_descrs(param_descrs & r) {
-}
-
-br_status float_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
- br_status st = BR_FAILED;
- SASSERT(f->get_family_id() == get_fid());
- switch (f->get_decl_kind()) {
- case OP_TO_FLOAT: st = mk_to_fp(f, num_args, args, result); break;
- case OP_FLOAT_ADD: SASSERT(num_args == 3); st = mk_add(args[0], args[1], args[2], result); break;
- case OP_FLOAT_SUB: SASSERT(num_args == 3); st = mk_sub(args[0], args[1], args[2], result); break;
- case OP_FLOAT_NEG: SASSERT(num_args == 1); st = mk_neg(args[0], result); break;
- case OP_FLOAT_MUL: SASSERT(num_args == 3); st = mk_mul(args[0], args[1], args[2], result); break;
- case OP_FLOAT_DIV: SASSERT(num_args == 3); st = mk_div(args[0], args[1], args[2], result); break;
- case OP_FLOAT_REM: SASSERT(num_args == 2); st = mk_rem(args[0], args[1], result); break;
- case OP_FLOAT_ABS: SASSERT(num_args == 1); st = mk_abs(args[0], result); break;
- case OP_FLOAT_MIN: SASSERT(num_args == 2); st = mk_min(args[0], args[1], result); break;
- case OP_FLOAT_MAX: SASSERT(num_args == 2); st = mk_max(args[0], args[1], result); break;
- case OP_FLOAT_FMA: SASSERT(num_args == 4); st = mk_fma(args[0], args[1], args[2], args[3], result); break;
- case OP_FLOAT_SQRT: SASSERT(num_args == 2); st = mk_sqrt(args[0], args[1], result); break;
- case OP_FLOAT_ROUND_TO_INTEGRAL: SASSERT(num_args == 2); st = mk_round(args[0], args[1], result); break;
-
- case OP_FLOAT_EQ: SASSERT(num_args == 2); st = mk_float_eq(args[0], args[1], result); break;
- case OP_FLOAT_LT: SASSERT(num_args == 2); st = mk_lt(args[0], args[1], result); break;
- case OP_FLOAT_GT: SASSERT(num_args == 2); st = mk_gt(args[0], args[1], result); break;
- case OP_FLOAT_LE: SASSERT(num_args == 2); st = mk_le(args[0], args[1], result); break;
- case OP_FLOAT_GE: SASSERT(num_args == 2); st = mk_ge(args[0], args[1], result); break;
- case OP_FLOAT_IS_ZERO: SASSERT(num_args == 1); st = mk_is_zero(args[0], result); break;
- case OP_FLOAT_IS_NZERO: SASSERT(num_args == 1); st = mk_is_nzero(args[0], result); break;
- case OP_FLOAT_IS_PZERO: SASSERT(num_args == 1); st = mk_is_pzero(args[0], result); break;
- case OP_FLOAT_IS_NAN: SASSERT(num_args == 1); st = mk_is_nan(args[0], result); break;
- case OP_FLOAT_IS_INF: SASSERT(num_args == 1); st = mk_is_inf(args[0], result); break;
- case OP_FLOAT_IS_NORMAL: SASSERT(num_args == 1); st = mk_is_normal(args[0], result); break;
- case OP_FLOAT_IS_SUBNORMAL: SASSERT(num_args == 1); st = mk_is_subnormal(args[0], result); break;
- case OP_FLOAT_IS_NEGATIVE: SASSERT(num_args == 1); st = mk_is_negative(args[0], result); break;
- case OP_FLOAT_IS_POSITIVE: SASSERT(num_args == 1); st = mk_is_positive(args[0], result); break;
- case OP_FLOAT_TO_IEEE_BV: SASSERT(num_args == 1); st = mk_to_ieee_bv(args[0], result); break;
- case OP_FLOAT_FP: SASSERT(num_args == 3); st = mk_fp(args[0], args[1], args[2], result); break;
- case OP_FLOAT_TO_UBV: SASSERT(num_args == 2); st = mk_to_ubv(args[0], args[1], result); break;
- case OP_FLOAT_TO_SBV: SASSERT(num_args == 2); st = mk_to_sbv(args[0], args[1], result); break;
- case OP_FLOAT_TO_REAL: SASSERT(num_args == 1); st = mk_to_real(args[0], result); break;
- }
- return st;
-}
-
-br_status float_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
- SASSERT(f->get_num_parameters() == 2);
- SASSERT(f->get_parameter(0).is_int());
- SASSERT(f->get_parameter(1).is_int());
- unsigned ebits = f->get_parameter(0).get_int();
- unsigned sbits = f->get_parameter(1).get_int();
-
- if (num_args == 2) {
- mpf_rounding_mode rm;
- if (!m_util.is_rm_value(args[0], rm))
- return BR_FAILED;
-
- rational q;
- mpf q_mpf;
- if (m_util.au().is_numeral(args[1], q)) {
- TRACE("fp_rewriter", tout << "q: " << q << std::endl; );
- mpf v;
- m_util.fm().set(v, ebits, sbits, rm, q.to_mpq());
- result = m_util.mk_value(v);
- m_util.fm().del(v);
- // TRACE("fp_rewriter", tout << "result: " << result << std::endl; );
- return BR_DONE;
- }
- else if (m_util.is_value(args[1], q_mpf)) {
- TRACE("fp_rewriter", tout << "q: " << m_util.fm().to_string(q_mpf) << std::endl; );
- mpf v;
- m_util.fm().set(v, ebits, sbits, rm, q_mpf);
- result = m_util.mk_value(v);
- m_util.fm().del(v);
- // TRACE("fp_rewriter", tout << "result: " << result << std::endl; );
- return BR_DONE;
- }
- else
- return BR_FAILED;
- }
- else if (num_args == 3 &&
- m_util.is_rm(args[0]) &&
- m_util.au().is_real(args[1]) &&
- m_util.au().is_int(args[2])) {
-
- mpf_rounding_mode rm;
- if (!m_util.is_rm_value(args[0], rm))
- return BR_FAILED;
-
- rational q;
- if (!m_util.au().is_numeral(args[1], q))
- return BR_FAILED;
-
- rational e;
- if (!m_util.au().is_numeral(args[2], e))
- return BR_FAILED;
-
- TRACE("fp_rewriter", tout << "q: " << q << ", e: " << e << "\n";);
- mpf v;
- m_util.fm().set(v, ebits, sbits, rm, q.to_mpq(), e.to_mpq().numerator());
- result = m_util.mk_value(v);
- m_util.fm().del(v);
- return BR_DONE;
- }
- else {
- return BR_FAILED;
- }
-}
-
-br_status float_rewriter::mk_add(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
- mpf_rounding_mode rm;
- if (m_util.is_rm_value(arg1, rm)) {
- scoped_mpf v2(m_util.fm()), v3(m_util.fm());
- if (m_util.is_value(arg2, v2) && m_util.is_value(arg3, v3)) {
- scoped_mpf t(m_util.fm());
- m_util.fm().add(rm, v2, v3, t);
- result = m_util.mk_value(t);
- return BR_DONE;
- }
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_sub(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
- // a - b = a + (-b)
- result = m_util.mk_add(arg1, arg2, m_util.mk_neg(arg3));
- return BR_REWRITE2;
-}
-
-br_status float_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
- mpf_rounding_mode rm;
- if (m_util.is_rm_value(arg1, rm)) {
- scoped_mpf v2(m_util.fm()), v3(m_util.fm());
- if (m_util.is_value(arg2, v2) && m_util.is_value(arg3, v3)) {
- scoped_mpf t(m_util.fm());
- m_util.fm().mul(rm, v2, v3, t);
- result = m_util.mk_value(t);
- return BR_DONE;
- }
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
- mpf_rounding_mode rm;
- if (m_util.is_rm_value(arg1, rm)) {
- scoped_mpf v2(m_util.fm()), v3(m_util.fm());
- if (m_util.is_value(arg2, v2) && m_util.is_value(arg3, v3)) {
- scoped_mpf t(m_util.fm());
- m_util.fm().div(rm, v2, v3, t);
- result = m_util.mk_value(t);
- return BR_DONE;
- }
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_neg(expr * arg1, expr_ref & result) {
- if (m_util.is_nan(arg1)) {
- // -nan --> nan
- result = arg1;
- return BR_DONE;
- }
- if (m_util.is_plus_inf(arg1)) {
- // - +oo --> -oo
- result = m_util.mk_minus_inf(m().get_sort(arg1));
- return BR_DONE;
- }
- if (m_util.is_minus_inf(arg1)) {
- // - -oo -> +oo
- result = m_util.mk_plus_inf(m().get_sort(arg1));
- return BR_DONE;
- }
- if (m_util.is_neg(arg1)) {
- // - - a --> a
- result = to_app(arg1)->get_arg(0);
- return BR_DONE;
- }
-
- scoped_mpf v1(m_util.fm());
- if (m_util.is_value(arg1, v1)) {
- m_util.fm().neg(v1);
- result = m_util.mk_value(v1);
- return BR_DONE;
- }
-
- // TODO: more simplifications
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_rem(expr * arg1, expr * arg2, expr_ref & result) {
- scoped_mpf v1(m_util.fm()), v2(m_util.fm());
- if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) {
- scoped_mpf t(m_util.fm());
- m_util.fm().rem(v1, v2, t);
- result = m_util.mk_value(t);
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_abs(expr * arg1, expr_ref & result) {
- if (m_util.is_nan(arg1)) {
- result = arg1;
- return BR_DONE;
- }
- result = m().mk_ite(m_util.mk_is_sign_minus(arg1),
- m_util.mk_neg(arg1),
- arg1);
- return BR_REWRITE2;
-}
-
-br_status float_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) {
- if (m_util.is_nan(arg1)) {
- result = arg2;
- return BR_DONE;
- }
- if (m_util.is_nan(arg2)) {
- result = arg1;
- return BR_DONE;
- }
- // expand as using ite's
- result = m().mk_ite(m().mk_or(mk_eq_nan(arg1), m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2))),
- arg2,
- m().mk_ite(mk_eq_nan(arg2),
- arg1,
- m().mk_ite(m_util.mk_lt(arg1, arg2),
- arg1,
- arg2)));
- return BR_REWRITE_FULL;
-}
-
-br_status float_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) {
- if (m_util.is_nan(arg1)) {
- result = arg2;
- return BR_DONE;
- }
- if (m_util.is_nan(arg2)) {
- result = arg1;
- return BR_DONE;
- }
- // expand as using ite's
- result = m().mk_ite(m().mk_or(mk_eq_nan(arg1), m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2))),
- arg2,
- m().mk_ite(mk_eq_nan(arg2),
- arg1,
- m().mk_ite(m_util.mk_gt(arg1, arg2),
- arg1,
- arg2)));
- return BR_REWRITE_FULL;
-}
-
-br_status float_rewriter::mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result) {
- mpf_rounding_mode rm;
- if (m_util.is_rm_value(arg1, rm)) {
- scoped_mpf v2(m_util.fm()), v3(m_util.fm()), v4(m_util.fm());
- if (m_util.is_value(arg2, v2) && m_util.is_value(arg3, v3) && m_util.is_value(arg4, v4)) {
- scoped_mpf t(m_util.fm());
- m_util.fm().fused_mul_add(rm, v2, v3, v4, t);
- result = m_util.mk_value(t);
- return BR_DONE;
- }
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) {
- mpf_rounding_mode rm;
- if (m_util.is_rm_value(arg1, rm)) {
- scoped_mpf v2(m_util.fm());
- if (m_util.is_value(arg2, v2)) {
- scoped_mpf t(m_util.fm());
- m_util.fm().sqrt(rm, v2, t);
- result = m_util.mk_value(t);
- return BR_DONE;
- }
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_round(expr * arg1, expr * arg2, expr_ref & result) {
- mpf_rounding_mode rm;
- if (m_util.is_rm_value(arg1, rm)) {
- scoped_mpf v2(m_util.fm());
- if (m_util.is_value(arg2, v2)) {
- scoped_mpf t(m_util.fm());
- m_util.fm().round_to_integral(rm, v2, t);
- result = m_util.mk_value(t);
- return BR_DONE;
- }
- }
-
- return BR_FAILED;
-}
-
-// This the floating point theory ==
-br_status float_rewriter::mk_float_eq(expr * arg1, expr * arg2, expr_ref & result) {
- scoped_mpf v1(m_util.fm()), v2(m_util.fm());
- if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) {
- result = (m_util.fm().eq(v1, v2)) ? m().mk_true() : m().mk_false();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-// Return (= arg NaN)
-app * float_rewriter::mk_eq_nan(expr * arg) {
- return m().mk_eq(arg, m_util.mk_nan(m().get_sort(arg)));
-}
-
-// Return (not (= arg NaN))
-app * float_rewriter::mk_neq_nan(expr * arg) {
- return m().mk_not(mk_eq_nan(arg));
-}
-
-br_status float_rewriter::mk_lt(expr * arg1, expr * arg2, expr_ref & result) {
- if (m_util.is_nan(arg1) || m_util.is_nan(arg2)) {
- result = m().mk_false();
- return BR_DONE;
- }
- if (m_util.is_minus_inf(arg1)) {
- // -oo < arg2 --> not(arg2 = -oo) and not(arg2 = NaN)
- result = m().mk_and(m().mk_not(m().mk_eq(arg2, arg1)), mk_neq_nan(arg2));
- return BR_REWRITE3;
- }
- if (m_util.is_minus_inf(arg2)) {
- // arg1 < -oo --> false
- result = m().mk_false();
- return BR_DONE;
- }
- if (m_util.is_plus_inf(arg1)) {
- // +oo < arg2 --> false
- result = m().mk_false();
- return BR_DONE;
- }
- if (m_util.is_plus_inf(arg2)) {
- // arg1 < +oo --> not(arg1 = +oo) and not(arg1 = NaN)
- result = m().mk_and(m().mk_not(m().mk_eq(arg1, arg2)), mk_neq_nan(arg1));
- return BR_REWRITE3;
- }
-
- scoped_mpf v1(m_util.fm()), v2(m_util.fm());
- if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) {
- result = (m_util.fm().lt(v1, v2)) ? m().mk_true() : m().mk_false();
- return BR_DONE;
- }
-
- // TODO: more simplifications
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_gt(expr * arg1, expr * arg2, expr_ref & result) {
- result = m_util.mk_lt(arg2, arg1);
- return BR_REWRITE1;
-}
-
-br_status float_rewriter::mk_le(expr * arg1, expr * arg2, expr_ref & result) {
- if (m_util.is_nan(arg1) || m_util.is_nan(arg2)) {
- result = m().mk_false();
- return BR_DONE;
- }
- scoped_mpf v1(m_util.fm()), v2(m_util.fm());
- if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) {
- result = (m_util.fm().le(v1, v2)) ? m().mk_true() : m().mk_false();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_ge(expr * arg1, expr * arg2, expr_ref & result) {
- result = m_util.mk_le(arg2, arg1);
- return BR_REWRITE1;
-}
-
-br_status float_rewriter::mk_is_zero(expr * arg1, expr_ref & result) {
- scoped_mpf v(m_util.fm());
- if (m_util.is_value(arg1, v)) {
- result = (m_util.fm().is_zero(v)) ? m().mk_true() : m().mk_false();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_is_nzero(expr * arg1, expr_ref & result) {
- scoped_mpf v(m_util.fm());
- if (m_util.is_value(arg1, v)) {
- result = (m_util.fm().is_nzero(v)) ? m().mk_true() : m().mk_false();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) {
- scoped_mpf v(m_util.fm());
- if (m_util.is_value(arg1, v)) {
- result = (m_util.fm().is_pzero(v)) ? m().mk_true() : m().mk_false();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_is_nan(expr * arg1, expr_ref & result) {
- scoped_mpf v(m_util.fm());
- if (m_util.is_value(arg1, v)) {
- result = (m_util.fm().is_nan(v)) ? m().mk_true() : m().mk_false();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_is_inf(expr * arg1, expr_ref & result) {
- scoped_mpf v(m_util.fm());
- if (m_util.is_value(arg1, v)) {
- result = (m_util.fm().is_inf(v)) ? m().mk_true() : m().mk_false();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_is_normal(expr * arg1, expr_ref & result) {
- scoped_mpf v(m_util.fm());
- if (m_util.is_value(arg1, v)) {
- result = (m_util.fm().is_normal(v)) ? m().mk_true() : m().mk_false();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) {
- scoped_mpf v(m_util.fm());
- if (m_util.is_value(arg1, v)) {
- result = (m_util.fm().is_denormal(v)) ? m().mk_true() : m().mk_false();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_is_negative(expr * arg1, expr_ref & result) {
- scoped_mpf v(m_util.fm());
- if (m_util.is_value(arg1, v)) {
- result = (m_util.fm().is_neg(v)) ? m().mk_true() : m().mk_false();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_is_positive(expr * arg1, expr_ref & result) {
- scoped_mpf v(m_util.fm());
- if (m_util.is_value(arg1, v)) {
- result = (m_util.fm().is_neg(v) || m_util.fm().is_nan(v)) ? m().mk_false() : m().mk_true();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-
-// This the SMT =
-br_status float_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) {
- scoped_mpf v1(m_util.fm()), v2(m_util.fm());
- if (m_util.is_value(arg1, v1) && m_util.is_value(arg2, v2)) {
- // Note: == is the floats-equality, here we need normal equality.
- result = (m_fm.is_nan(v1) && m_fm.is_nan(v2)) ? m().mk_true() :
- (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1)!=m_fm.sgn(v2)) ? m().mk_false() :
- (v1 == v2) ? m().mk_true() :
- m().mk_false();
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_to_ieee_bv(expr * arg1, expr_ref & result) {
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_fp(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
- bv_util bu(m());
- rational r1, r2, r3;
- unsigned bvs1, bvs2, bvs3;
-
- if (bu.is_numeral(arg1, r1, bvs1) && bu.is_numeral(arg2, r2, bvs2) && bu.is_numeral(arg3, r3, bvs3)) {
- SASSERT(m_util.fm().mpz_manager().is_one(r2.to_mpq().denominator()));
- SASSERT(m_util.fm().mpz_manager().is_one(r3.to_mpq().denominator()));
- SASSERT(m_util.fm().mpz_manager().is_int64(r3.to_mpq().numerator()));
- scoped_mpf v(m_util.fm());
- mpf_exp_t biased_exp = m_util.fm().mpz_manager().get_int64(r2.to_mpq().numerator());
- m_util.fm().set(v, bvs2, bvs3 + 1,
- r1.is_one(),
- r3.to_mpq().numerator(),
- m_util.fm().unbias_exp(bvs2, biased_exp));
- TRACE("fp_rewriter", tout << "v = " << m_util.fm().to_string(v) << std::endl;);
- result = m_util.mk_value(v);
- return BR_DONE;
- }
-
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_to_ubv(expr * arg1, expr * arg2, expr_ref & result) {
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_to_sbv(expr * arg1, expr * arg2, expr_ref & result) {
- return BR_FAILED;
-}
-
-br_status float_rewriter::mk_to_real(expr * arg1, expr_ref & result) {
- return BR_FAILED;
-}
\ No newline at end of file
diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp
new file mode 100644
index 000000000..ce7fe5ed6
--- /dev/null
+++ b/src/ast/rewriter/fpa_rewriter.cpp
@@ -0,0 +1,598 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+ fpa_rewriter.cpp
+
+Abstract:
+
+ Basic rewriting rules for floating point numbers.
+
+Author:
+
+ Leonardo (leonardo) 2012-02-02
+
+Notes:
+
+--*/
+#include"fpa_rewriter.h"
+
+fpa_rewriter::fpa_rewriter(ast_manager & m, params_ref const & p):
+ m_util(m) {
+ updt_params(p);
+}
+
+fpa_rewriter::~fpa_rewriter() {
+}
+
+void fpa_rewriter::updt_params(params_ref const & p) {
+}
+
+void fpa_rewriter::get_param_descrs(param_descrs & r) {
+}
+
+br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
+ br_status st = BR_FAILED;
+ SASSERT(f->get_family_id() == get_fid());
+ switch (f->get_decl_kind()) {
+ case OP_FPA_TO_FP: st = mk_to_fp(f, num_args, args, result); break;
+ case OP_FPA_TO_FP_UNSIGNED: st = mk_to_fp_unsigned(f, num_args, args, result); break;
+ case OP_FPA_ADD: SASSERT(num_args == 3); st = mk_add(args[0], args[1], args[2], result); break;
+ case OP_FPA_SUB: SASSERT(num_args == 3); st = mk_sub(args[0], args[1], args[2], result); break;
+ case OP_FPA_NEG: SASSERT(num_args == 1); st = mk_neg(args[0], result); break;
+ case OP_FPA_MUL: SASSERT(num_args == 3); st = mk_mul(args[0], args[1], args[2], result); break;
+ case OP_FPA_DIV: SASSERT(num_args == 3); st = mk_div(args[0], args[1], args[2], result); break;
+ case OP_FPA_REM: SASSERT(num_args == 2); st = mk_rem(args[0], args[1], result); break;
+ case OP_FPA_ABS: SASSERT(num_args == 1); st = mk_abs(args[0], result); break;
+ case OP_FPA_MIN: SASSERT(num_args == 2); st = mk_min(args[0], args[1], result); break;
+ case OP_FPA_MAX: SASSERT(num_args == 2); st = mk_max(args[0], args[1], result); break;
+ case OP_FPA_FMA: SASSERT(num_args == 4); st = mk_fma(args[0], args[1], args[2], args[3], result); break;
+ case OP_FPA_SQRT: SASSERT(num_args == 2); st = mk_sqrt(args[0], args[1], result); break;
+ case OP_FPA_ROUND_TO_INTEGRAL: SASSERT(num_args == 2); st = mk_round(args[0], args[1], result); break;
+
+ case OP_FPA_EQ: SASSERT(num_args == 2); st = mk_float_eq(args[0], args[1], result); break;
+ case OP_FPA_LT: SASSERT(num_args == 2); st = mk_lt(args[0], args[1], result); break;
+ case OP_FPA_GT: SASSERT(num_args == 2); st = mk_gt(args[0], args[1], result); break;
+ case OP_FPA_LE: SASSERT(num_args == 2); st = mk_le(args[0], args[1], result); break;
+ case OP_FPA_GE: SASSERT(num_args == 2); st = mk_ge(args[0], args[1], result); break;
+ case OP_FPA_IS_ZERO: SASSERT(num_args == 1); st = mk_is_zero(args[0], result); break;
+ case OP_FPA_IS_NAN: SASSERT(num_args == 1); st = mk_is_nan(args[0], result); break;
+ case OP_FPA_IS_INF: SASSERT(num_args == 1); st = mk_is_inf(args[0], result); break;
+ case OP_FPA_IS_NORMAL: SASSERT(num_args == 1); st = mk_is_normal(args[0], result); break;
+ case OP_FPA_IS_SUBNORMAL: SASSERT(num_args == 1); st = mk_is_subnormal(args[0], result); break;
+ case OP_FPA_IS_NEGATIVE: SASSERT(num_args == 1); st = mk_is_negative(args[0], result); break;
+ case OP_FPA_IS_POSITIVE: SASSERT(num_args == 1); st = mk_is_positive(args[0], result); break;
+ case OP_FPA_FP: SASSERT(num_args == 3); st = mk_fp(args[0], args[1], args[2], result); break;
+ case OP_FPA_TO_UBV: SASSERT(num_args == 2); st = mk_to_ubv(args[0], args[1], result); break;
+ case OP_FPA_TO_SBV: SASSERT(num_args == 2); st = mk_to_sbv(args[0], args[1], result); break;
+ case OP_FPA_TO_REAL: SASSERT(num_args == 1); st = mk_to_real(args[0], result); break;
+ case OP_FPA_TO_IEEE_BV: SASSERT(num_args == 1); st = mk_to_ieee_bv(args[0], result); break;
+ }
+ return st;
+}
+
+br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
+ SASSERT(f->get_num_parameters() == 2);
+ SASSERT(f->get_parameter(0).is_int());
+ SASSERT(f->get_parameter(1).is_int());
+ unsigned ebits = f->get_parameter(0).get_int();
+ unsigned sbits = f->get_parameter(1).get_int();
+
+ if (num_args == 2) {
+ mpf_rounding_mode rm;
+ if (!m_util.is_rm_numeral(args[0], rm))
+ return BR_FAILED;
+
+ rational q;
+ scoped_mpf q_mpf(m_util.fm());
+ if (m_util.au().is_numeral(args[1], q)) {
+ TRACE("fp_rewriter", tout << "q: " << q << std::endl; );
+ scoped_mpf v(m_util.fm());
+ m_util.fm().set(v, ebits, sbits, rm, q.to_mpq());
+ result = m_util.mk_value(v);
+ m_util.fm().del(v);
+ // TRACE("fp_rewriter", tout << "result: " << result << std::endl; );
+ return BR_DONE;
+ }
+ else if (m_util.is_numeral(args[1], q_mpf)) {
+ TRACE("fp_rewriter", tout << "q: " << m_util.fm().to_string(q_mpf) << std::endl; );
+ scoped_mpf v(m_util.fm());
+ m_util.fm().set(v, ebits, sbits, rm, q_mpf);
+ result = m_util.mk_value(v);
+ m_util.fm().del(v);
+ // TRACE("fp_rewriter", tout << "result: " << result << std::endl; );
+ return BR_DONE;
+ }
+ else
+ return BR_FAILED;
+ }
+ else if (num_args == 3) {
+ bv_util bu(m());
+ rational r1, r2, r3;
+ unsigned bvs1, bvs2, bvs3;
+
+ if (m_util.is_rm(args[0]) &&
+ m_util.au().is_real(args[1]) &&
+ m_util.au().is_int(args[2])) {
+ mpf_rounding_mode rm;
+ if (!m_util.is_rm_numeral(args[0], rm))
+ return BR_FAILED;
+
+ rational q;
+ if (!m_util.au().is_numeral(args[1], q))
+ return BR_FAILED;
+
+ rational e;
+ if (!m_util.au().is_numeral(args[2], e))
+ return BR_FAILED;
+
+ TRACE("fp_rewriter", tout << "q: " << q << ", e: " << e << "\n";);
+ scoped_mpf v(m_util.fm());
+ m_util.fm().set(v, ebits, sbits, rm, q.to_mpq(), e.to_mpq().numerator());
+ result = m_util.mk_value(v);
+ m_util.fm().del(v);
+ return BR_DONE;
+ }
+ else if (bu.is_numeral(args[0], r1, bvs1) &&
+ bu.is_numeral(args[1], r2, bvs2) &&
+ bu.is_numeral(args[2], r3, bvs3)) {
+ SASSERT(m_util.fm().mpz_manager().is_one(r2.to_mpq().denominator()));
+ SASSERT(m_util.fm().mpz_manager().is_one(r3.to_mpq().denominator()));
+ SASSERT(m_util.fm().mpz_manager().is_int64(r3.to_mpq().numerator()));
+ scoped_mpf v(m_util.fm());
+ mpf_exp_t biased_exp = m_util.fm().mpz_manager().get_int64(r2.to_mpq().numerator());
+ m_util.fm().set(v, bvs2, bvs3 + 1,
+ r1.is_one(),
+ r3.to_mpq().numerator(),
+ m_util.fm().unbias_exp(bvs2, biased_exp));
+ TRACE("fp_rewriter", tout << "v = " << m_util.fm().to_string(v) << std::endl;);
+ result = m_util.mk_value(v);
+ return BR_DONE;
+ }
+ else
+ return BR_FAILED;
+ }
+ else
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_to_fp_unsigned(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
+ SASSERT(f->get_num_parameters() == 2);
+ SASSERT(f->get_parameter(0).is_int());
+ SASSERT(f->get_parameter(1).is_int());
+ unsigned ebits = f->get_parameter(0).get_int();
+ unsigned sbits = f->get_parameter(1).get_int();
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_add(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
+ mpf_rounding_mode rm;
+ if (m_util.is_rm_numeral(arg1, rm)) {
+ scoped_mpf v2(m_util.fm()), v3(m_util.fm());
+ if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3)) {
+ scoped_mpf t(m_util.fm());
+ m_util.fm().add(rm, v2, v3, t);
+ result = m_util.mk_value(t);
+ return BR_DONE;
+ }
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_sub(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
+ // a - b = a + (-b)
+ result = m_util.mk_add(arg1, arg2, m_util.mk_neg(arg3));
+ return BR_REWRITE2;
+}
+
+br_status fpa_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
+ mpf_rounding_mode rm;
+ if (m_util.is_rm_numeral(arg1, rm)) {
+ scoped_mpf v2(m_util.fm()), v3(m_util.fm());
+ if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3)) {
+ scoped_mpf t(m_util.fm());
+ m_util.fm().mul(rm, v2, v3, t);
+ result = m_util.mk_value(t);
+ return BR_DONE;
+ }
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
+ mpf_rounding_mode rm;
+ if (m_util.is_rm_numeral(arg1, rm)) {
+ scoped_mpf v2(m_util.fm()), v3(m_util.fm());
+ if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3)) {
+ scoped_mpf t(m_util.fm());
+ m_util.fm().div(rm, v2, v3, t);
+ result = m_util.mk_value(t);
+ return BR_DONE;
+ }
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_neg(expr * arg1, expr_ref & result) {
+ if (m_util.is_nan(arg1)) {
+ // -nan --> nan
+ result = arg1;
+ return BR_DONE;
+ }
+ if (m_util.is_pinf(arg1)) {
+ // - +oo --> -oo
+ result = m_util.mk_ninf(m().get_sort(arg1));
+ return BR_DONE;
+ }
+ if (m_util.is_ninf(arg1)) {
+ // - -oo -> +oo
+ result = m_util.mk_pinf(m().get_sort(arg1));
+ return BR_DONE;
+ }
+ if (m_util.is_neg(arg1)) {
+ // - - a --> a
+ result = to_app(arg1)->get_arg(0);
+ return BR_DONE;
+ }
+
+ scoped_mpf v1(m_util.fm());
+ if (m_util.is_numeral(arg1, v1)) {
+ m_util.fm().neg(v1);
+ result = m_util.mk_value(v1);
+ return BR_DONE;
+ }
+
+ // TODO: more simplifications
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_rem(expr * arg1, expr * arg2, expr_ref & result) {
+ scoped_mpf v1(m_util.fm()), v2(m_util.fm());
+ if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
+ scoped_mpf t(m_util.fm());
+ m_util.fm().rem(v1, v2, t);
+ result = m_util.mk_value(t);
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_abs(expr * arg1, expr_ref & result) {
+ if (m_util.is_nan(arg1)) {
+ result = arg1;
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) {
+ if (m_util.is_nan(arg1)) {
+ result = arg2;
+ return BR_DONE;
+ }
+ if (m_util.is_nan(arg2)) {
+ result = arg1;
+ return BR_DONE;
+ }
+ // expand as using ite's
+ result = m().mk_ite(m().mk_or(mk_eq_nan(arg1), m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2))),
+ arg2,
+ m().mk_ite(mk_eq_nan(arg2),
+ arg1,
+ m().mk_ite(m_util.mk_lt(arg1, arg2),
+ arg1,
+ arg2)));
+ return BR_REWRITE_FULL;
+}
+
+br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) {
+ if (m_util.is_nan(arg1)) {
+ result = arg2;
+ return BR_DONE;
+ }
+ if (m_util.is_nan(arg2)) {
+ result = arg1;
+ return BR_DONE;
+ }
+ // expand as using ite's
+ result = m().mk_ite(m().mk_or(mk_eq_nan(arg1), m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2))),
+ arg2,
+ m().mk_ite(mk_eq_nan(arg2),
+ arg1,
+ m().mk_ite(m_util.mk_gt(arg1, arg2),
+ arg1,
+ arg2)));
+ return BR_REWRITE_FULL;
+}
+
+br_status fpa_rewriter::mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result) {
+ mpf_rounding_mode rm;
+ if (m_util.is_rm_numeral(arg1, rm)) {
+ scoped_mpf v2(m_util.fm()), v3(m_util.fm()), v4(m_util.fm());
+ if (m_util.is_numeral(arg2, v2) && m_util.is_numeral(arg3, v3) && m_util.is_numeral(arg4, v4)) {
+ scoped_mpf t(m_util.fm());
+ m_util.fm().fused_mul_add(rm, v2, v3, v4, t);
+ result = m_util.mk_value(t);
+ return BR_DONE;
+ }
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) {
+ mpf_rounding_mode rm;
+ if (m_util.is_rm_numeral(arg1, rm)) {
+ scoped_mpf v2(m_util.fm());
+ if (m_util.is_numeral(arg2, v2)) {
+ scoped_mpf t(m_util.fm());
+ m_util.fm().sqrt(rm, v2, t);
+ result = m_util.mk_value(t);
+ return BR_DONE;
+ }
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_round(expr * arg1, expr * arg2, expr_ref & result) {
+ mpf_rounding_mode rm;
+ if (m_util.is_rm_numeral(arg1, rm)) {
+ scoped_mpf v2(m_util.fm());
+ if (m_util.is_numeral(arg2, v2)) {
+ scoped_mpf t(m_util.fm());
+ m_util.fm().round_to_integral(rm, v2, t);
+ result = m_util.mk_value(t);
+ return BR_DONE;
+ }
+ }
+
+ return BR_FAILED;
+}
+
+// This the floating point theory ==
+br_status fpa_rewriter::mk_float_eq(expr * arg1, expr * arg2, expr_ref & result) {
+ scoped_mpf v1(m_util.fm()), v2(m_util.fm());
+ if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
+ result = (m_util.fm().eq(v1, v2)) ? m().mk_true() : m().mk_false();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+// Return (= arg NaN)
+app * fpa_rewriter::mk_eq_nan(expr * arg) {
+ return m().mk_eq(arg, m_util.mk_nan(m().get_sort(arg)));
+}
+
+// Return (not (= arg NaN))
+app * fpa_rewriter::mk_neq_nan(expr * arg) {
+ return m().mk_not(mk_eq_nan(arg));
+}
+
+br_status fpa_rewriter::mk_lt(expr * arg1, expr * arg2, expr_ref & result) {
+ if (m_util.is_nan(arg1) || m_util.is_nan(arg2)) {
+ result = m().mk_false();
+ return BR_DONE;
+ }
+ if (m_util.is_ninf(arg1)) {
+ // -oo < arg2 --> not(arg2 = -oo) and not(arg2 = NaN)
+ result = m().mk_and(m().mk_not(m().mk_eq(arg2, arg1)), mk_neq_nan(arg2));
+ return BR_REWRITE3;
+ }
+ if (m_util.is_ninf(arg2)) {
+ // arg1 < -oo --> false
+ result = m().mk_false();
+ return BR_DONE;
+ }
+ if (m_util.is_pinf(arg1)) {
+ // +oo < arg2 --> false
+ result = m().mk_false();
+ return BR_DONE;
+ }
+ if (m_util.is_pinf(arg2)) {
+ // arg1 < +oo --> not(arg1 = +oo) and not(arg1 = NaN)
+ result = m().mk_and(m().mk_not(m().mk_eq(arg1, arg2)), mk_neq_nan(arg1));
+ return BR_REWRITE3;
+ }
+
+ scoped_mpf v1(m_util.fm()), v2(m_util.fm());
+ if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
+ result = (m_util.fm().lt(v1, v2)) ? m().mk_true() : m().mk_false();
+ return BR_DONE;
+ }
+
+ // TODO: more simplifications
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_gt(expr * arg1, expr * arg2, expr_ref & result) {
+ result = m_util.mk_lt(arg2, arg1);
+ return BR_REWRITE1;
+}
+
+br_status fpa_rewriter::mk_le(expr * arg1, expr * arg2, expr_ref & result) {
+ if (m_util.is_nan(arg1) || m_util.is_nan(arg2)) {
+ result = m().mk_false();
+ return BR_DONE;
+ }
+ scoped_mpf v1(m_util.fm()), v2(m_util.fm());
+ if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
+ result = (m_util.fm().le(v1, v2)) ? m().mk_true() : m().mk_false();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_ge(expr * arg1, expr * arg2, expr_ref & result) {
+ result = m_util.mk_le(arg2, arg1);
+ return BR_REWRITE1;
+}
+
+br_status fpa_rewriter::mk_is_zero(expr * arg1, expr_ref & result) {
+ scoped_mpf v(m_util.fm());
+ if (m_util.is_numeral(arg1, v)) {
+ result = (m_util.fm().is_zero(v)) ? m().mk_true() : m().mk_false();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_is_nzero(expr * arg1, expr_ref & result) {
+ scoped_mpf v(m_util.fm());
+ if (m_util.is_numeral(arg1, v)) {
+ result = (m_util.fm().is_nzero(v)) ? m().mk_true() : m().mk_false();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) {
+ scoped_mpf v(m_util.fm());
+ if (m_util.is_numeral(arg1, v)) {
+ result = (m_util.fm().is_pzero(v)) ? m().mk_true() : m().mk_false();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_is_nan(expr * arg1, expr_ref & result) {
+ scoped_mpf v(m_util.fm());
+ if (m_util.is_numeral(arg1, v)) {
+ result = (m_util.fm().is_nan(v)) ? m().mk_true() : m().mk_false();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_is_inf(expr * arg1, expr_ref & result) {
+ scoped_mpf v(m_util.fm());
+ if (m_util.is_numeral(arg1, v)) {
+ result = (m_util.fm().is_inf(v)) ? m().mk_true() : m().mk_false();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_is_normal(expr * arg1, expr_ref & result) {
+ scoped_mpf v(m_util.fm());
+ if (m_util.is_numeral(arg1, v)) {
+ result = (m_util.fm().is_normal(v)) ? m().mk_true() : m().mk_false();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) {
+ scoped_mpf v(m_util.fm());
+ if (m_util.is_numeral(arg1, v)) {
+ result = (m_util.fm().is_denormal(v)) ? m().mk_true() : m().mk_false();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_is_negative(expr * arg1, expr_ref & result) {
+ scoped_mpf v(m_util.fm());
+ if (m_util.is_numeral(arg1, v)) {
+ result = (m_util.fm().is_neg(v)) ? m().mk_true() : m().mk_false();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_is_positive(expr * arg1, expr_ref & result) {
+ scoped_mpf v(m_util.fm());
+ if (m_util.is_numeral(arg1, v)) {
+ result = (m_util.fm().is_neg(v) || m_util.fm().is_nan(v)) ? m().mk_false() : m().mk_true();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+
+// This the SMT =
+br_status fpa_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) {
+ scoped_mpf v1(m_util.fm()), v2(m_util.fm());
+ if (m_util.is_numeral(arg1, v1) && m_util.is_numeral(arg2, v2)) {
+ // Note: == is the floats-equality, here we need normal equality.
+ result = (m_fm.is_nan(v1) && m_fm.is_nan(v2)) ? m().mk_true() :
+ (m_fm.is_zero(v1) && m_fm.is_zero(v2) && m_fm.sgn(v1)!=m_fm.sgn(v2)) ? m().mk_false() :
+ (v1 == v2) ? m().mk_true() :
+ m().mk_false();
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_to_ieee_bv(expr * arg1, expr_ref & result) {
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_fp(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
+ bv_util bu(m());
+ rational r1, r2, r3;
+ unsigned bvs1, bvs2, bvs3;
+
+ if (bu.is_numeral(arg1, r1, bvs1) && bu.is_numeral(arg2, r2, bvs2) && bu.is_numeral(arg3, r3, bvs3)) {
+ SASSERT(m_util.fm().mpz_manager().is_one(r2.to_mpq().denominator()));
+ SASSERT(m_util.fm().mpz_manager().is_one(r3.to_mpq().denominator()));
+ SASSERT(m_util.fm().mpz_manager().is_int64(r3.to_mpq().numerator()));
+ scoped_mpf v(m_util.fm());
+ mpf_exp_t biased_exp = m_util.fm().mpz_manager().get_int64(r2.to_mpq().numerator());
+ m_util.fm().set(v, bvs2, bvs3 + 1,
+ r1.is_one(),
+ r3.to_mpq().numerator(),
+ m_util.fm().unbias_exp(bvs2, biased_exp));
+ TRACE("fp_rewriter", tout << "simplified (fp ...) to " << m_util.fm().to_string(v) << std::endl;);
+ result = m_util.mk_value(v);
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_to_ubv(expr * arg1, expr * arg2, expr_ref & result) {
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_to_sbv(expr * arg1, expr * arg2, expr_ref & result) {
+ return BR_FAILED;
+}
+
+br_status fpa_rewriter::mk_to_real(expr * arg1, expr_ref & result) {
+ scoped_mpf fv(m_util.fm());
+
+ if (m_util.is_numeral(arg1, fv)) {
+ if (m_fm.is_nan(fv) || m_fm.is_inf(fv)) {
+ result = m_util.mk_internal_to_real_unspecified();
+ }
+ else {
+ scoped_mpq r(m_fm.mpq_manager());
+ m_fm.to_rational(fv, r);
+ result = m_util.au().mk_numeral(r.get(), false);
+ }
+ return BR_DONE;
+ }
+
+ return BR_FAILED;
+}
diff --git a/src/ast/rewriter/float_rewriter.h b/src/ast/rewriter/fpa_rewriter.h
similarity index 91%
rename from src/ast/rewriter/float_rewriter.h
rename to src/ast/rewriter/fpa_rewriter.h
index 4d8cec856..a10df95ca 100644
--- a/src/ast/rewriter/float_rewriter.h
+++ b/src/ast/rewriter/fpa_rewriter.h
@@ -22,19 +22,19 @@ Notes:
#include"ast.h"
#include"rewriter.h"
#include"params.h"
-#include"float_decl_plugin.h"
+#include"fpa_decl_plugin.h"
#include"mpf.h"
-class float_rewriter {
- float_util m_util;
+class fpa_rewriter {
+ fpa_util m_util;
mpf_manager m_fm;
app * mk_eq_nan(expr * arg);
app * mk_neq_nan(expr * arg);
public:
- float_rewriter(ast_manager & m, params_ref const & p = params_ref());
- ~float_rewriter();
+ fpa_rewriter(ast_manager & m, params_ref const & p = params_ref());
+ ~fpa_rewriter();
ast_manager & m() const { return m_util.m(); }
family_id get_fid() const { return m_util.get_fid(); }
@@ -75,6 +75,7 @@ public:
br_status mk_to_ieee_bv(expr * arg1, expr_ref & result);
br_status mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
+ br_status mk_to_fp_unsigned(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_fp(expr * arg1, expr * arg2, expr * arg3, expr_ref & result);
br_status mk_to_fp_unsigned(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_to_ubv(expr * arg1, expr * arg2, expr_ref & result);
diff --git a/src/ast/rewriter/mk_simplified_app.cpp b/src/ast/rewriter/mk_simplified_app.cpp
index a46e71582..45245ce1b 100644
--- a/src/ast/rewriter/mk_simplified_app.cpp
+++ b/src/ast/rewriter/mk_simplified_app.cpp
@@ -22,7 +22,7 @@ Notes:
#include"bv_rewriter.h"
#include"datatype_rewriter.h"
#include"array_rewriter.h"
-#include"float_rewriter.h"
+#include"fpa_rewriter.h"
struct mk_simplified_app::imp {
ast_manager & m;
@@ -31,7 +31,7 @@ struct mk_simplified_app::imp {
bv_rewriter m_bv_rw;
array_rewriter m_ar_rw;
datatype_rewriter m_dt_rw;
- float_rewriter m_f_rw;
+ fpa_rewriter m_f_rw;
imp(ast_manager & _m, params_ref const & p):
m(_m),
diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp
index 0e2c8e781..f35c3b134 100644
--- a/src/ast/rewriter/th_rewriter.cpp
+++ b/src/ast/rewriter/th_rewriter.cpp
@@ -23,7 +23,7 @@ Notes:
#include"bv_rewriter.h"
#include"datatype_rewriter.h"
#include"array_rewriter.h"
-#include"float_rewriter.h"
+#include"fpa_rewriter.h"
#include"dl_rewriter.h"
#include"rewriter_def.h"
#include"expr_substitution.h"
@@ -39,7 +39,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
bv_rewriter m_bv_rw;
array_rewriter m_ar_rw;
datatype_rewriter m_dt_rw;
- float_rewriter m_f_rw;
+ fpa_rewriter m_f_rw;
dl_rewriter m_dl_rw;
arith_util m_a_util;
bv_util m_bv_util;
diff --git a/src/ast/simplifier/distribute_forall.cpp b/src/ast/simplifier/distribute_forall.cpp
index 5e2958579..bd2af5675 100644
--- a/src/ast/simplifier/distribute_forall.cpp
+++ b/src/ast/simplifier/distribute_forall.cpp
@@ -148,7 +148,7 @@ void distribute_forall::operator()(expr * f, expr_ref & result) {
while (!m_todo.empty()) {
expr * e = m_todo.back();
- if (visit_children(e)) {
+ if (visit_children(e)) {
m_todo.pop_back();
reduce1(e);
}
diff --git a/src/ast/simplifier/fpa_simplifier_plugin.cpp b/src/ast/simplifier/fpa_simplifier_plugin.cpp
new file mode 100644
index 000000000..d2f7a3e58
--- /dev/null
+++ b/src/ast/simplifier/fpa_simplifier_plugin.cpp
@@ -0,0 +1,43 @@
+/*++
+Copyright (c) 2015 Microsoft Corporation
+
+Module Name:
+
+ fpa_simplifier_plugin.cpp
+
+Abstract:
+
+ Simplifier for the floating-point theory
+
+Author:
+
+ Christoph (cwinter) 2015-01-14
+
+--*/
+#include"fpa_simplifier_plugin.h"
+
+fpa_simplifier_plugin::fpa_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b) :
+simplifier_plugin(symbol("fpa"), m),
+m_util(m),
+m_bsimp(b),
+m_rw(m) {}
+
+fpa_simplifier_plugin::~fpa_simplifier_plugin() {}
+
+bool fpa_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
+ set_reduce_invoked();
+
+ SASSERT(f->get_family_id() == get_family_id());
+ /*switch (f->get_decl_kind()) {
+ case OP_FPA_FP: break;
+ }*/
+
+ return m_rw.mk_app_core(f, num_args, args, result) == BR_DONE;
+}
+
+bool fpa_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) {
+ set_reduce_invoked();
+
+ return m_rw.mk_eq_core(lhs, rhs, result) == BR_DONE;
+}
+
diff --git a/src/ast/simplifier/fpa_simplifier_plugin.h b/src/ast/simplifier/fpa_simplifier_plugin.h
new file mode 100644
index 000000000..36e315737
--- /dev/null
+++ b/src/ast/simplifier/fpa_simplifier_plugin.h
@@ -0,0 +1,40 @@
+/*++
+Copyright (c) 2015 Microsoft Corporation
+
+Module Name:
+
+ fpa_simplifier_plugin.h
+
+Abstract:
+
+ Simplifier for the floating-point theory
+
+Author:
+
+ Christoph (cwinter) 2015-01-14
+
+--*/
+#ifndef _FPA_SIMPLIFIER_PLUGIN_H_
+#define _FPA_SIMPLIFIER_PLUGIN_H_
+
+#include"basic_simplifier_plugin.h"
+#include"fpa_decl_plugin.h"
+#include"fpa_rewriter.h"
+
+class fpa_simplifier_plugin : public simplifier_plugin {
+ fpa_util m_util;
+ basic_simplifier_plugin & m_bsimp;
+ fpa_rewriter m_rw;
+
+public:
+ fpa_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b);
+ ~fpa_simplifier_plugin();
+
+
+ virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
+
+ virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result);
+
+};
+
+#endif /* _FPA_SIMPLIFIER_PLUGIN_H_ */
diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp
index a80c5bc6c..94bd4f5e1 100644
--- a/src/cmd_context/basic_cmds.cpp
+++ b/src/cmd_context/basic_cmds.cpp
@@ -255,7 +255,7 @@ protected:
s == m_print_success || s == m_print_warning || s == m_expand_definitions ||
s == m_interactive_mode || s == m_produce_proofs || s == m_produce_unsat_cores ||
s == m_produce_models || s == m_produce_assignments || s == m_produce_interpolants ||
- s == m_regular_output_channel || s == m_diagnostic_output_channel ||
+ s == m_regular_output_channel || s == m_diagnostic_output_channel ||
s == m_random_seed || s == m_verbosity || s == m_global_decls;
}
diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp
index ee5437bd6..f5937955d 100644
--- a/src/cmd_context/cmd_context.cpp
+++ b/src/cmd_context/cmd_context.cpp
@@ -24,7 +24,7 @@ Notes:
#include"array_decl_plugin.h"
#include"datatype_decl_plugin.h"
#include"seq_decl_plugin.h"
-#include"float_decl_plugin.h"
+#include"fpa_decl_plugin.h"
#include"ast_pp.h"
#include"var_subst.h"
#include"pp.h"
@@ -240,7 +240,7 @@ protected:
arith_util m_autil;
bv_util m_bvutil;
array_util m_arutil;
- float_util m_futil;
+ fpa_util m_futil;
datalog::dl_decl_util m_dlutil;
format_ns::format * pp_fdecl_name(symbol const & s, func_decls const & fs, func_decl * f, unsigned & len) {
@@ -267,7 +267,7 @@ public:
virtual arith_util & get_autil() { return m_autil; }
virtual bv_util & get_bvutil() { return m_bvutil; }
virtual array_util & get_arutil() { return m_arutil; }
- virtual float_util & get_futil() { return m_futil; }
+ virtual fpa_util & get_futil() { return m_futil; }
virtual datalog::dl_decl_util& get_dlutil() { return m_dlutil; }
virtual bool uses(symbol const & s) const {
return
@@ -512,8 +512,8 @@ bool cmd_context::logic_has_arith_core(symbol const & s) const {
s == "UFNIA" ||
s == "LIA" ||
s == "LRA" ||
- s == "QF_FPA" ||
- s == "QF_FPABV" ||
+ s == "QF_FP" ||
+ s == "QF_FPBV" ||
s == "HORN";
}
@@ -532,7 +532,7 @@ bool cmd_context::logic_has_bv_core(symbol const & s) const {
s == "QF_ABV" ||
s == "QF_AUFBV" ||
s == "QF_BVRE" ||
- s == "QF_FPABV" ||
+ s == "QF_FPBV" ||
s == "HORN";
}
@@ -556,8 +556,8 @@ bool cmd_context::logic_has_seq() const {
return !has_logic() || logic_has_seq_core(m_logic);
}
-bool cmd_context::logic_has_floats() const {
- return !has_logic() || m_logic == "QF_FPA" || m_logic == "QF_FPABV";
+bool cmd_context::logic_has_fpa() const {
+ return !has_logic() || m_logic == "QF_FP" || m_logic == "QF_FPBV";
}
bool cmd_context::logic_has_array_core(symbol const & s) const {
@@ -601,7 +601,7 @@ void cmd_context::init_manager_core(bool new_manager) {
register_plugin(symbol("array"), alloc(array_decl_plugin), logic_has_array());
register_plugin(symbol("datatype"), alloc(datatype_decl_plugin), logic_has_datatype());
register_plugin(symbol("seq"), alloc(seq_decl_plugin), logic_has_seq());
- register_plugin(symbol("float"), alloc(float_decl_plugin), logic_has_floats());
+ register_plugin(symbol("fpa"), alloc(fpa_decl_plugin), logic_has_fpa());
}
else {
// the manager was created by an external module
@@ -614,7 +614,7 @@ void cmd_context::init_manager_core(bool new_manager) {
load_plugin(symbol("array"), logic_has_array(), fids);
load_plugin(symbol("datatype"), logic_has_datatype(), fids);
load_plugin(symbol("seq"), logic_has_seq(), fids);
- load_plugin(symbol("float"), logic_has_floats(), fids);
+ load_plugin(symbol("fpa"), logic_has_fpa(), fids);
svector::iterator it = fids.begin();
svector::iterator end = fids.end();
@@ -668,7 +668,7 @@ bool cmd_context::supported_logic(symbol const & s) const {
logic_has_arith_core(s) || logic_has_bv_core(s) ||
logic_has_array_core(s) || logic_has_seq_core(s) ||
logic_has_horn(s) ||
- s == "QF_FPA" || s == "QF_FPABV";
+ s == "QF_FP" || s == "QF_FPBV";
}
bool cmd_context::set_logic(symbol const & s) {
diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h
index 1c8dba21a..f9e50e611 100644
--- a/src/cmd_context/cmd_context.h
+++ b/src/cmd_context/cmd_context.h
@@ -241,7 +241,7 @@ protected:
bool logic_has_seq() const;
bool logic_has_array() const;
bool logic_has_datatype() const;
- bool logic_has_floats() const;
+ bool logic_has_fpa() const;
bool supported_logic(symbol const & s) const;
void print_unsupported_msg() { regular_stream() << "unsupported" << std::endl; }
diff --git a/src/duality/duality_profiling.cpp b/src/duality/duality_profiling.cpp
index 5bcda972a..13a379946 100755
--- a/src/duality/duality_profiling.cpp
+++ b/src/duality/duality_profiling.cpp
@@ -124,20 +124,20 @@ namespace Duality {
}
void timer_stop(const char *name){
- if(current->name != name || !current->parent){
+ if (current->name != name || !current->parent) {
#if 0
- std::cerr << "imbalanced timer_start and timer_stop";
- exit(1);
+ std::cerr << "imbalanced timer_start and timer_stop";
+ exit(1);
#endif
- // in case we lost a timer stop due to an exception
- while(current->name != name && current->parent)
- current = current->parent;
- if(current->parent){
- current->time += (current_time() - current->start_time);
- current = current->parent;
+ // in case we lost a timer stop due to an exception
+ while (current->name != name && current->parent)
+ current = current->parent;
+ if (current->parent) {
+ current->time += (current_time() - current->start_time);
+ current = current->parent;
+ }
+ return;
}
- return;
- }
current->time += (current_time() - current->start_time);
current = current->parent;
}
diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp
index 304e41168..e2a5d05dc 100755
--- a/src/duality/duality_rpfp.cpp
+++ b/src/duality/duality_rpfp.cpp
@@ -97,12 +97,12 @@ namespace Duality {
memo.insert(t);
if(t.is_app()){
decl_kind k = t.decl().get_decl_kind();
- if(k == And || k == Or || k == Not || k == Implies || k == Iff){
- ops++;
- int nargs = t.num_args();
- for(int i = 0; i < nargs; i++)
- SummarizeRec(memo,lits,ops,t.arg(i));
- return;
+ if (k == And || k == Or || k == Not || k == Implies || k == Iff) {
+ ops++;
+ int nargs = t.num_args();
+ for (int i = 0; i < nargs; i++)
+ SummarizeRec(memo, lits, ops, t.arg(i));
+ return;
}
}
lits.push_back(t);
@@ -137,12 +137,12 @@ namespace Duality {
memo.insert(t);
if(t.is_app()){
decl_kind k = t.decl().get_decl_kind();
- if(k == And || k == Or){
- int count = 1;
- int nargs = t.num_args();
- for(int i = 0; i < nargs; i++)
- count += CountOperatorsRec(memo,t.arg(i));
- return count;
+ if (k == And || k == Or) {
+ int count = 1;
+ int nargs = t.num_args();
+ for (int i = 0; i < nargs; i++)
+ count += CountOperatorsRec(memo, t.arg(i));
+ return count;
}
return 0;
}
@@ -172,13 +172,12 @@ namespace Duality {
Term b(ctx);
std::vector v;
RedVars(child, b, v);
- for (unsigned i = 0; i < args.size(); i++)
- {
- if (eq(args[i].get_sort(),ctx.bool_sort()))
- args[i] = ctx.make(Iff,args[i], v[i]);
- else
- args[i] = args[i] == v[i];
- }
+ for (unsigned i = 0; i < args.size(); i++) {
+ if (eq(args[i].get_sort(), ctx.bool_sort()))
+ args[i] = ctx.make(Iff, args[i], v[i]);
+ else
+ args[i] = args[i] == v[i];
+ }
return args.size() > 0 ? (b && conjoin(args)) : b;
}
@@ -202,18 +201,18 @@ namespace Duality {
names.push_back(Z3_get_quantifier_bound_name(c,a,i));
}
Z3_ast foo = Z3_mk_quantifier_ex(c,
- Z3_is_quantifier_forall(c,a),
- Z3_get_quantifier_weight(c,a),
- 0,
- 0,
- num_pats,
- &pats[0],
- num_no_pats,
- &no_pats[0],
- bound,
- &sorts[0],
- &names[0],
- new_body);
+ Z3_is_quantifier_forall(c,a),
+ Z3_get_quantifier_weight(c,a),
+ 0,
+ 0,
+ num_pats,
+ &pats[0],
+ num_no_pats,
+ &no_pats[0],
+ bound,
+ &sorts[0],
+ &names[0],
+ new_body);
return expr(ctx,foo);
#endif
return clone_quantifier(t,new_body);
@@ -231,36 +230,32 @@ namespace Duality {
res = it->second;
return res;
}
- if (t.is_app())
- {
- func_decl f = t.decl();
- std::vector args;
- int nargs = t.num_args();
- for(int i = 0; i < nargs; i++)
- args.push_back(LocalizeRec(e, memo, t.arg(i)));
- hash_map::iterator rit = e->relMap.find(f);
- if(rit != e->relMap.end())
- res = RedDualRela(e,args,(rit->second));
- else {
- if (args.size() == 0 && f.get_decl_kind() == Uninterpreted && !ls->is_constant(f))
- {
- res = HideVariable(t,e->number);
- }
- else
- {
- res = f(args.size(),&args[0]);
- }
- }
- }
- else if (t.is_quantifier())
- {
- std::vector pats;
- t.get_patterns(pats);
- for(unsigned i = 0; i < pats.size(); i++)
- pats[i] = LocalizeRec(e,memo,pats[i]);
- Term body = LocalizeRec(e,memo,t.body());
- res = clone_quantifier(t, body, pats);
- }
+ if (t.is_app()) {
+ func_decl f = t.decl();
+ std::vector args;
+ int nargs = t.num_args();
+ for (int i = 0; i < nargs; i++)
+ args.push_back(LocalizeRec(e, memo, t.arg(i)));
+ hash_map::iterator rit = e->relMap.find(f);
+ if (rit != e->relMap.end())
+ res = RedDualRela(e, args, (rit->second));
+ else {
+ if (args.size() == 0 && f.get_decl_kind() == Uninterpreted && !ls->is_constant(f)) {
+ res = HideVariable(t, e->number);
+ }
+ else {
+ res = f(args.size(), &args[0]);
+ }
+ }
+ }
+ else if (t.is_quantifier()) {
+ std::vector pats;
+ t.get_patterns(pats);
+ for (unsigned i = 0; i < pats.size(); i++)
+ pats[i] = LocalizeRec(e, memo, pats[i]);
+ Term body = LocalizeRec(e, memo, t.body());
+ res = clone_quantifier(t, body, pats);
+ }
else res = t;
return res;
}
@@ -353,24 +348,22 @@ namespace Duality {
std::pair::iterator, bool> bar = memo.insert(foo);
Term &res = bar.first->second;
if(!bar.second) return res;
- if (t.is_app())
- {
- func_decl f = t.decl();
- std::vector args;
- int nargs = t.num_args();
- for(int i = 0; i < nargs; i++)
- args.push_back(SubstRec(memo, t.arg(i)));
- res = f(args.size(),&args[0]);
- }
- else if (t.is_quantifier())
- {
- std::vector pats;
- t.get_patterns(pats);
- for(unsigned i = 0; i < pats.size(); i++)
- pats[i] = SubstRec(memo,pats[i]);
- Term body = SubstRec(memo,t.body());
- res = clone_quantifier(t, body, pats);
- }
+ if (t.is_app()) {
+ func_decl f = t.decl();
+ std::vector args;
+ int nargs = t.num_args();
+ for (int i = 0; i < nargs; i++)
+ args.push_back(SubstRec(memo, t.arg(i)));
+ res = f(args.size(), &args[0]);
+ }
+ else if (t.is_quantifier()) {
+ std::vector pats;
+ t.get_patterns(pats);
+ for (unsigned i = 0; i < pats.size(); i++)
+ pats[i] = SubstRec(memo, pats[i]);
+ Term body = SubstRec(memo, t.body());
+ res = clone_quantifier(t, body, pats);
+ }
// res = CloneQuantifier(t,SubstRec(memo, t.body()));
else res = t;
return res;
@@ -382,27 +375,25 @@ namespace Duality {
std::pair::iterator, bool> bar = memo.insert(foo);
Term &res = bar.first->second;
if(!bar.second) return res;
- if (t.is_app())
- {
- func_decl f = t.decl();
- std::vector args;
- int nargs = t.num_args();
- for(int i = 0; i < nargs; i++)
- args.push_back(SubstRec(memo, map, t.arg(i)));
- hash_map::iterator it = map.find(f);
- if(it != map.end())
- f = it->second;
- res = f(args.size(),&args[0]);
- }
- else if (t.is_quantifier())
- {
- std::vector pats;
- t.get_patterns(pats);
- for(unsigned i = 0; i < pats.size(); i++)
- pats[i] = SubstRec(memo, map, pats[i]);
- Term body = SubstRec(memo, map, t.body());
- res = clone_quantifier(t, body, pats);
- }
+ if (t.is_app()) {
+ func_decl f = t.decl();
+ std::vector args;
+ int nargs = t.num_args();
+ for (int i = 0; i < nargs; i++)
+ args.push_back(SubstRec(memo, map, t.arg(i)));
+ hash_map::iterator it = map.find(f);
+ if (it != map.end())
+ f = it->second;
+ res = f(args.size(), &args[0]);
+ }
+ else if (t.is_quantifier()) {
+ std::vector pats;
+ t.get_patterns(pats);
+ for (unsigned i = 0; i < pats.size(); i++)
+ pats[i] = SubstRec(memo, map, pats[i]);
+ Term body = SubstRec(memo, map, t.body());
+ res = clone_quantifier(t, body, pats);
+ }
// res = CloneQuantifier(t,SubstRec(memo, t.body()));
else res = t;
return res;
@@ -415,20 +406,20 @@ namespace Duality {
Term &res = bar.first->second;
if(!bar.second) return res;
if (t.is_app()) {
- func_decl f = t.decl();
- std::vector args;
- int nargs = t.num_args();
- for(int i = 0; i < nargs; i++)
- args.push_back(ExtractStores(memo, t.arg(i),cnstrs,renaming));
- res = f(args.size(),&args[0]);
- if(f.get_decl_kind() == Store){
- func_decl fresh = ctx.fresh_func_decl("@arr", res.get_sort());
- expr y = fresh();
- expr equ = ctx.make(Equal,y,res);
- cnstrs.push_back(equ);
- renaming[y] = res;
- res = y;
- }
+ func_decl f = t.decl();
+ std::vector args;
+ int nargs = t.num_args();
+ for (int i = 0; i < nargs; i++)
+ args.push_back(ExtractStores(memo, t.arg(i), cnstrs, renaming));
+ res = f(args.size(), &args[0]);
+ if (f.get_decl_kind() == Store) {
+ func_decl fresh = ctx.fresh_func_decl("@arr", res.get_sort());
+ expr y = fresh();
+ expr equ = ctx.make(Equal, y, res);
+ cnstrs.push_back(equ);
+ renaming[y] = res;
+ res = y;
+ }
}
else res = t;
return res;
@@ -436,20 +427,20 @@ namespace Duality {
bool Z3User::IsLiteral(const expr &lit, expr &atom, expr &val){
- if(!(lit.is_quantifier() && IsClosedFormula(lit))){
- if(!lit.is_app())
- return false;
- decl_kind k = lit.decl().get_decl_kind();
- if(k == Not){
- if(IsLiteral(lit.arg(0),atom,val)){
- val = eq(val,ctx.bool_val(true)) ? ctx.bool_val(false) : ctx.bool_val(true);
- return true;
- }
- return false;
+ if (!(lit.is_quantifier() && IsClosedFormula(lit))) {
+ if (!lit.is_app())
+ return false;
+ decl_kind k = lit.decl().get_decl_kind();
+ if (k == Not) {
+ if (IsLiteral(lit.arg(0), atom, val)) {
+ val = eq(val, ctx.bool_val(true)) ? ctx.bool_val(false) : ctx.bool_val(true);
+ return true;
+ }
+ return false;
+ }
+ if (k == And || k == Or || k == Iff || k == Implies)
+ return false;
}
- if(k == And || k == Or || k == Iff || k == Implies)
- return false;
- }
atom = lit;
val = ctx.bool_val(true);
return true;
@@ -467,11 +458,11 @@ namespace Duality {
expr Z3User::ReduceAndOr(const std::vector &args, bool is_and, std::vector &res){
for(unsigned i = 0; i < args.size(); i++)
- if(!eq(args[i],ctx.bool_val(is_and))){
- if(eq(args[i],ctx.bool_val(!is_and)))
- return ctx.bool_val(!is_and);
- res.push_back(args[i]);
- }
+ if (!eq(args[i], ctx.bool_val(is_and))) {
+ if (eq(args[i], ctx.bool_val(!is_and)))
+ return ctx.bool_val(!is_and);
+ res.push_back(args[i]);
+ }
return expr();
}
@@ -495,36 +486,36 @@ namespace Duality {
// first check if there's anything to do...
if(args.size() < 2)
return FinishAndOr(args,is_and);
- for(unsigned i = 0; i < args.size(); i++){
- const expr &a = args[i];
- if(!(a.is_app() && a.decl().get_decl_kind() == (is_and ? Or : And)))
- return FinishAndOr(args,is_and);
+ for (unsigned i = 0; i < args.size(); i++) {
+ const expr &a = args[i];
+ if (!(a.is_app() && a.decl().get_decl_kind() == (is_and ? Or : And)))
+ return FinishAndOr(args, is_and);
}
std::vector common;
- for(unsigned i = 0; i < args.size(); i++){
- unsigned n = args[i].num_args();
- std::vector v(n),w;
- for(unsigned j = 0; j < n; j++)
- v[j] = args[i].arg(j);
- std::less comp;
- std::sort(v.begin(),v.end(),comp);
- if(i == 0)
- common.swap(v);
- else {
- std::set_intersection(common.begin(),common.end(),v.begin(),v.end(),std::inserter(w,w.begin()),comp);
- common.swap(w);
- }
- }
+ for (unsigned i = 0; i < args.size(); i++) {
+ unsigned n = args[i].num_args();
+ std::vector v(n), w;
+ for (unsigned j = 0; j < n; j++)
+ v[j] = args[i].arg(j);
+ std::less comp;
+ std::sort(v.begin(), v.end(), comp);
+ if (i == 0)
+ common.swap(v);
+ else {
+ std::set_intersection(common.begin(), common.end(), v.begin(), v.end(), std::inserter(w, w.begin()), comp);
+ common.swap(w);
+ }
+ }
if(common.empty())
return FinishAndOr(args,is_and);
std::set common_set(common.begin(),common.end());
for(unsigned i = 0; i < args.size(); i++){
unsigned n = args[i].num_args();
std::vector lits;
- for(unsigned j = 0; j < n; j++){
- const expr b = args[i].arg(j);
- if(common_set.find(b) == common_set.end())
- lits.push_back(b);
+ for (unsigned j = 0; j < n; j++) {
+ const expr b = args[i].arg(j);
+ if (common_set.find(b) == common_set.end())
+ lits.push_back(b);
}
args[i] = SimplifyAndOr(lits,!is_and);
}
@@ -549,148 +540,145 @@ namespace Duality {
}
Z3User::Term Z3User::PushQuantifier(const expr &t, const expr &body, bool is_forall){
- if(t.get_quantifier_num_bound() == 1){
- std::vector fmlas,free,not_free;
- CollectJuncts(body,fmlas, is_forall ? Or : And, false);
- for(unsigned i = 0; i < fmlas.size(); i++){
- const expr &fmla = fmlas[i];
- if(fmla.has_free(0))
- free.push_back(fmla);
- else
- not_free.push_back(fmla);
+ if (t.get_quantifier_num_bound() == 1) {
+ std::vector fmlas, free, not_free;
+ CollectJuncts(body, fmlas, is_forall ? Or : And, false);
+ for (unsigned i = 0; i < fmlas.size(); i++) {
+ const expr &fmla = fmlas[i];
+ if (fmla.has_free(0))
+ free.push_back(fmla);
+ else
+ not_free.push_back(fmla);
+ }
+ decl_kind op = is_forall ? Or : And;
+ if (free.empty())
+ return DeleteBound(0, 1, SimplifyAndOr(not_free, op == And));
+ expr q = clone_quantifier(is_forall ? Forall : Exists, t, SimplifyAndOr(free, op == And));
+ if (!not_free.empty())
+ q = ctx.make(op, q, DeleteBound(0, 1, SimplifyAndOr(not_free, op == And)));
+ return q;
}
- decl_kind op = is_forall ? Or : And;
- if(free.empty())
- return DeleteBound(0,1,SimplifyAndOr(not_free,op == And));
- expr q = clone_quantifier(is_forall ? Forall : Exists,t, SimplifyAndOr(free, op == And));
- if(!not_free.empty())
- q = ctx.make(op,q,DeleteBound(0,1,SimplifyAndOr(not_free, op == And)));
- return q;
- }
return clone_quantifier(is_forall ? Forall : Exists,t,body);
}
- Z3User::Term Z3User::CloneQuantAndSimp(const expr &t, const expr &body, bool is_forall){
- if(body.is_app()){
- if(body.decl().get_decl_kind() == (is_forall ? And : Or)){ // quantifier distributes
- int nargs = body.num_args();
- std::vector args(nargs);
- for(int i = 0; i < nargs; i++)
- args[i] = CloneQuantAndSimp(t, body.arg(i), is_forall);
- return SimplifyAndOr(args, body.decl().get_decl_kind() == And);
+ Z3User::Term Z3User::CloneQuantAndSimp(const expr &t, const expr &body, bool is_forall) {
+ if (body.is_app()) {
+ if (body.decl().get_decl_kind() == (is_forall ? And : Or)) { // quantifier distributes
+ int nargs = body.num_args();
+ std::vector args(nargs);
+ for (int i = 0; i < nargs; i++)
+ args[i] = CloneQuantAndSimp(t, body.arg(i), is_forall);
+ return SimplifyAndOr(args, body.decl().get_decl_kind() == And);
+ }
+ else if (body.decl().get_decl_kind() == (is_forall ? Or : And)) { // quantifier distributes
+ return PushQuantifier(t, body, is_forall); // may distribute partially
+ }
+ else if (body.decl().get_decl_kind() == Not) {
+ return ctx.make(Not, CloneQuantAndSimp(t, body.arg(0), !is_forall));
+ }
}
- else if(body.decl().get_decl_kind() == (is_forall ? Or : And)){ // quantifier distributes
- return PushQuantifier(t,body,is_forall); // may distribute partially
- }
- else if(body.decl().get_decl_kind() == Not){
- return ctx.make(Not,CloneQuantAndSimp(t,body.arg(0),!is_forall));
- }
- }
- if(t.get_quantifier_num_bound() == 1 && !body.has_free(0))
- return DeleteBound(0,1,body); // drop the quantifier
- return clone_quantifier(is_forall ? Forall : Exists,t,body);
+ if (t.get_quantifier_num_bound() == 1 && !body.has_free(0))
+ return DeleteBound(0, 1, body); // drop the quantifier
+ return clone_quantifier(is_forall ? Forall : Exists, t, body);
}
Z3User::Term Z3User::CloneQuantAndSimp(const expr &t, const expr &body){
return CloneQuantAndSimp(t,body,t.is_quantifier_forall());
}
- Z3User::Term Z3User::SubstAtom(hash_map &memo, const expr &t, const expr &atom, const expr &val){
- std::pair foo(t,expr(ctx));
- std::pair::iterator, bool> bar = memo.insert(foo);
- Term &res = bar.first->second;
- if(!bar.second) return res;
- if (t.is_app()){
- func_decl f = t.decl();
- decl_kind k = f.get_decl_kind();
-
- // TODO: recur here, but how much? We don't want to be quadractic in formula size
-
- if(k == And || k == Or){
- int nargs = t.num_args();
- std::vector args(nargs);
- for(int i = 0; i < nargs; i++)
- args[i] = SubstAtom(memo,t.arg(i),atom,val);
- res = ReallySimplifyAndOr(args, k==And);
- return res;
+ Z3User::Term Z3User::SubstAtom(hash_map &memo, const expr &t, const expr &atom, const expr &val) {
+ std::pair foo(t, expr(ctx));
+ std::pair::iterator, bool> bar = memo.insert(foo);
+ Term &res = bar.first->second;
+ if (!bar.second) return res;
+ if (t.is_app()) {
+ func_decl f = t.decl();
+ decl_kind k = f.get_decl_kind();
+
+ // TODO: recur here, but how much? We don't want to be quadractic in formula size
+
+ if (k == And || k == Or) {
+ int nargs = t.num_args();
+ std::vector args(nargs);
+ for (int i = 0; i < nargs; i++)
+ args[i] = SubstAtom(memo, t.arg(i), atom, val);
+ res = ReallySimplifyAndOr(args, k == And);
+ return res;
+ }
}
- }
- else if(t.is_quantifier() && atom.is_quantifier()){
- if(eq(t,atom))
- res = val;
- else
- res = clone_quantifier(t,SubstAtom(memo,t.body(),atom,val));
+ else if (t.is_quantifier() && atom.is_quantifier()) {
+ if (eq(t, atom))
+ res = val;
+ else
+ res = clone_quantifier(t, SubstAtom(memo, t.body(), atom, val));
+ return res;
+ }
+ res = SubstAtomTriv(t, atom, val);
return res;
- }
- res = SubstAtomTriv(t,atom,val);
- return res;
}
- void Z3User::RemoveRedundancyOp(bool pol, std::vector &args, hash_map &smemo){
- for(unsigned i = 0; i < args.size(); i++){
- const expr &lit = args[i];
- expr atom, val;
- if(IsLiteral(lit,atom,val)){
- if(atom.is_app() && atom.decl().get_decl_kind() == Equal)
- if(pol ? eq(val,ctx.bool_val(true)) : eq(val,ctx.bool_val(false))){
- expr lhs = atom.arg(0), rhs = atom.arg(1);
- if(lhs.is_numeral())
- std::swap(lhs,rhs);
- if(rhs.is_numeral() && lhs.is_app()){
- for(unsigned j = 0; j < args.size(); j++)
- if(j != i){
- smemo.clear();
- smemo[lhs] = rhs;
- args[j] = SubstRec(smemo,args[j]);
- }
- }
- }
- for(unsigned j = 0; j < args.size(); j++)
- if(j != i){
- smemo.clear();
- args[j] = SubstAtom(smemo,args[j],atom,pol ? val : !val);
- }
+ void Z3User::RemoveRedundancyOp(bool pol, std::vector &args, hash_map &smemo) {
+ for (unsigned i = 0; i < args.size(); i++) {
+ const expr &lit = args[i];
+ expr atom, val;
+ if (IsLiteral(lit, atom, val)) {
+ if (atom.is_app() && atom.decl().get_decl_kind() == Equal)
+ if (pol ? eq(val, ctx.bool_val(true)) : eq(val, ctx.bool_val(false))) {
+ expr lhs = atom.arg(0), rhs = atom.arg(1);
+ if (lhs.is_numeral())
+ std::swap(lhs, rhs);
+ if (rhs.is_numeral() && lhs.is_app()) {
+ for (unsigned j = 0; j < args.size(); j++)
+ if (j != i) {
+ smemo.clear();
+ smemo[lhs] = rhs;
+ args[j] = SubstRec(smemo, args[j]);
+ }
+ }
+ }
+ for (unsigned j = 0; j < args.size(); j++)
+ if (j != i) {
+ smemo.clear();
+ args[j] = SubstAtom(smemo, args[j], atom, pol ? val : !val);
+ }
+ }
}
- }
}
- Z3User::Term Z3User::RemoveRedundancyRec(hash_map &memo, hash_map &smemo, const Term &t)
- {
- std::pair foo(t,expr(ctx));
- std::pair::iterator, bool> bar = memo.insert(foo);
- Term &res = bar.first->second;
- if(!bar.second) return res;
- if (t.is_app())
- {
- func_decl f = t.decl();
- std::vector args;
- int nargs = t.num_args();
- for(int i = 0; i < nargs; i++)
- args.push_back(RemoveRedundancyRec(memo, smemo, t.arg(i)));
+ Z3User::Term Z3User::RemoveRedundancyRec(hash_map &memo, hash_map &smemo, const Term &t) {
+ std::pair foo(t, expr(ctx));
+ std::pair::iterator, bool> bar = memo.insert(foo);
+ Term &res = bar.first->second;
+ if (!bar.second) return res;
+ if (t.is_app()) {
+ func_decl f = t.decl();
+ std::vector args;
+ int nargs = t.num_args();
+ for (int i = 0; i < nargs; i++)
+ args.push_back(RemoveRedundancyRec(memo, smemo, t.arg(i)));
- decl_kind k = f.get_decl_kind();
- if(k == And){
- RemoveRedundancyOp(true,args,smemo);
- res = ReallySimplifyAndOr(args, true);
- }
- else if(k == Or){
- RemoveRedundancyOp(false,args,smemo);
- res = ReallySimplifyAndOr(args, false);
- }
- else {
- if(k == Equal && args[0].get_id() > args[1].get_id())
- std::swap(args[0],args[1]);
- res = f(args.size(),&args[0]);
- }
+ decl_kind k = f.get_decl_kind();
+ if (k == And) {
+ RemoveRedundancyOp(true, args, smemo);
+ res = ReallySimplifyAndOr(args, true);
+ }
+ else if (k == Or) {
+ RemoveRedundancyOp(false, args, smemo);
+ res = ReallySimplifyAndOr(args, false);
+ }
+ else {
+ if (k == Equal && args[0].get_id() > args[1].get_id())
+ std::swap(args[0], args[1]);
+ res = f(args.size(), &args[0]);
+ }
}
- else if (t.is_quantifier())
- {
- Term body = RemoveRedundancyRec(memo,smemo,t.body());
- res = CloneQuantAndSimp(t, body);
+ else if (t.is_quantifier()) {
+ Term body = RemoveRedundancyRec(memo, smemo, t.body());
+ res = CloneQuantAndSimp(t, body);
}
- else res = t;
- return res;
+ else res = t;
+ return res;
}
Z3User::Term Z3User::RemoveRedundancy(const Term &t){
@@ -706,43 +694,40 @@ namespace Duality {
return t;
}
- Z3User::Term Z3User::IneqToEqRec(hash_map &memo, const Term &t)
- {
- std::pair foo(t,expr(ctx));
- std::pair::iterator, bool> bar = memo.insert(foo);
- Term &res = bar.first->second;
- if(!bar.second) return res;
- if (t.is_app())
- {
- func_decl f = t.decl();
- std::vector args;
- int nargs = t.num_args();
- for(int i = 0; i < nargs; i++)
- args.push_back(IneqToEqRec(memo, t.arg(i)));
+ Z3User::Term Z3User::IneqToEqRec(hash_map &memo, const Term &t) {
+ std::pair foo(t, expr(ctx));
+ std::pair::iterator, bool> bar = memo.insert(foo);
+ Term &res = bar.first->second;
+ if (!bar.second) return res;
+ if (t.is_app()) {
+ func_decl f = t.decl();
+ std::vector args;
+ int nargs = t.num_args();
+ for (int i = 0; i < nargs; i++)
+ args.push_back(IneqToEqRec(memo, t.arg(i)));
- decl_kind k = f.get_decl_kind();
- if(k == And){
- for(int i = 0; i < nargs-1; i++){
- if((args[i].is_app() && args[i].decl().get_decl_kind() == Geq &&
- args[i+1].is_app() && args[i+1].decl().get_decl_kind() == Leq)
- ||
- (args[i].is_app() && args[i].decl().get_decl_kind() == Leq &&
- args[i+1].is_app() && args[i+1].decl().get_decl_kind() == Geq))
- if(eq(args[i].arg(0),args[i+1].arg(0)) && eq(args[i].arg(1),args[i+1].arg(1))){
- args[i] = ctx.make(Equal,args[i].arg(0),args[i].arg(1));
- args[i+1] = ctx.bool_val(true);
- }
- }
- }
- res = f(args.size(),&args[0]);
+ decl_kind k = f.get_decl_kind();
+ if (k == And) {
+ for (int i = 0; i < nargs - 1; i++) {
+ if ((args[i].is_app() && args[i].decl().get_decl_kind() == Geq &&
+ args[i + 1].is_app() && args[i + 1].decl().get_decl_kind() == Leq)
+ ||
+ (args[i].is_app() && args[i].decl().get_decl_kind() == Leq &&
+ args[i + 1].is_app() && args[i + 1].decl().get_decl_kind() == Geq))
+ if (eq(args[i].arg(0), args[i + 1].arg(0)) && eq(args[i].arg(1), args[i + 1].arg(1))) {
+ args[i] = ctx.make(Equal, args[i].arg(0), args[i].arg(1));
+ args[i + 1] = ctx.bool_val(true);
+ }
+ }
+ }
+ res = f(args.size(), &args[0]);
}
- else if (t.is_quantifier())
- {
- Term body = IneqToEqRec(memo,t.body());
- res = clone_quantifier(t, body);
+ else if (t.is_quantifier()) {
+ Term body = IneqToEqRec(memo, t.body());
+ res = clone_quantifier(t, body);
}
- else res = t;
- return res;
+ else res = t;
+ return res;
}
Z3User::Term Z3User::IneqToEq(const Term &t){
@@ -750,87 +735,85 @@ namespace Duality {
return IneqToEqRec(memo,t);
}
- Z3User::Term Z3User::SubstRecHide(hash_map &memo, const Term &t, int number)
- {
- std::pair foo(t,expr(ctx));
- std::pair::iterator, bool> bar = memo.insert(foo);
- Term &res = bar.first->second;
- if(!bar.second) return res;
- if (t.is_app())
- {
- func_decl f = t.decl();
- std::vector args;
- int nargs = t.num_args();
- if (nargs == 0 && f.get_decl_kind() == Uninterpreted){
- std::string name = std::string("@q_") + t.decl().name().str() + "_" + string_of_int(number);
- res = ctx.constant(name.c_str(), t.get_sort());
- return res;
- }
- for(int i = 0; i < nargs; i++)
- args.push_back(SubstRec(memo, t.arg(i)));
- res = f(args.size(),&args[0]);
+ Z3User::Term Z3User::SubstRecHide(hash_map &memo, const Term &t, int number) {
+ std::pair foo(t, expr(ctx));
+ std::pair::iterator, bool> bar = memo.insert(foo);
+ Term &res = bar.first->second;
+ if (!bar.second) return res;
+ if (t.is_app()) {
+ func_decl f = t.decl();
+ std::vector args;
+ int nargs = t.num_args();
+ if (nargs == 0 && f.get_decl_kind() == Uninterpreted) {
+ std::string name = std::string("@q_") + t.decl().name().str() + "_" + string_of_int(number);
+ res = ctx.constant(name.c_str(), t.get_sort());
+ return res;
+ }
+ for (int i = 0; i < nargs; i++)
+ args.push_back(SubstRec(memo, t.arg(i)));
+ res = f(args.size(), &args[0]);
}
- else if (t.is_quantifier())
- res = CloneQuantifier(t,SubstRec(memo, t.body()));
- else res = t;
- return res;
+ else if (t.is_quantifier())
+ res = CloneQuantifier(t, SubstRec(memo, t.body()));
+ else res = t;
+ return res;
}
RPFP::Term RPFP::SubstParams(const std::vector &from,
- const std::vector &to, const Term &t){
- hash_map memo;
- bool some_diff = false;
- for(unsigned i = 0; i < from.size(); i++)
- if(i < to.size() && !eq(from[i],to[i])){
- memo[from[i]] = to[i];
- some_diff = true;
- }
- return some_diff ? SubstRec(memo,t) : t;
+ const std::vector &to, const Term &t) {
+ hash_map memo;
+ bool some_diff = false;
+ for (unsigned i = 0; i < from.size(); i++)
+ if (i < to.size() && !eq(from[i], to[i])) {
+ memo[from[i]] = to[i];
+ some_diff = true;
+ }
+ return some_diff ? SubstRec(memo, t) : t;
}
RPFP::Term RPFP::SubstParamsNoCapture(const std::vector &from,
- const std::vector &to, const Term &t){
- hash_map memo;
- bool some_diff = false;
- for(unsigned i = 0; i < from.size(); i++)
- if(i < to.size() && !eq(from[i],to[i])){
- memo[from[i]] = to[i];
- // if the new param is not being mapped to anything else, we need to rename it to prevent capture
- // note, if the new param *is* mapped later in the list, it will override this substitution
- const expr &w = to[i];
- if(memo.find(w) == memo.end()){
- std::string old_name = w.decl().name().str();
- func_decl fresh = ctx.fresh_func_decl(old_name.c_str(), w.get_sort());
- expr y = fresh();
- memo[w] = y;
- }
- some_diff = true;
- }
- return some_diff ? SubstRec(memo,t) : t;
+ const std::vector &to, const Term &t) {
+ hash_map memo;
+ bool some_diff = false;
+ for (unsigned i = 0; i < from.size(); i++)
+ if (i < to.size() && !eq(from[i], to[i])) {
+ memo[from[i]] = to[i];
+ // if the new param is not being mapped to anything else, we need to rename it to prevent capture
+ // note, if the new param *is* mapped later in the list, it will override this substitution
+ const expr &w = to[i];
+ if (memo.find(w) == memo.end()) {
+ std::string old_name = w.decl().name().str();
+ func_decl fresh = ctx.fresh_func_decl(old_name.c_str(), w.get_sort());
+ expr y = fresh();
+ memo[w] = y;
+ }
+ some_diff = true;
+ }
+ return some_diff ? SubstRec(memo, t) : t;
}
- RPFP::Transformer RPFP::Fuse(const std::vector &trs){
- assert(!trs.empty());
- const std::vector ¶ms = trs[0]->IndParams;
- std::vector fmlas(trs.size());
- fmlas[0] = trs[0]->Formula;
- for(unsigned i = 1; i < trs.size(); i++)
- fmlas[i] = SubstParamsNoCapture(trs[i]->IndParams,params,trs[i]->Formula);
- std::vector rel_params = trs[0]->RelParams;
- for(unsigned i = 1; i < trs.size(); i++){
- const std::vector ¶ms2 = trs[i]->RelParams;
- hash_map map;
- for(unsigned j = 0; j < params2.size(); j++){
- func_decl rel = RenumberPred(params2[j],rel_params.size());
- rel_params.push_back(rel);
- map[params2[j]] = rel;
+ RPFP::Transformer RPFP::Fuse(const std::vector &trs) {
+ assert(!trs.empty());
+ const std::vector ¶ms = trs[0]->IndParams;
+ std::vector fmlas(trs.size());
+ fmlas[0] = trs[0]->Formula;
+ for (unsigned i = 1; i < trs.size(); i++)
+ fmlas[i] = SubstParamsNoCapture(trs[i]->IndParams, params, trs[i]->Formula);
+ std::vector rel_params = trs[0]->RelParams;
+ for (unsigned i = 1; i < trs.size(); i++) {
+ const std::vector ¶ms2 = trs[i]->RelParams;
+ hash_map map;
+ for (unsigned j = 0; j < params2.size(); j++) {
+ func_decl rel = RenumberPred(params2[j], rel_params.size());
+ rel_params.push_back(rel);
+ map[params2[j]] = rel;
+ }
+ hash_map memo;
+ fmlas[i] = SubstRec(memo, map, fmlas[i]);
}
- hash_map memo;
- fmlas[i] = SubstRec(memo,map,fmlas[i]);
- }
- return Transformer(rel_params,params,ctx.make(Or,fmlas),trs[0]->owner);
+ return Transformer(rel_params, params, ctx.make(Or, fmlas), trs[0]->owner);
}
@@ -855,19 +838,17 @@ namespace Duality {
root->Annotation.Formula = annot;
}
- void RPFP::DecodeTree(Node *root, TermTree *interp, int persist)
- {
- std::vector &ic = interp->getChildren();
- if (ic.size() > 0)
- {
- std::vector &nc = root->Outgoing->Children;
- for (unsigned i = 0; i < nc.size(); i++)
- DecodeTree(nc[i], ic[i], persist);
+ void RPFP::DecodeTree(Node *root, TermTree *interp, int persist) {
+ std::vector &ic = interp->getChildren();
+ if (ic.size() > 0) {
+ std::vector &nc = root->Outgoing->Children;
+ for (unsigned i = 0; i < nc.size(); i++)
+ DecodeTree(nc[i], ic[i], persist);
}
- SetAnnotation(root,interp->getTerm());
+ SetAnnotation(root, interp->getTerm());
#if 0
- if(persist != 0)
- Z3_persist_ast(ctx,root->Annotation.Formula,persist);
+ if(persist != 0)
+ Z3_persist_ast(ctx,root->Annotation.Formula,persist);
#endif
}
@@ -926,31 +907,30 @@ namespace Duality {
#endif
- expr RPFP::GetEdgeFormula(Edge *e, int persist, bool with_children, bool underapprox)
- {
- if (e->dual.null()) {
- timer_start("ReducedDualEdge");
- e->dual = ReducedDualEdge(e);
- timer_stop("ReducedDualEdge");
- timer_start("getting children");
- if(underapprox){
- std::vector cus(e->Children.size());
- for(unsigned i = 0; i < e->Children.size(); i++)
- cus[i] = !UnderapproxFlag(e->Children[i]) || GetUnderapprox(e->Children[i]);
- expr cnst = conjoin(cus);
- e->dual = e->dual && cnst;
+ expr RPFP::GetEdgeFormula(Edge *e, int persist, bool with_children, bool underapprox) {
+ if (e->dual.null()) {
+ timer_start("ReducedDualEdge");
+ e->dual = ReducedDualEdge(e);
+ timer_stop("ReducedDualEdge");
+ timer_start("getting children");
+ if (underapprox) {
+ std::vector cus(e->Children.size());
+ for (unsigned i = 0; i < e->Children.size(); i++)
+ cus[i] = !UnderapproxFlag(e->Children[i]) || GetUnderapprox(e->Children[i]);
+ expr cnst = conjoin(cus);
+ e->dual = e->dual && cnst;
+ }
+ timer_stop("getting children");
+ timer_start("Persisting");
+ std::list::reverse_iterator it = stack.rbegin();
+ for (int i = 0; i < persist && it != stack.rend(); i++)
+ it++;
+ if (it != stack.rend())
+ it->edges.push_back(e);
+ timer_stop("Persisting");
+ //Console.WriteLine("{0}", cnst);
}
- timer_stop("getting children");
- timer_start("Persisting");
- std::list::reverse_iterator it = stack.rbegin();
- for(int i = 0; i < persist && it != stack.rend(); i++)
- it++;
- if(it != stack.rend())
- it->edges.push_back(e);
- timer_stop("Persisting");
- //Console.WriteLine("{0}", cnst);
- }
- return e->dual;
+ return e->dual;
}
/** For incremental solving, asserts the constraint associated
@@ -970,47 +950,46 @@ namespace Duality {
*
*/
- void RPFP::AssertEdge(Edge *e, int persist, bool with_children, bool underapprox)
- {
- if(eq(e->F.Formula,ctx.bool_val(true)) && (!with_children || e->Children.empty()))
- return;
- expr fmla = GetEdgeFormula(e, persist, with_children, underapprox);
- timer_start("solver add");
- slvr_add(e->dual);
- timer_stop("solver add");
- if(with_children)
- for(unsigned i = 0; i < e->Children.size(); i++)
- ConstrainParent(e,e->Children[i]);
+ void RPFP::AssertEdge(Edge *e, int persist, bool with_children, bool underapprox) {
+ if (eq(e->F.Formula, ctx.bool_val(true)) && (!with_children || e->Children.empty()))
+ return;
+ expr fmla = GetEdgeFormula(e, persist, with_children, underapprox);
+ timer_start("solver add");
+ slvr_add(e->dual);
+ timer_stop("solver add");
+ if (with_children)
+ for (unsigned i = 0; i < e->Children.size(); i++)
+ ConstrainParent(e, e->Children[i]);
}
#ifdef LIMIT_STACK_WEIGHT
void RPFP_caching::AssertEdge(Edge *e, int persist, bool with_children, bool underapprox)
{
- unsigned old_new_alits = new_alits.size();
- if(eq(e->F.Formula,ctx.bool_val(true)) && (!with_children || e->Children.empty()))
- return;
- expr fmla = GetEdgeFormula(e, persist, with_children, underapprox);
- timer_start("solver add");
- slvr_add(e->dual);
- timer_stop("solver add");
- if(old_new_alits < new_alits.size())
- weight_added.val++;
- if(with_children)
- for(unsigned i = 0; i < e->Children.size(); i++)
- ConstrainParent(e,e->Children[i]);
+ unsigned old_new_alits = new_alits.size();
+ if(eq(e->F.Formula,ctx.bool_val(true)) && (!with_children || e->Children.empty()))
+ return;
+ expr fmla = GetEdgeFormula(e, persist, with_children, underapprox);
+ timer_start("solver add");
+ slvr_add(e->dual);
+ timer_stop("solver add");
+ if(old_new_alits < new_alits.size())
+ weight_added.val++;
+ if(with_children)
+ for(unsigned i = 0; i < e->Children.size(); i++)
+ ConstrainParent(e,e->Children[i]);
}
#endif
// caching verion of above
- void RPFP_caching::AssertEdgeCache(Edge *e, std::vector &lits, bool with_children){
- if(eq(e->F.Formula,ctx.bool_val(true)) && (!with_children || e->Children.empty()))
- return;
- expr fmla = GetEdgeFormula(e, 0, with_children, false);
- GetAssumptionLits(fmla,lits);
- if(with_children)
- for(unsigned i = 0; i < e->Children.size(); i++)
- ConstrainParentCache(e,e->Children[i],lits);
+ void RPFP_caching::AssertEdgeCache(Edge *e, std::vector &lits, bool with_children) {
+ if (eq(e->F.Formula, ctx.bool_val(true)) && (!with_children || e->Children.empty()))
+ return;
+ expr fmla = GetEdgeFormula(e, 0, with_children, false);
+ GetAssumptionLits(fmla, lits);
+ if (with_children)
+ for (unsigned i = 0; i < e->Children.size(); i++)
+ ConstrainParentCache(e, e->Children[i], lits);
}
void RPFP::slvr_add(const expr &e){
@@ -1032,23 +1011,23 @@ namespace Duality {
void RPFP_caching::slvr_pop(int i){
for(int j = 0; j < i; j++){
#ifdef LIMIT_STACK_WEIGHT
- if(alit_stack_sizes.empty()){
- if(big_stack.empty())
- throw "stack underflow";
- for(unsigned k = 0; k < new_alits.size(); k++){
- if(AssumptionLits.find(new_alits[k]) == AssumptionLits.end())
- throw "foo!";
- AssumptionLits.erase(new_alits[k]);
- }
- big_stack_entry &bsb = big_stack.back();
- bsb.alit_stack_sizes.swap(alit_stack_sizes);
- bsb.alit_stack.swap(alit_stack);
- bsb.new_alits.swap(new_alits);
- bsb.weight_added.swap(weight_added);
- big_stack.pop_back();
- slvr().pop(1);
- continue;
- }
+ if(alit_stack_sizes.empty()){
+ if(big_stack.empty())
+ throw "stack underflow";
+ for(unsigned k = 0; k < new_alits.size(); k++){
+ if(AssumptionLits.find(new_alits[k]) == AssumptionLits.end())
+ throw "foo!";
+ AssumptionLits.erase(new_alits[k]);
+ }
+ big_stack_entry &bsb = big_stack.back();
+ bsb.alit_stack_sizes.swap(alit_stack_sizes);
+ bsb.alit_stack.swap(alit_stack);
+ bsb.new_alits.swap(new_alits);
+ bsb.weight_added.swap(weight_added);
+ big_stack.pop_back();
+ slvr().pop(1);
+ continue;
+ }
#endif
alit_stack.resize(alit_stack_sizes.back());
alit_stack_sizes.pop_back();
@@ -1057,18 +1036,18 @@ namespace Duality {
void RPFP_caching::slvr_push(){
#ifdef LIMIT_STACK_WEIGHT
- if(weight_added.val > LIMIT_STACK_WEIGHT){
- big_stack.resize(big_stack.size()+1);
- big_stack_entry &bsb = big_stack.back();
- bsb.alit_stack_sizes.swap(alit_stack_sizes);
- bsb.alit_stack.swap(alit_stack);
- bsb.new_alits.swap(new_alits);
- bsb.weight_added.swap(weight_added);
- slvr().push();
- for(unsigned i = 0; i < bsb.alit_stack.size(); i++)
- slvr().add(bsb.alit_stack[i]);
- return;
- }
+ if(weight_added.val > LIMIT_STACK_WEIGHT){
+ big_stack.resize(big_stack.size()+1);
+ big_stack_entry &bsb = big_stack.back();
+ bsb.alit_stack_sizes.swap(alit_stack_sizes);
+ bsb.alit_stack.swap(alit_stack);
+ bsb.new_alits.swap(new_alits);
+ bsb.weight_added.swap(weight_added);
+ slvr().push();
+ for(unsigned i = 0; i < bsb.alit_stack.size(); i++)
+ slvr().add(bsb.alit_stack[i]);
+ return;
+ }
#endif
alit_stack_sizes.push_back(alit_stack.size());
}
@@ -1082,16 +1061,16 @@ namespace Duality {
if(n && assumptions)
std::copy(assumptions,assumptions+n,std::inserter(alit_stack,alit_stack.end()));
check_result res;
- if(core_size && core){
- std::vector full_core(alit_stack.size()), core1(n);
- std::copy(assumptions,assumptions+n,core1.begin());
- res = slvr().check(alit_stack.size(), &alit_stack[0], core_size, &full_core[0]);
- full_core.resize(*core_size);
- if(res == unsat){
- FilterCore(core1,full_core);
- *core_size = core1.size();
- std::copy(core1.begin(),core1.end(),core);
- }
+ if (core_size && core) {
+ std::vector full_core(alit_stack.size()), core1(n);
+ std::copy(assumptions, assumptions + n, core1.begin());
+ res = slvr().check(alit_stack.size(), &alit_stack[0], core_size, &full_core[0]);
+ full_core.resize(*core_size);
+ if (res == unsat) {
+ FilterCore(core1, full_core);
+ *core_size = core1.size();
+ std::copy(core1.begin(), core1.end(), core);
+ }
}
else
res = slvr().check(alit_stack.size(), &alit_stack[0]);
@@ -1100,20 +1079,20 @@ namespace Duality {
}
lbool RPFP::ls_interpolate_tree(TermTree *assumptions,
- TermTree *&interpolants,
- model &_model,
- TermTree *goals,
- bool weak){
- return ls->interpolate_tree(assumptions, interpolants, _model, goals, weak);
+ TermTree *&interpolants,
+ model &_model,
+ TermTree *goals,
+ bool weak) {
+ return ls->interpolate_tree(assumptions, interpolants, _model, goals, weak);
}
lbool RPFP_caching::ls_interpolate_tree(TermTree *assumptions,
- TermTree *&interpolants,
- model &_model,
- TermTree *goals,
- bool weak){
- GetTermTreeAssertionLiterals(assumptions);
- return ls->interpolate_tree(assumptions, interpolants, _model, goals, weak);
+ TermTree *&interpolants,
+ model &_model,
+ TermTree *goals,
+ bool weak) {
+ GetTermTreeAssertionLiterals(assumptions);
+ return ls->interpolate_tree(assumptions, interpolants, _model, goals, weak);
}
void RPFP_caching::GetTermTreeAssertionLiteralsRec(TermTree *assumptions){
@@ -1132,34 +1111,34 @@ namespace Duality {
return;
}
- void RPFP_caching::GetTermTreeAssertionLiterals(TermTree *assumptions){
- // optimize binary case
- if(assumptions->getChildren().size() == 1
- && assumptions->getChildren()[0]->getChildren().size() == 0){
- hash_map map;
- TermTree *child = assumptions->getChildren()[0];
- std::vector dummy;
- GetAssumptionLits(child->getTerm(),dummy,&map);
- std::vector &ts = child->getTerms();
- for(unsigned i = 0; i < ts.size(); i++)
- GetAssumptionLits(ts[i],dummy,&map);
- std::vector assumps;
- slvr().get_proof().get_assumptions(assumps);
- if(!proof_core){ // save the proof core for later use
- proof_core = new hash_set;
- for(unsigned i = 0; i < assumps.size(); i++)
- proof_core->insert(assumps[i]);
+ void RPFP_caching::GetTermTreeAssertionLiterals(TermTree *assumptions) {
+ // optimize binary case
+ if (assumptions->getChildren().size() == 1
+ && assumptions->getChildren()[0]->getChildren().size() == 0) {
+ hash_map map;
+ TermTree *child = assumptions->getChildren()[0];
+ std::vector dummy;
+ GetAssumptionLits(child->getTerm(), dummy, &map);
+ std::vector &ts = child->getTerms();
+ for (unsigned i = 0; i < ts.size(); i++)
+ GetAssumptionLits(ts[i], dummy, &map);
+ std::vector assumps;
+ slvr().get_proof().get_assumptions(assumps);
+ if (!proof_core) { // save the proof core for later use
+ proof_core = new hash_set < ast > ;
+ for (unsigned i = 0; i < assumps.size(); i++)
+ proof_core->insert(assumps[i]);
+ }
+ std::vector *cnsts[2] = { &child->getTerms(), &assumptions->getTerms() };
+ for (unsigned i = 0; i < assumps.size(); i++) {
+ expr &ass = assumps[i];
+ expr alit = (ass.is_app() && ass.decl().get_decl_kind() == Implies) ? ass.arg(0) : ass;
+ bool isA = map.find(alit) != map.end();
+ cnsts[isA ? 0 : 1]->push_back(ass);
+ }
}
- std::vector *cnsts[2] = {&child->getTerms(),&assumptions->getTerms()};
- for(unsigned i = 0; i < assumps.size(); i++){
- expr &ass = assumps[i];
- expr alit = (ass.is_app() && ass.decl().get_decl_kind() == Implies) ? ass.arg(0) : ass;
- bool isA = map.find(alit) != map.end();
- cnsts[isA ? 0 : 1]->push_back(ass);
- }
- }
- else
- GetTermTreeAssertionLiteralsRec(assumptions);
+ else
+ GetTermTreeAssertionLiteralsRec(assumptions);
}
void RPFP::AddToProofCore(hash_set &core){
@@ -1177,27 +1156,27 @@ namespace Duality {
}
- void RPFP_caching::GetAssumptionLits(const expr &fmla, std::vector &lits, hash_map *opt_map){
- std::vector conjs;
- CollectConjuncts(fmla,conjs);
- for(unsigned i = 0; i < conjs.size(); i++){
- const expr &conj = conjs[i];
- std::pair foo(conj,expr(ctx));
- std::pair::iterator, bool> bar = AssumptionLits.insert(foo);
- Term &res = bar.first->second;
- if(bar.second){
- func_decl pred = ctx.fresh_func_decl("@alit", ctx.bool_sort());
- res = pred();
+ void RPFP_caching::GetAssumptionLits(const expr &fmla, std::vector &lits, hash_map *opt_map) {
+ std::vector conjs;
+ CollectConjuncts(fmla, conjs);
+ for (unsigned i = 0; i < conjs.size(); i++) {
+ const expr &conj = conjs[i];
+ std::pair foo(conj, expr(ctx));
+ std::pair::iterator, bool> bar = AssumptionLits.insert(foo);
+ Term &res = bar.first->second;
+ if (bar.second) {
+ func_decl pred = ctx.fresh_func_decl("@alit", ctx.bool_sort());
+ res = pred();
#ifdef LIMIT_STACK_WEIGHT
- new_alits.push_back(conj);
+ new_alits.push_back(conj);
#endif
- slvr().add(ctx.make(Implies,res,conj));
- // std::cout << res << ": " << conj << "\n";
+ slvr().add(ctx.make(Implies, res, conj));
+ // std::cout << res << ": " << conj << "\n";
+ }
+ if (opt_map)
+ (*opt_map)[res] = conj;
+ lits.push_back(res);
}
- if(opt_map)
- (*opt_map)[res] = conj;
- lits.push_back(res);
- }
}
void RPFP::ConstrainParent(Edge *parent, Node *child){
@@ -1215,39 +1194,37 @@ namespace Duality {
void RPFP::AssertNode(Node *n)
{
- if (n->dual.null())
- {
- n->dual = GetUpperBound(n);
- stack.back().nodes.push_back(n);
- slvr_add(n->dual);
+ if (n->dual.null()) {
+ n->dual = GetUpperBound(n);
+ stack.back().nodes.push_back(n);
+ slvr_add(n->dual);
}
}
// caching version of above
void RPFP_caching::AssertNodeCache(Node *n, std::vector lits){
- if (n->dual.null())
- {
- n->dual = GetUpperBound(n);
- stack.back().nodes.push_back(n);
- GetAssumptionLits(n->dual,lits);
+ if (n->dual.null()) {
+ n->dual = GetUpperBound(n);
+ stack.back().nodes.push_back(n);
+ GetAssumptionLits(n->dual, lits);
}
}
/** Clone another RPFP into this one, keeping a map */
- void RPFP_caching::Clone(RPFP *other){
+ void RPFP_caching::Clone(RPFP *other) {
#if 0
- for(unsigned i = 0; i < other->nodes.size(); i++)
- NodeCloneMap[other->nodes[i]] = CloneNode(other->nodes[i]);
+ for(unsigned i = 0; i < other->nodes.size(); i++)
+ NodeCloneMap[other->nodes[i]] = CloneNode(other->nodes[i]);
#endif
- for(unsigned i = 0; i < other->edges.size(); i++){
- Edge *edge = other->edges[i];
- Node *parent = CloneNode(edge->Parent);
- std::vector cs;
- for(unsigned j = 0; j < edge->Children.size(); j++)
- // cs.push_back(NodeCloneMap[edge->Children[j]]);
- cs.push_back(CloneNode(edge->Children[j]));
- EdgeCloneMap[edge] = CreateEdge(parent,edge->F,cs);
- }
+ for (unsigned i = 0; i < other->edges.size(); i++) {
+ Edge *edge = other->edges[i];
+ Node *parent = CloneNode(edge->Parent);
+ std::vector cs;
+ for (unsigned j = 0; j < edge->Children.size(); j++)
+ // cs.push_back(NodeCloneMap[edge->Children[j]]);
+ cs.push_back(CloneNode(edge->Children[j]));
+ EdgeCloneMap[edge] = CreateEdge(parent, edge->F, cs);
+ }
}
/** Get the clone of a node */
@@ -1373,11 +1350,10 @@ namespace Duality {
timer_start("interpolate_tree");
lbool res = ls_interpolate_tree(tree, interpolant, dualModel,goals,true);
timer_stop("interpolate_tree");
- if (res == l_false)
- {
- DecodeTree(root, interpolant->getChildren()[0], persist);
- delete interpolant;
- }
+ if (res == l_false) {
+ DecodeTree(root, interpolant->getChildren()[0], persist);
+ delete interpolant;
+ }
delete tree;
if(goals)
@@ -1419,11 +1395,10 @@ namespace Duality {
timer_start("interpolate_tree");
lbool res = ls_interpolate_tree(tree, interpolant, dualModel,0,true);
timer_stop("interpolate_tree");
- if (res == l_false)
- {
- DecodeTree(node, interpolant->getChildren()[0], 0);
- delete interpolant;
- }
+ if (res == l_false) {
+ DecodeTree(node, interpolant->getChildren()[0], 0);
+ delete interpolant;
+ }
delete tree;
timer_stop("Solve");
@@ -1461,44 +1436,43 @@ namespace Duality {
*
*/
- check_result RPFP::Check(Node *root, std::vector underapproxes, std::vector *underapprox_core )
- {
- timer_start("Check");
- ClearProofCore();
- // if (dualModel != null) dualModel.Dispose();
- check_result res;
- if(!underapproxes.size())
- res = slvr_check();
- else {
- std::vector us(underapproxes.size());
- for(unsigned i = 0; i < underapproxes.size(); i++)
- us[i] = UnderapproxFlag(underapproxes[i]);
- slvr_check(); // TODO: no idea why I need to do this
- if(underapprox_core){
- std::vector unsat_core(us.size());
- unsigned core_size = 0;
- res = slvr_check(us.size(),&us[0],&core_size,&unsat_core[0]);
- underapprox_core->resize(core_size);
- for(unsigned i = 0; i < core_size; i++)
- (*underapprox_core)[i] = UnderapproxFlagRev(unsat_core[i]);
- }
- else {
- res = slvr_check(us.size(),&us[0]);
- bool dump = false;
- if(dump){
- std::vector cnsts;
- // cnsts.push_back(axioms[0]);
- cnsts.push_back(root->dual);
- cnsts.push_back(root->Outgoing->dual);
- ls->write_interpolation_problem("temp.smt",cnsts,std::vector());
- }
- }
- // check_result temp = slvr_check();
- }
- dualModel = slvr().get_model();
- timer_stop("Check");
- return res;
- }
+ check_result RPFP::Check(Node *root, std::vector underapproxes, std::vector *underapprox_core) {
+ timer_start("Check");
+ ClearProofCore();
+ // if (dualModel != null) dualModel.Dispose();
+ check_result res;
+ if (!underapproxes.size())
+ res = slvr_check();
+ else {
+ std::vector us(underapproxes.size());
+ for (unsigned i = 0; i < underapproxes.size(); i++)
+ us[i] = UnderapproxFlag(underapproxes[i]);
+ slvr_check(); // TODO: no idea why I need to do this
+ if (underapprox_core) {
+ std::vector