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 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::CheckUpdateModel(Node *root, std::vector assumps){ // check_result temp1 = slvr_check(); // no idea why I need to do this @@ -1545,54 +1519,54 @@ namespace Duality { } void RPFP::EvalArrayTerm(const RPFP::Term &t, ArrayValue &res){ - if(t.is_app()){ - decl_kind k = t.decl().get_decl_kind(); - if(k == AsArray){ - func_decl fd = t.decl().get_func_decl_parameter(0); - func_interp r = dualModel.get_func_interp(fd); - int num = r.num_entries(); - res.defined = true; - for(int i = 0; i < num; i++){ - expr arg = r.get_arg(i,0); - expr value = r.get_value(i); - res.entries[arg] = value; - } - res.def_val = r.else_value(); - return; + if (t.is_app()) { + decl_kind k = t.decl().get_decl_kind(); + if (k == AsArray) { + func_decl fd = t.decl().get_func_decl_parameter(0); + func_interp r = dualModel.get_func_interp(fd); + int num = r.num_entries(); + res.defined = true; + for (int i = 0; i < num; i++) { + expr arg = r.get_arg(i, 0); + expr value = r.get_value(i); + res.entries[arg] = value; + } + res.def_val = r.else_value(); + return; + } + else if (k == Store) { + EvalArrayTerm(t.arg(0), res); + if (!res.defined)return; + expr addr = t.arg(1); + expr val = t.arg(2); + if (addr.is_numeral() && val.is_numeral()) { + if (eq(val, res.def_val)) + res.entries.erase(addr); + else + res.entries[addr] = val; + } + else + res.defined = false; + return; + } } - else if(k == Store){ - EvalArrayTerm(t.arg(0),res); - if(!res.defined)return; - expr addr = t.arg(1); - expr val = t.arg(2); - if(addr.is_numeral() && val.is_numeral()){ - if(eq(val,res.def_val)) - res.entries.erase(addr); - else - res.entries[addr] = val; - } - else - res.defined = false; - return; - } - } res.defined = false; } int eae_count = 0; - RPFP::Term RPFP::EvalArrayEquality(const RPFP::Term &f){ - ArrayValue lhs,rhs; - eae_count++; - EvalArrayTerm(f.arg(0),lhs); - EvalArrayTerm(f.arg(1),rhs); - if(lhs.defined && rhs.defined){ - if(eq(lhs.def_val,rhs.def_val)) - if(lhs.entries == rhs.entries) - return ctx.bool_val(true); - return ctx.bool_val(false); - } - return f; + RPFP::Term RPFP::EvalArrayEquality(const RPFP::Term &f) { + ArrayValue lhs, rhs; + eae_count++; + EvalArrayTerm(f.arg(0), lhs); + EvalArrayTerm(f.arg(1), rhs); + if (lhs.defined && rhs.defined) { + if (eq(lhs.def_val, rhs.def_val)) + if (lhs.entries == rhs.entries) + return ctx.bool_val(true); + return ctx.bool_val(false); + } + return f; } /** Compute truth values of all boolean subterms in current model. @@ -1600,75 +1574,75 @@ namespace Duality { ands and, or, not. Returns result in memo. */ - int RPFP::SubtermTruth(hash_map &memo, const Term &f){ - if(memo.find(f) != memo.end()){ - return memo[f]; - } - int res; - if(f.is_app()){ - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if(k == Implies){ - res = SubtermTruth(memo,!f.arg(0) || f.arg(1)); - goto done; + int RPFP::SubtermTruth(hash_map &memo, const Term &f) { + if (memo.find(f) != memo.end()) { + return memo[f]; } - if(k == And) { - res = 1; - for(int i = 0; i < nargs; i++){ - int ar = SubtermTruth(memo,f.arg(i)); - if(ar == 0){ - res = 0; - goto done; - } - if(ar == 2)res = 2; - } - goto done; - } - else if(k == Or) { - res = 0; - for(int i = 0; i < nargs; i++){ - int ar = SubtermTruth(memo,f.arg(i)); - if(ar == 1){ - res = 1; - goto done; - } - if(ar == 2)res = 2; - } - goto done; - } - else if(k == Not) { - int ar = SubtermTruth(memo,f.arg(0)); - res = (ar == 0) ? 1 : ((ar == 1) ? 0 : 2); - goto done; + int res; + if (f.is_app()) { + int nargs = f.num_args(); + decl_kind k = f.decl().get_decl_kind(); + if (k == Implies) { + res = SubtermTruth(memo, !f.arg(0) || f.arg(1)); + goto done; + } + if (k == And) { + res = 1; + for (int i = 0; i < nargs; i++) { + int ar = SubtermTruth(memo, f.arg(i)); + if (ar == 0) { + res = 0; + goto done; + } + if (ar == 2)res = 2; + } + goto done; + } + else if (k == Or) { + res = 0; + for (int i = 0; i < nargs; i++) { + int ar = SubtermTruth(memo, f.arg(i)); + if (ar == 1) { + res = 1; + goto done; + } + if (ar == 2)res = 2; + } + goto done; + } + else if (k == Not) { + int ar = SubtermTruth(memo, f.arg(0)); + res = (ar == 0) ? 1 : ((ar == 1) ? 0 : 2); + goto done; + } } + { + bool pos; std::vector names; + if (f.is_label(pos, names)) { + res = SubtermTruth(memo, f.arg(0)); + goto done; + } } { - bool pos; std::vector names; - if(f.is_label(pos,names)){ - res = SubtermTruth(memo,f.arg(0)); - goto done; - } + expr bv = dualModel.eval(f); + if (bv.is_app() && bv.decl().get_decl_kind() == Equal && + bv.arg(0).is_array()) { + bv = EvalArrayEquality(bv); + } + // Hack!!!! array equalities can occur negatively! + if (bv.is_app() && bv.decl().get_decl_kind() == Not && + bv.arg(0).decl().get_decl_kind() == Equal && + bv.arg(0).arg(0).is_array()) { + bv = dualModel.eval(!EvalArrayEquality(bv.arg(0))); + } + if (eq(bv, ctx.bool_val(true))) + res = 1; + else if (eq(bv, ctx.bool_val(false))) + res = 0; + else + res = 2; } - { - expr bv = dualModel.eval(f); - if(bv.is_app() && bv.decl().get_decl_kind() == Equal && - bv.arg(0).is_array()){ - bv = EvalArrayEquality(bv); - } - // Hack!!!! array equalities can occur negatively! - if(bv.is_app() && bv.decl().get_decl_kind() == Not && - bv.arg(0).decl().get_decl_kind() == Equal && - bv.arg(0).arg(0).is_array()){ - bv = dualModel.eval(!EvalArrayEquality(bv.arg(0))); - } - if(eq(bv,ctx.bool_val(true))) - res = 1; - else if(eq(bv,ctx.bool_val(false))) - res = 0; - else - res = 2; - } - done: +done: memo[f] = res; return res; } @@ -1685,137 +1659,137 @@ namespace Duality { #if 0 int RPFP::GetLabelsRec(hash_map *memo, const Term &f, std::vector &labels, bool labpos){ - if(memo[labpos].find(f) != memo[labpos].end()){ - return memo[labpos][f]; - } - int res; - if(f.is_app()){ - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if(k == Implies){ - res = GetLabelsRec(memo,f.arg(1) || !f.arg(0), labels, labpos); - goto done; + if(memo[labpos].find(f) != memo[labpos].end()){ + return memo[labpos][f]; } - if(k == And) { - res = 1; - for(int i = 0; i < nargs; i++){ - int ar = GetLabelsRec(memo,f.arg(i), labels, labpos); - if(ar == 0){ - res = 0; - goto done; - } - if(ar == 2)res = 2; - } - goto done; - } - else if(k == Or) { - res = 0; - for(int i = 0; i < nargs; i++){ - int ar = GetLabelsRec(memo,f.arg(i), labels, labpos); - if(ar == 1){ - res = 1; - goto done; - } - if(ar == 2)res = 2; - } - goto done; - } - else if(k == Not) { - int ar = GetLabelsRec(memo,f.arg(0), labels, !labpos); - res = (ar == 0) ? 1 : ((ar == 1) ? 0 : 2); - goto done; + int res; + if(f.is_app()){ + int nargs = f.num_args(); + decl_kind k = f.decl().get_decl_kind(); + if(k == Implies){ + res = GetLabelsRec(memo,f.arg(1) || !f.arg(0), labels, labpos); + goto done; + } + if(k == And) { + res = 1; + for(int i = 0; i < nargs; i++){ + int ar = GetLabelsRec(memo,f.arg(i), labels, labpos); + if(ar == 0){ + res = 0; + goto done; + } + if(ar == 2)res = 2; + } + goto done; + } + else if(k == Or) { + res = 0; + for(int i = 0; i < nargs; i++){ + int ar = GetLabelsRec(memo,f.arg(i), labels, labpos); + if(ar == 1){ + res = 1; + goto done; + } + if(ar == 2)res = 2; + } + goto done; + } + else if(k == Not) { + int ar = GetLabelsRec(memo,f.arg(0), labels, !labpos); + res = (ar == 0) ? 1 : ((ar == 1) ? 0 : 2); + goto done; + } } + { + bool pos; std::vector names; + if(f.is_label(pos,names)){ + res = GetLabelsRec(memo,f.arg(0), labels, labpos); + if(pos == labpos && res == (pos ? 1 : 0)) + for(unsigned i = 0; i < names.size(); i++) + labels.push_back(names[i]); + goto done; + } } { - bool pos; std::vector names; - if(f.is_label(pos,names)){ - res = GetLabelsRec(memo,f.arg(0), labels, labpos); - if(pos == labpos && res == (pos ? 1 : 0)) - for(unsigned i = 0; i < names.size(); i++) - labels.push_back(names[i]); - goto done; - } + expr bv = dualModel.eval(f); + if(bv.is_app() && bv.decl().get_decl_kind() == Equal && + bv.arg(0).is_array()){ + bv = EvalArrayEquality(bv); + } + // Hack!!!! array equalities can occur negatively! + if(bv.is_app() && bv.decl().get_decl_kind() == Not && + bv.arg(0).decl().get_decl_kind() == Equal && + bv.arg(0).arg(0).is_array()){ + bv = dualModel.eval(!EvalArrayEquality(bv.arg(0))); + } + if(eq(bv,ctx.bool_val(true))) + res = 1; + else if(eq(bv,ctx.bool_val(false))) + res = 0; + else + res = 2; } - { - expr bv = dualModel.eval(f); - if(bv.is_app() && bv.decl().get_decl_kind() == Equal && - bv.arg(0).is_array()){ - bv = EvalArrayEquality(bv); - } - // Hack!!!! array equalities can occur negatively! - if(bv.is_app() && bv.decl().get_decl_kind() == Not && - bv.arg(0).decl().get_decl_kind() == Equal && - bv.arg(0).arg(0).is_array()){ - bv = dualModel.eval(!EvalArrayEquality(bv.arg(0))); - } - if(eq(bv,ctx.bool_val(true))) - res = 1; - else if(eq(bv,ctx.bool_val(false))) - res = 0; - else - res = 2; - } - done: +done: memo[labpos][f] = res; return res; } #endif - void RPFP::GetLabelsRec(hash_map &memo, const Term &f, std::vector &labels, - hash_set *done, bool truth){ - if(done[truth].find(f) != done[truth].end()) - return; /* already processed */ - if(f.is_app()){ - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if(k == Implies){ - GetLabelsRec(memo,f.arg(1) || !f.arg(0) ,labels,done,truth); - goto done; + void RPFP::GetLabelsRec(hash_map &memo, const Term &f, std::vector &labels, + hash_set *done, bool truth) { + if (done[truth].find(f) != done[truth].end()) + return; /* already processed */ + if (f.is_app()) { + int nargs = f.num_args(); + decl_kind k = f.decl().get_decl_kind(); + if (k == Implies) { + GetLabelsRec(memo, f.arg(1) || !f.arg(0), labels, done, truth); + goto done; + } + if (k == Iff) { + int b = SubtermTruth(memo, f.arg(0)); + if (b == 2) + throw "disaster in GetLabelsRec"; + GetLabelsRec(memo, f.arg(1), labels, done, truth ? b : !b); + goto done; + } + if (truth ? k == And : k == Or) { + for (int i = 0; i < nargs; i++) + GetLabelsRec(memo, f.arg(i), labels, done, truth); + goto done; + } + if (truth ? k == Or : k == And) { + for (int i = 0; i < nargs; i++) { + Term a = f.arg(i); + timer_start("SubtermTruth"); + int b = SubtermTruth(memo, a); + timer_stop("SubtermTruth"); + if (truth ? (b == 1) : (b == 0)) { + GetLabelsRec(memo, a, labels, done, truth); + goto done; + } + } + /* Unreachable! */ + // throw "error in RPFP::GetLabelsRec"; + goto done; + } + else if (k == Not) { + GetLabelsRec(memo, f.arg(0), labels, done, !truth); + goto done; + } + else { + bool pos; std::vector names; + if (f.is_label(pos, names)) { + GetLabelsRec(memo, f.arg(0), labels, done, truth); + if (pos == truth) + for (unsigned i = 0; i < names.size(); i++) + labels.push_back(names[i]); + goto done; + } + } } - if(k == Iff){ - int b = SubtermTruth(memo,f.arg(0)); - if(b == 2) - throw "disaster in GetLabelsRec"; - GetLabelsRec(memo,f.arg(1),labels,done,truth ? b : !b); - goto done; - } - if(truth ? k == And : k == Or) { - for(int i = 0; i < nargs; i++) - GetLabelsRec(memo,f.arg(i),labels,done,truth); - goto done; - } - if(truth ? k == Or : k == And) { - for(int i = 0; i < nargs; i++){ - Term a = f.arg(i); - timer_start("SubtermTruth"); - int b = SubtermTruth(memo,a); - timer_stop("SubtermTruth"); - if(truth ? (b == 1) : (b == 0)){ - GetLabelsRec(memo,a,labels,done,truth); - goto done; - } - } - /* Unreachable! */ - // throw "error in RPFP::GetLabelsRec"; - goto done; - } - else if(k == Not) { - GetLabelsRec(memo,f.arg(0),labels,done,!truth); - goto done; - } - else { - bool pos; std::vector names; - if(f.is_label(pos,names)){ - GetLabelsRec(memo,f.arg(0), labels, done, truth); - if(pos == truth) - for(unsigned i = 0; i < names.size(); i++) - labels.push_back(names[i]); - goto done; - } - } - } done: - done[truth].insert(f); + done[truth].insert(f); } void RPFP::GetLabels(Edge *e, std::vector &labels){ @@ -1833,185 +1807,184 @@ namespace Duality { int ir_count = 0; - void RPFP::ImplicantRed(hash_map &memo, const Term &f, std::vector &lits, - hash_set *done, bool truth, hash_set &dont_cares){ - if(done[truth].find(f) != done[truth].end()) - return; /* already processed */ + void RPFP::ImplicantRed(hash_map &memo, const Term &f, std::vector &lits, + hash_set *done, bool truth, hash_set &dont_cares) { + if (done[truth].find(f) != done[truth].end()) + return; /* already processed */ #if 0 - int this_count = ir_count++; - if(this_count == 50092) - std::cout << "foo!\n"; + int this_count = ir_count++; + if(this_count == 50092) + std::cout << "foo!\n"; #endif - if(f.is_app()){ - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if(k == Implies){ - ImplicantRed(memo,f.arg(1) || !f.arg(0) ,lits,done,truth,dont_cares); - goto done; - } - if(k == Iff){ - int b = SubtermTruth(memo,f.arg(0)); - if(b == 2) - throw "disaster in ImplicantRed"; - ImplicantRed(memo,f.arg(1),lits,done,truth ? b : !b,dont_cares); - goto done; - } - if(truth ? k == And : k == Or) { - for(int i = 0; i < nargs; i++) - ImplicantRed(memo,f.arg(i),lits,done,truth,dont_cares); - goto done; - } - if(truth ? k == Or : k == And) { - for(int i = 0; i < nargs; i++){ - Term a = f.arg(i); + if (f.is_app()) { + int nargs = f.num_args(); + decl_kind k = f.decl().get_decl_kind(); + if (k == Implies) { + ImplicantRed(memo, f.arg(1) || !f.arg(0), lits, done, truth, dont_cares); + goto done; + } + if (k == Iff) { + int b = SubtermTruth(memo, f.arg(0)); + if (b == 2) + throw "disaster in ImplicantRed"; + ImplicantRed(memo, f.arg(1), lits, done, truth ? b : !b, dont_cares); + goto done; + } + if (truth ? k == And : k == Or) { + for (int i = 0; i < nargs; i++) + ImplicantRed(memo, f.arg(i), lits, done, truth, dont_cares); + goto done; + } + if (truth ? k == Or : k == And) { + for (int i = 0; i < nargs; i++) { + Term a = f.arg(i); #if 0 - if(i == nargs - 1){ // last chance! - ImplicantRed(memo,a,lits,done,truth,dont_cares); - goto done; - } + if(i == nargs - 1){ // last chance! + ImplicantRed(memo,a,lits,done,truth,dont_cares); + goto done; + } #endif - timer_start("SubtermTruth"); + timer_start("SubtermTruth"); #ifdef Z3OPS - bool b = stt->eval(a); + bool b = stt->eval(a); #else - int b = SubtermTruth(memo,a); + int b = SubtermTruth(memo, a); #endif - timer_stop("SubtermTruth"); - if(truth ? (b == 1) : (b == 0)){ - ImplicantRed(memo,a,lits,done,truth,dont_cares); - goto done; - } - } - /* Unreachable! */ - // TODO: need to indicate this failure to caller - // std::cerr << "error in RPFP::ImplicantRed"; - goto done; + timer_stop("SubtermTruth"); + if (truth ? (b == 1) : (b == 0)) { + ImplicantRed(memo, a, lits, done, truth, dont_cares); + goto done; + } + } + /* Unreachable! */ + // TODO: need to indicate this failure to caller + // std::cerr << "error in RPFP::ImplicantRed"; + goto done; + } + else if (k == Not) { + ImplicantRed(memo, f.arg(0), lits, done, !truth, dont_cares); + goto done; + } } - else if(k == Not) { - ImplicantRed(memo,f.arg(0),lits,done,!truth,dont_cares); - goto done; - } - } { - if(dont_cares.find(f) == dont_cares.end()){ - expr rf = ResolveIte(memo,f,lits,done,dont_cares); - expr bv = truth ? rf : !rf; - lits.push_back(bv); - } + if (dont_cares.find(f) == dont_cares.end()) { + expr rf = ResolveIte(memo, f, lits, done, dont_cares); + expr bv = truth ? rf : !rf; + lits.push_back(bv); + } } - done: +done: done[truth].insert(f); } - void RPFP::ImplicantFullRed(hash_map &memo, const Term &f, std::vector &lits, - hash_set &done, hash_set &dont_cares, bool extensional){ - if(done.find(f) != done.end()) - return; /* already processed */ - if(f.is_app()){ - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if(k == Implies || k == Iff || k == And || k == Or || k == Not){ - for(int i = 0; i < nargs; i++) - ImplicantFullRed(memo,f.arg(i),lits,done,dont_cares, extensional); - goto done; + void RPFP::ImplicantFullRed(hash_map &memo, const Term &f, std::vector &lits, + hash_set &done, hash_set &dont_cares, bool extensional) { + if (done.find(f) != done.end()) + return; /* already processed */ + if (f.is_app()) { + int nargs = f.num_args(); + decl_kind k = f.decl().get_decl_kind(); + if (k == Implies || k == Iff || k == And || k == Or || k == Not) { + for (int i = 0; i < nargs; i++) + ImplicantFullRed(memo, f.arg(i), lits, done, dont_cares, extensional); + goto done; + } } - } { - if(dont_cares.find(f) == dont_cares.end()){ - int b = SubtermTruth(memo,f); - if(b != 0 && b != 1) goto done; - if(f.is_app() && f.decl().get_decl_kind() == Equal && f.arg(0).is_array()){ - if(b == 1 && !extensional){ - expr x = dualModel.eval(f.arg(0)); expr y = dualModel.eval(f.arg(1)); - if(!eq(x,y)) - b = 0; - } - if(b == 0) - goto done; - } - expr bv = (b==1) ? f : !f; - lits.push_back(bv); - } + if (dont_cares.find(f) == dont_cares.end()) { + int b = SubtermTruth(memo, f); + if (b != 0 && b != 1) goto done; + if (f.is_app() && f.decl().get_decl_kind() == Equal && f.arg(0).is_array()) { + if (b == 1 && !extensional) { + expr x = dualModel.eval(f.arg(0)); expr y = dualModel.eval(f.arg(1)); + if (!eq(x, y)) + b = 0; + } + if (b == 0) + goto done; + } + expr bv = (b == 1) ? f : !f; + lits.push_back(bv); + } } - done: +done: done.insert(f); } - RPFP::Term RPFP::ResolveIte(hash_map &memo, const Term &t, std::vector &lits, - hash_set *done, hash_set &dont_cares){ - if(resolve_ite_memo.find(t) != resolve_ite_memo.end()) - return resolve_ite_memo[t]; - Term res; - if (t.is_app()) - { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - if(f.get_decl_kind() == Ite){ - timer_start("SubtermTruth"); + RPFP::Term RPFP::ResolveIte(hash_map &memo, const Term &t, std::vector &lits, + hash_set *done, hash_set &dont_cares) { + if (resolve_ite_memo.find(t) != resolve_ite_memo.end()) + return resolve_ite_memo[t]; + Term res; + if (t.is_app()) { + func_decl f = t.decl(); + std::vector args; + int nargs = t.num_args(); + if (f.get_decl_kind() == Ite) { + timer_start("SubtermTruth"); #ifdef Z3OPS - bool sel = stt->eval(t.arg(0)); + bool sel = stt->eval(t.arg(0)); #else - int xval = SubtermTruth(memo,t.arg(0)); - bool sel; - if(xval == 0)sel = false; - else if(xval == 1)sel = true; - else - throw "unresolved ite in model"; + int xval = SubtermTruth(memo, t.arg(0)); + bool sel; + if (xval == 0)sel = false; + else if (xval == 1)sel = true; + else + throw "unresolved ite in model"; #endif - timer_stop("SubtermTruth"); - ImplicantRed(memo,t.arg(0),lits,done,sel,dont_cares); - res = ResolveIte(memo,t.arg(sel?1:2),lits,done,dont_cares); - } - else { - for(int i = 0; i < nargs; i++) - args.push_back(ResolveIte(memo,t.arg(i),lits,done,dont_cares)); - res = f(args.size(),&args[0]); - } + timer_stop("SubtermTruth"); + ImplicantRed(memo, t.arg(0), lits, done, sel, dont_cares); + res = ResolveIte(memo, t.arg(sel ? 1 : 2), lits, done, dont_cares); + } + else { + for (int i = 0; i < nargs; i++) + args.push_back(ResolveIte(memo, t.arg(i), lits, done, dont_cares)); + res = f(args.size(), &args[0]); + } } - else res = t; - resolve_ite_memo[t] = res; - return res; + else res = t; + resolve_ite_memo[t] = res; + return res; } - RPFP::Term RPFP::ElimIteRec(hash_map &memo, const Term &t, std::vector &cnsts){ - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if(bar.second){ - if(t.is_app()){ - int nargs = t.num_args(); - std::vector args; - if(t.decl().get_decl_kind() == Equal){ - expr lhs = t.arg(0); - expr rhs = t.arg(1); - if(rhs.decl().get_decl_kind() == Ite){ - expr rhs_args[3]; - lhs = ElimIteRec(memo,lhs,cnsts); - for(int i = 0; i < 3; i++) - rhs_args[i] = ElimIteRec(memo,rhs.arg(i),cnsts); - res = (rhs_args[0] && (lhs == rhs_args[1])) || ((!rhs_args[0]) && (lhs == rhs_args[2])); - goto done; - } - } - if(t.decl().get_decl_kind() == Ite){ - func_decl sym = ctx.fresh_func_decl("@ite", t.get_sort()); - res = sym(); - cnsts.push_back(ElimIteRec(memo,ctx.make(Equal,res,t),cnsts)); - } - else { - for(int i = 0; i < nargs; i++) - args.push_back(ElimIteRec(memo,t.arg(i),cnsts)); - res = t.decl()(args.size(),&args[0]); - } + RPFP::Term RPFP::ElimIteRec(hash_map &memo, const Term &t, std::vector &cnsts) { + std::pair foo(t, expr(ctx)); + std::pair::iterator, bool> bar = memo.insert(foo); + Term &res = bar.first->second; + if (bar.second) { + if (t.is_app()) { + int nargs = t.num_args(); + std::vector args; + if (t.decl().get_decl_kind() == Equal) { + expr lhs = t.arg(0); + expr rhs = t.arg(1); + if (rhs.decl().get_decl_kind() == Ite) { + expr rhs_args[3]; + lhs = ElimIteRec(memo, lhs, cnsts); + for (int i = 0; i < 3; i++) + rhs_args[i] = ElimIteRec(memo, rhs.arg(i), cnsts); + res = (rhs_args[0] && (lhs == rhs_args[1])) || ((!rhs_args[0]) && (lhs == rhs_args[2])); + goto done; + } + } + if (t.decl().get_decl_kind() == Ite) { + func_decl sym = ctx.fresh_func_decl("@ite", t.get_sort()); + res = sym(); + cnsts.push_back(ElimIteRec(memo, ctx.make(Equal, res, t), cnsts)); + } + else { + for (int i = 0; i < nargs; i++) + args.push_back(ElimIteRec(memo, t.arg(i), cnsts)); + res = t.decl()(args.size(), &args[0]); + } + } + else if (t.is_quantifier()) + res = clone_quantifier(t, ElimIteRec(memo, t.body(), cnsts)); + else + res = t; } - else if(t.is_quantifier()) - res = clone_quantifier(t,ElimIteRec(memo,t.body(),cnsts)); - else - res = t; - } done: - return res; + return res; } RPFP::Term RPFP::ElimIte(const Term &t){ @@ -2084,169 +2057,166 @@ namespace Duality { hash_map cand_map; params simp_params; - VariableProjector(Z3User &_user, std::vector &keep_vec) : - Z3User(_user), simp_params() - { - num_vars = 0; - for(unsigned i = 0; i < keep_vec.size(); i++){ - keep.insert(keep_vec[i]); - var_ord[keep_vec[i]] = num_vars++; - } + VariableProjector(Z3User &_user, std::vector &keep_vec) : + Z3User(_user), simp_params() { + num_vars = 0; + for (unsigned i = 0; i < keep_vec.size(); i++) { + keep.insert(keep_vec[i]); + var_ord[keep_vec[i]] = num_vars++; + } } - - int VarNum(const Term &v){ - if(var_ord.find(v) == var_ord.end()) - var_ord[v] = num_vars++; - return var_ord[v]; + int VarNum(const Term &v) { + if (var_ord.find(v) == var_ord.end()) + var_ord[v] = num_vars++; + return var_ord[v]; } bool IsVar(const Term &t){ return t.is_app() && t.num_args() == 0 && t.decl().get_decl_kind() == Uninterpreted; } - bool IsPropLit(const Term &t, Term &a){ - if(IsVar(t)){ - a = t; - return true; - } - else if(t.is_app() && t.decl().get_decl_kind() == Not) - return IsPropLit(t.arg(0),a); - return false; + bool IsPropLit(const Term &t, Term &a) { + if (IsVar(t)) { + a = t; + return true; + } + else if (t.is_app() && t.decl().get_decl_kind() == Not) + return IsPropLit(t.arg(0), a); + return false; } - void CountOtherVarsRec(hash_map &memo, - const Term &t, - int id, - int &count){ - std::pair foo(t,0); - std::pair::iterator, bool> bar = memo.insert(foo); - // int &res = bar.first->second; - if(!bar.second) return; - 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){ - if(cand_map.find(t) != cand_map.end()){ - count++; - sup_map[t].push_back(id); - } - } - for(int i = 0; i < nargs; i++) - CountOtherVarsRec(memo, t.arg(i), id, count); - } - else if (t.is_quantifier()) - CountOtherVarsRec(memo, t.body(), id, count); - } + void CountOtherVarsRec(hash_map &memo, + const Term &t, + int id, + int &count) { + std::pair foo(t, 0); + std::pair::iterator, bool> bar = memo.insert(foo); + // int &res = bar.first->second; + if (!bar.second) return; + 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) { + if (cand_map.find(t) != cand_map.end()) { + count++; + sup_map[t].push_back(id); + } + } + for (int i = 0; i < nargs; i++) + CountOtherVarsRec(memo, t.arg(i), id, count); + } + else if (t.is_quantifier()) + CountOtherVarsRec(memo, t.body(), id, count); + } - void NewElimCand(const Term &lhs, const Term &rhs){ - if(debug_gauss){ - std::cout << "mapping " << lhs << " to " << rhs << std::endl; - } - elim_cand cand; - cand.var = lhs; - cand.sup = 0; - cand.val = rhs; - elim_cands.push_back(cand); - cand_map[lhs] = elim_cands.size()-1; + void NewElimCand(const Term &lhs, const Term &rhs) { + if (debug_gauss) { + std::cout << "mapping " << lhs << " to " << rhs << std::endl; + } + elim_cand cand; + cand.var = lhs; + cand.sup = 0; + cand.val = rhs; + elim_cands.push_back(cand); + cand_map[lhs] = elim_cands.size() - 1; } - void MakeElimCand(const Term &lhs, const Term &rhs){ - if(eq(lhs,rhs)) - return; - if(!IsVar(lhs)){ - if(IsVar(rhs)){ - MakeElimCand(rhs,lhs); - return; - } - else{ - std::cout << "would have mapped a non-var\n"; - return; - } - } - if(IsVar(rhs) && VarNum(rhs) > VarNum(lhs)){ - MakeElimCand(rhs,lhs); - return; - } - if(keep.find(lhs) != keep.end()) - return; - if(cand_map.find(lhs) == cand_map.end()) - NewElimCand(lhs,rhs); - else { - int cand_idx = cand_map[lhs]; - if(IsVar(rhs) && cand_map.find(rhs) == cand_map.end() - && keep.find(rhs) == keep.end()) - NewElimCand(rhs,elim_cands[cand_idx].val); - elim_cands[cand_idx].val = rhs; - } + void MakeElimCand(const Term &lhs, const Term &rhs) { + if (eq(lhs, rhs)) + return; + if (!IsVar(lhs)) { + if (IsVar(rhs)) { + MakeElimCand(rhs, lhs); + return; + } + else { + std::cout << "would have mapped a non-var\n"; + return; + } + } + if (IsVar(rhs) && VarNum(rhs) > VarNum(lhs)) { + MakeElimCand(rhs, lhs); + return; + } + if (keep.find(lhs) != keep.end()) + return; + if (cand_map.find(lhs) == cand_map.end()) + NewElimCand(lhs, rhs); + else { + int cand_idx = cand_map[lhs]; + if (IsVar(rhs) && cand_map.find(rhs) == cand_map.end() + && keep.find(rhs) == keep.end()) + NewElimCand(rhs, elim_cands[cand_idx].val); + elim_cands[cand_idx].val = rhs; + } } - Term FindRep(const Term &t){ - if(cand_map.find(t) == cand_map.end()) - return t; - Term &res = elim_cands[cand_map[t]].val; - if(IsVar(res)){ - assert(VarNum(res) < VarNum(t)); - res = FindRep(res); - return res; - } - return t; + Term FindRep(const Term &t) { + if (cand_map.find(t) == cand_map.end()) + return t; + Term &res = elim_cands[cand_map[t]].val; + if (IsVar(res)) { + assert(VarNum(res) < VarNum(t)); + res = FindRep(res); + return res; + } + return t; } void GaussElimCheap(const std::vector &lits_in, - std::vector &lits_out){ - for(unsigned i = 0; i < lits_in.size(); i++){ - Term lit = lits_in[i]; - if(lit.is_app()){ - decl_kind k = lit.decl().get_decl_kind(); - if(k == Equal || k == Iff) - MakeElimCand(FindRep(lit.arg(0)),FindRep(lit.arg(1))); - } - } - - for(unsigned i = 0; i < elim_cands.size(); i++){ - elim_cand &cand = elim_cands[i]; - hash_map memo; - CountOtherVarsRec(memo,cand.val,i,cand.sup); - if(cand.sup == 0) - ready_cands.push_back(i); - } - - while(!ready_cands.empty()){ - elim_cand &cand = elim_cands[ready_cands.back()]; - ready_cands.pop_back(); - Term rep = FindRep(cand.var); - if(!eq(rep,cand.var)) - if(cand_map.find(rep) != cand_map.end()){ - int rep_pos = cand_map[rep]; - cand.val = elim_cands[rep_pos].val; - } - Term val = SubstRec(elim_map,cand.val); - if(debug_gauss){ - std::cout << "subbing " << cand.var << " --> " << val << std::endl; - } - elim_map[cand.var] = val; - std::vector &sup = sup_map[cand.var]; - for(unsigned i = 0; i < sup.size(); i++){ - int c = sup[i]; - if((--elim_cands[c].sup) == 0) - ready_cands.push_back(c); - } - } - - for(unsigned i = 0; i < lits_in.size(); i++){ - Term lit = lits_in[i]; - lit = SubstRec(elim_map,lit); - lit = lit.simplify(); - if(eq(lit,ctx.bool_val(true))) - continue; - Term a; - if(IsPropLit(lit,a)) - if(keep.find(lit) == keep.end()) - continue; - lits_out.push_back(lit); - } + std::vector &lits_out) { + for (unsigned i = 0; i < lits_in.size(); i++) { + Term lit = lits_in[i]; + if (lit.is_app()) { + decl_kind k = lit.decl().get_decl_kind(); + if (k == Equal || k == Iff) + MakeElimCand(FindRep(lit.arg(0)), FindRep(lit.arg(1))); + } + } + + for (unsigned i = 0; i < elim_cands.size(); i++) { + elim_cand &cand = elim_cands[i]; + hash_map memo; + CountOtherVarsRec(memo, cand.val, i, cand.sup); + if (cand.sup == 0) + ready_cands.push_back(i); + } + + while (!ready_cands.empty()) { + elim_cand &cand = elim_cands[ready_cands.back()]; + ready_cands.pop_back(); + Term rep = FindRep(cand.var); + if (!eq(rep, cand.var)) + if (cand_map.find(rep) != cand_map.end()) { + int rep_pos = cand_map[rep]; + cand.val = elim_cands[rep_pos].val; + } + Term val = SubstRec(elim_map, cand.val); + if (debug_gauss) { + std::cout << "subbing " << cand.var << " --> " << val << std::endl; + } + elim_map[cand.var] = val; + std::vector &sup = sup_map[cand.var]; + for (unsigned i = 0; i < sup.size(); i++) { + int c = sup[i]; + if ((--elim_cands[c].sup) == 0) + ready_cands.push_back(c); + } + } + + for (unsigned i = 0; i < lits_in.size(); i++) { + Term lit = lits_in[i]; + lit = SubstRec(elim_map, lit); + lit = lit.simplify(); + if (eq(lit, ctx.bool_val(true))) + continue; + Term a; + if (IsPropLit(lit, a)) + if (keep.find(lit) == keep.end()) + continue; + lits_out.push_back(lit); + } } // maps variables to constrains in which the occur pos, neg @@ -2255,88 +2225,88 @@ namespace Duality { std::vector la_pos_vars; bool fixing; - void IndexLAcoeff(const Term &coeff1, const Term &coeff2, Term t, int id){ - Term coeff = coeff1 * coeff2; - coeff = coeff.simplify(); - Term is_pos = (coeff >= ctx.int_val(0)); - is_pos = is_pos.simplify(); - if(eq(is_pos,ctx.bool_val(true))) - IndexLA(true,coeff,t, id); - else - IndexLA(false,coeff,t, id); + void IndexLAcoeff(const Term &coeff1, const Term &coeff2, Term t, int id) { + Term coeff = coeff1 * coeff2; + coeff = coeff.simplify(); + Term is_pos = (coeff >= ctx.int_val(0)); + is_pos = is_pos.simplify(); + if (eq(is_pos, ctx.bool_val(true))) + IndexLA(true, coeff, t, id); + else + IndexLA(false, coeff, t, id); } - void IndexLAremove(const Term &t){ - if(IsVar(t)){ - la_index[0][t] = -1; // means ineligible to be eliminated - la_index[1][t] = -1; // (more that one occurrence, or occurs not in linear comb) - } - else if(t.is_app()){ - int nargs = t.num_args(); - for(int i = 0; i < nargs; i++) - IndexLAremove(t.arg(i)); - } - // TODO: quantifiers? + void IndexLAremove(const Term &t) { + if (IsVar(t)) { + la_index[0][t] = -1; // means ineligible to be eliminated + la_index[1][t] = -1; // (more that one occurrence, or occurs not in linear comb) + } + else if (t.is_app()) { + int nargs = t.num_args(); + for (int i = 0; i < nargs; i++) + IndexLAremove(t.arg(i)); + } + // TODO: quantifiers? } - void IndexLA(bool pos, const Term &coeff, const Term &t, int id){ - if(t.is_numeral()) - return; - if(t.is_app()){ - int nargs = t.num_args(); - switch(t.decl().get_decl_kind()){ - case Plus: - for(int i = 0; i < nargs; i++) - IndexLA(pos,coeff,t.arg(i), id); - break; - case Sub: - IndexLA(pos,coeff,t.arg(0), id); - IndexLA(!pos,coeff,t.arg(1), id); - break; - case Times: - if(t.arg(0).is_numeral()) - IndexLAcoeff(coeff,t.arg(0),t.arg(1), id); - else if(t.arg(1).is_numeral()) - IndexLAcoeff(coeff,t.arg(1),t.arg(0), id); - break; - default: - if(IsVar(t) && (fixing || la_index[pos].find(t) == la_index[pos].end())){ - la_index[pos][t] = id; - la_coeffs[pos][t] = coeff; - if(pos && !fixing) - la_pos_vars.push_back(t); // this means we only add a var once - } - else - IndexLAremove(t); - } - } + void IndexLA(bool pos, const Term &coeff, const Term &t, int id) { + if (t.is_numeral()) + return; + if (t.is_app()) { + int nargs = t.num_args(); + switch (t.decl().get_decl_kind()) { + case Plus: + for (int i = 0; i < nargs; i++) + IndexLA(pos, coeff, t.arg(i), id); + break; + case Sub: + IndexLA(pos, coeff, t.arg(0), id); + IndexLA(!pos, coeff, t.arg(1), id); + break; + case Times: + if (t.arg(0).is_numeral()) + IndexLAcoeff(coeff, t.arg(0), t.arg(1), id); + else if (t.arg(1).is_numeral()) + IndexLAcoeff(coeff, t.arg(1), t.arg(0), id); + break; + default: + if (IsVar(t) && (fixing || la_index[pos].find(t) == la_index[pos].end())) { + la_index[pos][t] = id; + la_coeffs[pos][t] = coeff; + if (pos && !fixing) + la_pos_vars.push_back(t); // this means we only add a var once + } + else + IndexLAremove(t); + } + } } void IndexLAstart(bool pos, const Term &t, int id){ IndexLA(pos,(pos ? ctx.int_val(1) : ctx.int_val(-1)), t, id); } - void IndexLApred(bool pos, const Term &p, int id){ - if(p.is_app()){ - switch(p.decl().get_decl_kind()){ - case Not: - IndexLApred(!pos, p.arg(0),id); - break; - case Leq: - case Lt: - IndexLAstart(!pos, p.arg(0), id); - IndexLAstart(pos, p.arg(1), id); - break; - case Geq: - case Gt: - IndexLAstart(pos,p.arg(0), id); - IndexLAstart(!pos,p.arg(1), id); - break; - default: - IndexLAremove(p); - } - } + void IndexLApred(bool pos, const Term &p, int id) { + if (p.is_app()) { + switch (p.decl().get_decl_kind()) { + case Not: + IndexLApred(!pos, p.arg(0), id); + break; + case Leq: + case Lt: + IndexLAstart(!pos, p.arg(0), id); + IndexLAstart(pos, p.arg(1), id); + break; + case Geq: + case Gt: + IndexLAstart(pos, p.arg(0), id); + IndexLAstart(!pos, p.arg(1), id); + break; + default: + IndexLAremove(p); + } + } } void IndexLAfix(const Term &p, int id){ @@ -2345,51 +2315,51 @@ namespace Duality { fixing = false; } - bool IsCanonIneq(const Term &lit, Term &term, Term &bound){ - // std::cout << Z3_simplify_get_help(ctx) << std::endl; - bool pos = lit.decl().get_decl_kind() != Not; - Term atom = pos ? lit : lit.arg(0); - if(atom.decl().get_decl_kind() == Leq){ - if(pos){ - bound = atom.arg(0); - term = atom.arg(1).simplify(simp_params); + bool IsCanonIneq(const Term &lit, Term &term, Term &bound) { + // std::cout << Z3_simplify_get_help(ctx) << std::endl; + bool pos = lit.decl().get_decl_kind() != Not; + Term atom = pos ? lit : lit.arg(0); + if (atom.decl().get_decl_kind() == Leq) { + if (pos) { + bound = atom.arg(0); + term = atom.arg(1).simplify(simp_params); #if Z3_MAJOR_VERSION < 4 - term = SortSum(term); + term = SortSum(term); #endif - } - else { - bound = (atom.arg(1) + ctx.int_val(1)); - term = atom.arg(0); - // std::cout << "simplifying bound: " << bound << std::endl; - bound = bound.simplify(); - term = term.simplify(simp_params); + } + else { + bound = (atom.arg(1) + ctx.int_val(1)); + term = atom.arg(0); + // std::cout << "simplifying bound: " << bound << std::endl; + bound = bound.simplify(); + term = term.simplify(simp_params); #if Z3_MAJOR_VERSION < 4 - term = SortSum(term); + term = SortSum(term); #endif - } - return true; - } - else if(atom.decl().get_decl_kind() == Geq){ - if(pos){ - bound = atom.arg(1); // integer axiom - term = atom.arg(0).simplify(simp_params); + } + return true; + } + else if (atom.decl().get_decl_kind() == Geq) { + if (pos) { + bound = atom.arg(1); // integer axiom + term = atom.arg(0).simplify(simp_params); #if Z3_MAJOR_VERSION < 4 - term = SortSum(term); + term = SortSum(term); #endif - return true; - } - else{ - bound = -(atom.arg(1) - ctx.int_val(1)); // integer axiom - term = -atom.arg(0); - bound = bound.simplify(); - term = term.simplify(simp_params); + return true; + } + else { + bound = -(atom.arg(1) - ctx.int_val(1)); // integer axiom + term = -atom.arg(0); + bound = bound.simplify(); + term = term.simplify(simp_params); #if Z3_MAJOR_VERSION < 4 - term = SortSum(term); + term = SortSum(term); #endif - } - return true; - } - return false; + } + return true; + } + return false; } Term CanonIneqTerm(const Term &p){ @@ -2400,64 +2370,64 @@ namespace Duality { return term - bound; } - void ElimRedundantBounds(std::vector &lits){ - hash_map best_bound; - for(unsigned i = 0; i < lits.size(); i++){ - lits[i] = lits[i].simplify(simp_params); - Term term,bound; - if(IsCanonIneq(lits[i],term,bound)){ - if(best_bound.find(term) == best_bound.end()) - best_bound[term] = i; - else { - int best = best_bound[term]; - Term bterm,bbound; - IsCanonIneq(lits[best],bterm,bbound); - Term comp = bound > bbound; - comp = comp.simplify(); - if(eq(comp,ctx.bool_val(true))){ - lits[best] = ctx.bool_val(true); - best_bound[term] = i; - } - else { - lits[i] = ctx.bool_val(true); - } - } - } - } + void ElimRedundantBounds(std::vector &lits) { + hash_map best_bound; + for (unsigned i = 0; i < lits.size(); i++) { + lits[i] = lits[i].simplify(simp_params); + Term term, bound; + if (IsCanonIneq(lits[i], term, bound)) { + if (best_bound.find(term) == best_bound.end()) + best_bound[term] = i; + else { + int best = best_bound[term]; + Term bterm, bbound; + IsCanonIneq(lits[best], bterm, bbound); + Term comp = bound > bbound; + comp = comp.simplify(); + if (eq(comp, ctx.bool_val(true))) { + lits[best] = ctx.bool_val(true); + best_bound[term] = i; + } + else { + lits[i] = ctx.bool_val(true); + } + } + } + } } void FourierMotzkinCheap(const std::vector &lits_in, - std::vector &lits_out){ - simp_params.set(":som",true); - simp_params.set(":sort-sums",true); - fixing = false; lits_out = lits_in; - ElimRedundantBounds(lits_out); - for(unsigned i = 0; i < lits_out.size(); i++) - IndexLApred(true,lits_out[i],i); + std::vector &lits_out) { + simp_params.set(":som", true); + simp_params.set(":sort-sums", true); + fixing = false; lits_out = lits_in; + ElimRedundantBounds(lits_out); + for (unsigned i = 0; i < lits_out.size(); i++) + IndexLApred(true, lits_out[i], i); - for(unsigned i = 0; i < la_pos_vars.size(); i++){ - Term var = la_pos_vars[i]; - if(la_index[false].find(var) != la_index[false].end()){ - int pos_idx = la_index[true][var]; - int neg_idx = la_index[false][var]; - if(pos_idx >= 0 && neg_idx >= 0){ - if(keep.find(var) != keep.end()){ - std::cout << "would have eliminated keep var\n"; - continue; - } - Term tpos = CanonIneqTerm(lits_out[pos_idx]); - Term tneg = CanonIneqTerm(lits_out[neg_idx]); - Term pos_coeff = la_coeffs[true][var]; - Term neg_coeff = -la_coeffs[false][var]; - Term comb = neg_coeff * tpos + pos_coeff * tneg; - Term ineq = ctx.int_val(0) <= comb; - ineq = ineq.simplify(); - lits_out[pos_idx] = ineq; - lits_out[neg_idx] = ctx.bool_val(true); - IndexLAfix(ineq,pos_idx); - } - } - } + for (unsigned i = 0; i < la_pos_vars.size(); i++) { + Term var = la_pos_vars[i]; + if (la_index[false].find(var) != la_index[false].end()) { + int pos_idx = la_index[true][var]; + int neg_idx = la_index[false][var]; + if (pos_idx >= 0 && neg_idx >= 0) { + if (keep.find(var) != keep.end()) { + std::cout << "would have eliminated keep var\n"; + continue; + } + Term tpos = CanonIneqTerm(lits_out[pos_idx]); + Term tneg = CanonIneqTerm(lits_out[neg_idx]); + Term pos_coeff = la_coeffs[true][var]; + Term neg_coeff = -la_coeffs[false][var]; + Term comb = neg_coeff * tpos + pos_coeff * tneg; + Term ineq = ctx.int_val(0) <= comb; + ineq = ineq.simplify(); + lits_out[pos_idx] = ineq; + lits_out[neg_idx] = ctx.bool_val(true); + IndexLAfix(ineq, pos_idx); + } + } + } } Term ProjectFormula(const Term &f){ @@ -2473,41 +2443,41 @@ namespace Duality { } }; - void Z3User::CollectConjuncts(const Term &f, std::vector &lits, bool pos){ - if(f.is_app() && f.decl().get_decl_kind() == Not) - CollectConjuncts(f.arg(0), lits, !pos); - else if(pos && f.is_app() && f.decl().get_decl_kind() == And){ - int num_args = f.num_args(); - for(int i = 0; i < num_args; i++) - CollectConjuncts(f.arg(i),lits,true); - } - else if(!pos && f.is_app() && f.decl().get_decl_kind() == Or){ - int num_args = f.num_args(); - for(int i = 0; i < num_args; i++) - CollectConjuncts(f.arg(i),lits,false); - } - else if(pos){ - if(!eq(f,ctx.bool_val(true))) - lits.push_back(f); - } - else { - if(!eq(f,ctx.bool_val(false))) - lits.push_back(!f); - } + void Z3User::CollectConjuncts(const Term &f, std::vector &lits, bool pos) { + if (f.is_app() && f.decl().get_decl_kind() == Not) + CollectConjuncts(f.arg(0), lits, !pos); + else if (pos && f.is_app() && f.decl().get_decl_kind() == And) { + int num_args = f.num_args(); + for (int i = 0; i < num_args; i++) + CollectConjuncts(f.arg(i), lits, true); + } + else if (!pos && f.is_app() && f.decl().get_decl_kind() == Or) { + int num_args = f.num_args(); + for (int i = 0; i < num_args; i++) + CollectConjuncts(f.arg(i), lits, false); + } + else if (pos) { + if (!eq(f, ctx.bool_val(true))) + lits.push_back(f); + } + else { + if (!eq(f, ctx.bool_val(false))) + lits.push_back(!f); + } } - void Z3User::CollectJuncts(const Term &f, std::vector &lits, decl_kind op, bool negate){ - if(f.is_app() && f.decl().get_decl_kind() == Not) - CollectJuncts(f.arg(0), lits, (op == And) ? Or : And, !negate); - else if(f.is_app() && f.decl().get_decl_kind() == op){ - int num_args = f.num_args(); - for(int i = 0; i < num_args; i++) - CollectJuncts(f.arg(i),lits,op,negate); - } - else { - expr junct = negate ? Negate(f) : f; - lits.push_back(junct); - } + void Z3User::CollectJuncts(const Term &f, std::vector &lits, decl_kind op, bool negate) { + if (f.is_app() && f.decl().get_decl_kind() == Not) + CollectJuncts(f.arg(0), lits, (op == And) ? Or : And, !negate); + else if (f.is_app() && f.decl().get_decl_kind() == op) { + int num_args = f.num_args(); + for (int i = 0; i < num_args; i++) + CollectJuncts(f.arg(i), lits, op, negate); + } + else { + expr junct = negate ? Negate(f) : f; + lits.push_back(junct); + } } struct TermLt { @@ -2591,7 +2561,7 @@ namespace Duality { hash_map memo; int res = SubtermTruth(memo, eu); if(res != 1) - throw "inconsistent projection"; + throw "inconsistent projection"; } #endif @@ -2622,16 +2592,16 @@ namespace Duality { if(memo[under].find(f) != memo[under].end()) return; memo[under].insert(f); - if(f.is_app()){ - if(!under && !f.has_quantifiers()) - return; - decl_kind k = f.decl().get_decl_kind(); - if(k == And || k == Or || k == Implies || k == Iff){ - int num_args = f.num_args(); - for(int i = 0; i < num_args; i++) - GetGroundLitsUnderQuants(memo,f.arg(i),res,under); - return; - } + if (f.is_app()) { + if (!under && !f.has_quantifiers()) + return; + decl_kind k = f.decl().get_decl_kind(); + if (k == And || k == Or || k == Implies || k == Iff) { + int num_args = f.num_args(); + for (int i = 0; i < num_args; i++) + GetGroundLitsUnderQuants(memo, f.arg(i), res, under); + return; + } } else if (f.is_quantifier()){ #if 0 @@ -2712,28 +2682,28 @@ namespace Duality { return g; } - RPFP::Term RPFP::ModelValueAsConstraint(const Term &t){ - if(t.is_array()){ - ArrayValue arr; - Term e = dualModel.eval(t); - EvalArrayTerm(e, arr); - if(arr.defined){ - std::vector cs; - for(std::map::iterator it = arr.entries.begin(), en = arr.entries.end(); it != en; ++it){ - expr foo = select(t,expr(ctx,it->first)) == expr(ctx,it->second); - cs.push_back(foo); - } - return conjoin(cs); + RPFP::Term RPFP::ModelValueAsConstraint(const Term &t) { + if (t.is_array()) { + ArrayValue arr; + Term e = dualModel.eval(t); + EvalArrayTerm(e, arr); + if (arr.defined) { + std::vector cs; + for (std::map::iterator it = arr.entries.begin(), en = arr.entries.end(); it != en; ++it) { + expr foo = select(t, expr(ctx, it->first)) == expr(ctx, it->second); + cs.push_back(foo); + } + return conjoin(cs); + } } - } - else { - expr r = dualModel.get_const_interp(t.decl()); - if(!r.null()){ - expr res = t == expr(ctx,r); - return res; + else { + expr r = dualModel.get_const_interp(t.decl()); + if (!r.null()) { + expr res = t == expr(ctx, r); + return res; + } } - } - return ctx.bool_val(true); + return ctx.bool_val(true); } void RPFP::EvalNodeAsConstraint(Node *p, Transformer &res) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 41bca940d..02c43eaad 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -25,7 +25,7 @@ Revision History: #include"bv_rewriter.h" #include"datatype_rewriter.h" #include"array_rewriter.h" -#include"float_rewriter.h" +#include"fpa_rewriter.h" #include"rewriter_def.h" #include"cooperate.h" @@ -36,7 +36,7 @@ struct evaluator_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; unsigned long long m_max_memory; unsigned m_max_steps; bool m_model_completion; diff --git a/src/muz/base/dl_boogie_proof.cpp b/src/muz/base/dl_boogie_proof.cpp index d11e4a932..42d21dfb9 100644 --- a/src/muz/base/dl_boogie_proof.cpp +++ b/src/muz/base/dl_boogie_proof.cpp @@ -142,7 +142,7 @@ namespace datalog { steps.push_back(step()); obj_map index; index.insert(m_proof, 0); - + for (unsigned j = 0; j < rules.size(); ++j) { proof* p = rules[j]; proof_ref_vector premises(m); diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 2548d1180..7c9c5813b 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -187,10 +187,10 @@ namespace datalog { if (m_trail.get_num_scopes() == 0) { throw default_exception("there are no backtracking points to pop to"); } - if(m_engine.get()){ - if(get_engine() != DUALITY_ENGINE) - throw default_exception("operation is not supported by engine"); - } + if(m_engine.get()){ + if(get_engine() != DUALITY_ENGINE) + throw default_exception("operation is not supported by engine"); + } m_trail.pop_scope(1); } @@ -478,7 +478,7 @@ namespace datalog { void context::add_rule(expr* rl, symbol const& name, unsigned bound) { m_rule_fmls.push_back(rl); m_rule_names.push_back(name); - m_rule_bounds.push_back(bound); + m_rule_bounds.push_back(bound); } void context::flush_add_rules() { @@ -706,7 +706,7 @@ namespace datalog { check_existential_tail(r); check_positive_predicates(r); break; - case DUALITY_ENGINE: + case DUALITY_ENGINE: check_existential_tail(r); check_positive_predicates(r); break; @@ -963,12 +963,12 @@ namespace datalog { // TODO: what? if(get_engine() != DUALITY_ENGINE) { new_query(); - rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); - rule_ref r(m_rule_manager); - for (; it != end; ++it) { + rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); + rule_ref r(m_rule_manager); + for (; it != end; ++it) { r = *it; check_rule(r); - } + } } #endif m_mc = mk_skip_model_converter(); @@ -985,10 +985,10 @@ namespace datalog { flush_add_rules(); break; case DUALITY_ENGINE: - // this lets us use duality with SAS 2013 abstraction - if(quantify_arrays()) - flush_add_rules(); - break; + // this lets us use duality with SAS 2013 abstraction + if(quantify_arrays()) + flush_add_rules(); + break; default: UNREACHABLE(); } @@ -1109,11 +1109,11 @@ namespace datalog { void context::get_raw_rule_formulas(expr_ref_vector& rules, svector& names, vector &bounds){ for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { - expr_ref r = bind_variables(m_rule_fmls[i].get(), true); - rules.push_back(r.get()); - // rules.push_back(m_rule_fmls[i].get()); - names.push_back(m_rule_names[i]); - bounds.push_back(m_rule_bounds[i]); + expr_ref r = bind_variables(m_rule_fmls[i].get(), true); + rules.push_back(r.get()); + // rules.push_back(m_rule_fmls[i].get()); + names.push_back(m_rule_names[i]); + bounds.push_back(m_rule_bounds[i]); } } diff --git a/src/muz/duality/duality_dl_interface.cpp b/src/muz/duality/duality_dl_interface.cpp index 7666b39cf..0ab9762b0 100755 --- a/src/muz/duality/duality_dl_interface.cpp +++ b/src/muz/duality/duality_dl_interface.cpp @@ -77,12 +77,12 @@ namespace Duality { old_rs = 0; } ~duality_data(){ - if(old_rs) - dealloc(old_rs); - if(rpfp) - dealloc(rpfp); - if(ls) - dealloc(ls); + if(old_rs) + dealloc(old_rs); + if(rpfp) + dealloc(rpfp); + if(ls) + (ls); } }; @@ -171,16 +171,16 @@ lbool dl_interface::query(::expr * query) { query_ref = m_ctx.get_manager().mk_false(); else { func_decl_ref query_pred(m_ctx.get_manager()); - query_pred = m_ctx.get_rules().get_output_predicate(); - ptr_vector sorts; - unsigned nargs = query_pred.get()->get_arity(); - expr_ref_vector vars(m_ctx.get_manager()); - for(unsigned i = 0; i < nargs; i++){ - ::sort *s = query_pred.get()->get_domain(i); - vars.push_back(m_ctx.get_manager().mk_var(nargs-1-i,s)); - } - query_ref = m_ctx.get_manager().mk_app(query_pred.get(),nargs,vars.c_ptr()); - query = query_ref.get(); + query_pred = m_ctx.get_rules().get_output_predicate(); + ptr_vector sorts; + unsigned nargs = query_pred.get()->get_arity(); + expr_ref_vector vars(m_ctx.get_manager()); + for(unsigned i = 0; i < nargs; i++){ + ::sort *s = query_pred.get()->get_domain(i); + vars.push_back(m_ctx.get_manager().mk_var(nargs-1-i,s)); + } + query_ref = m_ctx.get_manager().mk_app(query_pred.get(),nargs,vars.c_ptr()); + query = query_ref.get(); } unsigned nrules = rs.get_num_rules(); for(unsigned i = 0; i < nrules; i++){ @@ -250,16 +250,16 @@ lbool dl_interface::query(::expr * query) { while(true){ if(cl.is_app()){ - decl_kind k = cl.decl().get_decl_kind(); - if(k == Implies) - cl = cl.arg(1); - else { - heads.insert(cl.decl()); - break; - } + decl_kind k = cl.decl().get_decl_kind(); + if(k == Implies) + cl = cl.arg(1); + else { + heads.insert(cl.decl()); + break; + } } else if(cl.is_quantifier()) - cl = cl.body(); + cl = cl.body(); else break; } } @@ -268,18 +268,18 @@ lbool dl_interface::query(::expr * query) { ::ast *fa = pinned[i]; if(is_func_decl(fa)){ ::func_decl *fd = to_func_decl(fa); - if(m_ctx.is_predicate(fd)) { - func_decl f(_d->ctx,fd); - if(!heads.contains(fd)){ - int arity = f.arity(); - std::vector args; - for(int j = 0; j < arity; j++) - args.push_back(_d->ctx.fresh_func_decl("X",f.domain(j))()); - expr c = implies(_d->ctx.bool_val(false),f(args)); - c = _d->ctx.make_quant(Forall,args,c); - clauses.push_back(c); - bounds.push_back(UINT_MAX); - } + if (m_ctx.is_predicate(fd)) { + func_decl f(_d->ctx, fd); + if (!heads.contains(fd)) { + int arity = f.arity(); + std::vector args; + for (int j = 0; j < arity; j++) + args.push_back(_d->ctx.fresh_func_decl("X", f.domain(j))()); + expr c = implies(_d->ctx.bool_val(false), f(args)); + c = _d->ctx.make_quant(Forall, args, c); + clauses.push_back(c); + bounds.push_back(UINT_MAX); + } } } } @@ -483,17 +483,17 @@ void dl_interface::display_certificate_non_const(std::ostream& out) { model orig_model = _d->cex.get_tree()->dualModel; for(unsigned i = 0; i < orig_model.num_consts(); i++){ func_decl cnst = orig_model.get_const_decl(i); - if(locals.find(cnst) == locals.end()){ - expr thing = orig_model.get_const_interp(cnst); - mod.register_decl(to_func_decl(cnst.raw()),to_expr(thing.raw())); + if (locals.find(cnst) == locals.end()) { + expr thing = orig_model.get_const_interp(cnst); + mod.register_decl(to_func_decl(cnst.raw()), to_expr(thing.raw())); } } for(unsigned i = 0; i < orig_model.num_funcs(); i++){ func_decl cnst = orig_model.get_func_decl(i); - if(locals.find(cnst) == locals.end()){ - func_interp thing = orig_model.get_func_interp(cnst); - ::func_interp *thing_raw = thing; - mod.register_decl(to_func_decl(cnst.raw()),thing_raw->copy()); + if (locals.find(cnst) == locals.end()) { + func_interp thing = orig_model.get_func_interp(cnst); + ::func_interp *thing_raw = thing; + mod.register_decl(to_func_decl(cnst.raw()), thing_raw->copy()); } } model_v2_pp(out,mod); diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index e2e3680cc..a0af94953 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -110,7 +110,7 @@ struct dl_context { m_trail.push(push_back_vector >(m_collected_cmds->m_names)); } else { - m_context->add_rule(rule, name, bound); + m_context->add_rule(rule, name, bound); } } @@ -260,11 +260,11 @@ public: print_certificate(ctx); break; case l_undef: - if(dlctx.get_status() == datalog::BOUNDED){ - ctx.regular_stream() << "bounded\n"; - print_certificate(ctx); - break; - } + if(dlctx.get_status() == datalog::BOUNDED){ + ctx.regular_stream() << "bounded\n"; + print_certificate(ctx); + break; + } ctx.regular_stream() << "unknown\n"; switch(dlctx.get_status()) { case datalog::INPUT_ERROR: diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index fd1dbb205..9b451811c 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -219,7 +219,7 @@ namespace datalog { class mk_bit_blast::impl { - context & m_context; + context & m_context; ast_manager & m; params_ref m_params; mk_interp_tail_simplifier m_simplifier; diff --git a/src/muz/transforms/dl_transforms.cpp b/src/muz/transforms/dl_transforms.cpp index 9a4667f2c..08404b6e5 100644 --- a/src/muz/transforms/dl_transforms.cpp +++ b/src/muz/transforms/dl_transforms.cpp @@ -72,7 +72,7 @@ namespace datalog { transf.register_plugin(alloc(datalog::mk_bit_blast, ctx, 35000)); if (!ctx.get_params().quantify_arrays()) - transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 36000)); + transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 36000)); transf.register_plugin(alloc(datalog::mk_karr_invariants, ctx, 36010)); if (ctx.get_params().magic()) { transf.register_plugin(alloc(datalog::mk_magic_symbolic, ctx, 36020)); diff --git a/src/qe/nlarith_util.cpp b/src/qe/nlarith_util.cpp index c555b71f1..fce54aaa4 100644 --- a/src/qe/nlarith_util.cpp +++ b/src/qe/nlarith_util.cpp @@ -1492,11 +1492,11 @@ namespace nlarith { } fml = mk_and(equivs.size(), equivs.c_ptr()); } - void mk_plus_inf_sign(util::literal_set const& literals, app_ref& fml, app_ref_vector& new_atoms) { + void mk_pinf_sign(util::literal_set const& literals, app_ref& fml, app_ref_vector& new_atoms) { plus_inf_subst sub(*this); mk_inf_sign(sub, literals, fml, new_atoms); } - void mk_minus_inf_sign(util::literal_set const& literals, app_ref& fml, app_ref_vector& new_atoms) { + void mk_ninf_sign(util::literal_set const& literals, app_ref& fml, app_ref_vector& new_atoms) { minus_inf_subst sub(*this); mk_inf_sign(sub, literals, fml, new_atoms); } @@ -1704,10 +1704,10 @@ namespace nlarith { app_ref fml(m()); app_ref_vector new_atoms(m()); if (is_pos) { - mk_plus_inf_sign(literals, fml, new_atoms); + mk_pinf_sign(literals, fml, new_atoms); } else { - mk_minus_inf_sign(literals, fml, new_atoms); + mk_ninf_sign(literals, fml, new_atoms); } simple_branch* br = alloc(simple_branch, m(), fml); swap_atoms(br, literals.lits(), new_atoms); diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 4775e44a4..1acfcdf57 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -22,6 +22,7 @@ Revision History: #include"arith_simplifier_plugin.h" #include"array_simplifier_plugin.h" #include"datatype_simplifier_plugin.h" +#include"fpa_simplifier_plugin.h" #include"bv_simplifier_plugin.h" #include"for_each_expr.h" #include"well_sorted.h" @@ -96,7 +97,8 @@ void asserted_formulas::setup_simplifier_plugins(simplifier & s, basic_simplifie s.register_plugin(alloc(array_simplifier_plugin, m_manager, *bsimp, s, m_params)); bvsimp = alloc(bv_simplifier_plugin, m_manager, *bsimp, m_params); s.register_plugin(bvsimp); - s.register_plugin(alloc(datatype_simplifier_plugin, m_manager, *bsimp)); + s.register_plugin(alloc(datatype_simplifier_plugin, m_manager, *bsimp)); + s.register_plugin(alloc(fpa_simplifier_plugin, m_manager, *bsimp)); } void asserted_formulas::init(unsigned num_formulas, expr * const * formulas, proof * const * prs) { diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 51b83d61c..d17e4b803 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -30,6 +30,7 @@ Revision History: #include"theory_dummy.h" #include"theory_dl.h" #include"theory_seq_empty.h" +#include"theory_fpa.h" namespace smt { @@ -679,6 +680,15 @@ namespace smt { setup_mi_arith(); } + void setup::setup_QF_FP() { + m_context.register_plugin(alloc(smt::theory_fpa, m_manager)); + } + + void setup::setup_QF_FPBV() { + setup_QF_BV(); + m_context.register_plugin(alloc(smt::theory_fpa, m_manager)); + } + bool is_arith(static_features const & st) { return st.m_num_arith_ineqs > 0 || st.m_num_arith_terms > 0 || st.m_num_arith_eqs > 0; } @@ -780,6 +790,10 @@ namespace smt { m_context.register_plugin(alloc(theory_seq_empty, m_manager)); } + void setup::setup_fpa() { + m_context.register_plugin(alloc(theory_fpa, m_manager)); + } + void setup::setup_unknown() { setup_arith(); setup_arrays(); @@ -787,6 +801,7 @@ namespace smt { setup_datatypes(); setup_dl(); setup_seq(); + setup_fpa(); } void setup::setup_unknown(static_features & st) { @@ -798,6 +813,7 @@ namespace smt { setup_AUFLIA(false); setup_datatypes(); setup_bv(); + setup_fpa(); return; } diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index e0188537e..6cbcb9602 100644 --- a/src/smt/smt_setup.h +++ b/src/smt/smt_setup.h @@ -75,6 +75,8 @@ namespace smt { void setup_QF_AX(static_features const & st); void setup_QF_AUFLIA(); void setup_QF_AUFLIA(static_features const & st); + void setup_QF_FP(); + void setup_QF_FPBV(); void setup_LRA(); void setup_AUFLIA(bool simple_array = true); void setup_AUFLIA(static_features const & st); @@ -91,10 +93,12 @@ namespace smt { void setup_bv(); void setup_arith(); void setup_dl(); - void setup_seq(); + void setup_seq(); void setup_instgen(); void setup_i_arith(); void setup_mi_arith(); + void setup_fpa(); + public: setup(context & c, smt_params & params); void mark_already_configured() { m_already_configured = true; } diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 147d87496..ac9bd5141 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -17,30 +17,816 @@ Revision History: --*/ #include"ast_smt2_pp.h" +#include"smt_context.h" #include"theory_fpa.h" +#include"theory_bv.h" +#include"smt_model_generator.h" namespace smt { + class fpa2bv_conversion_trail_elem : public trail { + ast_manager & m; + obj_map & m_conversions; + expr * m_e; + public: + fpa2bv_conversion_trail_elem(ast_manager & m, obj_map & c, expr * e) : + m(m), m_conversions(c), m_e(e) {} + virtual ~fpa2bv_conversion_trail_elem() {} + virtual void undo(theory_fpa & th) { + expr * v = m_conversions.find(m_e); + m_conversions.remove(m_e); + m.dec_ref(v); + } + }; + + void theory_fpa::fpa2bv_converter_wrapped::mk_const(func_decl * f, expr_ref & result) { + SASSERT(f->get_family_id() == null_family_id); + SASSERT(f->get_arity() == 0); + expr * r; + if (m_const2bv.find(f, r)) { + result = r; + } + else { + sort * s = f->get_range(); + expr_ref bv(m); + bv = m_th.wrap(m.mk_const(f)); + unsigned bv_sz = m_th.m_bv_util.get_bv_size(bv); + unsigned ebits = m_th.m_fpa_util.get_ebits(s); + unsigned sbits = m_th.m_fpa_util.get_sbits(s); + SASSERT(bv_sz == ebits + sbits); + m_th.m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), + m_bv_util.mk_extract(sbits - 2, 0, bv), + result); + SASSERT(m_th.m_fpa_util.is_float(result)); + m_const2bv.insert(f, result); + m.inc_ref(f); + m.inc_ref(result); + } + } + + void theory_fpa::fpa2bv_converter_wrapped::mk_rm_const(func_decl * f, expr_ref & result) { + SASSERT(f->get_family_id() == null_family_id); + SASSERT(f->get_arity() == 0); + expr * r; + if (m_rm_const2bv.find(f, r)) { + result = r; + } + else { + SASSERT(is_rm(f->get_range())); + result = m_th.wrap(m.mk_const(f)); + m_rm_const2bv.insert(f, result); + m.inc_ref(f); + m.inc_ref(result); + } + } + + theory_fpa::theory_fpa(ast_manager & m) : + theory(m.mk_family_id("fpa")), + m_converter(m, this), + m_rw(m, m_converter, params_ref()), + m_th_rw(m), + m_trail_stack(*this), + m_fpa_util(m_converter.fu()), + m_bv_util(m_converter.bu()), + m_arith_util(m_converter.au()) + { + params_ref p; + p.set_bool("arith_lhs", true); + m_th_rw.updt_params(p); + } + + theory_fpa::~theory_fpa() + { + ast_manager & m = get_manager(); + dec_ref_map_values(m, m_conversions); + dec_ref_map_values(m, m_wraps); + dec_ref_map_values(m, m_unwraps); + } + + app * theory_fpa::fpa_value_proc::mk_value(model_generator & mg, ptr_vector & values) { + ast_manager & m = m_th.get_manager(); + + TRACE("t_fpa_detail", for (unsigned i = 0; i < values.size(); i++) + tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;); + + mpf_manager & mpfm = m_fu.fm(); + unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); + unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); + app * result; + + scoped_mpz bias(mpzm); + mpzm.power(mpz(2), m_ebits - 1, bias); + mpzm.dec(bias); + + scoped_mpz sgn_z(mpzm), sig_z(mpzm), exp_z(mpzm); + unsigned bv_sz; + + if (values.size() == 1) { + SASSERT(m_bu.is_bv(values[0])); + SASSERT(m_bu.get_bv_size(values[0]) == (m_ebits + m_sbits)); + + rational all_r(0); + scoped_mpz all_z(mpzm); + + bool r = m_bu.is_numeral(values[0], all_r, bv_sz); + SASSERT(r); + SASSERT(bv_sz == (m_ebits + m_sbits)); + SASSERT(all_r.is_int()); + mpzm.set(all_z, all_r.to_mpq().numerator()); + + mpzm.machine_div2k(all_z, m_ebits + m_sbits - 1, sgn_z); + mpzm.mod(all_z, mpfm.m_powers2(m_ebits + m_sbits - 1), all_z); + + mpzm.machine_div2k(all_z, m_sbits - 1, exp_z); + mpzm.mod(all_z, mpfm.m_powers2(m_sbits - 1), all_z); + + mpzm.set(sig_z, all_z); + } + else if (values.size() == 3) { + rational sgn_r(0), exp_r(0), sig_r(0); + + bool r = m_bu.is_numeral(values[0], sgn_r, bv_sz); + SASSERT(r && bv_sz == 1); + r = m_bu.is_numeral(values[1], exp_r, bv_sz); + SASSERT(r && bv_sz == m_ebits); + r = m_bu.is_numeral(values[2], sig_r, bv_sz); + SASSERT(r && bv_sz == m_sbits - 1); + + SASSERT(sgn_r.to_mpq().denominator() == mpz(1)); + SASSERT(exp_r.to_mpq().denominator() == mpz(1)); + SASSERT(sig_r.to_mpq().denominator() == mpz(1)); + + mpzm.set(sgn_z, sgn_r.to_mpq().numerator()); + mpzm.set(exp_z, exp_r.to_mpq().numerator()); + mpzm.set(sig_z, sig_r.to_mpq().numerator()); + } + else + UNREACHABLE(); + + scoped_mpz exp_u = exp_z - bias; + SASSERT(mpzm.is_int64(exp_u)); + + scoped_mpf f(mpfm); + mpfm.set(f, m_ebits, m_sbits, mpzm.is_one(sgn_z), sig_z, mpzm.get_int64(exp_u)); + result = m_fu.mk_value(f); + + TRACE("t_fpa", tout << "fpa_value_proc::mk_value [" << + mpzm.to_string(sgn_z) << "," << + mpzm.to_string(exp_z) << "," << + mpzm.to_string(sig_z) << "] --> " << + mk_ismt2_pp(result, m_th.get_manager()) << "\n";); + + return result; + } + + app * theory_fpa::fpa_rm_value_proc::mk_value(model_generator & mg, ptr_vector & values) { + SASSERT(values.size() == 1); + ast_manager & m = m_th.get_manager(); + + TRACE("t_fpa_detail", for (unsigned i = 0; i < values.size(); i++) + tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;); + + app * result = 0; + sort * s = m.get_sort(values[0]); + unsigned bv_sz; + + rational val(0); + bool r = m_bu.is_numeral(values[0], val, bv_sz); + SASSERT(r); + SASSERT(bv_sz == 3); + + switch (val.get_uint64()) + { + case BV_RM_TIES_TO_AWAY: result = m_fu.mk_round_nearest_ties_to_away(); break; + case BV_RM_TIES_TO_EVEN: result = m_fu.mk_round_nearest_ties_to_even(); break; + case BV_RM_TO_NEGATIVE: result = m_fu.mk_round_toward_negative(); break; + case BV_RM_TO_POSITIVE: result = m_fu.mk_round_toward_positive(); break; + case BV_RM_TO_ZERO: + default: result = m_fu.mk_round_toward_zero(); + } + + TRACE("t_fpa", tout << "fpa_rm_value_proc::mk_value result: " << + mk_ismt2_pp(result, m_th.get_manager()) << "\n";); + + return result; + } + + app_ref theory_fpa::wrap(expr * e) { + SASSERT(!m_fpa_util.is_wrap(e)); + ast_manager & m = get_manager(); + context & ctx = get_context(); + sort * e_srt = m.get_sort(e); + + func_decl *w; + + if (!m_wraps.find(e_srt, w)) { + SASSERT(!m_wraps.contains(e_srt)); + + sort * bv_srt; + if (m_converter.is_rm(e_srt)) + bv_srt = m_bv_util.mk_sort(3); + else { + SASSERT(m_converter.is_float(e_srt)); + unsigned ebits = m_fpa_util.get_ebits(e_srt); + unsigned sbits = m_fpa_util.get_sbits(e_srt); + bv_srt = m_bv_util.mk_sort(ebits + sbits); + } + + w = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVWRAP, 0, 0, 1, &e_srt, bv_srt); + m_wraps.insert(e_srt, w); + m.inc_ref(w); + } + + app_ref res(m); + res = m.mk_app(w, e); + return res; + } + + app_ref theory_fpa::unwrap(expr * e, sort * s) { + SASSERT(!m_fpa_util.is_unwrap(e)); + ast_manager & m = get_manager(); + context & ctx = get_context(); + sort * bv_srt = m.get_sort(e); + + func_decl *u; + + if (!m_unwraps.find(bv_srt, u)) { + SASSERT(!m_unwraps.contains(bv_srt)); + u = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVUNWRAP, 0, 0, 1, &bv_srt, s); + m_unwraps.insert(bv_srt, u); + m.inc_ref(u); + } + + app_ref res(m); + res = m.mk_app(u, e); + return res; + } + + expr_ref theory_fpa::convert_atom(expr * e) { + ast_manager & m = get_manager(); + expr_ref res(m); + proof_ref pr(m); + m_rw(e, res); + m_th_rw(res, res); + SASSERT(is_app(res)); + SASSERT(m.is_bool(res)); + return res; + } + + expr_ref theory_fpa::convert_term(expr * e) { + ast_manager & m = get_manager(); + + context & ctx = get_context(); + expr_ref e_conv(m), res(m); + proof_ref pr(m); + m_rw(e, e_conv); + + if (m_fpa_util.is_rm(e)) { + SASSERT(is_sort_of(m.get_sort(e_conv), m_bv_util.get_family_id(), BV_SORT)); + SASSERT(m_bv_util.get_bv_size(e_conv) == 3); + m_th_rw(e_conv, res); + } + else if (m_fpa_util.is_float(e)) { + expr_ref sgn(m), sig(m), exp(m); + m_converter.split_fp(e_conv, sgn, exp, sig); + m_th_rw(sgn); + m_th_rw(exp); + m_th_rw(sig); + m_converter.mk_fp(sgn, exp, sig, res); + } + else + UNREACHABLE(); + + SASSERT(res.get() != 0); + return res; + } + + expr_ref theory_fpa::convert_conversion_term(expr * e) { + /* This is for the conversion functions fp.to_* */ + ast_manager & m = get_manager(); + context & ctx = get_context(); + expr_ref res(m); + proof_ref pr(m); + + SASSERT(m_arith_util.is_real(e) || m_bv_util.is_bv(e)); + + m_rw(e, res); + m_th_rw(res, res); + return res; + } + + expr_ref theory_fpa::convert_unwrap(expr * e) { + SASSERT(m_fpa_util.is_unwrap(e)); + ast_manager & m = get_manager(); + sort * srt = m.get_sort(e); + expr_ref res(m); + if (m_fpa_util.is_rm(srt)) { + res = to_app(e)->get_arg(0); + } + else { + SASSERT(m_fpa_util.is_float(srt)); + unsigned ebits = m_fpa_util.get_ebits(srt); + unsigned sbits = m_fpa_util.get_sbits(srt); + expr_ref bv(m); + bv = to_app(e)->get_arg(0); + unsigned bv_sz = m_bv_util.get_bv_size(bv); + m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), + m_bv_util.mk_extract(sbits - 2, 0, bv), + res); + } + return res; + } + + expr_ref theory_fpa::convert(expr * e) + { + ast_manager & m = get_manager(); + context & ctx = get_context(); + expr_ref res(m); + + if (m_conversions.contains(e)) { + res = m_conversions.find(e); + TRACE("t_fpa_detail", tout << "cached:" << std::endl; + tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << + mk_ismt2_pp(res, m) << std::endl;); + return res; + } + else { + if (m_fpa_util.is_unwrap(e)) + res = convert_unwrap(e); + else if (m.is_bool(e)) + res = convert_atom(e); + else if (m_fpa_util.is_float(e) || m_fpa_util.is_rm(e)) + res = convert_term(e); + else if (m_arith_util.is_real(e) || m_bv_util.is_bv(e)) + res = convert_conversion_term(e); + else + UNREACHABLE(); + + TRACE("t_fpa_detail", tout << "converted; caching:" << std::endl; + tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << + mk_ismt2_pp(res, m) << std::endl;); + + m_conversions.insert(e, res); + m.inc_ref(res); + m_trail_stack.push(fpa2bv_conversion_trail_elem(m, m_conversions, e)); + } + + return res; + } + + expr_ref theory_fpa::mk_side_conditions() + { + ast_manager & m = get_manager(); + context & ctx = get_context(); + simplifier & simp = ctx.get_simplifier(); + + expr_ref res(m), t(m); + proof_ref t_pr(m); + res = m.mk_true(); + + expr_ref_vector::iterator it = m_converter.m_extra_assertions.begin(); + expr_ref_vector::iterator end = m_converter.m_extra_assertions.end(); + for (; it != end; it++) { + simp(*it, t, t_pr); + res = m.mk_and(res, t); + } + m_converter.m_extra_assertions.reset(); + + m_th_rw(res); + + CTRACE("t_fpa", !m.is_true(res), tout << "side condition: " << mk_ismt2_pp(res, m) << "\n";); + return res; + } + + void theory_fpa::assert_cnstr(expr * e) { + if (get_manager().is_true(e)) return; + TRACE("t_fpa_detail", tout << "asserting " << mk_ismt2_pp(e, get_manager()) << "\n";); + context & ctx = get_context(); + ctx.internalize(e, false); + literal lit(ctx.get_literal(e)); + ctx.mark_as_relevant(lit); + ctx.mk_th_axiom(get_id(), 1, &lit); + TRACE("t_fpa_detail", tout << "done asserting " << mk_ismt2_pp(e, get_manager()) << "\n";); + } + + void theory_fpa::attach_new_th_var(enode * n) { + context & ctx = get_context(); + theory_var v = mk_var(n); + ctx.attach_th_var(n, this, v); + TRACE("t_fpa_detail", tout << "new theory var: " << mk_ismt2_pp(n->get_owner(), get_manager()) << " := " << v << "\n";); + } + bool theory_fpa::internalize_atom(app * atom, bool gate_ctx) { - TRACE("bv", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << "\n";); + TRACE("t_fpa", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << "\n";); SASSERT(atom->get_family_id() == get_family_id()); - NOT_IMPLEMENTED_YET(); + + ast_manager & m = get_manager(); + context & ctx = get_context(); + + if (ctx.b_internalized(atom)) + return true; + + unsigned num_args = atom->get_num_args(); + for (unsigned i = 0; i < num_args; i++) + ctx.internalize(atom->get_arg(i), false); + + literal l(ctx.mk_bool_var(atom)); + ctx.set_var_theory(l.var(), get_id()); + + expr_ref bv_atom(m); + bv_atom = convert_atom(atom); + SASSERT(is_app(bv_atom) && m.is_bool(bv_atom)); + bv_atom = m.mk_and(bv_atom, mk_side_conditions()); + + assert_cnstr(m.mk_iff(atom, bv_atom)); return true; } - void theory_fpa::new_eq_eh(theory_var, theory_var) { - NOT_IMPLEMENTED_YET(); + bool theory_fpa::internalize_term(app * term) { + ast_manager & m = get_manager(); + context & ctx = get_context(); + TRACE("t_fpa", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";); + SASSERT(term->get_family_id() == get_family_id()); + SASSERT(!ctx.e_internalized(term)); + + unsigned num_args = term->get_num_args(); + for (unsigned i = 0; i < num_args; i++) + ctx.internalize(term->get_arg(i), false); + + enode * e = (ctx.e_internalized(term)) ? ctx.get_enode(term) : + ctx.mk_enode(term, false, false, true); + + if (is_attached_to_var(e)) + return false; + + attach_new_th_var(e); + + // The conversion operators fp.to_* appear in non-FP constraints. + // The corresponding constraints will not be translated and added + // via convert(...) and assert_cnstr(...) in initialize_atom(...). + // Therefore, we translate and assert them here. + fpa_op_kind k = (fpa_op_kind)term->get_decl_kind(); + switch (k) { + case OP_FPA_TO_UBV: + case OP_FPA_TO_SBV: + case OP_FPA_TO_REAL: { + expr_ref conv(m); + conv = convert(term); + assert_cnstr(m.mk_eq(term, conv)); + assert_cnstr(mk_side_conditions()); + break; + } + default: /* ignore */; + } + + return true; + } + + void theory_fpa::apply_sort_cnstr(enode * n, sort * s) { + TRACE("t_fpa", tout << "apply sort cnstr for: " << mk_ismt2_pp(n->get_owner(), get_manager()) << "\n";); + SASSERT(n->get_owner()->get_family_id() == get_family_id() || + n->get_owner()->get_family_id() == null_theory_id); + SASSERT(s->get_family_id() == get_family_id()); + + if (!is_attached_to_var(n)) { + attach_new_th_var(n); + + ast_manager & m = get_manager(); + context & ctx = get_context(); + + app_ref owner(m); + sort_ref owner_sort(m); + owner = n->get_owner(); + owner_sort = m.get_sort(owner); + + if (m_fpa_util.is_rm(owner_sort)) { + // For every RM term, we need to make sure that it's + // associated bit-vector is within the valid range. + if (!m_fpa_util.is_unwrap(owner)) { + expr_ref valid(m), limit(m); + limit = m_bv_util.mk_numeral(4, 3); + valid = m_bv_util.mk_ule(wrap(owner), limit); + assert_cnstr(valid); + } + } + + if (!ctx.relevancy() && !m_fpa_util.is_unwrap(owner)) + assert_cnstr(m.mk_eq(unwrap(wrap(owner), owner_sort), owner)); + } } - void theory_fpa::new_diseq_eh(theory_var, theory_var) { - NOT_IMPLEMENTED_YET(); + void theory_fpa::new_eq_eh(theory_var x, theory_var y) { + ast_manager & m = get_manager(); + + TRACE("t_fpa", tout << "new eq: " << x << " = " << y << std::endl;); + TRACE("t_fpa_detail", tout << mk_ismt2_pp(get_enode(x)->get_owner(), m) << " = " << + mk_ismt2_pp(get_enode(y)->get_owner(), m) << std::endl;); + + context & ctx = get_context(); + fpa_util & fu = m_fpa_util; + bv_util & bu = m_bv_util; + mpf_manager & mpfm = fu.fm(); + + expr_ref xe(m), ye(m); + xe = get_enode(x)->get_owner(); + ye = get_enode(y)->get_owner(); + + if ((m.is_bool(xe) && m.is_bool(ye)) || + (m_bv_util.is_bv(xe) && m_bv_util.is_bv(ye))) { + SASSERT(to_app(xe)->get_decl()->get_family_id() == get_family_id()); + return; + } + + expr_ref xc(m), yc(m); + xc = convert(xe); + yc = convert(ye); + + TRACE("t_fpa_detail", tout << "xc=" << mk_ismt2_pp(xc, m) << std::endl; + tout << "yc=" << mk_ismt2_pp(yc, m) << std::endl;); + + expr_ref c(m); + + if (fu.is_float(xe) && fu.is_float(ye)) + { + expr *x_sgn, *x_sig, *x_exp; + m_converter.split_fp(xc, x_sgn, x_exp, x_sig); + expr *y_sgn, *y_sig, *y_exp; + m_converter.split_fp(yc, y_sgn, y_exp, y_sig); + + c = m.mk_eq(m_bv_util.mk_concat(m_bv_util.mk_concat(x_sgn, x_exp), x_sig), + m_bv_util.mk_concat(m_bv_util.mk_concat(y_sgn, y_exp), y_sig)); + } + else + c = m.mk_eq(xc, yc); + + m_th_rw(c); + assert_cnstr(m.mk_iff(m.mk_eq(xe, ye), c)); + assert_cnstr(mk_side_conditions()); + + return; + } + + void theory_fpa::new_diseq_eh(theory_var x, theory_var y) { + ast_manager & m = get_manager(); + + TRACE("t_fpa", tout << "new diseq: " << x << " != " << y << std::endl;); + TRACE("t_fpa_detail", tout << mk_ismt2_pp(get_enode(x)->get_owner(), m) << " != " << + mk_ismt2_pp(get_enode(y)->get_owner(), m) << std::endl;); + + context & ctx = get_context(); + mpf_manager & mpfm = m_fpa_util.fm(); + + expr_ref xe(m), ye(m); + xe = get_enode(x)->get_owner(); + ye = get_enode(y)->get_owner(); + + if ((m.is_bool(xe) && m.is_bool(ye)) || + (m_bv_util.is_bv(xe) && m_bv_util.is_bv(ye))) { + SASSERT(to_app(xe)->get_decl()->get_family_id() == get_family_id()); + return; + } + + expr_ref xc(m), yc(m); + xc = convert(xe); + yc = convert(ye); + + expr_ref c(m); + + if (m_fpa_util.is_float(xe) && m_fpa_util.is_float(ye)) + { + expr *x_sgn, *x_sig, *x_exp; + m_converter.split_fp(xc, x_sgn, x_exp, x_sig); + expr *y_sgn, *y_sig, *y_exp; + m_converter.split_fp(yc, y_sgn, y_exp, y_sig); + + c = m.mk_not(m.mk_eq(m_bv_util.mk_concat(m_bv_util.mk_concat(x_sgn, x_exp), x_sig), + m_bv_util.mk_concat(m_bv_util.mk_concat(y_sgn, y_exp), y_sig))); + } + else + c = m.mk_not(m.mk_eq(xc, yc)); + + m_th_rw(c); + assert_cnstr(m.mk_iff(m.mk_not(m.mk_eq(xe, ye)), c)); + assert_cnstr(mk_side_conditions()); + + return; } void theory_fpa::push_scope_eh() { - NOT_IMPLEMENTED_YET(); + theory::push_scope_eh(); + m_trail_stack.push_scope(); } - void theory_fpa::pop_scope_eh(unsigned num_scopes) { - NOT_IMPLEMENTED_YET(); + void theory_fpa::pop_scope_eh(unsigned num_scopes) { + m_trail_stack.pop_scope(num_scopes); + TRACE("t_fpa", tout << "pop " << num_scopes << "; now " << m_trail_stack.get_num_scopes() << "\n";); + // unsigned num_old_vars = get_old_num_vars(num_scopes); + theory::pop_scope_eh(num_scopes); + } + + void theory_fpa::assign_eh(bool_var v, bool is_true) { + ast_manager & m = get_manager(); + context & ctx = get_context(); + expr * e = ctx.bool_var2expr(v); + + TRACE("t_fpa", tout << "assign_eh for: " << v << " (" << is_true << "):\n" << mk_ismt2_pp(e, m) << "\n";); + + expr_ref converted(m); + converted = m.mk_and(convert(e), mk_side_conditions()); + if (is_true) + assert_cnstr(m.mk_implies(e, converted)); + else + assert_cnstr(m.mk_implies(m.mk_not(e), m.mk_not(converted))); + } + + void theory_fpa::relevant_eh(app * n) { + ast_manager & m = get_manager(); + TRACE("t_fpa", tout << "relevant_eh for: " << mk_ismt2_pp(n, m) << "\n";); + + mpf_manager & mpfm = m_fpa_util.fm(); + unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); + + if (m_fpa_util.is_float(n) || m_fpa_util.is_rm(n)) { + sort * s = m.get_sort(n); + + if (!m_fpa_util.is_unwrap(n)) { + expr_ref wrapped(m), c(m); + wrapped = wrap(n); + mpf_rounding_mode rm; + scoped_mpf val(mpfm); + if (m_fpa_util.is_rm_numeral(n, rm)) { + c = m.mk_eq(wrapped, m_bv_util.mk_numeral(rm, 3)); + assert_cnstr(c); + } + else if (m_fpa_util.is_numeral(n, val)) { + unsigned sz = val.get().get_ebits() + val.get().get_sbits(); + expr_ref bv_val_e(m); + bv_val_e = convert(n); + SASSERT(is_app(bv_val_e)); + SASSERT(to_app(bv_val_e)->get_num_args() == 3); + app_ref bv_val_a(to_app(bv_val_e.get()), m); + expr * args[] = { bv_val_a->get_arg(0), bv_val_a->get_arg(1), bv_val_a->get_arg(2) }; + c = m.mk_eq(wrapped, m_bv_util.mk_concat(3, args)); + c = m.mk_and(c, mk_side_conditions()); + assert_cnstr(c); + } + else { + c = m.mk_eq(unwrap(wrapped, m.get_sort(n)), n); + assert_cnstr(c); + } + } + } + else if (n->get_family_id() == get_family_id()) { + // These are the conversion functions fp.to_* */ + SASSERT(!m_fpa_util.is_float(n) && !m_fpa_util.is_rm(n)); + } + else + UNREACHABLE(); + } + + void theory_fpa::reset_eh() { + TRACE("t_fpa", tout << "reset_eh\n";); + pop_scope_eh(m_trail_stack.get_num_scopes()); + m_converter.reset(); + m_rw.reset(); + m_th_rw.reset(); + m_trail_stack.pop_scope(m_trail_stack.get_num_scopes()); + if (m_factory) dealloc(m_factory); m_factory = 0; + ast_manager & m = get_manager(); + dec_ref_map_values(m, m_conversions); + dec_ref_map_values(m, m_wraps); + dec_ref_map_values(m, m_unwraps); + theory::reset_eh(); + } + + final_check_status theory_fpa::final_check_eh() { + TRACE("t_fpa", tout << "final_check_eh\n";); + SASSERT(m_converter.m_extra_assertions.empty()); + return FC_DONE; + } + + void theory_fpa::init_model(model_generator & mg) { + TRACE("t_fpa", tout << "initializing model" << std::endl; display(tout);); + m_factory = alloc(fpa_value_factory, get_manager(), get_family_id()); + mg.register_factory(m_factory); + } + + model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) { + TRACE("t_fpa", tout << "mk_value for: " << mk_ismt2_pp(n->get_owner(), get_manager()) << + " (sort " << mk_ismt2_pp(get_manager().get_sort(n->get_owner()), get_manager()) << ")\n";); + + ast_manager & m = get_manager(); + context & ctx = get_context(); + app_ref owner(m); + owner = n->get_owner(); + + // If the owner is not internalized, it doesn't have an enode associated. + SASSERT(ctx.e_internalized(owner)); + + if (m_fpa_util.is_rm_numeral(owner) || + m_fpa_util.is_numeral(owner)) { + return alloc(expr_wrapper_proc, owner); + } + + model_value_proc * res = 0; + + app_ref wrapped(m); + wrapped = wrap(owner); + SASSERT(m_bv_util.is_bv(wrapped)); + + CTRACE("t_fpa_detail", !ctx.e_internalized(wrapped), + tout << "Model dependency not internalized: " << + mk_ismt2_pp(wrapped, m) << + " (owner " << (!ctx.e_internalized(owner) ? "not" : "is") << + " internalized)" << std::endl;); + + if (is_app_of(owner, get_family_id(), OP_FPA_FP)) { + SASSERT(to_app(owner)->get_num_args() == 3); + app_ref a0(m), a1(m), a2(m); + a0 = to_app(owner->get_arg(0)); + a1 = to_app(owner->get_arg(1)); + a2 = to_app(owner->get_arg(2)); + unsigned ebits = m_fpa_util.get_ebits(m.get_sort(owner)); + unsigned sbits = m_fpa_util.get_sbits(m.get_sort(owner)); + fpa_value_proc * vp = alloc(fpa_value_proc, this, ebits, sbits); + vp->add_dependency(ctx.get_enode(a0)); + vp->add_dependency(ctx.get_enode(a1)); + vp->add_dependency(ctx.get_enode(a2)); + TRACE("t_fpa_detail", tout << "Depends on: " << + mk_ismt2_pp(a0, m) << " eq. cls. #" << get_enode(a0)->get_root()->get_owner()->get_id() << std::endl << + mk_ismt2_pp(a1, m) << " eq. cls. #" << get_enode(a1)->get_root()->get_owner()->get_id() << std::endl << + mk_ismt2_pp(a2, m) << " eq. cls. #" << get_enode(a2)->get_root()->get_owner()->get_id() << std::endl;); + res = vp; + } + else if (ctx.e_internalized(wrapped)) { + if (m_fpa_util.is_rm(owner)) { + fpa_rm_value_proc * vp = alloc(fpa_rm_value_proc, this); + vp->add_dependency(ctx.get_enode(wrapped)); + res = vp; + } + else if (m_fpa_util.is_float(owner)) { + unsigned ebits = m_fpa_util.get_ebits(m.get_sort(owner)); + unsigned sbits = m_fpa_util.get_sbits(m.get_sort(owner)); + fpa_value_proc * vp = alloc(fpa_value_proc, this, ebits, sbits); + enode * en = ctx.get_enode(wrapped); + vp->add_dependency(en); + TRACE("t_fpa_detail", tout << "Depends on: " << mk_ismt2_pp(wrapped, m) << " eq. cls. #" << en->get_root()->get_owner()->get_id() << std::endl;); + res = vp; + } + } + else { + unsigned ebits = m_fpa_util.get_ebits(m.get_sort(owner)); + unsigned sbits = m_fpa_util.get_sbits(m.get_sort(owner)); + return alloc(expr_wrapper_proc, m_fpa_util.mk_pzero(ebits, sbits)); + } + + SASSERT(res != 0); + return res; + } + + void theory_fpa::finalize_model(model_generator & mg) {} + + void theory_fpa::display(std::ostream & out) const + { + ast_manager & m = get_manager(); + context & ctx = get_context(); + + out << "fpa theory variables:" << std::endl; + ptr_vector::const_iterator it = ctx.begin_enodes(); + ptr_vector::const_iterator end = ctx.end_enodes(); + for (; it != end; it++) { + theory_var v = (*it)->get_th_var(get_family_id()); + if (v != -1) out << v << " -> " << + mk_ismt2_pp((*it)->get_owner(), m) << std::endl; + } + + out << "bv theory variables:" << std::endl; + it = ctx.begin_enodes(); + end = ctx.end_enodes(); + for (; it != end; it++) { + theory_var v = (*it)->get_th_var(m_bv_util.get_family_id()); + if (v != -1) out << v << " -> " << + mk_ismt2_pp((*it)->get_owner(), m) << std::endl; + } + + out << "arith theory variables:" << std::endl; + it = ctx.begin_enodes(); + end = ctx.end_enodes(); + for (; it != end; it++) { + theory_var v = (*it)->get_th_var(m_arith_util.get_family_id()); + if (v != -1) out << v << " -> " << + mk_ismt2_pp((*it)->get_owner(), m) << std::endl; + } + + out << "equivalence classes:\n"; + it = ctx.begin_enodes(); + end = ctx.end_enodes(); + for (; it != end; ++it) { + expr * n = (*it)->get_owner(); + expr * r = (*it)->get_root()->get_owner(); + out << r->get_id() << " --> " << mk_ismt2_pp(n, m) << std::endl; + } } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 3716247d3..33733d7d9 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -20,26 +20,173 @@ Revision History: #define _THEORY_FPA_H_ #include"smt_theory.h" +#include"trail.h" #include"fpa2bv_converter.h" +#include"fpa2bv_rewriter.h" +#include"th_rewriter.h" +#include"value_factory.h" +#include"smt_model_generator.h" namespace smt { - class theory_fpa : public theory { - fpa2bv_converter m_converter; - virtual final_check_status final_check_eh() { return FC_DONE; } - virtual bool internalize_atom(app*, bool); - virtual bool internalize_term(app*) { return internalize_atom(0, false); } + class fpa_value_factory : public value_factory { + fpa_util m_util; + + virtual app * mk_value_core(mpf const & val, sort * s) { + SASSERT(m_util.get_ebits(s) == val.get_ebits()); + SASSERT(m_util.get_sbits(s) == val.get_sbits()); + return m_util.mk_value(val); + } + + public: + fpa_value_factory(ast_manager & m, family_id fid) : + value_factory(m, fid), + m_util(m) {} + + virtual ~fpa_value_factory() {} + + virtual expr * get_some_value(sort * s) { + mpf_manager & mpfm = m_util.fm(); + scoped_mpf q(mpfm); + mpfm.set(q, m_util.get_ebits(s), m_util.get_sbits(s), 0); + return m_util.mk_value(q); + } + + virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { + mpf_manager & mpfm = m_util.fm(); + scoped_mpf q(mpfm); + mpfm.set(q, m_util.get_ebits(s), m_util.get_sbits(s), 0); + v1 = m_util.mk_value(q); + mpfm.set(q, m_util.get_ebits(s), m_util.get_sbits(s), 1); + v2 = m_util.mk_value(q); + return true; + } + + virtual expr * get_fresh_value(sort * s) { NOT_IMPLEMENTED_YET(); } + virtual void register_value(expr * n) { /* Ignore */ } + + app * mk_value(mpf const & x) { + return m_util.mk_value(x); + } + }; + + class theory_fpa : public theory { + protected: + typedef trail_stack th_trail_stack; + + class fpa2bv_converter_wrapped : public fpa2bv_converter { + public: + theory_fpa & m_th; + fpa2bv_converter_wrapped(ast_manager & m, theory_fpa * th) : + fpa2bv_converter(m), + m_th(*th) {} + virtual ~fpa2bv_converter_wrapped() {} + virtual void mk_const(func_decl * f, expr_ref & result); + virtual void mk_rm_const(func_decl * f, expr_ref & result); + }; + + class fpa_value_proc : public model_value_proc { + protected: + theory_fpa & m_th; + ast_manager & m; + fpa_util & m_fu; + bv_util & m_bu; + buffer m_deps; + unsigned m_ebits; + unsigned m_sbits; + + public: + fpa_value_proc(theory_fpa * th, unsigned ebits, unsigned sbits) : + m_th(*th), m_fu(th->m_fpa_util), m_bu(th->m_bv_util), m(th->get_manager()), + m_ebits(ebits), m_sbits(sbits) {} + + virtual ~fpa_value_proc() {} + + void add_dependency(enode * e) { m_deps.push_back(model_value_dependency(e)); } + + virtual void get_dependencies(buffer & result) { + result.append(m_deps); + } + + virtual app * mk_value(model_generator & mg, ptr_vector & values); + }; + + class fpa_rm_value_proc : public model_value_proc { + theory_fpa & m_th; + ast_manager & m; + fpa_util & m_fu; + bv_util & m_bu; + buffer m_deps; + + public: + fpa_rm_value_proc(theory_fpa * th) : + m_th(*th), m_fu(th->m_fpa_util), m_bu(th->m_bv_util), m(th->get_manager()) {} + + void add_dependency(enode * e) { m_deps.push_back(model_value_dependency(e)); } + + virtual void get_dependencies(buffer & result) { + result.append(m_deps); + } + + virtual ~fpa_rm_value_proc() {} + virtual app * mk_value(model_generator & mg, ptr_vector & values); + }; + + protected: + fpa2bv_converter_wrapped m_converter; + fpa2bv_rewriter m_rw; + th_rewriter m_th_rw; + th_trail_stack m_trail_stack; + fpa_value_factory * m_factory; + fpa_util & m_fpa_util; + bv_util & m_bv_util; + arith_util & m_arith_util; + obj_map m_wraps; + obj_map m_unwraps; + obj_map m_conversions; + + virtual final_check_status final_check_eh(); + virtual bool internalize_atom(app * atom, bool gate_ctx); + virtual bool internalize_term(app * term); + virtual void apply_sort_cnstr(enode * n, sort * s); virtual void new_eq_eh(theory_var, theory_var); virtual void new_diseq_eh(theory_var, theory_var); virtual void push_scope_eh(); virtual void pop_scope_eh(unsigned num_scopes); + virtual void reset_eh(); virtual theory* mk_fresh(context*) { return alloc(theory_fpa, get_manager()); } - virtual char const * get_name() const { return "fpa"; } + virtual char const * get_name() const { return "fpa"; } + + virtual model_value_proc * mk_value(enode * n, model_generator & mg); + + void assign_eh(bool_var v, bool is_true); + virtual void relevant_eh(app * n); + virtual void init_model(model_generator & m); + virtual void finalize_model(model_generator & mg); + public: - theory_fpa(ast_manager& m) : theory(m.mk_family_id("fpa")), m_converter(m) {} + theory_fpa(ast_manager& m); + virtual ~theory_fpa(); + + virtual void display(std::ostream & out) const; + + protected: + expr_ref mk_side_conditions(); + expr_ref convert(expr * e); + expr_ref convert_atom(expr * e); + expr_ref convert_term(expr * e); + expr_ref convert_conversion_term(expr * e); + expr_ref convert_unwrap(expr * e); + + void add_trail(ast * a); + + void attach_new_th_var(enode * n); + void assert_cnstr(expr * e); + + app_ref wrap(expr * e); + app_ref unwrap(expr * e, sort * s); }; }; #endif /* _THEORY_FPA_H_ */ - diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index 9fdce96e9..e3101ad67 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -27,7 +27,7 @@ Notes: struct aig; class aig_lit { - friend class aig_ref; + friend class aig_ref; aig * m_ref; public: aig_lit(aig * n = 0):m_ref(n) {} @@ -1508,10 +1508,10 @@ public: template aig_lit mk_aig(S const & s) { aig_lit r; - r = m_true; - inc_ref(r); + r = m_true; + inc_ref(r); try { - expr2aig proc(*this); + expr2aig proc(*this); unsigned sz = s.size(); for (unsigned i = 0; i < sz; i++) { SASSERT(ref_count(r) >= 1); @@ -1528,10 +1528,10 @@ public: } SASSERT(ref_count(r) >= 1); } - catch (aig_exception ex) { - dec_ref(r); - throw ex; - } + catch (aig_exception ex) { + dec_ref(r); + throw ex; + } dec_ref_result(r); return r; } diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 53fa2405b..5c12cbd8f 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -85,7 +85,7 @@ model_converter * fpa2bv_model_converter::translate(ast_translation & translator } void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { - float_util fu(m); + fpa_util fu(m); bv_util bu(m); mpf fp_val; unsynch_mpz_manager & mpzm = fu.fm().mpz_manager(); @@ -112,16 +112,16 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { unsigned sbits = fu.get_sbits(var->get_range()); expr_ref sgn(m), sig(m), exp(m); - bv_mdl->eval(a->get_arg(0), sgn, true); - bv_mdl->eval(a->get_arg(1), sig, true); - bv_mdl->eval(a->get_arg(2), exp, true); + bv_mdl->eval(a->get_arg(0), sgn, true); + bv_mdl->eval(a->get_arg(1), exp, true); + bv_mdl->eval(a->get_arg(2), sig, true); - SASSERT(a->is_app_of(fu.get_family_id(), OP_TO_FLOAT)); + SASSERT(a->is_app_of(fu.get_family_id(), OP_FPA_FP)); #ifdef Z3DEBUG SASSERT(to_app(a->get_arg(0))->get_decl()->get_arity() == 0); SASSERT(to_app(a->get_arg(1))->get_decl()->get_arity() == 0); - SASSERT(to_app(a->get_arg(1))->get_decl()->get_arity() == 0); + SASSERT(to_app(a->get_arg(2))->get_decl()->get_arity() == 0); seen.insert(to_app(a->get_arg(0))->get_decl()); seen.insert(to_app(a->get_arg(1))->get_decl()); seen.insert(to_app(a->get_arg(2))->get_decl()); @@ -134,9 +134,9 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { if (!sgn && !sig && !exp) continue; - unsigned sgn_sz = bu.get_bv_size(m.get_sort(a->get_arg(0))); - unsigned sig_sz = bu.get_bv_size(m.get_sort(a->get_arg(1))) - 1; - unsigned exp_sz = bu.get_bv_size(m.get_sort(a->get_arg(2))); + unsigned sgn_sz = bu.get_bv_size(m.get_sort(a->get_arg(0))); + unsigned exp_sz = bu.get_bv_size(m.get_sort(a->get_arg(1))); + unsigned sig_sz = bu.get_bv_size(m.get_sort(a->get_arg(2))) - 1; rational sgn_q(0), sig_q(0), exp_q(0); @@ -167,14 +167,15 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { it++) { func_decl * var = it->m_key; - app * a = to_app(it->m_value); + expr * v = it->m_value; + expr_ref eval_v(m); SASSERT(fu.is_rm(var->get_range())); - rational val(0); + rational bv_val(0); unsigned sz = 0; - if (a && bu.is_numeral(a, val, sz)) { - TRACE("fpa2bv_mc", tout << var->get_name() << " == " << val.to_string() << std::endl;); - SASSERT(val.is_uint64()); - switch (val.get_uint64()) + if (v && bv_mdl->eval(v, eval_v, true) && bu.is_numeral(eval_v, bv_val, sz)) { + TRACE("fpa2bv_mc", tout << var->get_name() << " == " << bv_val.to_string() << std::endl;); + SASSERT(bv_val.is_uint64()); + switch (bv_val.get_uint64()) { case BV_RM_TIES_TO_AWAY: float_mdl->register_decl(var, fu.mk_round_nearest_ties_to_away()); break; case BV_RM_TIES_TO_EVEN: float_mdl->register_decl(var, fu.mk_round_nearest_ties_to_even()); break; @@ -183,7 +184,8 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { case BV_RM_TO_ZERO: default: float_mdl->register_decl(var, fu.mk_round_toward_zero()); } - seen.insert(var); + SASSERT(v->get_kind() == AST_APP); + seen.insert(to_app(v)->get_decl()); } } diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index 4a3a01b6f..5fb35d972 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -96,8 +96,8 @@ class fpa2bv_tactic : public tactic { g->inc_depth(); result.push_back(g.get()); - for (unsigned i = 0; i < m_conv.extra_assertions.size(); i++) - result.back()->assert_expr(m_conv.extra_assertions[i].get()); + for (unsigned i = 0; i < m_conv.m_extra_assertions.size(); i++) + result.back()->assert_expr(m_conv.m_extra_assertions[i].get()); SASSERT(g->is_well_sorted()); TRACE("fpa2bv", tout << "AFTER: " << std::endl; g->display(tout); diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp new file mode 100644 index 000000000..6b081f0a5 --- /dev/null +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -0,0 +1,100 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + qffpa_tactic.cpp + +Abstract: + + Tactic for QF_FP benchmarks. + +Author: + + Christoph (cwinter) 2012-01-16 + +Notes: + +--*/ +#include"tactical.h" +#include"simplify_tactic.h" +#include"bit_blaster_tactic.h" +#include"sat_tactic.h" +#include"fpa2bv_tactic.h" +#include"smt_tactic.h" +#include"propagate_values_tactic.h" + +#include"qffp_tactic.h" + +tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { + params_ref simp_p = p; + simp_p.set_bool("arith_lhs", true); + simp_p.set_bool("elim_and", true); + + tactic * st = and_then(mk_simplify_tactic(m, simp_p), + mk_propagate_values_tactic(m, p), + cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), + mk_smt_tactic(), + and_then( + mk_fpa2bv_tactic(m, p), + using_params(mk_simplify_tactic(m, p), simp_p), + mk_bit_blaster_tactic(m, p), + using_params(mk_simplify_tactic(m, p), simp_p), + cond(mk_is_propositional_probe(), + mk_sat_tactic(m, p), + mk_smt_tactic(p)), + mk_fail_if_undecided_tactic()))); + + st->updt_params(p); + return st; +} + +tactic * mk_qffpbv_tactic(ast_manager & m, params_ref const & p) { + return mk_qffp_tactic(m, p); +} + +struct is_non_qffp_predicate { + struct found {}; + ast_manager & m; + bv_util bu; + fpa_util fu; + arith_util au; + + is_non_qffp_predicate(ast_manager & _m) : m(_m), bu(m), fu(m), au(m) {} + + void operator()(var *) { throw found(); } + + void operator()(quantifier *) { throw found(); } + + void operator()(app * n) { + sort * s = get_sort(n); + if (!m.is_bool(s) && !fu.is_float(s) && !fu.is_rm(s) && !bu.is_bv_sort(s) && !au.is_real(s)) + throw found(); + family_id fid = n->get_family_id(); + if (fid == m.get_basic_family_id()) + return; + if (fid == fu.get_family_id() || fid == bu.get_family_id()) + return; + if (is_uninterp_const(n)) + return; + if (au.is_real(s) && au.is_numeral(n)) + return; + + throw found(); + } +}; + +class is_qffp_probe : public probe { +public: + virtual result operator()(goal const & g) { + return !test(g); + } +}; + +probe * mk_is_qffp_probe() { + return alloc(is_qffp_probe); +} + +probe * mk_is_qffpbv_probe() { + return alloc(is_qffp_probe); +} diff --git a/src/tactic/fpa/qffp_tactic.h b/src/tactic/fpa/qffp_tactic.h new file mode 100644 index 000000000..5c8caba2b --- /dev/null +++ b/src/tactic/fpa/qffp_tactic.h @@ -0,0 +1,41 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + qffp_tactic.h + +Abstract: + + Tactic for QF_FP benchmarks. + +Author: + + Christoph (cwinter) 2012-01-16 + +Notes: + + +--*/ +#ifndef _QFFP_TACTIC_H_ +#define _QFFP_TACTIC_H_ + +#include"params.h" +class ast_manager; +class tactic; + +tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p = params_ref()); +tactic * mk_qffpbv_tactic(ast_manager & m, params_ref const & p = params_ref()); +/* + ADD_TACTIC("qffp", "(try to) solve goal using the tactic for QF_FP.", "mk_qffp_tactic(m, p)") + ADD_TACTIC("qffpbv", "(try to) solve goal using the tactic for QF_FPBV (floats+bit-vectors).", "mk_qffpbv_tactic(m, p)") +*/ + +probe * mk_is_qffp_probe(); +probe * mk_is_qffpbv_probe(); +/* + ADD_PROBE("is-qffp", "true if the goal is in QF_FP (floats).", "mk_is_qffp_probe()") + ADD_PROBE("is-qffpbv", "true if the goal is in QF_FPBV (floats+bit-vectors).", "mk_is_qffpbv_probe()") +*/ + +#endif diff --git a/src/tactic/fpa/qffpa_tactic.cpp b/src/tactic/fpa/qffpa_tactic.cpp deleted file mode 100644 index f9b7f88a1..000000000 --- a/src/tactic/fpa/qffpa_tactic.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - qffpa_tactic.cpp - -Abstract: - - Tactic for QF_FPA benchmarks. - -Author: - - Christoph (cwinter) 2012-01-16 - -Notes: - ---*/ -#include"tactical.h" -#include"simplify_tactic.h" -#include"bit_blaster_tactic.h" -#include"sat_tactic.h" -#include"fpa2bv_tactic.h" - -#include"qffpa_tactic.h" - -tactic * mk_qffpa_tactic(ast_manager & m, params_ref const & p) { - params_ref sat_simp_p = p; - sat_simp_p .set_bool("elim_and", true); - - return and_then(mk_simplify_tactic(m, p), - mk_fpa2bv_tactic(m, p), - using_params(mk_simplify_tactic(m, p), sat_simp_p), - mk_bit_blaster_tactic(m, p), - using_params(mk_simplify_tactic(m, p), sat_simp_p), - mk_sat_tactic(m, p), - mk_fail_if_undecided_tactic()); -} - -struct is_non_qffpa_predicate { - struct found {}; - ast_manager & m; - float_util u; - - is_non_qffpa_predicate(ast_manager & _m) : m(_m), u(m) {} - - void operator()(var *) { throw found(); } - - void operator()(quantifier *) { throw found(); } - - void operator()(app * n) { - sort * s = get_sort(n); - if (!m.is_bool(s) && !u.is_float(s) && !u.is_rm(s)) - throw found(); - family_id fid = n->get_family_id(); - if (fid == m.get_basic_family_id()) - return; - if (fid == u.get_family_id()) - return; - if (is_uninterp_const(n)) - return; - - throw found(); - } -}; - -struct is_non_qffpabv_predicate { - struct found {}; - ast_manager & m; - bv_util bu; - float_util fu; - - is_non_qffpabv_predicate(ast_manager & _m) : m(_m), bu(m), fu(m) {} - - void operator()(var *) { throw found(); } - - void operator()(quantifier *) { throw found(); } - - void operator()(app * n) { - sort * s = get_sort(n); - if (!m.is_bool(s) && !fu.is_float(s) && !fu.is_rm(s) && !bu.is_bv_sort(s)) - throw found(); - family_id fid = n->get_family_id(); - if (fid == m.get_basic_family_id()) - return; - if (fid == fu.get_family_id() || fid == bu.get_family_id()) - return; - if (is_uninterp_const(n)) - return; - - throw found(); - } -}; - -class is_qffpa_probe : public probe { -public: - virtual result operator()(goal const & g) { - return !test(g); - } -}; - -class is_qffpabv_probe : public probe { -public: - virtual result operator()(goal const & g) { - return !test(g); - } -}; - -probe * mk_is_qffpa_probe() { - return alloc(is_qffpa_probe); -} - -probe * mk_is_qffpabv_probe() { - return alloc(is_qffpabv_probe); -} - \ No newline at end of file diff --git a/src/tactic/fpa/qffpa_tactic.h b/src/tactic/fpa/qffpa_tactic.h deleted file mode 100644 index cd16c5817..000000000 --- a/src/tactic/fpa/qffpa_tactic.h +++ /dev/null @@ -1,40 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - qffpa_tactic.h - -Abstract: - - Tactic QF_FPA benchmarks. - -Author: - - Christoph (cwinter) 2012-01-16 - -Notes: - - ---*/ -#ifndef _QFFPA_TACTIC_H_ -#define _QFFPA_TACTIC_H_ - -#include"params.h" -class ast_manager; -class tactic; - -tactic * mk_qffpa_tactic(ast_manager & m, params_ref const & p = params_ref()); -/* - ADD_TACTIC("qffpa", "(try to) solve goal using the tactic for QF_FPA.", "mk_qffpa_tactic(m, p)") - ADD_TACTIC("qffpabv", "(try to) solve goal using the tactic for QF_FPABV (floats+bit-vectors).", "mk_qffpa_tactic(m, p)") -*/ - -probe * mk_is_qffpa_probe(); -probe * mk_is_qffpabv_probe(); -/* - ADD_PROBE("is-qffpa", "true if the goal is in QF_FPA (FloatingPoints).", "mk_is_qffpa_probe()") - ADD_PROBE("is-qffpabv", "true if the goal is in QF_FPABV (FloatingPoints+Bitvectors).", "mk_is_qffpabv_probe()") -*/ - -#endif diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 4bd82b969..6419098bc 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -27,7 +27,7 @@ Notes: #include"nra_tactic.h" #include"probe_arith.h" #include"quant_tactics.h" -#include"qffpa_tactic.h" +#include"qffp_tactic.h" #include"qfaufbv_tactic.h" #include"qfauflia_tactic.h" @@ -42,8 +42,8 @@ tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { cond(mk_is_qfnia_probe(), mk_qfnia_tactic(m), cond(mk_is_nra_probe(), mk_nra_tactic(m), cond(mk_is_lira_probe(), mk_lira_tactic(m, p), - cond(mk_is_qffpabv_probe(), mk_qffpa_tactic(m, p), - mk_smt_tactic()))))))))))), + cond(mk_is_qffp_probe(), mk_qffp_tactic(m, p), + mk_smt_tactic()))))))))), p); return st; } diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 586c3a349..d8f23fc71 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -33,7 +33,7 @@ Notes: #include"qfidl_tactic.h" #include"default_tactic.h" #include"ufbv_tactic.h" -#include"qffpa_tactic.h" +#include"qffp_tactic.h" #include"horn_tactic.h" #include"smt_solver.h" @@ -78,10 +78,10 @@ tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const return mk_ufbv_tactic(m, p); else if (logic=="BV") return mk_ufbv_tactic(m, p); - else if (logic=="QF_FPA") - return mk_qffpa_tactic(m, p); - else if (logic=="QF_FPABV") - return mk_qffpa_tactic(m, p); + else if (logic=="QF_FP") + return mk_qffp_tactic(m, p); + else if (logic == "QF_FPBV") + return mk_qffpbv_tactic(m, p); else if (logic=="HORN") return mk_horn_tactic(m, p); else diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index f5785c072..acf6eae39 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -196,38 +196,51 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode else { o.ebits = ebits; o.sbits = sbits; - o.sign = m_mpq_manager.is_neg(value); - - m_mpz_manager.set(o.significand, 0); - const mpz & p = m_powers2(sbits+2); - signed lz = 0; + o.sign = m_mpq_manager.is_neg(value); - o.exponent = sbits+2; + scoped_mpq x(m_mpq_manager); + m_mpq_manager.set(x, value); + m_mpq_manager.abs(x); + + m_mpz_manager.set(o.significand, 0); + const mpz & p = m_powers2(sbits+3); + + scoped_mpq v(m_mpq_manager); + m_mpq_manager.set(v, x); + o.exponent = 0; - // CMW: This could be optimized considerably. - scoped_mpz t(m_mpz_manager); - retry: - m_mpz_manager.mul2k(value.numerator(), lz, t); - m_mpz_manager.machine_div(t, value.denominator(), o.significand); - m_mpz_manager.abs(o.significand); - if (m_mpz_manager.lt(o.significand, p)) { - lz++; - goto retry; - } - o.exponent -= lz; - - bool sticky = false; - while (m_mpz_manager.ge(o.significand, m_powers2(sbits+3))) { - sticky = sticky || !m_mpz_manager.is_even(o.significand); - m_mpz_manager.machine_div2k(o.significand, 1); + // Normalize + while (m_mpq_manager.ge(v, mpq(2))) + { + m_mpq_manager.div(v, mpq(2), v); o.exponent++; } - if (sticky && m_mpz_manager.is_even(o.significand)) - m_mpz_manager.inc(o.significand); - TRACE("mpf_dbg", tout << "QUOTIENT = " << m_mpz_manager.to_string(o.significand) << " shift=" << lz << std::endl;); + while (m_mpq_manager.lt(v, mpq(1))) + { + m_mpq_manager.mul(v, mpq(2), v); + o.exponent--; + } - SASSERT(m_mpz_manager.ge(o.significand, m_powers2(sbits+2))); + m_mpz_manager.set(o.significand, 0); + SASSERT(m_mpq_manager.lt(v, mpq(2))); + SASSERT(m_mpq_manager.ge(v, mpq(1))); + + // 1.0 <= v < 2.0 (* 2^o.exponent) + // (and v != 0.0) + for (unsigned i = 0; i < sbits + 3 ; i++) + { + m_mpz_manager.mul2k(o.significand, 1); + if (m_mpq_manager.ge(v, mpq(1))) { + m_mpz_manager.inc(o.significand); + m_mpq_manager.dec(v); // v := v - 1.0 + } + m_mpq_manager.mul(mpq(2), v, v); // v := 2.0 * v + } + + TRACE("mpf_dbg", tout << "rnd sig=" << m_mpz_manager.to_string(o.significand) << + " exp=" << o.exponent << std::endl;); + round(rm, o); } @@ -253,7 +266,6 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode TRACE("mpf_dbg", tout << " f = " << f << " e = " << e << std::endl;); - // [Leo]: potential memory leak. moving q and ex to scoped versions scoped_mpq q(m_mpq_manager); m_mpq_manager.set(q, f.c_str()); @@ -276,9 +288,6 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode if (m_mpq_manager.is_zero(significand)) mk_zero(ebits, sbits, o.sign, o); else { - // [Leo]: The following two lines may produce a memory leak. Moving to scoped version - // mpq sig; - // mpz exp; scoped_mpq sig(m_mpq_manager); scoped_mpz exp(m_mpq_manager); @@ -296,34 +305,42 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode m_mpq_manager.mul(sig, 2, sig); m_mpz_manager.dec(exp); } - + // 1.0 <= sig < 2.0 SASSERT((m_mpq_manager.le(1, sig) && m_mpq_manager.lt(sig, 2))); - TRACE("mpf_dbg", tout << "sig = " << m_mpq_manager.to_string(sig) << " exp = " << m_mpz_manager.to_string(exp) << std::endl;); - + TRACE("mpf_dbg", tout << "sig = " << m_mpq_manager.to_string(sig) << + " exp = " << m_mpz_manager.to_string(exp) << std::endl;); + m_mpz_manager.set(o.significand, 0); for (unsigned i = 0; i < (sbits+3); i++) { m_mpz_manager.mul2k(o.significand, 1); - if (!m_mpq_manager.lt(sig, 1)) { - m_mpz_manager.inc(o.significand); + if (m_mpq_manager.ge(sig, 1)) { + m_mpz_manager.inc(o.significand); m_mpq_manager.dec(sig); } - m_mpq_manager.mul(sig, 2, sig); + m_mpq_manager.mul(sig, mpq(2), sig); } + + // sticky + if (!m_mpq_manager.is_zero(sig) && m_mpz_manager.is_even(o.significand)) + m_mpz_manager.inc(o.significand); + + TRACE("mpf_dbg", tout << "sig = " << m_mpz_manager.to_string(o.significand) << + " exp = " << o.exponent << std::endl;); if (m_mpz_manager.is_small(exp)) { o.exponent = m_mpz_manager.get_int64(exp); round(rm, o); } else - mk_inf(ebits, sbits, o.sign, o); // CMW: output warning message? throw exception? + mk_inf(ebits, sbits, o.sign, o); } TRACE("mpf_dbg", tout << "set: res = " << to_string(o) << std::endl;); } -void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, bool sign, uint64 significand, int exponent) { +void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, bool sign, uint64 significand, mpf_exp_t exponent) { // Assumption: this represents (sign * -1) * (significand/2^sbits) * 2^exponent. o.ebits = ebits; o.sbits = sbits; @@ -1168,14 +1185,13 @@ std::string mpf_manager::to_string(mpf const & x) { if (is_nan(x)) res = "NaN"; - else { - res = sgn(x) ? "-" : "+"; - + else { if (is_inf(x)) - res += "INF"; + res = sgn(x) ? "-oo" : "+oo"; else if (is_zero(x)) - res += "0"; + res = sgn(x) ? "-zero" : "+zero"; else { + res = sgn(x) ? "-" : ""; scoped_mpz num(m_mpq_manager), denom(m_mpq_manager); num = 0; denom = 1; @@ -1203,7 +1219,9 @@ std::string mpf_manager::to_string(mpf const & x) { std::stringstream ss; m_mpq_manager.display_decimal(ss, r, x.sbits); - ss << "p" << exponent; // "p" means 2^exp + if (m_mpq_manager.is_int(r)) + ss << ".0"; + ss << " " << exponent; res += ss.str(); } } diff --git a/src/util/mpf.h b/src/util/mpf.h index 83646f9f3..599e8e743 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -75,7 +75,7 @@ public: void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpq const & value); void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, char const * value); void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpq const & significand, mpz const & exponent); - void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, uint64 significand, int exponent); + void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, uint64 significand, mpf_exp_t exponent); void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpz const & significand, mpf_exp_t exponent); void set(mpf & o, mpf const & x); void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpf const & x); @@ -146,7 +146,24 @@ public: bool sgn(mpf const & x) const { return x.sign; } const mpz & sig(mpf const & x) const { return x.significand; } + mpz sig_normalized(mpf const & x) { + mpf t; + set(t, x); + unpack(t, true); + mpz r; + mpz_manager().set(r, t.significand); + del(t); + return r; + } const mpf_exp_t & exp(mpf const & x) const { return x.exponent; } + mpf_exp_t exp_normalized(mpf const & x) { + mpf t; + set(t, x); + unpack(t, true); + mpf_exp_t r = t.exponent; + del(t); + return r; + } bool is_nan(mpf const & x); bool is_inf(mpf const & x);