From 9b13ca5260b671904942fccaf25b5ed892a0860f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 6 Jun 2013 14:50:01 +0100 Subject: [PATCH 001/118] Added first FPA API functions. Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_project.py | 2 +- src/api/api_fpa.cpp | 107 ++++++++++++++++++++++++++++++++++++++++++ src/api/z3.h | 1 + src/api/z3_fpa.h | 82 ++++++++++++++++++++++++++++++++ 4 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 src/api/api_fpa.cpp create mode 100644 src/api/z3_fpa.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index e6e7d5dc8..e2bbd20ca 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -59,7 +59,7 @@ def init_project_def(): add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'muz_qe', 'sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('smtparser', ['portfolio'], 'parsers/smt') - API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h'] + API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_fpa.h'] add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure'], includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) add_exe('shell', ['api', 'sat', 'extra_cmds'], exe_name='z3') diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp new file mode 100644 index 000000000..8e8493d63 --- /dev/null +++ b/src/api/api_fpa.cpp @@ -0,0 +1,107 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + api_fpa.cpp + +Abstract: + + +Author: + + Christoph M. Wintersteiger (cwinter) 2013-06-05 + +Notes: + +--*/ +#include +#include"z3.h" +#include"api_log_macros.h" +#include"api_context.h" +#include"float_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(float_util(ctx->m()).mk_rm_sort()); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_even(__in 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(float_util(ctx->m()).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(__in 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(float_util(ctx->m()).mk_round_nearest_ties_to_away()); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_mk_fpa_round_toward_positive(__in 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(float_util(ctx->m()).mk_round_toward_positive()); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_mk_fpa_round_toward_negative(__in 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(float_util(ctx->m()).mk_round_toward_negative()); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_mk_fpa_round_toward_zero(__in 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(float_util(ctx->m()).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); + float_util fu(ctx->m()); + Z3_sort r = of_sort(fu.mk_float_sort(ebits, sbits)); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + + + +}; diff --git a/src/api/z3.h b/src/api/z3.h index db8becafd..2a56fa9a7 100644 --- a/src/api/z3.h +++ b/src/api/z3.h @@ -27,6 +27,7 @@ Notes: #include"z3_algebraic.h" #include"z3_polynomial.h" #include"z3_rcf.h" +#include"z3_fpa.h" #undef __in #undef __out diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h new file mode 100644 index 000000000..a3e61931b --- /dev/null +++ b/src/api/z3_fpa.h @@ -0,0 +1,82 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + z3_fpa.h + +Abstract: + + Additional APIs for floating-point arithmetic (FPA). + +Author: + + Christoph M. Wintersteiger (cwinter) 2013-06-05 + +Notes: + +--*/ +#ifndef _Z3_FPA_H_ +#define _Z3_FPA_H_ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + + /** + \brief Create a rounding mode sort. + + 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 rounding mode sort which represents the NearestTiesToEven rounding mode. + + 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 rounding mode sort which represents the NearestTiesToAway rounding mode. + + 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 rounding mode sort which represents the TowardPositive rounding mode. + + 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 rounding mode sort which represents the TowardNegative rounding mode. + + 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 rounding mode sort which represents the TowardZero rounding mode. + + 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 floating point sort. + + def_API('Z3_mk_fpa_sort', SORT, (_in(CONTEXT), _in(UINT), _in(UINT))) + + \remark ebits must be larger than 1 and sbits must be larger than 2. + */ + Z3_sort Z3_API Z3_mk_fpa_sort(__in Z3_context c, __in unsigned ebits, __in unsigned sbits); + +#ifdef __cplusplus +}; +#endif // __cplusplus + +#endif From 573ec293dc0fc6d9dc9408c832b62f55b4bfd909 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 7 Jun 2013 19:09:41 +0100 Subject: [PATCH 002/118] FPA: Added core C API. Signed-off-by: Christoph M. Wintersteiger --- src/api/api_fpa.cpp | 253 +++++++++++++++++++++++++++++++++++- src/api/z3_fpa.h | 220 ++++++++++++++++++++++++++++++- src/ast/float_decl_plugin.h | 3 +- 3 files changed, 469 insertions(+), 7 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 8e8493d63..74030a0b0 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -33,7 +33,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_even(__in Z3_context c) + 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); @@ -44,7 +44,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_away(__in Z3_context c) + 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_even(c); @@ -55,7 +55,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_round_toward_positive(__in Z3_context c) + Z3_ast Z3_API Z3_mk_fpa_round_toward_positive(Z3_context c) { Z3_TRY; LOG_Z3_mk_fpa_round_nearest_ties_to_even(c); @@ -66,7 +66,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_round_toward_negative(__in Z3_context c) + Z3_ast Z3_API Z3_mk_fpa_round_toward_negative(Z3_context c) { Z3_TRY; LOG_Z3_mk_fpa_round_nearest_ties_to_even(c); @@ -77,7 +77,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_round_toward_zero(__in Z3_context c) + Z3_ast Z3_API Z3_mk_fpa_round_toward_zero(Z3_context c) { Z3_TRY; LOG_Z3_mk_fpa_round_nearest_ties_to_even(c); @@ -102,6 +102,249 @@ extern "C" { Z3_CATCH_RETURN(0); } + 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(float_util(ctx->m()).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); + float_util fu(ctx->m()); + Z3_ast r = of_ast(negative != 0 ? fu.mk_minus_inf(to_sort(s)) : fu.mk_plus_inf(to_sort(s))); + 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(float_util(ctx->m()).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(float_util(ctx->m()).mk_uminus(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(float_util(ctx->m()).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(float_util(ctx->m()).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(float_util(ctx->m()).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(float_util(ctx->m()).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(float_util(ctx->m()).mk_fused_ma(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(float_util(ctx->m()).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(float_util(ctx->m()).mk_rem(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(float_util(ctx->m()).mk_float_eq(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(float_util(ctx->m()).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(float_util(ctx->m()).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(float_util(ctx->m()).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(float_util(ctx->m()).mk_gt(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(float_util(ctx->m()).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(float_util(ctx->m()).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(float_util(ctx->m()).mk_is_zero(to_expr(t))); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_mk_fpa_is_inf(Z3_context c, Z3_ast t) { + Z3_TRY; + LOG_Z3_mk_fpa_is_inf(c, t); + RESET_ERROR_CODE(); + api::context * ctx = mk_c(c); + Z3_ast r = of_ast(float_util(ctx->m()).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(float_util(ctx->m()).mk_is_nan(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(float_util(ctx->m()).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(float_util(ctx->m()).mk_max(to_expr(t1), to_expr(t2))); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_mk_fpa_convert(Z3_context c, Z3_sort s, Z3_ast rm, Z3_ast t) { + Z3_TRY; + LOG_Z3_mk_fpa_convert(c, s, rm, t); + RESET_ERROR_CODE(); + api::context * ctx = mk_c(c); + float_util fu(ctx->m()); + expr * args [2] = { to_expr(rm), to_expr(t) }; + Z3_ast r = of_ast(ctx->m().mk_app(fu.get_family_id(), OP_TO_FLOAT, + to_sort(s)->get_num_parameters(), to_sort(s)->get_parameters(), + 2, args)); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } }; diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index a3e61931b..c9feb0778 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -65,7 +65,6 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_fpa_round_toward_zero(__in Z3_context c); - /** \brief Create a floating point sort. @@ -74,7 +73,226 @@ extern "C" { \remark ebits must be larger than 1 and sbits must be larger than 2. */ Z3_sort Z3_API Z3_mk_fpa_sort(__in Z3_context c, __in unsigned ebits, __in unsigned sbits); + + /** + \brief Create a NaN of sort s. + + 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. + + When \c negative is true, -Inf will be generated instead of +Inf. + + 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 Floating-point absolute value + + t must have floating point 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 + + t must have floating point 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 + + rm must be of FPA rounding mode sort, t1 and t2 must have floating point 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 + + rm must be of FPA rounding mode sort, t1 and t2 must have floating point 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 + + rm must be of FPA rounding mode sort, t1 and t2 must have floating point 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 + + The nodes rm must be of FPA rounding mode sort t1 and t2 must have floating point 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. + + The result is round((t1 * t2) + t3) + + rm must be of FPA rounding mode sort, t1, t2, and t3 must have floating point 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 + + rm must be of FPA rounding mode sort, t must have floating point 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 + + t1 and t2 must have floating point 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 equality + + Note that this is IEEE 754 equality (as opposed to SMT-LIB =). + + t1 and t2 must have floating point 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 Floating-point less-than or equal + + t1 and t2 must have floating point 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 + + t1 and t2 must have floating point 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 + + t1 and t2 must have floating point 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 + + t1 and t2 must have floating point 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 Predicate indicating whether t is a normal floating point number + + t must have floating point 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 + + t must have floating point 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., +0 or -0. + + t must have floating point 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 +Inf or -Inf + + t must have floating point sort. + + def_API('Z3_mk_fpa_is_inf', AST, (_in(CONTEXT),_in(AST))) + */ + Z3_ast Z3_API Z3_mk_fpa_is_inf(__in Z3_context c, __in Z3_ast t); + + /** + \brief Predicate indicating whether t is a NaN + + t must have floating point 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 Minimum of floating point numbers + + t1, t2 must have floating point 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 + + t1, t2 must have floating point 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 Conversion of a floating point number to sort s. + + s must be a floating point sort, rm must have rounding mode sort, and t must have floating point sort. + + def_API('Z3_mk_fpa_convert', AST, (_in(CONTEXT),_in(SORT),_in(AST),_in(AST))) + */ + Z3_ast Z3_API Z3_mk_fpa_convert(__in Z3_context c, __in Z3_sort s, __in Z3_ast rm, __in Z3_ast t); + #ifdef __cplusplus }; #endif // __cplusplus diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index f1b60a91b..deda7e045 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -178,6 +178,7 @@ public: 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); } @@ -211,7 +212,7 @@ public: 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_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); } From ebbdff87577473d14c990e580118a42bc2c937fa Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 10 Jun 2013 15:53:24 +0100 Subject: [PATCH 003/118] doc bugfix Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/IntExpr.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/dotnet/IntExpr.cs b/src/api/dotnet/IntExpr.cs index 4c52ec79f..58bf1b973 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: From a36a09e08171e7e0d0c00f1bab508a780b5bbae2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 10 Jun 2013 15:53:41 +0100 Subject: [PATCH 004/118] FPA API: minor fixes Signed-off-by: Christoph M. Wintersteiger --- src/api/api_fpa.cpp | 30 ++++++- src/api/z3_fpa.h | 191 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 194 insertions(+), 27 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 74030a0b0..cfb5a2624 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -122,6 +122,19 @@ extern "C" { RETURN_Z3(r); Z3_CATCH_RETURN(0); } + + Z3_ast Z3_API Z3_mk_double(Z3_context c, double v, Z3_sort ty) { + Z3_TRY; + LOG_Z3_mk_double(c, v, ty); + RESET_ERROR_CODE(); + api::context * ctx = mk_c(c); + float_util fu(ctx->m()); + mpf tmp; + fu.fm().set(tmp, fu.get_ebits(to_sort(ty)), fu.get_sbits(to_sort(ty)), v); + Z3_ast r = of_ast(fu.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; @@ -223,9 +236,9 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_leq(Z3_context c, Z3_ast t1, Z3_ast t2) { + Z3_ast Z3_API Z3_mk_fpa_le(Z3_context c, Z3_ast t1, Z3_ast t2) { Z3_TRY; - LOG_Z3_mk_fpa_leq(c, t1, t2); + LOG_Z3_mk_fpa_le(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); Z3_ast r = of_ast(float_util(ctx->m()).mk_le(to_expr(t1), to_expr(t2))); @@ -243,9 +256,9 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_geq(Z3_context c, Z3_ast t1, Z3_ast t2) { + Z3_ast Z3_API Z3_mk_fpa_ge(Z3_context c, Z3_ast t1, Z3_ast t2) { Z3_TRY; - LOG_Z3_mk_fpa_geq(c, t1, t2); + LOG_Z3_mk_fpa_ge(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); Z3_ast r = of_ast(float_util(ctx->m()).mk_ge(to_expr(t1), to_expr(t2))); @@ -347,4 +360,13 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_ast Z3_API Z3_mk_fpa_to_ieee_bv(__in Z3_context c, __in 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(float_util(ctx->m()).mk_to_ieee_bv(to_expr(t))); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } }; diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index c9feb0778..93268b821 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -25,6 +25,8 @@ extern "C" { /** \brief Create a rounding mode sort. + + \param c logical context. def_API('Z3_mk_fpa_rounding_mode_sort', SORT, (_in(CONTEXT),)) */ @@ -32,6 +34,8 @@ extern "C" { /** \brief Create a numeral of rounding mode sort which represents the NearestTiesToEven rounding mode. + + \param c logical context. def_API('Z3_mk_fpa_round_nearest_ties_to_even', AST, (_in(CONTEXT),)) */ @@ -39,6 +43,8 @@ extern "C" { /** \brief Create a numeral of rounding mode sort which represents the NearestTiesToAway rounding mode. + + \param c logical context. def_API('Z3_mk_fpa_round_nearest_ties_to_away', AST, (_in(CONTEXT),)) */ @@ -46,6 +52,8 @@ extern "C" { /** \brief Create a numeral of rounding mode sort which represents the TowardPositive rounding mode. + + \param c logical context. def_API('Z3_mk_fpa_round_toward_positive', AST, (_in(CONTEXT),)) */ @@ -54,28 +62,41 @@ extern "C" { /** \brief Create a numeral of rounding mode 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 rounding mode 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 floating point sort. - - def_API('Z3_mk_fpa_sort', SORT, (_in(CONTEXT), _in(UINT), _in(UINT))) + + \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 a NaN of sort s. + + \param c logical context. + \param s target sort def_API('Z3_mk_fpa_nan', AST, (_in(CONTEXT),_in(SORT))) */ @@ -83,16 +104,41 @@ extern "C" { /** \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, -Inf will be generated instead of +Inf. 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 numeral of floating point sort. + + This function can be use 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 floating point sort + + \sa Z3_mk_numeral + + def_API('Z3_mk_double', AST, (_in(CONTEXT), _in(DOUBLE), _in(SORT))) + */ + Z3_ast Z3_API Z3_mk_double(__in Z3_context c, __in double v, __in Z3_sort ty); + /** \brief Floating-point absolute value + \param c logical context. + \param t floating-point term. + t must have floating point sort. def_API('Z3_mk_fpa_abs', AST, (_in(CONTEXT),_in(AST))) @@ -102,6 +148,9 @@ extern "C" { /** \brief Floating-point negation + \param c logical context. + \param t floating-point term. + t must have floating point sort. def_API('Z3_mk_fpa_neg', AST, (_in(CONTEXT),_in(AST))) @@ -111,7 +160,12 @@ extern "C" { /** \brief Floating-point addition - rm must be of FPA rounding mode sort, t1 and t2 must have floating point sort. + \param c logical context. + \param rm rounding mode + \param t1 floating-point term. + \param t2 floating-point term. + + rm must be of FPA rounding mode sort, t1 and t2 must have the same floating point sort. def_API('Z3_mk_fpa_add', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST))) */ @@ -120,7 +174,12 @@ extern "C" { /** \brief Floating-point subtraction - rm must be of FPA rounding mode sort, t1 and t2 must have floating point sort. + \param c logical context. + \param rm rounding mode + \param t1 floating-point term. + \param t2 floating-point term. + + rm must be of FPA rounding mode sort, t1 and t2 must have the same floating point sort. def_API('Z3_mk_fpa_sub', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST))) */ @@ -129,7 +188,12 @@ extern "C" { /** \brief Floating-point multiplication - rm must be of FPA rounding mode sort, t1 and t2 must have floating point sort. + \param c logical context. + \param rm rounding mode + \param t1 floating-point term. + \param t2 floating-point term. + + rm must be of FPA rounding mode sort, t1 and t2 must have the same floating point sort. def_API('Z3_mk_fpa_mul', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST))) */ @@ -138,7 +202,12 @@ extern "C" { /** \brief Floating-point division - The nodes rm must be of FPA rounding mode sort t1 and t2 must have floating point sort. + \param c logical context. + \param rm rounding mode + \param t1 floating-point term. + \param t2 floating-point term. + + The nodes rm must be of FPA rounding mode sort t1 and t2 must have the same floating point sort. def_API('Z3_mk_fpa_div', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST))) */ @@ -147,9 +216,14 @@ extern "C" { /** \brief Floating-point fused multiply-add. + \param c logical context. + \param rm rounding mode + \param t1 floating-point term. + \param t2 floating-point term. + The result is round((t1 * t2) + t3) - rm must be of FPA rounding mode sort, t1, t2, and t3 must have floating point sort. + rm must be of FPA rounding mode sort, t1, t2, and t3 must have the same floating point sort. def_API('Z3_mk_fpa_fma', AST, (_in(CONTEXT),_in(AST),_in(AST),_in(AST),_in(AST))) */ @@ -158,6 +232,10 @@ extern "C" { /** \brief Floating-point square root + \param c logical context. + \param rm rounding mode + \param t floating-point term. + rm must be of FPA rounding mode sort, t must have floating point sort. def_API('Z3_mk_fpa_sqrt', AST, (_in(CONTEXT),_in(AST),_in(AST))) @@ -167,7 +245,11 @@ extern "C" { /** \brief Floating-point remainder - t1 and t2 must have floating point sort. + \param c logical context. + \param t1 floating-point term. + \param t2 floating-point term. + + t1 and t2 must have the same floating point sort. def_API('Z3_mk_fpa_rem', AST, (_in(CONTEXT),_in(AST),_in(AST))) */ @@ -176,27 +258,39 @@ extern "C" { /** \brief Floating-point equality + \param c logical context. + \param t1 floating-point term. + \param t2 floating-point term. + Note that this is IEEE 754 equality (as opposed to SMT-LIB =). - t1 and t2 must have floating point sort. + t1 and t2 must have the same floating point 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 Floating-point less-than or equal + \brief Floating-point less than or equal - t1 and t2 must have floating point sort. + \param c logical context. + \param t1 floating-point term. + \param t2 floating-point term. + + t1 and t2 must have the same floating point sort. - def_API('Z3_mk_fpa_leq', AST, (_in(CONTEXT),_in(AST),_in(AST))) + def_API('Z3_mk_fpa_le', 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); + Z3_ast Z3_API Z3_mk_fpa_le(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2); /** \brief Floating-point less-than - t1 and t2 must have floating point sort. + \param c logical context. + \param t1 floating-point term. + \param t2 floating-point term. + + t1 and t2 must have the same floating point sort. def_API('Z3_mk_fpa_lt', AST, (_in(CONTEXT),_in(AST),_in(AST))) */ @@ -204,18 +298,26 @@ extern "C" { /** - \brief Floating-point greater-than or equal + \brief Floating-point greater than or equal - t1 and t2 must have floating point sort. + \param c logical context. + \param t1 floating-point term. + \param t2 floating-point term. + + t1 and t2 must have the same floating point sort. - def_API('Z3_mk_fpa_geq', AST, (_in(CONTEXT),_in(AST),_in(AST))) + def_API('Z3_mk_fpa_ge', 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); + Z3_ast Z3_API Z3_mk_fpa_ge(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2); /** \brief Floating-point greater-than - t1 and t2 must have floating point sort. + \param c logical context. + \param t1 floating-point term. + \param t2 floating-point term. + + t1 and t2 must have the same floating point sort. def_API('Z3_mk_fpa_gt', AST, (_in(CONTEXT),_in(AST),_in(AST))) */ @@ -224,6 +326,9 @@ extern "C" { /** \brief Predicate indicating whether t is a normal floating point number + \param c logical context. + \param t floating-point term. + t must have floating point sort. def_API('Z3_mk_fpa_is_normal', AST, (_in(CONTEXT),_in(AST))) @@ -233,6 +338,9 @@ extern "C" { /** \brief Predicate indicating whether t is a subnormal floating point number + \param c logical context. + \param t floating-point term. + t must have floating point sort. def_API('Z3_mk_fpa_is_subnormal', AST, (_in(CONTEXT),_in(AST))) @@ -242,6 +350,9 @@ extern "C" { /** \brief Predicate indicating whether t is a floating point number with zero value, i.e., +0 or -0. + \param c logical context. + \param t floating-point term. + t must have floating point sort. def_API('Z3_mk_fpa_is_zero', AST, (_in(CONTEXT),_in(AST))) @@ -251,6 +362,9 @@ extern "C" { /** \brief Predicate indicating whether t is a floating point number representing +Inf or -Inf + \param c logical context. + \param t floating-point term. + t must have floating point sort. def_API('Z3_mk_fpa_is_inf', AST, (_in(CONTEXT),_in(AST))) @@ -260,6 +374,9 @@ extern "C" { /** \brief Predicate indicating whether t is a NaN + \param c logical context. + \param t floating-point term. + t must have floating point sort. def_API('Z3_mk_fpa_is_nan', AST, (_in(CONTEXT),_in(AST))) @@ -269,7 +386,11 @@ extern "C" { /** \brief Minimum of floating point numbers - t1, t2 must have floating point sort. + \param c logical context. + \param t1 floating-point term. + \param t2 floating-point term. + + t1, t2 must have the same floating point sort. def_API('Z3_mk_fpa_min', AST, (_in(CONTEXT),_in(AST),_in(AST))) */ @@ -278,20 +399,44 @@ extern "C" { /** \brief Maximum of floating point numbers - t1, t2 must have floating point sort. + \param c logical context. + \param t1 floating-point term. + \param t2 floating-point term. + + t1, t2 must have the same floating point 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 Conversion of a floating point number to sort s. + \brief Conversion of a floating point number to another floating-point sort s. + + Produces a term that represents the conversion of a floating-point term t to a different + floating point sort s. If necessary, rounding according to rm is applied. + + \param c logical context. + \param s floating-point sort. + \param rm rounding mode. + \param t floating-point term. s must be a floating point sort, rm must have rounding mode sort, and t must have floating point sort. def_API('Z3_mk_fpa_convert', AST, (_in(CONTEXT),_in(SORT),_in(AST),_in(AST))) */ Z3_ast Z3_API Z3_mk_fpa_convert(__in Z3_context c, __in Z3_sort s, __in Z3_ast rm, __in Z3_ast t); + + /** + \brief Conversion of a floating point term to a bit-vector term in IEEE754 format. + + \param c logical context. + \param t floating-point term. + + t must have floating point sort. The size of the resulting bit-vector is automatically determined. + + 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); #ifdef __cplusplus }; From e14819c1b1eddbe05e7240e43543cd0d8cbf8889 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 10 Jun 2013 15:54:20 +0100 Subject: [PATCH 005/118] FPA: Added .NET API calls Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Context.cs | 365 +++++++++++++++++++++++++++++ src/api/dotnet/FPExpr.cs | 46 ++++ src/api/dotnet/FPNum.cs | 47 ++++ src/api/dotnet/FPRMExpr.cs | 46 ++++ src/api/dotnet/FPRMNum.cs | 47 ++++ src/api/dotnet/FPRMSort.cs | 43 ++++ src/api/dotnet/FPSort.cs | 43 ++++ src/api/dotnet/Microsoft.Z3.csproj | 8 +- 8 files changed, 644 insertions(+), 1 deletion(-) create mode 100644 src/api/dotnet/FPExpr.cs create mode 100644 src/api/dotnet/FPNum.cs create mode 100644 src/api/dotnet/FPRMExpr.cs create mode 100644 src/api/dotnet/FPRMNum.cs create mode 100644 src/api/dotnet/FPRMSort.cs create mode 100644 src/api/dotnet/FPSort.cs diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 68cca046e..1e9bd1323 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3428,6 +3428,371 @@ namespace Microsoft.Z3 } #endregion + #region Floating-Point Arithmetic + /// + /// Create a floating point rounding mode sort. + /// + public FPRMSort MkFPRMSort() + { + Contract.Ensures(Contract.Result() != null); + return new FPRMSort(this); + } + + /// + /// Create a NearestTiesToEven rounding mode numeral. + /// + public FPRMNum MkFPRMNearestTiesToEven() + { + Contract.Ensures(Contract.Result() != null); + return new FPRMNum(this, Native.Z3_mk_fpa_round_nearest_ties_to_even(nCtx)); + } + + /// + /// Create a NearestTiesToAway rounding mode numeral. + /// + public FPRMNum MkFPRMNearestTiesToAway() + { + Contract.Ensures(Contract.Result() != null); + return new FPRMNum(this, Native.Z3_mk_fpa_round_nearest_ties_to_away(nCtx)); + } + + /// + /// Create a TowardPositive rounding mode numeral. + /// + public FPRMNum MkFPRMTowardPositive() + { + Contract.Ensures(Contract.Result() != null); + return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_positive(nCtx)); + } + + /// + /// Create a TowardNegative rounding mode numeral. + /// + public FPRMNum MkFPRMTowardNegative() + { + Contract.Ensures(Contract.Result() != null); + return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_negative(nCtx)); + } + + /// + /// Create a TowardZero rounding mode numeral. + /// + public FPRMNum MkFPRMTowardZero() + { + Contract.Ensures(Contract.Result() != null); + return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_zero(nCtx)); + } + + /// + /// Create a floating point sort. + /// + /// exponent bits in the floating point sort. + /// significand bits in the floating point sort. + public FPSort MkFPSort(uint ebits, uint sbits) + { + Contract.Ensures(Contract.Result() != null); + return new FPSort(this, ebits, sbits); + } + + /// + /// Create a floating point NaN numeral. + /// + /// A string representing the value in decimal notation. + /// floating point sort. + public FPNum MkFPNaN(double v, FPSort s) + { + Contract.Ensures(Contract.Result() != null); + return new FPNum(this, Native.Z3_mk_fpa_nan(nCtx, s.NativeObject)); + } + + /// + /// Create a floating point Inf numeral. + /// + /// A string representing the value in decimal notation. + /// floating point sort. + /// indicates whether the result should be negative. + public FPNum MkFPInf(double v, 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 numeral. + /// + /// A string representing the value in decimal notation. + /// floating point sort + public FPNum MkFP(double v, FPSort s) + { + Contract.Ensures(Contract.Result() != null); + return new FPNum(this, Native.Z3_mk_double(this.nCtx, v, s.NativeObject)); + } + + /// + /// Floating-point absolute value + /// + /// floating point term + 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 + 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 + 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 + 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 + 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 + 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 + 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 + /// + /// floating point term + 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 + 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 equality + /// + /// + /// Note that this is IEEE 754 equality (as opposed to standard =). + /// + /// floating point term + /// floating point term + 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)); + } + + /// + /// Floating-point less than or equal + /// + /// floating point term + /// floating point term + BoolExpr MkFPLe(FPExpr t1, FPExpr t2) + { + Contract.Ensures(Contract.Result() != null); + return new BoolExpr(this, Native.Z3_mk_fpa_le(this.nCtx, t1.NativeObject, t2.NativeObject)); + } + + /// + /// Floating-point less than + /// + /// floating point term + /// floating point term + 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 + BoolExpr MkFPGe(FPExpr t1, FPExpr t2) + { + Contract.Ensures(Contract.Result() != null); + return new BoolExpr(this, Native.Z3_mk_fpa_ge(this.nCtx, t1.NativeObject, t2.NativeObject)); + } + + /// + /// Floating-point greater than + /// + /// floating point term + /// floating point term + 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)); + } + + /// + /// Predicate indicating whether t is a normal floating point number + /// + /// floating point term + 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 + 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 + 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 +Inf or -Inf + /// + /// floating point term + BoolExpr MkFPIsInf(FPExpr t) + { + Contract.Ensures(Contract.Result() != null); + return new BoolExpr(this, Native.Z3_mk_fpa_is_inf(this.nCtx, t.NativeObject)); + } + + /// + /// Predicate indicating whether t is a NaN + /// + /// floating point term + BoolExpr MkFPIsNaN(FPExpr t) + { + Contract.Ensures(Contract.Result() != null); + return new BoolExpr(this, Native.Z3_mk_fpa_is_nan(this.nCtx, t.NativeObject)); + } + + /// + /// Floating-point minimum + /// + /// floating point term + /// floating point term + 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)); + } + + /// + /// Floating-point maximium + /// + /// floating point term + /// floating point term + 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)); + } + + /// + /// Conversion of a floating point number to another floating-point sort s. + /// + /// + /// Produces a term that represents the conversion of a floating-point term t to a different + /// floating point sort s. If necessary, rounding according to rm is applied. + /// + /// floating point sort + /// floating point rounding mode term + /// floating point term + FPExpr MkFPConvert(FPSort s, FPRMExpr rm, FPExpr t) + { + Contract.Ensures(Contract.Result() != null); + return new FPExpr(this, Native.Z3_mk_fpa_convert(this.nCtx, s.NativeObject, rm.NativeObject, t.NativeObject)); + } + + /// + /// Conversion of a floating point term to a bit-vector term in IEEE754 format. + /// + /// + /// The size of the resulting bit-vector is automatically determined. + /// + /// floating point term + FPExpr MkFPToIEEEBV(FPExpr t) + { + Contract.Ensures(Contract.Result() != null); + return new FPExpr(this, Native.Z3_mk_fpa_to_ieee_bv(this.nCtx, t.NativeObject)); + } + + #endregion #region Miscellaneous /// diff --git a/src/api/dotnet/FPExpr.cs b/src/api/dotnet/FPExpr.cs new file mode 100644 index 000000000..66b3fc10d --- /dev/null +++ b/src/api/dotnet/FPExpr.cs @@ -0,0 +1,46 @@ +/*++ +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 +{ + /// + /// Floating Point Expressions + /// + public class FPExpr : Expr + { + #region Internal + internal protected FPExpr(Context ctx) + : base(ctx) + { + Contract.Requires(ctx != null); + } + 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..044598e58 --- /dev/null +++ b/src/api/dotnet/FPNum.cs @@ -0,0 +1,47 @@ +/*++ +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 +{ + /// + /// Floatiung Point Numerals + /// + [ContractVerification(true)] + public class FPNum : FPExpr + { + + #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..fa43a346a --- /dev/null +++ b/src/api/dotnet/FPRMExpr.cs @@ -0,0 +1,46 @@ +/*++ +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 +{ + /// + /// Floating Point Expressions + /// + public class FPRMExpr : Expr + { + #region Internal + internal protected FPRMExpr(Context ctx) + : base(ctx) + { + Contract.Requires(ctx != null); + } + 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..eaf105718 --- /dev/null +++ b/src/api/dotnet/FPRMNum.cs @@ -0,0 +1,47 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + FPRMNum.cs + +Abstract: + + Z3 Managed API: Floating Point Rounding Mode Numerals + +Author: + + Christoph Wintersteiger (cwinter) 2013-06-10 + +Notes: + +--*/ +using System; +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// Floatiung Point Rounding Mode Numerals + /// + [ContractVerification(true)] + public class FPRMNum : FPRMExpr + { + + #region Internal + internal FPRMNum(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/FPRMSort.cs b/src/api/dotnet/FPRMSort.cs new file mode 100644 index 000000000..23d454a65 --- /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: Floating Point Rounding Mode Sorts + +Author: + + Christoph Wintersteiger (cwinter) 2013-06-10 + +Notes: + +--*/ + +using System; +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// A floating point rounding mode 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..a79557ae6 --- /dev/null +++ b/src/api/dotnet/FPSort.cs @@ -0,0 +1,43 @@ +/*++ +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 +{ + /// + /// A floating point sort + /// + public class FPSort : Sort + { + #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/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj index 9eb9eb660..083cd048f 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj +++ b/src/api/dotnet/Microsoft.Z3.csproj @@ -341,6 +341,12 @@ + + + + + + @@ -399,4 +405,4 @@ --> - + \ No newline at end of file From a9840b291f2ce960910b7fec6209e74a8b02d665 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 10 Jun 2013 19:06:45 +0100 Subject: [PATCH 006/118] FPA API: Tied into rest of the API; added numeral/value handling through existing functions; added trivial .NET example. Signed-off-by: Christoph M. Wintersteiger --- examples/dotnet/Program.cs | 12 ++++++ src/api/api_ast.cpp | 6 +++ src/api/api_context.cpp | 2 + src/api/api_context.h | 5 +++ src/api/api_fpa.cpp | 78 ++++++++++++++++++------------------- src/api/api_numeral.cpp | 35 ++++++++++++++--- src/api/dotnet/Expr.cs | 8 +++- src/api/z3_api.h | 2 + src/ast/float_decl_plugin.h | 8 ++-- 9 files changed, 104 insertions(+), 52 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 2085de296..c75553e7b 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -2022,6 +2022,17 @@ namespace test_mapi // Console.WriteLine("{0}", ctx.MkEq(s1, t1)); } + public static void FloatingPointExample(Context ctx) + { + Console.WriteLine("FloatingPointExample"); + + FPSort s = ctx.MkFPSort(11, 53); + Console.WriteLine("Sort: {0}", s); + + FPNum n = (FPNum) ctx.MkNumeral("0.125", s); + Console.WriteLine("Numeral: {0}", n.ToString()); + } + static void Main(string[] args) { try @@ -2063,6 +2074,7 @@ namespace test_mapi FindSmallModelExample(ctx); SimplifierExample(ctx); FiniteDomainExample(ctx); + FloatingPointExample(ctx); } // These examples need proof generation turned on. diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 6855f6209..ccc2cbf88 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -647,6 +647,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 == FLOAT_SORT) { + return Z3_FLOATING_POINT_SORT; + } + else if (fid == mk_c(c)->get_fpa_fid() && k == ROUNDING_MODE_SORT) { + return Z3_FLOATING_POINT_ROUNDING_MODE_SORT; + } else { return Z3_UNKNOWN_SORT; } diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index cf179332a..f4314dcca 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_float_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("float"); 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..f409a4ece 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"float_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; + float_util m_float_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; } + float_util & float_util() { return m_float_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 index cfb5a2624..278a0556a 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -28,7 +28,7 @@ extern "C" { LOG_Z3_mk_fpa_rounding_mode_sort(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_sort r = of_sort(float_util(ctx->m()).mk_rm_sort()); + Z3_sort r = of_sort(ctx->float_util().mk_rm_sort()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -39,7 +39,7 @@ extern "C" { LOG_Z3_mk_fpa_round_nearest_ties_to_even(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_round_nearest_ties_to_even()); + Z3_ast r = of_ast(ctx->float_util().mk_round_nearest_ties_to_even()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -50,7 +50,7 @@ extern "C" { LOG_Z3_mk_fpa_round_nearest_ties_to_even(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_round_nearest_ties_to_away()); + Z3_ast r = of_ast(ctx->float_util().mk_round_nearest_ties_to_away()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -61,7 +61,7 @@ extern "C" { LOG_Z3_mk_fpa_round_nearest_ties_to_even(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_round_toward_positive()); + Z3_ast r = of_ast(ctx->float_util().mk_round_toward_positive()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -72,7 +72,7 @@ extern "C" { LOG_Z3_mk_fpa_round_nearest_ties_to_even(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_round_toward_negative()); + Z3_ast r = of_ast(ctx->float_util().mk_round_toward_negative()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -83,7 +83,7 @@ extern "C" { LOG_Z3_mk_fpa_round_nearest_ties_to_even(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_round_toward_zero()); + Z3_ast r = of_ast(ctx->float_util().mk_round_toward_zero()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -95,9 +95,8 @@ extern "C" { if (ebits < 2 || sbits < 3) { SET_ERROR_CODE(Z3_INVALID_ARG); } - api::context * ctx = mk_c(c); - float_util fu(ctx->m()); - Z3_sort r = of_sort(fu.mk_float_sort(ebits, sbits)); + api::context * ctx = mk_c(c); + Z3_sort r = of_sort(ctx->float_util().mk_float_sort(ebits, sbits)); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -107,7 +106,7 @@ extern "C" { LOG_Z3_mk_fpa_nan(c, s); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_nan(to_sort(s))); + Z3_ast r = of_ast(ctx->float_util().mk_nan(to_sort(s))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -117,8 +116,7 @@ extern "C" { LOG_Z3_mk_fpa_inf(c, s, negative); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - float_util fu(ctx->m()); - Z3_ast r = of_ast(negative != 0 ? fu.mk_minus_inf(to_sort(s)) : fu.mk_plus_inf(to_sort(s))); + Z3_ast r = of_ast(negative != 0 ? ctx->float_util().mk_minus_inf(to_sort(s)) : ctx->float_util().mk_plus_inf(to_sort(s))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -128,10 +126,9 @@ extern "C" { LOG_Z3_mk_double(c, v, ty); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - float_util fu(ctx->m()); - mpf tmp; - fu.fm().set(tmp, fu.get_ebits(to_sort(ty)), fu.get_sbits(to_sort(ty)), v); - Z3_ast r = of_ast(fu.mk_value(tmp)); + scoped_mpf tmp(ctx->float_util().fm()); + ctx->float_util().fm().set(tmp, ctx->float_util().get_ebits(to_sort(ty)), ctx->float_util().get_sbits(to_sort(ty)), v); + Z3_ast r = of_ast(ctx->float_util().mk_value(tmp)); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -141,7 +138,7 @@ extern "C" { LOG_Z3_mk_fpa_abs(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_abs(to_expr(t))); + Z3_ast r = of_ast(ctx->float_util().mk_abs(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -151,7 +148,7 @@ extern "C" { LOG_Z3_mk_fpa_neg(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_uminus(to_expr(t))); + Z3_ast r = of_ast(ctx->float_util().mk_uminus(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -161,7 +158,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_add(to_expr(rm), to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_add(to_expr(rm), to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -171,7 +168,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_sub(to_expr(rm), to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_sub(to_expr(rm), to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -181,7 +178,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_mul(to_expr(rm), to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_mul(to_expr(rm), to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -191,7 +188,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_div(to_expr(rm), to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_div(to_expr(rm), to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -201,7 +198,7 @@ extern "C" { LOG_Z3_mk_fpa_fma(c, rm, t1, t2, t3); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_fused_ma(to_expr(rm), to_expr(t1), to_expr(t2), to_expr(t3))); + Z3_ast r = of_ast(ctx->float_util().mk_fused_ma(to_expr(rm), to_expr(t1), to_expr(t2), to_expr(t3))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -211,7 +208,7 @@ extern "C" { LOG_Z3_mk_fpa_sqrt(c, rm, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_sqrt(to_expr(rm), to_expr(t))); + Z3_ast r = of_ast(ctx->float_util().mk_sqrt(to_expr(rm), to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -221,7 +218,7 @@ extern "C" { LOG_Z3_mk_fpa_rem(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_rem(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_rem(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -231,7 +228,7 @@ extern "C" { LOG_Z3_mk_fpa_eq(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_float_eq(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_float_eq(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -241,7 +238,7 @@ extern "C" { LOG_Z3_mk_fpa_le(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_le(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_le(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -251,7 +248,7 @@ extern "C" { LOG_Z3_mk_fpa_lt(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_lt(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_lt(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -261,7 +258,7 @@ extern "C" { LOG_Z3_mk_fpa_ge(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_ge(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_ge(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -271,7 +268,7 @@ extern "C" { LOG_Z3_mk_fpa_gt(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_gt(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_gt(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -281,7 +278,7 @@ extern "C" { LOG_Z3_mk_fpa_is_normal(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_is_normal(to_expr(t))); + Z3_ast r = of_ast(ctx->float_util().mk_is_normal(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -291,7 +288,7 @@ extern "C" { LOG_Z3_mk_fpa_is_subnormal(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_is_subnormal(to_expr(t))); + Z3_ast r = of_ast(ctx->float_util().mk_is_subnormal(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -301,7 +298,7 @@ extern "C" { LOG_Z3_mk_fpa_is_zero(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_is_zero(to_expr(t))); + Z3_ast r = of_ast(ctx->float_util().mk_is_zero(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -311,7 +308,7 @@ extern "C" { LOG_Z3_mk_fpa_is_inf(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_is_inf(to_expr(t))); + Z3_ast r = of_ast(ctx->float_util().mk_is_inf(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -321,7 +318,7 @@ extern "C" { LOG_Z3_mk_fpa_is_nan(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_is_nan(to_expr(t))); + Z3_ast r = of_ast(ctx->float_util().mk_is_nan(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -331,7 +328,7 @@ extern "C" { LOG_Z3_mk_fpa_min(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_min(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_min(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -341,7 +338,7 @@ extern "C" { LOG_Z3_mk_fpa_max(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_max(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_max(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -350,10 +347,9 @@ extern "C" { Z3_TRY; LOG_Z3_mk_fpa_convert(c, s, rm, t); RESET_ERROR_CODE(); - api::context * ctx = mk_c(c); - float_util fu(ctx->m()); + api::context * ctx = mk_c(c); expr * args [2] = { to_expr(rm), to_expr(t) }; - Z3_ast r = of_ast(ctx->m().mk_app(fu.get_family_id(), OP_TO_FLOAT, + Z3_ast r = of_ast(ctx->m().mk_app(ctx->float_util().get_family_id(), OP_TO_FLOAT, to_sort(s)->get_num_parameters(), to_sort(s)->get_parameters(), 2, args)); RETURN_Z3(r); @@ -365,7 +361,7 @@ extern "C" { LOG_Z3_mk_fpa_to_ieee_bv(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(float_util(ctx->m()).mk_to_ieee_bv(to_expr(t))); + Z3_ast r = of_ast(ctx->float_util().mk_to_ieee_bv(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index d4a6587bc..6924afff3 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"float_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; @@ -69,7 +71,19 @@ extern "C" { } ++m; } - ast * a = mk_c(c)->mk_numeral_core(rational(n), to_sort(ty)); + ast * a = 0; + sort * _ty = to_sort(ty); + if (_ty->get_family_id() == mk_c(c)->get_fpa_fid()) + { + // avoid expanding floats into huge rationals. + float_util & fu = mk_c(c)->float_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); } @@ -131,7 +145,8 @@ extern "C" { expr* e = to_expr(a); 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)->float_util().is_value(e); Z3_CATCH_RETURN(Z3_FALSE); } @@ -155,7 +170,7 @@ extern "C" { if (mk_c(c)->datalog_util().is_numeral(e, v)) { r = rational(v, rational::ui64()); return Z3_TRUE; - } + } return Z3_FALSE; Z3_CATCH_RETURN(Z3_FALSE); } @@ -172,8 +187,16 @@ 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. + float_util & fu = mk_c(c)->float_util(); + scoped_mpf tmp(fu.fm()); + if (mk_c(c)->float_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/Expr.cs b/src/api/dotnet/Expr.cs index b2927e2c3..367e62666 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -1532,7 +1532,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_FLOATING_POINT_ROUNDING_MODE_SORT: return new FPRMNum(ctx, obj); } } @@ -1543,7 +1545,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_FLOATING_POINT_ROUNDING_MODE_SORT: return new FPRMExpr(ctx, obj); } return new Expr(ctx, obj); diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 6d59cf650..a761c89eb 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_FLOATING_POINT_ROUNDING_MODE_SORT, Z3_UNKNOWN_SORT = 1000 } Z3_sort_kind; diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index deda7e045..0b8349793 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -201,9 +201,11 @@ public: 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(expr * n, mpf_rounding_mode & v) { return m_plugin->is_rm(n, v); } + bool is_value(expr * n) const { return m_plugin->is_value(n); } + bool is_numeral(expr * n) const { return is_value(n); } + bool is_value(expr * n, mpf & v) const { return m_plugin->is_value(n, v); } + bool is_numeral(expr * n, mpf & v) const { return is_value(n, v); } + bool is_rm(expr * n, mpf_rounding_mode & v) { return m_plugin->is_rm(n, v); } app * mk_pzero(unsigned ebits, unsigned sbits); app * mk_nzero(unsigned ebits, unsigned sbits); From cc5081587fd7025eff92fa9a41540668b86a9e7d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 14 Jun 2013 12:00:10 +0100 Subject: [PATCH 007/118] FPA API: made FPA functions public Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Context.cs | 46 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 1e9bd1323..452018ae4 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3532,7 +3532,7 @@ namespace Microsoft.Z3 /// Floating-point absolute value /// /// floating point term - FPExpr MkFPAbs(FPExpr t) + public FPExpr MkFPAbs(FPExpr t) { Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_abs(this.nCtx, t.NativeObject)); @@ -3542,7 +3542,7 @@ namespace Microsoft.Z3 /// Floating-point negation /// /// floating point term - FPExpr MkFPNeg(FPExpr t) + public FPExpr MkFPNeg(FPExpr t) { Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_neg(this.nCtx, t.NativeObject)); @@ -3554,7 +3554,7 @@ namespace Microsoft.Z3 /// rounding mode term /// floating point term /// floating point term - FPExpr MkFPAdd(FPRMExpr rm, FPExpr t1, FPExpr t2) + 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)); @@ -3566,7 +3566,7 @@ namespace Microsoft.Z3 /// rounding mode term /// floating point term /// floating point term - FPExpr MkFPSub(FPRMExpr rm, FPExpr t1, FPExpr t2) + 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)); @@ -3578,7 +3578,7 @@ namespace Microsoft.Z3 /// rounding mode term /// floating point term /// floating point term - FPExpr MkFPMul(FPRMExpr rm, FPExpr t1, FPExpr t2) + 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)); @@ -3590,7 +3590,7 @@ namespace Microsoft.Z3 /// rounding mode term /// floating point term /// floating point term - FPExpr MkFPDiv(FPRMExpr rm, FPExpr t1, FPExpr t2) + 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)); @@ -3606,7 +3606,7 @@ namespace Microsoft.Z3 /// floating point term /// floating point term /// floating point term - FPExpr MkFPFMA(FPRMExpr rm, FPExpr t1, FPExpr t2, FPExpr t3) + 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)); @@ -3616,7 +3616,7 @@ namespace Microsoft.Z3 /// Floating-point square root /// /// floating point term - FPExpr MkFPSqrt(FPRMExpr rm, FPExpr t) + 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)); @@ -3627,7 +3627,7 @@ namespace Microsoft.Z3 /// /// floating point term /// floating point term - FPExpr MkFPRem(FPExpr t1, FPExpr t2) + 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)); @@ -3641,7 +3641,7 @@ namespace Microsoft.Z3 /// /// floating point term /// floating point term - BoolExpr MkFPEq(FPExpr t1, FPExpr t2) + 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)); @@ -3652,7 +3652,7 @@ namespace Microsoft.Z3 /// /// floating point term /// floating point term - BoolExpr MkFPLe(FPExpr t1, FPExpr t2) + public BoolExpr MkFPLe(FPExpr t1, FPExpr t2) { Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_le(this.nCtx, t1.NativeObject, t2.NativeObject)); @@ -3663,7 +3663,7 @@ namespace Microsoft.Z3 /// /// floating point term /// floating point term - BoolExpr MkFPLt(FPExpr t1, FPExpr t2) + 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)); @@ -3674,7 +3674,7 @@ namespace Microsoft.Z3 /// /// floating point term /// floating point term - BoolExpr MkFPGe(FPExpr t1, FPExpr t2) + public BoolExpr MkFPGe(FPExpr t1, FPExpr t2) { Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_ge(this.nCtx, t1.NativeObject, t2.NativeObject)); @@ -3685,7 +3685,7 @@ namespace Microsoft.Z3 /// /// floating point term /// floating point term - BoolExpr MkFPGt(FPExpr t1, FPExpr t2) + 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)); @@ -3695,7 +3695,7 @@ namespace Microsoft.Z3 /// Predicate indicating whether t is a normal floating point number /// /// floating point term - BoolExpr MkFPIsNormal(FPExpr t) + public BoolExpr MkFPIsNormal(FPExpr t) { Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_normal(this.nCtx, t.NativeObject)); @@ -3705,7 +3705,7 @@ namespace Microsoft.Z3 /// Predicate indicating whether t is a subnormal floating point number /// /// floating point term - BoolExpr MkFPIsSubnormal(FPExpr t) + public BoolExpr MkFPIsSubnormal(FPExpr t) { Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_subnormal(this.nCtx, t.NativeObject)); @@ -3715,7 +3715,7 @@ namespace Microsoft.Z3 /// Predicate indicating whether t is a floating point number with zero value, i.e., +0 or -0. /// /// floating point term - BoolExpr MkFPIsZero(FPExpr t) + public BoolExpr MkFPIsZero(FPExpr t) { Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_zero(this.nCtx, t.NativeObject)); @@ -3725,7 +3725,7 @@ namespace Microsoft.Z3 /// Predicate indicating whether t is a floating point number representing +Inf or -Inf /// /// floating point term - BoolExpr MkFPIsInf(FPExpr t) + public BoolExpr MkFPIsInf(FPExpr t) { Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_inf(this.nCtx, t.NativeObject)); @@ -3735,7 +3735,7 @@ namespace Microsoft.Z3 /// Predicate indicating whether t is a NaN /// /// floating point term - BoolExpr MkFPIsNaN(FPExpr t) + public BoolExpr MkFPIsNaN(FPExpr t) { Contract.Ensures(Contract.Result() != null); return new BoolExpr(this, Native.Z3_mk_fpa_is_nan(this.nCtx, t.NativeObject)); @@ -3746,7 +3746,7 @@ namespace Microsoft.Z3 /// /// floating point term /// floating point term - FPExpr MkFPMin(FPExpr t1, FPExpr t2) + 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)); @@ -3757,7 +3757,7 @@ namespace Microsoft.Z3 /// /// floating point term /// floating point term - FPExpr MkFPMax(FPExpr t1, FPExpr t2) + 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)); @@ -3773,7 +3773,7 @@ namespace Microsoft.Z3 /// floating point sort /// floating point rounding mode term /// floating point term - FPExpr MkFPConvert(FPSort s, FPRMExpr rm, FPExpr t) + public FPExpr MkFPConvert(FPSort s, FPRMExpr rm, FPExpr t) { Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_convert(this.nCtx, s.NativeObject, rm.NativeObject, t.NativeObject)); @@ -3786,7 +3786,7 @@ namespace Microsoft.Z3 /// The size of the resulting bit-vector is automatically determined. /// /// floating point term - FPExpr MkFPToIEEEBV(FPExpr t) + public FPExpr MkFPToIEEEBV(FPExpr t) { Contract.Ensures(Contract.Result() != null); return new FPExpr(this, Native.Z3_mk_fpa_to_ieee_bv(this.nCtx, t.NativeObject)); From 4af39b432cecc0fd3d3c1e4675154c4914ebad33 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 14 Jun 2013 12:25:43 +0100 Subject: [PATCH 008/118] FPA API: dotnet bugfixes Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Context.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 452018ae4..7da54c5eb 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3499,7 +3499,7 @@ namespace Microsoft.Z3 /// /// A string representing the value in decimal notation. /// floating point sort. - public FPNum MkFPNaN(double v, FPSort s) + public FPNum MkFPNaN(FPSort s) { Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_nan(nCtx, s.NativeObject)); @@ -3511,7 +3511,7 @@ namespace Microsoft.Z3 /// A string representing the value in decimal notation. /// floating point sort. /// indicates whether the result should be negative. - public FPNum MkFPInf(double v, FPSort s, bool 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)); From 165da842b7027e950d561363c23829aa74478896 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 14 Jun 2013 13:12:44 +0100 Subject: [PATCH 009/118] Numeral API: added floating-point numeral cases. Signed-off-by: Christoph M. Wintersteiger --- src/api/api_numeral.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 6924afff3..740fef2ac 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -58,6 +58,8 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } + sort * _ty = to_sort(ty); + bool is_float = mk_c(c)->float_util().is_float(_ty); std::string fixed_num; char const* m = n; while (*m) { @@ -65,14 +67,15 @@ extern "C" { ('/' == *m) || ('-' == *m) || (' ' == *m) || ('\n' == *m) || ('.' == *m) || ('e' == *m) || - ('E' == *m))) { + ('E' == *m) || + (('p' == *m) && is_float) || + (('P' == *m)) && is_float)) { SET_ERROR_CODE(Z3_PARSER_ERROR); return 0; } ++m; } - ast * a = 0; - sort * _ty = to_sort(ty); + ast * a = 0; if (_ty->get_family_id() == mk_c(c)->get_fpa_fid()) { // avoid expanding floats into huge rationals. From 8e497fbbaf06d179db93020d86c78e8479564aec Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 14 Jun 2013 13:13:14 +0100 Subject: [PATCH 010/118] Extended FPA dotnet example Signed-off-by: Christoph M. Wintersteiger --- examples/dotnet/Program.cs | 92 +++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 27 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index c75553e7b..2f9d24fb1 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -2029,8 +2029,46 @@ namespace test_mapi FPSort s = ctx.MkFPSort(11, 53); Console.WriteLine("Sort: {0}", s); - FPNum n = (FPNum) ctx.MkNumeral("0.125", s); - Console.WriteLine("Numeral: {0}", n.ToString()); + FPNum x = (FPNum)ctx.MkNumeral("-1e1", s); + Console.WriteLine("Numeral: {0}", x.ToString()); + + FPNum y = (FPNum)ctx.MkNumeral("-10", s); + Console.WriteLine("Numeral: {0}", y.ToString()); + + FPNum z = (FPNum)ctx.MkNumeral("-1.25p3", s); + Console.WriteLine("Numeral: {0}", z.ToString()); + + BoolExpr a = ctx.MkAnd(ctx.MkFPEq(x, y), ctx.MkFPEq(y, z)); + + Check(ctx, ctx.MkNot(a), Status.UNSATISFIABLE); + + x = ctx.MkFPNaN(s); + FPExpr c = (FPExpr)ctx.MkConst("y", s); + + // Note: We need to use a special solver for QF_FPA here; the + // general solver does not support FPA yet. + + Solver slvr = ctx.MkSolver("QF_FPA"); + slvr.Add(ctx.MkFPEq(x, c)); + if (slvr.Check() != Status.UNSATISFIABLE) // nothing is equal to NaN according to floating-point equality. + throw new TestFailedException(); + + slvr = ctx.MkSolver("QF_FPA"); + slvr.Add(ctx.MkEq(x, c)); // NaN is equal to NaN according to normal equality. + if (slvr.Check() != Status.SATISFIABLE) + throw new TestFailedException(); + + + x = (FPNum)ctx.MkNumeral("-1e1", s); + y = (FPNum)ctx.MkNumeral("-10", s); + FPExpr q = (FPExpr)ctx.MkConst("q", s); + FPNum mh = (FPNum)ctx.MkNumeral("100", s); + slvr = ctx.MkSolver("QF_FPA"); + // Let's prove -1e1 * -10 == +100 + slvr.Add(ctx.MkEq(ctx.MkFPMul(ctx.MkFPRMNearestTiesToAway(), x, y), q)); + slvr.Add(ctx.MkNot(ctx.MkFPEq(q, mh))); + if (slvr.Check() != Status.UNSATISFIABLE) + throw new TestFailedException(); } static void Main(string[] args) @@ -2050,30 +2088,30 @@ namespace test_mapi // These examples need model generation turned on. using (Context ctx = new Context(new Dictionary() { { "model", "true" } })) { - BasicTests(ctx); - CastingTest(ctx); - SudokuExample(ctx); - QuantifierExample1(ctx); - QuantifierExample2(ctx); - LogicExample(ctx); - ParOrExample(ctx); - FindModelExample1(ctx); - FindModelExample2(ctx); - PushPopExample1(ctx); - ArrayExample1(ctx); - ArrayExample3(ctx); - BitvectorExample1(ctx); - BitvectorExample2(ctx); - ParserExample1(ctx); - ParserExample2(ctx); - ParserExample4(ctx); - ParserExample5(ctx); - ITEExample(ctx); - EvalExample1(ctx); - EvalExample2(ctx); - FindSmallModelExample(ctx); - SimplifierExample(ctx); - FiniteDomainExample(ctx); + //BasicTests(ctx); + //CastingTest(ctx); + //SudokuExample(ctx); + //QuantifierExample1(ctx); + //QuantifierExample2(ctx); + //LogicExample(ctx); + //ParOrExample(ctx); + //FindModelExample1(ctx); + //FindModelExample2(ctx); + //PushPopExample1(ctx); + //ArrayExample1(ctx); + //ArrayExample3(ctx); + //BitvectorExample1(ctx); + //BitvectorExample2(ctx); + //ParserExample1(ctx); + //ParserExample2(ctx); + //ParserExample4(ctx); + //ParserExample5(ctx); + //ITEExample(ctx); + //EvalExample1(ctx); + //EvalExample2(ctx); + //FindSmallModelExample(ctx); + //SimplifierExample(ctx); + //FiniteDomainExample(ctx); FloatingPointExample(ctx); } @@ -2099,7 +2137,7 @@ namespace test_mapi { QuantifierExample3(ctx); QuantifierExample4(ctx); - } + } Log.Close(); if (Log.isOpen()) From f50016d8a1ab69ad729182f4c0d01e07bae340d6 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 14 Jun 2013 13:18:33 +0100 Subject: [PATCH 011/118] bugfix in .NET example Signed-off-by: Christoph M. Wintersteiger --- examples/dotnet/Program.cs | 48 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 2f9d24fb1..76624fa1c 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -2088,30 +2088,30 @@ namespace test_mapi // These examples need model generation turned on. using (Context ctx = new Context(new Dictionary() { { "model", "true" } })) { - //BasicTests(ctx); - //CastingTest(ctx); - //SudokuExample(ctx); - //QuantifierExample1(ctx); - //QuantifierExample2(ctx); - //LogicExample(ctx); - //ParOrExample(ctx); - //FindModelExample1(ctx); - //FindModelExample2(ctx); - //PushPopExample1(ctx); - //ArrayExample1(ctx); - //ArrayExample3(ctx); - //BitvectorExample1(ctx); - //BitvectorExample2(ctx); - //ParserExample1(ctx); - //ParserExample2(ctx); - //ParserExample4(ctx); - //ParserExample5(ctx); - //ITEExample(ctx); - //EvalExample1(ctx); - //EvalExample2(ctx); - //FindSmallModelExample(ctx); - //SimplifierExample(ctx); - //FiniteDomainExample(ctx); + BasicTests(ctx); + CastingTest(ctx); + SudokuExample(ctx); + QuantifierExample1(ctx); + QuantifierExample2(ctx); + LogicExample(ctx); + ParOrExample(ctx); + FindModelExample1(ctx); + FindModelExample2(ctx); + PushPopExample1(ctx); + ArrayExample1(ctx); + ArrayExample3(ctx); + BitvectorExample1(ctx); + BitvectorExample2(ctx); + ParserExample1(ctx); + ParserExample2(ctx); + ParserExample4(ctx); + ParserExample5(ctx); + ITEExample(ctx); + EvalExample1(ctx); + EvalExample2(ctx); + FindSmallModelExample(ctx); + SimplifierExample(ctx); + FiniteDomainExample(ctx); FloatingPointExample(ctx); } From fa9a9d13cf0d41fdbf409109999b9d31a574655a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 28 Jun 2013 12:13:02 +0100 Subject: [PATCH 012/118] FPA: avoid compiler warnings Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 234c343b8..ff24d1ceb 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -2437,7 +2437,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & t = m_bv_util.mk_bv_sub(t, lz); t = m_bv_util.mk_bv_sub(t, m_bv_util.mk_sign_extend(2, e_min)); expr_ref TINY(m); - TINY = m_bv_util.mk_sle(t, m_bv_util.mk_numeral(-1, ebits+2)); + TINY = m_bv_util.mk_sle(t, m_bv_util.mk_numeral((unsigned)-1, ebits+2)); TRACE("fpa2bv_dbg", tout << "TINY = " << mk_ismt2_pp(TINY, m) << std::endl;); SASSERT(is_well_sorted(m, TINY)); @@ -2481,7 +2481,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & m_simp.mk_ite(sigma_le_cap, sigma_neg, sigma_cap, sigma_neg_capped); dbg_decouple("fpa2bv_rnd_sigma_neg", sigma_neg); dbg_decouple("fpa2bv_rnd_sigma_neg_capped", sigma_neg_capped); - sigma_lt_zero = m_bv_util.mk_sle(sigma, m_bv_util.mk_numeral(-1, sigma_size)); + sigma_lt_zero = m_bv_util.mk_sle(sigma, m_bv_util.mk_numeral((unsigned)-1, sigma_size)); dbg_decouple("fpa2bv_rnd_sigma_lt_zero", sigma_lt_zero); sig_ext = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, sig_size)); From 0279a1042d6f7088e4628e592dc5ac9ef253bc92 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 23 Apr 2014 18:39:36 +0100 Subject: [PATCH 013/118] FPA API documentation fixes Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Context.cs | 7 +++---- src/api/dotnet/FPExpr.cs | 3 ++- src/api/dotnet/FPRMExpr.cs | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 7ef91f7ac..b654feb7e 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3506,8 +3506,7 @@ namespace Microsoft.Z3 /// /// Create a floating point NaN numeral. - /// - /// A string representing the value in decimal notation. + /// /// floating point sort. public FPNum MkFPNaN(FPSort s) { @@ -3517,8 +3516,7 @@ namespace Microsoft.Z3 /// /// Create a floating point Inf numeral. - /// - /// A string representing the value in decimal notation. + /// /// floating point sort. /// indicates whether the result should be negative. public FPNum MkFPInf(FPSort s, bool negative) @@ -3625,6 +3623,7 @@ namespace Microsoft.Z3 /// /// Floating-point square root /// + /// rounding mode term /// floating point term public FPExpr MkFPSqrt(FPRMExpr rm, FPExpr t) { diff --git a/src/api/dotnet/FPExpr.cs b/src/api/dotnet/FPExpr.cs index 66b3fc10d..0bb1e4c09 100644 --- a/src/api/dotnet/FPExpr.cs +++ b/src/api/dotnet/FPExpr.cs @@ -30,7 +30,8 @@ namespace Microsoft.Z3 /// public class FPExpr : Expr { - #region Internal + #region Internal + /// Constructor for FPExpr internal protected FPExpr(Context ctx) : base(ctx) { diff --git a/src/api/dotnet/FPRMExpr.cs b/src/api/dotnet/FPRMExpr.cs index fa43a346a..b95816023 100644 --- a/src/api/dotnet/FPRMExpr.cs +++ b/src/api/dotnet/FPRMExpr.cs @@ -31,6 +31,7 @@ namespace Microsoft.Z3 public class FPRMExpr : Expr { #region Internal + /// Constructor for FPRMExpr internal protected FPRMExpr(Context ctx) : base(ctx) { From a8b65ebb360168c9659e943e3f264690c5d8e3f8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 23 Apr 2014 20:10:53 +0100 Subject: [PATCH 014/118] added stubs for theory_fpa Signed-off-by: Christoph M. Wintersteiger --- examples/c/test_capi.c | 36 +++++++++++++++++++++++++++++++++++ src/ast/fpa/fpa2bv_rewriter.h | 6 ++---- src/smt/smt_setup.cpp | 15 +++++++++++++++ src/smt/smt_setup.h | 6 +++++- src/smt/theory_fpa.cpp | 19 ++++++++++++++++-- src/smt/theory_fpa.h | 8 +++++--- 6 files changed, 80 insertions(+), 10 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 27bf6de2c..4363ee382 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2595,6 +2595,42 @@ void substitute_vars_example() { Z3_del_context(ctx); } +void fpa_example() { + Z3_config cfg; + Z3_context ctx; + Z3_sort double_sort, rm_sort; + Z3_symbol symbol_rm, symbol_x, symbol_y; + Z3_ast rm, x, y, n, c; + + printf("\nFPA-example\n"); + LOG_MSG("FPA-example"); + + enable_trace("fpa"); + + 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); + + symbol_rm = Z3_mk_string_symbol(ctx, "rm"); + rm = Z3_mk_const(ctx, symbol_rm, rm_sort); + symbol_x = Z3_mk_string_symbol(ctx, "x"); + symbol_y = Z3_mk_string_symbol(ctx, "y"); + x = Z3_mk_const(ctx, symbol_x, double_sort); + y = Z3_mk_const(ctx, symbol_y, double_sort); + n = Z3_mk_double(ctx, 42.0, double_sort); + + c = Z3_mk_eq(ctx, Z3_mk_fpa_add(ctx, rm, x, y), n); + + Z3_assert_cnstr(ctx, c); + if (Z3_check(ctx) != Z3_L_TRUE) + printf("FPA-example not satisfied!\n"); + + Z3_del_context(ctx); +} + /*@}*/ /*@}*/ diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index b2e3da939..bdfa6ca3f 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -64,9 +64,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { } bool max_steps_exceeded(unsigned num_steps) const { - cooperate("fpa2bv"); - if (memory::get_allocation_size() > m_max_memory) - throw tactic_exception(TACTIC_MAX_MEMORY_MSG); + cooperate("fpa2bv"); return num_steps > m_max_steps; } @@ -147,7 +145,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { 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;); - throw tactic_exception("NYI"); + NOT_IMPLEMENTED_YET(); } } diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 51b83d61c..64477164a 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_FPA() { + m_context.register_plugin(alloc(smt::theory_fpa, m_manager)); + } + + void setup::setup_QF_FPABV() { + 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) { diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index e0188537e..299ce7834 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_FPA(); + void setup_QF_FPABV(); 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..e235dbb06 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -17,14 +17,29 @@ Revision History: --*/ #include"ast_smt2_pp.h" +#include"smt_context.h" #include"theory_fpa.h" namespace smt { + theory_fpa::theory_fpa(ast_manager & m) : + theory(m.mk_family_id("float")), + m_converter(m), + m_rw(m, m_converter, params_ref()) + { + } + bool theory_fpa::internalize_atom(app * atom, bool gate_ctx) { - TRACE("bv", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << "\n";); + TRACE("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(); + + expr_ref res(m); + m_rw(atom, res); + SASSERT(res.get() != atom); + ctx.internalize(res, gate_ctx); return true; } diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 3716247d3..bb3a8b786 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -21,14 +21,16 @@ Revision History: #include"smt_theory.h" #include"fpa2bv_converter.h" +#include"fpa2bv_rewriter.h" namespace smt { class theory_fpa : public theory { fpa2bv_converter m_converter; + fpa2bv_rewriter m_rw; 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); } + virtual bool internalize_atom(app * a, bool); + virtual bool internalize_term(app * a) { return internalize_atom(a, false); } virtual void new_eq_eh(theory_var, theory_var); virtual void new_diseq_eh(theory_var, theory_var); virtual void push_scope_eh(); @@ -36,7 +38,7 @@ namespace smt { virtual theory* mk_fresh(context*) { return alloc(theory_fpa, get_manager()); } virtual char const * get_name() const { return "fpa"; } public: - theory_fpa(ast_manager& m) : theory(m.mk_family_id("fpa")), m_converter(m) {} + theory_fpa(ast_manager& m); }; }; From baee61a2e48e7c601aad89797e15133f8768af0e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 2 Jun 2014 17:57:59 +0100 Subject: [PATCH 015/118] More experimental FPA theory code Signed-off-by: Christoph M. Wintersteiger --- src/smt/theory_fpa.cpp | 254 +++++++++++++++++++++++++++++++++++++++-- src/smt/theory_fpa.h | 23 +++- 2 files changed, 263 insertions(+), 14 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index e235dbb06..bd95d78f1 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -19,43 +19,275 @@ Revision History: #include"ast_smt2_pp.h" #include"smt_context.h" #include"theory_fpa.h" +#include"smt_model_generator.h" namespace smt { theory_fpa::theory_fpa(ast_manager & m) : theory(m.mk_family_id("float")), m_converter(m), - m_rw(m, m_converter, params_ref()) + m_rw(m, m_converter, params_ref()), + m_trans_map(m), + m_trail_stack(*this) { } bool theory_fpa::internalize_atom(app * atom, bool gate_ctx) { TRACE("fpa", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << "\n";); SASSERT(atom->get_family_id() == get_family_id()); + NOT_IMPLEMENTED_YET(); + } + + bool theory_fpa::internalize_term(app * term) { + TRACE("fpa", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";); + SASSERT(term->get_family_id() == get_family_id()); + SASSERT(!get_context().e_internalized(term)); ast_manager & m = get_manager(); context & ctx = get_context(); + simplifier & simp = ctx.get_simplifier(); + unsigned num_args = term->get_num_args(); + for (unsigned i = 0; i < num_args; i++) + ctx.internalize(term->get_arg(i), false); + expr_ref res(m); - m_rw(atom, res); - SASSERT(res.get() != atom); - ctx.internalize(res, gate_ctx); - return true; + m_rw(term, res); + SASSERT(is_app(res) && to_app(res)->get_num_args() == 3); + app * a = to_app(res); + TRACE("fpa", tout << "converted: " << mk_ismt2_pp(res, get_manager()) << "\n";); + + expr_ref sgn(m), sig(m), exp(m); + proof_ref pr_sgn(m), pr_sig(m), pr_exp(m); + simp(a->get_arg(0), sgn, pr_sgn); + simp(a->get_arg(1), sig, pr_sig); + simp(a->get_arg(2), exp, pr_exp); + + ctx.internalize(sgn, false); + ctx.internalize(sig, false); + ctx.internalize(exp, false); + + expr_ref s_term(m); + m_converter.mk_triple(sgn, sig, exp, s_term); + + SASSERT(!m_trans_map.contains(term)); + m_trans_map.insert(term, s_term, 0); + + enode * e = ctx.mk_enode(term, false, false, true); + theory_var v = mk_var(e); + ctx.attach_th_var(e, this, v); + TRACE("fpa", tout << "new theory var: " << mk_ismt2_pp(term, get_manager()) << " := " << v << "\n";); + SASSERT(e->get_th_var(get_id()) != null_theory_var); + + return v != null_theory_var; } - void theory_fpa::new_eq_eh(theory_var, theory_var) { - NOT_IMPLEMENTED_YET(); + void theory_fpa::apply_sort_cnstr(enode * n, sort * s) { + if (!is_attached_to_var(n)) { + context & ctx = get_context(); + ast_manager & m = get_manager(); + simplifier & simp = ctx.get_simplifier(); + app * owner = n->get_owner(); + expr_ref converted(m); + + theory_var v = mk_var(n); + ctx.attach_th_var(n, this, v); + m_rw(owner, converted); + m_trans_map.insert(owner, converted, 0); + + if (m_converter.is_rm_sort(m.get_sort(owner))) { + ctx.internalize(converted, false); + } + else { + app * a = to_app(converted); + expr_ref sgn(m), sig(m), exp(m); + proof_ref pr_sgn(m), pr_sig(m), pr_exp(m); + simp(a->get_arg(0), sgn, pr_sgn); + simp(a->get_arg(1), sig, pr_sig); + simp(a->get_arg(2), exp, pr_exp); + + ctx.internalize(sgn, false); + ctx.internalize(sig, false); + ctx.internalize(exp, false); + } + + TRACE("fpa", tout << "new const: " << mk_ismt2_pp(owner, get_manager()) << " := " << v << "\n";); + } } - 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) { + TRACE("fpa", tout << "new eq: " << x << " = " << y << "\n";); + ast_manager & m = get_manager(); + context & ctx = get_context(); + app * ax = get_enode(x)->get_owner(); + app * ay = get_enode(y)->get_owner(); + + expr * ex, * ey; + proof * px, * py; + m_trans_map.get(ax, ex, px); + m_trans_map.get(ay, ey, py); + + expr * sgn_x, * sig_x, * exp_x; + expr * sgn_y, * sig_y, * exp_y; + split_triple(ex, sgn_x, sig_x, exp_x); + split_triple(ey, sgn_y, sig_y, exp_y); + + literal_vector lits; + lits.push_back(mk_eq(ax, ay, true)); + + expr_ref e1(m), e2(m), e3(m); + e1 = m.mk_eq(sgn_x, sgn_y); + e2 = m.mk_eq(sig_x, sig_y); + e3 = m.mk_eq(exp_x, exp_y); + ctx.internalize(e1, true); + ctx.internalize(e2, true); + ctx.internalize(e3, true); + lits.push_back(ctx.get_literal(e1)); + lits.push_back(ctx.get_literal(e2)); + lits.push_back(ctx.get_literal(e3)); + + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + } + + void theory_fpa::new_diseq_eh(theory_var x, theory_var y) { + TRACE("fpa", tout << "new eq: " << x << " = " << y << "\n";); + ast_manager & m = get_manager(); + context & ctx = get_context(); + app * ax = get_enode(x)->get_owner(); + app * ay = get_enode(y)->get_owner(); + + expr * ex, *ey; + proof * px, *py; + m_trans_map.get(ax, ex, px); + m_trans_map.get(ay, ey, py); + + expr * sgn_x, *sig_x, *exp_x; + expr * sgn_y, *sig_y, *exp_y; + split_triple(ex, sgn_x, sig_x, exp_x); + split_triple(ex, sgn_y, sig_y, exp_y); + + ctx.internalize(m.mk_not(m.mk_eq(sgn_x, sgn_y)), true); + ctx.internalize(m.mk_not(m.mk_eq(sig_x, sig_y)), true); + ctx.internalize(m.mk_not(m.mk_eq(exp_x, exp_y)), true); } 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(); + m_trail_stack.pop_scope(num_scopes); + theory::pop_scope_eh(num_scopes); + } + + model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) { + ast_manager & m = get_manager(); + context & ctx = get_context(); + bv_util & bu = m_converter.bu(); + float_util & fu = m_converter.fu(); + unsynch_mpz_manager & mpzm = fu.fm().mpz_manager(); + unsynch_mpq_manager & mpqm = fu.fm().mpq_manager(); + + theory_var v = n->get_th_var(get_id()); + SASSERT(v != null_theory_var); + expr * fpa_e = get_enode(v)->get_owner(); + TRACE("fpa", tout << "mk_value for: " << mk_ismt2_pp(fpa_e, m) << "\n";); + + expr * bv_e; + proof * bv_pr; + m_trans_map.get(fpa_e, bv_e, bv_pr); + + expr_wrapper_proc * res = 0; + + if (fu.is_rm(m.get_sort(fpa_e))) { + SASSERT(ctx.e_internalized(bv_e)); + sort * s = m.get_sort(bv_e); + family_id fid = s->get_family_id(); + theory * bv_th = ctx.get_theory(fid); + + enode * ev = ctx.get_enode(bv_e); + ptr_vector pve; + app_ref mv(m); + mv = ((expr_wrapper_proc*)bv_th->mk_value(ev, mg))->mk_value(mg, pve); + + rational val(0); + unsigned sz = 0; + if (bu.is_numeral(mv, val, sz)) { + app_ref fp_val_e(m); + SASSERT(val.is_uint64()); + switch (val.get_uint64()) + { + case BV_RM_TIES_TO_AWAY: fp_val_e = fu.mk_round_nearest_ties_to_away(); break; + case BV_RM_TIES_TO_EVEN: fp_val_e = fu.mk_round_nearest_ties_to_even(); break; + case BV_RM_TO_NEGATIVE: fp_val_e = fu.mk_round_toward_negative(); break; + case BV_RM_TO_POSITIVE: fp_val_e = fu.mk_round_toward_positive(); break; + case BV_RM_TO_ZERO: + default: fp_val_e = fu.mk_round_toward_zero(); + } + + TRACE("fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mk_ismt2_pp(fp_val_e, m) << std::endl;); + res = alloc(expr_wrapper_proc, fp_val_e); + m.inc_ref(fp_val_e); + } + } + else { + expr * bv_sgn, *bv_sig, *bv_exp; + split_triple(bv_e, bv_sgn, bv_sig, bv_exp); + + SASSERT(ctx.e_internalized(bv_sgn)); + SASSERT(ctx.e_internalized(bv_sig)); + SASSERT(ctx.e_internalized(bv_exp)); + + enode * e_sgn = ctx.get_enode(bv_sgn); + enode * e_sig = ctx.get_enode(bv_sig); + enode * e_exp = ctx.get_enode(bv_exp); + + sort * s = m.get_sort(e_sgn->get_owner()); + family_id fid = s->get_family_id(); + theory * bv_th = ctx.get_theory(fid); + + expr_wrapper_proc * mv_sgn = (expr_wrapper_proc*)bv_th->mk_value(e_sgn, mg); + expr_wrapper_proc * mv_sig = (expr_wrapper_proc*)bv_th->mk_value(e_sig, mg); + expr_wrapper_proc * mv_exp = (expr_wrapper_proc*)bv_th->mk_value(e_exp, mg); + + ptr_vector pve; + app_ref bvm_sgn(m), bvm_sig(m), bvm_exp(m); + bvm_sgn = mv_sgn->mk_value(mg, pve); + bvm_sig = mv_sig->mk_value(mg, pve); + bvm_exp = mv_exp->mk_value(mg, pve); + + TRACE("fpa", tout << "bv model: [" << mk_ismt2_pp(bvm_sgn, get_manager()) << " " + << mk_ismt2_pp(bvm_sig, get_manager()) << " " + << mk_ismt2_pp(bvm_exp, get_manager()) << "]\n";); + + unsigned sgn_sz, sig_sz, exp_sz; + rational sgn_q(0), sig_q(0), exp_q(0); + if (bvm_sgn) bu.is_numeral(bvm_sgn, sgn_q, sgn_sz); + if (bvm_sig) bu.is_numeral(bvm_sig, sig_q, sig_sz); + if (bvm_exp) bu.is_numeral(bvm_exp, exp_q, exp_sz); + + // un-bias exponent + rational exp_unbiased_q; + exp_unbiased_q = exp_q - fu.fm().m_powers2.m1(exp_sz - 1); + + mpz sig_z; mpf_exp_t exp_z; + mpzm.set(sig_z, sig_q.to_mpq().numerator()); + exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator()); + + mpf fp_val; + fu.fm().set(fp_val, exp_sz, sig_sz+1, !mpqm.is_zero(sgn_q.to_mpq()), sig_z, exp_z); + + app_ref fp_val_e(m); + fp_val_e = fu.mk_value(fp_val); + mpzm.del(sig_z); + + TRACE("fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mk_ismt2_pp(fp_val_e, m) << std::endl;); + + res = alloc(expr_wrapper_proc, fp_val_e); + m.inc_ref(fp_val_e); + } + + return res; } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index bb3a8b786..51e0ff0d5 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -25,20 +25,37 @@ Revision History: namespace smt { class theory_fpa : public theory { + typedef trail_stack th_trail_stack; + fpa2bv_converter m_converter; fpa2bv_rewriter m_rw; + expr_map m_trans_map; + th_trail_stack m_trail_stack; virtual final_check_status final_check_eh() { return FC_DONE; } - virtual bool internalize_atom(app * a, bool); - virtual bool internalize_term(app * a) { return internalize_atom(a, false); } + 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 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); + public: theory_fpa(ast_manager& m); + + protected: + void split_triple(expr * e, expr * & sgn, expr * & sig, expr * & exp) const { + SASSERT(is_app_of(e, get_family_id(), OP_TO_FLOAT)); + 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); + } }; }; From c2a2d2d0dfdccccc9e611d8556014fdff774be3f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 11 Jun 2014 13:27:21 +0100 Subject: [PATCH 016/118] Renamed Z3_mk_double to Z3_mk_fpa_double for consistency Signed-off-by: Christoph M. Wintersteiger --- src/api/api_fpa.cpp | 4 ++-- src/api/z3_fpa.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 278a0556a..374e3d344 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -121,9 +121,9 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_double(Z3_context c, double v, Z3_sort ty) { + Z3_ast Z3_API Z3_mk_fpa_double(Z3_context c, double v, Z3_sort ty) { Z3_TRY; - LOG_Z3_mk_double(c, v, ty); + LOG_Z3_mk_fpa_double(c, v, ty); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); scoped_mpf tmp(ctx->float_util().fm()); diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 93268b821..81cfff591 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -131,7 +131,7 @@ extern "C" { def_API('Z3_mk_double', AST, (_in(CONTEXT), _in(DOUBLE), _in(SORT))) */ - Z3_ast Z3_API Z3_mk_double(__in Z3_context c, __in double v, __in Z3_sort ty); + Z3_ast Z3_API Z3_mk_fpa_double(__in Z3_context c, __in double v, __in Z3_sort ty); /** \brief Floating-point absolute value From ca89b120d3b2c1ebb83eb996f022425c701768db Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 11 Jun 2014 16:44:12 +0100 Subject: [PATCH 017/118] improve FPA theory implementation Signed-off-by: Christoph M. Wintersteiger --- src/smt/theory_fpa.cpp | 239 ++++++++++++++++++++++++++++------------- src/smt/theory_fpa.h | 7 +- 2 files changed, 170 insertions(+), 76 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index bd95d78f1..e606857e5 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -19,27 +19,32 @@ 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 { - theory_fpa::theory_fpa(ast_manager & m) : - theory(m.mk_family_id("float")), - m_converter(m), + theory_fpa::theory_fpa(ast_manager & m) : + theory(m.mk_family_id("float")), + m_converter(m), m_rw(m, m_converter, params_ref()), m_trans_map(m), m_trail_stack(*this) { } + theory_fpa::~theory_fpa() + { + } + bool theory_fpa::internalize_atom(app * atom, bool gate_ctx) { - TRACE("fpa", 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(); } bool theory_fpa::internalize_term(app * term) { - TRACE("fpa", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";); + TRACE("t_fpa", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";); SASSERT(term->get_family_id() == get_family_id()); SASSERT(!get_context().e_internalized(term)); @@ -55,7 +60,7 @@ namespace smt { m_rw(term, res); SASSERT(is_app(res) && to_app(res)->get_num_args() == 3); app * a = to_app(res); - TRACE("fpa", tout << "converted: " << mk_ismt2_pp(res, get_manager()) << "\n";); + TRACE("t_fpa", tout << "converted: " << mk_ismt2_pp(res, get_manager()) << "\n";); expr_ref sgn(m), sig(m), exp(m); proof_ref pr_sgn(m), pr_sig(m), pr_exp(m); @@ -63,20 +68,34 @@ namespace smt { simp(a->get_arg(1), sig, pr_sig); simp(a->get_arg(2), exp, pr_exp); - ctx.internalize(sgn, false); - ctx.internalize(sig, false); - ctx.internalize(exp, false); + expr_ref bv_v_sgn(m), bv_v_sig(m), bv_v_exp(m); + bv_v_sgn = m.mk_fresh_const("fpa2bv", m.get_sort(sgn)); + bv_v_sig = m.mk_fresh_const("fpa2bv", m.get_sort(sig)); + bv_v_exp = m.mk_fresh_const("fpa2bv", m.get_sort(exp)); + expr_ref e1(m), e2(m), e3(m); + e1 = m.mk_eq(bv_v_sgn, sgn); + e2 = m.mk_eq(bv_v_sig, sig); + e3 = m.mk_eq(bv_v_exp, exp); + ctx.internalize(e1, false); + ctx.internalize(e2, false); + ctx.internalize(e3, false); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e1)); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e2)); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e3)); + ctx.mark_as_relevant(e1); + ctx.mark_as_relevant(e2); + ctx.mark_as_relevant(e3); expr_ref s_term(m); - m_converter.mk_triple(sgn, sig, exp, s_term); + m_converter.mk_triple(bv_v_sgn, bv_v_sig, bv_v_exp, s_term); SASSERT(!m_trans_map.contains(term)); m_trans_map.insert(term, s_term, 0); enode * e = ctx.mk_enode(term, false, false, true); - theory_var v = mk_var(e); + theory_var v = mk_var(e); ctx.attach_th_var(e, this, v); - TRACE("fpa", tout << "new theory var: " << mk_ismt2_pp(term, get_manager()) << " := " << v << "\n";); + TRACE("t_fpa", tout << "new theory var: " << mk_ismt2_pp(term, get_manager()) << " := " << v << "\n";); SASSERT(e->get_th_var(get_id()) != null_theory_var); return v != null_theory_var; @@ -84,6 +103,7 @@ namespace smt { void theory_fpa::apply_sort_cnstr(enode * n, sort * s) { if (!is_attached_to_var(n)) { + TRACE("t_fpa", tout << "apply sort cnstr for: " << mk_ismt2_pp(n->get_owner(), get_manager()) << "\n";); context & ctx = get_context(); ast_manager & m = get_manager(); simplifier & simp = ctx.get_simplifier(); @@ -96,7 +116,12 @@ namespace smt { m_trans_map.insert(owner, converted, 0); if (m_converter.is_rm_sort(m.get_sort(owner))) { - ctx.internalize(converted, false); + expr_ref bv_v(m), eq(m); + bv_v = m.mk_fresh_const("fpa2bv", m.get_sort(converted)); + eq = m.mk_eq(bv_v, converted); + ctx.internalize(eq, false); + literal l = ctx.get_literal(eq); + ctx.mk_th_axiom(get_id(), 1, &l); } else { app * a = to_app(converted); @@ -109,14 +134,32 @@ namespace smt { ctx.internalize(sgn, false); ctx.internalize(sig, false); ctx.internalize(exp, false); + + expr_ref bv_v_sgn(m), bv_v_sig(m), bv_v_exp(m); + bv_v_sgn = m.mk_fresh_const("fpa2bv", m.get_sort(sgn)); + bv_v_sig = m.mk_fresh_const("fpa2bv", m.get_sort(sig)); + bv_v_exp = m.mk_fresh_const("fpa2bv", m.get_sort(exp)); + expr_ref e1(m), e2(m), e3(m); + e1 = m.mk_eq(bv_v_sgn, sgn); + e2 = m.mk_eq(bv_v_sig, sig); + e3 = m.mk_eq(bv_v_exp, exp); + ctx.internalize(e1, true); + ctx.internalize(e2, true); + ctx.internalize(e3, true); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e1)); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e2)); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e3)); + ctx.mark_as_relevant(e1); + ctx.mark_as_relevant(e2); + ctx.mark_as_relevant(e3); } - TRACE("fpa", tout << "new const: " << mk_ismt2_pp(owner, get_manager()) << " := " << v << "\n";); + TRACE("t_fpa", tout << "new theory var (const): " << mk_ismt2_pp(owner, get_manager()) << " := " << v << "\n";); } } void theory_fpa::new_eq_eh(theory_var x, theory_var y) { - TRACE("fpa", tout << "new eq: " << x << " = " << y << "\n";); + TRACE("t_fpa", tout << "new eq: " << x << " = " << y << "\n";); ast_manager & m = get_manager(); context & ctx = get_context(); app * ax = get_enode(x)->get_owner(); @@ -132,9 +175,6 @@ namespace smt { split_triple(ex, sgn_x, sig_x, exp_x); split_triple(ey, sgn_y, sig_y, exp_y); - literal_vector lits; - lits.push_back(mk_eq(ax, ay, true)); - expr_ref e1(m), e2(m), e3(m); e1 = m.mk_eq(sgn_x, sgn_y); e2 = m.mk_eq(sig_x, sig_y); @@ -142,15 +182,16 @@ namespace smt { ctx.internalize(e1, true); ctx.internalize(e2, true); ctx.internalize(e3, true); - lits.push_back(ctx.get_literal(e1)); - lits.push_back(ctx.get_literal(e2)); - lits.push_back(ctx.get_literal(e3)); - - ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e1)); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e2)); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e3)); + ctx.mark_as_relevant(e1); + ctx.mark_as_relevant(e2); + ctx.mark_as_relevant(e3); } void theory_fpa::new_diseq_eh(theory_var x, theory_var y) { - TRACE("fpa", tout << "new eq: " << x << " = " << y << "\n";); + TRACE("t_fpa", tout << "new eq: " << x << " = " << y << "\n";); ast_manager & m = get_manager(); context & ctx = get_context(); app * ax = get_enode(x)->get_owner(); @@ -166,9 +207,13 @@ namespace smt { split_triple(ex, sgn_x, sig_x, exp_x); split_triple(ex, sgn_y, sig_y, exp_y); - ctx.internalize(m.mk_not(m.mk_eq(sgn_x, sgn_y)), true); - ctx.internalize(m.mk_not(m.mk_eq(sig_x, sig_y)), true); - ctx.internalize(m.mk_not(m.mk_eq(exp_x, exp_y)), true); + expr_ref e1(m), e2(m), e3(m); + e1 = m.mk_not(m.mk_eq(sgn_x, sgn_y)); + e2 = m.mk_or(e1, m.mk_not(m.mk_eq(sig_x, sig_y))); + e3 = m.mk_or(e2, m.mk_not(m.mk_eq(exp_x, exp_y))); + ctx.internalize(e3, true); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e3)); + ctx.mark_as_relevant(e3); } void theory_fpa::push_scope_eh() { @@ -186,13 +231,14 @@ namespace smt { context & ctx = get_context(); bv_util & bu = m_converter.bu(); float_util & fu = m_converter.fu(); - unsynch_mpz_manager & mpzm = fu.fm().mpz_manager(); - unsynch_mpq_manager & mpqm = fu.fm().mpq_manager(); + mpf_manager & mpfm = fu.fm(); + unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); + unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); theory_var v = n->get_th_var(get_id()); SASSERT(v != null_theory_var); expr * fpa_e = get_enode(v)->get_owner(); - TRACE("fpa", tout << "mk_value for: " << mk_ismt2_pp(fpa_e, m) << "\n";); + TRACE("t_fpa", tout << "mk_value for: " << mk_ismt2_pp(fpa_e, m) << "\n";); expr * bv_e; proof * bv_pr; @@ -204,17 +250,14 @@ namespace smt { SASSERT(ctx.e_internalized(bv_e)); sort * s = m.get_sort(bv_e); family_id fid = s->get_family_id(); - theory * bv_th = ctx.get_theory(fid); - - enode * ev = ctx.get_enode(bv_e); - ptr_vector pve; - app_ref mv(m); - mv = ((expr_wrapper_proc*)bv_th->mk_value(ev, mg))->mk_value(mg, pve); - - rational val(0); - unsigned sz = 0; - if (bu.is_numeral(mv, val, sz)) { - app_ref fp_val_e(m); + theory_bv * bv_th = (theory_bv*)ctx.get_theory(fid); + rational val; + if (!bv_th->get_fixed_value(ctx.get_enode(bv_e)->get_owner(), val)) { + NOT_IMPLEMENTED_YET(); + } + else + { + app * fp_val_e; SASSERT(val.is_uint64()); switch (val.get_uint64()) { @@ -226,9 +269,8 @@ namespace smt { default: fp_val_e = fu.mk_round_toward_zero(); } - TRACE("fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mk_ismt2_pp(fp_val_e, m) << std::endl;); + TRACE("t_fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mk_ismt2_pp(fp_val_e, m) << std::endl;); res = alloc(expr_wrapper_proc, fp_val_e); - m.inc_ref(fp_val_e); } } else { @@ -241,53 +283,100 @@ namespace smt { enode * e_sgn = ctx.get_enode(bv_sgn); enode * e_sig = ctx.get_enode(bv_sig); - enode * e_exp = ctx.get_enode(bv_exp); + enode * e_exp = ctx.get_enode(bv_exp); + + TRACE("t_fpa", tout << "bv rep: [" << mk_ismt2_pp(e_sgn->get_owner(), m) << " " + << mk_ismt2_pp(e_sig->get_owner(), m) << " " + << mk_ismt2_pp(e_exp->get_owner(), m) << "]\n";); sort * s = m.get_sort(e_sgn->get_owner()); family_id fid = s->get_family_id(); - theory * bv_th = ctx.get_theory(fid); + theory_bv * bv_th = (theory_bv*)ctx.get_theory(fid); - expr_wrapper_proc * mv_sgn = (expr_wrapper_proc*)bv_th->mk_value(e_sgn, mg); - expr_wrapper_proc * mv_sig = (expr_wrapper_proc*)bv_th->mk_value(e_sig, mg); - expr_wrapper_proc * mv_exp = (expr_wrapper_proc*)bv_th->mk_value(e_exp, mg); + SASSERT(bv_th->is_attached_to_var(e_sgn)); + SASSERT(bv_th->is_attached_to_var(e_sig)); + SASSERT(bv_th->is_attached_to_var(e_exp)); - ptr_vector pve; - app_ref bvm_sgn(m), bvm_sig(m), bvm_exp(m); - bvm_sgn = mv_sgn->mk_value(mg, pve); - bvm_sig = mv_sig->mk_value(mg, pve); - bvm_exp = mv_exp->mk_value(mg, pve); + unsigned sig_sz, exp_sz; + sig_sz = bu.get_bv_size(e_sig->get_owner()); + exp_sz = bu.get_bv_size(e_exp->get_owner()); - TRACE("fpa", tout << "bv model: [" << mk_ismt2_pp(bvm_sgn, get_manager()) << " " - << mk_ismt2_pp(bvm_sig, get_manager()) << " " - << mk_ismt2_pp(bvm_exp, get_manager()) << "]\n";); + rational sgn_r(0), sig_r(0), exp_r(0); + + if (!bv_th->get_fixed_value(e_sgn->get_owner(), sgn_r) || + !bv_th->get_fixed_value(e_sig->get_owner(), sig_r) || + !bv_th->get_fixed_value(e_exp->get_owner(), exp_r)) { + NOT_IMPLEMENTED_YET(); + } + else { + TRACE("t_fpa", tout << "bv model: [" << sgn_r.to_string() << " " + << sig_r.to_string() << " " + << exp_r.to_string() << "]\n";); - unsigned sgn_sz, sig_sz, exp_sz; - rational sgn_q(0), sig_q(0), exp_q(0); - if (bvm_sgn) bu.is_numeral(bvm_sgn, sgn_q, sgn_sz); - if (bvm_sig) bu.is_numeral(bvm_sig, sig_q, sig_sz); - if (bvm_exp) bu.is_numeral(bvm_exp, exp_q, exp_sz); + // un-bias exponent + rational exp_unbiased_r; + exp_unbiased_r = exp_r - mpfm.m_powers2.m1(exp_sz - 1); - // un-bias exponent - rational exp_unbiased_q; - exp_unbiased_q = exp_q - fu.fm().m_powers2.m1(exp_sz - 1); + mpz sig_z; mpf_exp_t exp_z; + mpq sig_q, exp_q; + mpz sig_num, exp_num; + mpqm.set(sig_q, sig_r.to_mpq()); + mpzm.set(sig_num, sig_q.numerator()); + mpqm.set(exp_q, exp_unbiased_r.to_mpq()); + mpzm.set(exp_num, exp_q.numerator()); + mpzm.set(sig_z, sig_num); + exp_z = mpzm.get_int64(exp_num); - mpz sig_z; mpf_exp_t exp_z; - mpzm.set(sig_z, sig_q.to_mpq().numerator()); - exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator()); + mpf fp_val; + mpfm.set(fp_val, exp_sz, sig_sz + 1, !sgn_r.is_zero(), sig_z, exp_z); - mpf fp_val; - fu.fm().set(fp_val, exp_sz, sig_sz+1, !mpqm.is_zero(sgn_q.to_mpq()), sig_z, exp_z); + app * fp_val_e; + fp_val_e = fu.mk_value(fp_val); - app_ref fp_val_e(m); - fp_val_e = fu.mk_value(fp_val); - mpzm.del(sig_z); + TRACE("t_fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mk_ismt2_pp(fp_val_e, m) << std::endl;); - TRACE("fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mk_ismt2_pp(fp_val_e, m) << std::endl;); + mpfm.del(fp_val); + mpzm.del(sig_num); + mpzm.del(exp_num); + mpqm.del(sig_q); + mpqm.del(exp_q); + mpzm.del(sig_z); - res = alloc(expr_wrapper_proc, fp_val_e); - m.inc_ref(fp_val_e); + res = alloc(expr_wrapper_proc, fp_val_e); + } } return res; } + + void theory_fpa::assign_eh(bool_var v, bool is_true) { + TRACE("t_fpa", tout << "assign_eh for: " << v << " (" << is_true << ")\n";); + UNREACHABLE(); + } + + void theory_fpa::relevant_eh(app * n) { + ast_manager & m = get_manager(); + context & ctx = get_context(); + float_util & fu = m_converter.fu(); + if (ctx.e_internalized(n)) { + SASSERT(m_trans_map.contains(n)); + expr * ex; + proof * px; + m_trans_map.get(n, ex, px); + + if (fu.is_rm(m.get_sort(n))) { + ctx.mark_as_relevant(ex); + } + else { + expr * bv_sgn, *bv_sig, *bv_exp; + split_triple(ex, bv_sgn, bv_sig, bv_exp); + + ctx.mark_as_relevant(bv_sgn); + ctx.mark_as_relevant(bv_sig); + ctx.mark_as_relevant(bv_exp); + } + } + else + NOT_IMPLEMENTED_YET(); + } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 51e0ff0d5..4a465ada2 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -44,9 +44,12 @@ namespace smt { 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); public: theory_fpa(ast_manager& m); + virtual ~theory_fpa(); protected: void split_triple(expr * e, expr * & sgn, expr * & sig, expr * & exp) const { @@ -56,6 +59,8 @@ namespace smt { sig = to_app(e)->get_arg(1); exp = to_app(e)->get_arg(2); } + + void ensure_bv_var(expr_ref const & n); }; }; From 129e2f5e238daf2bb37d2e1e9dcc425a741fbf75 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 11 Jun 2014 17:55:31 +0100 Subject: [PATCH 018/118] FPA API fixes and examples Signed-off-by: Christoph M. Wintersteiger --- examples/c/test_capi.c | 55 +++++++++++++++++++++++++++------------ src/api/dotnet/Context.cs | 2 +- src/api/z3_fpa.h | 2 +- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 4363ee382..578c563b7 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2604,29 +2604,49 @@ void fpa_example() { printf("\nFPA-example\n"); LOG_MSG("FPA-example"); - - enable_trace("fpa"); - cfg = Z3_mk_config(); - ctx = Z3_mk_context(cfg); + 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); + double_sort = Z3_mk_fpa_sort(ctx, 11, 53); + rm_sort = Z3_mk_fpa_rounding_mode_sort(ctx); - symbol_rm = Z3_mk_string_symbol(ctx, "rm"); - rm = Z3_mk_const(ctx, symbol_rm, rm_sort); - symbol_x = Z3_mk_string_symbol(ctx, "x"); - symbol_y = Z3_mk_string_symbol(ctx, "y"); - x = Z3_mk_const(ctx, symbol_x, double_sort); - y = Z3_mk_const(ctx, symbol_y, double_sort); - n = Z3_mk_double(ctx, 42.0, double_sort); + symbol_rm = Z3_mk_string_symbol(ctx, "rm"); + rm = Z3_mk_const(ctx, symbol_rm, rm_sort); + symbol_x = Z3_mk_string_symbol(ctx, "x"); + symbol_y = Z3_mk_string_symbol(ctx, "y"); + x = Z3_mk_const(ctx, symbol_x, double_sort); + y = Z3_mk_const(ctx, symbol_y, double_sort); + n = Z3_mk_fpa_double(ctx, 42.0, double_sort); + + Z3_symbol q_s = Z3_mk_string_symbol(ctx, "q"); + Z3_ast q = Z3_mk_const(ctx, q_s, double_sort); + c = Z3_mk_eq(ctx, q, Z3_mk_fpa_add(ctx, rm, x, y)); + + Z3_ast args[2] = { c, Z3_mk_eq(ctx, q, n) }; + c = Z3_mk_and(ctx, 2, (Z3_ast*)&args); + + printf("c = %s\n", Z3_ast_to_string(ctx, c)); - c = Z3_mk_eq(ctx, Z3_mk_fpa_add(ctx, rm, x, y), n); - Z3_assert_cnstr(ctx, c); - if (Z3_check(ctx) != Z3_L_TRUE) - printf("FPA-example not satisfied!\n"); + + Z3_model m = 0; + Z3_lbool result = Z3_check_and_get_model(ctx, &m); + switch (result) { + case Z3_L_FALSE: + printf("unsat\n"); + break; + case Z3_L_UNDEF: + printf("unknown\n"); + break; + case Z3_L_TRUE: + printf("sat\n%s\n", Z3_model_to_string(ctx, m)); + break; + } + + if (m) + Z3_del_model(ctx, m); Z3_del_context(ctx); } @@ -2676,5 +2696,6 @@ int main() { smt2parser_example(); substitute_example(); substitute_vars_example(); + fpa_example(); return 0; } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index b654feb7e..e60c93fba 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3533,7 +3533,7 @@ namespace Microsoft.Z3 public FPNum MkFP(double v, FPSort s) { Contract.Ensures(Contract.Result() != null); - return new FPNum(this, Native.Z3_mk_double(this.nCtx, v, s.NativeObject)); + return new FPNum(this, Native.Z3_mk_fpa_double(this.nCtx, v, s.NativeObject)); } /// diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 81cfff591..93cfb8dd5 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -129,7 +129,7 @@ extern "C" { \sa Z3_mk_numeral - def_API('Z3_mk_double', AST, (_in(CONTEXT), _in(DOUBLE), _in(SORT))) + def_API('Z3_mk_fpa_double', AST, (_in(CONTEXT), _in(DOUBLE), _in(SORT))) */ Z3_ast Z3_API Z3_mk_fpa_double(__in Z3_context c, __in double v, __in Z3_sort ty); From 8b8cee7f6484ff0dfaa466c29c5f7f318b780101 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 12 Jun 2014 15:14:06 +0100 Subject: [PATCH 019/118] FPA theory improvements Signed-off-by: Christoph M. Wintersteiger --- src/smt/theory_fpa.cpp | 221 +++++++++++++++++++++-------------------- src/smt/theory_fpa.h | 5 +- 2 files changed, 119 insertions(+), 107 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index e606857e5..3a52b2590 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -37,6 +37,25 @@ namespace smt { { } + void theory_fpa::mk_bv_eq(expr * x, expr * y) { + ast_manager & m = get_manager(); + context & ctx = get_context(); + expr_ref eq(m); + eq = m.mk_eq(x, y); + ctx.internalize(eq, false); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(eq)); + ctx.mark_as_relevant(eq); + } + + expr_ref theory_fpa::mk_eq_bv_const(expr_ref const & e) { + ast_manager & m = get_manager(); + context & ctx = get_context(); + expr_ref bv_const(m); + bv_const = m.mk_fresh_const(0, m.get_sort(e)); + mk_bv_eq(bv_const, e); + return bv_const; + } + bool theory_fpa::internalize_atom(app * atom, bool gate_ctx) { TRACE("t_fpa", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << "\n";); SASSERT(atom->get_family_id() == get_family_id()); @@ -51,53 +70,60 @@ namespace smt { ast_manager & m = get_manager(); context & ctx = get_context(); simplifier & simp = ctx.get_simplifier(); - + unsigned num_args = term->get_num_args(); for (unsigned i = 0; i < num_args; i++) ctx.internalize(term->get_arg(i), false); + + if (m_converter.is_float(m.get_sort(term))) { + expr_ref res(m); + m_rw(term, res); + SASSERT(is_app(res) && to_app(res)->get_num_args() == 3); + TRACE("t_fpa", tout << "converted: " << mk_ismt2_pp(res, get_manager()) << "\n";); + + app * a = to_app(res); + expr_ref sgn(m), sig(m), exp(m); + proof_ref pr_sgn(m), pr_sig(m), pr_exp(m); + simp(a->get_arg(0), sgn, pr_sgn); + simp(a->get_arg(1), sig, pr_sig); + simp(a->get_arg(2), exp, pr_exp); - expr_ref res(m); - m_rw(term, res); - SASSERT(is_app(res) && to_app(res)->get_num_args() == 3); - app * a = to_app(res); - TRACE("t_fpa", tout << "converted: " << mk_ismt2_pp(res, get_manager()) << "\n";); + expr_ref bv_v_sgn = mk_eq_bv_const(sgn); + expr_ref bv_v_sig = mk_eq_bv_const(sig); + expr_ref bv_v_exp = mk_eq_bv_const(exp); - expr_ref sgn(m), sig(m), exp(m); - proof_ref pr_sgn(m), pr_sig(m), pr_exp(m); - simp(a->get_arg(0), sgn, pr_sgn); - simp(a->get_arg(1), sig, pr_sig); - simp(a->get_arg(2), exp, pr_exp); + expr_ref s_term(m); + m_converter.mk_triple(bv_v_sgn, bv_v_sig, bv_v_exp, s_term); - expr_ref bv_v_sgn(m), bv_v_sig(m), bv_v_exp(m); - bv_v_sgn = m.mk_fresh_const("fpa2bv", m.get_sort(sgn)); - bv_v_sig = m.mk_fresh_const("fpa2bv", m.get_sort(sig)); - bv_v_exp = m.mk_fresh_const("fpa2bv", m.get_sort(exp)); - expr_ref e1(m), e2(m), e3(m); - e1 = m.mk_eq(bv_v_sgn, sgn); - e2 = m.mk_eq(bv_v_sig, sig); - e3 = m.mk_eq(bv_v_exp, exp); - ctx.internalize(e1, false); - ctx.internalize(e2, false); - ctx.internalize(e3, false); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e1)); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e2)); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e3)); - ctx.mark_as_relevant(e1); - ctx.mark_as_relevant(e2); - ctx.mark_as_relevant(e3); + SASSERT(!m_trans_map.contains(term)); + m_trans_map.insert(term, s_term, 0); + } + else if (m_converter.is_rm_sort(m.get_sort(term))) { + expr_ref res(m); + m_rw(term, res); + SASSERT(is_app(res)); + TRACE("t_fpa", tout << "converted: " << mk_ismt2_pp(res, get_manager()) << "\n";); + + app * a = to_app(res); + expr_ref bv_rm(m); + proof_ref bv_pr(m); + simp(res, bv_rm, bv_pr); - expr_ref s_term(m); - m_converter.mk_triple(bv_v_sgn, bv_v_sig, bv_v_exp, s_term); + expr_ref bv_v = mk_eq_bv_const(bv_rm); - SASSERT(!m_trans_map.contains(term)); - m_trans_map.insert(term, s_term, 0); + SASSERT(!m_trans_map.contains(term)); + m_trans_map.insert(term, bv_v, 0); + + + } + else + UNREACHABLE(); enode * e = ctx.mk_enode(term, false, false, true); - theory_var v = mk_var(e); + theory_var v = mk_var(e); ctx.attach_th_var(e, this, v); TRACE("t_fpa", tout << "new theory var: " << mk_ismt2_pp(term, get_manager()) << " := " << v << "\n";); SASSERT(e->get_th_var(get_id()) != null_theory_var); - return v != null_theory_var; } @@ -116,12 +142,7 @@ namespace smt { m_trans_map.insert(owner, converted, 0); if (m_converter.is_rm_sort(m.get_sort(owner))) { - expr_ref bv_v(m), eq(m); - bv_v = m.mk_fresh_const("fpa2bv", m.get_sort(converted)); - eq = m.mk_eq(bv_v, converted); - ctx.internalize(eq, false); - literal l = ctx.get_literal(eq); - ctx.mk_th_axiom(get_id(), 1, &l); + mk_eq_bv_const(converted); } else { app * a = to_app(converted); @@ -131,89 +152,77 @@ namespace smt { simp(a->get_arg(1), sig, pr_sig); simp(a->get_arg(2), exp, pr_exp); - ctx.internalize(sgn, false); - ctx.internalize(sig, false); - ctx.internalize(exp, false); - - expr_ref bv_v_sgn(m), bv_v_sig(m), bv_v_exp(m); - bv_v_sgn = m.mk_fresh_const("fpa2bv", m.get_sort(sgn)); - bv_v_sig = m.mk_fresh_const("fpa2bv", m.get_sort(sig)); - bv_v_exp = m.mk_fresh_const("fpa2bv", m.get_sort(exp)); - expr_ref e1(m), e2(m), e3(m); - e1 = m.mk_eq(bv_v_sgn, sgn); - e2 = m.mk_eq(bv_v_sig, sig); - e3 = m.mk_eq(bv_v_exp, exp); - ctx.internalize(e1, true); - ctx.internalize(e2, true); - ctx.internalize(e3, true); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e1)); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e2)); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e3)); - ctx.mark_as_relevant(e1); - ctx.mark_as_relevant(e2); - ctx.mark_as_relevant(e3); + mk_eq_bv_const(sgn); + mk_eq_bv_const(sig); + mk_eq_bv_const(exp); } TRACE("t_fpa", tout << "new theory var (const): " << mk_ismt2_pp(owner, get_manager()) << " := " << v << "\n";); } } - void theory_fpa::new_eq_eh(theory_var x, theory_var y) { + void theory_fpa::new_eq_eh(theory_var x, theory_var y) { TRACE("t_fpa", tout << "new eq: " << x << " = " << y << "\n";); ast_manager & m = get_manager(); context & ctx = get_context(); + app * ax = get_enode(x)->get_owner(); app * ay = get_enode(y)->get_owner(); - - expr * ex, * ey; - proof * px, * py; + expr * ex, *ey; + proof * px, *py; m_trans_map.get(ax, ex, px); m_trans_map.get(ay, ey, py); - expr * sgn_x, * sig_x, * exp_x; - expr * sgn_y, * sig_y, * exp_y; - split_triple(ex, sgn_x, sig_x, exp_x); - split_triple(ey, sgn_y, sig_y, exp_y); - - expr_ref e1(m), e2(m), e3(m); - e1 = m.mk_eq(sgn_x, sgn_y); - e2 = m.mk_eq(sig_x, sig_y); - e3 = m.mk_eq(exp_x, exp_y); - ctx.internalize(e1, true); - ctx.internalize(e2, true); - ctx.internalize(e3, true); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e1)); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e2)); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e3)); - ctx.mark_as_relevant(e1); - ctx.mark_as_relevant(e2); - ctx.mark_as_relevant(e3); + if (m_converter.fu().is_float(m.get_sort(get_enode(x)->get_owner()))) { + expr * sgn_x, *sig_x, *exp_x; + expr * sgn_y, *sig_y, *exp_y; + split_triple(ex, sgn_x, sig_x, exp_x); + split_triple(ey, sgn_y, sig_y, exp_y); + + mk_bv_eq(sgn_x, sgn_y); + mk_bv_eq(sig_x, sig_y); + mk_bv_eq(exp_x, exp_y); + } + else if (m_converter.fu().is_rm(m.get_sort(get_enode(x)->get_owner()))) { + mk_bv_eq(ex, ey); + } + else + UNREACHABLE(); } void theory_fpa::new_diseq_eh(theory_var x, theory_var y) { TRACE("t_fpa", tout << "new eq: " << x << " = " << y << "\n";); ast_manager & m = get_manager(); context & ctx = get_context(); + app * ax = get_enode(x)->get_owner(); app * ay = get_enode(y)->get_owner(); - expr * ex, *ey; proof * px, *py; m_trans_map.get(ax, ex, px); m_trans_map.get(ay, ey, py); - expr * sgn_x, *sig_x, *exp_x; - expr * sgn_y, *sig_y, *exp_y; - split_triple(ex, sgn_x, sig_x, exp_x); - split_triple(ex, sgn_y, sig_y, exp_y); + expr_ref deq(m); - expr_ref e1(m), e2(m), e3(m); - e1 = m.mk_not(m.mk_eq(sgn_x, sgn_y)); - e2 = m.mk_or(e1, m.mk_not(m.mk_eq(sig_x, sig_y))); - e3 = m.mk_or(e2, m.mk_not(m.mk_eq(exp_x, exp_y))); - ctx.internalize(e3, true); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(e3)); - ctx.mark_as_relevant(e3); + if (m_converter.fu().is_float(m.get_sort(get_enode(x)->get_owner()))) { + expr * sgn_x, *sig_x, *exp_x; + expr * sgn_y, *sig_y, *exp_y; + split_triple(ex, sgn_x, sig_x, exp_x); + split_triple(ex, sgn_y, sig_y, exp_y); + + deq = m.mk_or(m.mk_not(m.mk_eq(sgn_x, sgn_y)), + m.mk_not(m.mk_eq(sig_x, sig_y)), + m.mk_not(m.mk_eq(exp_x, exp_y))); + } + else if (m_converter.fu().is_rm(m.get_sort(get_enode(x)->get_owner()))) { + deq = m.mk_not(m.mk_eq(ex, ey)); + } + else + UNREACHABLE(); + + ctx.internalize(deq, true); + ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(deq)); + ctx.mark_as_relevant(deq); } void theory_fpa::push_scope_eh() { @@ -273,7 +282,7 @@ namespace smt { res = alloc(expr_wrapper_proc, fp_val_e); } } - else { + else if (fu.is_float(m.get_sort(fpa_e))) { expr * bv_sgn, *bv_sig, *bv_exp; split_triple(bv_e, bv_sgn, bv_sig, bv_exp); @@ -283,15 +292,15 @@ namespace smt { enode * e_sgn = ctx.get_enode(bv_sgn); enode * e_sig = ctx.get_enode(bv_sig); - enode * e_exp = ctx.get_enode(bv_exp); + enode * e_exp = ctx.get_enode(bv_exp); TRACE("t_fpa", tout << "bv rep: [" << mk_ismt2_pp(e_sgn->get_owner(), m) << " " - << mk_ismt2_pp(e_sig->get_owner(), m) << " " - << mk_ismt2_pp(e_exp->get_owner(), m) << "]\n";); + << mk_ismt2_pp(e_sig->get_owner(), m) << " " + << mk_ismt2_pp(e_exp->get_owner(), m) << "]\n";); sort * s = m.get_sort(e_sgn->get_owner()); family_id fid = s->get_family_id(); - theory_bv * bv_th = (theory_bv*)ctx.get_theory(fid); + theory_bv * bv_th = (theory_bv*)ctx.get_theory(fid); SASSERT(bv_th->is_attached_to_var(e_sgn)); SASSERT(bv_th->is_attached_to_var(e_sig)); @@ -301,8 +310,8 @@ namespace smt { sig_sz = bu.get_bv_size(e_sig->get_owner()); exp_sz = bu.get_bv_size(e_exp->get_owner()); - rational sgn_r(0), sig_r(0), exp_r(0); - + rational sgn_r(0), sig_r(0), exp_r(0); + if (!bv_th->get_fixed_value(e_sgn->get_owner(), sgn_r) || !bv_th->get_fixed_value(e_sig->get_owner(), sig_r) || !bv_th->get_fixed_value(e_exp->get_owner(), exp_r)) { @@ -310,8 +319,8 @@ namespace smt { } else { TRACE("t_fpa", tout << "bv model: [" << sgn_r.to_string() << " " - << sig_r.to_string() << " " - << exp_r.to_string() << "]\n";); + << sig_r.to_string() << " " + << exp_r.to_string() << "]\n";); // un-bias exponent rational exp_unbiased_r; @@ -345,6 +354,8 @@ namespace smt { res = alloc(expr_wrapper_proc, fp_val_e); } } + else + UNREACHABLE(); return res; } @@ -377,6 +388,6 @@ namespace smt { } } else - NOT_IMPLEMENTED_YET(); + UNREACHABLE(); } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 4a465ada2..ea09df27b 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -59,8 +59,9 @@ namespace smt { sig = to_app(e)->get_arg(1); exp = to_app(e)->get_arg(2); } - - void ensure_bv_var(expr_ref const & n); + + void mk_bv_eq(expr * x, expr * y); + expr_ref mk_eq_bv_const(expr_ref const & e); }; }; From 4a915f6528f33802f9b271be53a8fcf158384231 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 12 Jun 2014 21:16:11 +0100 Subject: [PATCH 020/118] FPA theory additions Signed-off-by: Christoph M. Wintersteiger --- src/smt/theory_fpa.cpp | 163 ++++++++++++++++++++++++++++------------- src/smt/theory_fpa.h | 28 ++++++- 2 files changed, 139 insertions(+), 52 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 3a52b2590..7082a9582 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -24,6 +24,18 @@ Revision History: namespace smt { + class mk_atom_trail : public trail { + bool_var m_var; + public: + mk_atom_trail(bool_var v) : m_var(v) {} + virtual ~mk_atom_trail() {} + virtual void undo(theory_fpa & th) { + theory_fpa::atom * a = th.get_bv2a(m_var); + a->~atom(); + th.erase_bv2a(m_var); + } + }; + theory_fpa::theory_fpa(ast_manager & m) : theory(m.mk_family_id("float")), m_converter(m), @@ -38,13 +50,13 @@ namespace smt { } void theory_fpa::mk_bv_eq(expr * x, expr * y) { + SASSERT(get_sort(x)->get_family_id() == m_converter.bu().get_family_id()); ast_manager & m = get_manager(); - context & ctx = get_context(); - expr_ref eq(m); - eq = m.mk_eq(x, y); - ctx.internalize(eq, false); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(eq)); - ctx.mark_as_relevant(eq); + context & ctx = get_context(); + theory_id bv_tid = ctx.get_theory(m.get_sort(x)->get_family_id())->get_id(); + literal l = mk_eq(x, y, false); + ctx.mk_th_axiom(get_id(), 1, &l); + ctx.mark_as_relevant(l); } expr_ref theory_fpa::mk_eq_bv_const(expr_ref const & e) { @@ -59,7 +71,33 @@ namespace smt { bool theory_fpa::internalize_atom(app * atom, bool gate_ctx) { 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(); + simplifier & simp = ctx.get_simplifier(); + bv_util & bu = m_converter.bu(); + expr_ref bv_atom(m); + + unsigned num_args = atom->get_num_args(); + for (unsigned i = 0; i < num_args; i++) + ctx.internalize(atom->get_arg(i), false); + + m_rw(atom, bv_atom); + + ctx.internalize(bv_atom, gate_ctx); + literal def = ctx.get_literal(bv_atom); + literal l(ctx.mk_bool_var(atom)); + ctx.set_var_theory(l.var(), get_id()); + pred_atom * a = new (get_region()) pred_atom(l, def); + insert_bv2a(l.var(), a); + m_trail_stack.push(mk_atom_trail(l.var())); + + if (!ctx.relevancy()) { + ctx.mk_th_axiom(get_id(), l, ~def); + ctx.mk_th_axiom(get_id(), ~l, def); + } + + return true; } bool theory_fpa::internalize_term(app * term) { @@ -69,19 +107,28 @@ namespace smt { ast_manager & m = get_manager(); context & ctx = get_context(); - simplifier & simp = ctx.get_simplifier(); + simplifier & simp = ctx.get_simplifier(); + bv_util & bu = m_converter.bu(); + sort * term_sort = m.get_sort(term); + expr_ref t(m), bv_term(m); unsigned num_args = term->get_num_args(); for (unsigned i = 0; i < num_args; i++) ctx.internalize(term->get_arg(i), false); - - if (m_converter.is_float(m.get_sort(term))) { - expr_ref res(m); - m_rw(term, res); - SASSERT(is_app(res) && to_app(res)->get_num_args() == 3); - TRACE("t_fpa", tout << "converted: " << mk_ismt2_pp(res, get_manager()) << "\n";); - - app * a = to_app(res); + + m_rw(term, t); + + if (m_converter.is_rm_sort(term_sort)) { + SASSERT(is_app(t)); + expr_ref bv_rm(m); + proof_ref bv_pr(m); + simp(t, bv_rm, bv_pr); + + bv_term = mk_eq_bv_const(bv_rm); + } + else if (m_converter.is_float(term_sort)) { + SASSERT(is_app(t) && to_app(t)->get_num_args() == 3); + app * a = to_app(t); expr_ref sgn(m), sig(m), exp(m); proof_ref pr_sgn(m), pr_sig(m), pr_exp(m); simp(a->get_arg(0), sgn, pr_sgn); @@ -92,34 +139,25 @@ namespace smt { expr_ref bv_v_sig = mk_eq_bv_const(sig); expr_ref bv_v_exp = mk_eq_bv_const(exp); - expr_ref s_term(m); - m_converter.mk_triple(bv_v_sgn, bv_v_sig, bv_v_exp, s_term); - - SASSERT(!m_trans_map.contains(term)); - m_trans_map.insert(term, s_term, 0); + m_converter.mk_triple(bv_v_sgn, bv_v_sig, bv_v_exp, bv_term); } - else if (m_converter.is_rm_sort(m.get_sort(term))) { - expr_ref res(m); - m_rw(term, res); - SASSERT(is_app(res)); - TRACE("t_fpa", tout << "converted: " << mk_ismt2_pp(res, get_manager()) << "\n";); - - app * a = to_app(res); - expr_ref bv_rm(m); + else if (term->get_decl_kind() == OP_TO_IEEE_BV) { + SASSERT(is_app(t)); + expr_ref bv_e(m); proof_ref bv_pr(m); - simp(res, bv_rm, bv_pr); + simp(t, bv_e, bv_pr); - expr_ref bv_v = mk_eq_bv_const(bv_rm); - - SASSERT(!m_trans_map.contains(term)); - m_trans_map.insert(term, bv_v, 0); - - + bv_term = mk_eq_bv_const(bv_e); } else - UNREACHABLE(); + NOT_IMPLEMENTED_YET(); - enode * e = ctx.mk_enode(term, false, false, true); + TRACE("t_fpa", tout << "converted: " << mk_ismt2_pp(bv_term, get_manager()) << "\n";); + + SASSERT(!m_trans_map.contains(term)); + m_trans_map.insert(term, bv_term, 0); + + enode * e = ctx.mk_enode(term, false, false, true); theory_var v = mk_var(e); ctx.attach_th_var(e, this, v); TRACE("t_fpa", tout << "new theory var: " << mk_ismt2_pp(term, get_manager()) << " := " << v << "\n";); @@ -191,7 +229,7 @@ namespace smt { } void theory_fpa::new_diseq_eh(theory_var x, theory_var y) { - TRACE("t_fpa", tout << "new eq: " << x << " = " << y << "\n";); + TRACE("t_fpa", tout << "new diseq: " << x << " != " << y << "\n";); ast_manager & m = get_manager(); context & ctx = get_context(); @@ -219,7 +257,7 @@ namespace smt { } else UNREACHABLE(); - + ctx.internalize(deq, true); ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(deq)); ctx.mark_as_relevant(deq); @@ -252,17 +290,17 @@ namespace smt { expr * bv_e; proof * bv_pr; m_trans_map.get(fpa_e, bv_e, bv_pr); - + sort * fpa_e_srt = m.get_sort(fpa_e); expr_wrapper_proc * res = 0; - if (fu.is_rm(m.get_sort(fpa_e))) { + if (fu.is_rm(fpa_e_srt)) { SASSERT(ctx.e_internalized(bv_e)); sort * s = m.get_sort(bv_e); family_id fid = s->get_family_id(); theory_bv * bv_th = (theory_bv*)ctx.get_theory(fid); rational val; if (!bv_th->get_fixed_value(ctx.get_enode(bv_e)->get_owner(), val)) { - NOT_IMPLEMENTED_YET(); + UNREACHABLE(); } else { @@ -282,7 +320,7 @@ namespace smt { res = alloc(expr_wrapper_proc, fp_val_e); } } - else if (fu.is_float(m.get_sort(fpa_e))) { + else if (fu.is_float(fpa_e_srt)) { expr * bv_sgn, *bv_sig, *bv_exp; split_triple(bv_e, bv_sgn, bv_sig, bv_exp); @@ -315,7 +353,7 @@ namespace smt { if (!bv_th->get_fixed_value(e_sgn->get_owner(), sgn_r) || !bv_th->get_fixed_value(e_sig->get_owner(), sig_r) || !bv_th->get_fixed_value(e_exp->get_owner(), exp_r)) { - NOT_IMPLEMENTED_YET(); + UNREACHABLE(); } else { TRACE("t_fpa", tout << "bv model: [" << sgn_r.to_string() << " " @@ -362,23 +400,35 @@ namespace smt { void theory_fpa::assign_eh(bool_var v, bool is_true) { TRACE("t_fpa", tout << "assign_eh for: " << v << " (" << is_true << ")\n";); - UNREACHABLE(); + /* CMW: okay to ignore? */ } void theory_fpa::relevant_eh(app * n) { + TRACE("t_fpa", tout << "relevant_eh for: " << mk_ismt2_pp(n, get_manager()) << "\n";); ast_manager & m = get_manager(); context & ctx = get_context(); float_util & fu = m_converter.fu(); - if (ctx.e_internalized(n)) { + bv_util & bu = m_converter.bu(); + + if (m.is_bool(n)) { + bool_var v = ctx.get_bool_var(n); + atom * a = get_bv2a(v); + pred_atom * pa = static_cast(a); + ctx.mark_as_relevant(pa->m_def); + ctx.mk_th_axiom(get_id(), pa->m_var, ~pa->m_def); + ctx.mk_th_axiom(get_id(), ~pa->m_var, pa->m_def); + } + else if (ctx.e_internalized(n)) { SASSERT(m_trans_map.contains(n)); expr * ex; proof * px; m_trans_map.get(n, ex, px); + sort * n_srt = m.get_sort(n); - if (fu.is_rm(m.get_sort(n))) { - ctx.mark_as_relevant(ex); + if (fu.is_rm(n_srt)) { + ctx.mark_as_relevant(ex); } - else { + else if (fu.is_float(n_srt)) { expr * bv_sgn, *bv_sig, *bv_exp; split_triple(ex, bv_sgn, bv_sig, bv_exp); @@ -386,8 +436,21 @@ namespace smt { ctx.mark_as_relevant(bv_sig); ctx.mark_as_relevant(bv_exp); } + else if (n->get_decl()->get_decl_kind() == OP_TO_IEEE_BV) { + literal l = mk_eq(n, ex, false); + ctx.mark_as_relevant(l); + ctx.mk_th_axiom(get_id(), 1, &l); + } + else + NOT_IMPLEMENTED_YET(); } else UNREACHABLE(); } + + void theory_fpa::reset_eh() { + pop_scope_eh(m_trail_stack.get_num_scopes()); + m_bool_var2atom.reset(); + theory::reset_eh(); + } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index ea09df27b..2039e34df 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -20,17 +20,40 @@ Revision History: #define _THEORY_FPA_H_ #include"smt_theory.h" +#include"trail.h" #include"fpa2bv_converter.h" #include"fpa2bv_rewriter.h" namespace smt { + class theory_fpa : public theory { typedef trail_stack th_trail_stack; - + + public: + class atom { + public: + virtual ~atom() {} + }; + + struct pred_atom : public atom { + literal m_var; + literal m_def; + pred_atom(literal v, literal d) : m_var(v), m_def(d) {} + virtual ~pred_atom() {} + }; + + typedef ptr_vector bool_var2atom; + void insert_bv2a(bool_var bv, pred_atom * a) { m_bool_var2atom.setx(bv, a, 0); } + void erase_bv2a(bool_var bv) { m_bool_var2atom[bv] = 0; } + pred_atom * get_bv2a(bool_var bv) const { return m_bool_var2atom.get(bv, 0); } + region & get_region() { return m_trail_stack.get_region(); } + + protected: fpa2bv_converter m_converter; fpa2bv_rewriter m_rw; expr_map m_trans_map; th_trail_stack m_trail_stack; + bool_var2atom m_bool_var2atom; virtual final_check_status final_check_eh() { return FC_DONE; } virtual bool internalize_atom(app * atom, bool gate_ctx); @@ -40,6 +63,7 @@ namespace smt { 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"; } @@ -47,6 +71,7 @@ namespace smt { void assign_eh(bool_var v, bool is_true); virtual void relevant_eh(app * n); + public: theory_fpa(ast_manager& m); virtual ~theory_fpa(); @@ -67,4 +92,3 @@ namespace smt { }; #endif /* _THEORY_FPA_H_ */ - From 2cd4edf1a23a3978851c83338f01d0ea775dabb6 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 31 Jul 2014 17:56:18 +0100 Subject: [PATCH 021/118] FPA API bugfixes Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.h | 2 +- src/smt/theory_fpa.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 4dedbc2e2..2b6b7fd64 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -221,7 +221,7 @@ public: 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_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); diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index f44447b8f..9c03cb76c 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -122,7 +122,7 @@ namespace smt { m_rw(term, t); - if (m_converter.is_rm_sort(term_sort)) { + if (m_converter.is_rm(term_sort)) { SASSERT(is_app(t)); expr_ref bv_rm(m); proof_ref bv_pr(m); @@ -183,7 +183,7 @@ namespace smt { m_rw(owner, converted); m_trans_map.insert(owner, converted, 0); - if (m_converter.is_rm_sort(m.get_sort(owner))) { + if (m_converter.is_rm(m.get_sort(owner))) { mk_eq_bv_const(converted); } else { From 8b40d4a7357cbe13a3aaefb1b848a7b710cdd30d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 4 Aug 2014 17:00:04 +0100 Subject: [PATCH 022/118] FPA theory bug fixes. Also removed unnecessary intermediate variables. Signed-off-by: Christoph M. Wintersteiger --- examples/c/test_capi.c | 73 ++++++++++++++++++++++++++++++++--------- src/api/api_numeral.cpp | 2 +- src/smt/theory_fpa.cpp | 68 +++++++++++++++----------------------- src/smt/theory_fpa.h | 2 +- 4 files changed, 85 insertions(+), 60 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 578c563b7..6eb7a2e11 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2599,11 +2599,11 @@ void fpa_example() { Z3_config cfg; Z3_context ctx; Z3_sort double_sort, rm_sort; - Z3_symbol symbol_rm, symbol_x, symbol_y; - Z3_ast rm, x, y, n, c; - - printf("\nFPA-example\n"); - LOG_MSG("FPA-example"); + Z3_symbol symbol_rm, symbol_x, symbol_y, symbol_q; + Z3_ast rm, x, y, n, q, c1, c2, c3, c4, c5, c6; + + printf("\nfpa_example\n"); + LOG_MSG("fpa_example"); cfg = Z3_mk_config(); ctx = Z3_mk_context(cfg); @@ -2620,16 +2620,32 @@ void fpa_example() { y = Z3_mk_const(ctx, symbol_y, double_sort); n = Z3_mk_fpa_double(ctx, 42.0, double_sort); - Z3_symbol q_s = Z3_mk_string_symbol(ctx, "q"); - Z3_ast q = Z3_mk_const(ctx, q_s, double_sort); - c = Z3_mk_eq(ctx, q, Z3_mk_fpa_add(ctx, rm, x, y)); + symbol_q = Z3_mk_string_symbol(ctx, "q"); + q = Z3_mk_const(ctx, symbol_q, double_sort); + c1 = Z3_mk_eq(ctx, q, Z3_mk_fpa_add(ctx, rm, x, y)); - Z3_ast args[2] = { c, Z3_mk_eq(ctx, q, n) }; - c = Z3_mk_and(ctx, 2, (Z3_ast*)&args); + Z3_ast args[2] = { c1, Z3_mk_eq(ctx, q, n) }; + c2 = Z3_mk_and(ctx, 2, (Z3_ast*)&args); - printf("c = %s\n", Z3_ast_to_string(ctx, c)); + Z3_ast args2[2] = { c2, Z3_mk_not(ctx, Z3_mk_eq(ctx, rm, Z3_mk_fpa_round_nearest_ties_to_away(ctx))) }; + c3 = Z3_mk_and(ctx, 2, (Z3_ast*)&args2); - Z3_assert_cnstr(ctx, c); + 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_inf(ctx, y)) }; + Z3_ast args3[2] = { c3, Z3_mk_and(ctx, 3, and_args) }; + c4 = Z3_mk_and(ctx, 2, (Z3_ast*)&args3); + + + Z3_assert_cnstr(ctx, c4); + Z3_push(ctx); + + // c5 := (IEEEBV(x) == 7.0). + c5 = Z3_mk_eq(ctx, Z3_mk_fpa_to_ieee_bv(ctx, x), + Z3_mk_numeral(ctx, "4619567317775286272", Z3_mk_bv_sort(ctx, 64))); + + Z3_assert_cnstr(ctx, c5); Z3_model m = 0; Z3_lbool result = Z3_check_and_get_model(ctx, &m); @@ -2639,19 +2655,44 @@ void fpa_example() { break; case Z3_L_UNDEF: printf("unknown\n"); + printf("potential model:\n%s\n", Z3_model_to_string(ctx, m)); + break; + case Z3_L_TRUE: + printf("sat\n%s\n", Z3_model_to_string(ctx, m)); + Z3_del_model(ctx, m); + break; + } + + Z3_pop(ctx, 1); + + // c6 := (IEEEBV(x) == 28.0). + c6 = Z3_mk_eq(ctx, Z3_mk_fpa_to_ieee_bv(ctx, x), + Z3_mk_numeral(ctx, "4628574517030027264", Z3_mk_bv_sort(ctx, 64))); + + Z3_assert_cnstr(ctx, c6); + Z3_push(ctx); + + m = 0; + result = Z3_check_and_get_model(ctx, &m); + switch (result) { + case Z3_L_FALSE: + printf("unsat\n"); + break; + case Z3_L_UNDEF: + printf("unknown\n"); + printf("potential model:\n%s\n", Z3_model_to_string(ctx, m)); break; case Z3_L_TRUE: - printf("sat\n%s\n", Z3_model_to_string(ctx, m)); + printf("sat\n%s\n", Z3_model_to_string(ctx, m)); + Z3_del_model(ctx, m); break; } - if (m) - Z3_del_model(ctx, m); + Z3_pop(ctx, 1); Z3_del_context(ctx); } - /*@}*/ /*@}*/ diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 740fef2ac..d2829e990 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -193,7 +193,7 @@ extern "C" { // floats are separated from all others to avoid huge rationals. float_util & fu = mk_c(c)->float_util(); scoped_mpf tmp(fu.fm()); - if (mk_c(c)->float_util().is_numeral(to_expr(a), tmp)) { + if (mk_c(c)->float_util().is_value(to_expr(a), tmp)) { return mk_c(c)->mk_external_string(fu.fm().to_string(tmp)); } else { diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 9c03cb76c..a228ec4a5 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -60,15 +60,6 @@ namespace smt { ctx.mark_as_relevant(l); } - app_ref theory_fpa::mk_eq_bv_const(expr_ref const & e) { - ast_manager & m = get_manager(); - context & ctx = get_context(); - app_ref bv_const(m); - bv_const = m.mk_fresh_const(0, m.get_sort(e)); - mk_bv_eq(bv_const, e); - return bv_const; - } - bool theory_fpa::internalize_atom(app * atom, bool gate_ctx) { TRACE("t_fpa", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << "\n";); SASSERT(atom->get_family_id() == get_family_id()); @@ -128,7 +119,7 @@ namespace smt { proof_ref bv_pr(m); simp(t, bv_rm, bv_pr); - bv_term = mk_eq_bv_const(bv_rm); + bv_term = bv_rm; } else if (m_converter.is_float(term_sort)) { SASSERT(is_app(t) && to_app(t)->get_num_args() == 3); @@ -139,19 +130,13 @@ namespace smt { simp(a->get_arg(1), sig, pr_sig); simp(a->get_arg(2), exp, pr_exp); - app_ref bv_v_sgn = mk_eq_bv_const(sgn); - app_ref bv_v_sig = mk_eq_bv_const(sig); - app_ref bv_v_exp = mk_eq_bv_const(exp); - - m_converter.mk_triple(bv_v_sgn, bv_v_sig, bv_v_exp, bv_term); + m_converter.mk_triple(sgn, sig, exp, bv_term); } else if (term->get_decl_kind() == OP_TO_IEEE_BV) { SASSERT(is_app(t)); expr_ref bv_e(m); proof_ref bv_pr(m); - simp(t, bv_e, bv_pr); - - bv_term = mk_eq_bv_const(bv_e); + simp(t, bv_term, bv_pr); } else NOT_IMPLEMENTED_YET(); @@ -159,11 +144,12 @@ namespace smt { TRACE("t_fpa", tout << "converted: " << mk_ismt2_pp(bv_term, get_manager()) << "\n";); SASSERT(!m_trans_map.contains(term)); - m_trans_map.insert(term, bv_term, 0); + m_trans_map.insert(term, bv_term, 0); enode * e = (ctx.e_internalized(term)) ? ctx.get_enode(term) : ctx.mk_enode(term, false, false, true); theory_var v = mk_var(e); ctx.attach_th_var(e, this, v); + m_tvars.push_back(v); TRACE("t_fpa", tout << "new theory var: " << mk_ismt2_pp(term, get_manager()) << " := " << v << "\n";); SASSERT(e->get_th_var(get_id()) != null_theory_var); return v != null_theory_var; @@ -180,23 +166,14 @@ namespace smt { theory_var v = mk_var(n); ctx.attach_th_var(n, this, v); + m_tvars.push_back(v); m_rw(owner, converted); m_trans_map.insert(owner, converted, 0); - if (m_converter.is_rm(m.get_sort(owner))) { - mk_eq_bv_const(converted); - } - else { - app * a = to_app(converted); - expr_ref sgn(m), sig(m), exp(m); - proof_ref pr_sgn(m), pr_sig(m), pr_exp(m); - simp(a->get_arg(0), sgn, pr_sgn); - simp(a->get_arg(1), sig, pr_sig); - simp(a->get_arg(2), exp, pr_exp); - - mk_eq_bv_const(sgn); - mk_eq_bv_const(sig); - mk_eq_bv_const(exp); + sort * owner_sort = m.get_sort(owner); + if (m_converter.is_rm(owner_sort)) { + bv_util & bu = m_converter.bu(); + bu.mk_ule(converted, bu.mk_numeral(4, bu.get_bv_size(converted))); } TRACE("t_fpa", tout << "new theory var (const): " << mk_ismt2_pp(owner, get_manager()) << " := " << v << "\n";); @@ -215,7 +192,7 @@ namespace smt { m_trans_map.get(ax, ex, px); m_trans_map.get(ay, ey, py); - if (m_converter.fu().is_float(m.get_sort(get_enode(x)->get_owner()))) { + if (m_converter.fu().is_float(get_enode(x)->get_owner())) { expr * sgn_x, *sig_x, *exp_x; expr * sgn_y, *sig_y, *exp_y; split_triple(ex, sgn_x, sig_x, exp_x); @@ -225,7 +202,7 @@ namespace smt { mk_bv_eq(sig_x, sig_y); mk_bv_eq(exp_x, exp_y); } - else if (m_converter.fu().is_rm(m.get_sort(get_enode(x)->get_owner()))) { + else if (m_converter.fu().is_rm(get_enode(x)->get_owner())) { mk_bv_eq(ex, ey); } else @@ -273,7 +250,13 @@ namespace smt { } void theory_fpa::pop_scope_eh(unsigned num_scopes) { + TRACE("bv", tout << num_scopes << "\n";); m_trail_stack.pop_scope(num_scopes); + unsigned num_old_vars = get_old_num_vars(num_scopes); + for (unsigned i = num_old_vars; i < get_num_vars(); i++) { + m_trans_map.erase(get_enode(m_tvars[i])->get_owner()); + } + m_tvars.shrink(num_old_vars); theory::pop_scope_eh(num_scopes); } @@ -405,6 +388,7 @@ namespace smt { void theory_fpa::assign_eh(bool_var v, bool is_true) { TRACE("t_fpa", tout << "assign_eh for: " << v << " (" << is_true << ")\n";); /* CMW: okay to ignore? */ + theory::assign_eh(v, is_true); } void theory_fpa::relevant_eh(app * n) { @@ -441,14 +425,10 @@ namespace smt { ctx.mark_as_relevant(bv_exp); } else if (n->get_decl()->get_decl_kind() == OP_TO_IEEE_BV) { - //literal l = mk_eq(n, ex, false); - //ctx.mark_as_relevant(l); - //ctx.mk_th_axiom(get_id(), 1, &l); - + expr_ref eq(m); app * ex_a = to_app(ex); if (n->get_id() > ex_a->get_id()) - std::swap(n, ex_a); - expr_ref eq(m); + std::swap(n, ex_a); eq = m.mk_eq(n, ex_a); ctx.internalize(eq, false); literal l = ctx.get_literal(eq); @@ -464,7 +444,11 @@ namespace smt { void theory_fpa::reset_eh() { pop_scope_eh(m_trail_stack.get_num_scopes()); - m_bool_var2atom.reset(); + m_rw.reset(); + m_trans_map.reset(); + m_bool_var2atom.reset(); + m_temporaries.reset(); + m_tvars.reset(); theory::reset_eh(); } diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 998cc17e8..5c0d2acca 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -55,6 +55,7 @@ namespace smt { th_trail_stack m_trail_stack; bool_var2atom m_bool_var2atom; enode_vector m_temporaries; + int_vector m_tvars; virtual final_check_status final_check_eh() { return FC_DONE; } virtual bool internalize_atom(app * atom, bool gate_ctx); @@ -88,7 +89,6 @@ namespace smt { } void mk_bv_eq(expr * x, expr * y); - app_ref mk_eq_bv_const(expr_ref const & e); }; }; From 4610acca0f4e7761be73f7a6851f3169c9a49ff2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 4 Aug 2014 17:10:56 +0100 Subject: [PATCH 023/118] FPA: reduced number of temporary variables. Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index d6f362902..07f0cdc8a 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -136,12 +136,13 @@ void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) { unsigned sbits = m_util.get_sbits(srt); expr_ref sgn(m), s(m), e(m); - 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); #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(); @@ -149,9 +150,17 @@ void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) { s = m.mk_fresh_const((p + "_sig_" + name).c_str(), s_sig); e = m.mk_fresh_const((p + "_exp_" + name).c_str(), s_exp); #else - sgn = m.mk_fresh_const(0, s_sgn); - s = m.mk_fresh_const(0, s_sig); - e = m.mk_fresh_const(0, s_exp); + expr_ref bv(m); + unsigned bv_sz = 1 + ebits + (sbits - 1); + bv = m.mk_fresh_const(0, m_bv_util.mk_sort(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); + s = m_bv_util.mk_extract(sbits - 2, 0, bv); + + SASSERT(m_bv_util.get_bv_size(sgn) == 1); + SASSERT(m_bv_util.get_bv_size(s) == sbits-1); + SASSERT(m_bv_util.get_bv_size(e) == ebits); #endif mk_triple(sgn, s, e, result); From 7af410e6d668674fab67019941995dad603fa736 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 18 Oct 2014 13:42:28 +0100 Subject: [PATCH 024/118] FPA updates and bugfixes Signed-off-by: Christoph M. Wintersteiger --- src/api/api_fpa.cpp | 12 +- src/api/z3_fpa.h | 33 ++- src/ast/float_decl_plugin.cpp | 326 ++++++++++++++++------------ src/ast/float_decl_plugin.h | 42 ++-- src/ast/fpa/fpa2bv_converter.cpp | 14 +- src/ast/fpa/fpa2bv_converter.h | 3 +- src/ast/fpa/fpa2bv_rewriter.h | 14 +- src/ast/rewriter/float_rewriter.cpp | 37 ++-- src/ast/rewriter/float_rewriter.h | 11 +- src/smt/theory_fpa.cpp | 4 +- 10 files changed, 308 insertions(+), 188 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 374e3d344..8bcc4c1af 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -121,6 +121,16 @@ extern "C" { 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->float_util().mk_nzero(to_sort(s)) : ctx->float_util().mk_pzero(to_sort(s))); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + Z3_ast Z3_API Z3_mk_fpa_double(Z3_context c, double v, Z3_sort ty) { Z3_TRY; LOG_Z3_mk_fpa_double(c, v, ty); @@ -361,7 +371,7 @@ extern "C" { LOG_Z3_mk_fpa_to_ieee_bv(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_to_ieee_bv(to_expr(t))); + Z3_ast r = of_ast(ctx->float_util().mk_float_to_ieee_bv(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 93cfb8dd5..265657bf4 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -109,12 +109,25 @@ extern "C" { \param s target sort \param negative indicates whether the result should be negative - When \c negative is true, -Inf will be generated instead of +Inf. + 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 a numeral of floating point sort. @@ -133,6 +146,24 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_fpa_double(__in Z3_context c, __in double v, __in Z3_sort ty); + /** + \brief Create a numeral of floating point sort. + + This function can be use 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 floating point sort + + \sa Z3_mk_numeral + + def_API('Z3_mk_fpa_double', AST, (_in(CONTEXT), _in(DOUBLE), _in(SORT))) + */ + Z3_ast Z3_API Z3_mk_fpa_double(__in Z3_context c, __in double v, __in Z3_sort ty); + /** \brief Floating-point absolute value diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index df26422c8..c31c0b89b 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -40,11 +40,10 @@ void float_decl_plugin::set_manager(ast_manager * m, family_id id) { SASSERT(m_int_sort != 0); // arith_decl_plugin must be installed before float_decl_plugin. m_manager->inc_ref(m_int_sort); - if (m_manager->has_plugin(symbol("bv"))) { - // bv plugin is optional, so m_bv_plugin may be 0 - m_bv_fid = m_manager->mk_family_id("bv"); - m_bv_plugin = static_cast(m_manager->get_plugin(m_bv_fid)); - } + // 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() { @@ -103,6 +102,18 @@ bool float_decl_plugin::is_value(expr * n, mpf & val) { 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; } @@ -156,7 +167,7 @@ sort * float_decl_plugin::mk_float_sort(unsigned ebits, unsigned sbits) { parameter ps[2] = { p1, p2 }; sort_size sz; sz = sort_size::mk_very_big(); // TODO: refine - return m_manager->mk_sort(symbol("FP"), sort_info(m_family_id, FLOAT_SORT, sz, 2, ps)); + return m_manager->mk_sort(symbol("FloatingPoint"), sort_info(m_family_id, FLOAT_SORT, sz, 2, ps)); } sort * float_decl_plugin::mk_rm_sort() { @@ -176,6 +187,14 @@ sort * float_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, paramete 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; @@ -229,17 +248,18 @@ func_decl * float_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_par unsigned ebits = s->get_parameter(0).get_int(); unsigned sbits = s->get_parameter(1).get_int(); scoped_mpf val(m_fm); - if (k == OP_FLOAT_NAN) { - m_fm.mk_nan(ebits, sbits, val); + + 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; } - else if (k == OP_FLOAT_MINUS_INF) { - m_fm.mk_ninf(ebits, sbits, val); - } - else { - SASSERT(k == OP_FLOAT_PLUS_INF); - m_fm.mk_pinf(ebits, sbits, val); - } + return mk_value_decl(val); } @@ -251,11 +271,11 @@ func_decl * float_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_paramet m_manager->raise_exception("sort mismatch"); symbol name; switch (k) { - case OP_FLOAT_EQ: name = "=="; break; - case OP_FLOAT_LT: name = "<"; break; - case OP_FLOAT_GT: name = ">"; break; - case OP_FLOAT_LE: name = "<="; break; - case OP_FLOAT_GE: name = ">="; break; + 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; @@ -273,14 +293,15 @@ func_decl * float_decl_plugin::mk_unary_rel_decl(decl_kind k, unsigned num_param m_manager->raise_exception("sort mismatch"); symbol name; switch (k) { - case OP_FLOAT_IS_ZERO: name = "isZero"; break; - case OP_FLOAT_IS_NZERO: name = "isNZero"; break; - case OP_FLOAT_IS_PZERO: name = "isPZero"; break; - case OP_FLOAT_IS_SIGN_MINUS: name = "isSignMinus"; break; - case OP_FLOAT_IS_NAN: name = "isNaN"; break; - case OP_FLOAT_IS_INF: name = "isInfinite"; break; - case OP_FLOAT_IS_NORMAL: name = "isNormal"; break; - case OP_FLOAT_IS_SUBNORMAL: name = "isSubnormal"; break; + 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; @@ -296,8 +317,8 @@ func_decl * float_decl_plugin::mk_unary_decl(decl_kind k, unsigned num_parameter m_manager->raise_exception("sort mismatch"); symbol name; switch (k) { - case OP_FLOAT_ABS: name = "abs"; break; - case OP_FLOAT_UMINUS: name = "-"; break; + case OP_FLOAT_ABS: name = "fp.abs"; break; + case OP_FLOAT_NEG: name = "fp.neg"; break; default: UNREACHABLE(); break; @@ -313,9 +334,9 @@ func_decl * float_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_paramete m_manager->raise_exception("sort mismatch"); symbol name; switch (k) { - case OP_FLOAT_REM: name = "remainder"; break; - case OP_FLOAT_MIN: name = "min"; break; - case OP_FLOAT_MAX: name = "max"; break; + 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; @@ -331,10 +352,10 @@ func_decl * float_decl_plugin::mk_rm_binary_decl(decl_kind k, unsigned num_param m_manager->raise_exception("sort mismatch"); symbol name; switch (k) { - case OP_FLOAT_ADD: name = "+"; break; - case OP_FLOAT_SUB: name = "-"; break; - case OP_FLOAT_MUL: name = "*"; break; - case OP_FLOAT_DIV: name = "/"; break; + 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; @@ -350,8 +371,8 @@ func_decl * float_decl_plugin::mk_rm_unary_decl(decl_kind k, unsigned num_parame m_manager->raise_exception("sort mismatch"); symbol name; switch (k) { - case OP_FLOAT_SQRT: name = "squareRoot"; break; - case OP_FLOAT_ROUND_TO_INTEGRAL: name = "roundToIntegral"; break; + case OP_FLOAT_SQRT: name = "fp.sqrt"; break; + case OP_FLOAT_ROUND_TO_INTEGRAL: name = "fp.roundToIntegral"; break; default: UNREACHABLE(); break; @@ -359,13 +380,13 @@ func_decl * float_decl_plugin::mk_rm_unary_decl(decl_kind k, unsigned num_parame return m_manager->mk_func_decl(name, arity, domain, domain[1], func_decl_info(m_family_id, k)); } -func_decl * float_decl_plugin::mk_fused_ma(decl_kind k, unsigned num_parameters, parameter const * parameters, +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]) || domain[1] != domain[2] || domain[1] != domain[3] || !is_float_sort(domain[1])) m_manager->raise_exception("sort mismatch"); - symbol name("fusedMA"); + symbol name("fp.fma"); return m_manager->mk_func_decl(name, arity, domain, domain[1], func_decl_info(m_family_id, k)); } @@ -375,12 +396,13 @@ func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_parameters, 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)) { - // When the bv_decl_plugin is installed, then we know how to convert 3 bit-vectors into a float! + // 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("asFloat"); + 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()) @@ -389,28 +411,56 @@ func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_parameters, int sbits = parameters[1].get_int(); sort * fp = mk_float_sort(ebits, sbits); - symbol name("asFloat"); + 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 { - // .. Otherwise we only know how to convert rationals/reals. - if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) - m_manager->raise_exception("expecting two integer parameters to asFloat"); - if (arity != 2 && arity != 3) - m_manager->raise_exception("invalid number of arguments to asFloat operator"); - if (arity == 3 && domain[2] != m_int_sort) - m_manager->raise_exception("sort mismatch"); + 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]) || - !(domain[1] == m_real_sort || is_sort_of(domain[1], m_family_id, FLOAT_SORT))) + !is_sort_of(domain[1], m_family_id, FLOAT_SORT)) + m_manager->raise_exception("sort mismatch"); + } + 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"); + if (domain[1] != m_real_sort) m_manager->raise_exception("sort mismatch"); sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); - symbol name("asFloat"); + 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_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * 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 (!m_bv_plugin) m_manager->raise_exception("asIEEEBV unsupported; use a logic with BV support"); @@ -443,7 +493,7 @@ func_decl * float_decl_plugin::mk_from3bv(decl_kind k, unsigned num_parameters, return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k)); } -func_decl * float_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_parameters, parameter const * parameters, +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"); @@ -455,15 +505,10 @@ func_decl * float_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_param m_manager->raise_exception("sort mismtach"); sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); - symbol name("to_fp_unsigned"); + 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_ubv(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_sbv(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { NOT_IMPLEMENTED_YET(); @@ -498,14 +543,15 @@ func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_FLOAT_IS_ZERO: case OP_FLOAT_IS_NZERO: case OP_FLOAT_IS_PZERO: - case OP_FLOAT_IS_SIGN_MINUS: + 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_UMINUS: + case OP_FLOAT_NEG: return mk_unary_decl(k, num_parameters, parameters, arity, domain, range); case OP_FLOAT_REM: case OP_FLOAT_MIN: @@ -517,20 +563,18 @@ func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters 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_UMINUS, num_parameters, parameters, arity, domain, range); + 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_FUSED_MA: - return mk_fused_ma(k, num_parameters, parameters, arity, domain, range); - case OP_TO_IEEE_BV: - return mk_to_ieee_bv(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_FP_UNSIGNED: - return mk_to_fp_unsigned(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: @@ -544,8 +588,11 @@ func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters } void float_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { - op_names.push_back(builtin_name("plusInfinity", OP_FLOAT_PLUS_INF)); - op_names.push_back(builtin_name("minusInfinity", OP_FLOAT_MINUS_INF)); + // 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)); @@ -553,22 +600,66 @@ void float_decl_plugin::get_op_names(svector & op_names, symbol co 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("+", OP_FLOAT_ADD)); - op_names.push_back(builtin_name("-", OP_FLOAT_SUB)); - op_names.push_back(builtin_name("/", OP_FLOAT_DIV)); - op_names.push_back(builtin_name("*", OP_FLOAT_MUL)); - op_names.push_back(builtin_name("abs", OP_FLOAT_ABS)); - op_names.push_back(builtin_name("remainder", OP_FLOAT_REM)); - op_names.push_back(builtin_name("fusedMA", OP_FLOAT_FUSED_MA)); - op_names.push_back(builtin_name("squareRoot", OP_FLOAT_SQRT)); - op_names.push_back(builtin_name("roundToIntegral", OP_FLOAT_ROUND_TO_INTEGRAL)); + 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("to_fp", OP_FLOAT_FP)); + + if (m_bv_plugin) { + 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)); + } + + // We also support the names of operators in older drafts. + op_names.push_back(builtin_name("plusInfinity", OP_FLOAT_PLUS_INF)); + op_names.push_back(builtin_name("minusInfinity", OP_FLOAT_MINUS_INF)); + + op_names.push_back(builtin_name("+", OP_FLOAT_ADD)); + op_names.push_back(builtin_name("-", OP_FLOAT_SUB)); + op_names.push_back(builtin_name("/", OP_FLOAT_DIV)); + op_names.push_back(builtin_name("*", OP_FLOAT_MUL)); + + op_names.push_back(builtin_name("abs", OP_FLOAT_ABS)); + op_names.push_back(builtin_name("remainder", OP_FLOAT_REM)); + op_names.push_back(builtin_name("fusedMA", OP_FLOAT_FMA)); + op_names.push_back(builtin_name("squareRoot", OP_FLOAT_SQRT)); + op_names.push_back(builtin_name("roundToIntegral", OP_FLOAT_ROUND_TO_INTEGRAL)); + op_names.push_back(builtin_name("==", OP_FLOAT_EQ)); - - op_names.push_back(builtin_name("<", OP_FLOAT_LT)); - op_names.push_back(builtin_name(">", OP_FLOAT_GT)); + + op_names.push_back(builtin_name("<", OP_FLOAT_LT)); + op_names.push_back(builtin_name(">", OP_FLOAT_GT)); op_names.push_back(builtin_name("<=", OP_FLOAT_LE)); op_names.push_back(builtin_name(">=", OP_FLOAT_GE)); @@ -579,65 +670,30 @@ void float_decl_plugin::get_op_names(svector & op_names, symbol co op_names.push_back(builtin_name("isPZero", OP_FLOAT_IS_PZERO)); op_names.push_back(builtin_name("isNormal", OP_FLOAT_IS_NORMAL)); op_names.push_back(builtin_name("isSubnormal", OP_FLOAT_IS_SUBNORMAL)); - op_names.push_back(builtin_name("isSignMinus", OP_FLOAT_IS_SIGN_MINUS)); + op_names.push_back(builtin_name("isSignMinus", OP_FLOAT_IS_NEGATIVE)); - op_names.push_back(builtin_name("min", OP_FLOAT_MIN)); - op_names.push_back(builtin_name("max", OP_FLOAT_MAX)); + // Disabled min/max, clashes with user-defined min/max functions + // op_names.push_back(builtin_name("min", OP_FLOAT_MIN)); + // op_names.push_back(builtin_name("max", OP_FLOAT_MAX)); - op_names.push_back(builtin_name("asFloat", OP_TO_FLOAT)); - - if (m_bv_plugin) - op_names.push_back(builtin_name("asIEEEBV", OP_TO_IEEE_BV)); - - // These are the operators from the final draft of the SMT FloatingPoints 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("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_UMINUS)); - 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_FUSED_MA)); - 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.eq", OP_FLOAT_EQ)); - 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.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.min", OP_FLOAT_MIN)); - op_names.push_back(builtin_name("fp.max", OP_FLOAT_MAX)); op_names.push_back(builtin_name("to_fp", OP_TO_FLOAT)); - if (m_bv_plugin) { - op_names.push_back(builtin_name("fp", OP_FLOAT_FP)); - op_names.push_back(builtin_name("to_fp_unsigned", OP_FLOAT_TO_FP_UNSIGNED)); - 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("fp.toReal", ?)); + if (m_bv_plugin) + op_names.push_back(builtin_name("asIEEEBV", OP_FLOAT_TO_IEEE_BV)); } void float_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { + // Old draft sort names. sort_names.push_back(builtin_name("FP", FLOAT_SORT)); sort_names.push_back(builtin_name("RoundingMode", ROUNDING_MODE_SORT)); - // In the SMT FPA final draft, FP is called FloatingPoint + // In the final draft, FP is called FloatingPoint ... sort_names.push_back(builtin_name("FloatingPoint", FLOAT_SORT)); + // ... and it 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) { @@ -661,6 +717,8 @@ bool float_decl_plugin::is_value(app * e) const { 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: diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 2b6b7fd64..8a77b63cc 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -27,7 +27,11 @@ Revision History: enum float_sort_kind { FLOAT_SORT, - ROUNDING_MODE_SORT + ROUNDING_MODE_SORT, + FLOAT16_SORT, + FLOAT32_SORT, + FLOAT64_SORT, + FLOAT128_SORT }; enum float_op_kind { @@ -37,22 +41,23 @@ enum float_op_kind { 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_UMINUS, + OP_FLOAT_NEG, OP_FLOAT_MUL, OP_FLOAT_DIV, OP_FLOAT_REM, OP_FLOAT_ABS, OP_FLOAT_MIN, OP_FLOAT_MAX, - OP_FLOAT_FUSED_MA, // x*y + z + OP_FLOAT_FMA, // x*y + z OP_FLOAT_SQRT, OP_FLOAT_ROUND_TO_INTEGRAL, @@ -68,13 +73,14 @@ enum float_op_kind { OP_FLOAT_IS_SUBNORMAL, OP_FLOAT_IS_PZERO, OP_FLOAT_IS_NZERO, - OP_FLOAT_IS_SIGN_MINUS, + OP_FLOAT_IS_NEGATIVE, + OP_FLOAT_IS_POSITIVE, OP_TO_FLOAT, - OP_TO_IEEE_BV, + OP_FLOAT_TO_IEEE_BV, OP_FLOAT_FP, - OP_FLOAT_TO_FP_UNSIGNED, + OP_FLOAT_TO_FP, OP_FLOAT_TO_UBV, OP_FLOAT_TO_SBV, OP_FLOAT_TO_REAL, @@ -125,16 +131,14 @@ class float_decl_plugin : public decl_plugin { 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_fused_ma(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_to_ieee_bv(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_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, @@ -243,7 +247,7 @@ public: 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_uminus(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_UMINUS, arg1); } + app * mk_uminus(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); } @@ -252,7 +256,7 @@ public: app * mk_round(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_ROUND_TO_INTEGRAL, arg1, arg2); } app * mk_fused_ma(expr * arg1, expr * arg2, expr * arg3, expr * arg4) { expr * args[4] = { arg1, arg2, arg3, arg4 }; - return m().mk_app(m_fid, OP_FLOAT_FUSED_MA, 4, args); + 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); } @@ -268,11 +272,13 @@ public: 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_SIGN_MINUS, 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_uminus(expr * a) { return is_app_of(a, m_fid, OP_FLOAT_UMINUS); } + bool is_uminus(expr * a) { return is_app_of(a, m_fid, OP_FLOAT_NEG); } - app * mk_to_ieee_bv(expr * arg1) { return m().mk_app(m_fid, OP_TO_IEEE_BV, arg1); } + 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 07f0cdc8a..8564777f2 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1844,11 +1844,19 @@ void fpa2bv_converter::mk_is_subnormal(func_decl * f, unsigned num, expr * const mk_is_denormal(args[0], result); } -void fpa2bv_converter::mk_is_sign_minus(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { +void fpa2bv_converter::mk_is_negative(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 1); mk_is_neg(args[0], result); } +void fpa2bv_converter::mk_is_positive(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 1); + expr_ref t1(m), t2(m); + mk_is_nan(args[0], t1); + mk_is_pos(args[0], t2); + 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; ); @@ -2141,10 +2149,6 @@ void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, e mk_triple(args[0], args[2], args[1], result); } -void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - NOT_IMPLEMENTED_YET(); -} - void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { NOT_IMPLEMENTED_YET(); } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index dcb508ffd..31ff0f7c9 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -114,7 +114,8 @@ public: void mk_is_zero(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_is_nzero(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_is_pzero(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_is_sign_minus(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_is_negative(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_is_positive(func_decl * f, unsigned num, expr * const * args, expr_ref & result); 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); diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index 9a0f2564f..bb2506be0 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -115,17 +115,19 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { 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_UMINUS: m_conv.mk_uminus(f, num, args, result); return BR_DONE; + case OP_FLOAT_NEG: m_conv.mk_uminus(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_remainder(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_FUSED_MA: m_conv.mk_fusedma(f, num, args, result); return BR_DONE; + case OP_FLOAT_FMA: m_conv.mk_fusedma(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; @@ -140,11 +142,11 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { 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_SIGN_MINUS: m_conv.mk_is_sign_minus(f, num, args, result); return BR_DONE; + case OP_FLOAT_IS_POSITIVE: m_conv.mk_is_negative(f, num, args, result); return BR_DONE; + case OP_FLOAT_IS_NEGATIVE: m_conv.mk_is_positive(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_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_FP_UNSIGNED: m_conv.mk_to_fp_unsigned(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; diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index a4212d579..e44540290 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -36,17 +36,17 @@ br_status float_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c br_status st = BR_FAILED; SASSERT(f->get_family_id() == get_fid()); switch (f->get_decl_kind()) { - case OP_TO_FLOAT: st = mk_to_float(f, num_args, args, result); break; + 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_UMINUS: SASSERT(num_args == 1); st = mk_uminus(args[0], 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_FUSED_MA: SASSERT(num_args == 4); st = mk_fused_ma(args[0], args[1], args[2], args[3], 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; @@ -62,10 +62,10 @@ br_status float_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c 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_SIGN_MINUS: SASSERT(num_args == 1); st = mk_is_sign_minus(args[0], result); break; - case OP_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_FP_UNSIGNED: SASSERT(num_args == 2); st = mk_to_fp_unsigned(args[0], args[1], 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; @@ -73,7 +73,7 @@ br_status float_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c return st; } -br_status float_rewriter::mk_to_float(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { +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()); @@ -188,7 +188,7 @@ br_status float_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref return BR_FAILED; } -br_status float_rewriter::mk_uminus(expr * arg1, expr_ref & result) { +br_status float_rewriter::mk_neg(expr * arg1, expr_ref & result) { if (m_util.is_nan(arg1)) { // -nan --> nan result = arg1; @@ -284,7 +284,7 @@ br_status float_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { return BR_REWRITE_FULL; } -br_status float_rewriter::mk_fused_ma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result) { +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()); @@ -480,7 +480,7 @@ br_status float_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_is_sign_minus(expr * arg1, expr_ref & result) { +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(); @@ -490,6 +490,17 @@ br_status float_rewriter::mk_is_sign_minus(expr * arg1, expr_ref & result) { 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()); @@ -532,10 +543,6 @@ br_status float_rewriter::mk_fp(expr * arg1, expr * arg2, expr * arg3, expr_ref return BR_FAILED; } -br_status float_rewriter::mk_to_fp_unsigned(expr * arg1, expr * arg2, expr_ref & result) { - return BR_FAILED; -} - br_status float_rewriter::mk_to_ubv(expr * arg1, expr * arg2, expr_ref & result) { return BR_FAILED; } diff --git a/src/ast/rewriter/float_rewriter.h b/src/ast/rewriter/float_rewriter.h index 0f44d227c..16ac766a9 100644 --- a/src/ast/rewriter/float_rewriter.h +++ b/src/ast/rewriter/float_rewriter.h @@ -44,18 +44,17 @@ public: br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); br_status mk_eq_core(expr * arg1, expr * arg2, expr_ref & result); - - br_status mk_to_float(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); + br_status mk_add(expr * arg1, expr * arg2, expr * arg3, expr_ref & result); br_status mk_sub(expr * arg1, expr * arg2, expr * arg3, expr_ref & result); br_status mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & result); br_status mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & result); - br_status mk_uminus(expr * arg1, expr_ref & result); + br_status mk_neg(expr * arg1, expr_ref & result); br_status mk_rem(expr * arg1, expr * arg2, expr_ref & result); br_status mk_abs(expr * arg1, expr_ref & result); br_status mk_min(expr * arg1, expr * arg2, expr_ref & result); br_status mk_max(expr * arg1, expr * arg2, expr_ref & result); - br_status mk_fused_ma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result); + br_status mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result); br_status mk_sqrt(expr * arg1, expr * arg2, expr_ref & result); br_status mk_round(expr * arg1, expr * arg2, expr_ref & result); br_status mk_float_eq(expr * arg1, expr * arg2, expr_ref & result); @@ -70,10 +69,12 @@ public: br_status mk_is_inf(expr * arg1, expr_ref & result); br_status mk_is_normal(expr * arg1, expr_ref & result); br_status mk_is_subnormal(expr * arg1, expr_ref & result); - br_status mk_is_sign_minus(expr * arg1, expr_ref & result); + br_status mk_is_negative(expr * arg1, expr_ref & result); + br_status mk_is_positive(expr * arg1, expr_ref & result); 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_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/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index a228ec4a5..ad353c3d0 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -132,7 +132,7 @@ namespace smt { m_converter.mk_triple(sgn, sig, exp, bv_term); } - else if (term->get_decl_kind() == OP_TO_IEEE_BV) { + else if (term->get_decl_kind() == OP_FLOAT_TO_IEEE_BV) { SASSERT(is_app(t)); expr_ref bv_e(m); proof_ref bv_pr(m); @@ -424,7 +424,7 @@ namespace smt { ctx.mark_as_relevant(bv_sig); ctx.mark_as_relevant(bv_exp); } - else if (n->get_decl()->get_decl_kind() == OP_TO_IEEE_BV) { + else if (n->get_decl()->get_decl_kind() == OP_FLOAT_TO_IEEE_BV) { expr_ref eq(m); app * ex_a = to_app(ex); if (n->get_id() > ex_a->get_id()) From b3f569574c46837209f8b38b8234924307deed1b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 22 Oct 2014 19:28:54 +0100 Subject: [PATCH 025/118] FPA API consistency Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 57 +++++------------------------------ 1 file changed, 7 insertions(+), 50 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index c31c0b89b..eb53403f6 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -635,61 +635,18 @@ void float_decl_plugin::get_op_names(svector & op_names, symbol co op_names.push_back(builtin_name("to_fp", OP_FLOAT_FP)); - if (m_bv_plugin) { - 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)); - } - - // We also support the names of operators in older drafts. - op_names.push_back(builtin_name("plusInfinity", OP_FLOAT_PLUS_INF)); - op_names.push_back(builtin_name("minusInfinity", OP_FLOAT_MINUS_INF)); + 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("+", OP_FLOAT_ADD)); - op_names.push_back(builtin_name("-", OP_FLOAT_SUB)); - op_names.push_back(builtin_name("/", OP_FLOAT_DIV)); - op_names.push_back(builtin_name("*", OP_FLOAT_MUL)); - - op_names.push_back(builtin_name("abs", OP_FLOAT_ABS)); - op_names.push_back(builtin_name("remainder", OP_FLOAT_REM)); - op_names.push_back(builtin_name("fusedMA", OP_FLOAT_FMA)); - op_names.push_back(builtin_name("squareRoot", OP_FLOAT_SQRT)); - op_names.push_back(builtin_name("roundToIntegral", OP_FLOAT_ROUND_TO_INTEGRAL)); - - op_names.push_back(builtin_name("==", OP_FLOAT_EQ)); - - op_names.push_back(builtin_name("<", OP_FLOAT_LT)); - op_names.push_back(builtin_name(">", OP_FLOAT_GT)); - op_names.push_back(builtin_name("<=", OP_FLOAT_LE)); - op_names.push_back(builtin_name(">=", OP_FLOAT_GE)); - - op_names.push_back(builtin_name("isNaN", OP_FLOAT_IS_NAN)); - op_names.push_back(builtin_name("isInfinite", OP_FLOAT_IS_INF)); - op_names.push_back(builtin_name("isZero", OP_FLOAT_IS_ZERO)); - op_names.push_back(builtin_name("isNZero", OP_FLOAT_IS_NZERO)); - op_names.push_back(builtin_name("isPZero", OP_FLOAT_IS_PZERO)); - op_names.push_back(builtin_name("isNormal", OP_FLOAT_IS_NORMAL)); - op_names.push_back(builtin_name("isSubnormal", OP_FLOAT_IS_SUBNORMAL)); - op_names.push_back(builtin_name("isSignMinus", OP_FLOAT_IS_NEGATIVE)); - - // Disabled min/max, clashes with user-defined min/max functions - // op_names.push_back(builtin_name("min", OP_FLOAT_MIN)); - // op_names.push_back(builtin_name("max", OP_FLOAT_MAX)); - - op_names.push_back(builtin_name("to_fp", OP_TO_FLOAT)); - - if (m_bv_plugin) - op_names.push_back(builtin_name("asIEEEBV", OP_FLOAT_TO_IEEE_BV)); + op_names.push_back(builtin_name("to_fp", OP_TO_FLOAT)); } -void float_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { - // Old draft sort names. - sort_names.push_back(builtin_name("FP", FLOAT_SORT)); +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)); - // In the final draft, FP is called FloatingPoint ... - sort_names.push_back(builtin_name("FloatingPoint", FLOAT_SORT)); - // ... and it supports three common FloatingPoint sorts + // 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)); From 60478b7022b31ada3c5cbfb48c58bb37c3cca579 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 22 Oct 2014 19:29:03 +0100 Subject: [PATCH 026/118] FPA API bugfix Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_rewriter.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index bb2506be0..89aaf4e12 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -142,8 +142,8 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { 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_negative(f, num, args, result); return BR_DONE; - case OP_FLOAT_IS_NEGATIVE: m_conv.mk_is_positive(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; From 261fe01ceadae0f5a387fdaf0f2af4f3147f0c6d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 11 Nov 2014 12:38:59 +0000 Subject: [PATCH 027/118] FPA API bug and consistency fixes Signed-off-by: Christoph M. Wintersteiger --- examples/c/test_capi.c | 2 +- src/api/api_fpa.cpp | 26 +++++++-- src/api/dotnet/Context.cs | 2 +- src/api/z3_fpa.h | 94 ++++++++++++++++++++++++-------- src/ast/fpa/fpa2bv_converter.cpp | 8 --- 5 files changed, 95 insertions(+), 37 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 6eb7a2e11..1aef9eb1b 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2618,7 +2618,7 @@ void fpa_example() { symbol_y = Z3_mk_string_symbol(ctx, "y"); x = Z3_mk_const(ctx, symbol_x, double_sort); y = Z3_mk_const(ctx, symbol_y, double_sort); - n = Z3_mk_fpa_double(ctx, 42.0, double_sort); + n = Z3_mk_fpa_numeral_double(ctx, 42.0, double_sort); symbol_q = Z3_mk_string_symbol(ctx, "q"); q = Z3_mk_const(ctx, symbol_q, double_sort); diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 8bcc4c1af..df0dd232a 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -99,7 +99,23 @@ extern "C" { Z3_sort r = of_sort(ctx->float_util().mk_float_sort(ebits, sbits)); RETURN_Z3(r); Z3_CATCH_RETURN(0); - } + } + + Z3_sort Z3_API Z3_mk_fpa_sort_half(__in Z3_context c) { + return Z3_mk_fpa_sort(c, 5, 11); + } + + Z3_sort Z3_API Z3_mk_fpa_sort_single(__in Z3_context c) { + return Z3_mk_fpa_sort(c, 8, 24); + } + + Z3_sort Z3_API Z3_mk_fpa_sort_double(__in Z3_context c) { + return Z3_mk_fpa_sort(c, 11, 53); + } + + Z3_sort Z3_API Z3_mk_fpa_sort_quadruple(__in 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; @@ -131,9 +147,9 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_double(Z3_context c, double v, Z3_sort ty) { + Z3_ast Z3_API Z3_mk_fpa_numeral_double(Z3_context c, double v, Z3_sort ty) { Z3_TRY; - LOG_Z3_mk_fpa_double(c, v, ty); + LOG_Z3_mk_fpa_numeral_double(c, v, ty); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); scoped_mpf tmp(ctx->float_util().fm()); @@ -158,7 +174,7 @@ extern "C" { LOG_Z3_mk_fpa_neg(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_uminus(to_expr(t))); + Z3_ast r = of_ast(ctx->float_util().mk_neg(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -208,7 +224,7 @@ extern "C" { 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->float_util().mk_fused_ma(to_expr(rm), to_expr(t1), to_expr(t2), to_expr(t3))); + Z3_ast r = of_ast(ctx->float_util().mk_fma(to_expr(rm), to_expr(t1), to_expr(t2), to_expr(t3))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index b1e60d34f..19f6d582c 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3533,7 +3533,7 @@ namespace Microsoft.Z3 public FPNum MkFP(double v, FPSort s) { Contract.Ensures(Contract.Result() != null); - return new FPNum(this, Native.Z3_mk_fpa_double(this.nCtx, v, s.NativeObject)); + return new FPNum(this, Native.Z3_mk_fpa_numeral_double(this.nCtx, v, s.NativeObject)); } /// diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 265657bf4..63b489c83 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -23,6 +23,18 @@ Notes: extern "C" { #endif // __cplusplus + /** + \defgroup capi C API + + */ + + /*@{*/ + + /** + @name Floating-Point API + */ + /*@{*/ + /** \brief Create a rounding mode sort. @@ -92,6 +104,59 @@ extern "C" { */ 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) floating point 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_half', SORT, (_in(CONTEXT),)) + */ + Z3_sort Z3_API Z3_mk_fpa_sort_half(__in Z3_context c); + + /** + \brief Create the single-precision (32-bit) floating point 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_single', SORT, (_in(CONTEXT),)) + */ + Z3_sort Z3_API Z3_mk_fpa_sort_single(__in Z3_context c); + + /** + \brief Create the double-precision (64-bit) floating point 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_double', SORT, (_in(CONTEXT),)) + */ + Z3_sort Z3_API Z3_mk_fpa_sort_double(__in Z3_context c); + + /** + \brief Create the quadruple-precision (128-bit) floating point 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 a NaN of sort s. @@ -129,7 +194,7 @@ extern "C" { Z3_ast Z3_API Z3_mk_fpa_zero(__in Z3_context c, __in Z3_sort s, __in Z3_bool negative); /** - \brief Create a numeral of floating point sort. + \brief Create a numeral of floating point sort from a double. This function can be use 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. @@ -142,27 +207,9 @@ extern "C" { \sa Z3_mk_numeral - def_API('Z3_mk_fpa_double', AST, (_in(CONTEXT), _in(DOUBLE), _in(SORT))) + def_API('Z3_mk_fpa_numeral_double', AST, (_in(CONTEXT), _in(DOUBLE), _in(SORT))) */ - Z3_ast Z3_API Z3_mk_fpa_double(__in Z3_context c, __in double v, __in Z3_sort ty); - - /** - \brief Create a numeral of floating point sort. - - This function can be use 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 floating point sort - - \sa Z3_mk_numeral - - def_API('Z3_mk_fpa_double', AST, (_in(CONTEXT), _in(DOUBLE), _in(SORT))) - */ - Z3_ast Z3_API Z3_mk_fpa_double(__in Z3_context c, __in double v, __in Z3_sort ty); + Z3_ast Z3_API Z3_mk_fpa_numeral_double(__in Z3_context c, __in double v, __in Z3_sort ty); /** \brief Floating-point absolute value @@ -468,7 +515,10 @@ extern "C" { 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); - + + /*@}*/ + /*@}*/ + #ifdef __cplusplus }; #endif // __cplusplus diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 20d8a00e1..de4797f80 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1858,14 +1858,6 @@ 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_is_positive(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 1); - expr_ref t1(m), t2(m); - mk_is_nan(args[0], t1); - mk_is_pos(args[0], t2); - 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; ); From 62d4542f83c4f314e94c1deaf1d4007e6d73aa6d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 11 Nov 2014 13:05:48 +0000 Subject: [PATCH 028/118] FPA API bug fix for RoundingMode values in models Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_model_converter.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 53fa2405b..3de869e15 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -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()); } } From 9503d955f9d0b4597fc1623e70df942e03dcabe0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 11 Nov 2014 13:16:28 +0000 Subject: [PATCH 029/118] FPA API bugfix Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 9bf2d5c81..f11389024 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -194,7 +194,7 @@ sort * float_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, paramete case FLOAT64_SORT: return mk_float_sort(11, 53); case FLOAT128_SORT: - return mk_float_sort(15, 133); + return mk_float_sort(15, 113); default: m_manager->raise_exception("unknown floating point theory sort"); return 0; From c9c11f3b3ae5299ec2975e4c96171d20c8a277b8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 11 Nov 2014 16:20:19 +0000 Subject: [PATCH 030/118] FPA API bugfix Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index f11389024..20078f73f 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -454,20 +454,6 @@ func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_parameters, 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]) || - !is_sort_of(domain[1], m_family_id, FLOAT_SORT)) - m_manager->raise_exception("sort mismatch"); - } else { // 1 Real -> 1 FP if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) @@ -481,7 +467,7 @@ func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_parameters, 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)); + return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); } } From b7c5a295705f10114e84d0d457a06ef27bda87b8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 11 Nov 2014 18:36:18 +0000 Subject: [PATCH 031/118] FPA theory bug fixes Signed-off-by: Christoph M. Wintersteiger --- src/smt/theory_fpa.cpp | 128 ++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 66 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index ad353c3d0..a7e1c7bf1 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -53,7 +53,7 @@ namespace smt { SASSERT(get_sort(x)->get_family_id() == m_converter.bu().get_family_id()); SASSERT(get_sort(y)->get_family_id() == m_converter.bu().get_family_id()); ast_manager & m = get_manager(); - context & ctx = get_context(); + context & ctx = get_context(); theory_id bv_tid = ctx.get_theory(m.get_sort(x)->get_family_id())->get_id(); literal l = mk_eq(x, y, false); ctx.mk_th_axiom(bv_tid, 1, &l); @@ -69,6 +69,7 @@ namespace smt { simplifier & simp = ctx.get_simplifier(); bv_util & bu = m_converter.bu(); expr_ref bv_atom(m); + proof_ref pr(m); if (ctx.b_internalized(atom)) return true; @@ -78,6 +79,7 @@ namespace smt { ctx.internalize(atom->get_arg(i), false); m_rw(atom, bv_atom); + simp(bv_atom, bv_atom, pr); ctx.internalize(bv_atom, gate_ctx); literal def = ctx.get_literal(bv_atom); @@ -106,12 +108,14 @@ namespace smt { bv_util & bu = m_converter.bu(); sort * term_sort = m.get_sort(term); expr_ref t(m), bv_term(m); + proof_ref pr(m); unsigned num_args = term->get_num_args(); for (unsigned i = 0; i < num_args; i++) ctx.internalize(term->get_arg(i), false); m_rw(term, t); + simp(t, t, pr); if (m_converter.is_rm(term_sort)) { SASSERT(is_app(t)); @@ -163,11 +167,13 @@ namespace smt { simplifier & simp = ctx.get_simplifier(); app * owner = n->get_owner(); expr_ref converted(m); + proof_ref pr(m); theory_var v = mk_var(n); ctx.attach_th_var(n, this, v); m_tvars.push_back(v); m_rw(owner, converted); + simp(converted, converted, pr); m_trans_map.insert(owner, converted, 0); sort * owner_sort = m.get_sort(owner); @@ -260,7 +266,7 @@ namespace smt { theory::pop_scope_eh(num_scopes); } - model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) { + model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) { ast_manager & m = get_manager(); context & ctx = get_context(); bv_util & bu = m_converter.bu(); @@ -268,12 +274,12 @@ namespace smt { mpf_manager & mpfm = fu.fm(); unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); - + theory_var v = n->get_th_var(get_id()); SASSERT(v != null_theory_var); expr * fpa_e = get_enode(v)->get_owner(); TRACE("t_fpa", tout << "mk_value for: " << mk_ismt2_pp(fpa_e, m) << "\n";); - + expr * bv_e; proof * bv_pr; m_trans_map.get(fpa_e, bv_e, bv_pr); @@ -281,16 +287,14 @@ namespace smt { expr_wrapper_proc * res = 0; if (fu.is_rm(fpa_e_srt)) { - SASSERT(ctx.e_internalized(bv_e)); - sort * s = m.get_sort(bv_e); - family_id fid = s->get_family_id(); - theory_bv * bv_th = (theory_bv*)ctx.get_theory(fid); - rational val; - if (!bv_th->get_fixed_value(ctx.get_enode(bv_e)->get_owner(), val)) { - UNREACHABLE(); - } + if (!ctx.e_internalized(bv_e)) + res = alloc(expr_wrapper_proc, fu.mk_round_nearest_ties_to_away()); else { + theory_bv * bv_th = (theory_bv*)ctx.get_theory(m.get_family_id("bv")); + rational val; + + bv_th->get_fixed_value(ctx.get_enode(bv_e)->get_owner(), val); // OK to fail app * fp_val_e; SASSERT(val.is_uint64()); switch (val.get_uint64()) @@ -301,8 +305,8 @@ namespace smt { case BV_RM_TO_POSITIVE: fp_val_e = fu.mk_round_toward_positive(); break; case BV_RM_TO_ZERO: default: fp_val_e = fu.mk_round_toward_zero(); - } - + } + TRACE("t_fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mk_ismt2_pp(fp_val_e, m) << std::endl;); res = alloc(expr_wrapper_proc, fp_val_e); } @@ -311,73 +315,65 @@ namespace smt { expr * bv_sgn, *bv_sig, *bv_exp; split_triple(bv_e, bv_sgn, bv_sig, bv_exp); - SASSERT(ctx.e_internalized(bv_sgn)); - SASSERT(ctx.e_internalized(bv_sig)); - SASSERT(ctx.e_internalized(bv_exp)); - - enode * e_sgn = ctx.get_enode(bv_sgn); - enode * e_sig = ctx.get_enode(bv_sig); - enode * e_exp = ctx.get_enode(bv_exp); - - TRACE("t_fpa", tout << "bv rep: [" << mk_ismt2_pp(e_sgn->get_owner(), m) << " " - << mk_ismt2_pp(e_sig->get_owner(), m) << " " - << mk_ismt2_pp(e_exp->get_owner(), m) << "]\n";); - - sort * s = m.get_sort(e_sgn->get_owner()); - family_id fid = s->get_family_id(); + family_id fid = m.get_family_id("bv"); theory_bv * bv_th = (theory_bv*)ctx.get_theory(fid); - SASSERT(bv_th->is_attached_to_var(e_sgn)); - SASSERT(bv_th->is_attached_to_var(e_sig)); - SASSERT(bv_th->is_attached_to_var(e_exp)); + app * e_sgn, *e_sig, *e_exp; + unsigned exp_sz = fpa_e_srt->get_parameter(0).get_int(); + unsigned sig_sz = fpa_e_srt->get_parameter(1).get_int() - 1; - unsigned sig_sz, exp_sz; - sig_sz = bu.get_bv_size(e_sig->get_owner()); - exp_sz = bu.get_bv_size(e_exp->get_owner()); + e_sgn = (ctx.e_internalized(bv_sgn)) ? ctx.get_enode(bv_sgn)->get_owner() : + m_converter.bu().mk_numeral(0, 1); + e_sig = (ctx.e_internalized(bv_sig)) ? ctx.get_enode(bv_sig)->get_owner() : + m_converter.bu().mk_numeral(0, sig_sz); + e_exp = (ctx.e_internalized(bv_exp)) ? ctx.get_enode(bv_exp)->get_owner() : + m_converter.bu().mk_numeral(0, exp_sz); + + TRACE("t_fpa", tout << "bv rep: [" + << mk_ismt2_pp(e_sgn, m) << "\n" + << mk_ismt2_pp(e_sig, m) << "\n" + << mk_ismt2_pp(e_exp, m) << "]\n";); rational sgn_r(0), sig_r(0), exp_r(0); - if (!bv_th->get_fixed_value(e_sgn->get_owner(), sgn_r) || - !bv_th->get_fixed_value(e_sig->get_owner(), sig_r) || - !bv_th->get_fixed_value(e_exp->get_owner(), exp_r)) { - UNREACHABLE(); - } - else { - TRACE("t_fpa", tout << "bv model: [" << sgn_r.to_string() << " " + bv_th->get_fixed_value(e_sgn, sgn_r); // OK to fail + bv_th->get_fixed_value(e_sig, sig_r); // OK to fail + bv_th->get_fixed_value(e_exp, exp_r); // OK to fail + + TRACE("t_fpa", tout << "bv model: [" << sgn_r.to_string() << " " << sig_r.to_string() << " " << exp_r.to_string() << "]\n";); - // un-bias exponent - rational exp_unbiased_r; - exp_unbiased_r = exp_r - mpfm.m_powers2.m1(exp_sz - 1); + // un-bias exponent + rational exp_unbiased_r; + exp_unbiased_r = exp_r - mpfm.m_powers2.m1(exp_sz - 1); - mpz sig_z; mpf_exp_t exp_z; - mpq sig_q, exp_q; - mpz sig_num, exp_num; - mpqm.set(sig_q, sig_r.to_mpq()); - mpzm.set(sig_num, sig_q.numerator()); - mpqm.set(exp_q, exp_unbiased_r.to_mpq()); - mpzm.set(exp_num, exp_q.numerator()); - mpzm.set(sig_z, sig_num); - exp_z = mpzm.get_int64(exp_num); + mpz sig_z; mpf_exp_t exp_z; + mpq sig_q, exp_q; + mpz sig_num, exp_num; + mpqm.set(sig_q, sig_r.to_mpq()); + mpzm.set(sig_num, sig_q.numerator()); + mpqm.set(exp_q, exp_unbiased_r.to_mpq()); + mpzm.set(exp_num, exp_q.numerator()); + mpzm.set(sig_z, sig_num); + exp_z = mpzm.get_int64(exp_num); - mpf fp_val; - mpfm.set(fp_val, exp_sz, sig_sz + 1, !sgn_r.is_zero(), sig_z, exp_z); + mpf fp_val; + mpfm.set(fp_val, exp_sz, sig_sz + 1, !sgn_r.is_zero(), sig_z, exp_z); - app * fp_val_e; - fp_val_e = fu.mk_value(fp_val); + app * fp_val_e; + fp_val_e = fu.mk_value(fp_val); - TRACE("t_fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mk_ismt2_pp(fp_val_e, m) << std::endl;); + TRACE("t_fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mk_ismt2_pp(fp_val_e, m) << std::endl;); - mpfm.del(fp_val); - mpzm.del(sig_num); - mpzm.del(exp_num); - mpqm.del(sig_q); - mpqm.del(exp_q); - mpzm.del(sig_z); + mpfm.del(fp_val); + mpzm.del(sig_num); + mpzm.del(exp_num); + mpqm.del(sig_q); + mpqm.del(exp_q); + mpzm.del(sig_z); - res = alloc(expr_wrapper_proc, fp_val_e); - } + res = alloc(expr_wrapper_proc, fp_val_e); } else UNREACHABLE(); From 657595818ee97233bd47955630e63ef9a6d62d6e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 10 Dec 2014 18:45:44 +0000 Subject: [PATCH 032/118] FPA API: Renaming for consistency with final SMT standard. Signed-off-by: Christoph M. Wintersteiger --- src/api/api_fpa.cpp | 31 +++++---- src/api/z3_fpa.h | 63 +++++++++++++---- src/ast/float_decl_plugin.cpp | 85 ++++++++++------------- src/ast/float_decl_plugin.h | 36 ++++------ src/ast/fpa/fpa2bv_converter.cpp | 26 +++---- src/ast/fpa/fpa2bv_converter.h | 2 +- src/ast/fpa/fpa2bv_rewriter.h | 13 ++-- src/ast/rewriter/float_rewriter.cpp | 5 +- src/smt/theory_fpa.cpp | 19 +---- src/smt/theory_fpa.h | 2 +- src/tactic/fpa/fpa2bv_model_converter.cpp | 2 +- 11 files changed, 146 insertions(+), 138 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index df0dd232a..12d32c04a 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -88,6 +88,7 @@ extern "C" { 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); @@ -105,18 +106,34 @@ extern "C" { return Z3_mk_fpa_sort(c, 5, 11); } + Z3_sort Z3_API Z3_mk_fpa_sort_16(__in Z3_context c) { + return Z3_mk_fpa_sort(c, 5, 11); + } + Z3_sort Z3_API Z3_mk_fpa_sort_single(__in Z3_context c) { return Z3_mk_fpa_sort(c, 8, 24); } + Z3_sort Z3_API Z3_mk_fpa_sort_32(__in Z3_context c) { + return Z3_mk_fpa_sort(c, 8, 24); + } + Z3_sort Z3_API Z3_mk_fpa_sort_double(__in Z3_context c) { return Z3_mk_fpa_sort(c, 11, 53); } + Z3_sort Z3_API Z3_mk_fpa_sort_64(__in Z3_context c) { + return Z3_mk_fpa_sort(c, 11, 53); + } + Z3_sort Z3_API Z3_mk_fpa_sort_quadruple(__in Z3_context c) { return Z3_mk_fpa_sort(c, 15, 113); } + Z3_sort Z3_API Z3_mk_fpa_sort_128(__in 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); @@ -373,22 +390,12 @@ extern "C" { Z3_TRY; LOG_Z3_mk_fpa_convert(c, s, rm, t); RESET_ERROR_CODE(); - api::context * ctx = mk_c(c); + api::context * ctx = mk_c(c); expr * args [2] = { to_expr(rm), to_expr(t) }; - Z3_ast r = of_ast(ctx->m().mk_app(ctx->float_util().get_family_id(), OP_TO_FLOAT, + Z3_ast r = of_ast(ctx->m().mk_app(ctx->float_util().get_family_id(), OP_FLOAT_TO_FP, to_sort(s)->get_num_parameters(), to_sort(s)->get_parameters(), 2, args)); RETURN_Z3(r); Z3_CATCH_RETURN(0); } - - Z3_ast Z3_API Z3_mk_fpa_to_ieee_bv(__in Z3_context c, __in 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->float_util().mk_float_to_ieee_bv(to_expr(t))); - RETURN_Z3(r); - Z3_CATCH_RETURN(0); - } }; diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 63b489c83..f04b87ea3 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -117,6 +117,19 @@ extern "C" { */ Z3_sort Z3_API Z3_mk_fpa_sort_half(__in Z3_context c); + /** + \brief Create the half-precision (16-bit) floating point 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_16', SORT, (_in(CONTEXT),)) + */ + Z3_sort Z3_API Z3_mk_fpa_sort_16(__in Z3_context c); + /** \brief Create the single-precision (32-bit) floating point sort. @@ -130,6 +143,19 @@ extern "C" { */ Z3_sort Z3_API Z3_mk_fpa_sort_single(__in Z3_context c); + /** + \brief Create the single-precision (32-bit) floating point 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_32', SORT, (_in(CONTEXT),)) + */ + Z3_sort Z3_API Z3_mk_fpa_sort_32(__in Z3_context c); + /** \brief Create the double-precision (64-bit) floating point sort. @@ -143,6 +169,19 @@ extern "C" { */ Z3_sort Z3_API Z3_mk_fpa_sort_double(__in Z3_context c); + /** + \brief Create the double-precision (64-bit) floating point 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_64', SORT, (_in(CONTEXT),)) + */ + Z3_sort Z3_API Z3_mk_fpa_sort__64(__in Z3_context c); + /** \brief Create the quadruple-precision (128-bit) floating point sort. @@ -156,6 +195,18 @@ extern "C" { */ Z3_sort Z3_API Z3_mk_fpa_sort_quadruple(__in Z3_context c); + /** + \brief Create the quadruple-precision (128-bit) floating point 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 NaN of sort s. @@ -504,18 +555,6 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_fpa_convert(__in Z3_context c, __in Z3_sort s, __in Z3_ast rm, __in Z3_ast t); - /** - \brief Conversion of a floating point term to a bit-vector term in IEEE754 format. - - \param c logical context. - \param t floating-point term. - - t must have floating point sort. The size of the resulting bit-vector is automatically determined. - - 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); - /*@}*/ /*@}*/ diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 20078f73f..4f8650610 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -118,23 +118,23 @@ bool float_decl_plugin::is_value(expr * n, mpf & val) { } 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)) { + if (is_app_of(n, m_family_id, OP_FLOAT_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)) { + else if (is_app_of(n, m_family_id, OP_FLOAT_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)) { + else if (is_app_of(n, m_family_id, OP_FLOAT_RM_TOWARD_NEGATIVE)) { val = MPF_ROUND_TOWARD_NEGATIVE; return true; } - else if (is_app_of(n, m_family_id, OP_RM_TOWARD_POSITIVE)) { + else if (is_app_of(n, m_family_id, OP_FLOAT_RM_TOWARD_POSITIVE)) { val = MPF_ROUND_TOWARD_POSITIVE; return true; } - else if (is_app_of(n, m_family_id, OP_RM_TOWARD_ZERO)) { + else if (is_app_of(n, m_family_id, OP_FLOAT_RM_TOWARD_ZERO)) { val = MPF_ROUND_TOWARD_ZERO; return true; } @@ -210,15 +210,15 @@ func_decl * float_decl_plugin::mk_rm_const_decl(decl_kind k, unsigned num_parame sort * s = mk_rm_sort(); func_decl_info finfo(m_family_id, k); switch (k) { - case OP_RM_NEAREST_TIES_TO_EVEN: + case OP_FLOAT_RM_NEAREST_TIES_TO_EVEN: return m_manager->mk_const_decl(symbol("roundNearestTiesToEven"), s, finfo); - case OP_RM_NEAREST_TIES_TO_AWAY: + case OP_FLOAT_RM_NEAREST_TIES_TO_AWAY: return m_manager->mk_const_decl(symbol("roundNearestTiesToAway"), s, finfo); - case OP_RM_TOWARD_POSITIVE: + case OP_FLOAT_RM_TOWARD_POSITIVE: return m_manager->mk_const_decl(symbol("roundTowardPositive"), s, finfo); - case OP_RM_TOWARD_NEGATIVE: + case OP_FLOAT_RM_TOWARD_NEGATIVE: return m_manager->mk_const_decl(symbol("roundTowardNegative"), s, finfo); - case OP_RM_TOWARD_ZERO: + case OP_FLOAT_RM_TOWARD_ZERO: return m_manager->mk_const_decl(symbol("roundTowardZero"), s, finfo); default: UNREACHABLE(); @@ -471,20 +471,6 @@ func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_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) @@ -528,17 +514,19 @@ func_decl * float_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, 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: + case OP_FLOAT_TO_FP: 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: + case OP_FLOAT_MINUS_ZERO: + case OP_FLOAT_PLUS_ZERO: 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: + case OP_FLOAT_RM_NEAREST_TIES_TO_EVEN: + case OP_FLOAT_RM_NEAREST_TIES_TO_AWAY: + case OP_FLOAT_RM_TOWARD_POSITIVE: + case OP_FLOAT_RM_TOWARD_NEGATIVE: + case OP_FLOAT_RM_TOWARD_ZERO: return mk_rm_const_decl(k, num_parameters, parameters, arity, domain, range); case OP_FLOAT_EQ: case OP_FLOAT_LT: @@ -577,8 +565,6 @@ func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters 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: @@ -601,17 +587,17 @@ void float_decl_plugin::get_op_names(svector & op_names, symbol co 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("roundNearestTiesToEven", OP_FLOAT_RM_NEAREST_TIES_TO_EVEN)); + op_names.push_back(builtin_name("roundNearestTiesToAway", OP_FLOAT_RM_NEAREST_TIES_TO_AWAY)); + op_names.push_back(builtin_name("roundTowardPositive", OP_FLOAT_RM_TOWARD_POSITIVE)); + op_names.push_back(builtin_name("roundTowardNegative", OP_FLOAT_RM_TOWARD_NEGATIVE)); + op_names.push_back(builtin_name("roundTowardZero", OP_FLOAT_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("RNE", OP_FLOAT_RM_NEAREST_TIES_TO_EVEN)); + op_names.push_back(builtin_name("RNA", OP_FLOAT_RM_NEAREST_TIES_TO_AWAY)); + op_names.push_back(builtin_name("RTP", OP_FLOAT_RM_TOWARD_POSITIVE)); + op_names.push_back(builtin_name("RTN", OP_FLOAT_RM_TOWARD_NEGATIVE)); + op_names.push_back(builtin_name("RTZ", OP_FLOAT_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)); @@ -643,7 +629,8 @@ void float_decl_plugin::get_op_names(svector & op_names, symbol co 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)); + op_names.push_back(builtin_name("to_fp", OP_FLOAT_TO_FP)); + op_names.push_back(builtin_name("to_fp_unsigned", OP_FLOAT_TO_FP_UNSIGNED)); } void float_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { @@ -670,11 +657,11 @@ 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_RM_NEAREST_TIES_TO_EVEN: + case OP_FLOAT_RM_NEAREST_TIES_TO_AWAY: + case OP_FLOAT_RM_TOWARD_POSITIVE: + case OP_FLOAT_RM_TOWARD_NEGATIVE: + case OP_FLOAT_RM_TOWARD_ZERO: case OP_FLOAT_VALUE: case OP_FLOAT_PLUS_INF: case OP_FLOAT_MINUS_INF: @@ -682,7 +669,7 @@ bool float_decl_plugin::is_value(app * e) const { case OP_FLOAT_MINUS_ZERO: case OP_FLOAT_NAN: return true; - case OP_TO_FLOAT: + case OP_FLOAT_TO_FP: return m_manager->is_value(e->get_arg(0)); default: return false; diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 93ff2e664..98b87f6c9 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -35,11 +35,11 @@ enum float_sort_kind { }; 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_RM_NEAREST_TIES_TO_EVEN, + OP_FLOAT_RM_NEAREST_TIES_TO_AWAY, + OP_FLOAT_RM_TOWARD_POSITIVE, + OP_FLOAT_RM_TOWARD_NEGATIVE, + OP_FLOAT_RM_TOWARD_ZERO, OP_FLOAT_VALUE, OP_FLOAT_PLUS_INF, @@ -76,11 +76,9 @@ enum float_op_kind { 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_FP, + OP_FLOAT_TO_FP_UNSIGNED, OP_FLOAT_TO_UBV, OP_FLOAT_TO_SBV, OP_FLOAT_TO_REAL, @@ -134,9 +132,7 @@ class float_decl_plugin : public decl_plugin { 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); + 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, @@ -210,11 +206,11 @@ public: 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_round_nearest_ties_to_even() { return m().mk_const(m_fid, OP_FLOAT_RM_NEAREST_TIES_TO_EVEN); } + app * mk_round_nearest_ties_to_away() { return m().mk_const(m_fid, OP_FLOAT_RM_NEAREST_TIES_TO_AWAY); } + app * mk_round_toward_positive() { return m().mk_const(m_fid, OP_FLOAT_RM_TOWARD_POSITIVE); } + app * mk_round_toward_negative() { return m().mk_const(m_fid, OP_FLOAT_RM_TOWARD_NEGATIVE); } + app * mk_round_toward_zero() { return m().mk_const(m_fid, OP_FLOAT_RM_TOWARD_ZERO); } app * mk_nan(unsigned ebits, unsigned sbits); app * mk_plus_inf(unsigned ebits, unsigned sbits); @@ -240,9 +236,9 @@ public: 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); } + bool is_to_float(expr * n) { return is_app_of(n, m_fid, OP_FLOAT_TO_FP); } - app * mk_to_float(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_TO_FLOAT, arg1, arg2); } + app * mk_to_float(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_TO_FP, 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); } @@ -277,8 +273,6 @@ public: 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 de4797f80..3fbb7ccf8 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -53,8 +53,8 @@ fpa2bv_converter::~fpa2bv_converter() { } 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_FLOAT_TO_FP)); + SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FLOAT_TO_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); @@ -73,8 +73,8 @@ 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_FLOAT_TO_FP)); + SASSERT(is_app_of(f, m_plugin->get_family_id(), OP_FLOAT_TO_FP)); 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); @@ -2203,7 +2203,7 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar } 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)); + SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FLOAT_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); sgn = to_app(e)->get_arg(0); @@ -2252,7 +2252,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_FLOAT_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); expr * a0 = to_app(e)->get_arg(0); expr_ref zero(m); @@ -2261,7 +2261,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_FLOAT_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); expr * a0 = to_app(e)->get_arg(0); expr_ref one(m); @@ -2424,7 +2424,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_FLOAT_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); sort * srt = to_app(e)->get_decl()->get_range(); @@ -2519,11 +2519,11 @@ 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_FLOAT_RM_NEAREST_TIES_TO_AWAY: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3); break; + case OP_FLOAT_RM_NEAREST_TIES_TO_EVEN: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); break; + case OP_FLOAT_RM_TOWARD_NEGATIVE: result = m_bv_util.mk_numeral(BV_RM_TO_NEGATIVE, 3); break; + case OP_FLOAT_RM_TOWARD_POSITIVE: result = m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3); break; + case OP_FLOAT_RM_TOWARD_ZERO: result = m_bv_util.mk_numeral(BV_RM_TO_ZERO, 3); break; default: UNREACHABLE(); } } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index eb539d8ae..d033890be 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -73,7 +73,7 @@ public: 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); + result = m.mk_app(m_util.get_family_id(), OP_FLOAT_FP, sign, significand, exponent); } void mk_eq(expr * a, expr * b, expr_ref & result); diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index 7a245b71a..62554e06e 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -107,11 +107,11 @@ 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_RM_NEAREST_TIES_TO_AWAY: + case OP_FLOAT_RM_NEAREST_TIES_TO_EVEN: + case OP_FLOAT_RM_TOWARD_NEGATIVE: + case OP_FLOAT_RM_TOWARD_POSITIVE: + case OP_FLOAT_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; @@ -144,8 +144,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { 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_TO_FP: m_conv.mk_to_float(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; diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 04546bb4b..436194844 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -36,7 +36,7 @@ br_status float_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c 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_TO_FP: 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; @@ -63,8 +63,7 @@ br_status float_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c 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_IS_POSITIVE: SASSERT(num_args == 1); st = mk_is_positive(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; diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index a7e1c7bf1..b1947ceb5 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -135,13 +135,7 @@ namespace smt { simp(a->get_arg(2), exp, pr_exp); m_converter.mk_triple(sgn, sig, exp, bv_term); - } - else if (term->get_decl_kind() == OP_FLOAT_TO_IEEE_BV) { - SASSERT(is_app(t)); - expr_ref bv_e(m); - proof_ref bv_pr(m); - simp(t, bv_term, bv_pr); - } + } else NOT_IMPLEMENTED_YET(); @@ -420,17 +414,6 @@ namespace smt { ctx.mark_as_relevant(bv_sig); ctx.mark_as_relevant(bv_exp); } - else if (n->get_decl()->get_decl_kind() == OP_FLOAT_TO_IEEE_BV) { - expr_ref eq(m); - app * ex_a = to_app(ex); - if (n->get_id() > ex_a->get_id()) - std::swap(n, ex_a); - eq = m.mk_eq(n, ex_a); - ctx.internalize(eq, false); - literal l = ctx.get_literal(eq); - ctx.mk_th_axiom(get_id(), 1, &l); - ctx.mark_as_relevant(l); - } else NOT_IMPLEMENTED_YET(); } diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 5c0d2acca..c833f2be3 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -81,7 +81,7 @@ namespace smt { protected: void split_triple(expr * e, expr * & sgn, expr * & sig, expr * & exp) const { - SASSERT(is_app_of(e, get_family_id(), OP_TO_FLOAT)); + SASSERT(is_app_of(e, get_family_id(), OP_FLOAT_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); sgn = to_app(e)->get_arg(0); sig = to_app(e)->get_arg(1); diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 3de869e15..23809d265 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -116,7 +116,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { bv_mdl->eval(a->get_arg(1), sig, true); bv_mdl->eval(a->get_arg(2), exp, true); - SASSERT(a->is_app_of(fu.get_family_id(), OP_TO_FLOAT)); + SASSERT(a->is_app_of(fu.get_family_id(), OP_FLOAT_TO_FP)); #ifdef Z3DEBUG SASSERT(to_app(a->get_arg(0))->get_decl()->get_arity() == 0); From 7965d24df8a37f26b5f4d722d3c51ba7df4cc124 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 10 Dec 2014 19:36:58 +0000 Subject: [PATCH 033/118] FPA API: added conversion functions to float_decl_plugin Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 118 +++++++++++++++++++++++++--------- src/ast/float_decl_plugin.h | 13 ++-- 2 files changed, 95 insertions(+), 36 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 4f8650610..3941d3a97 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -31,12 +31,12 @@ float_decl_plugin::float_decl_plugin(): 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); + 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 float_decl_plugin. m_manager->inc_ref(m_real_sort); - m_int_sort = m_manager->mk_sort(aid, INT_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 float_decl_plugin. m_manager->inc_ref(m_int_sort); @@ -396,8 +396,8 @@ func_decl * float_decl_plugin::mk_fma(decl_kind k, unsigned num_parameters, para 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) { +func_decl * float_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) && @@ -423,7 +423,7 @@ func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_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 + // 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()) @@ -471,51 +471,103 @@ func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_parameters, } } -func_decl * float_decl_plugin::mk_from3bv(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { +func_decl * float_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 * float_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) || + 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"); - - sort * fp = mk_float_sort(domain[1]->get_parameter(0).get_int(), domain[2]->get_parameter(0).get_int() + 1); - symbol name("fp"); + 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 * 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"); + 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"); + 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_bv_fid, BV_SORT)) - m_manager->raise_exception("sort mismatch, expected second argument of BV sort"); + if (!is_sort_of(domain[1], m_family_id, FLOAT_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"); - 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)); + 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)); } 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(); + 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 (parameters[0].is_int()) + m_manager->raise_exception("invalid parameter type; fp.to_sbv expects an int parameter"); + if (num_parameters != 1) + m_manager->raise_exception("invalid number of parameters to fp.to_sbv"); + 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"); + 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_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)); } 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(); + 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 * 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_FLOAT_TO_FP: - return mk_to_float(k, num_parameters, parameters, arity, domain, range); + switch (k) { case OP_FLOAT_MINUS_INF: case OP_FLOAT_PLUS_INF: case OP_FLOAT_NAN: @@ -566,13 +618,17 @@ func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_FLOAT_FMA: return mk_fma(k, num_parameters, parameters, arity, domain, range); case OP_FLOAT_FP: - return mk_from3bv(k, num_parameters, parameters, arity, domain, range); + return mk_fp(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); + case OP_FLOAT_TO_FP: + return mk_to_fp(k, num_parameters, parameters, arity, domain, range); + case OP_FLOAT_TO_FP_UNSIGNED: + return mk_to_fp_unsigned(k, num_parameters, parameters, arity, domain, range); default: m_manager->raise_exception("unsupported floating point operator"); return 0; @@ -628,7 +684,7 @@ void float_decl_plugin::get_op_names(svector & op_names, symbol co 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_FLOAT_TO_FP)); op_names.push_back(builtin_name("to_fp_unsigned", OP_FLOAT_TO_FP_UNSIGNED)); } diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 98b87f6c9..92610444a 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -108,6 +108,7 @@ class float_decl_plugin : public decl_plugin { 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; @@ -130,11 +131,13 @@ class float_decl_plugin : public decl_plugin { 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_from3bv(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + 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, From c2b5b6a36b1b20a8d729b8ca53678324dd2f59c6 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 10 Dec 2014 19:45:18 +0000 Subject: [PATCH 034/118] typo Signed-off-by: Christoph M. Wintersteiger --- src/api/z3_fpa.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index f04b87ea3..6042fc044 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -180,7 +180,7 @@ extern "C" { def_API('Z3_mk_fpa_sort_64', SORT, (_in(CONTEXT),)) */ - Z3_sort Z3_API Z3_mk_fpa_sort__64(__in Z3_context c); + Z3_sort Z3_API Z3_mk_fpa_sort_64(__in Z3_context c); /** \brief Create the quadruple-precision (128-bit) floating point sort. From 72dbb2a51315e729cf6cadb515acad3b00359edc Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 10 Dec 2014 20:04:24 +0000 Subject: [PATCH 035/118] FPA API bugfix Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Context.cs | 13 ------------- src/ast/fpa/fpa2bv_converter.h | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 19f6d582c..87090dcc9 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3788,19 +3788,6 @@ namespace Microsoft.Z3 return new FPExpr(this, Native.Z3_mk_fpa_convert(this.nCtx, s.NativeObject, rm.NativeObject, t.NativeObject)); } - /// - /// Conversion of a floating point term to a bit-vector term in IEEE754 format. - /// - /// - /// The size of the resulting bit-vector is automatically determined. - /// - /// floating point term - public FPExpr MkFPToIEEEBV(FPExpr t) - { - Contract.Ensures(Contract.Result() != null); - return new FPExpr(this, Native.Z3_mk_fpa_to_ieee_bv(this.nCtx, t.NativeObject)); - } - #endregion #region Miscellaneous diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index d033890be..08542cd40 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -73,7 +73,7 @@ public: 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_FLOAT_FP, sign, significand, exponent); + result = m.mk_app(m_util.get_family_id(), OP_FLOAT_TO_FP, sign, significand, exponent); } void mk_eq(expr * a, expr * b, expr_ref & result); From d6ac98a494fc6b5e3d6fa9e82250b53ad1027051 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 11 Dec 2014 12:05:52 +0000 Subject: [PATCH 036/118] FPA API: reintroduced to_ieee_bv Signed-off-by: Christoph M. Wintersteiger --- src/api/api_fpa.cpp | 11 +++++++++++ src/api/z3_fpa.h | 13 +++++++++++++ src/ast/float_decl_plugin.cpp | 20 ++++++++++++++++++++ src/ast/float_decl_plugin.h | 15 +++++++++++---- src/ast/rewriter/float_rewriter.cpp | 1 + src/smt/theory_fpa.cpp | 19 ++++++++++++++++++- 6 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 12d32c04a..876e3cff5 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -398,4 +398,15 @@ extern "C" { RETURN_Z3(r); Z3_CATCH_RETURN(0); } + + Z3_ast Z3_API Z3_mk_fpa_to_ieee_bv(__in Z3_context c, __in 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->float_util().mk_float_to_ieee_bv(to_expr(t))); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + }; diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 6042fc044..50ad49590 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -555,6 +555,19 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_fpa_convert(__in Z3_context c, __in Z3_sort s, __in Z3_ast rm, __in Z3_ast t); + /** + \brief Conversion of a floating point term to a bit-vector term in IEEE754 format. + + \param c logical context. + \param t floating-point term. + + t must have floating point sort. The size of the resulting bit-vector is automatically determined. + + 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); + + /*@}*/ /*@}*/ diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 3941d3a97..231d826b2 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -565,6 +565,21 @@ func_decl * float_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, return m_manager->mk_func_decl(name, 1, domain, m_real_sort, func_decl_info(m_family_id, k)); } +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("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 * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { switch (k) { @@ -629,6 +644,8 @@ func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters return mk_to_fp(k, num_parameters, parameters, arity, domain, range); case OP_FLOAT_TO_FP_UNSIGNED: return mk_to_fp_unsigned(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); default: m_manager->raise_exception("unsupported floating point operator"); return 0; @@ -687,6 +704,9 @@ void float_decl_plugin::get_op_names(svector & op_names, symbol co op_names.push_back(builtin_name("to_fp", OP_FLOAT_TO_FP)); op_names.push_back(builtin_name("to_fp_unsigned", OP_FLOAT_TO_FP_UNSIGNED)); + + /* Extensions */ + op_names.push_back(builtin_name("to_ieee_bv", OP_FLOAT_TO_IEEE_BV)); } void float_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 92610444a..dbd3dda2e 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -82,6 +82,9 @@ enum float_op_kind { OP_FLOAT_TO_UBV, OP_FLOAT_TO_SBV, OP_FLOAT_TO_REAL, + + /* Extensions */ + OP_FLOAT_TO_IEEE_BV, LAST_FLOAT_OP }; @@ -139,12 +142,14 @@ class float_decl_plugin : public decl_plugin { 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); + 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); + 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); - + 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); + virtual void set_manager(ast_manager * m, family_id id); unsigned mk_id(mpf const & v); void recycled_id(unsigned id); @@ -276,6 +281,8 @@ public: 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/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 436194844..d1e1ab00e 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -68,6 +68,7 @@ br_status float_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c 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; + case OP_FLOAT_TO_IEEE_BV: SASSERT(num_args == 1); st = mk_to_ieee_bv(args[0], result); break; } return st; } diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index b1947ceb5..5efac6596 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -135,7 +135,13 @@ namespace smt { simp(a->get_arg(2), exp, pr_exp); m_converter.mk_triple(sgn, sig, exp, bv_term); - } + } + else if (term->get_decl_kind() == OP_FLOAT_TO_IEEE_BV) { + SASSERT(is_app(t)); + expr_ref bv_e(m); + proof_ref bv_pr(m); + simp(t, bv_term, bv_pr); + } else NOT_IMPLEMENTED_YET(); @@ -414,6 +420,17 @@ namespace smt { ctx.mark_as_relevant(bv_sig); ctx.mark_as_relevant(bv_exp); } + else if (n->get_decl()->get_decl_kind() == OP_FLOAT_TO_IEEE_BV) { + expr_ref eq(m); + app * ex_a = to_app(ex); + if (n->get_id() > ex_a->get_id()) + std::swap(n, ex_a); + eq = m.mk_eq(n, ex_a); + ctx.internalize(eq, false); + literal l = ctx.get_literal(eq); + ctx.mk_th_axiom(get_id(), 1, &l); + ctx.mark_as_relevant(l); + } else NOT_IMPLEMENTED_YET(); } From b30e61e528b819c18831b903a37ed98291b7db90 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 13 Dec 2014 19:34:55 +0000 Subject: [PATCH 037/118] FPA: bugfixes, leakfixes, added fp.to_real Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 7 +- src/ast/fpa/fpa2bv_converter.cpp | 136 ++++++++++++++++++++++------ src/ast/fpa/fpa2bv_converter.h | 2 +- src/ast/fpa/fpa2bv_rewriter.h | 3 +- src/ast/rewriter/float_rewriter.cpp | 9 ++ src/smt/theory_fpa.cpp | 6 +- src/util/mpf.cpp | 76 ++++++++++------ 7 files changed, 177 insertions(+), 62 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 231d826b2..9b6af92ff 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -413,9 +413,13 @@ func_decl * float_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, pa 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 mismtach; 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)); @@ -461,7 +465,7 @@ func_decl * float_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, pa 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"); + m_manager->raise_exception("sort mismatch, expected third argument of Int sort"); if (domain[1] != m_real_sort) m_manager->raise_exception("sort mismatch, expected second argument of Real sort"); @@ -701,6 +705,7 @@ void float_decl_plugin::get_op_names(svector & op_names, symbol co 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("fp.to_real", OP_FLOAT_TO_REAL)); op_names.push_back(builtin_name("to_fp", OP_FLOAT_TO_FP)); op_names.push_back(builtin_name("to_fp_unsigned", OP_FLOAT_TO_FP_UNSIGNED)); diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 3fbb7ccf8..5fd96eace 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1858,9 +1858,9 @@ 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]) && @@ -1884,16 +1884,16 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a rational q; if (!m_arith_util.is_numeral(args[1], q)) - NOT_IMPLEMENTED_YET(); + UNREACHABLE(); rational e; if (!m_arith_util.is_numeral(args[2], e)) - NOT_IMPLEMENTED_YET(); + UNREACHABLE(); SASSERT(e.is_int64()); SASSERT(m_mpz_manager.eq(e.to_mpq().denominator(), 1)); - mpf nte, nta, tp, tn, tz; + 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()); @@ -1914,21 +1914,26 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a 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); + 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); } else 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); + unsigned to_ebits = m_util.get_ebits(s); expr * bv = args[0]; 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), @@ -2093,8 +2098,8 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a else if (num == 2 && m_util.is_rm(args[0]), m_arith_util.is_real(args[1])) { - // .. other than that, we only support rationals for asFloat - SASSERT(m_util.is_float(f->get_range())); + // .. other than that, we only support rationals for to_fp + 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()); @@ -2121,16 +2126,16 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a rational q; m_util.au().is_numeral(args[1], 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); } else UNREACHABLE(); @@ -2187,19 +2192,92 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg } 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_FLOAT_TO_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); - //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(); + 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 * rm = args[0]; - //expr * x = args[1]; + expr_ref sgn(m), sig(m), exp(m), lz(m); + unpack(x, sgn, sig, exp, lz, true); + // sig is of the form [1].[sigbits] - //expr * sgn, *s, *e; - //split(x, sgn, s, e); + 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); - NOT_IMPLEMENTED_YET(); + 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_mul(rsig, two); + rsig = m_arith_util.mk_add(rsig, 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_not(m_bv_util.mk_sign_extend(1, exp)); + 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; + prev_bit = bv0; + for (unsigned i = ebits; i != (unsigned)-1; i--) + { + bit = m_bv_util.mk_extract(i, i, exp_abs); + exp2 = m_arith_util.mk_mul(exp2, two); + exp2 = m_arith_util.mk_add(exp2, m.mk_ite(m.mk_eq(bit, prev_bit), zero, one)); + 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;); + + expr_ref undef(m); + undef = m.mk_fresh_const(0, rs); + + result = m.mk_ite(x_is_zero, zero, res); + result = m.mk_ite(x_is_inf, undef, result); + result = m.mk_ite(x_is_nan, undef, result); + + SASSERT(is_well_sorted(m, result)); } void fpa2bv_converter::split(expr * e, expr * & sgn, expr * & sig, expr * & exp) const { diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 08542cd40..caad0875c 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -121,7 +121,7 @@ public: 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_to_float(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_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); diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index 62554e06e..a5ff8f5ca 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -144,11 +144,12 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { 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_FLOAT_TO_FP: m_conv.mk_to_float(f, num, args, result); return BR_DONE; + case OP_FLOAT_TO_FP: m_conv.mk_to_fp(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_FLOAT_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; 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;); diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index d1e1ab00e..42a4e5660 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -552,5 +552,14 @@ br_status float_rewriter::mk_to_sbv(expr * arg1, expr * arg2, expr_ref & result) } br_status float_rewriter::mk_to_real(expr * arg1, expr_ref & result) { + scoped_mpf fv(m_util.fm()); + + if (m_util.is_value(arg1, fv)) { + 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; } \ No newline at end of file diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 5efac6596..ba53dc20f 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -136,7 +136,8 @@ namespace smt { m_converter.mk_triple(sgn, sig, exp, bv_term); } - else if (term->get_decl_kind() == OP_FLOAT_TO_IEEE_BV) { + else if (term->get_decl_kind() == OP_FLOAT_TO_IEEE_BV || + term->get_decl_kind() == OP_FLOAT_TO_REAL) { SASSERT(is_app(t)); expr_ref bv_e(m); proof_ref bv_pr(m); @@ -420,7 +421,8 @@ namespace smt { ctx.mark_as_relevant(bv_sig); ctx.mark_as_relevant(bv_exp); } - else if (n->get_decl()->get_decl_kind() == OP_FLOAT_TO_IEEE_BV) { + else if (n->get_decl()->get_decl_kind() == OP_FLOAT_TO_IEEE_BV || + n->get_decl()->get_decl_kind() == OP_FLOAT_TO_REAL) { expr_ref eq(m); app * ex_a = to_app(ex); if (n->get_id() > ex_a->get_id()) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index f5785c072..c4fa17d9a 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -199,35 +199,59 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode 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.exponent = sbits+2; + const mpz & p = m_powers2(sbits+3); + + scoped_mpq v(m_mpq_manager); + m_mpq_manager.set(v, value); + 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); + // o.exponent += sbits ; + + 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.mul(o.significand, mpz(2), o.significand); + if (m_mpq_manager.ge(v, mpq(1))) + m_mpz_manager.add(o.significand, mpz(1), o.significand); + m_mpq_manager.sub(v, mpq(1), v); // v := v - 1.0 + m_mpq_manager.mul(mpq(2), v, v); // v := 2.0 * v + } + + // Sticky + // m_mpz_manager.mul(o.significand, mpz(2), o.significand); + /*if (!m_mpq_manager.is_zero(v)) + m_mpz_manager.add(o.significand, mpz(1), o.significand);*/ + + // bias? + // o.exponent += m_mpz_manager.get_int64(m_powers2.m1(ebits - 1, false)); + + // mpq pow; + // m_mpq_manager.power(mpq(2), sbits + 3, pow); + // m_mpq_manager.div(o.significand, pow, o.significand); + // SASSERT(m_mpz_manager.ge(o.significand, mpq(1.0))); + // SASSERT(m_mpz_manager.lt(o.significand, mpq(2.0))); + + TRACE("mpf_dbg", tout << "sig=" << m_mpz_manager.to_string(o.significand) << " exp=" << o.exponent << + " sticky=" << (!m_mpq_manager.is_zero(v)) << std::endl;); + round(rm, o); } @@ -253,7 +277,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 +299,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); From 4e913bb18c561e47fef33a831cfcd568ad100e19 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 14 Dec 2014 17:34:18 +0000 Subject: [PATCH 038/118] FPA bugfixes Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 6 ++++-- src/smt/theory_fpa.cpp | 10 +++++----- src/smt/theory_fpa.h | 6 +++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 9b6af92ff..1ae8a2a2c 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -750,8 +750,10 @@ bool float_decl_plugin::is_value(app * e) const { case OP_FLOAT_MINUS_ZERO: case OP_FLOAT_NAN: return true; - case OP_FLOAT_TO_FP: - return m_manager->is_value(e->get_arg(0)); + case OP_FLOAT_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; } diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index ba53dc20f..3c6b18349 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -24,11 +24,11 @@ Revision History: namespace smt { - class mk_atom_trail : public trail { + class fpa_atom_trail : public trail { bool_var m_var; public: - mk_atom_trail(bool_var v) : m_var(v) {} - virtual ~mk_atom_trail() {} + fpa_atom_trail(bool_var v) : m_var(v) {} + virtual ~fpa_atom_trail() {} virtual void undo(theory_fpa & th) { theory_fpa::atom * a = th.get_bv2a(m_var); a->~atom(); @@ -87,7 +87,7 @@ namespace smt { ctx.set_var_theory(l.var(), get_id()); pred_atom * a = new (get_region()) pred_atom(l, def); insert_bv2a(l.var(), a); - m_trail_stack.push(mk_atom_trail(l.var())); + m_trail_stack.push(fpa_atom_trail(l.var())); if (!ctx.relevancy()) { ctx.mk_th_axiom(get_id(), l, ~def); @@ -257,7 +257,7 @@ namespace smt { } void theory_fpa::pop_scope_eh(unsigned num_scopes) { - TRACE("bv", tout << num_scopes << "\n";); + TRACE("t_fpa", tout << num_scopes << "\n";); m_trail_stack.pop_scope(num_scopes); unsigned num_old_vars = get_old_num_vars(num_scopes); for (unsigned i = num_old_vars; i < get_num_vars(); i++) { diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index c833f2be3..41374fd8f 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -27,7 +27,11 @@ Revision History: namespace smt { class theory_fpa : public theory { - typedef trail_stack th_trail_stack; + class th_trail_stack : public trail_stack { + public: + th_trail_stack(theory_fpa & th) : trail_stack(th) {} + virtual ~th_trail_stack() {} + }; public: class atom { From f11ee40c38928d84e54ca5fcee404a8cc619f6aa Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 14 Dec 2014 19:09:17 +0000 Subject: [PATCH 039/118] FPA: bug and leak fixes Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 75 ++++++++++++++++++++++++----- src/ast/float_decl_plugin.h | 2 +- src/ast/fpa/fpa2bv_converter.cpp | 50 +++++++++++++++++++ src/ast/fpa/fpa2bv_converter.h | 8 +-- src/ast/rewriter/float_rewriter.cpp | 19 ++++++-- src/ast/rewriter/float_rewriter.h | 1 + src/smt/theory_fpa.cpp | 11 +++-- 7 files changed, 142 insertions(+), 24 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 1ae8a2a2c..625ed9ade 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -457,22 +457,47 @@ func_decl * float_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, pa 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 third argument of Int sort"); - if (domain[1] != m_real_sort) - m_manager->raise_exception("sort mismatch, expected second argument of Real sort"); - + } + 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 + NOT_IMPLEMENTED_YET(); } func_decl * float_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -759,6 +784,32 @@ bool float_decl_plugin::is_value(app * e) const { } } +bool float_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_FLOAT_RM_NEAREST_TIES_TO_EVEN: + case OP_FLOAT_RM_NEAREST_TIES_TO_AWAY: + case OP_FLOAT_RM_TOWARD_POSITIVE: + case OP_FLOAT_RM_TOWARD_NEGATIVE: + case OP_FLOAT_RM_TOWARD_ZERO: + return true; + case OP_FLOAT_PLUS_INF: /* No; +oo == fp(#b0 #b11 #b00) */ + case OP_FLOAT_MINUS_INF: /* Nol -oo == fp #b1 #b11 #b00) */ + case OP_FLOAT_PLUS_ZERO: /* No; +zero == fp #b0 #b00 #b000) */ + case OP_FLOAT_MINUS_ZERO: /* No; -zero == fp #b1 #b00 #b000) */ + case OP_FLOAT_NAN: /* No; NaN == (fp #b0 #b111111 #b0000001) */ + case OP_FLOAT_VALUE: /* above */ + return false; + case OP_FLOAT_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; + } +} + float_util::float_util(ast_manager & m): m_manager(m), m_fid(m.mk_family_id("float")), diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index dbd3dda2e..bd180c45c 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -170,7 +170,7 @@ public: 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); } + virtual bool is_unique_value(app* e) const; mpf_manager & fm() { return m_fm; } func_decl * mk_value_decl(mpf const & v); diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 5fd96eace..afad59dff 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1870,6 +1870,12 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args // 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 == 2 && + m_bv_util.is_bv(args[0]) && + 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_arith_util.is_numeral(args[1]) && @@ -2143,6 +2149,50 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args 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 meant to be 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: + //((_ to_fp eb sb) RoundingMode (_ BitVec m) (_ FloatingPoint eb sb)): + // 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. + + NOT_IMPLEMENTED_YET(); + + 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()); + unsigned sz = sbits + ebits; + SASSERT(m_bv_util.get_bv_size(args[0]) == 3); + SASSERT(m_bv_util.get_bv_size(args[1]) == sz); + + expr_ref rm(m), x(m); + rm = args[0]; + x = args[1]; + + expr_ref sgn(m), sig(m), exp(m); + sgn = m_bv_util.mk_extract(sz - 1, sz - 1, x); + sig = m_bv_util.mk_extract(sz - ebits - 2, 0, x); + exp = m_bv_util.mk_extract(sz - 2, sz - ebits - 1, x); + + round(f->get_range(), rm, sgn, sig, exp, 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;); + + NOT_IMPLEMENTED_YET(); +} + 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; diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index caad0875c..e83754e38 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -121,11 +121,13 @@ public: 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_to_fp(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_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_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); diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 42a4e5660..583268c34 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -37,6 +37,7 @@ br_status float_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c SASSERT(f->get_family_id() == get_fid()); switch (f->get_decl_kind()) { case OP_FLOAT_TO_FP: st = mk_to_fp(f, num_args, args, result); break; + case OP_FLOAT_TO_FP_UNSIGNED: st = mk_to_fp_unsigned(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; @@ -86,10 +87,10 @@ br_status float_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * cons return BR_FAILED; rational q; - mpf q_mpf; + scoped_mpf q_mpf(m_util.fm()); if (m_util.au().is_numeral(args[1], q)) { TRACE("fp_rewriter", tout << "q: " << q << std::endl; ); - mpf v; + 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); @@ -98,7 +99,7 @@ br_status float_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * cons } 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; + 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); @@ -126,7 +127,7 @@ br_status float_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * cons return BR_FAILED; TRACE("fp_rewriter", tout << "q: " << q << ", e: " << e << "\n";); - mpf v; + 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); @@ -137,6 +138,16 @@ br_status float_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * cons } } +br_status float_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 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)) { diff --git a/src/ast/rewriter/float_rewriter.h b/src/ast/rewriter/float_rewriter.h index 4d8cec856..31c571f32 100644 --- a/src/ast/rewriter/float_rewriter.h +++ b/src/ast/rewriter/float_rewriter.h @@ -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/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 3c6b18349..26ee88226 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -336,10 +336,13 @@ namespace smt { << mk_ismt2_pp(e_exp, m) << "]\n";); rational sgn_r(0), sig_r(0), exp_r(0); - - bv_th->get_fixed_value(e_sgn, sgn_r); // OK to fail - bv_th->get_fixed_value(e_sig, sig_r); // OK to fail - bv_th->get_fixed_value(e_exp, exp_r); // OK to fail + + if (ctx.e_internalized(bv_sgn) && ctx.get_enode(bv_sgn)->get_num_th_vars() > 0) + bv_th->get_fixed_value(e_sgn, sgn_r); // OK to fail + if (ctx.e_internalized(bv_sig) && ctx.get_enode(bv_sig)->get_num_th_vars() > 0) + bv_th->get_fixed_value(e_sig, sig_r); // OK to fail + if (ctx.e_internalized(bv_exp) && ctx.get_enode(bv_exp)->get_num_th_vars() > 0) + bv_th->get_fixed_value(e_exp, exp_r); // OK to fail TRACE("t_fpa", tout << "bv model: [" << sgn_r.to_string() << " " << sig_r.to_string() << " " From 47325c5fd3f8bee823a8a9a6a89930309cf2999f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 16 Dec 2014 23:59:27 +0000 Subject: [PATCH 040/118] FPA: bugfixes, naming convention, core theory additions Signed-off-by: Christoph M. Wintersteiger --- src/api/api_fpa.cpp | 2 +- src/ast/float_decl_plugin.cpp | 9 +- src/ast/float_decl_plugin.h | 12 +- src/ast/fpa/fpa2bv_converter.cpp | 184 ++++++++++++++++++++++------ src/ast/fpa/fpa2bv_converter.h | 4 +- src/ast/fpa/fpa2bv_rewriter.h | 4 +- src/ast/rewriter/float_rewriter.cpp | 16 +-- src/qe/nlarith_util.cpp | 8 +- src/smt/theory_fpa.cpp | 128 +++++++++++-------- src/smt/theory_fpa.h | 34 ++++- 10 files changed, 287 insertions(+), 114 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 876e3cff5..bbf27d25d 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -149,7 +149,7 @@ extern "C" { 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->float_util().mk_minus_inf(to_sort(s)) : ctx->float_util().mk_plus_inf(to_sort(s))); + Z3_ast r = of_ast(negative != 0 ? ctx->float_util().mk_ninf(to_sort(s)) : ctx->float_util().mk_pinf(to_sort(s))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 625ed9ade..816df906e 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -163,6 +163,11 @@ decl_plugin * float_decl_plugin::mk_fresh() { } sort * float_decl_plugin::mk_float_sort(unsigned ebits, unsigned sbits) { + if (ebits > sbits) + m_manager->raise_exception("floating point sorts with ebits > sbits are currently not supported"); + if (ebits <= 2) + m_manager->raise_exception("floating point sorts with ebits <= 2 are currently not supported"); + parameter p1(ebits), p2(sbits); parameter ps[2] = { p1, p2 }; sort_size sz; @@ -841,13 +846,13 @@ app * float_util::mk_nan(unsigned ebits, unsigned sbits) { return mk_value(v); } -app * float_util::mk_plus_inf(unsigned ebits, unsigned sbits) { +app * float_util::mk_pinf(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) { +app * float_util::mk_ninf(unsigned ebits, unsigned sbits) { scoped_mpf v(fm()); fm().mk_ninf(ebits, sbits, v); return mk_value(v); diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index bd180c45c..ebf424578 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -221,11 +221,11 @@ public: app * mk_round_toward_zero() { return m().mk_const(m_fid, OP_FLOAT_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_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_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_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_value(v); } bool is_value(expr * n) { return m_plugin->is_value(n); } @@ -238,8 +238,8 @@ public: 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_pinf(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_pinf(v); } + bool is_ninf(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); } diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index afad59dff..be951098a 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -103,9 +103,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); @@ -298,7 +298,7 @@ void fpa2bv_converter::mk_rm_const(func_decl * f, expr_ref & result) { } } -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); @@ -311,7 +311,7 @@ void fpa2bv_converter::mk_plus_inf(func_decl * f, expr_ref & result) { 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); @@ -633,8 +633,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); @@ -781,8 +781,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 +927,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); @@ -1137,8 +1137,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); @@ -1447,8 +1447,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); @@ -1871,9 +1871,11 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args mk_triple(args[0], args[1], args[2], result); } else if (num == 2 && - m_bv_util.is_bv(args[0]) && + 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 && @@ -1968,8 +1970,8 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args one1 = m_bv_util.mk_numeral(1, 1); expr_ref ninf(m), pinf(m); - mk_plus_inf(f, pinf); - mk_minus_inf(f, ninf); + mk_pinf(f, pinf); + mk_ninf(f, ninf); // NaN -> NaN mk_is_nan(x, c1); @@ -2152,38 +2154,146 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args 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 meant to be a conversion from signed bitvector to float: + + // 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: - //((_ 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. - - NOT_IMPLEMENTED_YET(); + // 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())); - unsigned ebits = m_util.get_ebits(f->get_range()); - unsigned sbits = m_util.get_sbits(f->get_range()); - unsigned sz = sbits + ebits; - SASSERT(m_bv_util.get_bv_size(args[0]) == 3); - SASSERT(m_bv_util.get_bv_size(args[1]) == sz); + 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]; - expr_ref sgn(m), sig(m), exp(m); - sgn = m_bv_util.mk_extract(sz - 1, sz - 1, x); - sig = m_bv_util.mk_extract(sz - ebits - 2, 0, x); - exp = m_bv_util.mk_extract(sz - 2, sz - ebits - 1, x); + dbg_decouple("fpa2bv_to_fp_signed_x", x); - round(f->get_range(), rm, sgn, sig, exp, result); + 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); + + //if (bv_sz < f_sz) { + // x = m_bv_util.mk_zero_extend(f_sz - bv_sz, x); + // bv_sz = f_sz; + //} + + 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(); // 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(bv_sz) / log(2)) + 1); + + 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) { @@ -2538,7 +2648,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)); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index e83754e38..eb4435132 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -86,8 +86,8 @@ public: 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); diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index a5ff8f5ca..bb42bdf5d 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -113,8 +113,8 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { case OP_FLOAT_RM_TOWARD_POSITIVE: case OP_FLOAT_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_INF: m_conv.mk_pinf(f, result); return BR_DONE; + case OP_FLOAT_MINUS_INF: m_conv.mk_ninf(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; diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 583268c34..3c1f51990 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -205,14 +205,14 @@ br_status float_rewriter::mk_neg(expr * arg1, expr_ref & result) { result = arg1; return BR_DONE; } - if (m_util.is_plus_inf(arg1)) { + if (m_util.is_pinf(arg1)) { // - +oo --> -oo - result = m_util.mk_minus_inf(m().get_sort(arg1)); + result = m_util.mk_ninf(m().get_sort(arg1)); return BR_DONE; } - if (m_util.is_minus_inf(arg1)) { + if (m_util.is_ninf(arg1)) { // - -oo -> +oo - result = m_util.mk_plus_inf(m().get_sort(arg1)); + result = m_util.mk_pinf(m().get_sort(arg1)); return BR_DONE; } if (m_util.is_neg(arg1)) { @@ -366,22 +366,22 @@ br_status float_rewriter::mk_lt(expr * arg1, expr * arg2, expr_ref & result) { result = m().mk_false(); return BR_DONE; } - if (m_util.is_minus_inf(arg1)) { + 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_minus_inf(arg2)) { + if (m_util.is_ninf(arg2)) { // arg1 < -oo --> false result = m().mk_false(); return BR_DONE; } - if (m_util.is_plus_inf(arg1)) { + if (m_util.is_pinf(arg1)) { // +oo < arg2 --> false result = m().mk_false(); return BR_DONE; } - if (m_util.is_plus_inf(arg2)) { + 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; 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/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 26ee88226..7552e276b 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -49,6 +49,24 @@ namespace smt { { } + void theory_fpa::add_extra_assertions() + { + ast_manager & m = get_manager(); + context & ctx = get_context(); + simplifier & simp = ctx.get_simplifier(); + + expr_ref_vector::iterator it = m_converter.extra_assertions.begin(); + expr_ref_vector::iterator end = m_converter.extra_assertions.end(); + for (; it != end; it++) { + expr_ref t(m); + proof_ref t_pr(m); + simp(*it, t, t_pr); + TRACE("t_fpa", tout << "extra: " << mk_ismt2_pp(t, m) << "\n";); + ctx.internalize_assertion(t, t_pr, 0); + } + m_converter.extra_assertions.reset(); + } + void theory_fpa::mk_bv_eq(expr * x, expr * y) { SASSERT(get_sort(x)->get_family_id() == m_converter.bu().get_family_id()); SASSERT(get_sort(y)->get_family_id() == m_converter.bu().get_family_id()); @@ -94,6 +112,8 @@ namespace smt { ctx.mk_th_axiom(get_id(), ~l, def); } + add_extra_assertions(); + return true; } @@ -134,7 +154,7 @@ namespace smt { simp(a->get_arg(1), sig, pr_sig); simp(a->get_arg(2), exp, pr_exp); - m_converter.mk_triple(sgn, sig, exp, bv_term); + m_converter.mk_triple(sgn, sig, exp, bv_term); } else if (term->get_decl_kind() == OP_FLOAT_TO_IEEE_BV || term->get_decl_kind() == OP_FLOAT_TO_REAL) { @@ -149,7 +169,9 @@ namespace smt { TRACE("t_fpa", tout << "converted: " << mk_ismt2_pp(bv_term, get_manager()) << "\n";); SASSERT(!m_trans_map.contains(term)); - m_trans_map.insert(term, bv_term, 0); + m_trans_map.insert(term, bv_term, 0); + + add_extra_assertions(); enode * e = (ctx.e_internalized(term)) ? ctx.get_enode(term) : ctx.mk_enode(term, false, false, true); theory_var v = mk_var(e); @@ -176,11 +198,15 @@ namespace smt { m_rw(owner, converted); simp(converted, converted, pr); m_trans_map.insert(owner, converted, 0); + + add_extra_assertions(); sort * owner_sort = m.get_sort(owner); if (m_converter.is_rm(owner_sort)) { bv_util & bu = m_converter.bu(); - bu.mk_ule(converted, bu.mk_numeral(4, bu.get_bv_size(converted))); + expr_ref t(m); + t = bu.mk_ule(converted, bu.mk_numeral(4, bu.get_bv_size(converted))); + ctx.internalize_assertion(t, proof_ref(m), 0); } TRACE("t_fpa", tout << "new theory var (const): " << mk_ismt2_pp(owner, get_manager()) << " := " << v << "\n";); @@ -191,7 +217,8 @@ namespace smt { TRACE("t_fpa", tout << "new eq: " << x << " = " << y << "\n";); ast_manager & m = get_manager(); context & ctx = get_context(); - + float_util & fu = m_converter.fu(); + app * ax = get_enode(x)->get_owner(); app * ay = get_enode(y)->get_owner(); expr * ex, *ey; @@ -199,7 +226,7 @@ namespace smt { m_trans_map.get(ax, ex, px); m_trans_map.get(ay, ey, py); - if (m_converter.fu().is_float(get_enode(x)->get_owner())) { + if (fu.is_float(get_enode(x)->get_owner())) { expr * sgn_x, *sig_x, *exp_x; expr * sgn_y, *sig_y, *exp_y; split_triple(ex, sgn_x, sig_x, exp_x); @@ -209,7 +236,7 @@ namespace smt { mk_bv_eq(sig_x, sig_y); mk_bv_eq(exp_x, exp_y); } - else if (m_converter.fu().is_rm(get_enode(x)->get_owner())) { + else if (fu.is_rm(get_enode(x)->get_owner())) { mk_bv_eq(ex, ey); } else @@ -220,7 +247,8 @@ namespace smt { TRACE("t_fpa", tout << "new diseq: " << x << " != " << y << "\n";); ast_manager & m = get_manager(); context & ctx = get_context(); - + float_util & fu = m_converter.fu(); + app * ax = get_enode(x)->get_owner(); app * ay = get_enode(y)->get_owner(); expr * ex, *ey; @@ -230,7 +258,7 @@ namespace smt { expr_ref deq(m); - if (m_converter.fu().is_float(m.get_sort(get_enode(x)->get_owner()))) { + if (fu.is_float(m.get_sort(get_enode(x)->get_owner()))) { expr * sgn_x, *sig_x, *exp_x; expr * sgn_y, *sig_y, *exp_y; split_triple(ex, sgn_x, sig_x, exp_x); @@ -240,7 +268,7 @@ namespace smt { m.mk_not(m.mk_eq(sig_x, sig_y)), m.mk_not(m.mk_eq(exp_x, exp_y))); } - else if (m_converter.fu().is_rm(m.get_sort(get_enode(x)->get_owner()))) { + else if (fu.is_rm(m.get_sort(get_enode(x)->get_owner()))) { deq = m.mk_not(m.mk_eq(ex, ey)); } else @@ -317,67 +345,65 @@ namespace smt { split_triple(bv_e, bv_sgn, bv_sig, bv_exp); family_id fid = m.get_family_id("bv"); - theory_bv * bv_th = (theory_bv*)ctx.get_theory(fid); + theory_bv * bv_th = (theory_bv*)ctx.get_theory(fid); app * e_sgn, *e_sig, *e_exp; - unsigned exp_sz = fpa_e_srt->get_parameter(0).get_int(); + unsigned ebits = fpa_e_srt->get_parameter(0).get_int(); + unsigned sbits = fpa_e_srt->get_parameter(1).get_int(); unsigned sig_sz = fpa_e_srt->get_parameter(1).get_int() - 1; + rational bias = mpfm.m_powers2.m1(ebits - 1); + rational sgn_r(0), sig_r(0), exp_r(bias); + e_sgn = (ctx.e_internalized(bv_sgn)) ? ctx.get_enode(bv_sgn)->get_owner() : - m_converter.bu().mk_numeral(0, 1); + bu.mk_numeral(0, 1); e_sig = (ctx.e_internalized(bv_sig)) ? ctx.get_enode(bv_sig)->get_owner() : - m_converter.bu().mk_numeral(0, sig_sz); + bu.mk_numeral(0, sig_sz); e_exp = (ctx.e_internalized(bv_exp)) ? ctx.get_enode(bv_exp)->get_owner() : - m_converter.bu().mk_numeral(0, exp_sz); + bu.mk_numeral(bias, ebits); TRACE("t_fpa", tout << "bv rep: [" << mk_ismt2_pp(e_sgn, m) << "\n" << mk_ismt2_pp(e_sig, m) << "\n" - << mk_ismt2_pp(e_exp, m) << "]\n";); - - rational sgn_r(0), sig_r(0), exp_r(0); + << mk_ismt2_pp(e_exp, m) << "]\n";); - if (ctx.e_internalized(bv_sgn) && ctx.get_enode(bv_sgn)->get_num_th_vars() > 0) - bv_th->get_fixed_value(e_sgn, sgn_r); // OK to fail - if (ctx.e_internalized(bv_sig) && ctx.get_enode(bv_sig)->get_num_th_vars() > 0) - bv_th->get_fixed_value(e_sig, sig_r); // OK to fail - if (ctx.e_internalized(bv_exp) && ctx.get_enode(bv_exp)->get_num_th_vars() > 0) - bv_th->get_fixed_value(e_exp, exp_r); // OK to fail - - TRACE("t_fpa", tout << "bv model: [" << sgn_r.to_string() << " " - << sig_r.to_string() << " " - << exp_r.to_string() << "]\n";); + if (!ctx.e_internalized(bv_sgn) || + ctx.get_enode(bv_sgn)->get_num_th_vars() == 0 || + !bv_th->get_fixed_value(e_sgn, sgn_r)) + sgn_r = rational(0); + if (!ctx.e_internalized(bv_sig) || + ctx.get_enode(bv_sig)->get_num_th_vars() == 0 || + !bv_th->get_fixed_value(e_sig, sig_r)) + sig_r = rational(0); + if (!ctx.e_internalized(bv_exp) || + ctx.get_enode(bv_exp)->get_num_th_vars() == 0 || + !bv_th->get_fixed_value(e_exp, exp_r)) + exp_r = bias; // un-bias exponent rational exp_unbiased_r; - exp_unbiased_r = exp_r - mpfm.m_powers2.m1(exp_sz - 1); + exp_unbiased_r = exp_r - bias; - mpz sig_z; mpf_exp_t exp_z; - mpq sig_q, exp_q; - mpz sig_num, exp_num; + TRACE("t_fpa", tout << "bv model: [" << sgn_r.to_string() << " " + << sig_r.to_string() << " " + << exp_unbiased_r.to_string() << "(" << exp_r.to_string() << ")]\n"; ); + + scoped_mpz sig_z(mpzm); + mpf_exp_t exp_z; + scoped_mpq sig_q(mpqm), exp_q(mpqm); + scoped_mpz sig_num(mpzm), exp_num(mpzm); mpqm.set(sig_q, sig_r.to_mpq()); - mpzm.set(sig_num, sig_q.numerator()); + mpzm.set(sig_num, sig_q.get().numerator()); mpqm.set(exp_q, exp_unbiased_r.to_mpq()); - mpzm.set(exp_num, exp_q.numerator()); + mpzm.set(exp_num, exp_q.get().numerator()); mpzm.set(sig_z, sig_num); exp_z = mpzm.get_int64(exp_num); - mpf fp_val; - mpfm.set(fp_val, exp_sz, sig_sz + 1, !sgn_r.is_zero(), sig_z, exp_z); + scoped_mpf fp_val(mpfm); + mpfm.set(fp_val, ebits, sbits, !sgn_r.is_zero(), sig_z, exp_z); - app * fp_val_e; - fp_val_e = fu.mk_value(fp_val); - - TRACE("t_fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mk_ismt2_pp(fp_val_e, m) << std::endl;); - - mpfm.del(fp_val); - mpzm.del(sig_num); - mpzm.del(exp_num); - mpqm.del(sig_q); - mpqm.del(exp_q); - mpzm.del(sig_z); - - res = alloc(expr_wrapper_proc, fp_val_e); + TRACE("t_fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mpfm.to_string(fp_val) << std::endl;); + res = alloc(expr_wrapper_proc, m_factory->mk_value(fp_val)); } else UNREACHABLE(); @@ -445,7 +471,7 @@ namespace smt { void theory_fpa::reset_eh() { pop_scope_eh(m_trail_stack.get_num_scopes()); - m_rw.reset(); + m_rw.reset(); m_trans_map.reset(); m_bool_var2atom.reset(); m_temporaries.reset(); @@ -453,6 +479,8 @@ namespace smt { theory::reset_eh(); } - void theory_fpa::init_model(model_generator & m) { + void theory_fpa::init_model(model_generator & m) { + m_factory = alloc(fpa_factory, get_manager(), get_family_id()); + m.register_factory(m_factory); } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 41374fd8f..7b29b82de 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -23,9 +23,38 @@ Revision History: #include"trail.h" #include"fpa2bv_converter.h" #include"fpa2bv_rewriter.h" +#include"value_factory.h" namespace smt { + class fpa_factory : public value_factory { + float_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_factory(ast_manager & m, family_id fid) : + value_factory(m, fid), + m_util(m) { + } + + virtual ~fpa_factory() {} + + virtual expr * get_some_value(sort * s) { NOT_IMPLEMENTED_YET(); } + virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { NOT_IMPLEMENTED_YET(); } + 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 { class th_trail_stack : public trail_stack { public: @@ -60,6 +89,7 @@ namespace smt { bool_var2atom m_bool_var2atom; enode_vector m_temporaries; int_vector m_tvars; + fpa_factory * m_factory; virtual final_check_status final_check_eh() { return FC_DONE; } virtual bool internalize_atom(app * atom, bool gate_ctx); @@ -78,7 +108,6 @@ namespace smt { void assign_eh(bool_var v, bool is_true); virtual void relevant_eh(app * n); virtual void init_model(model_generator & m); - public: theory_fpa(ast_manager& m); virtual ~theory_fpa(); @@ -91,7 +120,8 @@ namespace smt { sig = to_app(e)->get_arg(1); exp = to_app(e)->get_arg(2); } - + + void add_extra_assertions(); void mk_bv_eq(expr * x, expr * y); }; From d5fef38c00ca42dbe91818f16f85ba239e1afb5f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 21 Dec 2014 18:43:22 +0000 Subject: [PATCH 041/118] FPA: Switched default value representation to 3-bitvector Signed-off-by: Christoph M. Wintersteiger --- src/ast/ast_smt2_pp.cpp | 51 +++++++++++++++++++++++++++++------------ src/ast/ast_smt2_pp.h | 2 +- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 77c8ac58f..00ce6aa8f 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -222,34 +222,55 @@ 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) { mpf_manager & fm = get_futil().fm(); scoped_mpf v(fm); + ast_manager & m = get_manager(); format * body = 0; + string_buffer<> buf; VERIFY(get_futil().is_value(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(get_manager(), 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(get_manager(), 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(get_manager(), 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(get_manager(), 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(get_manager(), 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()); + else { + buf << "(fp #b" << (fm.sgn(v) ? 1 : 0); + body = mk_string(get_manager(), buf.c_str()); + body = mk_compose(m, body, mk_string(get_manager(), " ")); + + 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(get_manager(), " ")); + + 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(get_manager(), ")")); + return body; } - return pp_as(body, get_manager().get_sort(t)); } // generate (- f) @@ -544,7 +565,7 @@ class smt2_printer { 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); + f = m_env.pp_float_literal(c, m_pp_bv_lits); } else if (m_env.get_dlutil().is_numeral(c)) { f = m_env.pp_datalog_literal(c); diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index aa84d6e03..93feec8d5 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -52,7 +52,7 @@ public: 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); 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); From a1b4ef9e1b7dcdf85eea923aab907bec5debf560 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 21 Dec 2014 18:44:12 +0000 Subject: [PATCH 042/118] fpa2bv refactoring Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 69 ++++++++++---- src/ast/float_decl_plugin.h | 9 ++ src/ast/fpa/fpa2bv_converter.cpp | 152 +++++++++++++++++++------------ src/ast/fpa/fpa2bv_converter.h | 18 ++-- src/ast/fpa/fpa2bv_rewriter.h | 2 + 5 files changed, 169 insertions(+), 81 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 816df906e..d775523ec 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -163,10 +163,10 @@ decl_plugin * float_decl_plugin::mk_fresh() { } sort * float_decl_plugin::mk_float_sort(unsigned ebits, unsigned sbits) { - if (ebits > sbits) - m_manager->raise_exception("floating point sorts with ebits > sbits are currently not supported"); - if (ebits <= 2) - m_manager->raise_exception("floating point sorts with ebits <= 2 are currently not supported"); + 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 }; @@ -182,13 +182,8 @@ sort * float_decl_plugin::mk_rm_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"); + 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(); @@ -279,8 +274,8 @@ func_decl * float_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_paramet 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; + case OP_FLOAT_LE: name = "fp.leq"; break; + case OP_FLOAT_GE: name = "fp.geq"; break; default: UNREACHABLE(); break; @@ -408,9 +403,12 @@ func_decl * float_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, pa 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)); + 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 @@ -423,7 +421,7 @@ func_decl * float_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, pa int sbits = parameters[1].get_int(); if (domain[0]->get_parameter(0).get_int() != (ebits + sbits)) - m_manager->raise_exception("sort mismtach; invalid bit-vector size, expected bitvector of size (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"); @@ -613,6 +611,39 @@ func_decl * float_decl_plugin::mk_float_to_ieee_bv(decl_kind k, unsigned num_par 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_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 * float_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 * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { @@ -680,6 +711,10 @@ func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters return mk_to_fp_unsigned(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_INTERNAL_BVWRAP: + return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); + case OP_FLOAT_INTERNAL_BVUNWRAP: + return mk_internal_bv_unwrap(k, num_parameters, parameters, arity, domain, range); default: m_manager->raise_exception("unsupported floating point operator"); return 0; diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index ebf424578..e4bf633a5 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -86,6 +86,10 @@ enum float_op_kind { /* Extensions */ OP_FLOAT_TO_IEEE_BV, + /* Internal use only */ + OP_FLOAT_INTERNAL_BVWRAP, + OP_FLOAT_INTERNAL_BVUNWRAP, + LAST_FLOAT_OP }; @@ -150,6 +154,11 @@ class float_decl_plugin : public decl_plugin { 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); + virtual void set_manager(ast_manager * m, family_id id); unsigned mk_id(mpf const & v); void recycled_id(unsigned id); diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index be951098a..f4b4e7951 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -32,7 +32,7 @@ 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_extra_assertions(m) { m_plugin = static_cast(m.get_plugin(m.mk_family_id("float"))); } @@ -76,10 +76,15 @@ 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_FLOAT_TO_FP)); SASSERT(is_app_of(f, m_plugin->get_family_id(), OP_FLOAT_TO_FP)); + expr *t_sgn, *t_sig, *t_exp; + expr *f_sgn, *f_sig, *f_exp; + split_triple(t, t_sgn, t_sig, t_exp); + split_triple(f, f_sgn, f_sig, f_exp); + 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); } @@ -122,6 +127,10 @@ void fpa2bv_converter::mk_value(func_decl * f, unsigned num, expr * const * args } } +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 +143,21 @@ 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); + m_fresh_bv_variables.insert(bv); 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); @@ -196,7 +201,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_triple(args[i], sgn, sig, exp); new_args.push_back(sgn); new_args.push_back(sig); new_args.push_back(exp); @@ -294,7 +299,7 @@ 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); } } @@ -612,7 +617,7 @@ 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_triple(args[0], sgn, s, e); expr_ref c(m), nsgn(m); mk_is_nan(args[0], c); nsgn = m_bv_util.mk_bv_not(sgn); @@ -695,8 +700,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); @@ -1033,7 +1037,7 @@ 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); + split_triple(args[0], sgn, s, e); mk_triple(m_bv_util.mk_numeral(0, 1), s, e, result); } @@ -1044,8 +1048,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_triple(x, x_sgn, x_sig, x_exp); + split_triple(y, y_sgn, y_sig, y_exp); 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); @@ -1087,8 +1091,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_triple(x, x_sgn, x_sig, x_exp); + split_triple(y, y_sgn, y_sig, y_exp); 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); @@ -1225,11 +1229,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); @@ -1482,7 +1484,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 +1699,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_triple(x, x_sgn, x_sig, x_exp); + split_triple(y, y_sgn, y_sig, y_exp); 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 +1735,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_triple(x, x_sgn, x_sig, x_exp); + split_triple(y, y_sgn, y_sig, y_exp); expr_ref c3(m), t3(m), t4(m), one_1(m), nil_1(m); one_1 = m_bv_util.mk_numeral(1, 1); @@ -1865,10 +1866,11 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args 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); + 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_triple(args[0], args[2], args[1], result); } else if (num == 2 && m_bv_util.is_bv(args[0]) && @@ -2148,7 +2150,7 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args else UNREACHABLE(); - SASSERT(is_well_sorted(m, 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) { @@ -2306,13 +2308,40 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con 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_triple(args[0], sgn, s, e); result = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s); } +void fpa2bv_converter::mk_internal_bvwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + TRACE("fpa2bv_internal", tout << "wrap "; + for (unsigned i = 0; i < num; i++) + tout << " " << mk_ismt2_pp(args[i], m); + tout << std::endl;); + SASSERT(num == 1); + result = m.mk_app(f, num, args); +} + +void fpa2bv_converter::mk_internal_bvunwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + TRACE("fpa2bv_internal", tout << "unwrap "; + for (unsigned i = 0; i < num; i++) + tout << " " << mk_ismt2_pp(args[i], m); + tout << std::endl;); + SASSERT(num == 1); + app * a0 = to_app(args[0]); + SASSERT(a0->get_kind() == AST_APP); + SASSERT(is_float_family(a0->get_decl())); + decl_kind k = a0->get_decl_kind(); + SASSERT(k == OP_FLOAT_INTERNAL_BVWRAP); + SASSERT(a0->get_num_args() == 1); + result = a0->get_arg(0); +} void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); + 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_triple(args[0], args[2], args[1], 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) { @@ -2328,7 +2357,7 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg //expr * x = args[1]; //expr * sgn, *s, *e; - //split(x, sgn, s, e); + //split_triple(x, sgn, s, e); NOT_IMPLEMENTED_YET(); } @@ -2346,7 +2375,7 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg //expr * x = args[1]; //expr * sgn, *s, *e; - //split(x, sgn, s, e); + //split_triple(x, sgn, s, e); NOT_IMPLEMENTED_YET(); } @@ -2440,18 +2469,28 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar SASSERT(is_well_sorted(m, result)); } -void fpa2bv_converter::split(expr * e, expr * & sgn, expr * & sig, expr * & exp) const { +void fpa2bv_converter::split_triple(expr * e, expr * & sgn, expr * & sig, expr * & exp) const { SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FLOAT_TO_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); + sig = to_app(e)->get_arg(2); + exp = to_app(e)->get_arg(1); +} + +void fpa2bv_converter::split_triple(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp) const { + SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FLOAT_TO_FP)); + SASSERT(to_app(e)->get_num_args() == 3); + expr *e_sgn, *e_sig, *e_exp; + split_triple(e, e_sgn, e_sig, e_exp); + sgn = e_sgn; + sig = e_sig; + exp = e_exp; } void fpa2bv_converter::mk_is_nan(expr * e, expr_ref & result) { expr * sgn, * sig, * exp; - split(e, sgn, sig, exp); + split_triple(e, sgn, sig, exp); // 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); @@ -2466,7 +2505,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_triple(e, sgn, sig, exp); 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)); @@ -2509,7 +2548,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_triple(e, sgn, sig, exp); 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)); @@ -2520,7 +2559,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_triple(e, sgn, sig, exp); 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); @@ -2530,7 +2569,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_triple(e, sgn, sig, exp); 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); @@ -2540,7 +2579,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_triple(e, sgn, sig, exp); 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); @@ -2548,7 +2587,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_triple(e, sgn, sig, exp); expr_ref is_special(m), is_denormal(m), p(m); mk_is_denormal(e, is_denormal); @@ -2670,9 +2709,7 @@ 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_triple(e, sgn, sig, exp); expr_ref is_normal(m); mk_is_normal(e, is_normal); @@ -2684,7 +2721,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); @@ -2772,7 +2809,7 @@ void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { // 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 } @@ -2802,7 +2839,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); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index eb4435132..5da0ca463 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -42,6 +42,7 @@ struct func_decl_triple { }; class fpa2bv_converter { +protected: ast_manager & m; basic_simplifier_plugin m_simp; float_util m_util; @@ -73,16 +74,19 @@ public: 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_FLOAT_TO_FP, sign, significand, exponent); + result = m.mk_app(m_util.get_family_id(), OP_FLOAT_TO_FP, sign, exponent, significand); } + void split_triple(expr * e, expr * & sgn, expr * & sig, expr * & exp) const; + void split_triple(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp) 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); + 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); @@ -138,11 +142,11 @@ public: obj_map const & uf23bvuf() const { return m_uf23bvuf; } void dbg_decouple(const char * prefix, expr_ref & e); - expr_ref_vector extra_assertions; + expr_ref_vector m_extra_assertions; + void mk_internal_bvwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_internal_bvunwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result); 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); @@ -173,6 +177,8 @@ protected: 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 bb42bdf5d..17ee924ad 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -150,6 +150,8 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { 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_FLOAT_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; + case OP_FLOAT_INTERNAL_BVWRAP: m_conv.mk_internal_bvwrap(f, num, args, result); return BR_DONE; + case OP_FLOAT_INTERNAL_BVUNWRAP: m_conv.mk_internal_bvunwrap(f, num, args, result); return BR_DONE; 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;); From d394b9579fd658afa26968251123392d095d5d92 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 21 Dec 2014 18:45:05 +0000 Subject: [PATCH 043/118] FPA: new conversion Signed-off-by: Christoph M. Wintersteiger --- src/ast/rewriter/float_rewriter.cpp | 67 +++++++++++++++++++---------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 3c1f51990..522fad678 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -109,33 +109,54 @@ br_status float_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * cons 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])) { + else if (num_args == 3) { + bv_util bu(m()); + rational r1, r2, r3; + unsigned bvs1, bvs2, bvs3; - mpf_rounding_mode rm; - if (!m_util.is_rm_value(args[0], rm)) + 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_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";); + 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; - - 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 { + else return BR_FAILED; - } } br_status float_rewriter::mk_to_fp_unsigned(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { From cf4b7219e10c4fdb1a6533eaab0fe6b7ec892afc Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 21 Dec 2014 18:45:36 +0000 Subject: [PATCH 044/118] new theory_fpa. plenty of bugs remain. Signed-off-by: Christoph M. Wintersteiger --- src/smt/theory_fpa.cpp | 824 +++++++++++++++++++++++++---------------- src/smt/theory_fpa.h | 86 ++++- 2 files changed, 563 insertions(+), 347 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 7552e276b..354dc7596 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -22,7 +22,7 @@ Revision History: #include"theory_bv.h" #include"smt_model_generator.h" -namespace smt { +namespace smt { class fpa_atom_trail : public trail { bool_var m_var; @@ -36,11 +36,60 @@ namespace smt { } }; + 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(); + func_decl *w, *u; + m_th.get_wrap(s, w, u); + expr_ref bv(m); + bv = m.mk_app(w, m.mk_const(f)); + unsigned bv_sz = m_th.m_converter.bu().get_bv_size(bv); + unsigned ebits = m_th.m_converter.fu().get_ebits(f->get_range()); + unsigned sbits = m_th.m_converter.fu().get_sbits(f->get_range()); + SASSERT(bv_sz == ebits + sbits); + m_th.m_converter.mk_triple(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), + m_bv_util.mk_extract(sbits - 2, 0, bv), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), + 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())); + + sort * s = f->get_range(); + func_decl *w, *u; + m_th.get_wrap(s, w, u); + result = m.mk_app(w, 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("float")), - m_converter(m), + m_converter(m, this), m_rw(m, m_converter, params_ref()), - m_trans_map(m), + m_th_rw(m), m_trail_stack(*this) { } @@ -49,45 +98,277 @@ namespace smt { { } - void theory_fpa::add_extra_assertions() + app * theory_fpa::fpa_value_proc::mk_value(model_generator & mg, ptr_vector & values) { + TRACE("t_fpa", tout << "fpa_value_proc::mk_value for: " << mk_ismt2_pp(m_a, m_th.get_manager()) << "\n";); + ast_manager & m = m_th.get_manager(); + context & ctx = m_th.get_context(); + theory_id bv_id = m.mk_family_id("bv"); + theory_bv * th_bv = dynamic_cast(ctx.get_theory(bv_id)); + SASSERT(th_bv != 0); + + float_util & fu = m_th.m_converter.fu(); + bv_util & bu = m_th.m_converter.bu(); + mpf_manager & mpfm = fu.fm(); + unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); + unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); + + sort * s = m.get_sort(m_a); + unsigned ebits = fu.get_ebits(s); + unsigned sbits = fu.get_sbits(s); + + scoped_mpz bias(mpzm); + mpzm.power(mpz(2), ebits - 1, bias); + mpzm.dec(bias); + + app * result; + float_op_kind k = (float_op_kind) to_app(m_a)->get_decl_kind(); + switch (k) + { + case -1: { + func_decl *w, *u; + m_th.get_wrap(s, w, u); + rational bv_val(0); + scoped_mpz sgn(mpzm), sig(mpzm), exp(bias); + app_ref bv_w(m); + bv_w = m.mk_app(w, m_a); + + if (!th_bv->get_fixed_value(bv_w, bv_val)) + result = fu.mk_nan(ebits, sbits); + else { + scoped_mpz all_bits(mpzm); + all_bits = bv_val.to_mpq().numerator(); + SASSERT(mpzm.is_one(bv_val.to_mpq().denominator())); + + mpzm.machine_div2k(all_bits, ebits + sbits - 1, sgn); + + scoped_mpz tmp_p(mpzm); + mpzm.power(mpz(2), ebits + sbits - 1, tmp_p); + + if (mpzm.is_one(sgn)) mpzm.sub(all_bits, tmp_p, all_bits); + + mpzm.machine_div2k(all_bits, sbits - 1, exp); + scoped_mpz exp_u(mpzm); + mpzm.sub(exp, bias, exp_u); + SASSERT(mpzm.is_int64(exp_u)); + + mpzm.power(mpz(2), sbits - 1, tmp_p); + mpzm.mod(all_bits, tmp_p, sig); + + scoped_mpf f(mpfm); + mpfm.set(f, ebits, sbits, mpzm.is_one(sgn), sig, mpzm.get_int64(exp_u)); + result = fu.mk_value(f); + } + break; + } + case OP_FLOAT_FP: { + bool is_internalized = ctx.e_internalized(m_a); + if (is_internalized) { + SASSERT(m_a->get_num_args() == 3); + app_ref a_sgn(m), a_sig(m), a_exp(m); + a_sgn = to_app(m_a->get_arg(0)); + a_exp = to_app(m_a->get_arg(1)); + a_sig = to_app(m_a->get_arg(2)); + + scoped_mpz bias(mpzm); + mpzm.power(mpz(2), ebits - 1, bias); + mpzm.dec(bias); + + rational sgn(0), sig(0), exp(bias); + th_bv->get_fixed_value(a_sgn, sgn); + th_bv->get_fixed_value(a_sig, sig); + th_bv->get_fixed_value(a_exp, exp); + + TRACE("t_fpa", tout << "sgn=" << sgn.to_string() << " ; " << + "sig=" << sig.to_string() << " ; " << + "exp=" << exp.to_string() << std::endl;); + + rational exp_u = exp - rational(bias); + SASSERT(exp_u.is_int64()); + + scoped_mpf f(mpfm); + scoped_mpq sig_q(mpqm); + sig_q = sig.to_mpq(); + mpfm.set(f, ebits, sbits, sgn.is_one(), sig_q.get().numerator(), exp_u.get_int64()); + result = fu.mk_value(f); + } + else { + result = fu.mk_nan(ebits, sbits); + } + break; + } + default: + NOT_IMPLEMENTED_YET(); + } + + TRACE("t_fpa", tout << "fpa_value_proc::mk_value result: " << 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) { + TRACE("t_fpa", tout << "fpa_rm_value_proc::mk_value for: " << mk_ismt2_pp(m_a, m_th.get_manager()) << "\n";); + ast_manager & m = m_th.get_manager(); + context & ctx = m_th.get_context(); + theory_id bv_id = m.mk_family_id("bv"); + theory_bv * th_bv = dynamic_cast(ctx.get_theory(bv_id)); + + app * result = 0; + mpf_rounding_mode rm; + if (m_th.m_converter.fu().is_rm_value(m_a, rm)) { + result = m_a.get(); + } + else { + sort * s = m.get_sort(m_a); + func_decl *w, *u; + m_th.get_wrap(s, w, u); + + app_ref bv_w(m); + bv_w = m.mk_app(w, m_a); + + rational val(0); + if (ctx.e_internalized(bv_w)) + if (!th_bv->get_fixed_value(bv_w, val)) + val = rational(0); + + 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; + } + + void theory_fpa::get_wrap(sort * s, func_decl *& wrap, func_decl *& unwrap) + { + if (!m_wraps.find(s, wrap) || !m_unwraps.find(s, unwrap)) { + SASSERT(!m_wraps.contains(s)); + ast_manager & m = get_manager(); + sort * bv_srt = 0; + + if (m_converter.is_rm(s)) + bv_srt = m_converter.bu().mk_sort(3); + else { + SASSERT(m_converter.is_float(s)); + unsigned ebits = m_converter.fu().get_ebits(s); + unsigned sbits = m_converter.fu().get_sbits(s); + bv_srt = m_converter.bu().mk_sort(ebits + sbits); + } + + wrap = m.mk_func_decl(get_family_id(), OP_FLOAT_INTERNAL_BVWRAP, 0, 0, 1, &s, bv_srt); + unwrap = m.mk_func_decl(get_family_id(), OP_FLOAT_INTERNAL_BVUNWRAP, 0, 0, 1, &bv_srt, s); + m_wraps.insert(s, wrap); + m_unwraps.insert(s, unwrap); + get_context().push_trail(insert_obj_map(m_wraps, s)); + get_context().push_trail(insert_obj_map(m_unwraps, s)); + } + } + + 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); + + TRACE("t_fpa", tout << "converted atom:" << std::endl; + tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << + mk_ismt2_pp(res, m) << std::endl;); + return res; + } + + expr_ref theory_fpa::convert_term(expr * e) { + ast_manager & m = get_manager(); + expr_ref res(m); + proof_ref pr(m); + m_rw(e, res); + + SASSERT(is_app(res)); + + if (m_converter.fu().is_rm(e)) { + SASSERT(is_sort_of(m.get_sort(res), m_converter.bu().get_family_id(), BV_SORT)); + SASSERT(m_converter.bu().get_bv_size(res) == 3); + } + else { + SASSERT(to_app(res)->get_family_id() == get_family_id()); + decl_kind k = to_app(res)->get_decl_kind(); + if (k == OP_FLOAT_TO_FP) { + SASSERT(to_app(res)->get_num_args() == 3); + SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(0)), m_converter.bu().get_family_id(), BV_SORT)); + SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(1)), m_converter.bu().get_family_id(), BV_SORT)); + SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(2)), m_converter.bu().get_family_id(), BV_SORT)); + + expr *sgn, *sig, *exp; + expr_ref s_sgn(m), s_sig(m), s_exp(m); + m_converter.split_triple(res, sgn, sig, exp); + m_th_rw(sgn, s_sgn); + m_th_rw(sig, s_sig); + m_th_rw(exp, s_exp); + + m_converter.mk_triple(s_sgn, s_sig, s_exp, res); + } + else { + SASSERT(is_sort_of(m.get_sort(e), get_family_id(), ROUNDING_MODE_SORT)); + SASSERT(is_sort_of(m.get_sort(res), m_converter.bu().get_family_id(), BV_SORT)); + } + } + + TRACE("t_fpa", tout << "converted term:" << std::endl; + tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << + mk_ismt2_pp(res, m) << std::endl;); + 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.extra_assertions.begin(); - expr_ref_vector::iterator end = m_converter.extra_assertions.end(); + 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++) { - expr_ref t(m); - proof_ref t_pr(m); - simp(*it, t, t_pr); - TRACE("t_fpa", tout << "extra: " << mk_ismt2_pp(t, m) << "\n";); - ctx.internalize_assertion(t, t_pr, 0); + simp(*it, t, t_pr); + res = m.mk_and(res, t); } - m_converter.extra_assertions.reset(); + m_converter.m_extra_assertions.reset(); + + TRACE("t_fpa", if (!m.is_true(res)) tout << "side condition: " << mk_ismt2_pp(res, m) << "\n";); + return res; } - void theory_fpa::mk_bv_eq(expr * x, expr * y) { - SASSERT(get_sort(x)->get_family_id() == m_converter.bu().get_family_id()); - SASSERT(get_sort(y)->get_family_id() == m_converter.bu().get_family_id()); - ast_manager & m = get_manager(); + void theory_fpa::assert_cnstr(expr * e) { + if (get_manager().is_true(e)) return; + TRACE("t_fpa", 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); + } + + void theory_fpa::attach_new_th_var(enode * n) { context & ctx = get_context(); - theory_id bv_tid = ctx.get_theory(m.get_sort(x)->get_family_id())->get_id(); - literal l = mk_eq(x, y, false); - ctx.mk_th_axiom(bv_tid, 1, &l); - ctx.mark_as_relevant(l); + theory_var v = mk_var(n); + ctx.attach_th_var(n, this, v); + m_tvars.push_back(v); + TRACE("t_fpa", 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("t_fpa", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << "\n";); - SASSERT(atom->get_family_id() == get_family_id()); + TRACE("t_fpa_detail", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << "\n";); + SASSERT(atom->get_family_id() == get_family_id()); ast_manager & m = get_manager(); context & ctx = get_context(); - simplifier & simp = ctx.get_simplifier(); - bv_util & bu = m_converter.bu(); - expr_ref bv_atom(m); - proof_ref pr(m); if (ctx.b_internalized(atom)) return true; @@ -96,187 +377,157 @@ namespace smt { for (unsigned i = 0; i < num_args; i++) ctx.internalize(atom->get_arg(i), false); - m_rw(atom, bv_atom); - simp(bv_atom, bv_atom, pr); - - ctx.internalize(bv_atom, gate_ctx); - literal def = ctx.get_literal(bv_atom); literal l(ctx.mk_bool_var(atom)); ctx.set_var_theory(l.var(), get_id()); - pred_atom * a = new (get_region()) pred_atom(l, def); - insert_bv2a(l.var(), a); - m_trail_stack.push(fpa_atom_trail(l.var())); + + expr_ref bv_atom(m); + bv_atom = convert_atom(atom); + bv_atom = m.mk_and(bv_atom, mk_side_conditions()); - if (!ctx.relevancy()) { - ctx.mk_th_axiom(get_id(), l, ~def); - ctx.mk_th_axiom(get_id(), ~l, def); - } - - add_extra_assertions(); - + expr_ref atom_iff(m); + assert_cnstr(m.mk_iff(atom, bv_atom)); return true; } bool theory_fpa::internalize_term(app * term) { - TRACE("t_fpa", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";); + TRACE("t_fpa_detail", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";); SASSERT(term->get_family_id() == get_family_id()); SASSERT(!get_context().e_internalized(term)); - + ast_manager & m = get_manager(); context & ctx = get_context(); - simplifier & simp = ctx.get_simplifier(); - bv_util & bu = m_converter.bu(); - sort * term_sort = m.get_sort(term); - expr_ref t(m), bv_term(m); - proof_ref pr(m); 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); - m_rw(term, t); - simp(t, t, pr); + if (is_attached_to_var(e)) + return false; - if (m_converter.is_rm(term_sort)) { - SASSERT(is_app(t)); - expr_ref bv_rm(m); - proof_ref bv_pr(m); - simp(t, bv_rm, bv_pr); + attach_new_th_var(e); + TRACE("t_fpa", tout << "internalized? " << (ctx.e_internalized(term)?"yes":"no") << std::endl;); + return true; + } - bv_term = bv_rm; - } - else if (m_converter.is_float(term_sort)) { - SASSERT(is_app(t) && to_app(t)->get_num_args() == 3); - app * a = to_app(t); - expr_ref sgn(m), sig(m), exp(m); - proof_ref pr_sgn(m), pr_sig(m), pr_exp(m); - simp(a->get_arg(0), sgn, pr_sgn); - simp(a->get_arg(1), sig, pr_sig); - simp(a->get_arg(2), exp, pr_exp); + 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()); + ast_manager & m = get_manager(); - m_converter.mk_triple(sgn, sig, exp, bv_term); - } - else if (term->get_decl_kind() == OP_FLOAT_TO_IEEE_BV || - term->get_decl_kind() == OP_FLOAT_TO_REAL) { - SASSERT(is_app(t)); - expr_ref bv_e(m); - proof_ref bv_pr(m); - simp(t, bv_term, bv_pr); - } - else - NOT_IMPLEMENTED_YET(); - - TRACE("t_fpa", tout << "converted: " << mk_ismt2_pp(bv_term, get_manager()) << "\n";); - - SASSERT(!m_trans_map.contains(term)); - m_trans_map.insert(term, bv_term, 0); - - add_extra_assertions(); - - enode * e = (ctx.e_internalized(term)) ? ctx.get_enode(term) : ctx.mk_enode(term, false, false, true); - theory_var v = mk_var(e); - ctx.attach_th_var(e, this, v); - m_tvars.push_back(v); - TRACE("t_fpa", tout << "new theory var: " << mk_ismt2_pp(term, get_manager()) << " := " << v << "\n";); - SASSERT(e->get_th_var(get_id()) != null_theory_var); - return v != null_theory_var; - } - - void theory_fpa::apply_sort_cnstr(enode * n, sort * s) { - if (!is_attached_to_var(n)) { - TRACE("t_fpa", tout << "apply sort cnstr for: " << mk_ismt2_pp(n->get_owner(), get_manager()) << "\n";); - context & ctx = get_context(); - ast_manager & m = get_manager(); - simplifier & simp = ctx.get_simplifier(); - app * owner = n->get_owner(); - expr_ref converted(m); - proof_ref pr(m); - - theory_var v = mk_var(n); - ctx.attach_th_var(n, this, v); - m_tvars.push_back(v); - m_rw(owner, converted); - simp(converted, converted, pr); - m_trans_map.insert(owner, converted, 0); - - add_extra_assertions(); + if (!is_attached_to_var(n)) + attach_new_th_var(n); - sort * owner_sort = m.get_sort(owner); - if (m_converter.is_rm(owner_sort)) { - bv_util & bu = m_converter.bu(); - expr_ref t(m); - t = bu.mk_ule(converted, bu.mk_numeral(4, bu.get_bv_size(converted))); - ctx.internalize_assertion(t, proof_ref(m), 0); + app * owner = n->get_owner(); + sort * owner_sort = m.get_sort(owner); + if (m_converter.is_rm(owner_sort)) { + bv_util & bu = m_converter.bu(); + func_decl *wrap, *unwrap; + get_wrap(owner_sort, wrap, unwrap); + if (owner->get_decl() != unwrap) + { + expr_ref converted(m), t(m); + m_rw(owner, converted); + t = bu.mk_ule(converted, bu.mk_numeral(4, 3)); + assert_cnstr(t); } - - TRACE("t_fpa", tout << "new theory var (const): " << mk_ismt2_pp(owner, get_manager()) << " := " << v << "\n";); } } void theory_fpa::new_eq_eh(theory_var x, theory_var y) { - TRACE("t_fpa", tout << "new eq: " << x << " = " << y << "\n";); ast_manager & m = get_manager(); + + TRACE("t_fpa", tout << "new eq: " << x << " = " << y << std::endl; + 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(); float_util & fu = m_converter.fu(); + bv_util & bu = m_converter.bu(); + mpf_manager & mpfm = fu.fm(); - app * ax = get_enode(x)->get_owner(); - app * ay = get_enode(y)->get_owner(); - expr * ex, *ey; - proof * px, *py; - m_trans_map.get(ax, ex, px); - m_trans_map.get(ay, ey, py); + app * xe = get_enode(x)->get_owner(); + app * ye = get_enode(y)->get_owner(); - if (fu.is_float(get_enode(x)->get_owner())) { - expr * sgn_x, *sig_x, *exp_x; - expr * sgn_y, *sig_y, *exp_y; - split_triple(ex, sgn_x, sig_x, exp_x); - split_triple(ey, sgn_y, sig_y, exp_y); + if (fu.is_float(xe) && fu.is_float(ye)) + { + expr_ref xc(m), yc(m); + xc = convert_term(xe); + yc = convert_term(ye); - mk_bv_eq(sgn_x, sgn_y); - mk_bv_eq(sig_x, sig_y); - mk_bv_eq(exp_x, exp_y); + expr *x_sgn, *x_sig, *x_exp; + m_converter.split_triple(xc, x_sgn, x_sig, x_exp); + expr *y_sgn, *y_sig, *y_exp; + m_converter.split_triple(yc, y_sgn, y_sig, y_exp); + + expr_ref c(m); + c = m.mk_and(m.mk_eq(x_sgn, y_sgn), + m.mk_eq(x_sig, y_sig), + m.mk_eq(x_exp, y_exp)); + assert_cnstr(c); + assert_cnstr(mk_side_conditions()); } - else if (fu.is_rm(get_enode(x)->get_owner())) { - mk_bv_eq(ex, ey); + else if (fu.is_rm(xe) && fu.is_rm(ye)) { + expr_ref xc(m), yc(m); + xc = convert_term(xe); + yc = convert_term(ye); + expr_ref c(m); + c = m.mk_eq(xc, yc); + assert_cnstr(c); + assert_cnstr(mk_side_conditions()); } - else - UNREACHABLE(); + + return; } void theory_fpa::new_diseq_eh(theory_var x, theory_var y) { - TRACE("t_fpa", tout << "new diseq: " << x << " != " << y << "\n";); ast_manager & m = get_manager(); + + TRACE("t_fpa", tout << "new diseq: " << x << " != " << y << std::endl; + 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(); float_util & fu = m_converter.fu(); + bv_util & bu = m_converter.bu(); + mpf_manager & mpfm = fu.fm(); - app * ax = get_enode(x)->get_owner(); - app * ay = get_enode(y)->get_owner(); - expr * ex, *ey; - proof * px, *py; - m_trans_map.get(ax, ex, px); - m_trans_map.get(ay, ey, py); + app * xe = get_enode(x)->get_owner(); + app * ye = get_enode(y)->get_owner(); - expr_ref deq(m); + if (fu.is_float(xe) && fu.is_float(ye)) + { + expr_ref xc(m), yc(m); + xc = convert_term(xe); + yc = convert_term(ye); - if (fu.is_float(m.get_sort(get_enode(x)->get_owner()))) { - expr * sgn_x, *sig_x, *exp_x; - expr * sgn_y, *sig_y, *exp_y; - split_triple(ex, sgn_x, sig_x, exp_x); - split_triple(ex, sgn_y, sig_y, exp_y); - - deq = m.mk_or(m.mk_not(m.mk_eq(sgn_x, sgn_y)), - m.mk_not(m.mk_eq(sig_x, sig_y)), - m.mk_not(m.mk_eq(exp_x, exp_y))); - } - else if (fu.is_rm(m.get_sort(get_enode(x)->get_owner()))) { - deq = m.mk_not(m.mk_eq(ex, ey)); + expr *x_sgn, *x_sig, *x_exp; + m_converter.split_triple(xc, x_sgn, x_sig, x_exp); + expr *y_sgn, *y_sig, *y_exp; + m_converter.split_triple(yc, y_sgn, y_sig, y_exp); + + expr_ref c(m); + c = m.mk_or(m.mk_not(m.mk_eq(x_sgn, y_sgn)), + m.mk_not(m.mk_eq(x_sig, y_sig)), + m.mk_not(m.mk_eq(x_exp, y_exp))); + assert_cnstr(c); + assert_cnstr(mk_side_conditions()); } - else - UNREACHABLE(); - - ctx.internalize(deq, true); - ctx.mk_th_axiom(get_id(), 1, &ctx.get_literal(deq)); - ctx.mark_as_relevant(deq); + else if (fu.is_rm(xe) && fu.is_rm(ye)) { + expr_ref xc(m), yc(m); + xc = convert_term(xe); + yc = convert_term(ye); + expr_ref c(m); + c = m.mk_not(m.mk_eq(xc, yc)); + assert_cnstr(c); + assert_cnstr(mk_side_conditions()); + } + + return; } void theory_fpa::push_scope_eh() { @@ -289,198 +540,117 @@ namespace smt { m_trail_stack.pop_scope(num_scopes); unsigned num_old_vars = get_old_num_vars(num_scopes); for (unsigned i = num_old_vars; i < get_num_vars(); i++) { - m_trans_map.erase(get_enode(m_tvars[i])->get_owner()); + // m_trans_map.erase(get_enode(m_tvars[i])->get_owner()); } m_tvars.shrink(num_old_vars); theory::pop_scope_eh(num_scopes); - } - - model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) { - ast_manager & m = get_manager(); - context & ctx = get_context(); - bv_util & bu = m_converter.bu(); - float_util & fu = m_converter.fu(); - mpf_manager & mpfm = fu.fm(); - unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); - unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); - - theory_var v = n->get_th_var(get_id()); - SASSERT(v != null_theory_var); - expr * fpa_e = get_enode(v)->get_owner(); - TRACE("t_fpa", tout << "mk_value for: " << mk_ismt2_pp(fpa_e, m) << "\n";); - - expr * bv_e; - proof * bv_pr; - m_trans_map.get(fpa_e, bv_e, bv_pr); - sort * fpa_e_srt = m.get_sort(fpa_e); - expr_wrapper_proc * res = 0; - - if (fu.is_rm(fpa_e_srt)) { - if (!ctx.e_internalized(bv_e)) - res = alloc(expr_wrapper_proc, fu.mk_round_nearest_ties_to_away()); - else - { - theory_bv * bv_th = (theory_bv*)ctx.get_theory(m.get_family_id("bv")); - rational val; - - bv_th->get_fixed_value(ctx.get_enode(bv_e)->get_owner(), val); // OK to fail - app * fp_val_e; - SASSERT(val.is_uint64()); - switch (val.get_uint64()) - { - case BV_RM_TIES_TO_AWAY: fp_val_e = fu.mk_round_nearest_ties_to_away(); break; - case BV_RM_TIES_TO_EVEN: fp_val_e = fu.mk_round_nearest_ties_to_even(); break; - case BV_RM_TO_NEGATIVE: fp_val_e = fu.mk_round_toward_negative(); break; - case BV_RM_TO_POSITIVE: fp_val_e = fu.mk_round_toward_positive(); break; - case BV_RM_TO_ZERO: - default: fp_val_e = fu.mk_round_toward_zero(); - } - - TRACE("t_fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mk_ismt2_pp(fp_val_e, m) << std::endl;); - res = alloc(expr_wrapper_proc, fp_val_e); - } - } - else if (fu.is_float(fpa_e_srt)) { - expr * bv_sgn, *bv_sig, *bv_exp; - split_triple(bv_e, bv_sgn, bv_sig, bv_exp); - - family_id fid = m.get_family_id("bv"); - theory_bv * bv_th = (theory_bv*)ctx.get_theory(fid); - - app * e_sgn, *e_sig, *e_exp; - unsigned ebits = fpa_e_srt->get_parameter(0).get_int(); - unsigned sbits = fpa_e_srt->get_parameter(1).get_int(); - unsigned sig_sz = fpa_e_srt->get_parameter(1).get_int() - 1; - - rational bias = mpfm.m_powers2.m1(ebits - 1); - rational sgn_r(0), sig_r(0), exp_r(bias); - - e_sgn = (ctx.e_internalized(bv_sgn)) ? ctx.get_enode(bv_sgn)->get_owner() : - bu.mk_numeral(0, 1); - e_sig = (ctx.e_internalized(bv_sig)) ? ctx.get_enode(bv_sig)->get_owner() : - bu.mk_numeral(0, sig_sz); - e_exp = (ctx.e_internalized(bv_exp)) ? ctx.get_enode(bv_exp)->get_owner() : - bu.mk_numeral(bias, ebits); - - TRACE("t_fpa", tout << "bv rep: [" - << mk_ismt2_pp(e_sgn, m) << "\n" - << mk_ismt2_pp(e_sig, m) << "\n" - << mk_ismt2_pp(e_exp, m) << "]\n";); - - if (!ctx.e_internalized(bv_sgn) || - ctx.get_enode(bv_sgn)->get_num_th_vars() == 0 || - !bv_th->get_fixed_value(e_sgn, sgn_r)) - sgn_r = rational(0); - if (!ctx.e_internalized(bv_sig) || - ctx.get_enode(bv_sig)->get_num_th_vars() == 0 || - !bv_th->get_fixed_value(e_sig, sig_r)) - sig_r = rational(0); - if (!ctx.e_internalized(bv_exp) || - ctx.get_enode(bv_exp)->get_num_th_vars() == 0 || - !bv_th->get_fixed_value(e_exp, exp_r)) - exp_r = bias; - - // un-bias exponent - rational exp_unbiased_r; - exp_unbiased_r = exp_r - bias; - - TRACE("t_fpa", tout << "bv model: [" << sgn_r.to_string() << " " - << sig_r.to_string() << " " - << exp_unbiased_r.to_string() << "(" << exp_r.to_string() << ")]\n"; ); - - scoped_mpz sig_z(mpzm); - mpf_exp_t exp_z; - scoped_mpq sig_q(mpqm), exp_q(mpqm); - scoped_mpz sig_num(mpzm), exp_num(mpzm); - mpqm.set(sig_q, sig_r.to_mpq()); - mpzm.set(sig_num, sig_q.get().numerator()); - mpqm.set(exp_q, exp_unbiased_r.to_mpq()); - mpzm.set(exp_num, exp_q.get().numerator()); - mpzm.set(sig_z, sig_num); - exp_z = mpzm.get_int64(exp_num); - - scoped_mpf fp_val(mpfm); - mpfm.set(fp_val, ebits, sbits, !sgn_r.is_zero(), sig_z, exp_z); - - TRACE("t_fpa", tout << mk_ismt2_pp(fpa_e, m) << " := " << mpfm.to_string(fp_val) << std::endl;); - res = alloc(expr_wrapper_proc, m_factory->mk_value(fp_val)); - } - else - UNREACHABLE(); - - return res; - } + } void theory_fpa::assign_eh(bool_var v, bool is_true) { - TRACE("t_fpa", tout << "assign_eh for: " << v << " (" << is_true << ")\n";); - /* CMW: okay to ignore? */ - theory::assign_eh(v, 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); + m_rw(e, converted); + converted = m.mk_and(converted, mk_side_conditions()); + if (!is_true) converted = m.mk_not(converted); + assert_cnstr(converted); } void theory_fpa::relevant_eh(app * n) { TRACE("t_fpa", tout << "relevant_eh for: " << mk_ismt2_pp(n, get_manager()) << "\n";); + + NOT_IMPLEMENTED_YET(); + ast_manager & m = get_manager(); - context & ctx = get_context(); + + if (m.is_bool(n)) + return; + float_util & fu = m_converter.fu(); bv_util & bu = m_converter.bu(); + mpf_manager & mpfm = fu.fm(); - if (m.is_bool(n)) { - bool_var v = ctx.get_bool_var(n); - atom * a = get_bv2a(v); - pred_atom * pa = static_cast(a); - ctx.mark_as_relevant(pa->m_def); - ctx.mk_th_axiom(get_id(), pa->m_var, ~pa->m_def); - ctx.mk_th_axiom(get_id(), ~pa->m_var, pa->m_def); - } - else if (ctx.e_internalized(n)) { - SASSERT(m_trans_map.contains(n)); - expr * ex; - proof * px; - m_trans_map.get(n, ex, px); - sort * n_srt = m.get_sort(n); + if (bu.is_bv(n)) + return; - if (fu.is_rm(n_srt)) { - ctx.mark_as_relevant(ex); - } - else if (fu.is_float(n_srt)) { - expr * bv_sgn, *bv_sig, *bv_exp; - split_triple(ex, bv_sgn, bv_sig, bv_exp); + sort * s = m.get_sort(n); + func_decl *wrap, *unwrap; + get_wrap(s, wrap, unwrap); - ctx.mark_as_relevant(bv_sgn); - ctx.mark_as_relevant(bv_sig); - ctx.mark_as_relevant(bv_exp); - } - else if (n->get_decl()->get_decl_kind() == OP_FLOAT_TO_IEEE_BV || - n->get_decl()->get_decl_kind() == OP_FLOAT_TO_REAL) { - expr_ref eq(m); - app * ex_a = to_app(ex); - if (n->get_id() > ex_a->get_id()) - std::swap(n, ex_a); - eq = m.mk_eq(n, ex_a); - ctx.internalize(eq, false); - literal l = ctx.get_literal(eq); - ctx.mk_th_axiom(get_id(), 1, &l); - ctx.mark_as_relevant(l); + if (n->get_decl() != unwrap) { + expr * wrapped = m.mk_app(wrap, n); + mpf_rounding_mode rm; + scoped_mpf val(mpfm); + if (fu.is_rm_value(n, rm)) + assert_cnstr(m.mk_eq(wrapped, bu.mk_numeral(rm, 3))); + else if (fu.is_value(n, val)) { + unsigned sz = val.get().get_ebits() + val.get().get_sbits(); + scoped_mpq q(fu.fm().mpq_manager()); + mpfm.to_rational(val, q); + assert_cnstr(m.mk_eq(wrapped, bu.mk_numeral(rational(q), sz))); } else - NOT_IMPLEMENTED_YET(); + assert_cnstr(m.mk_eq(m.mk_app(unwrap, wrapped), n)); } - else - UNREACHABLE(); } void theory_fpa::reset_eh() { + TRACE("t_fpa", tout << "reset_eh for: " << "\n";); pop_scope_eh(m_trail_stack.get_num_scopes()); m_rw.reset(); - m_trans_map.reset(); m_bool_var2atom.reset(); m_temporaries.reset(); m_tvars.reset(); theory::reset_eh(); } - void theory_fpa::init_model(model_generator & m) { + void theory_fpa::init_model(model_generator & mg) { + TRACE("t_fpa", tout << "initializing model" << std::endl;); m_factory = alloc(fpa_factory, get_manager(), get_family_id()); - m.register_factory(m_factory); + mg.register_factory(m_factory); + TRACE("t_fpa", display(tout);); + } + + 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()) << "\n";); + + ast_manager & m = get_manager(); + float_util & fu = m_converter.fu(); + + expr * owner = n->get_owner(); + sort * o_srt = m.get_sort(owner); + + mpf_rounding_mode rm; + + if (fu.is_rm_value(n->get_owner(), rm)) + return alloc(expr_wrapper_proc, n->get_owner()); + else if (fu.is_value(n->get_owner())) + return alloc(expr_wrapper_proc, n->get_owner()); + else if (fu.is_rm(owner)) + return alloc(fpa_rm_value_proc, this, app_ref(to_app(owner), m)); + else if (fu.is_float(owner)) + return alloc(fpa_value_proc, this, app_ref(to_app(owner), m)); + + UNREACHABLE(); + return 0; + } + + 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 << "theory variables:" << std::endl; + ptr_vector::const_iterator it = ctx.begin_enodes(); + ptr_vector::const_iterator end = ctx.end_enodes(); + for (; it != end; it++) + out << (*it)->get_th_var(get_family_id()) << " -> " << + mk_ismt2_pp((*it)->get_owner(), m) << std::endl; } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 7b29b82de..0c472be33 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -23,7 +23,9 @@ Revision History: #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 { @@ -52,8 +54,7 @@ namespace smt { app * mk_value(mpf const & x) { return m_util.mk_value(x); } - }; - + }; class theory_fpa : public theory { class th_trail_stack : public trail_stack { @@ -62,6 +63,45 @@ namespace smt { virtual ~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; + app_ref m_a; + svector m_dependencies; + public: + fpa_value_proc(theory_fpa * th, app_ref & a) : m_th(*th), m_a(a) {} + void add_dependency(enode * n) { m_dependencies.push_back(model_value_dependency(n)); } + virtual ~fpa_value_proc() {} + virtual void get_dependencies(buffer & result) { + result.append(m_dependencies.size(), m_dependencies.c_ptr()); + } + virtual app * mk_value(model_generator & mg, ptr_vector & values); + }; + + class fpa_rm_value_proc : public fpa_value_proc { + float_util & m_fu; + bv_util & m_bu; + public: + fpa_rm_value_proc(theory_fpa * th, app_ref & a) : + fpa_value_proc(th, a), + m_fu(th->m_converter.fu()), + m_bu(th->m_converter.bu()) {} + void add_dependency(enode * n) { fpa_value_proc::add_dependency(n); } + virtual ~fpa_rm_value_proc() {} + virtual app * mk_value(model_generator & mg, ptr_vector & values); + }; + public: class atom { public: @@ -79,17 +119,20 @@ namespace smt { void insert_bv2a(bool_var bv, pred_atom * a) { m_bool_var2atom.setx(bv, a, 0); } void erase_bv2a(bool_var bv) { m_bool_var2atom[bv] = 0; } pred_atom * get_bv2a(bool_var bv) const { return m_bool_var2atom.get(bv, 0); } - region & get_region() { return m_trail_stack.get_region(); } + region & get_region() { return m_trail_stack.get_region(); } protected: - fpa2bv_converter m_converter; - fpa2bv_rewriter m_rw; - expr_map m_trans_map; - th_trail_stack m_trail_stack; - bool_var2atom m_bool_var2atom; - enode_vector m_temporaries; - int_vector m_tvars; - fpa_factory * m_factory; + fpa2bv_converter_wrapped m_converter; + fpa2bv_rewriter m_rw; + th_rewriter m_th_rw; + th_trail_stack m_trail_stack; + bool_var2atom m_bool_var2atom; + enode_vector m_temporaries; + vector m_tvars; + fpa_factory * m_factory; + obj_map m_wraps; + obj_map m_unwraps; + float_decl_plugin m_flt_plugin; virtual final_check_status final_check_eh() { return FC_DONE; } virtual bool internalize_atom(app * atom, bool gate_ctx); @@ -108,21 +151,24 @@ namespace smt { 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); virtual ~theory_fpa(); - protected: - void split_triple(expr * e, expr * & sgn, expr * & sig, expr * & exp) const { - SASSERT(is_app_of(e, get_family_id(), OP_FLOAT_TO_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); - } + virtual void display(std::ostream & out) const; + + protected: + expr_ref mk_side_conditions(); + expr_ref convert_atom(expr * e); + expr_ref convert_term(expr * e); + void get_wrap(sort * s, func_decl *& wrap, func_decl *& unwrap); + void add_trail(ast * a); - void add_extra_assertions(); void mk_bv_eq(expr * x, expr * y); + void attach_new_th_var(enode * n); + void assert_cnstr(expr * e); }; }; From b8c373bbce423f861cb1583dbc73d53fa987e3d6 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 22 Dec 2014 14:25:23 +0000 Subject: [PATCH 045/118] fpa2bv tactic bugfix Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_tactic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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); From 7f8a34d2e11e99ff5272de113bfbe382b16bb0cd Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 13:31:30 +0000 Subject: [PATCH 046/118] Adjusted default model display for float literals. Signed-off-by: Christoph M. Wintersteiger --- src/ast/ast_smt2_pp.cpp | 38 +++++++++++++++++++++++++------------- src/ast/ast_smt2_pp.h | 2 +- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 00ce6aa8f..a9e223c55 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -222,7 +222,7 @@ 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, bool use_bv_lits) { +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(); @@ -231,28 +231,38 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits) { VERIFY(get_futil().is_value(t, v)); if (fm.is_nan(v)) { buf << "(_ NaN " << v.get().get_ebits() << " " << v.get().get_sbits() << ")"; - return mk_string(get_manager(), buf.c_str()); + return mk_string(m, buf.c_str()); } else if (fm.is_pinf(v)) { buf << "(_ +oo " << v.get().get_ebits() << " " << v.get().get_sbits() << ")"; - return mk_string(get_manager(), buf.c_str()); + return mk_string(m, buf.c_str()); } else if (fm.is_ninf(v)) { buf << "(_ -oo " << v.get().get_ebits() << " " << v.get().get_sbits() << ")"; - return mk_string(get_manager(), buf.c_str()); + return mk_string(m, buf.c_str()); } else if (fm.is_pzero(v)) { buf << "(_ +zero " << v.get().get_ebits() << " " << v.get().get_sbits() << ")"; - return mk_string(get_manager(), buf.c_str()); + return mk_string(m, buf.c_str()); } else if (fm.is_nzero(v)) { buf << "(_ -zero " << v.get().get_ebits() << " " << v.get().get_sbits() << ")"; - return mk_string(get_manager(), buf.c_str()); + return mk_string(m, buf.c_str()); } - else { - buf << "(fp #b" << (fm.sgn(v) ? 1 : 0); - body = mk_string(get_manager(), buf.c_str()); - body = mk_compose(m, body, mk_string(get_manager(), " ")); + 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 { + 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); @@ -260,7 +270,7 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits) { 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(get_manager(), " ")); + body = mk_compose(m, body, mk_string(m, " ")); scoped_mpz sig(fm.mpz_manager()); sig = fm.sig(v); @@ -268,7 +278,7 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits) { 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(get_manager(), ")")); + body = mk_compose(m, body, mk_string(m, ")")); return body; } } @@ -446,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; @@ -565,7 +576,7 @@ class smt2_printer { 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, m_pp_bv_lits); + 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); @@ -1008,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 93feec8d5..37d13e57a 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -52,7 +52,7 @@ public: 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, bool use_bv_lits); + 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); From 6ebeebde509d23b597889f3dc2078c79d964beb8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 13:32:34 +0000 Subject: [PATCH 047/118] Added parameter to display floating point numerals as reals Signed-off-by: Christoph M. Wintersteiger --- src/ast/pp_params.pyg | 1 + src/util/mpf.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) 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/util/mpf.cpp b/src/util/mpf.cpp index c4fa17d9a..ac2eb3096 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1223,7 +1223,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(); } } From 55662bcf6b62d835878ebd4404f428a2b6ab4dbc Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 13:33:19 +0000 Subject: [PATCH 048/118] fpa2bv: added reset(), adjustments for consistency Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 43 +++++++++++++++++++------------- src/ast/fpa/fpa2bv_converter.h | 4 +++ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index f4b4e7951..0de267d2f 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -37,19 +37,7 @@ fpa2bv_converter::fpa2bv_converter(ast_manager & m) : } 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) { @@ -58,8 +46,8 @@ void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { 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 @@ -2261,7 +2249,7 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const // 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(bv_sz) / log(2)) + 1); + 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. @@ -2473,9 +2461,9 @@ void fpa2bv_converter::split_triple(expr * e, expr * & sgn, expr * & sig, expr * SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FLOAT_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); - sgn = to_app(e)->get_arg(0); - sig = to_app(e)->get_arg(2); + sgn = to_app(e)->get_arg(0); exp = to_app(e)->get_arg(1); + sig = to_app(e)->get_arg(2); } void fpa2bv_converter::split_triple(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp) const { @@ -3140,3 +3128,22 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & 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 5da0ca463..cd92a6ab2 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -63,6 +63,7 @@ public: float_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()); } @@ -141,11 +142,14 @@ public: 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 m_extra_assertions; void mk_internal_bvwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_internal_bvunwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + protected: void mk_is_nan(expr * e, expr_ref & result); void mk_is_inf(expr * e, expr_ref & result); From d1cb2566e4e45239000d82b703ea66585e317285 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 13:33:48 +0000 Subject: [PATCH 049/118] fpa2bv: adjustments for consistency Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_model_converter.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 23809d265..989ad64ff 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -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_FLOAT_TO_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); From 7a15c41c473152ffd6d83e48133c3dd30b3e67be Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 13:40:36 +0000 Subject: [PATCH 050/118] FPA: improved error messages for to_fp Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 15 +++++++++++++-- src/ast/float_decl_plugin.h | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index d775523ec..846d6ddb7 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -499,8 +499,19 @@ func_decl * float_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, pa 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 - NOT_IMPLEMENTED_YET(); + 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 * float_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_parameters, parameter const * parameters, diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index e4bf633a5..01daab8e3 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -239,6 +239,7 @@ public: 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) { return m_plugin->is_rm_value(n); } 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); @@ -254,8 +255,7 @@ public: 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_FLOAT_TO_FP); } - - app * mk_to_float(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_TO_FP, 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); } From 23aa614d55994518ac9079badd8027839edf0e99 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 13:44:29 +0000 Subject: [PATCH 051/118] FPA: New theory implementation with support for "hidden" variables, relevancy, and eq/diseq. Signed-off-by: Christoph M. Wintersteiger --- src/smt/theory_fpa.cpp | 638 ++++++++++++++++++++++------------------- src/smt/theory_fpa.h | 82 ++---- 2 files changed, 366 insertions(+), 354 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 354dc7596..ec22e3ebb 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -22,17 +22,46 @@ Revision History: #include"theory_bv.h" #include"smt_model_generator.h" -namespace smt { +namespace smt { + + class fpa_factory : public value_factory { + float_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); + } - class fpa_atom_trail : public trail { - bool_var m_var; public: - fpa_atom_trail(bool_var v) : m_var(v) {} - virtual ~fpa_atom_trail() {} + fpa_factory(ast_manager & m, family_id fid) : + value_factory(m, fid), + m_util(m) { + } + + virtual ~fpa_factory() {} + + virtual expr * get_some_value(sort * s) { NOT_IMPLEMENTED_YET(); } + virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { NOT_IMPLEMENTED_YET(); } + 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 fpa_conv_trail : public trail { + ast_manager & m; + obj_map & m_conversions; + expr * m_e; + public: + fpa_conv_trail(ast_manager & m, obj_map & c, expr * e) : m(m), m_conversions(c), m_e(e) {} + virtual ~fpa_conv_trail() {} virtual void undo(theory_fpa & th) { - theory_fpa::atom * a = th.get_bv2a(m_var); - a->~atom(); - th.erase_bv2a(m_var); + expr * v = m_conversions.find(m_e); + m_conversions.remove(m_e); + m.dec_ref(v); } }; @@ -43,15 +72,15 @@ namespace smt { if (m_const2bv.find(f, r)) { result = r; } - else { + else { sort * s = f->get_range(); - func_decl *w, *u; + func_decl_ref w(m), u(m); m_th.get_wrap(s, w, u); expr_ref bv(m); bv = m.mk_app(w, m.mk_const(f)); - unsigned bv_sz = m_th.m_converter.bu().get_bv_size(bv); - unsigned ebits = m_th.m_converter.fu().get_ebits(f->get_range()); - unsigned sbits = m_th.m_converter.fu().get_sbits(f->get_range()); + unsigned bv_sz = m_th.m_bv_util.get_bv_size(bv); + unsigned ebits = m_th.m_float_util.get_ebits(f->get_range()); + unsigned sbits = m_th.m_float_util.get_sbits(f->get_range()); SASSERT(bv_sz == ebits + sbits); m_th.m_converter.mk_triple(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), m_bv_util.mk_extract(sbits - 2, 0, bv), @@ -75,7 +104,7 @@ namespace smt { SASSERT(is_rm(f->get_range())); sort * s = f->get_range(); - func_decl *w, *u; + func_decl_ref w(m), u(m); m_th.get_wrap(s, w, u); result = m.mk_app(w, m.mk_const(f)); @@ -87,186 +116,134 @@ namespace smt { theory_fpa::theory_fpa(ast_manager & m) : theory(m.mk_family_id("float")), - m_converter(m, this), + m_converter(m, this), m_rw(m, m_converter, params_ref()), m_th_rw(m), - m_trail_stack(*this) + m_trail_stack(*this), + m_float_util(m_converter.fu()), + m_bv_util(m_converter.bu()), + m_arith_util(m_converter.au()) { } 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) { - TRACE("t_fpa", tout << "fpa_value_proc::mk_value for: " << mk_ismt2_pp(m_a, m_th.get_manager()) << "\n";); + SASSERT(values.size() == 3); ast_manager & m = m_th.get_manager(); - context & ctx = m_th.get_context(); - theory_id bv_id = m.mk_family_id("bv"); - theory_bv * th_bv = dynamic_cast(ctx.get_theory(bv_id)); - SASSERT(th_bv != 0); - - float_util & fu = m_th.m_converter.fu(); - bv_util & bu = m_th.m_converter.bu(); - mpf_manager & mpfm = fu.fm(); - unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); - unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); - - sort * s = m.get_sort(m_a); - unsigned ebits = fu.get_ebits(s); - unsigned sbits = fu.get_sbits(s); + TRACE("t_fpa", tout << "fpa_value_proc::mk_value for: [" << + mk_ismt2_pp(values[0], m) << " " << + mk_ismt2_pp(values[1], m) << " " << + mk_ismt2_pp(values[2], m) << "]" << std::endl;); + + mpf_manager & mpfm = m_fu.fm(); + unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); + unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); + + unsigned ebits = m_bu.get_bv_size(values[2]); + unsigned sbits = m_bu.get_bv_size(values[1]) + 1; + app * result; + + scoped_mpz sgn_z(mpzm), sig_z(mpzm), exp_z(mpzm); scoped_mpz bias(mpzm); mpzm.power(mpz(2), ebits - 1, bias); mpzm.dec(bias); - app * result; - float_op_kind k = (float_op_kind) to_app(m_a)->get_decl_kind(); - switch (k) - { - case -1: { - func_decl *w, *u; - m_th.get_wrap(s, w, u); - rational bv_val(0); - scoped_mpz sgn(mpzm), sig(mpzm), exp(bias); - app_ref bv_w(m); - bv_w = m.mk_app(w, m_a); + rational sgn_q(0), sig_q(0), exp_q(bias); + unsigned bv_sz; - if (!th_bv->get_fixed_value(bv_w, bv_val)) - result = fu.mk_nan(ebits, sbits); - else { - scoped_mpz all_bits(mpzm); - all_bits = bv_val.to_mpq().numerator(); - SASSERT(mpzm.is_one(bv_val.to_mpq().denominator())); - - mpzm.machine_div2k(all_bits, ebits + sbits - 1, sgn); + bool r; + r = m_bu.is_numeral(values[0], sgn_q, bv_sz); SASSERT(r); SASSERT(bv_sz == 1); + r = m_bu.is_numeral(values[1], sig_q, bv_sz); SASSERT(r); SASSERT(bv_sz == sbits - 1); + r = m_bu.is_numeral(values[2], exp_q, bv_sz); SASSERT(r); SASSERT(bv_sz == ebits); - scoped_mpz tmp_p(mpzm); - mpzm.power(mpz(2), ebits + sbits - 1, tmp_p); + TRACE("t_fpa", tout << "sgn=" << sgn_q.to_string() << " ; " << + "sig=" << sig_q.to_string() << " ; " << + "exp=" << exp_q.to_string() << std::endl;); - if (mpzm.is_one(sgn)) mpzm.sub(all_bits, tmp_p, all_bits); + rational exp_u = exp_q - rational(bias); + SASSERT(exp_u.is_int64()); - mpzm.machine_div2k(all_bits, sbits - 1, exp); - scoped_mpz exp_u(mpzm); - mpzm.sub(exp, bias, exp_u); - SASSERT(mpzm.is_int64(exp_u)); - - mpzm.power(mpz(2), sbits - 1, tmp_p); - mpzm.mod(all_bits, tmp_p, sig); + scoped_mpf f(mpfm); + scoped_mpq sig_mpq(mpqm); + sig_mpq = sig_q.to_mpq(); + mpfm.set(f, ebits, sbits, sgn_q.is_one(), sig_mpq.get().numerator(), exp_u.get_int64()); + result = m_fu.mk_value(f); - scoped_mpf f(mpfm); - mpfm.set(f, ebits, sbits, mpzm.is_one(sgn), sig, mpzm.get_int64(exp_u)); - result = fu.mk_value(f); - } - break; - } - case OP_FLOAT_FP: { - bool is_internalized = ctx.e_internalized(m_a); - if (is_internalized) { - SASSERT(m_a->get_num_args() == 3); - app_ref a_sgn(m), a_sig(m), a_exp(m); - a_sgn = to_app(m_a->get_arg(0)); - a_exp = to_app(m_a->get_arg(1)); - a_sig = to_app(m_a->get_arg(2)); - - scoped_mpz bias(mpzm); - mpzm.power(mpz(2), ebits - 1, bias); - mpzm.dec(bias); - - rational sgn(0), sig(0), exp(bias); - th_bv->get_fixed_value(a_sgn, sgn); - th_bv->get_fixed_value(a_sig, sig); - th_bv->get_fixed_value(a_exp, exp); - - TRACE("t_fpa", tout << "sgn=" << sgn.to_string() << " ; " << - "sig=" << sig.to_string() << " ; " << - "exp=" << exp.to_string() << std::endl;); - - rational exp_u = exp - rational(bias); - SASSERT(exp_u.is_int64()); - - scoped_mpf f(mpfm); - scoped_mpq sig_q(mpqm); - sig_q = sig.to_mpq(); - mpfm.set(f, ebits, sbits, sgn.is_one(), sig_q.get().numerator(), exp_u.get_int64()); - result = fu.mk_value(f); - } - else { - result = fu.mk_nan(ebits, sbits); - } - break; - } - default: - NOT_IMPLEMENTED_YET(); - } - - TRACE("t_fpa", tout << "fpa_value_proc::mk_value result: " << mk_ismt2_pp(result, m_th.get_manager()) << "\n";); + TRACE("t_fpa", tout << "fpa_value_proc::mk_value result: " << + 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) { - TRACE("t_fpa", tout << "fpa_rm_value_proc::mk_value for: " << mk_ismt2_pp(m_a, m_th.get_manager()) << "\n";); + 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(); - context & ctx = m_th.get_context(); - theory_id bv_id = m.mk_family_id("bv"); - theory_bv * th_bv = dynamic_cast(ctx.get_theory(bv_id)); + + TRACE("t_fpa", tout << "fpa_rm_value_proc::mk_value for: [" << + mk_ismt2_pp(values[0], m) << "]" << std::endl;); app * result = 0; - mpf_rounding_mode rm; - if (m_th.m_converter.fu().is_rm_value(m_a, rm)) { - result = m_a.get(); - } - else { - sort * s = m.get_sort(m_a); - func_decl *w, *u; - m_th.get_wrap(s, w, u); + sort * s = m.get_sort(values[0]); + unsigned bv_sz; - app_ref bv_w(m); - bv_w = m.mk_app(w, m_a); - - rational val(0); - if (ctx.e_internalized(bv_w)) - if (!th_bv->get_fixed_value(bv_w, val)) - val = rational(0); + 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(); - } + 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";); + TRACE("t_fpa", tout << "fpa_rm_value_proc::mk_value result: " << + mk_ismt2_pp(result, m_th.get_manager()) << "\n";); + return result; } - void theory_fpa::get_wrap(sort * s, func_decl *& wrap, func_decl *& unwrap) + void theory_fpa::get_wrap(sort * s, func_decl_ref & wrap, func_decl_ref & unwrap) { - if (!m_wraps.find(s, wrap) || !m_unwraps.find(s, unwrap)) { + func_decl *w, *u; + + if (!m_wraps.find(s, w) || !m_unwraps.find(s, u)) { SASSERT(!m_wraps.contains(s)); + SASSERT(!m_unwraps.contains(s)); ast_manager & m = get_manager(); + context & ctx = get_context(); sort * bv_srt = 0; if (m_converter.is_rm(s)) - bv_srt = m_converter.bu().mk_sort(3); + bv_srt = m_bv_util.mk_sort(3); else { - SASSERT(m_converter.is_float(s)); - unsigned ebits = m_converter.fu().get_ebits(s); - unsigned sbits = m_converter.fu().get_sbits(s); - bv_srt = m_converter.bu().mk_sort(ebits + sbits); + SASSERT(m_converter.is_float(s)); + unsigned ebits = m_float_util.get_ebits(s); + unsigned sbits = m_float_util.get_sbits(s); + bv_srt = m_bv_util.mk_sort(ebits + sbits); } - - wrap = m.mk_func_decl(get_family_id(), OP_FLOAT_INTERNAL_BVWRAP, 0, 0, 1, &s, bv_srt); - unwrap = m.mk_func_decl(get_family_id(), OP_FLOAT_INTERNAL_BVUNWRAP, 0, 0, 1, &bv_srt, s); - m_wraps.insert(s, wrap); - m_unwraps.insert(s, unwrap); - get_context().push_trail(insert_obj_map(m_wraps, s)); - get_context().push_trail(insert_obj_map(m_unwraps, s)); + + w = m.mk_func_decl(get_family_id(), OP_FLOAT_INTERNAL_BVWRAP, 0, 0, 1, &s, bv_srt); + u = m.mk_func_decl(get_family_id(), OP_FLOAT_INTERNAL_BVUNWRAP, 0, 0, 1, &bv_srt, s); + m_wraps.insert(s, w); + m_unwraps.insert(s, u); + m.inc_ref(w); + m.inc_ref(u); } + + wrap = w; + unwrap = u; } expr_ref theory_fpa::convert_atom(expr * e) { @@ -274,52 +251,91 @@ namespace smt { expr_ref res(m); proof_ref pr(m); m_rw(e, res); + m_th_rw(res, res); - TRACE("t_fpa", tout << "converted atom:" << std::endl; - tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << - mk_ismt2_pp(res, m) << std::endl;); + TRACE("t_fpa_detail", tout << "converted atom:" << std::endl; + tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << + mk_ismt2_pp(res, m) << std::endl;); + + 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 res(m); proof_ref pr(m); m_rw(e, res); SASSERT(is_app(res)); - if (m_converter.fu().is_rm(e)) { - SASSERT(is_sort_of(m.get_sort(res), m_converter.bu().get_family_id(), BV_SORT)); - SASSERT(m_converter.bu().get_bv_size(res) == 3); + if (m_float_util.is_rm(e)) { + SASSERT(is_sort_of(m.get_sort(res), m_bv_util.get_family_id(), BV_SORT)); + SASSERT(m_bv_util.get_bv_size(res) == 3); + ctx.internalize(res, false); } else { SASSERT(to_app(res)->get_family_id() == get_family_id()); decl_kind k = to_app(res)->get_decl_kind(); if (k == OP_FLOAT_TO_FP) { SASSERT(to_app(res)->get_num_args() == 3); - SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(0)), m_converter.bu().get_family_id(), BV_SORT)); - SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(1)), m_converter.bu().get_family_id(), BV_SORT)); - SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(2)), m_converter.bu().get_family_id(), BV_SORT)); + SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(0)), m_bv_util.get_family_id(), BV_SORT)); + SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(1)), m_bv_util.get_family_id(), BV_SORT)); + SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(2)), m_bv_util.get_family_id(), BV_SORT)); expr *sgn, *sig, *exp; expr_ref s_sgn(m), s_sig(m), s_exp(m); m_converter.split_triple(res, sgn, sig, exp); m_th_rw(sgn, s_sgn); m_th_rw(sig, s_sig); - m_th_rw(exp, s_exp); - + m_th_rw(exp, s_exp); + m_converter.mk_triple(s_sgn, s_sig, s_exp, res); } else { SASSERT(is_sort_of(m.get_sort(e), get_family_id(), ROUNDING_MODE_SORT)); - SASSERT(is_sort_of(m.get_sort(res), m_converter.bu().get_family_id(), BV_SORT)); + SASSERT(is_sort_of(m.get_sort(res), m_bv_util.get_family_id(), BV_SORT)); } } - TRACE("t_fpa", tout << "converted term:" << std::endl; - tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << - mk_ismt2_pp(res, m) << std::endl;); + TRACE("t_fpa_detail", tout << "converted term:" << std::endl; + tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << + mk_ismt2_pp(res, m) << std::endl;); + 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.is_bool(e)) + res = convert_atom(e); + else if (m_float_util.is_float(e) || m_float_util.is_rm(e)) + res = convert_term(e); + else + UNREACHABLE(); + + TRACE("t_fpa_detail", tout << "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(fpa_conv_trail(m, m_conversions, e)); + } + return res; } @@ -340,14 +356,14 @@ namespace smt { res = m.mk_and(res, t); } m_converter.m_extra_assertions.reset(); - - TRACE("t_fpa", if (!m.is_true(res)) tout << "side condition: " << mk_ismt2_pp(res, m) << "\n";); + + 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) { + void theory_fpa::assert_cnstr(expr * e) { + TRACE("t_fpa_detail", tout << "asserting " << mk_ismt2_pp(e, get_manager()) << "\n";); if (get_manager().is_true(e)) return; - TRACE("t_fpa", tout << "asserting " << mk_ismt2_pp(e, get_manager()) << "\n";); context& ctx = get_context(); ctx.internalize(e, false); literal lit(ctx.get_literal(e)); @@ -359,7 +375,6 @@ namespace smt { context & ctx = get_context(); theory_var v = mk_var(n); ctx.attach_th_var(n, this, v); - m_tvars.push_back(v); TRACE("t_fpa", tout << "new theory var: " << mk_ismt2_pp(n->get_owner(), get_manager()) << " := " << v << "\n";); } @@ -381,7 +396,9 @@ namespace smt { ctx.set_var_theory(l.var(), get_id()); expr_ref bv_atom(m); - bv_atom = convert_atom(atom); + bv_atom = convert(atom); + TRACE("t_fpa_detail", tout << "converted: " << mk_ismt2_pp(bv_atom, get_manager()) << "\n";); + SASSERT(bv_atom.get()->get_kind() == AST_APP); bv_atom = m.mk_and(bv_atom, mk_side_conditions()); expr_ref atom_iff(m); @@ -390,13 +407,13 @@ namespace smt { } bool theory_fpa::internalize_term(app * term) { - TRACE("t_fpa_detail", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";); - SASSERT(term->get_family_id() == get_family_id()); - SASSERT(!get_context().e_internalized(term)); - ast_manager & m = get_manager(); context & ctx = get_context(); + TRACE("t_fpa_detail", 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); @@ -407,8 +424,7 @@ namespace smt { if (is_attached_to_var(e)) return false; - attach_new_th_var(e); - TRACE("t_fpa", tout << "internalized? " << (ctx.e_internalized(term)?"yes":"no") << std::endl;); + attach_new_th_var(e); return true; } @@ -417,22 +433,25 @@ namespace smt { 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()); - ast_manager & m = get_manager(); + ast_manager & m = get_manager(); if (!is_attached_to_var(n)) attach_new_th_var(n); - app * owner = n->get_owner(); - sort * owner_sort = m.get_sort(owner); - if (m_converter.is_rm(owner_sort)) { - bv_util & bu = m_converter.bu(); - func_decl *wrap, *unwrap; + app_ref owner(m); + sort_ref owner_sort(m); + owner = n->get_owner(); + owner_sort = m.get_sort(owner); + + if (m_float_util.is_rm(owner_sort)) { + func_decl_ref wrap(m), unwrap(m); get_wrap(owner_sort, wrap, unwrap); if (owner->get_decl() != unwrap) - { - expr_ref converted(m), t(m); - m_rw(owner, converted); - t = bu.mk_ule(converted, bu.mk_numeral(4, 3)); + { + expr_ref converted(m), t(m), limit(m); + converted = convert(owner); + limit = m_bv_util.mk_numeral(4, 3); + t = m_bv_util.mk_ule(converted, limit); assert_cnstr(t); } } @@ -446,41 +465,45 @@ namespace smt { mk_ismt2_pp(get_enode(y)->get_owner(), m) << std::endl; ); context & ctx = get_context(); - float_util & fu = m_converter.fu(); - bv_util & bu = m_converter.bu(); + float_util & fu = m_float_util; + bv_util & bu = m_bv_util; mpf_manager & mpfm = fu.fm(); app * xe = get_enode(x)->get_owner(); - app * ye = get_enode(y)->get_owner(); + app * ye = get_enode(y)->get_owner(); + + if (m_bv_util.is_bv(xe) && m_bv_util.is_bv(ye)) + { + SASSERT(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 (fu.is_float(xe) && fu.is_float(ye)) { - expr_ref xc(m), yc(m); - xc = convert_term(xe); - yc = convert_term(ye); - expr *x_sgn, *x_sig, *x_exp; m_converter.split_triple(xc, x_sgn, x_sig, x_exp); expr *y_sgn, *y_sig, *y_exp; m_converter.split_triple(yc, y_sgn, y_sig, y_exp); - expr_ref c(m); c = m.mk_and(m.mk_eq(x_sgn, y_sgn), m.mk_eq(x_sig, y_sig), - m.mk_eq(x_exp, y_exp)); - assert_cnstr(c); - assert_cnstr(mk_side_conditions()); + m.mk_eq(x_exp, y_exp)); } - else if (fu.is_rm(xe) && fu.is_rm(ye)) { - expr_ref xc(m), yc(m); - xc = convert_term(xe); - yc = convert_term(ye); - expr_ref c(m); + else if (fu.is_rm(xe) && fu.is_rm(ye)) c = m.mk_eq(xc, yc); - assert_cnstr(c); - assert_cnstr(mk_side_conditions()); - } - + else + UNREACHABLE(); + + // assert_cnstr(m.mk_iff(m.mk_eq(xe, ye), c)); + assert_cnstr(c); + assert_cnstr(mk_side_conditions()); + return; } @@ -492,57 +515,55 @@ namespace smt { mk_ismt2_pp(get_enode(y)->get_owner(), m) << std::endl;); context & ctx = get_context(); - float_util & fu = m_converter.fu(); - bv_util & bu = m_converter.bu(); - mpf_manager & mpfm = fu.fm(); + mpf_manager & mpfm = m_float_util.fm(); app * xe = get_enode(x)->get_owner(); app * ye = get_enode(y)->get_owner(); - if (fu.is_float(xe) && fu.is_float(ye)) + if (m_bv_util.is_bv(xe) && m_bv_util.is_bv(ye)) { - expr_ref xc(m), yc(m); - xc = convert_term(xe); - yc = convert_term(ye); + SASSERT(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_float_util.is_float(xe) && m_float_util.is_float(ye)) + { expr *x_sgn, *x_sig, *x_exp; m_converter.split_triple(xc, x_sgn, x_sig, x_exp); expr *y_sgn, *y_sig, *y_exp; m_converter.split_triple(yc, y_sgn, y_sig, y_exp); - - expr_ref c(m); + c = m.mk_or(m.mk_not(m.mk_eq(x_sgn, y_sgn)), m.mk_not(m.mk_eq(x_sig, y_sig)), m.mk_not(m.mk_eq(x_exp, y_exp))); - assert_cnstr(c); - assert_cnstr(mk_side_conditions()); } - else if (fu.is_rm(xe) && fu.is_rm(ye)) { - expr_ref xc(m), yc(m); - xc = convert_term(xe); - yc = convert_term(ye); - expr_ref c(m); + else if (m_float_util.is_rm(xe) && m_float_util.is_rm(ye)) c = m.mk_not(m.mk_eq(xc, yc)); - assert_cnstr(c); - assert_cnstr(mk_side_conditions()); - } + else + UNREACHABLE(); + + // assert_cnstr(m.mk_iff(m.mk_not(m.mk_eq(xe, ye)), c)); + assert_cnstr(c); + assert_cnstr(mk_side_conditions()); return; } void theory_fpa::push_scope_eh() { theory::push_scope_eh(); - m_trail_stack.push_scope(); + m_trail_stack.push_scope(); } - void theory_fpa::pop_scope_eh(unsigned num_scopes) { - TRACE("t_fpa", tout << num_scopes << "\n";); + void theory_fpa::pop_scope_eh(unsigned num_scopes) { m_trail_stack.pop_scope(num_scopes); - unsigned num_old_vars = get_old_num_vars(num_scopes); - for (unsigned i = num_old_vars; i < get_num_vars(); i++) { - // m_trans_map.erase(get_enode(m_tvars[i])->get_owner()); - } - m_tvars.shrink(num_old_vars); + 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); } @@ -554,57 +575,68 @@ namespace smt { TRACE("t_fpa", tout << "assign_eh for: " << v << " (" << is_true << "):\n" << mk_ismt2_pp(e, m) << "\n";); expr_ref converted(m); - m_rw(e, converted); + converted = convert(e); converted = m.mk_and(converted, mk_side_conditions()); if (!is_true) converted = m.mk_not(converted); assert_cnstr(converted); } void theory_fpa::relevant_eh(app * n) { - TRACE("t_fpa", tout << "relevant_eh for: " << mk_ismt2_pp(n, get_manager()) << "\n";); - - NOT_IMPLEMENTED_YET(); - ast_manager & m = get_manager(); + TRACE("t_fpa", tout << "relevant_eh for: " << mk_ismt2_pp(n, m) << "\n";); - if (m.is_bool(n)) - return; + mpf_manager & mpfm = m_float_util.fm(); + unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); - float_util & fu = m_converter.fu(); - bv_util & bu = m_converter.bu(); - mpf_manager & mpfm = fu.fm(); + if (m_float_util.is_float(n) || m_float_util.is_rm(n)) { + sort * s = m.get_sort(n); + func_decl_ref wrap(m), unwrap(m); + get_wrap(s, wrap, unwrap); - if (bu.is_bv(n)) - return; - - sort * s = m.get_sort(n); - func_decl *wrap, *unwrap; - get_wrap(s, wrap, unwrap); - - if (n->get_decl() != unwrap) { - expr * wrapped = m.mk_app(wrap, n); - mpf_rounding_mode rm; - scoped_mpf val(mpfm); - if (fu.is_rm_value(n, rm)) - assert_cnstr(m.mk_eq(wrapped, bu.mk_numeral(rm, 3))); - else if (fu.is_value(n, val)) { - unsigned sz = val.get().get_ebits() + val.get().get_sbits(); - scoped_mpq q(fu.fm().mpq_manager()); - mpfm.to_rational(val, q); - assert_cnstr(m.mk_eq(wrapped, bu.mk_numeral(rational(q), sz))); + if (n->get_decl() != unwrap) { + expr_ref wrapped(m), c(m); + wrapped = m.mk_app(wrap, n); + mpf_rounding_mode rm; + scoped_mpf val(mpfm); + if (m_float_util.is_rm_value(n, rm)) { + c = m.mk_eq(wrapped, m_bv_util.mk_numeral(rm, 3)); + c = m.mk_and(c, mk_side_conditions()); + assert_cnstr(c); + } + else if (m_float_util.is_value(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); + c = m.mk_eq(wrapped, m_bv_util.mk_concat( + m_bv_util.mk_concat(bv_val_a->get_arg(0), bv_val_a->get_arg(1)), + bv_val_a->get_arg(2))); + c = m.mk_and(c, mk_side_conditions()); + assert_cnstr(c); + } + else { + c = m.mk_eq(m.mk_app(unwrap, wrapped), n); + c = m.mk_and(c, mk_side_conditions()); + assert_cnstr(c); + } } - else - assert_cnstr(m.mk_eq(m.mk_app(unwrap, wrapped), n)); } } void theory_fpa::reset_eh() { - TRACE("t_fpa", tout << "reset_eh for: " << "\n";); + TRACE("t_fpa", tout << "reset_eh\n";); pop_scope_eh(m_trail_stack.get_num_scopes()); + m_converter.reset(); m_rw.reset(); - m_bool_var2atom.reset(); - m_temporaries.reset(); - m_tvars.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(); } @@ -615,28 +647,54 @@ namespace smt { TRACE("t_fpa", display(tout);); } + void theory_fpa::add_value_dep(fpa_value_proc * vp, expr * e) { + SASSERT(m_bv_util.is_bv(e)); + ast_manager & m = get_manager(); + context & ctx = get_context(); + if (ctx.e_internalized(e)) + vp->add_dependency(ctx.get_enode(e)); + else { + expr_ref n(m); + n = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(e)); + if (!ctx.e_internalized(n)) + ctx.internalize(n, false); + vp->add_dependency(ctx.get_enode(n)); + } + } + 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()) << "\n";); + TRACE("t_fpa", tout << "mk_value for: " << mk_ismt2_pp(n->get_owner(), get_manager()) << "\n";); ast_manager & m = get_manager(); - float_util & fu = m_converter.fu(); + context & ctx = get_context(); + app * owner = n->get_owner(); - expr * owner = n->get_owner(); - sort * o_srt = m.get_sort(owner); + app_ref c_a(m); + c_a = to_app(convert(owner)); + SASSERT(ctx.e_internalized(owner)); - mpf_rounding_mode rm; + TRACE("t_fpa", tout << "converted = " << mk_ismt2_pp(c_a, get_manager()) << "\n";); - if (fu.is_rm_value(n->get_owner(), rm)) - return alloc(expr_wrapper_proc, n->get_owner()); - else if (fu.is_value(n->get_owner())) - return alloc(expr_wrapper_proc, n->get_owner()); - else if (fu.is_rm(owner)) - return alloc(fpa_rm_value_proc, this, app_ref(to_app(owner), m)); - else if (fu.is_float(owner)) - return alloc(fpa_value_proc, this, app_ref(to_app(owner), m)); - - UNREACHABLE(); - return 0; + model_value_proc * res = 0; + + if (m_float_util.is_rm(owner)) { + fpa_rm_value_proc * vp = alloc(fpa_rm_value_proc, this); + add_value_dep(vp, c_a); + res = vp; + } + else if (m_float_util.is_float(owner)) { + fpa_value_proc * vp = alloc(fpa_value_proc, this); + expr_ref bv_sgn(m), bv_sig(m), bv_exp(m); + m_converter.split_triple(c_a, bv_sgn, bv_sig, bv_exp); + add_value_dep(vp, bv_sgn); + add_value_dep(vp, bv_sig); + add_value_dep(vp, bv_exp); + res = vp; + } + else + UNREACHABLE(); + + return res; } void theory_fpa::finalize_model(model_generator & mg) {} @@ -649,8 +707,10 @@ namespace smt { out << "theory variables:" << std::endl; ptr_vector::const_iterator it = ctx.begin_enodes(); ptr_vector::const_iterator end = ctx.end_enodes(); - for (; it != end; it++) - out << (*it)->get_th_var(get_family_id()) << " -> " << - mk_ismt2_pp((*it)->get_owner(), m) << std::endl; + 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; + } } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 0c472be33..bd2ea29f8 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -29,39 +29,10 @@ Revision History: namespace smt { - class fpa_factory : public value_factory { - float_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_factory(ast_manager & m, family_id fid) : - value_factory(m, fid), - m_util(m) { - } - - virtual ~fpa_factory() {} - - virtual expr * get_some_value(sort * s) { NOT_IMPLEMENTED_YET(); } - virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { NOT_IMPLEMENTED_YET(); } - 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 fpa_factory; class theory_fpa : public theory { - class th_trail_stack : public trail_stack { - public: - th_trail_stack(theory_fpa & th) : trail_stack(th) {} - virtual ~th_trail_stack() {} - }; + typedef trail_stack th_trail_stack; class fpa2bv_converter_wrapped : public fpa2bv_converter { public: @@ -76,11 +47,13 @@ namespace smt { class fpa_value_proc : public model_value_proc { protected: - theory_fpa & m_th; - app_ref m_a; + theory_fpa & m_th; + float_util & m_fu; + bv_util & m_bu; svector m_dependencies; public: - fpa_value_proc(theory_fpa * th, app_ref & a) : m_th(*th), m_a(a) {} + fpa_value_proc(theory_fpa * th) : + m_th(*th),m_fu(th->m_float_util),m_bu(th->m_bv_util) {} void add_dependency(enode * n) { m_dependencies.push_back(model_value_dependency(n)); } virtual ~fpa_value_proc() {} virtual void get_dependencies(buffer & result) { @@ -89,50 +62,27 @@ namespace smt { virtual app * mk_value(model_generator & mg, ptr_vector & values); }; - class fpa_rm_value_proc : public fpa_value_proc { - float_util & m_fu; - bv_util & m_bu; + class fpa_rm_value_proc : public fpa_value_proc { public: - fpa_rm_value_proc(theory_fpa * th, app_ref & a) : - fpa_value_proc(th, a), - m_fu(th->m_converter.fu()), - m_bu(th->m_converter.bu()) {} + fpa_rm_value_proc(theory_fpa * th) : + fpa_value_proc(th) {} void add_dependency(enode * n) { fpa_value_proc::add_dependency(n); } virtual ~fpa_rm_value_proc() {} virtual app * mk_value(model_generator & mg, ptr_vector & values); }; - public: - class atom { - public: - virtual ~atom() {} - }; - - struct pred_atom : public atom { - literal m_var; - literal m_def; - pred_atom(literal v, literal d) : m_var(v), m_def(d) {} - virtual ~pred_atom() {} - }; - - typedef ptr_vector bool_var2atom; - void insert_bv2a(bool_var bv, pred_atom * a) { m_bool_var2atom.setx(bv, a, 0); } - void erase_bv2a(bool_var bv) { m_bool_var2atom[bv] = 0; } - pred_atom * get_bv2a(bool_var bv) const { return m_bool_var2atom.get(bv, 0); } - region & get_region() { return m_trail_stack.get_region(); } - protected: fpa2bv_converter_wrapped m_converter; fpa2bv_rewriter m_rw; th_rewriter m_th_rw; th_trail_stack m_trail_stack; - bool_var2atom m_bool_var2atom; - enode_vector m_temporaries; - vector m_tvars; fpa_factory * m_factory; + float_util & m_float_util; + bv_util & m_bv_util; + arith_util & m_arith_util; obj_map m_wraps; obj_map m_unwraps; - float_decl_plugin m_flt_plugin; + obj_map m_conversions; virtual final_check_status final_check_eh() { return FC_DONE; } virtual bool internalize_atom(app * atom, bool gate_ctx); @@ -161,14 +111,16 @@ namespace smt { protected: expr_ref mk_side_conditions(); + expr_ref convert(expr * e); expr_ref convert_atom(expr * e); expr_ref convert_term(expr * e); - void get_wrap(sort * s, func_decl *& wrap, func_decl *& unwrap); + void get_wrap(sort * s, func_decl_ref & wrap, func_decl_ref & unwrap); void add_trail(ast * a); void mk_bv_eq(expr * x, expr * y); void attach_new_th_var(enode * n); void assert_cnstr(expr * e); + void add_value_dep(fpa_value_proc * vp, expr * e); }; }; From 1aae53f48c9d82fa3173f9a33054e8d7b5896830 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 15:26:41 +0000 Subject: [PATCH 052/118] FPA: comment fixes Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 846d6ddb7..bfc038cf7 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -846,11 +846,11 @@ bool float_decl_plugin::is_unique_value(app* e) const { case OP_FLOAT_RM_TOWARD_ZERO: return true; case OP_FLOAT_PLUS_INF: /* No; +oo == fp(#b0 #b11 #b00) */ - case OP_FLOAT_MINUS_INF: /* Nol -oo == fp #b1 #b11 #b00) */ + case OP_FLOAT_MINUS_INF: /* No; -oo == fp #b1 #b11 #b00) */ case OP_FLOAT_PLUS_ZERO: /* No; +zero == fp #b0 #b00 #b000) */ case OP_FLOAT_MINUS_ZERO: /* No; -zero == fp #b1 #b00 #b000) */ case OP_FLOAT_NAN: /* No; NaN == (fp #b0 #b111111 #b0000001) */ - case OP_FLOAT_VALUE: /* above */ + case OP_FLOAT_VALUE: /* see NaN */ return false; case OP_FLOAT_FP: return m_manager->is_unique_value(e->get_arg(0)) && From 4d1f71775d1144fb7a2af4f548a8e1c9bc74cd03 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 15:26:52 +0000 Subject: [PATCH 053/118] FPA: added to_fp_unsigned Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 140 +++++++++++++++++++++++++++++-- src/ast/fpa/fpa2bv_rewriter.h | 3 +- 2 files changed, 134 insertions(+), 9 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 0de267d2f..4d2826681 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2171,11 +2171,6 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const unsigned bv_sz = m_bv_util.get_bv_size(x); SASSERT(m_bv_util.get_bv_size(rm) == 3); - //if (bv_sz < f_sz) { - // x = m_bv_util.mk_zero_extend(f_sz - bv_sz, x); - // bv_sz = f_sz; - //} - 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); @@ -2245,12 +2240,14 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const 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. + 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 @@ -2266,7 +2263,7 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const 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); + dbg_decouple("fpa2bv_to_fp_signed_exp_too_large", exp_too_large); expr_ref sgn(m), sig(m), exp(m); sgn = is_neg_bit; @@ -2290,7 +2287,134 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con TRACE("fpa2bv_to_fp_unsigned", for (unsigned i = 0; i < num; i++) tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); - NOT_IMPLEMENTED_YET(); + // 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) { diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index 17ee924ad..42fd7a7fe 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -144,7 +144,8 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { 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_FLOAT_TO_FP: m_conv.mk_to_fp(f, num, args, result); return BR_DONE; + case OP_FLOAT_TO_FP: m_conv.mk_to_fp(f, num, args, result); return BR_DONE; + case OP_FLOAT_TO_FP_UNSIGNED: m_conv.mk_to_fp_unsigned(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; From 12aaa0610b5dc064e60f783a00a8af2525e91b1a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 15:27:40 +0000 Subject: [PATCH 054/118] FPA: added get_some_value/s for FP models Signed-off-by: Christoph M. Wintersteiger --- src/smt/theory_fpa.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index ec22e3ebb..f05bca4a1 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -41,8 +41,23 @@ namespace smt { virtual ~fpa_factory() {} - virtual expr * get_some_value(sort * s) { NOT_IMPLEMENTED_YET(); } - virtual bool get_some_values(sort * s, expr_ref & v1, expr_ref & v2) { NOT_IMPLEMENTED_YET(); } + 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 */ } From 96c8bd7e91ac9952612e38e17b150f52ba174f76 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 17:57:21 +0000 Subject: [PATCH 055/118] MPF conversion bugfix Signed-off-by: Christoph M. Wintersteiger --- src/util/mpf.cpp | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index ac2eb3096..405f34c9d 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -218,39 +218,24 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode o.exponent--; } - m_mpz_manager.set(o.significand, 0); - // o.exponent += sbits ; - + 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) + // (and v != 0.0) for (unsigned i = 0; i < sbits + 3 ; i++) { - m_mpz_manager.mul(o.significand, mpz(2), o.significand); - if (m_mpq_manager.ge(v, mpq(1))) - m_mpz_manager.add(o.significand, mpz(1), o.significand); - m_mpq_manager.sub(v, mpq(1), v); // v := v - 1.0 + 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 - } - - // Sticky - // m_mpz_manager.mul(o.significand, mpz(2), o.significand); - /*if (!m_mpq_manager.is_zero(v)) - m_mpz_manager.add(o.significand, mpz(1), o.significand);*/ + } - // bias? - // o.exponent += m_mpz_manager.get_int64(m_powers2.m1(ebits - 1, false)); - - // mpq pow; - // m_mpq_manager.power(mpq(2), sbits + 3, pow); - // m_mpq_manager.div(o.significand, pow, o.significand); - // SASSERT(m_mpz_manager.ge(o.significand, mpq(1.0))); - // SASSERT(m_mpz_manager.lt(o.significand, mpq(2.0))); - - TRACE("mpf_dbg", tout << "sig=" << m_mpz_manager.to_string(o.significand) << " exp=" << o.exponent << - " sticky=" << (!m_mpq_manager.is_zero(v)) << std::endl;); + TRACE("mpf_dbg", tout << "rnd sig=" << m_mpz_manager.to_string(o.significand) << + " exp=" << o.exponent << std::endl;); round(rm, o); } From 621be0f47f37588c27d546916a9a3afb448171a4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 18:01:18 +0000 Subject: [PATCH 056/118] FPA: Added fp.to_ubv Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 8 +-- src/ast/fpa/fpa2bv_converter.cpp | 112 +++++++++++++++++++++++++++---- 2 files changed, 103 insertions(+), 17 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index bfc038cf7..a861865f5 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -562,9 +562,9 @@ func_decl * float_decl_plugin::mk_to_ubv(decl_kind k, unsigned num_parameters, p 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()) + 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])) + 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"); @@ -573,7 +573,7 @@ func_decl * float_decl_plugin::mk_to_ubv(decl_kind k, unsigned num_parameters, p 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)); + return m_manager->mk_func_decl(name, arity, domain, bvs, func_decl_info(m_family_id, k, num_parameters, parameters)); } func_decl * float_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -594,7 +594,7 @@ func_decl * float_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, p 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)); + return m_manager->mk_func_decl(name, arity, domain, bvs, func_decl_info(m_family_id, k, num_parameters, parameters)); } func_decl * float_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, parameter const * parameters, diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 4d2826681..88e738041 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1865,7 +1865,6 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args 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 && @@ -2457,27 +2456,114 @@ void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, e } void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 2); + 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()); - - //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(); + 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]; - - //expr * sgn, *s, *e; - //split_triple(x, sgn, s, e); + expr * rm = args[0]; + expr * x = args[1]; + sort * xs = m.get_sort(x); + sort * bv_srt = f->get_range(); - NOT_IMPLEMENTED_YET(); + dbg_decouple("fpa2bv_to_ubv_x", expr_ref(x, m)); + + unsigned ebits = m_util.get_ebits(xs); + unsigned sbits = m_util.get_sbits(xs); + unsigned bv_sz = (unsigned)f->get_parameter(0).get_int(); + + 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) -> undefined + 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_fresh_const(0, 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); + + // last number that's representable + expr_ref last_valid_bv(m); + last_valid_bv = m_bv_util.mk_numeral(-1, bv_sz); // == 1.0 * 2^bv_sz - 1.0 + + // first invalid bv + mpz const & first_invalid_bv = m_util.fm().m_powers2(bv_sz); + + unsigned sig_sz = m_bv_util.get_bv_size(sig); + SASSERT(sig_sz == sbits); + + expr_ref shift(m); + if (sig_sz < bv_sz) { + sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, bv_sz - sig_sz)); + shift = m_bv_util.mk_bv_sub(m_bv_util.mk_bv_sub(m_bv_util.mk_sign_extend(2, exp), + m_bv_util.mk_zero_extend(2, lz)), + m_bv_util.mk_numeral(bv_sz-1, ebits + 2)); + } + SASSERT(m_bv_util.get_bv_size(shift) == ebits + 2); + SASSERT(m_bv_util.get_bv_size(sig) >= bv_sz); + dbg_decouple("fpa2bv_to_ubv_shift", shift); + + 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), shift_abs(m); + shift_abs = m_bv_util.mk_bv_neg(shift); + SASSERT(m_bv_util.get_bv_size(shift_abs) == ebits+2); + SASSERT(bv_sz > (ebits + 2)); + shift_abs = m_bv_util.mk_zero_extend(bv_sz - ebits - 2, shift_abs); + + shifted_sig = m_bv_util.mk_bv_lshr(sig, shift_abs); + dbg_decouple("fpa2bv_to_ubv_shift_abs", shift_abs); + dbg_decouple("fpa2bv_to_ubv_shifted_sig", shifted_sig); + + expr_ref rounded(m); + rounded = shifted_sig; // TODO. + + result = m.mk_ite(c_in_limits, rounded, mk_fresh_const(0, 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) { - SASSERT(num == 2); + 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])); //unsigned ebits = m_util.get_ebits(f->get_range()); //unsigned sbits = m_util.get_sbits(f->get_range()); From 05121e25d45319c22d976bacdfb82502c9a89333 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 28 Dec 2014 19:28:48 +0000 Subject: [PATCH 057/118] FPA theory support for conversion functions Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 64 +++++++++++++++++++++++++++++++- src/ast/float_decl_plugin.h | 24 +++++++++--- src/ast/fpa/fpa2bv_converter.cpp | 12 ++++-- src/ast/fpa/fpa2bv_converter.h | 4 ++ src/smt/theory_fpa.cpp | 22 ++++++----- 5 files changed, 107 insertions(+), 19 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index a861865f5..b019c7359 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -655,6 +655,45 @@ func_decl * float_decl_plugin::mk_internal_bv_unwrap(decl_kind k, unsigned num_p return m_manager->mk_func_decl(symbol("bv_unwrap"), 1, domain, range, func_decl_info(m_family_id, k, num_parameters, parameters)); } +func_decl * float_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 * float_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 (!is_sort_of(domain[0], m_bv_fid, BV_SORT)) + m_manager->raise_exception("sort mismatch, expected argument of bitvector sort"); + if (!is_sort_of(range, m_bv_fid, BV_SORT)) + m_manager->raise_exception("sort mismatch, expected range of FloatingPoint sort"); + + 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 * float_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 * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { @@ -726,6 +765,12 @@ func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); case OP_FLOAT_INTERNAL_BVUNWRAP: return mk_internal_bv_unwrap(k, num_parameters, parameters, arity, domain, range); + case OP_FLOAT_INTERNAL_TO_UBV_UNSPECIFIED: + return mk_internal_to_ubv_unspecified(k, num_parameters, parameters, arity, domain, range); + case OP_FLOAT_INTERNAL_TO_SBV_UNSPECIFIED: + return mk_internal_to_sbv_unspecified(k, num_parameters, parameters, arity, domain, range); + case OP_FLOAT_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; @@ -864,7 +909,8 @@ bool float_decl_plugin::is_unique_value(app* e) const { float_util::float_util(ast_manager & m): m_manager(m), m_fid(m.mk_family_id("float")), - m_a_util(m) { + m_a_util(m), + m_bv_util(m) { m_plugin = static_cast(m.get_plugin(m_fid)); } @@ -916,3 +962,19 @@ app * float_util::mk_nzero(unsigned ebits, unsigned sbits) { return mk_value(v); } +app * float_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_FLOAT_INTERNAL_TO_UBV_UNSPECIFIED, 1, ps, 0, 0, range); +} + +app * float_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_FLOAT_INTERNAL_TO_SBV_UNSPECIFIED, 1, ps, 0, 0, range); +} + +app * float_util::mk_internal_to_real_unspecified() { + sort * range = m_a_util.mk_real(); + return m().mk_app(get_family_id(), OP_FLOAT_INTERNAL_TO_REAL_UNSPECIFIED, 0, 0, 0, 0, range); +} \ No newline at end of file diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 01daab8e3..3403665a9 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -47,7 +47,7 @@ enum float_op_kind { OP_FLOAT_NAN, OP_FLOAT_PLUS_ZERO, OP_FLOAT_MINUS_ZERO, - + OP_FLOAT_ADD, OP_FLOAT_SUB, OP_FLOAT_NEG, @@ -70,7 +70,7 @@ enum float_op_kind { OP_FLOAT_IS_INF, OP_FLOAT_IS_ZERO, OP_FLOAT_IS_NORMAL, - OP_FLOAT_IS_SUBNORMAL, + OP_FLOAT_IS_SUBNORMAL, OP_FLOAT_IS_PZERO, OP_FLOAT_IS_NZERO, OP_FLOAT_IS_NEGATIVE, @@ -85,10 +85,13 @@ enum float_op_kind { /* Extensions */ OP_FLOAT_TO_IEEE_BV, - + /* Internal use only */ OP_FLOAT_INTERNAL_BVWRAP, OP_FLOAT_INTERNAL_BVUNWRAP, + OP_FLOAT_INTERNAL_TO_UBV_UNSPECIFIED, + OP_FLOAT_INTERNAL_TO_SBV_UNSPECIFIED, + OP_FLOAT_INTERNAL_TO_REAL_UNSPECIFIED, LAST_FLOAT_OP }; @@ -155,9 +158,15 @@ class float_decl_plugin : public decl_plugin { 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); + 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); + 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); @@ -203,6 +212,7 @@ class float_util { float_decl_plugin * m_plugin; family_id m_fid; arith_util m_a_util; + bv_util m_bv_util; public: float_util(ast_manager & m); ~float_util(); @@ -292,6 +302,10 @@ public: 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); } + + app * mk_internal_to_ubv_unspecified(unsigned width); + app * mk_internal_to_sbv_unspecified(unsigned width); + app * mk_internal_to_real_unspecified(); }; #endif diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 88e738041..bd8240b31 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2487,10 +2487,13 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg mk_is_neg(x, x_is_neg); mk_is_nzero(x, x_is_nzero); + expr_ref undef(m); + undef = m_util.mk_internal_to_ubv_unspecified(bv_sz); + // NaN, Inf, or negative (except -0) -> undefined 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_fresh_const(0, bv_sz); + v1 = undef; dbg_decouple("fpa2bv_to_ubv_c1", c1); // +-Zero -> 0 @@ -2546,9 +2549,10 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg dbg_decouple("fpa2bv_to_ubv_shifted_sig", shifted_sig); expr_ref rounded(m); - rounded = shifted_sig; // TODO. + // TODO: Rounding. + rounded = shifted_sig; - result = m.mk_ite(c_in_limits, rounded, mk_fresh_const(0, bv_sz)); + result = m.mk_ite(c_in_limits, rounded, undef); result = m.mk_ite(c2, v2, result); result = m.mk_ite(c1, v1, result); @@ -2658,7 +2662,7 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar tout << "exp2 = " << mk_ismt2_pp(exp2, m) << std::endl;); expr_ref undef(m); - undef = m.mk_fresh_const(0, rs); + undef = m_util.mk_internal_to_real_unspecified(); result = m.mk_ite(x_is_zero, zero, res); result = m.mk_ite(x_is_inf, undef, result); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index cd92a6ab2..ee7ffa192 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -149,6 +149,10 @@ public: void mk_internal_bvwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_internal_bvunwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + + void mk_internal_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_internal_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_internal_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); protected: void mk_is_nan(expr * e, expr_ref & result); diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index f05bca4a1..b63073893 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -291,7 +291,7 @@ namespace smt { SASSERT(m_bv_util.get_bv_size(res) == 3); ctx.internalize(res, false); } - else { + else if (m_float_util.is_float(e)) { SASSERT(to_app(res)->get_family_id() == get_family_id()); decl_kind k = to_app(res)->get_decl_kind(); if (k == OP_FLOAT_TO_FP) { @@ -314,6 +314,9 @@ namespace smt { SASSERT(is_sort_of(m.get_sort(res), m_bv_util.get_family_id(), BV_SORT)); } } + else { + /* ignore; these are the conversion functions fp.to_* */ + } TRACE("t_fpa_detail", tout << "converted term:" << std::endl; tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << @@ -339,6 +342,8 @@ namespace smt { res = convert_atom(e); else if (m_float_util.is_float(e) || m_float_util.is_rm(e)) res = convert_term(e); + else if (m_arith_util.is_real(e)) + res = convert_term(e); else UNREACHABLE(); @@ -508,12 +513,10 @@ namespace smt { c = m.mk_and(m.mk_eq(x_sgn, y_sgn), m.mk_eq(x_sig, y_sig), - m.mk_eq(x_exp, y_exp)); + m.mk_eq(x_exp, y_exp)); } - else if (fu.is_rm(xe) && fu.is_rm(ye)) - c = m.mk_eq(xc, yc); else - UNREACHABLE(); + c = m.mk_eq(xc, yc); // assert_cnstr(m.mk_iff(m.mk_eq(xe, ye), c)); assert_cnstr(c); @@ -556,12 +559,10 @@ namespace smt { c = m.mk_or(m.mk_not(m.mk_eq(x_sgn, y_sgn)), m.mk_not(m.mk_eq(x_sig, y_sig)), - m.mk_not(m.mk_eq(x_exp, y_exp))); + m.mk_not(m.mk_eq(x_exp, y_exp))); } - else if (m_float_util.is_rm(xe) && m_float_util.is_rm(ye)) - c = m.mk_not(m.mk_eq(xc, yc)); else - UNREACHABLE(); + c = m.mk_not(m.mk_eq(xc, yc)); // assert_cnstr(m.mk_iff(m.mk_not(m.mk_eq(xe, ye)), c)); assert_cnstr(c); @@ -638,6 +639,9 @@ namespace smt { } } } + else { + // These are the conversion functions fp.to_* */ + } } void theory_fpa::reset_eh() { From 0ab2782048b733f31ff0364069ac8bb2284ce191 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 29 Dec 2014 17:08:46 +0000 Subject: [PATCH 058/118] FPA: name consistency Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 3403665a9..1598db9c3 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -264,7 +264,7 @@ public: 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_FLOAT_TO_FP); } + bool is_to_fp(expr * n) { return is_app_of(n, m_fid, OP_FLOAT_TO_FP); } 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); } From 33af7e8468ba0621149f65cfd856df72444c181a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 29 Dec 2014 17:09:18 +0000 Subject: [PATCH 059/118] FPA: bugfixes for fp.to_ubv Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 163 +++++++++++++++++++------------ src/ast/fpa/fpa2bv_converter.h | 1 + 2 files changed, 102 insertions(+), 62 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index bd8240b31..7edc4a7a0 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2475,6 +2475,7 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg 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); @@ -2489,6 +2490,7 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg expr_ref undef(m); undef = m_util.mk_internal_to_ubv_unspecified(bv_sz); + dbg_decouple("fpa2bv_to_ubv_undef", undef); // NaN, Inf, or negative (except -0) -> undefined expr_ref c1(m), v1(m); @@ -2499,7 +2501,7 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg // +-Zero -> 0 expr_ref c2(m), v2(m); c2 = x_is_zero; - v2 = m_bv_util.mk_numeral(rational(0), bv_srt); + v2 = m_bv_util.mk_numeral(rational(0), bv_srt); dbg_decouple("fpa2bv_to_ubv_c2", c2); // Otherwise... @@ -2512,47 +2514,73 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg 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); - - // last number that's representable - expr_ref last_valid_bv(m); - last_valid_bv = m_bv_util.mk_numeral(-1, bv_sz); // == 1.0 * 2^bv_sz - 1.0 - - // first invalid bv - mpz const & first_invalid_bv = m_util.fm().m_powers2(bv_sz); - unsigned sig_sz = m_bv_util.get_bv_size(sig); SASSERT(sig_sz == sbits); - - expr_ref shift(m); - if (sig_sz < bv_sz) { - sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, bv_sz - sig_sz)); - shift = m_bv_util.mk_bv_sub(m_bv_util.mk_bv_sub(m_bv_util.mk_sign_extend(2, exp), - m_bv_util.mk_zero_extend(2, lz)), - m_bv_util.mk_numeral(bv_sz-1, ebits + 2)); - } + 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(sig) >= bv_sz); + 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); + + // 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_ubv_in_limits", c_in_limits); - expr_ref shifted_sig(m), shift_abs(m); - shift_abs = m_bv_util.mk_bv_neg(shift); - SASSERT(m_bv_util.get_bv_size(shift_abs) == ebits+2); - SASSERT(bv_sz > (ebits + 2)); - shift_abs = m_bv_util.mk_zero_extend(bv_sz - ebits - 2, shift_abs); - + expr_ref shifted_sig(m); shifted_sig = m_bv_util.mk_bv_lshr(sig, shift_abs); - dbg_decouple("fpa2bv_to_ubv_shift_abs", shift_abs); dbg_decouple("fpa2bv_to_ubv_shifted_sig", shifted_sig); - expr_ref rounded(m); - // TODO: Rounding. - rounded = 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); - result = m.mk_ite(c_in_limits, rounded, undef); + 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), rounded(m), rnd_has_overflown(m); + rnd_overflow = m_bv_util.mk_extract(bv_sz, bv_sz, pre_rounded); + rounded = m_bv_util.mk_extract(bv_sz - 1, 0, pre_rounded); + rnd_has_overflown = m.mk_eq(rnd_overflow, bv1); + + result = m.mk_ite(rnd_has_overflown, undef, rounded); + result = m.mk_ite(c_in_limits, result, undef); result = m.mk_ite(c2, v2, result); result = m.mk_ite(c1, v1, result); @@ -3016,6 +3044,41 @@ void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & 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_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 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); @@ -3110,7 +3173,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); @@ -3191,36 +3253,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); @@ -3289,8 +3323,13 @@ 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); @@ -3306,7 +3345,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & dbg_decouple("fpa2bv_rnd_max_exp", max_exp); - expr_ref ovfl_exp(m), max_inf_exp_neg(m), max_inf_exp_pos(m), n_d_check(m), n_d_exp(m); + 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); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index ee7ffa192..6a854adb3 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -181,6 +181,7 @@ 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, From defb6158fe61d0c93662b07bd547c6dcf2dd7beb Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 29 Dec 2014 17:09:28 +0000 Subject: [PATCH 060/118] MPF: bugfix Signed-off-by: Christoph M. Wintersteiger --- src/util/mpf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 405f34c9d..e3f35538e 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1174,7 +1174,7 @@ std::string mpf_manager::to_string(mpf const & x) { if (is_nan(x)) res = "NaN"; else { - res = sgn(x) ? "-" : "+"; + res = sgn(x) ? "-" : ""; if (is_inf(x)) res += "INF"; From 2258988b37e7d8869ab5c2cf003d7e12272f92b4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 31 Dec 2014 14:48:06 +0000 Subject: [PATCH 061/118] MPF bugfix Signed-off-by: Christoph M. Wintersteiger --- src/util/mpf.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index e3f35538e..245120866 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -301,28 +301,36 @@ 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;); From 4d18e24fb4ee28431cdbe7461ae611473076895c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 31 Dec 2014 14:48:45 +0000 Subject: [PATCH 062/118] FPA rewriter bugfix Signed-off-by: Christoph M. Wintersteiger --- src/ast/rewriter/float_rewriter.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 522fad678..96561395e 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -587,9 +587,14 @@ br_status float_rewriter::mk_to_real(expr * arg1, expr_ref & result) { scoped_mpf fv(m_util.fm()); if (m_util.is_value(arg1, fv)) { - scoped_mpq r(m_fm.mpq_manager()); - m_fm.to_rational(fv, r); - result = m_util.au().mk_numeral(r.get(), false); + 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; } From 01d78b7274d578e174851263728341ccde58ee4c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 31 Dec 2014 14:49:52 +0000 Subject: [PATCH 063/118] added internal functions to fpa2bv converter Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 36 ++++++-------------------------- src/ast/fpa/fpa2bv_converter.h | 7 ------- src/ast/fpa/fpa2bv_rewriter.h | 7 +++++-- 3 files changed, 11 insertions(+), 39 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 7edc4a7a0..e396bb6b5 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2422,29 +2422,6 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * split_triple(args[0], sgn, s, e); result = m_bv_util.mk_concat(m_bv_util.mk_concat(sgn, e), s); } -void fpa2bv_converter::mk_internal_bvwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - TRACE("fpa2bv_internal", tout << "wrap "; - for (unsigned i = 0; i < num; i++) - tout << " " << mk_ismt2_pp(args[i], m); - tout << std::endl;); - SASSERT(num == 1); - result = m.mk_app(f, num, args); -} - -void fpa2bv_converter::mk_internal_bvunwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - TRACE("fpa2bv_internal", tout << "unwrap "; - for (unsigned i = 0; i < num; i++) - tout << " " << mk_ismt2_pp(args[i], m); - tout << std::endl;); - SASSERT(num == 1); - app * a0 = to_app(args[0]); - SASSERT(a0->get_kind() == AST_APP); - SASSERT(is_float_family(a0->get_decl())); - decl_kind k = a0->get_decl_kind(); - SASSERT(k == OP_FLOAT_INTERNAL_BVWRAP); - SASSERT(a0->get_num_args() == 1); - result = a0->get_arg(0); -} void fpa2bv_converter::mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); @@ -2631,7 +2608,7 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar 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); @@ -2646,8 +2623,8 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar for (unsigned i = sbits-2; i != (unsigned)-1; i--) { bit = m_bv_util.mk_extract(i, i, sig); - rsig = m_arith_util.mk_mul(rsig, two); - rsig = m_arith_util.mk_add(rsig, m.mk_ite(m.mk_eq(bit, bv1), one, zero)); + 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); @@ -2661,19 +2638,18 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar 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_not(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; - prev_bit = bv0; for (unsigned i = ebits; i != (unsigned)-1; i--) { bit = m_bv_util.mk_extract(i, i, exp_abs); - exp2 = m_arith_util.mk_mul(exp2, two); - exp2 = m_arith_util.mk_add(exp2, m.mk_ite(m.mk_eq(bit, prev_bit), zero, one)); + 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; } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 6a854adb3..440fc9d14 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -147,13 +147,6 @@ public: void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector m_extra_assertions; - void mk_internal_bvwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_internal_bvunwrap(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - - void mk_internal_to_ubv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_internal_to_sbv_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_internal_to_real_unspecified(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - protected: void mk_is_nan(expr * e, expr_ref & result); void mk_is_inf(expr * e, expr_ref & result); diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index 42fd7a7fe..c9296dd5b 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -151,8 +151,11 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { 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_FLOAT_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; - case OP_FLOAT_INTERNAL_BVWRAP: m_conv.mk_internal_bvwrap(f, num, args, result); return BR_DONE; - case OP_FLOAT_INTERNAL_BVUNWRAP: m_conv.mk_internal_bvunwrap(f, num, args, result); return BR_DONE; + case OP_FLOAT_INTERNAL_BVWRAP: + case OP_FLOAT_INTERNAL_BVUNWRAP: + case OP_FLOAT_INTERNAL_TO_REAL_UNSPECIFIED: + case OP_FLOAT_INTERNAL_TO_UBV_UNSPECIFIED: + case OP_FLOAT_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;); From 208994e2dc63214ddcf3f4dd25e344a253db484c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 31 Dec 2014 15:33:50 +0000 Subject: [PATCH 064/118] Renamed the default tactics form QF_FPA and QF_FPABV to QF_FP and QF_FPBV, in anticipation of the logic name QF_FPA to mean floats+arrays. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/qffpa_tactic.cpp | 53 +++---------------- src/tactic/fpa/qffpa_tactic.h | 14 ++--- src/tactic/portfolio/default_tactic.cpp | 2 +- src/tactic/portfolio/smt_strategic_solver.cpp | 6 +-- 4 files changed, 18 insertions(+), 57 deletions(-) diff --git a/src/tactic/fpa/qffpa_tactic.cpp b/src/tactic/fpa/qffpa_tactic.cpp index f9b7f88a1..6f1517c98 100644 --- a/src/tactic/fpa/qffpa_tactic.cpp +++ b/src/tactic/fpa/qffpa_tactic.cpp @@ -24,7 +24,7 @@ Notes: #include"qffpa_tactic.h" -tactic * mk_qffpa_tactic(ast_manager & m, params_ref const & p) { +tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { params_ref sat_simp_p = p; sat_simp_p .set_bool("elim_and", true); @@ -37,40 +37,14 @@ tactic * mk_qffpa_tactic(ast_manager & m, params_ref const & 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 is_non_qffp_predicate { struct found {}; ast_manager & m; bv_util bu; float_util fu; + arith_util au; - is_non_qffpabv_predicate(ast_manager & _m) : m(_m), bu(m), fu(m) {} + is_non_qffp_predicate(ast_manager & _m) : m(_m), bu(m), fu(m), au(m) {} void operator()(var *) { throw found(); } @@ -78,7 +52,7 @@ struct is_non_qffpabv_predicate { 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)) + 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()) @@ -92,25 +66,14 @@ struct is_non_qffpabv_predicate { } }; -class is_qffpa_probe : public probe { +class is_qffp_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); + return !test(g); } }; probe * mk_is_qffpa_probe() { - return alloc(is_qffpa_probe); -} - -probe * mk_is_qffpabv_probe() { - return alloc(is_qffpabv_probe); + return alloc(is_qffp_probe); } \ No newline at end of file diff --git a/src/tactic/fpa/qffpa_tactic.h b/src/tactic/fpa/qffpa_tactic.h index cd16c5817..923c19970 100644 --- a/src/tactic/fpa/qffpa_tactic.h +++ b/src/tactic/fpa/qffpa_tactic.h @@ -24,17 +24,17 @@ Notes: class ast_manager; class tactic; -tactic * mk_qffpa_tactic(ast_manager & m, params_ref const & p = params_ref()); +tactic * mk_qffp_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)") + ADD_TACTIC("qffp", "(try to) solve goal using the tactic for QF_FPA.", "mk_qffp_tactic(m, p)") + ADD_TACTIC("qffpbv", "(try to) solve goal using the tactic for QF_FPABV (floats+bit-vectors).", "mk_qffp_tactic(m, p)") */ -probe * mk_is_qffpa_probe(); -probe * mk_is_qffpabv_probe(); +probe * mk_is_qffp_probe(); +probe * mk_is_qffpbv_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()") + ADD_PROBE("is-qffp", "true if the goal is in QF_FPA (FloatingPoints).", "mk_is_qffp_probe()") + ADD_PROBE("is-qffpbv", "true if the goal is in QF_FPABV (FloatingPoints+Bitvectors).", "mk_is_qffp_probe()") */ #endif diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 9ecc16ecf..a01b547df 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -38,7 +38,7 @@ 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), + 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 ae79446e3..9e0ce6e89 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -78,10 +78,8 @@ 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" || logic=="QF_FPBV") + return mk_qffp_tactic(m, p); else if (logic=="HORN") return mk_horn_tactic(m, p); else From 21a847d299972b6498cdf335c7fa1d30f2748ac8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 31 Dec 2014 15:36:11 +0000 Subject: [PATCH 065/118] More renamings for QF_FP/qffp/is-qffp Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/qffpa_tactic.cpp | 2 +- src/tactic/fpa/qffpa_tactic.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tactic/fpa/qffpa_tactic.cpp b/src/tactic/fpa/qffpa_tactic.cpp index 6f1517c98..fc292bca6 100644 --- a/src/tactic/fpa/qffpa_tactic.cpp +++ b/src/tactic/fpa/qffpa_tactic.cpp @@ -73,7 +73,7 @@ public: } }; -probe * mk_is_qffpa_probe() { +probe * mk_is_qffp_probe() { return alloc(is_qffp_probe); } \ No newline at end of file diff --git a/src/tactic/fpa/qffpa_tactic.h b/src/tactic/fpa/qffpa_tactic.h index 923c19970..660622fb8 100644 --- a/src/tactic/fpa/qffpa_tactic.h +++ b/src/tactic/fpa/qffpa_tactic.h @@ -26,15 +26,15 @@ class tactic; tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p = params_ref()); /* - ADD_TACTIC("qffp", "(try to) solve goal using the tactic for QF_FPA.", "mk_qffp_tactic(m, p)") - ADD_TACTIC("qffpbv", "(try to) solve goal using the tactic for QF_FPABV (floats+bit-vectors).", "mk_qffp_tactic(m, p)") + 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_qffp_tactic(m, p)") */ probe * mk_is_qffp_probe(); probe * mk_is_qffpbv_probe(); /* - ADD_PROBE("is-qffp", "true if the goal is in QF_FPA (FloatingPoints).", "mk_is_qffp_probe()") - ADD_PROBE("is-qffpbv", "true if the goal is in QF_FPABV (FloatingPoints+Bitvectors).", "mk_is_qffp_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_qffp_probe()") */ #endif From afae49b9edd13cc45e8c5ae6a484b4a26abe1489 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 31 Dec 2014 16:15:40 +0000 Subject: [PATCH 066/118] More renaming QF_FPA -> QF_FP Signed-off-by: Christoph M. Wintersteiger --- src/cmd_context/cmd_context.cpp | 10 +++++----- src/smt/smt_setup.cpp | 4 ++-- src/smt/smt_setup.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index ee5437bd6..4dd0cc614 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -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"; } @@ -557,7 +557,7 @@ bool cmd_context::logic_has_seq() const { } bool cmd_context::logic_has_floats() const { - return !has_logic() || m_logic == "QF_FPA" || m_logic == "QF_FPABV"; + return !has_logic() || m_logic == "QF_FP" || m_logic == "QF_FPBV"; } bool cmd_context::logic_has_array_core(symbol const & s) const { @@ -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/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 64477164a..68e960fb8 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -680,11 +680,11 @@ namespace smt { setup_mi_arith(); } - void setup::setup_QF_FPA() { + void setup::setup_QF_FP() { m_context.register_plugin(alloc(smt::theory_fpa, m_manager)); } - void setup::setup_QF_FPABV() { + void setup::setup_QF_FPBV() { setup_QF_BV(); m_context.register_plugin(alloc(smt::theory_fpa, m_manager)); } diff --git a/src/smt/smt_setup.h b/src/smt/smt_setup.h index 299ce7834..6cbcb9602 100644 --- a/src/smt/smt_setup.h +++ b/src/smt/smt_setup.h @@ -75,8 +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_FPA(); - void setup_QF_FPABV(); + 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); From 80c025b2893cc6adc9d8747f0eb9145bfa04d2ec Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 31 Dec 2014 16:15:55 +0000 Subject: [PATCH 067/118] Improved default tactic for QF_FP Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/qffpa_tactic.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/tactic/fpa/qffpa_tactic.cpp b/src/tactic/fpa/qffpa_tactic.cpp index fc292bca6..6cfc699c7 100644 --- a/src/tactic/fpa/qffpa_tactic.cpp +++ b/src/tactic/fpa/qffpa_tactic.cpp @@ -21,6 +21,7 @@ Notes: #include"bit_blaster_tactic.h" #include"sat_tactic.h" #include"fpa2bv_tactic.h" +#include"smt_tactic.h" #include"qffpa_tactic.h" @@ -28,13 +29,17 @@ tactic * mk_qffp_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), + return cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), + and_then(mk_simplify_tactic(m), + mk_smt_tactic()), + 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()); + mk_fail_if_undecided_tactic())); } struct is_non_qffp_predicate { From 2b7f9b7e5c98f5433877a65605f4fed824904c6d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 31 Dec 2014 16:40:54 +0000 Subject: [PATCH 068/118] build fix for floats Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 2bdf7c4f8..1298093cf 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']) From 7a5239ef707251a409894eef7eed773a96ede48e Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 31 Dec 2014 17:30:45 +0000 Subject: [PATCH 069/118] QF_FP default tactic bugfix Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/qffpa_tactic.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tactic/fpa/qffpa_tactic.cpp b/src/tactic/fpa/qffpa_tactic.cpp index 6cfc699c7..919cf0c1b 100644 --- a/src/tactic/fpa/qffpa_tactic.cpp +++ b/src/tactic/fpa/qffpa_tactic.cpp @@ -29,7 +29,8 @@ tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { params_ref sat_simp_p = p; sat_simp_p .set_bool("elim_and", true); - return cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), + tactic * st = + cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), and_then(mk_simplify_tactic(m), mk_smt_tactic()), and_then( @@ -40,6 +41,9 @@ tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { using_params(mk_simplify_tactic(m, p), sat_simp_p), mk_sat_tactic(m, p), mk_fail_if_undecided_tactic())); + + st->updt_params(p); + return st; } struct is_non_qffp_predicate { From 3fe11e4c38977e938c106166cc361a46469cebb1 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 31 Dec 2014 17:31:11 +0000 Subject: [PATCH 070/118] improved handling of unspecified values in FP Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 39 ++++++++++++++++++++++---------- src/ast/fpa/fpa2bv_converter.h | 6 +++++ src/ast/fpa/fpa2bv_rewriter.h | 14 +++++++++--- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index e396bb6b5..94538861d 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -32,6 +32,7 @@ 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()), + m_hi_fp_unspecified(true), m_extra_assertions(m) { m_plugin = static_cast(m.get_plugin(m.mk_family_id("float"))); } @@ -2465,14 +2466,10 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg mk_is_neg(x, x_is_neg); mk_is_nzero(x, x_is_nzero); - expr_ref undef(m); - undef = m_util.mk_internal_to_ubv_unspecified(bv_sz); - dbg_decouple("fpa2bv_to_ubv_undef", undef); - // NaN, Inf, or negative (except -0) -> undefined 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 = undef; + v1 = mk_to_ubv_unspecified(bv_sz); dbg_decouple("fpa2bv_to_ubv_c1", c1); // +-Zero -> 0 @@ -2556,8 +2553,8 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg rounded = m_bv_util.mk_extract(bv_sz - 1, 0, pre_rounded); rnd_has_overflown = m.mk_eq(rnd_overflow, bv1); - result = m.mk_ite(rnd_has_overflown, undef, rounded); - result = m.mk_ite(c_in_limits, result, undef); + result = m.mk_ite(rnd_has_overflown, mk_to_ubv_unspecified(bv_sz), rounded); + 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); @@ -2664,17 +2661,35 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar TRACE("fpa2bv_to_real", tout << "rsig = " << mk_ismt2_pp(rsig, m) << std::endl; tout << "exp2 = " << mk_ismt2_pp(exp2, m) << std::endl;); - - expr_ref undef(m); - undef = m_util.mk_internal_to_real_unspecified(); result = m.mk_ite(x_is_zero, zero, res); - result = m.mk_ite(x_is_inf, undef, result); - result = m.mk_ite(x_is_nan, undef, result); + 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)); } +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::split_triple(expr * e, expr * & sgn, expr * & sig, expr * & exp) const { SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FLOAT_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 440fc9d14..197c7ce9a 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -51,6 +51,7 @@ protected: mpf_manager & m_mpf_manager; unsynch_mpz_manager & m_mpz_manager; float_decl_plugin * m_plugin; + bool m_hi_fp_unspecified; obj_map m_const2bv; obj_map m_rm_const2bv; @@ -137,6 +138,11 @@ public: 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 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; } diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index c9296dd5b..797f681e7 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 { From 7d61223a3a94b1ac1091ac0a4997cb009ac25b35 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 31 Dec 2014 18:34:42 +0000 Subject: [PATCH 071/118] Improved FP theory Signed-off-by: Christoph M. Wintersteiger --- src/smt/theory_fpa.cpp | 360 +++++++++++++++++++++-------------------- src/smt/theory_fpa.h | 90 +++++++++-- 2 files changed, 260 insertions(+), 190 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index b63073893..f7fd1de30 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -24,55 +24,14 @@ Revision History: namespace smt { - class fpa_factory : public value_factory { - float_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_factory(ast_manager & m, family_id fid) : - value_factory(m, fid), - m_util(m) { - } - - virtual ~fpa_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 fpa_conv_trail : public trail { + class fpa2bv_conversion_trail_elem : public trail { ast_manager & m; obj_map & m_conversions; expr * m_e; public: - fpa_conv_trail(ast_manager & m, obj_map & c, expr * e) : m(m), m_conversions(c), m_e(e) {} - virtual ~fpa_conv_trail() {} + 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); @@ -150,50 +109,52 @@ namespace smt { } app * theory_fpa::fpa_value_proc::mk_value(model_generator & mg, ptr_vector & values) { - SASSERT(values.size() == 3); - ast_manager & m = m_th.get_manager(); - - TRACE("t_fpa", tout << "fpa_value_proc::mk_value for: [" << - mk_ismt2_pp(values[0], m) << " " << - mk_ismt2_pp(values[1], m) << " " << - mk_ismt2_pp(values[2], m) << "]" << std::endl;); + SASSERT(values.size() == 1); + ast_manager & m = m_th.get_manager(); mpf_manager & mpfm = m_fu.fm(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); - - unsigned ebits = m_bu.get_bv_size(values[2]); - unsigned sbits = m_bu.get_bv_size(values[1]) + 1; + + SASSERT(m_bu.get_bv_size(values[0]) == (m_ebits + m_sbits)); + app * result; - scoped_mpz sgn_z(mpzm), sig_z(mpzm), exp_z(mpzm); scoped_mpz bias(mpzm); - mpzm.power(mpz(2), ebits - 1, bias); + mpzm.power(mpz(2), m_ebits - 1, bias); mpzm.dec(bias); - rational sgn_q(0), sig_q(0), exp_q(bias); + rational all_rat(0); + scoped_mpz all_bits(mpzm); unsigned bv_sz; - bool r; - r = m_bu.is_numeral(values[0], sgn_q, bv_sz); SASSERT(r); SASSERT(bv_sz == 1); - r = m_bu.is_numeral(values[1], sig_q, bv_sz); SASSERT(r); SASSERT(bv_sz == sbits - 1); - r = m_bu.is_numeral(values[2], exp_q, bv_sz); SASSERT(r); SASSERT(bv_sz == ebits); + bool r = m_bu.is_numeral(values[0], all_rat, bv_sz); + SASSERT(r); + SASSERT(bv_sz == (m_ebits+m_sbits)); + SASSERT(all_rat.is_int()); + mpzm.set(all_bits, all_rat.to_mpq().numerator()); - TRACE("t_fpa", tout << "sgn=" << sgn_q.to_string() << " ; " << - "sig=" << sig_q.to_string() << " ; " << - "exp=" << exp_q.to_string() << std::endl;); + scoped_mpz sgn_z(mpzm), sig_z(mpzm), exp_z(mpzm); + mpzm.machine_div2k(all_bits, m_ebits + m_sbits - 1, sgn_z); + mpzm.mod(all_bits, mpfm.m_powers2(m_ebits + m_sbits - 1), all_bits); - rational exp_u = exp_q - rational(bias); - SASSERT(exp_u.is_int64()); + mpzm.machine_div2k(all_bits, m_sbits - 1, exp_z); + mpzm.mod(all_bits, mpfm.m_powers2(m_sbits - 1), all_bits); - scoped_mpf f(mpfm); - scoped_mpq sig_mpq(mpqm); - sig_mpq = sig_q.to_mpq(); - mpfm.set(f, ebits, sbits, sgn_q.is_one(), sig_mpq.get().numerator(), exp_u.get_int64()); + TRACE("t_fpa_detail", tout << "sgn=" << mpzm.to_string(sgn_z) << " ; " << + "sig=" << mpzm.to_string(sig_z) << " ; " << + "exp=" << mpzm.to_string(exp_z) << std::endl;); + + 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 result: " << - mk_ismt2_pp(result, m_th.get_manager()) << "\n";); + TRACE("t_fpa", tout << "fpa_value_proc::mk_value [" << + mk_ismt2_pp(values[0], m) << "] --> " << + mk_ismt2_pp(result, m_th.get_manager()) << "\n";); return result; } @@ -267,11 +228,6 @@ namespace smt { proof_ref pr(m); m_rw(e, res); m_th_rw(res, res); - - TRACE("t_fpa_detail", tout << "converted atom:" << std::endl; - tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << - mk_ismt2_pp(res, m) << std::endl;); - SASSERT(is_app(res)); SASSERT(m.is_bool(res)); return res; @@ -290,11 +246,13 @@ namespace smt { SASSERT(is_sort_of(m.get_sort(res), m_bv_util.get_family_id(), BV_SORT)); SASSERT(m_bv_util.get_bv_size(res) == 3); ctx.internalize(res, false); + m_th_rw(res, res); } else if (m_float_util.is_float(e)) { SASSERT(to_app(res)->get_family_id() == get_family_id()); - decl_kind k = to_app(res)->get_decl_kind(); - if (k == OP_FLOAT_TO_FP) { + float_op_kind k = (float_op_kind)(to_app(res)->get_decl_kind()); + switch (k) { + case OP_FLOAT_TO_FP: { SASSERT(to_app(res)->get_num_args() == 3); SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(0)), m_bv_util.get_family_id(), BV_SORT)); SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(1)), m_bv_util.get_family_id(), BV_SORT)); @@ -305,22 +263,32 @@ namespace smt { m_converter.split_triple(res, sgn, sig, exp); m_th_rw(sgn, s_sgn); m_th_rw(sig, s_sig); - m_th_rw(exp, s_exp); - - m_converter.mk_triple(s_sgn, s_sig, s_exp, res); - } - else { - SASSERT(is_sort_of(m.get_sort(e), get_family_id(), ROUNDING_MODE_SORT)); - SASSERT(is_sort_of(m.get_sort(res), m_bv_util.get_family_id(), BV_SORT)); - } - } - else { - /* ignore; these are the conversion functions fp.to_* */ - } + m_th_rw(exp, s_exp); - TRACE("t_fpa_detail", tout << "converted term:" << std::endl; - tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << - mk_ismt2_pp(res, m) << std::endl;); + m_converter.mk_triple(s_sgn, s_sig, s_exp, res); + break; + } + default: + /* nothing */; + } + } + else + UNREACHABLE(); + + 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; } @@ -342,18 +310,18 @@ namespace smt { res = convert_atom(e); else if (m_float_util.is_float(e) || m_float_util.is_rm(e)) res = convert_term(e); - else if (m_arith_util.is_real(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 << "caching:" << std::endl; + 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(fpa_conv_trail(m, m_conversions, e)); + m_trail_stack.push(fpa2bv_conversion_trail_elem(m, m_conversions, e)); } return res; @@ -381,9 +349,9 @@ namespace smt { return res; } - void theory_fpa::assert_cnstr(expr * e) { - TRACE("t_fpa_detail", tout << "asserting " << mk_ismt2_pp(e, get_manager()) << "\n";); + 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)); @@ -395,11 +363,11 @@ namespace smt { context & ctx = get_context(); theory_var v = mk_var(n); ctx.attach_th_var(n, this, v); - TRACE("t_fpa", tout << "new theory var: " << mk_ismt2_pp(n->get_owner(), get_manager()) << " := " << v << "\n";); + 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("t_fpa_detail", 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()); ast_manager & m = get_manager(); @@ -416,9 +384,8 @@ namespace smt { ctx.set_var_theory(l.var(), get_id()); expr_ref bv_atom(m); - bv_atom = convert(atom); - TRACE("t_fpa_detail", tout << "converted: " << mk_ismt2_pp(bv_atom, get_manager()) << "\n";); - SASSERT(bv_atom.get()->get_kind() == AST_APP); + bv_atom = convert(atom); + SASSERT(is_app(bv_atom) && m.is_bool(bv_atom)); bv_atom = m.mk_and(bv_atom, mk_side_conditions()); expr_ref atom_iff(m); @@ -429,8 +396,7 @@ namespace smt { bool theory_fpa::internalize_term(app * term) { ast_manager & m = get_manager(); context & ctx = get_context(); - - TRACE("t_fpa_detail", tout << "internalizing term: " << mk_ismt2_pp(term, get_manager()) << "\n";); + 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)); @@ -438,51 +404,90 @@ namespace smt { 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) : + 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); + 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. + float_op_kind k = (float_op_kind)term->get_decl_kind(); + switch (k) { + case OP_FLOAT_TO_UBV: + case OP_FLOAT_TO_SBV: + case OP_FLOAT_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";); + 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()); - ast_manager & m = get_manager(); + 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_float_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. + // This also ensures that wrap(owner) is internalized. func_decl_ref wrap(m), unwrap(m); get_wrap(owner_sort, wrap, unwrap); if (owner->get_decl() != unwrap) { - expr_ref converted(m), t(m), limit(m); - converted = convert(owner); + expr_ref wrapped(m), valid(m), limit(m); + wrapped = m.mk_app(wrap, owner.get()); limit = m_bv_util.mk_numeral(4, 3); - t = m_bv_util.mk_ule(converted, limit); - assert_cnstr(t); + valid = m_bv_util.mk_ule(wrapped, limit); + assert_cnstr(valid); } } + else if (m_float_util.is_float(owner_sort)) { + // For every FP term, we need to make sure that + // its wrapped version is also internalized so that + // we can build a model for it later. + func_decl_ref wrap(m), unwrap(m); + get_wrap(owner_sort, wrap, unwrap); + if (owner->get_decl() != unwrap) { + expr_ref wrapped(m); + wrapped = m.mk_app(wrap, owner.get()); + if (!ctx.e_internalized(wrapped)) + ctx.internalize(wrapped, false); + } + } + else + UNREACHABLE(); } 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; - tout << mk_ismt2_pp(get_enode(x)->get_owner(), m) << " = " << - mk_ismt2_pp(get_enode(y)->get_owner(), m) << std::endl; ); + 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(); float_util & fu = m_float_util; @@ -492,7 +497,8 @@ namespace smt { app * xe = get_enode(x)->get_owner(); app * ye = get_enode(y)->get_owner(); - if (m_bv_util.is_bv(xe) && m_bv_util.is_bv(ye)) + if ((m.is_bool(xe) && m.is_bool(ye)) || + (m_bv_util.is_bv(xe) && m_bv_util.is_bv(ye))) { SASSERT(xe->get_decl()->get_family_id() == get_family_id()); return; @@ -503,9 +509,14 @@ namespace smt { yc = convert(ye); expr_ref c(m); - + if (fu.is_float(xe) && fu.is_float(ye)) { + func_decl_ref wrap(m), unwrap(m); + get_wrap(m.get_sort(ye), wrap, unwrap); + if (ye->get_decl() == unwrap) + return; + expr *x_sgn, *x_sig, *x_exp; m_converter.split_triple(xc, x_sgn, x_sig, x_exp); expr *y_sgn, *y_sig, *y_exp; @@ -518,8 +529,7 @@ namespace smt { else c = m.mk_eq(xc, yc); - // assert_cnstr(m.mk_iff(m.mk_eq(xe, ye), c)); - assert_cnstr(c); + assert_cnstr(m.mk_iff(m.mk_eq(xe, ye), c)); assert_cnstr(mk_side_conditions()); return; @@ -528,9 +538,9 @@ namespace smt { 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; - tout << mk_ismt2_pp(get_enode(x)->get_owner(), m) << " != " << - mk_ismt2_pp(get_enode(y)->get_owner(), m) << std::endl;); + 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_float_util.fm(); @@ -538,8 +548,8 @@ namespace smt { app * xe = get_enode(x)->get_owner(); app * ye = get_enode(y)->get_owner(); - if (m_bv_util.is_bv(xe) && m_bv_util.is_bv(ye)) - { + if ((m.is_bool(xe) && m.is_bool(ye)) || + (m_bv_util.is_bv(xe) && m_bv_util.is_bv(ye))) { SASSERT(xe->get_decl()->get_family_id() == get_family_id()); return; } @@ -559,13 +569,12 @@ namespace smt { c = m.mk_or(m.mk_not(m.mk_eq(x_sgn, y_sgn)), m.mk_not(m.mk_eq(x_sig, y_sig)), - m.mk_not(m.mk_eq(x_exp, y_exp))); + m.mk_not(m.mk_eq(x_exp, y_exp))); } else c = m.mk_not(m.mk_eq(xc, yc)); - // assert_cnstr(m.mk_iff(m.mk_not(m.mk_eq(xe, ye)), c)); - assert_cnstr(c); + assert_cnstr(m.mk_iff(m.mk_not(m.mk_eq(xe, ye)), c)); assert_cnstr(mk_side_conditions()); return; @@ -591,8 +600,7 @@ namespace smt { TRACE("t_fpa", tout << "assign_eh for: " << v << " (" << is_true << "):\n" << mk_ismt2_pp(e, m) << "\n";); expr_ref converted(m); - converted = convert(e); - converted = m.mk_and(converted, mk_side_conditions()); + converted = m.mk_and(convert(e), mk_side_conditions()); if (!is_true) converted = m.mk_not(converted); assert_cnstr(converted); } @@ -615,8 +623,7 @@ namespace smt { mpf_rounding_mode rm; scoped_mpf val(mpfm); if (m_float_util.is_rm_value(n, rm)) { - c = m.mk_eq(wrapped, m_bv_util.mk_numeral(rm, 3)); - c = m.mk_and(c, mk_side_conditions()); + c = m.mk_eq(wrapped, m_bv_util.mk_numeral(rm, 3)); assert_cnstr(c); } else if (m_float_util.is_value(n, val)) { @@ -626,22 +633,26 @@ namespace smt { 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); - c = m.mk_eq(wrapped, m_bv_util.mk_concat( - m_bv_util.mk_concat(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( m_bv_util.mk_concat( + bv_val_a->get_arg(0), + bv_val_a->get_arg(1)), + bv_val_a->get_arg(2))); c = m.mk_and(c, mk_side_conditions()); assert_cnstr(c); } else { c = m.mk_eq(m.mk_app(unwrap, wrapped), n); - c = m.mk_and(c, mk_side_conditions()); assert_cnstr(c); } } } - else { + else if (n->get_family_id() == get_family_id()) { + SASSERT(!m_float_util.is_float(n) && !m_float_util.is_rm(n)); // These are the conversion functions fp.to_* */ } + else + UNREACHABLE(); + } void theory_fpa::reset_eh() { @@ -659,26 +670,15 @@ namespace smt { theory::reset_eh(); } - void theory_fpa::init_model(model_generator & mg) { - TRACE("t_fpa", tout << "initializing model" << std::endl;); - m_factory = alloc(fpa_factory, get_manager(), get_family_id()); - mg.register_factory(m_factory); - TRACE("t_fpa", display(tout);); + final_check_status theory_fpa::final_check_eh() { + TRACE("t_fpa", tout << "final_check_eh\n";); + return FC_DONE; } - void theory_fpa::add_value_dep(fpa_value_proc * vp, expr * e) { - SASSERT(m_bv_util.is_bv(e)); - ast_manager & m = get_manager(); - context & ctx = get_context(); - if (ctx.e_internalized(e)) - vp->add_dependency(ctx.get_enode(e)); - else { - expr_ref n(m); - n = m_bv_util.mk_numeral(0, m_bv_util.get_bv_size(e)); - if (!ctx.e_internalized(n)) - ctx.internalize(n, false); - vp->add_dependency(ctx.get_enode(n)); - } + void theory_fpa::init_model(model_generator & mg) { + TRACE("t_fpa", tout << "initializing model" << std::endl; display(tout);); + m_factory = alloc(fpa_factory, get_manager(), get_family_id()); + mg.register_factory(m_factory); } model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) { @@ -688,26 +688,36 @@ namespace smt { context & ctx = get_context(); app * owner = n->get_owner(); - app_ref c_a(m); - c_a = to_app(convert(owner)); + // If the owner is not internalized, it doesn't have an enode associated. SASSERT(ctx.e_internalized(owner)); - - TRACE("t_fpa", tout << "converted = " << mk_ismt2_pp(c_a, get_manager()) << "\n";); - + + if (m_float_util.is_rm_value(owner) || + m_float_util.is_value(owner)) + return alloc(expr_wrapper_proc, owner); + model_value_proc * res = 0; + func_decl_ref wrap(m), unwrap(m); + get_wrap(m.get_sort(owner), wrap, unwrap); + app_ref wrapped(m); + wrapped = m.mk_app(wrap, owner); + + CTRACE("t_fpa", !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 (m_float_util.is_rm(owner)) { - fpa_rm_value_proc * vp = alloc(fpa_rm_value_proc, this); - add_value_dep(vp, c_a); - res = vp; + fpa_rm_value_proc * vp = alloc(fpa_rm_value_proc, this); + vp->add_dependency(ctx.get_enode(wrapped)); + res = vp; } else if (m_float_util.is_float(owner)) { - fpa_value_proc * vp = alloc(fpa_value_proc, this); - expr_ref bv_sgn(m), bv_sig(m), bv_exp(m); - m_converter.split_triple(c_a, bv_sgn, bv_sig, bv_exp); - add_value_dep(vp, bv_sgn); - add_value_dep(vp, bv_sig); - add_value_dep(vp, bv_exp); + unsigned ebits = m_float_util.get_ebits(m.get_sort(owner)); + unsigned sbits = m_float_util.get_sbits(m.get_sort(owner)); + fpa_value_proc * vp = alloc(fpa_value_proc, this, ebits, sbits); + vp->add_dependency(ctx.get_enode(wrapped)); res = vp; } else diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index bd2ea29f8..c21096ec0 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -29,9 +29,49 @@ Revision History: namespace smt { - class fpa_factory; + class fpa_factory : public value_factory { + float_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_factory(ast_manager & m, family_id fid) : + value_factory(m, fid), + m_util(m) {} + + virtual ~fpa_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 { @@ -46,27 +86,48 @@ namespace smt { }; class fpa_value_proc : public model_value_proc { - protected: - theory_fpa & m_th; + protected: + theory_fpa & m_th; + ast_manager & m; float_util & m_fu; bv_util & m_bu; - svector m_dependencies; + buffer m_deps; + unsigned m_ebits; + unsigned m_sbits; + public: - fpa_value_proc(theory_fpa * th) : - m_th(*th),m_fu(th->m_float_util),m_bu(th->m_bv_util) {} - void add_dependency(enode * n) { m_dependencies.push_back(model_value_dependency(n)); } + fpa_value_proc(theory_fpa * th, unsigned ebits, unsigned sbits) : + m_th(*th), m_fu(th->m_float_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_dependencies.size(), m_dependencies.c_ptr()); + result.append(m_deps); } + virtual app * mk_value(model_generator & mg, ptr_vector & values); }; - class fpa_rm_value_proc : public fpa_value_proc { + class fpa_rm_value_proc : public model_value_proc { + theory_fpa & m_th; + ast_manager & m; + float_util & m_fu; + bv_util & m_bu; + buffer m_deps; + public: fpa_rm_value_proc(theory_fpa * th) : - fpa_value_proc(th) {} - void add_dependency(enode * n) { fpa_value_proc::add_dependency(n); } + m_th(*th), m_fu(th->m_float_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); }; @@ -84,7 +145,7 @@ namespace smt { obj_map m_unwraps; obj_map m_conversions; - virtual final_check_status final_check_eh() { return FC_DONE; } + 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); @@ -114,13 +175,12 @@ namespace smt { expr_ref convert(expr * e); expr_ref convert_atom(expr * e); expr_ref convert_term(expr * e); + expr_ref convert_conversion_term(expr * e); void get_wrap(sort * s, func_decl_ref & wrap, func_decl_ref & unwrap); void add_trail(ast * a); - void mk_bv_eq(expr * x, expr * y); void attach_new_th_var(enode * n); - void assert_cnstr(expr * e); - void add_value_dep(fpa_value_proc * vp, expr * e); + void assert_cnstr(expr * e); }; }; From 4f453703f7baf85a16a822a48edc7c6cb95d5a64 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 1 Jan 2015 15:23:02 +0000 Subject: [PATCH 072/118] Added arguments of type float to the replayer. Signed-off-by: Christoph M. Wintersteiger --- src/api/z3_replayer.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- src/api/z3_replayer.h | 1 + 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index acdb10bf6..676ba0c69 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,19 @@ struct z3_replayer::imp { return curr() == '-' || curr() == '.' || ('0' <= curr() && curr() <= '9') || curr() == 'e' || curr() == 'E'; } + 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 +426,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 +541,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 +684,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; From 97df505dbaed0e9c51cd756b5d84620e91ba2bb3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 1 Jan 2015 15:23:27 +0000 Subject: [PATCH 073/118] MPF consistency fix Signed-off-by: Christoph M. Wintersteiger --- src/util/mpf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 245120866..cc4b3a35a 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -336,7 +336,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode 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; From a28454d95e314d17beb4ca21c2eb51b3ed726ecb Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 1 Jan 2015 15:24:36 +0000 Subject: [PATCH 074/118] FPA: sort names consistency fix Signed-off-by: Christoph M. Wintersteiger --- src/ast/ast_smt2_pp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index a9e223c55..982b80d37 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -396,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(), "_"); From 09247d2e29563d2f2a5926c85816ac1c2fb69187 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 1 Jan 2015 18:44:41 +0000 Subject: [PATCH 075/118] FPA theory and API overhaul Signed-off-by: Christoph M. Wintersteiger --- scripts/update_api.py | 14 +- src/api/api_fpa.cpp | 354 +++++++++++++++++--- src/api/dotnet/Context.cs | 14 +- src/api/z3_api.h | 3 +- src/api/z3_fpa.h | 641 ++++++++++++++++++++++++++---------- src/ast/float_decl_plugin.h | 39 ++- src/smt/theory_fpa.cpp | 200 ++++++----- src/smt/theory_fpa.h | 8 +- src/util/mpf.h | 2 +- 9 files changed, 944 insertions(+), 331 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 2fbf42cca..a47835904 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_fpa.cpp b/src/api/api_fpa.cpp index bbf27d25d..89b278c91 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -7,6 +7,7 @@ Module Name: Abstract: + Additional APIs for floating-point arithmetic (FP). Author: @@ -31,7 +32,7 @@ extern "C" { Z3_sort r = of_sort(ctx->float_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) { @@ -44,10 +45,20 @@ extern "C" { 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->float_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_even(c); + 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->float_util().mk_round_nearest_ties_to_away()); @@ -55,10 +66,20 @@ extern "C" { 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->float_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_nearest_ties_to_even(c); + LOG_Z3_mk_fpa_round_toward_positive(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); Z3_ast r = of_ast(ctx->float_util().mk_round_toward_positive()); @@ -66,10 +87,20 @@ extern "C" { 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->float_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_nearest_ties_to_even(c); + LOG_Z3_mk_fpa_round_toward_negative(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); Z3_ast r = of_ast(ctx->float_util().mk_round_toward_negative()); @@ -77,10 +108,20 @@ extern "C" { 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->float_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_nearest_ties_to_even(c); + LOG_Z3_mk_fpa_round_toward_zero(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); Z3_ast r = of_ast(ctx->float_util().mk_round_toward_zero()); @@ -88,6 +129,16 @@ extern "C" { 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->float_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; @@ -102,35 +153,35 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_sort Z3_API Z3_mk_fpa_sort_half(__in Z3_context c) { + 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(__in Z3_context c) { + 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(__in Z3_context c) { + 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(__in Z3_context c) { + 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(__in Z3_context c) { + 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(__in Z3_context c) { + 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(__in Z3_context c) { + 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(__in Z3_context c) { + Z3_sort Z3_API Z3_mk_fpa_sort_128(Z3_context c) { return Z3_mk_fpa_sort(c, 15, 113); } @@ -164,6 +215,28 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_ast Z3_API Z3_mk_fpa_fp(Z3_context c, Z3_ast sgn, Z3_ast sig, Z3_ast exp) { + 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->float_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->float_util().fm()); + ctx->float_util().fm().set(tmp, ctx->float_util().get_ebits(to_sort(ty)), ctx->float_util().get_sbits(to_sort(ty)), v); + Z3_ast r = of_ast(ctx->float_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); @@ -175,6 +248,51 @@ extern "C" { 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->float_util().fm()); + ctx->float_util().fm().set(tmp, + ctx->float_util().get_ebits(to_sort(ty)), + ctx->float_util().get_sbits(to_sort(ty)), + v); + Z3_ast r = of_ast(ctx->float_util().mk_value(tmp)); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_mk_fpa_numeral_uint_int(Z3_context c, 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->float_util().fm()); + ctx->float_util().fm().set(tmp, + ctx->float_util().get_ebits(to_sort(ty)), + ctx->float_util().get_sbits(to_sort(ty)), + sgn, sig, exp); + Z3_ast r = of_ast(ctx->float_util().mk_value(tmp)); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_mk_fpa_numeral_uint64_int64(Z3_context c, 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->float_util().fm()); + ctx->float_util().fm().set(tmp, + ctx->float_util().get_ebits(to_sort(ty)), + ctx->float_util().get_sbits(to_sort(ty)), + sgn, sig, exp); + Z3_ast r = of_ast(ctx->float_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; @@ -265,20 +383,40 @@ extern "C" { 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_ast Z3_API Z3_mk_fpa_round_to_integral(Z3_context c, Z3_ast rm, Z3_ast t) { Z3_TRY; - LOG_Z3_mk_fpa_eq(c, t1, t2); + 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->float_util().mk_float_eq(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_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->float_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->float_util().mk_max(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_le(Z3_context c, Z3_ast t1, Z3_ast t2) { + Z3_ast Z3_API Z3_mk_fpa_leq(Z3_context c, Z3_ast t1, Z3_ast t2) { Z3_TRY; - LOG_Z3_mk_fpa_le(c, t1, t2); + LOG_Z3_mk_fpa_leq(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); Z3_ast r = of_ast(ctx->float_util().mk_le(to_expr(t1), to_expr(t2))); @@ -296,9 +434,9 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_ge(Z3_context c, Z3_ast t1, Z3_ast t2) { + Z3_ast Z3_API Z3_mk_fpa_geq(Z3_context c, Z3_ast t1, Z3_ast t2) { Z3_TRY; - LOG_Z3_mk_fpa_ge(c, t1, t2); + LOG_Z3_mk_fpa_geq(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); Z3_ast r = of_ast(ctx->float_util().mk_ge(to_expr(t1), to_expr(t2))); @@ -315,6 +453,16 @@ extern "C" { 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->float_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; @@ -346,9 +494,9 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_is_inf(Z3_context c, Z3_ast t) { + Z3_ast Z3_API Z3_mk_fpa_is_infinite(Z3_context c, Z3_ast t) { Z3_TRY; - LOG_Z3_mk_fpa_is_inf(c, t); + LOG_Z3_mk_fpa_is_infinite(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); Z3_ast r = of_ast(ctx->float_util().mk_is_inf(to_expr(t))); @@ -366,40 +514,142 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_min(Z3_context c, Z3_ast t1, Z3_ast t2) { + Z3_ast Z3_API Z3_mk_fpa_is_negative(Z3_context c, Z3_ast t) { Z3_TRY; - LOG_Z3_mk_fpa_min(c, t1, t2); + LOG_Z3_mk_fpa_is_negative(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_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->float_util().mk_max(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->float_util().mk_is_negative(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_convert(Z3_context c, Z3_sort s, Z3_ast rm, Z3_ast t) { + Z3_ast Z3_API Z3_mk_fpa_is_positive(Z3_context c, Z3_ast t) { Z3_TRY; - LOG_Z3_mk_fpa_convert(c, s, rm, t); + LOG_Z3_mk_fpa_is_positive(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - expr * args [2] = { to_expr(rm), to_expr(t) }; - Z3_ast r = of_ast(ctx->m().mk_app(ctx->float_util().get_family_id(), OP_FLOAT_TO_FP, - to_sort(s)->get_num_parameters(), to_sort(s)->get_parameters(), - 2, args)); + Z3_ast r = of_ast(ctx->float_util().mk_is_positive(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_to_ieee_bv(__in Z3_context c, __in Z3_ast t) { + + 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); + float_util & fu = ctx->float_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); + float_util & fu = ctx->float_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); + float_util & fu = ctx->float_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); + float_util & fu = ctx->float_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); + float_util & fu = ctx->float_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->float_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->float_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->float_util().mk_to_real(to_expr(t))); + RETURN_Z3(r); + 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(); @@ -409,4 +659,22 @@ extern "C" { 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); + float_util & fu = ctx->float_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/dotnet/Context.cs b/src/api/dotnet/Context.cs index 87090dcc9..69855fc4f 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3661,10 +3661,10 @@ namespace Microsoft.Z3 /// /// floating point term /// floating point term - public BoolExpr MkFPLe(FPExpr t1, FPExpr t2) + public BoolExpr MkFPLEq(FPExpr t1, FPExpr t2) { Contract.Ensures(Contract.Result() != null); - return new BoolExpr(this, Native.Z3_mk_fpa_le(this.nCtx, t1.NativeObject, t2.NativeObject)); + return new BoolExpr(this, Native.Z3_mk_fpa_leq(this.nCtx, t1.NativeObject, t2.NativeObject)); } /// @@ -3683,10 +3683,10 @@ namespace Microsoft.Z3 /// /// floating point term /// floating point term - public BoolExpr MkFPGe(FPExpr t1, FPExpr t2) + public BoolExpr MkFPGEq(FPExpr t1, FPExpr t2) { Contract.Ensures(Contract.Result() != null); - return new BoolExpr(this, Native.Z3_mk_fpa_ge(this.nCtx, t1.NativeObject, t2.NativeObject)); + return new BoolExpr(this, Native.Z3_mk_fpa_geq(this.nCtx, t1.NativeObject, t2.NativeObject)); } /// @@ -3737,7 +3737,7 @@ namespace Microsoft.Z3 public BoolExpr MkFPIsInf(FPExpr t) { Contract.Ensures(Contract.Result() != null); - return new BoolExpr(this, Native.Z3_mk_fpa_is_inf(this.nCtx, t.NativeObject)); + return new BoolExpr(this, Native.Z3_mk_fpa_is_infinite(this.nCtx, t.NativeObject)); } /// @@ -3782,10 +3782,10 @@ namespace Microsoft.Z3 /// floating point sort /// floating point rounding mode term /// floating point term - public FPExpr MkFPConvert(FPSort s, FPRMExpr rm, FPExpr t) + public FPExpr MkFPToFP(FPSort s, FPRMExpr rm, FPExpr t) { Contract.Ensures(Contract.Result() != null); - return new FPExpr(this, Native.Z3_mk_fpa_convert(this.nCtx, s.NativeObject, rm.NativeObject, t.NativeObject)); + return new FPExpr(this, Native.Z3_mk_fpa_to_fp_float(this.nCtx, s.NativeObject, rm.NativeObject, t.NativeObject)); } #endregion diff --git a/src/api/z3_api.h b/src/api/z3_api.h index e4bb4bd1d..776e4e9fe 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1700,8 +1700,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 index 50ad49590..48d3e790d 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -7,7 +7,7 @@ Module Name: Abstract: - Additional APIs for floating-point arithmetic (FPA). + Additional APIs for floating-point arithmetic (FP). Author: @@ -36,7 +36,7 @@ extern "C" { /*@{*/ /** - \brief Create a rounding mode sort. + \brief Create the RoundingMode sort. \param c logical context. @@ -45,7 +45,7 @@ extern "C" { Z3_sort Z3_API Z3_mk_fpa_rounding_mode_sort(__in Z3_context c); /** - \brief Create a numeral of rounding mode sort which represents the NearestTiesToEven rounding mode. + \brief Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. \param c logical context. @@ -54,7 +54,16 @@ extern "C" { Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_even(__in Z3_context c); /** - \brief Create a numeral of rounding mode sort which represents the NearestTiesToAway rounding mode. + \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. @@ -63,25 +72,52 @@ extern "C" { Z3_ast Z3_API Z3_mk_fpa_round_nearest_ties_to_away(__in Z3_context c); /** - \brief Create a numeral of rounding mode sort which represents the TowardPositive rounding mode. + \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); + Z3_ast Z3_API Z3_mk_fpa_round_toward_positive(__in Z3_context c); /** - \brief Create a numeral of rounding mode sort which represents the TowardNegative rounding mode. + \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); + Z3_ast Z3_API Z3_mk_fpa_round_toward_negative(__in Z3_context c); /** - \brief Create a numeral of rounding mode sort which represents the TowardZero rounding mode. + \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. @@ -89,14 +125,21 @@ extern "C" { */ Z3_ast Z3_API Z3_mk_fpa_round_toward_zero(__in Z3_context c); - - /** - \brief Create a floating point sort. + \brief Create a numeral of RoundingMode sort which represents the TowardZero rounding mode. \param c logical context. - \param ebits number of exponent bits - \param sbits number of significand bits + + 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. @@ -105,85 +148,61 @@ extern "C" { 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) floating point sort. + \brief Create the half-precision (16-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_half', SORT, (_in(CONTEXT),)) */ Z3_sort Z3_API Z3_mk_fpa_sort_half(__in Z3_context c); /** - \brief Create the half-precision (16-bit) floating point sort. + \brief Create the half-precision (16-bit) FloatingPoint sort. - \param c logical context. - \param ebits number of exponent bits - \param sbits number of significand bits + \param c logical context. - \remark ebits must be larger than 1 and sbits must be larger than 2. - - def_API('Z3_mk_fpa_sort_16', SORT, (_in(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) floating point sort. + \brief Create the single-precision (32-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. + \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) floating point sort. + \brief Create the single-precision (32-bit) FloatingPoint sort. - \param c logical context. - \param ebits number of exponent bits - \param sbits number of significand bits + \param c logical context. - \remark ebits must be larger than 1 and sbits must be larger than 2. - - def_API('Z3_mk_fpa_sort_32', SORT, (_in(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) floating point sort. + \brief Create the double-precision (64-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_double', SORT, (_in(CONTEXT),)) */ Z3_sort Z3_API Z3_mk_fpa_sort_double(__in Z3_context c); /** - \brief Create the double-precision (64-bit) floating point sort. + \brief Create the double-precision (64-bit) FloatingPoint sort. - \param c logical context. - \param ebits number of exponent bits - \param sbits number of significand bits + \param c logical context. - \remark ebits must be larger than 1 and sbits must be larger than 2. - - def_API('Z3_mk_fpa_sort_64', SORT, (_in(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) floating point sort. + \brief Create the quadruple-precision (128-bit) FloatingPoint sort. \param c logical context. \param ebits number of exponent bits @@ -196,15 +215,15 @@ extern "C" { Z3_sort Z3_API Z3_mk_fpa_sort_quadruple(__in Z3_context c); /** - \brief Create the quadruple-precision (128-bit) floating point sort. + \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 + \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. + \remark ebits must be larger than 1 and sbits must be larger than 2. - def_API('Z3_mk_fpa_sort_128', SORT, (_in(CONTEXT),)) + def_API('Z3_mk_fpa_sort_128', SORT, (_in(CONTEXT),)) */ Z3_sort Z3_API Z3_mk_fpa_sort_128(__in Z3_context c); @@ -219,7 +238,7 @@ extern "C" { 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. + \brief Create a floating-point infinity of sort s. \param c logical context. \param s target sort @@ -232,29 +251,64 @@ extern "C" { 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. + \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 + \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. + 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))) + 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 a numeral of floating point sort from a double. + \brief Create an expression of FloatingPoint sort from three bit-vector expressions. + + 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 sig significand + \params exp exponent + + 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 sig, __in Z3_ast exp); + + /** + \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 can be use to create numerals that fit in a double value. + 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 floating point sort + ty must be a FloatingPoint sort \sa Z3_mk_numeral @@ -262,13 +316,57 @@ extern "C" { */ 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 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 bool sgn, __in __uint64 sig, __in __int64 exp, Z3_sort ty); + /** \brief Floating-point absolute value \param c logical context. - \param t floating-point term. - - t must have floating point sort. + \param t term of FloatingPoint sort. def_API('Z3_mk_fpa_abs', AST, (_in(CONTEXT),_in(AST))) */ @@ -278,9 +376,7 @@ extern "C" { \brief Floating-point negation \param c logical context. - \param t floating-point term. - - t must have floating point sort. + \param t term of FloatingPoint sort. def_API('Z3_mk_fpa_neg', AST, (_in(CONTEXT),_in(AST))) */ @@ -290,11 +386,11 @@ extern "C" { \brief Floating-point addition \param c logical context. - \param rm rounding mode - \param t1 floating-point term. - \param t2 floating-point term. + \param rm term of RoundingMode sort. + \param t1 term of FloatingPoint sort. + \param t2 term of FloatingPoint sort. - rm must be of FPA rounding mode sort, t1 and t2 must have the same floating point 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))) */ @@ -304,11 +400,11 @@ extern "C" { \brief Floating-point subtraction \param c logical context. - \param rm rounding mode - \param t1 floating-point term. - \param t2 floating-point term. + \param rm term of RoundingMode sort. + \param t1 term of FloatingPoint sort. + \param t2 term of FloatingPoint sort. - rm must be of FPA rounding mode sort, t1 and t2 must have the same floating point 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))) */ @@ -318,11 +414,11 @@ extern "C" { \brief Floating-point multiplication \param c logical context. - \param rm rounding mode - \param t1 floating-point term. - \param t2 floating-point term. + \param rm term of RoundingMode sort. + \param t1 term of FloatingPoint sort. + \param t2 term of FloatingPoint sort. - rm must be of FPA rounding mode sort, t1 and t2 must have the same floating point 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))) */ @@ -332,11 +428,11 @@ extern "C" { \brief Floating-point division \param c logical context. - \param rm rounding mode - \param t1 floating-point term. - \param t2 floating-point term. + \param rm term of RoundingMode sort. + \param t1 term of FloatingPoint sort. + \param t2 term of FloatingPoint sort. - The nodes rm must be of FPA rounding mode sort t1 and t2 must have the same floating point 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))) */ @@ -346,13 +442,13 @@ extern "C" { \brief Floating-point fused multiply-add. \param c logical context. - \param rm rounding mode - \param t1 floating-point term. - \param t2 floating-point term. + \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 FPA rounding mode sort, t1, t2, and t3 must have the same floating point sort. + 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))) */ @@ -362,10 +458,10 @@ extern "C" { \brief Floating-point square root \param c logical context. - \param rm rounding mode - \param t floating-point term. + \param rm term of RoundingMode sort. + \param t term of FloatingPoint sort. - rm must be of FPA rounding mode sort, t must have floating point 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))) */ @@ -375,198 +471,387 @@ extern "C" { \brief Floating-point remainder \param c logical context. - \param t1 floating-point term. - \param t2 floating-point term. + \param t1 term of FloatingPoint sort. + \param t2 term of FloatingPoint sort. - t1 and t2 must have the same floating point 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); - + Z3_ast Z3_API Z3_mk_fpa_rem(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2); + /** - \brief Floating-point equality + \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 t1 floating-point term. - \param t2 floating-point term. + \param rm term of RoundingMode sort. + \param t term of FloatingPoint sort. - Note that this is IEEE 754 equality (as opposed to SMT-LIB =). + t must be of FloatingPoint sort. - t1 and t2 must have the same floating point 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); + 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 floating-point term. - \param t2 floating-point term. + \param t1 term of FloatingPoint sort. + \param t2 term of FloatingPoint sort. - t1 and t2 must have the same floating point sort. + t1 and t2 must have the same FloatingPoint sort. - def_API('Z3_mk_fpa_le', AST, (_in(CONTEXT),_in(AST),_in(AST))) + def_API('Z3_mk_fpa_leq', AST, (_in(CONTEXT),_in(AST),_in(AST))) */ - Z3_ast Z3_API Z3_mk_fpa_le(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2); + 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 floating-point term. - \param t2 floating-point term. + \param t1 term of FloatingPoint sort. + \param t2 term of FloatingPoint sort. - t1 and t2 must have the same floating point 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 floating-point term. - \param t2 floating-point term. + \param t1 term of FloatingPoint sort. + \param t2 term of FloatingPoint sort. - t1 and t2 must have the same floating point sort. + t1 and t2 must have the same FloatingPoint sort. - def_API('Z3_mk_fpa_ge', AST, (_in(CONTEXT),_in(AST),_in(AST))) + def_API('Z3_mk_fpa_geq', AST, (_in(CONTEXT),_in(AST),_in(AST))) */ - Z3_ast Z3_API Z3_mk_fpa_ge(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2); + 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 floating-point term. - \param t2 floating-point term. + \param t1 term of FloatingPoint sort. + \param t2 term of FloatingPoint sort. - t1 and t2 must have the same floating point 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 Predicate indicating whether t is a normal floating point number + \brief Floating-point equality \param c logical context. - \param t floating-point term. + \param t1 term of FloatingPoint sort. + \param t2 term of FloatingPoint sort. - t must have floating point 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 + \brief Predicate indicating whether t is a subnormal floating-point number. \param c logical context. - \param t floating-point term. + \param t term of FloatingPoint sort. - t must have floating point 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., +0 or -0. + \brief Predicate indicating whether t is a floating-point number with zero value, i.e., +zero or -zero. \param c logical context. - \param t floating-point term. + \param t term of FloatingPoint sort. - t must have floating point 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 +Inf or -Inf + \brief Predicate indicating whether t is a floating-point number representing +oo or -oo. \param c logical context. - \param t floating-point term. + \param t term of FloatingPoint sort. - t must have floating point sort. + t must have FloatingPoint sort. - def_API('Z3_mk_fpa_is_inf', AST, (_in(CONTEXT),_in(AST))) + def_API('Z3_mk_fpa_is_infinite', AST, (_in(CONTEXT),_in(AST))) */ - Z3_ast Z3_API Z3_mk_fpa_is_inf(__in Z3_context c, __in Z3_ast t); + 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 floating-point term. + \param t term of FloatingPoint sort. - t must have floating point 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 Minimum of floating point numbers + \brief Predicate indicating whether t is a negative floating-point number. \param c logical context. - \param t1 floating-point term. - \param t2 floating-point term. + \param t term of FloatingPoint sort. - t1, t2 must have the same floating point 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 + t must have FloatingPoint sort. - \param c logical context. - \param t1 floating-point term. - \param t2 floating-point term. - - t1, t2 must have the same floating point 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); + 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 Conversion of a floating point number to another floating-point sort s. - - Produces a term that represents the conversion of a floating-point term t to a different - floating point sort s. If necessary, rounding according to rm is applied. + \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. - \param rm rounding mode. - \param t floating-point term. - s must be a floating point sort, rm must have rounding mode sort, and t must have floating point sort. + s must be a FloatingPoint sort, t must be of bit-vector sort, and 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 and the resulting floating-point + sort (ebits, sbits) is automatically determined. - def_API('Z3_mk_fpa_convert', AST, (_in(CONTEXT),_in(SORT),_in(AST),_in(AST))) + def_API('Z3_mk_fpa_to_fp_bv', AST, (_in(CONTEXT),_in(AST),_in(SORT))) */ - Z3_ast Z3_API Z3_mk_fpa_convert(__in Z3_context c, __in Z3_sort s, __in Z3_ast rm, __in Z3_ast t); + 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 floating point term to a bit-vector term in IEEE754 format. + \brief Conversion of a floating-point term into another floating-point term of different floating-point 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 in unsigned 2's complement format. If necessary, the result will be + rounded according to rounding mode rm. \param c logical context. - \param t floating-point term. + \param rm term of RoundingMode sort. + \param t term of FloatingPoint sort. + \param sz size of the resulting bit-vector. - t must have floating point sort. The size of the resulting bit-vector is automatically determined. + 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 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 number. + + 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 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 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_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); + + /*@}*/ /*@}*/ /*@}*/ diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 1598db9c3..cbcd706cd 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -263,9 +263,41 @@ public: 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); } + + app * mk_fp(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FLOAT_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_FLOAT_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_FLOAT_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_FLOAT_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_FLOAT_TO_FP_UNSIGNED, 2, s->get_parameters(), 2, args); + } bool is_to_fp(expr * n) { return is_app_of(n, m_fid, OP_FLOAT_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_FLOAT_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_FLOAT_TO_SBV, 1, ps, 2, args); + } + app * mk_to_real(expr * t) { return m().mk_app(m_fid, OP_FLOAT_TO_REAL, t); } + 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); } @@ -276,7 +308,7 @@ public: 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_round_to_integral(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); @@ -306,6 +338,9 @@ public: 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_FLOAT_INTERNAL_BVWRAP); } + bool is_unwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FLOAT_INTERNAL_BVUNWRAP); } }; #endif diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index f7fd1de30..03a2e73bf 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -48,13 +48,11 @@ namespace smt { } else { sort * s = f->get_range(); - func_decl_ref w(m), u(m); - m_th.get_wrap(s, w, u); expr_ref bv(m); - bv = m.mk_app(w, m.mk_const(f)); + 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_float_util.get_ebits(f->get_range()); - unsigned sbits = m_th.m_float_util.get_sbits(f->get_range()); + unsigned ebits = m_th.m_float_util.get_ebits(s); + unsigned sbits = m_th.m_float_util.get_sbits(s); SASSERT(bv_sz == ebits + sbits); m_th.m_converter.mk_triple(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), m_bv_util.mk_extract(sbits - 2, 0, bv), @@ -76,12 +74,7 @@ namespace smt { } else { SASSERT(is_rm(f->get_range())); - - sort * s = f->get_range(); - func_decl_ref w(m), u(m); - m_th.get_wrap(s, w, u); - result = m.mk_app(w, m.mk_const(f)); - + result = m_th.wrap(m.mk_const(f)); m_rm_const2bv.insert(f, result); m.inc_ref(f); m.inc_ref(result); @@ -133,13 +126,15 @@ namespace smt { SASSERT(bv_sz == (m_ebits+m_sbits)); SASSERT(all_rat.is_int()); mpzm.set(all_bits, all_rat.to_mpq().numerator()); - + scoped_mpz sgn_z(mpzm), sig_z(mpzm), exp_z(mpzm); mpzm.machine_div2k(all_bits, m_ebits + m_sbits - 1, sgn_z); mpzm.mod(all_bits, mpfm.m_powers2(m_ebits + m_sbits - 1), all_bits); mpzm.machine_div2k(all_bits, m_sbits - 1, exp_z); mpzm.mod(all_bits, mpfm.m_powers2(m_sbits - 1), all_bits); + + mpzm.set(sig_z, all_bits); TRACE("t_fpa_detail", tout << "sgn=" << mpzm.to_string(sgn_z) << " ; " << "sig=" << mpzm.to_string(sig_z) << " ; " << @@ -190,36 +185,53 @@ namespace smt { return result; } - void theory_fpa::get_wrap(sort * s, func_decl_ref & wrap, func_decl_ref & unwrap) - { - func_decl *w, *u; + app_ref theory_fpa::wrap(expr * e) { + SASSERT(!m_float_util.is_wrap(e)); + ast_manager & m = get_manager(); + context & ctx = get_context(); + sort * e_srt = m.get_sort(e); - if (!m_wraps.find(s, w) || !m_unwraps.find(s, u)) { - SASSERT(!m_wraps.contains(s)); - SASSERT(!m_unwraps.contains(s)); - ast_manager & m = get_manager(); - context & ctx = get_context(); + func_decl *w; + + if (!m_wraps.find(e_srt, w)) { + SASSERT(!m_wraps.contains(e_srt)); + sort * bv_srt = 0; - if (m_converter.is_rm(s)) + if (m_converter.is_rm(e_srt)) bv_srt = m_bv_util.mk_sort(3); else { - SASSERT(m_converter.is_float(s)); - unsigned ebits = m_float_util.get_ebits(s); - unsigned sbits = m_float_util.get_sbits(s); + SASSERT(m_converter.is_float(e_srt)); + unsigned ebits = m_float_util.get_ebits(e_srt); + unsigned sbits = m_float_util.get_sbits(e_srt); bv_srt = m_bv_util.mk_sort(ebits + sbits); } - w = m.mk_func_decl(get_family_id(), OP_FLOAT_INTERNAL_BVWRAP, 0, 0, 1, &s, bv_srt); + w = m.mk_func_decl(get_family_id(), OP_FLOAT_INTERNAL_BVWRAP, 0, 0, 1, &e_srt, bv_srt); + m_wraps.insert(e_srt, w); + m.inc_ref(w); + } + + return app_ref(m.mk_app(w, e), m); + } + + app_ref theory_fpa::unwrap(expr * e, sort * s) { + SASSERT(!m_float_util.is_unwrap(e)); + ast_manager & m = get_manager(); + context & ctx = get_context(); + sort * e_srt = m.get_sort(e); + + func_decl *u; + + if (!m_unwraps.find(e_srt, u)) { + SASSERT(!m_unwraps.contains(e_srt)); + sort * bv_srt = m.get_sort(e); u = m.mk_func_decl(get_family_id(), OP_FLOAT_INTERNAL_BVUNWRAP, 0, 0, 1, &bv_srt, s); - m_wraps.insert(s, w); m_unwraps.insert(s, u); - m.inc_ref(w); m.inc_ref(u); } - wrap = w; - unwrap = u; + return app_ref(m.mk_app(u, e), m); } expr_ref theory_fpa::convert_atom(expr * e) { @@ -235,32 +247,39 @@ namespace smt { expr_ref theory_fpa::convert_term(expr * e) { ast_manager & m = get_manager(); + TRACE("t_fpa_detail", tout << "converting: " << mk_ismt2_pp(e, m) << " sort is: " << mk_ismt2_pp(m.get_sort(e), m) << std::endl;); + context & ctx = get_context(); - expr_ref res(m); + expr_ref ec(m), res(m); proof_ref pr(m); - m_rw(e, res); - - SASSERT(is_app(res)); - - if (m_float_util.is_rm(e)) { - SASSERT(is_sort_of(m.get_sort(res), m_bv_util.get_family_id(), BV_SORT)); - SASSERT(m_bv_util.get_bv_size(res) == 3); - ctx.internalize(res, false); - m_th_rw(res, res); + m_rw(e, ec); + + SASSERT(is_app(ec)); + app_ref eca(to_app(ec), m); + TRACE("t_fpa_detail", tout << "eca = " << mk_ismt2_pp(eca, m) << " sort is: " << mk_ismt2_pp(m.get_sort(eca), m) << std::endl;); + + if (m_float_util.is_rm(e)) { + expr_ref bv_rm(m); + bv_rm = eca; + TRACE("t_fpa_detail", tout << "bvrm = " << mk_ismt2_pp(bv_rm, m) << " sort is: " << mk_ismt2_pp(m.get_sort(bv_rm), m) << std::endl;); + SASSERT(is_sort_of(m.get_sort(bv_rm), m_bv_util.get_family_id(), BV_SORT)); + SASSERT(m_bv_util.get_bv_size(bv_rm) == 3); + m_th_rw(bv_rm, res); } else if (m_float_util.is_float(e)) { - SASSERT(to_app(res)->get_family_id() == get_family_id()); - float_op_kind k = (float_op_kind)(to_app(res)->get_decl_kind()); + SASSERT(eca->get_family_id() == get_family_id()); + float_op_kind k = (float_op_kind)(eca->get_decl_kind()); + SASSERT(k == OP_FLOAT_TO_FP || k == OP_FLOAT_INTERNAL_BVUNWRAP); switch (k) { case OP_FLOAT_TO_FP: { - SASSERT(to_app(res)->get_num_args() == 3); - SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(0)), m_bv_util.get_family_id(), BV_SORT)); - SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(1)), m_bv_util.get_family_id(), BV_SORT)); - SASSERT(is_sort_of(m.get_sort(to_app(res)->get_arg(2)), m_bv_util.get_family_id(), BV_SORT)); - + SASSERT(eca->get_num_args() == 3); + SASSERT(is_sort_of(m.get_sort(eca->get_arg(0)), m_bv_util.get_family_id(), BV_SORT)); + SASSERT(is_sort_of(m.get_sort(eca->get_arg(1)), m_bv_util.get_family_id(), BV_SORT)); + SASSERT(is_sort_of(m.get_sort(eca->get_arg(2)), m_bv_util.get_family_id(), BV_SORT)); + expr *sgn, *sig, *exp; expr_ref s_sgn(m), s_sig(m), s_exp(m); - m_converter.split_triple(res, sgn, sig, exp); + m_converter.split_triple(eca, sgn, sig, exp); m_th_rw(sgn, s_sgn); m_th_rw(sig, s_sig); m_th_rw(exp, s_exp); @@ -269,12 +288,13 @@ namespace smt { break; } default: - /* nothing */; + res = eca; } } else UNREACHABLE(); + SASSERT(res.get() != 0); return res; } @@ -292,6 +312,28 @@ namespace smt { return res; } + expr_ref theory_fpa::convert_unwrap(expr * e) { + SASSERT(m_float_util.is_unwrap(e)); + ast_manager & m = get_manager(); + sort * srt = m.get_sort(e); + expr_ref res(m); + if (m_float_util.is_rm(srt)) { + res = to_app(e)->get_arg(0); + } + else { + SASSERT(m_float_util.is_float(srt)); + unsigned ebits = m_float_util.get_ebits(srt); + unsigned sbits = m_float_util.get_sbits(srt); + expr * bv = to_app(e)->get_arg(0); + unsigned bv_sz = m_bv_util.get_bv_size(bv); + m_converter.mk_triple(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), + m_bv_util.mk_extract(sbits - 2, 0, bv), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), + res); + } + return res; + } + expr_ref theory_fpa::convert(expr * e) { ast_manager & m = get_manager(); @@ -306,7 +348,9 @@ namespace smt { return res; } else { - if (m.is_bool(e)) + if (m_float_util.is_unwrap(e)) + res = convert_unwrap(e); + else if (m.is_bool(e)) res = convert_atom(e); else if (m_float_util.is_float(e) || m_float_util.is_rm(e)) res = convert_term(e); @@ -452,34 +496,18 @@ namespace smt { if (m_float_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. - // This also ensures that wrap(owner) is internalized. - func_decl_ref wrap(m), unwrap(m); - get_wrap(owner_sort, wrap, unwrap); - if (owner->get_decl() != unwrap) + // associated bit-vector is within the valid range. + if (!m_float_util.is_unwrap(owner)) { - expr_ref wrapped(m), valid(m), limit(m); - wrapped = m.mk_app(wrap, owner.get()); + expr_ref valid(m), limit(m); limit = m_bv_util.mk_numeral(4, 3); - valid = m_bv_util.mk_ule(wrapped, limit); + valid = m_bv_util.mk_ule(wrap(owner), limit); assert_cnstr(valid); } } - else if (m_float_util.is_float(owner_sort)) { - // For every FP term, we need to make sure that - // its wrapped version is also internalized so that - // we can build a model for it later. - func_decl_ref wrap(m), unwrap(m); - get_wrap(owner_sort, wrap, unwrap); - if (owner->get_decl() != unwrap) { - expr_ref wrapped(m); - wrapped = m.mk_app(wrap, owner.get()); - if (!ctx.e_internalized(wrapped)) - ctx.internalize(wrapped, false); - } - } - else - UNREACHABLE(); + + if (!ctx.relevancy() && !m_float_util.is_unwrap(owner)) + assert_cnstr(m.mk_eq(unwrap(wrap(owner), owner_sort), owner)); } void theory_fpa::new_eq_eh(theory_var x, theory_var y) { @@ -498,8 +526,7 @@ namespace smt { app * 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))) - { + (m_bv_util.is_bv(xe) && m_bv_util.is_bv(ye))) { SASSERT(xe->get_decl()->get_family_id() == get_family_id()); return; } @@ -509,16 +536,13 @@ namespace smt { yc = convert(ye); expr_ref c(m); - + if (fu.is_float(xe) && fu.is_float(ye)) { - func_decl_ref wrap(m), unwrap(m); - get_wrap(m.get_sort(ye), wrap, unwrap); - if (ye->get_decl() == unwrap) - return; expr *x_sgn, *x_sig, *x_exp; m_converter.split_triple(xc, x_sgn, x_sig, x_exp); + expr *y_sgn, *y_sig, *y_exp; m_converter.split_triple(yc, y_sgn, y_sig, y_exp); @@ -614,12 +638,10 @@ namespace smt { if (m_float_util.is_float(n) || m_float_util.is_rm(n)) { sort * s = m.get_sort(n); - func_decl_ref wrap(m), unwrap(m); - get_wrap(s, wrap, unwrap); - if (n->get_decl() != unwrap) { + if (!m_float_util.is_unwrap(n)) { expr_ref wrapped(m), c(m); - wrapped = m.mk_app(wrap, n); + wrapped = wrap(n); mpf_rounding_mode rm; scoped_mpf val(mpfm); if (m_float_util.is_rm_value(n, rm)) { @@ -633,15 +655,13 @@ namespace smt { 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); - c = m.mk_eq(wrapped, m_bv_util.mk_concat( m_bv_util.mk_concat( - bv_val_a->get_arg(0), - bv_val_a->get_arg(1)), - bv_val_a->get_arg(2))); + 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(m.mk_app(unwrap, wrapped), n); + c = m.mk_eq(unwrap(wrapped, m.get_sort(n)), n); assert_cnstr(c); } } @@ -696,11 +716,9 @@ namespace smt { return alloc(expr_wrapper_proc, owner); model_value_proc * res = 0; - func_decl_ref wrap(m), unwrap(m); - get_wrap(m.get_sort(owner), wrap, unwrap); app_ref wrapped(m); - wrapped = m.mk_app(wrap, owner); + wrapped = wrap(owner); CTRACE("t_fpa", !ctx.e_internalized(wrapped), tout << "Model dependency not internalized: " << diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index c21096ec0..c51b02c28 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -176,11 +176,15 @@ namespace smt { expr_ref convert_atom(expr * e); expr_ref convert_term(expr * e); expr_ref convert_conversion_term(expr * e); - void get_wrap(sort * s, func_decl_ref & wrap, func_decl_ref & unwrap); + expr_ref convert_unwrap(expr * e); + void add_trail(ast * a); void attach_new_th_var(enode * n); - void assert_cnstr(expr * e); + void assert_cnstr(expr * e); + + app_ref wrap(expr * e); + app_ref unwrap(expr * e, sort * s); }; }; diff --git a/src/util/mpf.h b/src/util/mpf.h index 83646f9f3..b919e0371 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); From 076c709453146ca526fa454340370bbf2ad2376b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 1 Jan 2015 19:00:06 +0000 Subject: [PATCH 076/118] cosmetics Signed-off-by: Christoph M. Wintersteiger --- src/smt/theory_fpa.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 03a2e73bf..bec9cf235 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -344,7 +344,7 @@ namespace smt { 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;); + mk_ismt2_pp(res, m) << std::endl;); return res; } else { @@ -360,8 +360,8 @@ namespace smt { 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;); + 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); @@ -539,10 +539,8 @@ namespace smt { if (fu.is_float(xe) && fu.is_float(ye)) { - expr *x_sgn, *x_sig, *x_exp; m_converter.split_triple(xc, x_sgn, x_sig, x_exp); - expr *y_sgn, *y_sig, *y_exp; m_converter.split_triple(yc, y_sgn, y_sig, y_exp); From 6e849d7f73905d415a9fd4e07970a52baa1972bf Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 1 Jan 2015 19:16:02 +0000 Subject: [PATCH 077/118] FPA API cosmetics Signed-off-by: Christoph M. Wintersteiger --- src/api/api_fpa.cpp | 8 ++++---- src/api/z3_fpa.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 89b278c91..97225f0f3 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -264,7 +264,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_numeral_uint_int(Z3_context c, bool sgn, unsigned sig, signed exp, Z3_sort ty) { + 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(); @@ -273,13 +273,13 @@ extern "C" { ctx->float_util().fm().set(tmp, ctx->float_util().get_ebits(to_sort(ty)), ctx->float_util().get_sbits(to_sort(ty)), - sgn, sig, exp); + sgn != 0, sig, exp); Z3_ast r = of_ast(ctx->float_util().mk_value(tmp)); RETURN_Z3(r); Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_numeral_uint64_int64(Z3_context c, bool sgn, __uint64 sig, __int64 exp, Z3_sort ty) { + 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(); @@ -288,7 +288,7 @@ extern "C" { ctx->float_util().fm().set(tmp, ctx->float_util().get_ebits(to_sort(ty)), ctx->float_util().get_sbits(to_sort(ty)), - sgn, sig, exp); + sgn != 0, sig, exp); Z3_ast r = of_ast(ctx->float_util().mk_value(tmp)); RETURN_Z3(r); Z3_CATCH_RETURN(0); diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 48d3e790d..61ee0bd7f 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -344,7 +344,7 @@ extern "C" { 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 bool sgn, __in unsigned sig, __in signed exp, Z3_sort ty); + 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. @@ -360,7 +360,7 @@ extern "C" { 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 bool sgn, __in __uint64 sig, __in __int64 exp, Z3_sort ty); + 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 From b46d76cddbc889822ff5a1bdab7ab104113c9628 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 1 Jan 2015 19:16:44 +0000 Subject: [PATCH 078/118] New FPA C-API example Signed-off-by: Christoph M. Wintersteiger --- examples/c/test_capi.c | 149 ++++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 76 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 1aef9eb1b..920fdeb8c 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2595,16 +2595,20 @@ 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 symbol_rm, symbol_x, symbol_y, symbol_q; - Z3_ast rm, x, y, n, q, c1, c2, c3, c4, c5, c6; + 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"); - printf("\nfpa_example\n"); - LOG_MSG("fpa_example"); - cfg = Z3_mk_config(); ctx = Z3_mk_context(cfg); Z3_del_config(cfg); @@ -2612,83 +2616,76 @@ void fpa_example() { double_sort = Z3_mk_fpa_sort(ctx, 11, 53); rm_sort = Z3_mk_fpa_rounding_mode_sort(ctx); - symbol_rm = Z3_mk_string_symbol(ctx, "rm"); - rm = Z3_mk_const(ctx, symbol_rm, rm_sort); - symbol_x = Z3_mk_string_symbol(ctx, "x"); - symbol_y = Z3_mk_string_symbol(ctx, "y"); - x = Z3_mk_const(ctx, symbol_x, double_sort); - y = Z3_mk_const(ctx, symbol_y, double_sort); - n = Z3_mk_fpa_numeral_double(ctx, 42.0, double_sort); + { + // 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); - symbol_q = Z3_mk_string_symbol(ctx, "q"); - q = Z3_mk_const(ctx, symbol_q, double_sort); - c1 = Z3_mk_eq(ctx, q, Z3_mk_fpa_add(ctx, rm, x, y)); + 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, q, n) }; - c2 = Z3_mk_and(ctx, 2, (Z3_ast*)&args); + 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_round_nearest_ties_to_away(ctx))) }; - c3 = Z3_mk_and(ctx, 2, (Z3_ast*)&args2); + 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_inf(ctx, y)) }; - Z3_ast args3[2] = { c3, Z3_mk_and(ctx, 3, and_args) }; - c4 = Z3_mk_and(ctx, 2, (Z3_ast*)&args3); - - - Z3_assert_cnstr(ctx, c4); - Z3_push(ctx); - - // c5 := (IEEEBV(x) == 7.0). - c5 = Z3_mk_eq(ctx, Z3_mk_fpa_to_ieee_bv(ctx, x), - Z3_mk_numeral(ctx, "4619567317775286272", Z3_mk_bv_sort(ctx, 64))); - - Z3_assert_cnstr(ctx, c5); - - Z3_model m = 0; - Z3_lbool result = Z3_check_and_get_model(ctx, &m); - switch (result) { - case Z3_L_FALSE: - printf("unsat\n"); - break; - case Z3_L_UNDEF: - printf("unknown\n"); - printf("potential model:\n%s\n", Z3_model_to_string(ctx, m)); - break; - case Z3_L_TRUE: - printf("sat\n%s\n", Z3_model_to_string(ctx, m)); - Z3_del_model(ctx, m); - break; - } - - Z3_pop(ctx, 1); - - // c6 := (IEEEBV(x) == 28.0). - c6 = Z3_mk_eq(ctx, Z3_mk_fpa_to_ieee_bv(ctx, x), - Z3_mk_numeral(ctx, "4628574517030027264", Z3_mk_bv_sort(ctx, 64))); - - Z3_assert_cnstr(ctx, c6); - Z3_push(ctx); - - m = 0; - result = Z3_check_and_get_model(ctx, &m); - switch (result) { - case Z3_L_FALSE: - printf("unsat\n"); - break; - case Z3_L_UNDEF: - printf("unknown\n"); - printf("potential model:\n%s\n", Z3_model_to_string(ctx, m)); - break; - case Z3_L_TRUE: - printf("sat\n%s\n", Z3_model_to_string(ctx, m)); - Z3_del_model(ctx, m); - break; + 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); } - 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); } From 09814128a62446d40f9aad264bce092321188c59 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 2 Jan 2015 18:57:38 +0000 Subject: [PATCH 079/118] Update MPF toString Signed-off-by: Christoph M. Wintersteiger --- src/util/mpf.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index cc4b3a35a..f5dcfc612 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1181,14 +1181,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; @@ -1218,7 +1217,7 @@ std::string mpf_manager::to_string(mpf const & x) { m_mpq_manager.display_decimal(ss, r, x.sbits); if (m_mpq_manager.is_int(r)) ss << ".0"; - ss << " " << exponent; + ss << "p" << exponent; res += ss.str(); } } From f684675a6e7bf18722ccb9d21b15768853a14cb9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 2 Jan 2015 18:58:43 +0000 Subject: [PATCH 080/118] FPA API: Added get_ebits/get_sbits + doc fixes Signed-off-by: Christoph M. Wintersteiger --- src/api/api_fpa.cpp | 20 +++++++++++++++ src/api/z3_fpa.h | 59 ++++++++++++++++++++++++++++++--------------- 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 97225f0f3..d2d4e7155 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -649,6 +649,26 @@ extern "C" { Z3_CATCH_RETURN(0); } + unsigned int Z3_API Z3_mk_fpa_get_ebits(Z3_context c, Z3_sort s) { + Z3_TRY; + LOG_Z3_mk_fpa_get_ebits(c, s); + RESET_ERROR_CODE(); + api::context * ctx = mk_c(c); + unsigned r = ctx->float_util().get_ebits(to_sort(s)); + RETURN_Z3(r); + Z3_CATCH_RETURN(0); + } + + unsigned Z3_API Z3_mk_fpa_get_sbits(Z3_context c, Z3_sort s) { + Z3_TRY; + LOG_Z3_mk_fpa_get_sbits(c, s); + RESET_ERROR_CODE(); + api::context * ctx = mk_c(c); + unsigned r = ctx->float_util().get_sbits(to_sort(s)); + RETURN_Z3(r); + 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); diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 61ee0bd7f..8208fbb2c 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -228,7 +228,7 @@ extern "C" { Z3_sort Z3_API Z3_mk_fpa_sort_128(__in Z3_context c); /** - \brief Create a NaN of sort s. + \brief Create a floating-point NaN of sort s. \param c logical context. \param s target sort @@ -266,6 +266,7 @@ extern "C" { /** \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 @@ -495,7 +496,7 @@ extern "C" { 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 + \brief Minimum of floating-point numbers. \param c logical context. \param t1 term of FloatingPoint sort. @@ -508,7 +509,7 @@ extern "C" { 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 + \brief Maximum of floating-point numbers. \param c logical context. \param t1 term of FloatingPoint sort. @@ -521,7 +522,7 @@ extern "C" { 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 + \brief Floating-point less than or equal. \param c logical context. \param t1 term of FloatingPoint sort. @@ -534,7 +535,7 @@ extern "C" { 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 + \brief Floating-point less than. \param c logical context. \param t1 term of FloatingPoint sort. @@ -547,7 +548,7 @@ extern "C" { 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 + \brief Floating-point greater than or equal. \param c logical context. \param t1 term of FloatingPoint sort. @@ -560,7 +561,7 @@ extern "C" { 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 + \brief Floating-point greater than. \param c logical context. \param t1 term of FloatingPoint sort. @@ -573,7 +574,7 @@ extern "C" { Z3_ast Z3_API Z3_mk_fpa_gt(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2); /** - \brief Floating-point equality + \brief Floating-point equality. \param c logical context. \param t1 term of FloatingPoint sort. @@ -636,7 +637,7 @@ extern "C" { 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 + \brief Predicate indicating whether t is a NaN. \param c logical context. \param t term of FloatingPoint sort. @@ -682,16 +683,15 @@ extern "C" { \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, 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 and the resulting floating-point - sort (ebits, sbits) is automatically determined. + 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 floating-point term into another floating-point term of different floating-point sort. + \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 @@ -768,8 +768,8 @@ extern "C" { \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 in unsigned 2's complement format. If necessary, the result will be - rounded according to rounding mode rm. + 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. @@ -784,8 +784,8 @@ extern "C" { \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 in signed 2's complement format. If necessary, the result will be - rounded according to rounding mode rm. + 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. @@ -797,7 +797,7 @@ extern "C" { 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 number. + \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 @@ -810,11 +810,30 @@ extern "C" { */ 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_mk_fpa_get_ebits', UINT, (_in(CONTEXT),_in(SORT))) + */ + unsigned Z3_API Z3_mk_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_mk_fpa_get_sbits', UINT, (_in(CONTEXT),_in(SORT))) + */ + unsigned Z3_API Z3_mk_fpa_get_sbits(__in Z3_context c, __in Z3_sort s); + /** \brief Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format. @@ -842,8 +861,8 @@ extern "C" { \param c logical context. \param rm term of RoundingMode sort. \param sig significand term of Real sort. - \param exp exponent term of Real sort. - \param s floating-point 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. From 3266e96e8008e1544e0ecb86717ab7314ac5c125 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 2 Jan 2015 18:59:27 +0000 Subject: [PATCH 081/118] fpa2bv slight refactoring Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 349 ++++++++++++++++--------------- src/ast/fpa/fpa2bv_converter.h | 6 +- 2 files changed, 181 insertions(+), 174 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 94538861d..d51e34058 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1873,7 +1873,7 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args m_arith_util.is_numeral(args[1]) && m_arith_util.is_numeral(args[2])) { - // Three arguments, some of them are not numerals. + // 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()); @@ -1926,191 +1926,197 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args else 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); + unsigned to_ebits = m_util.get_ebits(s); expr * bv = args[0]; int sz = m_bv_util.get_bv_size(bv); SASSERT((unsigned)sz == to_sbits + to_ebits); - + 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); } - else if (num == 2 && + else if (num == 2 && + m_util.is_rm(args[0]) && 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_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, 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); - } + 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 && + else if (num == 2 && m_util.is_rm(args[0]), m_arith_util.is_real(args[1])) { - // .. other than that, we only support rationals for to_fp - 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 + 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) { + SASSERT(m_util.is_float(s)); + 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; @@ -2119,10 +2125,8 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args 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); scoped_mpf v(m_mpf_manager); m_util.fm().set(v, ebits, sbits, rm, q.to_mpq()); @@ -2135,10 +2139,11 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args mk_triple(sgn, s, e, result); } - else - UNREACHABLE(); + else { + NOT_IMPLEMENTED_YET(); + } - SASSERT(is_well_sorted(m, 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) { diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 197c7ce9a..6a7b6e92f 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -129,7 +129,9 @@ public: 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(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_real(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); @@ -186,7 +188,7 @@ protected: 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); + app * mk_fresh_const(char const * prefix, unsigned sz); }; #endif From 3c75b700e88d04cac373e05ecef1cbd9270e4090 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 2 Jan 2015 19:03:20 +0000 Subject: [PATCH 082/118] Updates to the .NET API for FP Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Context.cs | 665 +++++++++++++++++++++++++++++++------ src/api/dotnet/FPExpr.cs | 2 +- src/api/dotnet/FPNum.cs | 2 +- src/api/dotnet/FPRMExpr.cs | 2 +- src/api/dotnet/FPRMNum.cs | 2 +- src/api/dotnet/FPRMSort.cs | 4 +- src/api/dotnet/FPSort.cs | 15 +- 7 files changed, 575 insertions(+), 117 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 69855fc4f..986efc94d 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3439,65 +3439,118 @@ namespace Microsoft.Z3 #endregion #region Floating-Point Arithmetic + + #region Rounding Modes + #region RoundingMode Sort /// - /// Create a floating point rounding mode sort. + /// Create the floating-point RoundingMode sort. /// - public FPRMSort MkFPRMSort() + public FPRMSort MkFPRoundingModeSort() { Contract.Ensures(Contract.Result() != null); return new FPRMSort(this); } - + #endregion + + #region Numerals /// - /// Create a NearestTiesToEven rounding mode numeral. + /// Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. /// - public FPRMNum MkFPRMNearestTiesToEven() + public FPRMNum MkFPRoundNearestTiesToEven() { Contract.Ensures(Contract.Result() != null); return new FPRMNum(this, Native.Z3_mk_fpa_round_nearest_ties_to_even(nCtx)); } /// - /// Create a NearestTiesToAway rounding mode numeral. + /// Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. /// - public FPRMNum MkFPRMNearestTiesToAway() + 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 TowardPositive rounding mode numeral. + /// Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode. /// - public FPRMNum MkFPRMTowardPositive() + 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 TowardNegative rounding mode numeral. + /// Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode. /// - public FPRMNum MkFPRMTowardNegative() + 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 TowardZero rounding mode numeral. + /// Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode. /// - public FPRMNum MkFPRMTowardZero() + 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 floating point sort. + /// Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode. /// - /// exponent bits in the floating point sort. - /// significand bits in the floating point sort. + 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); @@ -3505,9 +3558,83 @@ namespace Microsoft.Z3 } /// - /// Create a floating point NaN numeral. + /// 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_16(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_double(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. /// - /// floating point sort. + /// FloatingPoint sort. public FPNum MkFPNaN(FPSort s) { Contract.Ensures(Contract.Result() != null); @@ -3515,9 +3642,9 @@ namespace Microsoft.Z3 } /// - /// Create a floating point Inf numeral. + /// Create a floating-point infinity of sort s. /// - /// floating point sort. + /// FloatingPoint sort. /// indicates whether the result should be negative. public FPNum MkFPInf(FPSort s, bool negative) { @@ -3526,20 +3653,141 @@ namespace Microsoft.Z3 } /// - /// Create a floating point numeral. - /// - /// A string representing the value in decimal notation. - /// floating point sort + /// 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 new FPNum(this, Native.Z3_mk_fpa_numeral_double(this.nCtx, v, s.NativeObject)); - } + 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 significand. + /// the exponent. + /// FloatingPoint sort. + public FPNum MkFP(bool sgn, uint sig, int exp, 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 significand. + /// the exponent. + /// FloatingPoint sort. + public FPNum MkFP(bool sgn, UInt64 sig, Int64 exp, FPSort s) + { + Contract.Ensures(Contract.Result() != null); + return MkFPNumeral(sgn, sig, exp, s); + } + + #endregion + + #region Operators /// /// Floating-point absolute value /// - /// floating point term + /// floating-point term public FPExpr MkFPAbs(FPExpr t) { Contract.Ensures(Contract.Result() != null); @@ -3549,7 +3797,7 @@ namespace Microsoft.Z3 /// /// Floating-point negation /// - /// floating point term + /// floating-point term public FPExpr MkFPNeg(FPExpr t) { Contract.Ensures(Contract.Result() != null); @@ -3560,8 +3808,8 @@ namespace Microsoft.Z3 /// Floating-point addition /// /// rounding mode term - /// floating point term - /// floating point term + /// floating-point term + /// floating-point term public FPExpr MkFPAdd(FPRMExpr rm, FPExpr t1, FPExpr t2) { Contract.Ensures(Contract.Result() != null); @@ -3572,8 +3820,8 @@ namespace Microsoft.Z3 /// Floating-point subtraction /// /// rounding mode term - /// floating point term - /// floating point term + /// floating-point term + /// floating-point term public FPExpr MkFPSub(FPRMExpr rm, FPExpr t1, FPExpr t2) { Contract.Ensures(Contract.Result() != null); @@ -3584,8 +3832,8 @@ namespace Microsoft.Z3 /// Floating-point multiplication /// /// rounding mode term - /// floating point term - /// floating point term + /// floating-point term + /// floating-point term public FPExpr MkFPMul(FPRMExpr rm, FPExpr t1, FPExpr t2) { Contract.Ensures(Contract.Result() != null); @@ -3596,8 +3844,8 @@ namespace Microsoft.Z3 /// Floating-point division /// /// rounding mode term - /// floating point term - /// floating point term + /// floating-point term + /// floating-point term public FPExpr MkFPDiv(FPRMExpr rm, FPExpr t1, FPExpr t2) { Contract.Ensures(Contract.Result() != null); @@ -3611,9 +3859,9 @@ namespace Microsoft.Z3 /// The result is round((t1 * t2) + t3) /// /// rounding mode term - /// floating point term - /// floating point term - /// floating point 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); @@ -3624,7 +3872,7 @@ namespace Microsoft.Z3 /// Floating-point square root /// /// rounding mode term - /// floating point term + /// floating-point term public FPExpr MkFPSqrt(FPRMExpr rm, FPExpr t) { Contract.Ensures(Contract.Result() != null); @@ -3634,33 +3882,53 @@ namespace Microsoft.Z3 /// /// Floating-point remainder /// - /// floating point term - /// floating point term + /// 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 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)); - } - - /// - /// Floating-point less than or equal + /// Floating-point roundToIntegral. Rounds a floating-point number to + /// the closest integer, again represented as a floating-point number. /// - /// floating point term - /// floating point term + /// 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); @@ -3668,10 +3936,10 @@ namespace Microsoft.Z3 } /// - /// Floating-point less than + /// Floating-point less than. /// - /// floating point term - /// floating point term + /// floating-point term + /// floating-point term public BoolExpr MkFPLt(FPExpr t1, FPExpr t2) { Contract.Ensures(Contract.Result() != null); @@ -3679,10 +3947,10 @@ namespace Microsoft.Z3 } /// - /// Floating-point greater than or equal + /// Floating-point greater than or equal. /// - /// floating point term - /// floating point term + /// floating-point term + /// floating-point term public BoolExpr MkFPGEq(FPExpr t1, FPExpr t2) { Contract.Ensures(Contract.Result() != null); @@ -3690,10 +3958,10 @@ namespace Microsoft.Z3 } /// - /// Floating-point greater than + /// Floating-point greater than. /// - /// floating point term - /// floating point term + /// floating-point term + /// floating-point term public BoolExpr MkFPGt(FPExpr t1, FPExpr t2) { Contract.Ensures(Contract.Result() != null); @@ -3701,9 +3969,23 @@ namespace Microsoft.Z3 } /// - /// Predicate indicating whether t is a normal floating point number + /// 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 + /// floating-point term public BoolExpr MkFPIsNormal(FPExpr t) { Contract.Ensures(Contract.Result() != null); @@ -3711,9 +3993,9 @@ namespace Microsoft.Z3 } /// - /// Predicate indicating whether t is a subnormal floating point number + /// Predicate indicating whether t is a subnormal floating-point number. /// - /// floating point term + /// floating-point term public BoolExpr MkFPIsSubnormal(FPExpr t) { Contract.Ensures(Contract.Result() != null); @@ -3721,29 +4003,29 @@ namespace Microsoft.Z3 } /// - /// Predicate indicating whether t is a floating point number with zero value, i.e., +0 or -0. + /// 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) - { + /// 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 +Inf or -Inf + /// Predicate indicating whether t is a floating-point number representing +oo or -oo. /// - /// floating point term - public BoolExpr MkFPIsInf(FPExpr t) - { + /// 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 + /// Predicate indicating whether t is a NaN. /// - /// floating point term + /// floating-point term public BoolExpr MkFPIsNaN(FPExpr t) { Contract.Ensures(Contract.Result() != null); @@ -3751,45 +4033,212 @@ namespace Microsoft.Z3 } /// - /// Floating-point minimum + /// Predicate indicating whether t is a negative floating-point number. /// - /// floating point term - /// floating point term - public FPExpr MkFPMin(FPExpr t1, FPExpr t2) + /// floating-point term + public BoolExpr MkFPIsNegative(FPExpr t) { - Contract.Ensures(Contract.Result() != null); - return new FPExpr(this, Native.Z3_mk_fpa_min(this.nCtx, t1.NativeObject, t2.NativeObject)); + Contract.Ensures(Contract.Result() != null); + return new BoolExpr(this, Native.Z3_mk_fpa_is_negative(this.nCtx, t.NativeObject)); } - - /// - /// Floating-point maximium - /// - /// 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)); - } /// - /// Conversion of a floating point number to another floating-point sort s. + /// 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 - /// floating point sort s. If necessary, rounding according to rm is applied. + /// FloatingPoint sort s. If necessary, rounding according to rm is applied. /// - /// floating point sort - /// floating point rounding mode term - /// floating point term - public FPExpr MkFPToFP(FPSort s, FPRMExpr rm, FPExpr t) + /// FloatingPoint sort + /// floating-point rounding mode term + /// floating-point term + public FPExpr MkFPToFP(FPSort s, FPRMExpr rm, FPExpr t) { - Contract.Ensures(Contract.Result() != null); + 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 /// /// Wraps an AST. diff --git a/src/api/dotnet/FPExpr.cs b/src/api/dotnet/FPExpr.cs index 0bb1e4c09..cbba272d1 100644 --- a/src/api/dotnet/FPExpr.cs +++ b/src/api/dotnet/FPExpr.cs @@ -26,7 +26,7 @@ using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// - /// Floating Point Expressions + /// FloatingPoint Expressions /// public class FPExpr : Expr { diff --git a/src/api/dotnet/FPNum.cs b/src/api/dotnet/FPNum.cs index 044598e58..ab57d57c3 100644 --- a/src/api/dotnet/FPNum.cs +++ b/src/api/dotnet/FPNum.cs @@ -22,7 +22,7 @@ using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// - /// Floatiung Point Numerals + /// FloatiungPoint Numerals /// [ContractVerification(true)] public class FPNum : FPExpr diff --git a/src/api/dotnet/FPRMExpr.cs b/src/api/dotnet/FPRMExpr.cs index b95816023..92fea1ad4 100644 --- a/src/api/dotnet/FPRMExpr.cs +++ b/src/api/dotnet/FPRMExpr.cs @@ -26,7 +26,7 @@ using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// - /// Floating Point Expressions + /// FloatingPoint RoundingMode Expressions /// public class FPRMExpr : Expr { diff --git a/src/api/dotnet/FPRMNum.cs b/src/api/dotnet/FPRMNum.cs index eaf105718..7caa56f9f 100644 --- a/src/api/dotnet/FPRMNum.cs +++ b/src/api/dotnet/FPRMNum.cs @@ -22,7 +22,7 @@ using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// - /// Floatiung Point Rounding Mode Numerals + /// FloatingPoint RoundingMode Numerals /// [ContractVerification(true)] public class FPRMNum : FPRMExpr diff --git a/src/api/dotnet/FPRMSort.cs b/src/api/dotnet/FPRMSort.cs index 23d454a65..1d8334eb5 100644 --- a/src/api/dotnet/FPRMSort.cs +++ b/src/api/dotnet/FPRMSort.cs @@ -7,7 +7,7 @@ Module Name: Abstract: - Z3 Managed API: Floating Point Rounding Mode Sorts + Z3 Managed API: Rounding Mode Sort Author: @@ -23,7 +23,7 @@ using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// - /// A floating point rounding mode sort + /// The FloatingPoint RoundingMode sort /// public class FPRMSort : Sort { diff --git a/src/api/dotnet/FPSort.cs b/src/api/dotnet/FPSort.cs index a79557ae6..8d8560e53 100644 --- a/src/api/dotnet/FPSort.cs +++ b/src/api/dotnet/FPSort.cs @@ -16,17 +16,26 @@ Author: Notes: --*/ - using System; using System.Diagnostics.Contracts; namespace Microsoft.Z3 { /// - /// A floating point sort + /// FloatingPoint sort /// public class FPSort : Sort { + /// + /// The number of exponent bits. + /// + public uint EBits { get { return Native.Z3_mk_fpa_get_ebits(Context.nCtx, NativeObject); } } + + /// + /// The number of significand bits. + /// + public uint SBits { get { return Native.Z3_mk_fpa_get_ebits(Context.nCtx, NativeObject); } } + #region Internal internal FPSort(Context ctx, IntPtr obj) : base(ctx, obj) @@ -39,5 +48,5 @@ namespace Microsoft.Z3 Contract.Requires(ctx != null); } #endregion - } + } } From 263456116dde88c961900c88dc4da96b72deeb06 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 2 Jan 2015 19:05:40 +0000 Subject: [PATCH 083/118] Added fpa2bv_rewriter_params Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_rewriter_params.pyg | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/ast/fpa/fpa2bv_rewriter_params.pyg 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)"), + )) From 6bfc9878fb90c73cb80b7b80f725f70c9db01238 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 3 Jan 2015 15:13:57 +0000 Subject: [PATCH 084/118] FPA API cosmetics Signed-off-by: Christoph M. Wintersteiger --- src/api/z3_fpa.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 8208fbb2c..043d43e2f 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -821,18 +821,18 @@ extern "C" { \param s FloatingPoint sort. - def_API('Z3_mk_fpa_get_ebits', UINT, (_in(CONTEXT),_in(SORT))) + def_API('Z3_fpa_get_ebits', UINT, (_in(CONTEXT),_in(SORT))) */ - unsigned Z3_API Z3_mk_fpa_get_ebits(__in Z3_context c, __in Z3_sort s); + 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_mk_fpa_get_sbits', UINT, (_in(CONTEXT),_in(SORT))) + def_API('Z3_fpa_get_sbits', UINT, (_in(CONTEXT),_in(SORT))) */ - unsigned Z3_API Z3_mk_fpa_get_sbits(__in Z3_context c, __in Z3_sort s); + unsigned Z3_API Z3_fpa_get_sbits(__in Z3_context c, __in Z3_sort s); /** \brief Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format. From 3a2db1c793289014f2a8d487b9bbbbb23ea57e56 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 3 Jan 2015 15:15:55 +0000 Subject: [PATCH 085/118] FPA API cosmetics Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/FPSort.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/FPSort.cs b/src/api/dotnet/FPSort.cs index 8d8560e53..e1ad62d49 100644 --- a/src/api/dotnet/FPSort.cs +++ b/src/api/dotnet/FPSort.cs @@ -29,12 +29,12 @@ namespace Microsoft.Z3 /// /// The number of exponent bits. /// - public uint EBits { get { return Native.Z3_mk_fpa_get_ebits(Context.nCtx, NativeObject); } } + 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_mk_fpa_get_ebits(Context.nCtx, NativeObject); } } + public uint SBits { get { return Native.Z3_fpa_get_sbits(Context.nCtx, NativeObject); } } #region Internal internal FPSort(Context ctx, IntPtr obj) From cf4dc527c420a1e5e221f47aec7757fd1b0773ff Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 3 Jan 2015 16:49:42 +0000 Subject: [PATCH 086/118] .NET FPA API bugfix Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Context.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 986efc94d..f3e6220cf 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3590,7 +3590,7 @@ namespace Microsoft.Z3 public FPSort MkFPSort32() { Contract.Ensures(Contract.Result() != null); - return new FPSort(this, Native.Z3_mk_fpa_sort_16(nCtx)); + return new FPSort(this, Native.Z3_mk_fpa_sort_32(nCtx)); } /// @@ -3617,7 +3617,7 @@ namespace Microsoft.Z3 public FPSort MkFPSortQuadruple() { Contract.Ensures(Contract.Result() != null); - return new FPSort(this, Native.Z3_mk_fpa_sort_double(nCtx)); + return new FPSort(this, Native.Z3_mk_fpa_sort_quadruple(nCtx)); } /// From fa26e2423ef6f6c674b06a4b465f54baef2d96bf Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 3 Jan 2015 16:50:31 +0000 Subject: [PATCH 087/118] Java API: Added FPA Signed-off-by: Christoph M. Wintersteiger --- src/api/java/AST.java | 4 +- src/api/java/ASTMap.java | 4 +- src/api/java/ASTVector.java | 4 +- src/api/java/AlgebraicNum.java | 11 +- src/api/java/Context.java | 878 +++++++++++++++++++++++-- src/api/java/Expr.java | 10 +- src/api/java/Fixedpoint.java | 4 +- src/api/java/Global.java | 4 +- src/api/java/InterpolationContext.java | 2 +- src/api/java/Model.java | 8 +- src/api/java/Solver.java | 12 +- 11 files changed, 868 insertions(+), 73 deletions(-) diff --git a/src/api/java/AST.java b/src/api/java/AST.java index a201d5697..579d4b24d 100644 --- a/src/api/java/AST.java +++ b/src/api/java/AST.java @@ -28,7 +28,7 @@ public class AST extends Z3Object /** * Object comparison. - * another AST + * @param o another AST **/ public boolean equals(Object o) { @@ -46,7 +46,7 @@ public class AST extends Z3Object } /** - * Object Comparison. Another AST + * Object Comparison. @param other Another AST * * @return Negative if the object should be sorted before , positive if after else zero. diff --git a/src/api/java/ASTMap.java b/src/api/java/ASTMap.java index 6a4e6d56f..a26140a3d 100644 --- a/src/api/java/ASTMap.java +++ b/src/api/java/ASTMap.java @@ -39,7 +39,7 @@ class ASTMap extends Z3Object /** * Finds the value associated with the key . * This function signs an error when is not a key in - * the map. An AST + * the map. @param k An AST * * @throws Z3Exception **/ @@ -51,7 +51,7 @@ class ASTMap extends Z3Object /** * Stores or replaces a new key/value pair in the map. The - * key AST The value AST + * key AST @param v The value AST **/ public void insert(AST k, AST v) throws Z3Exception { diff --git a/src/api/java/ASTVector.java b/src/api/java/ASTVector.java index 07b7dbf56..99879848f 100644 --- a/src/api/java/ASTVector.java +++ b/src/api/java/ASTVector.java @@ -33,7 +33,7 @@ class ASTVector extends Z3Object /** * Retrieves the i-th object in the vector. May throw an * IndexOutOfBoundsException when is out of - * range. Index + * range. @param i Index * * @return An AST * @throws Z3Exception @@ -62,7 +62,7 @@ class ASTVector extends Z3Object /** * Add the AST to the back of the vector. The size is - * increased by 1. An AST + * increased by 1. @param a An AST **/ public void push(AST a) throws Z3Exception { diff --git a/src/api/java/AlgebraicNum.java b/src/api/java/AlgebraicNum.java index 340f37f80..a45e5a58e 100644 --- a/src/api/java/AlgebraicNum.java +++ b/src/api/java/AlgebraicNum.java @@ -25,7 +25,7 @@ public class AlgebraicNum extends ArithExpr /** * Return a upper bound for a given real algebraic number. The interval * isolating the number is smaller than 1/10^. - * the + * @see Expr.IsAlgebraicNumber the * precision of the result * * @return A numeral Expr of sort Real @@ -33,14 +33,17 @@ public class AlgebraicNum extends ArithExpr public RatNum toUpper(int precision) throws Z3Exception { - return new RatNum(getContext(), Native.getAlgebraicNumberUpper(getContext() - .nCtx(), getNativeObject(), precision)); + return new RatNum(getContext(), + Native.getAlgebraicNumberUpper( + getContext().nCtx(), + getNativeObject(), + precision)); } /** * Return a lower bound for the given real algebraic number. The interval * isolating the number is smaller than 1/10^. - * + * @see Expr.IsAlgebraicNumber @param precision * * @return A numeral Expr of sort Real **/ diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 4fbd79be2..cd3b9bebd 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -294,9 +294,9 @@ public class Context extends IDisposable } /** - * Create a datatype constructor. + * Create a datatype constructor. @param name @param fieldNames @param sortRefs * * @return **/ @@ -363,7 +363,7 @@ public class Context extends IDisposable } /** - * Create mutually recursive data-types. * * @return @@ -429,7 +429,7 @@ public class Context extends IDisposable /** * Creates a fresh function declaration with a name prefixed with . . @see MkFuncDecl(string,Sort,Sort) **/ public FuncDecl mkFreshFuncDecl(String prefix, Sort[] domain, Sort range) @@ -464,8 +464,8 @@ public class Context extends IDisposable /** * Creates a fresh constant function declaration with a name prefixed with - * . - * + * . @see MkFuncDecl(string,Sort,Sort) + * @see MkFuncDecl(string,Sort[],Sort) **/ public FuncDecl mkFreshConstDecl(String prefix, Sort range) throws Z3Exception @@ -477,7 +477,7 @@ public class Context extends IDisposable /** * Creates a new bound variable. The de-Bruijn index of - * the variable The sort of the variable + * the variable @param ty The sort of the variable **/ public Expr mkBound(int index, Sort ty) throws Z3Exception { @@ -686,7 +686,7 @@ public class Context extends IDisposable /** * Create an expression representing an if-then-else: * ite(t1, t2, t3). An expression with Boolean - * sort An expression An + * sort @param t2 An expression An * expression with the same sort as **/ public Expr mkITE(BoolExpr t1, Expr t2, Expr t3) throws Z3Exception @@ -1654,7 +1654,7 @@ public class Context extends IDisposable * The node a must have an array sort * [domain -> range], and i must have the sort * domain. The sort of the result is range. - * + * @see MkArraySort"/> + * cref="MkArraySort"/> @see MkSelect **/ public ArrayExpr mkStore(ArrayExpr a, Expr i, Expr v) throws Z3Exception { @@ -1693,7 +1693,7 @@ public class Context extends IDisposable /** * Create a constant array. The resulting term is an array, such * that a selecton an arbitrary index produces the value - * v. + * v. @see MkArraySort"/> + * [domain_i -> range]. @see MkArraySort @see MkStore **/ public ArrayExpr mkMap(FuncDecl f, ArrayExpr... args) throws Z3Exception { @@ -1899,7 +1899,7 @@ public class Context extends IDisposable * Create a Term of a given sort. This function can be use to create * numerals that fit in a machine integer. It is slightly faster than * MakeNumeral since it is not necessary to parse a string. - * Value of the numeral Sort of the + * @param v Value of the numeral Sort of the * numeral * * @return A Term with value and type MakeNumeral since it is not necessary to parse a string. - * Value of the numeral Sort of the + * @param v Value of the numeral Sort of the * numeral * * @return A Term with value and type numerator of - * rational. denominator of rational. + * rational. @param den denominator of rational. * * @return A Term with value / - * and sort Real + * and sort Real @see MkNumeral(string, Sort) **/ public RatNum mkReal(int num, int den) throws Z3Exception { @@ -1959,7 +1959,7 @@ public class Context extends IDisposable } /** - * Create a real numeral. value of the numeral. + * Create a real numeral. @param v value of the numeral. * * @return A Term with value and sort Real **/ @@ -1971,7 +1971,7 @@ public class Context extends IDisposable } /** - * Create a real numeral. value of the numeral. + * Create a real numeral. @param v value of the numeral. * * @return A Term with value and sort Real **/ @@ -1994,7 +1994,7 @@ public class Context extends IDisposable } /** - * Create an integer numeral. value of the numeral. + * Create an integer numeral. @param v value of the numeral. * * @return A Term with value and sort Integer **/ @@ -2006,7 +2006,7 @@ public class Context extends IDisposable } /** - * Create an integer numeral. value of the numeral. + * Create an integer numeral. @param v value of the numeral. * * @return A Term with value and sort Integer **/ @@ -2030,7 +2030,7 @@ public class Context extends IDisposable /** * Create a bit-vector numeral. value of the - * numeral. the size of the bit-vector + * numeral. @param size the size of the bit-vector **/ public BitVecNum mkBV(int v, int size) throws Z3Exception { @@ -2040,7 +2040,7 @@ public class Context extends IDisposable /** * Create a bit-vector numeral. value of the - * numeral. * the size of the bit-vector + * numeral. * @param size the size of the bit-vector **/ public BitVecNum mkBV(long v, int size) throws Z3Exception { @@ -2056,7 +2056,7 @@ public class Context extends IDisposable * 'names' of the bound variables, and is the body * of the quantifier. Quantifiers are associated with weights indicating the * importance of using the quantifier during instantiation. - * the sorts of the bound variables. names of the bound variables the * body of the quantifier. quantifiers are * associated with weights indicating the importance of using the quantifier @@ -2154,8 +2154,8 @@ public class Context extends IDisposable * subexpressions only once, use the Z3_PRINT_LOW_LEVEL mode. To print in * way that conforms to SMT-LIB standards and uses let expressions to share * common sub-expressions use Z3_PRINT_SMTLIB_COMPLIANT. + * cref="AST.ToString()"/> @see Pattern.ToString() @see Sort.ToString() **/ public void setPrintMode(Z3_ast_print_mode value) throws Z3Exception { @@ -2165,7 +2165,7 @@ public class Context extends IDisposable /** * Convert a benchmark into an SMT-LIB formatted string. Name of the benchmark. The argument is optional. - * The benchmark logic. The status string (sat, unsat, or unknown) Other attributes, such as source, difficulty or * category. Auxiliary @@ -2809,12 +2809,11 @@ public class Context extends IDisposable if (logic == null) return new Solver(this, Native.mkSolver(nCtx())); else - return new Solver(this, Native.mkSolverForLogic(nCtx(), - logic.getNativeObject())); + return new Solver(this, Native.mkSolverForLogic(nCtx(), logic.getNativeObject())); } /** - * Creates a new (incremental) solver. + * Creates a new (incremental) solver. @see MkSolver(Symbol) **/ public Solver mkSolver(String logic) throws Z3Exception { @@ -2839,8 +2838,7 @@ public class Context extends IDisposable public Solver mkSolver(Tactic t) throws Z3Exception { - return new Solver(this, Native.mkSolverFromTactic(nCtx(), - t.getNativeObject())); + return new Solver(this, Native.mkSolverFromTactic(nCtx(), t.getNativeObject())); } /** @@ -2851,15 +2849,807 @@ public class Context extends IDisposable return new Fixedpoint(this); } + + /** Begin Floating-Point Arithmetic **/ + + /** Rounding Modes: RoundingMode Sort **/ + + /** + * Create the floating-point RoundingMode sort. + * @throws Z3Exception on error + **/ + public FPRMSort mkFPRoundingModeSort() throws Z3Exception + { + return new FPRMSort(this); + } + + /** Rounding Modes: Numerals **/ + + /** + * Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. + * @throws Z3Exception on error + **/ + public FPRMNum mkFPRoundNearestTiesToEven() throws Z3Exception + { + return new FPRMNum(this, Native.mkFpaRoundNearestTiesToEven(nCtx())); + } + + /** + * Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. + * @throws Z3Exception + **/ + public FPRMNum mkFPRNE() throws Z3Exception + { + return new FPRMNum(this, Native.mkFpaRne(nCtx())); + } + + /** + * Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode. + * @throws Z3Exception + **/ + public FPRMNum mkFPRoundNearestTiesToAway() throws Z3Exception + { + return new FPRMNum(this, Native.mkFpaRoundNearestTiesToAway(nCtx())); + } + + /** + * Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode. + * @throws Z3Exception + **/ + public FPRMNum mkFPRNA() throws Z3Exception + { + return new FPRMNum(this, Native.mkFpaRna(nCtx())); + } + + /** + * Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode. + * @throws Z3Exception + **/ + public FPRMNum mkFPRoundTowardPositive() throws Z3Exception + { + return new FPRMNum(this, Native.mkFpaRoundTowardPositive(nCtx())); + } + + /** + * Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode. + * @throws Z3Exception + **/ + public FPRMNum mkFPRTP() throws Z3Exception + { + return new FPRMNum(this, Native.mkFpaRtp(nCtx())); + } + + /** + * Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode. + * @throws Z3Exception + **/ + public FPRMNum mkFPRoundTowardNegative() throws Z3Exception + { + return new FPRMNum(this, Native.mkFpaRoundTowardNegative(nCtx())); + } + + /** + * Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode. + * @throws Z3Exception + **/ + public FPRMNum mkFPRTN() throws Z3Exception + { + return new FPRMNum(this, Native.mkFpaRtn(nCtx())); + } + + /** + * Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode. + * @throws Z3Exception + **/ + public FPRMNum mkFPRoundTowardZero() throws Z3Exception + { + return new FPRMNum(this, Native.mkFpaRoundTowardZero(nCtx())); + } + + /** + * Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode. + * @throws Z3Exception + **/ + public FPRMNum mkFPRTZ() throws Z3Exception + { + return new FPRMNum(this, Native.mkFpaRtz(nCtx())); + } + + /** FloatingPoint Sorts **/ + + /** + * Create a FloatingPoint sort. + * @param ebits exponent bits in the FloatingPoint sort. + * @param sbits significand bits in the FloatingPoint sort. + * @throws Z3Exception + **/ + public FPSort mkFPSort(int ebits, int sbits) throws Z3Exception + { + return new FPSort(this, ebits, sbits); + } + + /** + * Create the half-precision (16-bit) FloatingPoint sort. + * @throws Z3Exception + **/ + public FPSort mkFPSortHalf() throws Z3Exception + { + return new FPSort(this, Native.mkFpaSortHalf(nCtx())); + } + + /** + * Create the half-precision (16-bit) FloatingPoint sort. + * @throws Z3Exception + **/ + public FPSort mkFPSort16() throws Z3Exception + { + return new FPSort(this, Native.mkFpaSort16(nCtx())); + } + + /** + * Create the single-precision (32-bit) FloatingPoint sort. + * @throws Z3Exception + **/ + public FPSort mkFPSortSingle() throws Z3Exception + { + return new FPSort(this, Native.mkFpaSortSingle(nCtx())); + } + + /** + * Create the single-precision (32-bit) FloatingPoint sort. + * @throws Z3Exception + **/ + public FPSort mkFPSort32() throws Z3Exception + { + return new FPSort(this, Native.mkFpaSort16(nCtx())); + } + + /** + * Create the double-precision (64-bit) FloatingPoint sort. + * @throws Z3Exception + **/ + public FPSort mkFPSortDouble() throws Z3Exception + { + return new FPSort(this, Native.mkFpaSortDouble(nCtx())); + } + + /** + * Create the double-precision (64-bit) FloatingPoint sort. + * @throws Z3Exception + **/ + public FPSort mkFPSort64() throws Z3Exception + { + return new FPSort(this, Native.mkFpaSort64(nCtx())); + } + + /** + * Create the quadruple-precision (128-bit) FloatingPoint sort. + * @throws Z3Exception + **/ + public FPSort mkFPSortQuadruple() throws Z3Exception + { + return new FPSort(this, Native.mkFpaSortQuadruple(nCtx())); + } + + /** + * Create the quadruple-precision (128-bit) FloatingPoint sort. + * @throws Z3Exception + **/ + public FPSort mkFPSort128() throws Z3Exception + { + return new FPSort(this, Native.mkFpaSort128(nCtx())); + } + + /** FloatingPoint Numerals **/ + + /** + * Create a NaN of sort s. + * @throws Z3Exception + * @param s FloatingPoint sort. + **/ + public FPNum mkFPNaN(FPSort s) throws Z3Exception + { + return new FPNum(this, Native.mkFpaNan(nCtx(), s.getNativeObject())); + } + + /** + * Create a floating-point infinity of sort s. + * @throws Z3Exception + * @param s FloatingPoint sort. + * @param negative indicates whether the result should be negative. + **/ + public FPNum mkFPInf(FPSort s, boolean negative) throws Z3Exception + { + return new FPNum(this, Native.mkFpaInf(nCtx(), s.getNativeObject(), negative)); + } + + /** + * Create a floating-point zero of sort s. + * @throws Z3Exception + * @param s FloatingPoint sort. + * @param negative indicates whether the result should be negative. + **/ + public FPNum mkFPZero(FPSort s, boolean negative) throws Z3Exception + { + return new FPNum(this, Native.mkFpaZero(nCtx(), s.getNativeObject(), negative)); + } + + /** + * Create a numeral of FloatingPoint sort from a float. + * @throws Z3Exception + * @param v numeral value. + * @param s FloatingPoint sort. + **/ + public FPNum mkFPNumeral(float v, FPSort s) throws Z3Exception + { + return new FPNum(this, Native.mkFpaNumeralFloat(nCtx(), v, s.getNativeObject())); + } + + /** + * Create a numeral of FloatingPoint sort from a float. + * @throws Z3Exception + * @param v numeral value. + * @param s FloatingPoint sort. + **/ + public FPNum mkFPNumeral(double v, FPSort s) throws Z3Exception + { + return new FPNum(this, Native.mkFpaNumeralDouble(nCtx(), v, s.getNativeObject())); + } + + /** + * Create a numeral of FloatingPoint sort from an int. + * @param v numeral value. + * @param s FloatingPoint sort. + * @throws Z3Exception + **/ + public FPNum mkFPNumeral(int v, FPSort s) throws Z3Exception + { + return new FPNum(this, Native.mkFpaNumeralInt(nCtx(), v, s.getNativeObject())); + } + + /** + * Create a numeral of FloatingPoint sort from a sign bit and two integers. + * @param sgn the sign. + * @param sig the significand. + * @param exp the exponent. + * @param s FloatingPoint sort. + * @throws Z3Exception + **/ + public FPNum mkFPNumeral(boolean sgn, int sig, int exp, FPSort s) throws Z3Exception + { + return new FPNum(this, Native.mkFpaNumeralUintInt(nCtx(), sgn, sig, exp, s.getNativeObject())); + } + + /** + * Create a numeral of FloatingPoint sort from a sign bit and two long integers. + * @param sgn the sign. + * @param sig the significand. + * @param exp the exponent. + * @param s FloatingPoint sort. + * @throws Z3Exception + **/ + public FPNum mkFPNumeral(boolean sgn, long sig, long exp, FPSort s) throws Z3Exception + { + return new FPNum(this, Native.mkFpaNumeralUint64Int64(nCtx(), sgn, sig, exp, s.getNativeObject())); + } + + /** + * Create a numeral of FloatingPoint sort from a float. + * @param v numeral value. + * @param s FloatingPoint sort. + * @throws Z3Exception + **/ + public FPNum mkFP(float v, FPSort s) throws Z3Exception + { + return mkFPNumeral(v, s); + } + + /** + * Create a numeral of FloatingPoint sort from a float. + * @param v numeral value. + * @param s FloatingPoint sort. + * @throws Z3Exception + **/ + public FPNum mkFP(double v, FPSort s) throws Z3Exception + { + return mkFPNumeral(v, s); + } + + /** + * Create a numeral of FloatingPoint sort from an int. + * @param v numeral value. + * @param s FloatingPoint sort. + * @throws Z3Exception + **/ + public FPNum mkFP(int v, FPSort s) throws Z3Exception + { + return mkFPNumeral(v, s); + } + + /** + * Create a numeral of FloatingPoint sort from a sign bit and two integers. + * @param sgn the sign. + * @param sig the significand. + * @param exp the exponent. + * @param s FloatingPoint sort. + * @throws Z3Exception + **/ + public FPNum mkFP(boolean sgn, int sig, int exp, FPSort s) throws Z3Exception + { + return mkFPNumeral(sgn, sig, exp, s); + } + + /** + * Create a numeral of FloatingPoint sort from a sign bit and two 64-bit integers. + * @param sgn the sign. + * @param sig the significand. + * @param exp the exponent. + * @param s FloatingPoint sort. + * @throws Z3Exception + **/ + public FPNum mkFP(boolean sgn, long sig, long exp, FPSort s) throws Z3Exception + { + return mkFPNumeral(sgn, sig, exp, s); + } + + /** FloatingPoint Operators **/ + + /** + * Floating-point absolute value + * @param t floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPAbs(FPExpr t) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaAbs(nCtx(), t.getNativeObject())); + } + + /** + * Floating-point negation + * @param t floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPNeg(FPExpr t) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaNeg(nCtx(), t.getNativeObject())); + } + + /** + * Floating-point addition + * @param rm rounding mode term + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPAdd(FPRMExpr rm, FPExpr t1, FPExpr t2) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaAdd(nCtx(), rm.getNativeObject(), t1.getNativeObject(), t2.getNativeObject())); + } + + /** + * Floating-point subtraction + * @param rm rounding mode term + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPSub(FPRMExpr rm, FPExpr t1, FPExpr t2) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaSub(nCtx(), rm.getNativeObject(), t1.getNativeObject(), t2.getNativeObject())); + } + + /** + * Floating-point multiplication + * @param rm rounding mode term + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPMul(FPRMExpr rm, FPExpr t1, FPExpr t2) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaMul(nCtx(), rm.getNativeObject(), t1.getNativeObject(), t2.getNativeObject())); + } + + /** + * Floating-point division + * @param rm rounding mode term + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPDiv(FPRMExpr rm, FPExpr t1, FPExpr t2) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaDiv(nCtx(), rm.getNativeObject(), t1.getNativeObject(), t2.getNativeObject())); + } + + /** + * Floating-point fused multiply-add + * + * Remarks: The result is round((t1 * t2) + t3) + * @param rm rounding mode term + * @param t1 floating-point term + * @param t2 floating-point term + * @param t3 floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPFMA(FPRMExpr rm, FPExpr t1, FPExpr t2, FPExpr t3) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaFma(nCtx(), rm.getNativeObject(), t1.getNativeObject(), t2.getNativeObject(), t3.getNativeObject())); + } + + /** + * Floating-point square root + * @param rm rounding mode term + * @param t floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPSqrt(FPRMExpr rm, FPExpr t) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaSqrt(nCtx(), rm.getNativeObject(), t.getNativeObject())); + } + + /** + * Floating-point remainder + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPRem(FPExpr t1, FPExpr t2) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaRem(nCtx(), t1.getNativeObject(), t2.getNativeObject())); + } /** - * Wraps an AST. This function is used for transitions between + * Floating-point roundToIntegral. Rounds a floating-point number to + * the closest integer, again represented as a floating-point number. + * @param rm term of RoundingMode sort + * @param t2 floating-point term + * @throws Z3Exception + */ + public FPExpr mkFPRoundToIntegral(FPRMExpr rm, FPExpr t) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaRoundToIntegral(nCtx(), rm.getNativeObject(), t.getNativeObject())); + } + + /** + * Minimum of floating-point numbers. + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPMin(FPExpr t1, FPExpr t2) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaMin(nCtx(), t1.getNativeObject(), t2.getNativeObject())); + } + + /** + * Maximum of floating-point numbers. + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPMax(FPExpr t1, FPExpr t2) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaMax(nCtx(), t1.getNativeObject(), t2.getNativeObject())); + } + + /** + * Floating-point less than or equal. + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPLEq(FPExpr t1, FPExpr t2) throws Z3Exception + { + + return new BoolExpr(this, Native.mkFpaLeq(nCtx(), t1.getNativeObject(), t2.getNativeObject())); + } + + /** + * Floating-point less than. + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPLt(FPExpr t1, FPExpr t2) throws Z3Exception + { + + return new BoolExpr(this, Native.mkFpaLt(nCtx(), t1.getNativeObject(), t2.getNativeObject())); + } + + /** + * Floating-point greater than or equal. + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPGEq(FPExpr t1, FPExpr t2) throws Z3Exception + { + + return new BoolExpr(this, Native.mkFpaGeq(nCtx(), t1.getNativeObject(), t2.getNativeObject())); + } + + /** + * Floating-point greater than. + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPGt(FPExpr t1, FPExpr t2) throws Z3Exception + { + + return new BoolExpr(this, Native.mkFpaGt(nCtx(), t1.getNativeObject(), t2.getNativeObject())); + } + + /** + * Floating-point equality. + * + * Remarks: Note that this is IEEE 754 equality (as opposed to standard =). + * @param t1 floating-point term + * @param t2 floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPEq(FPExpr t1, FPExpr t2) throws Z3Exception + { + return new BoolExpr(this, Native.mkFpaEq(nCtx(), t1.getNativeObject(), t2.getNativeObject())); + } + + /** + * Predicate indicating whether t is a normal floating-point number. + * @param t floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPIsNormal(FPExpr t) throws Z3Exception + { + + return new BoolExpr(this, Native.mkFpaIsNormal(nCtx(), t.getNativeObject())); + } + + /** + * Predicate indicating whether t is a subnormal floating-point number. + * @param t floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPIsSubnormal(FPExpr t) throws Z3Exception + { + return new BoolExpr(this, Native.mkFpaIsSubnormal(nCtx(), t.getNativeObject())); + } + + /** + * Predicate indicating whether t is a floating-point number with zero value, i.e., +0 or -0. + * @param t floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPIsZero(FPExpr t) throws Z3Exception + { + return new BoolExpr(this, Native.mkFpaIsZero(nCtx(), t.getNativeObject())); + } + + /** + * Predicate indicating whether t is a floating-point number representing +oo or -oo. + * @param t floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPIsInfinite(FPExpr t) throws Z3Exception + { + return new BoolExpr(this, Native.mkFpaIsInfinite(nCtx(), t.getNativeObject())); + } + + /** + * Predicate indicating whether t is a NaN. + * @param t floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPIsNaN(FPExpr t) throws Z3Exception + { + return new BoolExpr(this, Native.mkFpaIsNan(nCtx(), t.getNativeObject())); + } + + /** + * Predicate indicating whether t is a negative floating-point number. + * @param t floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPIsNegative(FPExpr t) throws Z3Exception + { + return new BoolExpr(this, Native.mkFpaIsNegative(nCtx(), t.getNativeObject())); + } + + /** + * Predicate indicating whether t is a positive floating-point number. + * @param t floating-point term + * @throws Z3Exception + **/ + public BoolExpr mkFPIsPositive(FPExpr t) throws Z3Exception + { + return new BoolExpr(this, Native.mkFpaIsPositive(nCtx(), t.getNativeObject())); + } + + /** Conversions to FloatingPoint terms **/ + + /** + * Create an expression of FloatingPoint sort from three bit-vector expressions. + * + * Remarks: 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. + * @param sgn bit-vector term (of size 1) representing the sign. + * @param sig bit-vector term representing the significand. + * @param exp bit-vector term representing the exponent. + * @throws Z3Exception + **/ + public FPExpr mkFP(BitVecExpr sgn, BitVecExpr sig, BitVecExpr exp) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaFp(nCtx(), sgn.getNativeObject(), sig.getNativeObject(), exp.getNativeObject())); + } + + /** + * Conversion of a single IEEE 754-2008 bit-vector into a floating-point number. + * + * Remarks: 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. + * @param bv bit-vector value (of size m). + * @param s FloatingPoint sort (ebits+sbits == m) + * @throws Z3Exception + **/ + public FPExpr mkFPToFP(BitVecExpr bv, FPSort s) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaToFpBv(nCtx(), bv.getNativeObject(), s.getNativeObject())); + } + + /** + * Conversion of a FloatingPoint term into another term of different FloatingPoint sort. + * + * Remarks: 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 rm RoundingMode term. + * @param t FloatingPoint term. + * @param s FloatingPoint sort. + * @throws Z3Exception + **/ + public FPExpr mkFPToFP(FPRMExpr rm, FPExpr t, FPSort s) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaToFpFloat(nCtx(), rm.getNativeObject(), t.getNativeObject(), s.getNativeObject())); + } + + /** + * Conversion of a term of real sort into a term of FloatingPoint sort. + * + * Remarks: 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 rm RoundingMode term. + * @param t term of Real sort. + * @param s FloatingPoint sort. + * @throws Z3Exception + **/ + public FPExpr mkFPToFP(FPRMExpr rm, RealExpr t, FPSort s) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaToFpReal(nCtx(), rm.getNativeObject(), t.getNativeObject(), s.getNativeObject())); + } + + /** + * Conversion of a 2's complement signed bit-vector term into a term of FloatingPoint sort. + * + * Remarks: 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. + * @param rm RoundingMode term. + * @param t term of bit-vector sort. + * @param s FloatingPoint sort. + * @param signed flag indicating whether t is interpreted as signed or unsigned bit-vector. + * @throws Z3Exception + **/ + public FPExpr mkFPToFP(FPRMExpr rm, BitVecExpr t, FPSort s, boolean signed) throws Z3Exception + { + if (signed) + return new FPExpr(this, Native.mkFpaToFpSigned(nCtx(), rm.getNativeObject(), t.getNativeObject(), s.getNativeObject())); + else + return new FPExpr(this, Native.mkFpaToFpUnsigned(nCtx(), rm.getNativeObject(), t.getNativeObject(), s.getNativeObject())); + } + + /** + * Conversion of a floating-point number to another FloatingPoint sort s. + * + * Remarks: 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. + * @param s FloatingPoint sort + * @param rm floating-point rounding mode term + * @param t floating-point term + * @throws Z3Exception + **/ + public FPExpr mkFPToFP(FPSort s, FPRMExpr rm, FPExpr t) throws Z3Exception + { + return new FPExpr(this, Native.mkFpaToFpFloat(nCtx(), s.getNativeObject(), rm.getNativeObject(), t.getNativeObject())); + } + + /** Conversions from FloatingPoint terms **/ + + /** + * Conversion of a floating-point term into a bit-vector. + * + * Remarks: 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. + * @param rm RoundingMode term. + * @param t FloatingPoint term + * @param sz Size of the resulting bit-vector. + * @param signed Indicates whether the result is a signed or unsigned bit-vector. + * @throws Z3Exception + **/ + public BitVecExpr mkFPToBV(FPRMExpr rm, FPExpr t, int sz, boolean signed) throws Z3Exception + { + if (signed) + return new BitVecExpr(this, Native.mkFpaToSbv(nCtx(), rm.getNativeObject(), t.getNativeObject(), sz)); + else + return new BitVecExpr(this, Native.mkFpaToUbv(nCtx(), rm.getNativeObject(), t.getNativeObject(), sz)); + } + + /** + * Conversion of a floating-point term into a real-numbered term. + * + * Remarks: 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 t FloatingPoint term + * @throws Z3Exception + **/ + public RealExpr mkFPToReal(FPExpr t) throws Z3Exception + { + return new RealExpr(this, Native.mkFpaToReal(nCtx(), t.getNativeObject())); + } + + /** Z3-specific extensions **/ + + /** + * Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format. + * + * Remarks: 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. + * @param t FloatingPoint term. + * @throws Z3Exception + **/ + public BitVecExpr mkFPToIEEEBV(FPExpr t) throws Z3Exception + { + return new BitVecExpr(this, Native.mkFpaToIeeeBv(nCtx(), t.getNativeObject())); + } + + /** + * Conversion of a real-sorted significand and an integer-sorted exponent into a term of FloatingPoint sort. + * + * Remarks: 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 rm RoundingMode term. + * @param sig Significand term of Real sort. + * @param exp Exponent term of Int sort. + * @param s FloatingPoint sort. + * @throws Z3Exception + **/ + public BitVecExpr mkFPToFP(FPRMExpr rm, RealExpr sig, IntExpr exp, FPSort s) throws Z3Exception + { + return new BitVecExpr(this, Native.mkFpaToFpRealInt(nCtx(), rm.getNativeObject(), sig.getNativeObject(), exp.getNativeObject(), s.getNativeObject())); + } + + /** End Floating-Point Arithmetic **/ + + /** + * Wraps an AST. + * Remarks: This function is used for transitions between * native and managed objects. Note that - * must be a native object obtained from Z3 (e.g., through ) and that it must have a correct reference count (see - * e.g., . The native pointer to - * wrap. + * must be a native object obtained from Z3 (e.g., through {@code unwrapAST}) + * and that it must have a correct reference count. + * @see Native.incRef + * @see wnwrapAST + * The native pointer to wrap. **/ public AST wrapAST(long nativeObject) throws Z3Exception { @@ -2868,13 +3658,15 @@ public class Context extends IDisposable } /** - * Unwraps an AST. This function is used for transitions between + * Unwraps an AST. + * Remarks: This function is used for transitions between * native and managed objects. It returns the native pointer to the AST. * Note that AST objects are reference counted and unwrapping an AST * disables automatic reference counting, i.e., all references to the IntPtr - * that is returned must be handled externally and through native calls (see - * e.g., ). The AST to unwrap. + * that is returned must be handled externally and through native calls + * @see Native.incRef + * @see wrapAST + * @param a The AST to unwrap. **/ public long unwrapAST(AST a) { diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index a4c669dad..6a7241e98 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -40,8 +40,8 @@ public class Expr extends AST /** * Returns a simplified version of the expression * A set of - * parameters a Params object to configure the simplifier - * + * parameters @param p a Params object to configure the simplifier + * @see Context.SimplifyHelp **/ public Expr simplify(Params p) throws Z3Exception { @@ -133,7 +133,7 @@ public class Expr extends AST /** * Substitute every occurrence of from in the expression with - * to. + * to. @see Substitute(Expr[],Expr[]) **/ public Expr substitute(Expr from, Expr to) throws Z3Exception { @@ -157,7 +157,7 @@ public class Expr extends AST /** * Translates (copies) the term to the Context . - * A context + * @param ctx A context * * @return A copy of the term which is associated with @@ -1682,7 +1682,7 @@ public class Expr extends AST * Indicates whether the term is a relational clone (copy) Create * a fresh copy (clone) of a relation. The function is logically the * identity, but in the context of a register machine allows for terms of - * kind to perform destructive updates to + * kind @see IsRelationUnion to perform destructive updates to * the first argument. **/ public boolean isRelationClone() throws Z3Exception diff --git a/src/api/java/Fixedpoint.java b/src/api/java/Fixedpoint.java index 57e1e105a..37653bbd0 100644 --- a/src/api/java/Fixedpoint.java +++ b/src/api/java/Fixedpoint.java @@ -163,7 +163,7 @@ public class Fixedpoint extends Z3Object } /** - * Creates a backtracking point. + * Creates a backtracking point. @see Pop **/ public void push() throws Z3Exception { @@ -173,7 +173,7 @@ public class Fixedpoint extends Z3Object /** * Backtrack one backtracking point. Note that an exception is * thrown if Pop is called without a corresponding Push - * + * @see Push **/ public void pop() throws Z3Exception { diff --git a/src/api/java/Global.java b/src/api/java/Global.java index c93f46c88..2fa3abbbe 100644 --- a/src/api/java/Global.java +++ b/src/api/java/Global.java @@ -50,7 +50,7 @@ public final class Global /** * Get a global (or module) parameter. * - * Returns null if the parameter parameter id does not exist. + * Returns null if the parameter @param id parameter id does not exist. * This function cannot be invoked simultaneously from different threads without synchronization. * The result string stored in param_value is stored in a shared location. * @@ -69,7 +69,7 @@ public final class Global * * This command will not affect already created objects (such as tactics and solvers) * - * + * @see SetParameter **/ public static void resetParameters() { diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java index 05d99b305..43ae86162 100644 --- a/src/api/java/InterpolationContext.java +++ b/src/api/java/InterpolationContext.java @@ -42,7 +42,7 @@ public class InterpolationContext extends Context /** * Constructor. * - * + * @see Context.Context(Dictionary<string, string>) **/ public InterpolationContext(Map settings) throws Z3Exception { diff --git a/src/api/java/Model.java b/src/api/java/Model.java index 11eed201e..1ebe7973b 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -26,7 +26,7 @@ public class Model extends Z3Object { /** * Retrieves the interpretation (the assignment) of in - * the model. A Constant + * the model. @param a A Constant * * @return An expression if the constant has an interpretation in the model, * null otherwise. @@ -40,7 +40,7 @@ public class Model extends Z3Object /** * Retrieves the interpretation (the assignment) of in - * the model. A function declaration of zero arity + * the model. @param f A function declaration of zero arity * * @return An expression if the function has an interpretation in the model, * null otherwise. @@ -242,7 +242,7 @@ public class Model extends Z3Object * Z3 also provides an intepretation for uninterpreted sorts used * in a formula. The interpretation for a sort is a finite set of distinct * values. We say this finite set is the "universe" of the sort. - * + * @see NumSorts"/> . An + * sort . @see Sorts An * uninterpreted sort * * @return An array of expressions, where each is an element of the universe diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index e129189f9..4a7c1ed09 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -56,8 +56,8 @@ public class Solver extends Z3Object } /** - * The current number of backtracking points (scopes). - * + * The current number of backtracking points (scopes). @see Pop + * @see Push **/ public int getNumScopes() throws Z3Exception { @@ -66,7 +66,7 @@ public class Solver extends Z3Object } /** - * Creates a backtracking point. + * Creates a backtracking point. @see Pop **/ public void push() throws Z3Exception { @@ -84,7 +84,7 @@ public class Solver extends Z3Object /** * Backtracks backtracking points. Note that * an exception is thrown if is not smaller than - * NumScopes + * NumScopes @see Push **/ public void pop(int n) throws Z3Exception { @@ -193,7 +193,7 @@ public class Solver extends Z3Object /** * Checks whether the assertions in the solver are consistent or not. - * @see Model"/> **/ public Status check(Expr... assumptions) throws Z3Exception @@ -219,7 +219,7 @@ public class Solver extends Z3Object /** * Checks whether the assertions in the solver are consistent or not. - * @see Model"/> **/ public Status check() throws Z3Exception From 0faf329054fc64410f5d832ca4473678bf946604 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 3 Jan 2015 17:26:58 +0000 Subject: [PATCH 088/118] FPA API: bugfixes and examples for .NET and Java Signed-off-by: Christoph M. Wintersteiger --- examples/dotnet/Program.cs | 101 +++++++++++++++++++++------------ examples/java/JavaExample.java | 84 ++++++++++++++++++++++++++- src/api/api_fpa.cpp | 18 +++--- src/api/dotnet/Context.cs | 2 +- src/api/java/Expr.java | 8 +++ 5 files changed, 165 insertions(+), 48 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 3d2910c8f..b03cfd28c 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -2028,53 +2028,81 @@ namespace test_mapi // Console.WriteLine("{0}", ctx.MkEq(s1, t1)); } - public static void FloatingPointExample(Context ctx) + public static void FloatingPointExample1(Context ctx) { - Console.WriteLine("FloatingPointExample"); + Console.WriteLine("FloatingPointExample1"); FPSort s = ctx.MkFPSort(11, 53); Console.WriteLine("Sort: {0}", s); - FPNum x = (FPNum)ctx.MkNumeral("-1e1", s); - Console.WriteLine("Numeral: {0}", x.ToString()); - - FPNum y = (FPNum)ctx.MkNumeral("-10", s); - Console.WriteLine("Numeral: {0}", y.ToString()); - - FPNum z = (FPNum)ctx.MkNumeral("-1.25p3", s); - Console.WriteLine("Numeral: {0}", z.ToString()); + 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); - x = ctx.MkFPNaN(s); - FPExpr c = (FPExpr)ctx.MkConst("y", s); + /* 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); - // Note: We need to use a special solver for QF_FPA here; the - // general solver does not support FPA yet. - - Solver slvr = ctx.MkSolver("QF_FPA"); - slvr.Add(ctx.MkFPEq(x, c)); - if (slvr.Check() != Status.UNSATISFIABLE) // nothing is equal to NaN according to floating-point equality. - throw new TestFailedException(); - - slvr = ctx.MkSolver("QF_FPA"); - slvr.Add(ctx.MkEq(x, c)); // NaN is equal to NaN according to normal equality. - if (slvr.Check() != Status.SATISFIABLE) - throw new TestFailedException(); - - - x = (FPNum)ctx.MkNumeral("-1e1", s); - y = (FPNum)ctx.MkNumeral("-10", s); - FPExpr q = (FPExpr)ctx.MkConst("q", s); - FPNum mh = (FPNum)ctx.MkNumeral("100", s); - slvr = ctx.MkSolver("QF_FPA"); - // Let's prove -1e1 * -10 == +100 - slvr.Add(ctx.MkEq(ctx.MkFPMul(ctx.MkFPRMNearestTiesToAway(), x, y), q)); - slvr.Add(ctx.MkNot(ctx.MkFPEq(q, mh))); + /* 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); + RealExpr real_val = ctx.MkReal(42); + BitVecExpr bv_val = ctx.MkBV(42, 64); + FPExpr fp_val = ctx.MkFP(42, double_sort); + + BoolExpr c1 = ctx.MkEq(x, ctx.MkFPToIEEEBV(fp_val)); + BoolExpr c2 = ctx.MkEq(x, ctx.MkBV(42, 64)); + BoolExpr c3 = ctx.MkEq(fp_val, ctx.MkFPToFP(rm, real_val, double_sort)); + BoolExpr c4 = ctx.MkAnd(c1, c2); + Console.WriteLine("c3 = " + c3); + + /* Generic solver */ + Solver s = ctx.MkSolver(); + s.Assert(c3); + + if (s.Check() != Status.SATISFIABLE) + throw new TestFailedException(); + + Console.WriteLine("OK, model: ", s.Model.ToString()); } static void Main(string[] args) @@ -2118,7 +2146,8 @@ namespace test_mapi FindSmallModelExample(ctx); SimplifierExample(ctx); FiniteDomainExample(ctx); - FloatingPointExample(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..878ec4693 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)); + RealExpr real_val = ctx.mkReal(42); + FPExpr fp_val = ctx.mkFP(42, double_sort); + + BoolExpr c1 = ctx.mkEq(x, ctx.mkFPToIEEEBV(fp_val)); + BoolExpr c2 = ctx.mkEq(x, ctx.mkBV(42, 64)); + BoolExpr c3 = ctx.mkEq(fp_val, ctx.mkFPToFP(rm, real_val, double_sort)); + BoolExpr c4 = ctx.mkAnd(c1, c2); + System.out.println("c3 = " + c3); + + /* Generic solver */ + Solver s = ctx.mkSolver(); + s.add(c3); + + 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/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index d2d4e7155..87568af09 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -649,23 +649,21 @@ extern "C" { Z3_CATCH_RETURN(0); } - unsigned int Z3_API Z3_mk_fpa_get_ebits(Z3_context c, Z3_sort s) { + unsigned Z3_API Z3_fpa_get_ebits(Z3_context c, Z3_sort s) { Z3_TRY; - LOG_Z3_mk_fpa_get_ebits(c, s); + LOG_Z3_fpa_get_ebits(c, s); RESET_ERROR_CODE(); - api::context * ctx = mk_c(c); - unsigned r = ctx->float_util().get_ebits(to_sort(s)); - RETURN_Z3(r); + CHECK_NON_NULL(s, 0); + return mk_c(c)->float_util().get_ebits(to_sort(s)); Z3_CATCH_RETURN(0); } - unsigned Z3_API Z3_mk_fpa_get_sbits(Z3_context c, Z3_sort s) { + unsigned Z3_API Z3_fpa_get_sbits(Z3_context c, Z3_sort s) { Z3_TRY; - LOG_Z3_mk_fpa_get_sbits(c, s); + LOG_Z3_fpa_get_ebits(c, s); RESET_ERROR_CODE(); - api::context * ctx = mk_c(c); - unsigned r = ctx->float_util().get_sbits(to_sort(s)); - RETURN_Z3(r); + CHECK_NON_NULL(s, 0); + return mk_c(c)->float_util().get_sbits(to_sort(s)); Z3_CATCH_RETURN(0); } diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index f3e6220cf..609db802d 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3895,7 +3895,7 @@ namespace Microsoft.Z3 /// the closest integer, again represented as a floating-point number. /// /// term of RoundingMode sort - /// floating-point term + /// floating-point term public FPExpr MkFPRoundToIntegral(FPRMExpr rm, FPExpr t) { Contract.Ensures(Contract.Result() != null); diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index 6a7241e98..233076516 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -1791,6 +1791,10 @@ public class Expr extends AST return new RatNum(ctx, obj); case Z3_BV_SORT: return new BitVecNum(ctx, obj); + case Z3_FLOATING_POINT_SORT: + return new FPNum(ctx, obj); + case Z3_FLOATING_POINT_ROUNDING_MODE_SORT: + return new FPRMNum(ctx, obj); default: ; } } @@ -1809,6 +1813,10 @@ public class Expr extends AST return new ArrayExpr(ctx, obj); case Z3_DATATYPE_SORT: return new DatatypeExpr(ctx, obj); + case Z3_FLOATING_POINT_SORT: + return new FPExpr(ctx, obj); + case Z3_FLOATING_POINT_ROUNDING_MODE_SORT: + return new FPRMExpr(ctx, obj); default: ; } From 007ecb4ab29aa02b15569299db924ee4d8dca5c1 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 4 Jan 2015 14:37:33 +0000 Subject: [PATCH 089/118] MPF bugfix Signed-off-by: Christoph M. Wintersteiger --- src/util/mpf.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index f5dcfc612..511bdb03c 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -196,13 +196,17 @@ 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); - + o.sign = m_mpq_manager.is_neg(value); + + 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, value); + m_mpq_manager.set(v, x); o.exponent = 0; // Normalize From cf81f86c6741e09ed93abdf14ee7fe63fcbe0827 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 4 Jan 2015 18:52:23 +0000 Subject: [PATCH 090/118] build fixes Signed-off-by: Christoph M. Wintersteiger --- src/api/z3_replayer.cpp | 7 +++++++ src/ast/fpa/fpa2bv_converter.cpp | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 676ba0c69..cfd022124 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -225,6 +225,13 @@ 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()) { diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index d51e34058..d6d1420e3 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -146,7 +146,6 @@ void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) { app_ref bv(m); unsigned bv_sz = 1 + ebits + (sbits - 1); bv = mk_fresh_const(0, bv_sz); - m_fresh_bv_variables.insert(bv); 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); From 6d8587dff9ab55d4190607c118b1242303e72ef0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 4 Jan 2015 18:53:21 +0000 Subject: [PATCH 091/118] FPA fixes for internal func_decls Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index b019c7359..bdc0c6fb1 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -581,20 +581,21 @@ func_decl * float_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, p SASSERT(m_bv_plugin); if (arity != 2) m_manager->raise_exception("invalid number of arguments to fp.to_sbv"); - if (parameters[0].is_int()) - m_manager->raise_exception("invalid parameter type; fp.to_sbv expects an int parameter"); if (num_parameters != 1) m_manager->raise_exception("invalid number of parameters to fp.to_sbv"); - if (is_rm_sort(domain[0])) + 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, FLOAT_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"); + 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 * float_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -674,11 +675,10 @@ func_decl * float_decl_plugin::mk_internal_to_sbv_unspecified( unsigned arity, sort * const * domain, sort * range) { if (arity != 0) m_manager->raise_exception("invalid number of arguments to internal_to_sbv_unspecified"); - if (!is_sort_of(domain[0], m_bv_fid, BV_SORT)) - m_manager->raise_exception("sort mismatch, expected argument of bitvector sort"); - if (!is_sort_of(range, m_bv_fid, BV_SORT)) - m_manager->raise_exception("sort mismatch, expected range of FloatingPoint sort"); - + 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)); } From 5ff923f5043a275d1ca36231f240fe3c17d11603 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 4 Jan 2015 19:01:02 +0000 Subject: [PATCH 092/118] Added fp.to_sbv Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 238 +++++++++++++++++++++++-------- 1 file changed, 178 insertions(+), 60 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index d6d1420e3..24e606cdc 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -1851,7 +1851,42 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args 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 && + 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); + + expr * bv = args[0]; + int sz = m_bv_util.get_bv_size(bv); + SASSERT((unsigned)sz == to_sbits + to_ebits); + + 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); + } + 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])) { + // 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])) { @@ -1860,13 +1895,6 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args SASSERT(m_util.get_sbits(f->get_range()) == m_bv_util.get_bv_size(args[2])+1); mk_triple(args[0], args[2], 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_arith_util.is_numeral(args[1]) && @@ -1921,34 +1949,7 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args mk_ite(c2, bv_tp, result, result); mk_ite(c3, bv_nta, result, result); mk_ite(c4, bv_nte, result, result); - } - else 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); - - expr * bv = args[0]; - int sz = m_bv_util.get_bv_size(bv); - SASSERT((unsigned)sz == to_sbits + to_ebits); - - 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); - } - else if (num == 2 && - m_util.is_rm(args[0]) && - is_app(args[1]) && - 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_util.is_rm(args[0]), - m_arith_util.is_real(args[1])) { - // rm + real -> float - mk_to_fp_real(f, f->get_range(), args[0], args[1], result); - } else UNREACHABLE(); @@ -2452,8 +2453,6 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg sort * xs = m.get_sort(x); sort * bv_srt = f->get_range(); - dbg_decouple("fpa2bv_to_ubv_x", expr_ref(x, m)); - unsigned ebits = m_util.get_ebits(xs); unsigned sbits = m_util.get_sbits(xs); unsigned bv_sz = (unsigned)f->get_parameter(0).get_int(); @@ -2470,7 +2469,7 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg mk_is_neg(x, x_is_neg); mk_is_nzero(x, x_is_nzero); - // NaN, Inf, or negative (except -0) -> undefined + // 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); @@ -2513,7 +2512,7 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg dbg_decouple("fpa2bv_to_ubv_shift", shift); dbg_decouple("fpa2bv_to_ubv_shift_abs", shift_abs); - // sig is of the form +- [1].[sig][r][g][s] ... and at least bv_sz + 3 long + // 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); @@ -2546,18 +2545,17 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg 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)); + 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), rounded(m), rnd_has_overflown(m); + expr_ref rnd_overflow(m), rnd(m), rnd_has_overflown(m); rnd_overflow = m_bv_util.mk_extract(bv_sz, bv_sz, pre_rounded); - rounded = m_bv_util.mk_extract(bv_sz - 1, 0, 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), rounded); + 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); @@ -2568,24 +2566,138 @@ void fpa2bv_converter::mk_to_ubv(func_decl * f, unsigned num, expr * const * arg 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])); - //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]; + sort * xs = m.get_sort(x); + sort * bv_srt = f->get_range(); - //expr * rm = args[0]; - //expr * x = args[1]; + 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 * sgn, *s, *e; - //split_triple(x, sgn, s, e); + 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); - NOT_IMPLEMENTED_YET(); + 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); + + // 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_ubv_shift", shift); + dbg_decouple("fpa2bv_to_ubv_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)); } void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -3030,7 +3142,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) 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)); @@ -3040,22 +3152,28 @@ void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { } 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_round(m), not_lors(m), not_rors(m), not_sgn(m); + 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 * round_lors[2] = { not_round, not_lors }; + 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, round_lors)); - inc_taway = round; + 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)); From dd17f3c7d6802e5649a22d2ae7f93f2cf368d416 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 13:18:56 +0000 Subject: [PATCH 093/118] Renaming floats, float, Floats, Float -> FPA, fpa Signed-off-by: Christoph M. Wintersteiger --- src/api/api_ast.cpp | 62 ++- src/api/api_context.cpp | 2 +- src/api/api_context.h | 2 +- src/api/api_fpa.cpp | 2 +- src/api/api_numeral.cpp | 2 +- src/api/dotnet/Expr.cs | 4 +- src/api/z3_api.h | 53 +- src/ast/ast_smt2_pp.h | 2 +- src/ast/fpa/fpa2bv_converter.cpp | 373 ++++++++------ src/ast/fpa/fpa2bv_converter.h | 15 +- src/ast/fpa/fpa2bv_rewriter.h | 98 ++-- ...at_decl_plugin.cpp => fpa_decl_plugin.cpp} | 460 +++++++++--------- ...{float_decl_plugin.h => fpa_decl_plugin.h} | 216 ++++---- src/ast/reg_decl_plugins.cpp | 6 +- .../{float_rewriter.cpp => fpa_rewriter.cpp} | 154 +++--- .../{float_rewriter.h => fpa_rewriter.h} | 8 +- src/ast/rewriter/mk_simplified_app.cpp | 4 +- src/ast/rewriter/th_rewriter.cpp | 4 +- src/cmd_context/cmd_context.cpp | 8 +- src/cmd_context/cmd_context.h | 2 +- src/model/model_evaluator.cpp | 4 +- src/smt/theory_fpa.cpp | 27 +- src/tactic/fpa/fpa2bv_model_converter.cpp | 2 +- src/tactic/fpa/qffpa_tactic.cpp | 32 +- src/tactic/fpa/qffpa_tactic.h | 4 +- 25 files changed, 859 insertions(+), 687 deletions(-) rename src/ast/{float_decl_plugin.cpp => fpa_decl_plugin.cpp} (71%) rename src/ast/{float_decl_plugin.h => fpa_decl_plugin.h} (77%) rename src/ast/rewriter/{float_rewriter.cpp => fpa_rewriter.cpp} (69%) rename src/ast/rewriter/{float_rewriter.h => fpa_rewriter.h} (95%) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 67358726c..c6b413dd4 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -648,11 +648,11 @@ 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 == FLOAT_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_FLOATING_POINT_ROUNDING_MODE_SORT; + return Z3_ROUNDING_MODE_SORT; } else { return Z3_UNKNOWN_SORT; @@ -1119,6 +1119,64 @@ 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_VALUE: return Z3_OP_FPA_VALUE; + 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_PZERO: return Z3_OP_FPA_IS_PZERO; + case OP_FPA_IS_NZERO: return Z3_OP_FPA_IS_NZERO; + 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 5d11e5bce..b83b72e35 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -113,7 +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("float"); + 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 f409a4ece..c71b88b61 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -27,7 +27,7 @@ Revision History: #include"bv_decl_plugin.h" #include"datatype_decl_plugin.h" #include"dl_decl_plugin.h" -#include"float_decl_plugin.h" +#include"fpa_decl_plugin.h" #include"smt_kernel.h" #include"smt_params.h" #include"event_handler.h" diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 87568af09..0f0f68ae1 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -20,7 +20,7 @@ Notes: #include"z3.h" #include"api_log_macros.h" #include"api_context.h" -#include"float_decl_plugin.h" +#include"fpa_decl_plugin.h" extern "C" { diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index d2829e990..17a743880 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -23,7 +23,7 @@ Revision History: #include"arith_decl_plugin.h" #include"bv_decl_plugin.h" #include"algebraic_numbers.h" -#include"float_decl_plugin.h" +#include"fpa_decl_plugin.h" bool is_numeral_sort(Z3_context c, Z3_sort ty) { sort * _ty = to_sort(ty); diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index ec8beeac0..826860eec 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -1543,7 +1543,7 @@ namespace Microsoft.Z3 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_FLOATING_POINT_SORT: return new FPNum(ctx, obj); - case Z3_sort_kind.Z3_FLOATING_POINT_ROUNDING_MODE_SORT: return new FPRMNum(ctx, obj); + case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMNum(ctx, obj); } } @@ -1556,7 +1556,7 @@ namespace Microsoft.Z3 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_FLOATING_POINT_SORT: return new FPExpr(ctx, obj); - case Z3_sort_kind.Z3_FLOATING_POINT_ROUNDING_MODE_SORT: return new FPRMExpr(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/z3_api.h b/src/api/z3_api.h index 776e4e9fe..3c3a5d1c2 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -195,7 +195,7 @@ typedef enum Z3_RELATION_SORT, Z3_FINITE_DOMAIN_SORT, Z3_FLOATING_POINT_SORT, - Z3_FLOATING_POINT_ROUNDING_MODE_SORT, + Z3_ROUNDING_MODE_SORT, Z3_UNKNOWN_SORT = 1000 } Z3_sort_kind; @@ -1058,6 +1058,57 @@ 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_VALUE, + 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_PZERO, + Z3_OP_FPA_IS_NZERO, + 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; diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index 37d13e57a..bc62448c7 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" diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 24e606cdc..dc1a255e8 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" @@ -34,7 +36,7 @@ fpa2bv_converter::fpa2bv_converter(ast_manager & m) : m_mpz_manager(m_mpf_manager.mpz_manager()), m_hi_fp_unspecified(true), m_extra_assertions(m) { - m_plugin = static_cast(m.get_plugin(m.mk_family_id("float"))); + m_plugin = static_cast(m.get_plugin(m.mk_family_id("fpa"))); } fpa2bv_converter::~fpa2bv_converter() { @@ -42,8 +44,8 @@ fpa2bv_converter::~fpa2bv_converter() { } void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { - SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_FLOAT_TO_FP)); - SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FLOAT_TO_FP)); + SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_FPA_TO_FP)); + SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FPA_TO_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); @@ -62,8 +64,8 @@ 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_FLOAT_TO_FP)); - SASSERT(is_app_of(f, m_plugin->get_family_id(), OP_FLOAT_TO_FP)); + SASSERT(is_app_of(t, m_plugin->get_family_id(), OP_FPA_TO_FP)); + SASSERT(is_app_of(f, m_plugin->get_family_id(), OP_FPA_TO_FP)); expr *t_sgn, *t_sig, *t_exp; expr *f_sgn, *f_sig, *f_exp; @@ -1881,15 +1883,15 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args 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); + 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])) { + 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); @@ -1900,55 +1902,7 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args m_arith_util.is_numeral(args[1]) && m_arith_util.is_numeral(args[2])) { - // 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(); - - 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_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); - - 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); + mk_to_fp_real_int(f, num, args, result); } else UNREACHABLE(); @@ -2104,11 +2058,13 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * } 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)); 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)) { + if (false && m_bv_util.is_numeral(rm) && m_util.au().is_numeral(x)) { rational tmp_rat; unsigned sz; m_bv_util.is_numeral(to_expr(rm), tmp_rat, sz); SASSERT(tmp_rat.is_int32()); @@ -2140,19 +2096,201 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * mk_triple(sgn, s, e, result); } else { - NOT_IMPLEMENTED_YET(); + 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 = m.mk_ite(au.mk_lt(x, zero), bv1, bv0); + sig = bu.mk_numeral(0, sbits + 4); + mpz const & max_normal_exponent = fm.m_powers2.m1(ebits-1); + exp = bu.mk_numeral(max_normal_exponent, ebits); + + //expr_ref cur_s(m), cur_d(m), cur_r(m), cur_s2(m), bv1_s4(m); + //bv1_s4 = bu.mk_numeral(1, sbits + 4); + //cur_s = x; + //std::string trace_name; + //for (unsigned i = 0; i < sbits + 3; i++) { + // std::stringstream dbg_name; + // dbg_name << "fpa2bv_to_float_real_sig_" << i; + // dbg_decouple(dbg_name.str().c_str(), sig); + + // cur_s = au.mk_div(cur_s, two); + // // cur_r = au.mk_rem(cur_s, two); + // cur_r = au.mk_mod(cur_s, two); + // cur_s2 = bu.mk_bv_shl(sig, bv1_s4); + // sig = m.mk_ite(au.mk_eq(cur_r, zero), + // cur_s2, + // bu.mk_bv_add(cur_s2, bv1_s4)); + //} + //dbg_decouple("fpa2bv_to_float_real_last_cur_s", cur_s); + //expr_ref inc(m); + //inc = m.mk_not(m.mk_eq(cur_s, zero)); + //dbg_decouple("fpa2bv_to_float_real_inc", inc); + //sig = m.mk_ite(inc, bu.mk_bv_add(sig, bv1_s4), sig); + + SASSERT(bu.get_bv_size(sgn) == 1); + SASSERT(bu.get_bv_size(sig) == sbits + 4); + SASSERT(bu.get_bv_size(exp) == ebits + 2); + + dbg_decouple("fpa2bv_to_float_real_sgn", sgn); + dbg_decouple("fpa2bv_to_float_real_sig", sig); + dbg_decouple("fpa2bv_to_float_real_exp", exp); + + expr_ref rmr(rm, m); + round(s, rmr, sgn, sig, exp, result); } 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(); + + 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_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); + + 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_TO_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)) + // ((_ 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 @@ -2293,7 +2431,7 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con 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)) + // ((_ 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 @@ -2700,91 +2838,6 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg SASSERT(is_well_sorted(m, 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_FLOAT_TO_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)); -} - 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); @@ -2807,7 +2860,7 @@ expr_ref fpa2bv_converter::mk_to_real_unspecified() { } void fpa2bv_converter::split_triple(expr * e, expr * & sgn, expr * & sig, expr * & exp) const { - SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FLOAT_TO_FP)); + SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); sgn = to_app(e)->get_arg(0); @@ -2816,7 +2869,7 @@ void fpa2bv_converter::split_triple(expr * e, expr * & sgn, expr * & sig, expr * } void fpa2bv_converter::split_triple(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp) const { - SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FLOAT_TO_FP)); + SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); expr *e_sgn, *e_sig, *e_exp; split_triple(e, e_sgn, e_sig, e_exp); @@ -2866,7 +2919,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_FLOAT_TO_FP)); + SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); expr * a0 = to_app(e)->get_arg(0); expr_ref zero(m); @@ -2875,7 +2928,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_FLOAT_TO_FP)); + SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); expr * a0 = to_app(e)->get_arg(0); expr_ref one(m); @@ -3038,7 +3091,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_FLOAT_TO_FP)); + SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_TO_FP)); SASSERT(to_app(e)->get_num_args() == 3); sort * srt = to_app(e)->get_decl()->get_range(); @@ -3131,11 +3184,11 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) { switch(f->get_decl_kind()) { - case OP_FLOAT_RM_NEAREST_TIES_TO_AWAY: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3); break; - case OP_FLOAT_RM_NEAREST_TIES_TO_EVEN: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); break; - case OP_FLOAT_RM_TOWARD_NEGATIVE: result = m_bv_util.mk_numeral(BV_RM_TO_NEGATIVE, 3); break; - case OP_FLOAT_RM_TOWARD_POSITIVE: result = m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3); break; - case OP_FLOAT_RM_TOWARD_ZERO: result = m_bv_util.mk_numeral(BV_RM_TO_ZERO, 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_NEAREST_TIES_TO_EVEN: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 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_POSITIVE: result = m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3); break; + case OP_FPA_RM_TOWARD_ZERO: result = m_bv_util.mk_numeral(BV_RM_TO_ZERO, 3); break; default: UNREACHABLE(); } } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 6a7b6e92f..f81edb653 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -22,7 +22,7 @@ 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" @@ -50,7 +50,7 @@ protected: 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; @@ -76,7 +76,7 @@ public: 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_FLOAT_TO_FP, sign, exponent, significand); + result = m.mk_app(m_util.get_family_id(), OP_FPA_TO_FP, sign, exponent, significand); } void split_triple(expr * e, expr * & sgn, expr * & sig, expr * & exp) const; @@ -130,15 +130,16 @@ public: 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_real(func_decl * f, sort * s, expr * rm, expr * x, 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); diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index 797f681e7..cbbd9e8a7 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -115,55 +115,55 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { if (m_conv.is_float_family(f)) { switch (f->get_decl_kind()) { - case OP_FLOAT_RM_NEAREST_TIES_TO_AWAY: - case OP_FLOAT_RM_NEAREST_TIES_TO_EVEN: - case OP_FLOAT_RM_TOWARD_NEGATIVE: - case OP_FLOAT_RM_TOWARD_POSITIVE: - case OP_FLOAT_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_pinf(f, result); return BR_DONE; - case OP_FLOAT_MINUS_INF: m_conv.mk_ninf(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_FLOAT_TO_FP: m_conv.mk_to_fp(f, num, args, result); return BR_DONE; - case OP_FLOAT_TO_FP_UNSIGNED: m_conv.mk_to_fp_unsigned(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_FLOAT_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; - case OP_FLOAT_INTERNAL_BVWRAP: - case OP_FLOAT_INTERNAL_BVUNWRAP: - case OP_FLOAT_INTERNAL_TO_REAL_UNSPECIFIED: - case OP_FLOAT_INTERNAL_TO_UBV_UNSPECIFIED: - case OP_FLOAT_INTERNAL_TO_SBV_UNSPECIFIED: return BR_FAILED; + 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_VALUE: m_conv.mk_value(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_NZERO: m_conv.mk_is_nzero(f, num, args, result); return BR_DONE; + case OP_FPA_IS_PZERO: m_conv.mk_is_pzero(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;); diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp similarity index 71% rename from src/ast/float_decl_plugin.cpp rename to src/ast/fpa_decl_plugin.cpp index bdc0c6fb1..be3e5f3ec 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -3,7 +3,7 @@ Copyright (c) 2012 Microsoft Corporation Module Name: - float_decl_plugin.cpp + fpa_decl_plugin.cpp Abstract: @@ -16,11 +16,11 @@ Author: Revision History: --*/ -#include"float_decl_plugin.h" +#include"fpa_decl_plugin.h" #include"arith_decl_plugin.h" #include"bv_decl_plugin.h" -float_decl_plugin::float_decl_plugin(): +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; @@ -28,16 +28,16 @@ float_decl_plugin::float_decl_plugin(): m_bv_plugin = 0; } -void float_decl_plugin::set_manager(ast_manager * m, family_id id) { +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 float_decl_plugin. + 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 float_decl_plugin. + 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. @@ -46,10 +46,10 @@ void float_decl_plugin::set_manager(ast_manager * m, family_id id) { m_bv_plugin = static_cast(m_manager->get_plugin(m_bv_fid)); } -float_decl_plugin::~float_decl_plugin() { +fpa_decl_plugin::~fpa_decl_plugin() { } -unsigned float_decl_plugin::mk_id(mpf const & v) { +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); @@ -61,54 +61,54 @@ unsigned float_decl_plugin::mk_id(mpf const & v) { return old_id; } -void float_decl_plugin::recycled_id(unsigned 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 * float_decl_plugin::mk_value_decl(mpf const & v) { +func_decl * fpa_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)); + return m_manager->mk_const_decl(symbol("fpa"), s, func_decl_info(m_family_id, OP_FPA_VALUE, 1, &p)); } -app * float_decl_plugin::mk_value(mpf const & v) { +app * fpa_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)) { +bool fpa_decl_plugin::is_value(expr * n, mpf & val) { + if (is_app_of(n, m_family_id, OP_FPA_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)) { + 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_FLOAT_PLUS_INF)) { + 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_FLOAT_NAN)) { + 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_FLOAT_PLUS_ZERO)) { + 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_FLOAT_MINUS_ZERO)) { + 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); @@ -117,24 +117,24 @@ bool float_decl_plugin::is_value(expr * n, mpf & val) { return false; } -bool float_decl_plugin::is_rm_value(expr * n, mpf_rounding_mode & val) { - if (is_app_of(n, m_family_id, OP_FLOAT_RM_NEAREST_TIES_TO_AWAY)) { +bool fpa_decl_plugin::is_rm_value(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_FLOAT_RM_NEAREST_TIES_TO_EVEN)) { + 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_FLOAT_RM_TOWARD_NEGATIVE)) { + 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_FLOAT_RM_TOWARD_POSITIVE)) { + 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_FLOAT_RM_TOWARD_ZERO)) { + else if (is_app_of(n, m_family_id, OP_FPA_RM_TOWARD_ZERO)) { val = MPF_ROUND_TOWARD_ZERO; return true; } @@ -142,27 +142,27 @@ bool float_decl_plugin::is_rm_value(expr * n, mpf_rounding_mode & val) { return 0; } -void float_decl_plugin::del(parameter const & p) { +void fpa_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) { +parameter fpa_decl_plugin::translate(parameter const & p, decl_plugin & target) { SASSERT(p.is_external()); - float_decl_plugin & _target = static_cast(target); + fpa_decl_plugin & _target = static_cast(target); return parameter(_target.mk_id(m_values[p.get_ext_id()]), true); } -void float_decl_plugin::finalize() { +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 * float_decl_plugin::mk_fresh() { - return alloc(float_decl_plugin); +decl_plugin * fpa_decl_plugin::mk_fresh() { + return alloc(fpa_decl_plugin); } -sort * float_decl_plugin::mk_float_sort(unsigned ebits, unsigned sbits) { +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) @@ -172,16 +172,16 @@ sort * float_decl_plugin::mk_float_sort(unsigned ebits, unsigned 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)); + return m_manager->mk_sort(symbol("FloatingPoint"), sort_info(m_family_id, FLOATING_POINT_SORT, sz, 2, ps)); } -sort * float_decl_plugin::mk_rm_sort() { +sort * fpa_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) { +sort * fpa_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { switch (k) { - case FLOAT_SORT: + 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()); @@ -201,7 +201,7 @@ sort * float_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, paramete } } -func_decl * float_decl_plugin::mk_rm_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, +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"); @@ -210,15 +210,15 @@ func_decl * float_decl_plugin::mk_rm_const_decl(decl_kind k, unsigned num_parame sort * s = mk_rm_sort(); func_decl_info finfo(m_family_id, k); switch (k) { - case OP_FLOAT_RM_NEAREST_TIES_TO_EVEN: + case OP_FPA_RM_NEAREST_TIES_TO_EVEN: return m_manager->mk_const_decl(symbol("roundNearestTiesToEven"), s, finfo); - case OP_FLOAT_RM_NEAREST_TIES_TO_AWAY: + case OP_FPA_RM_NEAREST_TIES_TO_AWAY: return m_manager->mk_const_decl(symbol("roundNearestTiesToAway"), s, finfo); - case OP_FLOAT_RM_TOWARD_POSITIVE: + case OP_FPA_RM_TOWARD_POSITIVE: return m_manager->mk_const_decl(symbol("roundTowardPositive"), s, finfo); - case OP_FLOAT_RM_TOWARD_NEGATIVE: + case OP_FPA_RM_TOWARD_NEGATIVE: return m_manager->mk_const_decl(symbol("roundTowardNegative"), s, finfo); - case OP_FLOAT_RM_TOWARD_ZERO: + case OP_FPA_RM_TOWARD_ZERO: return m_manager->mk_const_decl(symbol("roundTowardZero"), s, finfo); default: UNREACHABLE(); @@ -226,7 +226,7 @@ func_decl * float_decl_plugin::mk_rm_const_decl(decl_kind k, unsigned num_parame } } -func_decl * float_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, +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()))) { @@ -243,7 +243,7 @@ func_decl * float_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_par UNREACHABLE(); } - SASSERT(is_sort_of(s, m_family_id, FLOAT_SORT)); + 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(); @@ -251,19 +251,19 @@ func_decl * float_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_par switch (k) { - case OP_FLOAT_NAN: m_fm.mk_nan(ebits, sbits, val); + case OP_FPA_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; + 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_value_decl(val); } -func_decl * float_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, +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"); @@ -271,11 +271,11 @@ func_decl * float_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_paramet 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.leq"; break; - case OP_FLOAT_GE: name = "fp.geq"; break; + 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; @@ -285,7 +285,7 @@ func_decl * float_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_paramet 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, +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"); @@ -293,15 +293,15 @@ func_decl * float_decl_plugin::mk_unary_rel_decl(decl_kind k, unsigned num_param 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; + case OP_FPA_IS_ZERO: name = "fp.isZero"; break; + case OP_FPA_IS_NZERO: name = "fp.isNZero"; break; + case OP_FPA_IS_PZERO: name = "fp.isPZero"; 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; @@ -309,7 +309,7 @@ func_decl * float_decl_plugin::mk_unary_rel_decl(decl_kind k, unsigned num_param 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, +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"); @@ -317,8 +317,8 @@ func_decl * float_decl_plugin::mk_unary_decl(decl_kind k, unsigned num_parameter 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; + case OP_FPA_ABS: name = "fp.abs"; break; + case OP_FPA_NEG: name = "fp.neg"; break; default: UNREACHABLE(); break; @@ -326,7 +326,7 @@ func_decl * float_decl_plugin::mk_unary_decl(decl_kind k, unsigned num_parameter 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, +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"); @@ -334,9 +334,9 @@ func_decl * float_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_paramete 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; + 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; @@ -344,7 +344,7 @@ func_decl * float_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_paramete 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, +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"); @@ -354,10 +354,10 @@ func_decl * float_decl_plugin::mk_rm_binary_decl(decl_kind k, unsigned num_param 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; + 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; @@ -365,7 +365,7 @@ func_decl * float_decl_plugin::mk_rm_binary_decl(decl_kind k, unsigned num_param 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, +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"); @@ -375,8 +375,8 @@ func_decl * float_decl_plugin::mk_rm_unary_decl(decl_kind k, unsigned num_parame 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; + case OP_FPA_SQRT: name = "fp.sqrt"; break; + case OP_FPA_ROUND_TO_INTEGRAL: name = "fp.roundToIntegral"; break; default: UNREACHABLE(); break; @@ -384,7 +384,7 @@ func_decl * float_decl_plugin::mk_rm_unary_decl(decl_kind k, unsigned num_parame 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, +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"); @@ -396,7 +396,7 @@ func_decl * float_decl_plugin::mk_fma(decl_kind k, unsigned num_parameters, para 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_fp(decl_kind k, unsigned num_parameters, parameter const * parameters, +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) && @@ -444,7 +444,7 @@ func_decl * float_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, pa } 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)) { + 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"); @@ -454,7 +454,7 @@ func_decl * float_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, pa 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)) + 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); @@ -514,7 +514,7 @@ func_decl * float_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, pa return 0; } -func_decl * float_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_parameters, parameter const * parameters, +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) @@ -538,7 +538,7 @@ func_decl * float_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_param 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_fp(decl_kind k, unsigned num_parameters, parameter const * 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"); @@ -555,7 +555,7 @@ func_decl * float_decl_plugin::mk_fp(decl_kind k, unsigned num_parameters, param 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, +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) @@ -566,7 +566,7 @@ func_decl * float_decl_plugin::mk_to_ubv(decl_kind k, unsigned num_parameters, p 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, FLOAT_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"); @@ -576,7 +576,7 @@ func_decl * float_decl_plugin::mk_to_ubv(decl_kind k, unsigned num_parameters, p return m_manager->mk_func_decl(name, arity, domain, bvs, func_decl_info(m_family_id, k, num_parameters, parameters)); } -func_decl * float_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, parameter const * 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) @@ -587,7 +587,7 @@ func_decl * float_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, p 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, FLOAT_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"); @@ -598,7 +598,7 @@ func_decl * float_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, p } -func_decl * float_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, parameter const * 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"); @@ -609,7 +609,7 @@ func_decl * float_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, return m_manager->mk_func_decl(name, 1, domain, m_real_sort, func_decl_info(m_family_id, k)); } -func_decl * float_decl_plugin::mk_float_to_ieee_bv(decl_kind k, unsigned num_parameters, parameter const * parameters, +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"); @@ -623,7 +623,7 @@ func_decl * float_decl_plugin::mk_float_to_ieee_bv(decl_kind k, unsigned num_par 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_internal_bv_wrap(decl_kind k, unsigned num_parameters, parameter const * 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"); @@ -644,7 +644,7 @@ func_decl * float_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_par } } -func_decl * float_decl_plugin::mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * 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"); @@ -656,7 +656,7 @@ func_decl * float_decl_plugin::mk_internal_bv_unwrap(decl_kind k, unsigned num_p return m_manager->mk_func_decl(symbol("bv_unwrap"), 1, domain, range, func_decl_info(m_family_id, k, num_parameters, parameters)); } -func_decl * float_decl_plugin::mk_internal_to_ubv_unspecified( +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) @@ -670,7 +670,7 @@ func_decl * float_decl_plugin::mk_internal_to_ubv_unspecified( 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 * float_decl_plugin::mk_internal_to_sbv_unspecified( +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) @@ -683,7 +683,7 @@ func_decl * float_decl_plugin::mk_internal_to_sbv_unspecified( 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 * float_decl_plugin::mk_internal_to_real_unspecified( +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) @@ -695,81 +695,81 @@ func_decl * float_decl_plugin::mk_internal_to_real_unspecified( } -func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * 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_FLOAT_MINUS_INF: - case OP_FLOAT_PLUS_INF: - case OP_FLOAT_NAN: - case OP_FLOAT_MINUS_ZERO: - case OP_FLOAT_PLUS_ZERO: + 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_FLOAT_RM_NEAREST_TIES_TO_EVEN: - case OP_FLOAT_RM_NEAREST_TIES_TO_AWAY: - case OP_FLOAT_RM_TOWARD_POSITIVE: - case OP_FLOAT_RM_TOWARD_NEGATIVE: - case OP_FLOAT_RM_TOWARD_ZERO: + 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_FLOAT_EQ: - case OP_FLOAT_LT: - case OP_FLOAT_GT: - case OP_FLOAT_LE: - case OP_FLOAT_GE: + 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_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: + case OP_FPA_IS_ZERO: + case OP_FPA_IS_NZERO: + case OP_FPA_IS_PZERO: + 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_FLOAT_ABS: - case OP_FLOAT_NEG: + case OP_FPA_ABS: + case OP_FPA_NEG: return mk_unary_decl(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_REM: - case OP_FLOAT_MIN: - case OP_FLOAT_MAX: + 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_FLOAT_ADD: - case OP_FLOAT_MUL: - case OP_FLOAT_DIV: + 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_FLOAT_SUB: + case OP_FPA_SUB: if (arity == 1) - return mk_unary_decl(OP_FLOAT_NEG, num_parameters, parameters, arity, domain, range); + 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_FLOAT_SQRT: - case OP_FLOAT_ROUND_TO_INTEGRAL: + case OP_FPA_SQRT: + case OP_FPA_ROUND_TO_INTEGRAL: return mk_rm_unary_decl(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_FMA: + case OP_FPA_FMA: return mk_fma(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_FP: + case OP_FPA_FP: return mk_fp(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_TO_UBV: + case OP_FPA_TO_UBV: return mk_to_ubv(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_TO_SBV: + case OP_FPA_TO_SBV: return mk_to_sbv(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_TO_REAL: + case OP_FPA_TO_REAL: return mk_to_real(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_TO_FP: + case OP_FPA_TO_FP: return mk_to_fp(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_TO_FP_UNSIGNED: + case OP_FPA_TO_FP_UNSIGNED: return mk_to_fp_unsigned(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_TO_IEEE_BV: + case OP_FPA_TO_IEEE_BV: return mk_float_to_ieee_bv(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_INTERNAL_BVWRAP: + case OP_FPA_INTERNAL_BVWRAP: return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_INTERNAL_BVUNWRAP: + case OP_FPA_INTERNAL_BVUNWRAP: return mk_internal_bv_unwrap(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_INTERNAL_TO_UBV_UNSPECIFIED: + case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: return mk_internal_to_ubv_unspecified(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_INTERNAL_TO_SBV_UNSPECIFIED: + case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: return mk_internal_to_sbv_unspecified(k, num_parameters, parameters, arity, domain, range); - case OP_FLOAT_INTERNAL_TO_REAL_UNSPECIFIED: + 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"); @@ -777,66 +777,66 @@ func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters } } -void float_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { +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_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("+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_FLOAT_RM_NEAREST_TIES_TO_EVEN)); - op_names.push_back(builtin_name("roundNearestTiesToAway", OP_FLOAT_RM_NEAREST_TIES_TO_AWAY)); - op_names.push_back(builtin_name("roundTowardPositive", OP_FLOAT_RM_TOWARD_POSITIVE)); - op_names.push_back(builtin_name("roundTowardNegative", OP_FLOAT_RM_TOWARD_NEGATIVE)); - op_names.push_back(builtin_name("roundTowardZero", OP_FLOAT_RM_TOWARD_ZERO)); + 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_FLOAT_RM_NEAREST_TIES_TO_EVEN)); - op_names.push_back(builtin_name("RNA", OP_FLOAT_RM_NEAREST_TIES_TO_AWAY)); - op_names.push_back(builtin_name("RTP", OP_FLOAT_RM_TOWARD_POSITIVE)); - op_names.push_back(builtin_name("RTN", OP_FLOAT_RM_TOWARD_NEGATIVE)); - op_names.push_back(builtin_name("RTZ", OP_FLOAT_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_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.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_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.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_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("fp.to_real", OP_FLOAT_TO_REAL)); + 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_FLOAT_TO_FP)); - op_names.push_back(builtin_name("to_fp_unsigned", OP_FLOAT_TO_FP_UNSIGNED)); + 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_FLOAT_TO_IEEE_BV)); + op_names.push_back(builtin_name("to_ieee_bv", OP_FPA_TO_IEEE_BV)); } -void float_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { - sort_names.push_back(builtin_name("FloatingPoint", FLOAT_SORT)); +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 @@ -846,8 +846,8 @@ void float_decl_plugin::get_sort_names(svector & sort_names, symbo 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)); +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_value(tmp); @@ -855,23 +855,23 @@ expr * float_decl_plugin::get_some_value(sort * s) { return res; } -bool float_decl_plugin::is_value(app * e) const { +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_FLOAT_RM_NEAREST_TIES_TO_EVEN: - case OP_FLOAT_RM_NEAREST_TIES_TO_AWAY: - case OP_FLOAT_RM_TOWARD_POSITIVE: - case OP_FLOAT_RM_TOWARD_NEGATIVE: - case OP_FLOAT_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: + 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_VALUE: + 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_FLOAT_FP: + 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)); @@ -880,24 +880,24 @@ bool float_decl_plugin::is_value(app * e) const { } } -bool float_decl_plugin::is_unique_value(app* e) const { +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_FLOAT_RM_NEAREST_TIES_TO_EVEN: - case OP_FLOAT_RM_NEAREST_TIES_TO_AWAY: - case OP_FLOAT_RM_TOWARD_POSITIVE: - case OP_FLOAT_RM_TOWARD_NEGATIVE: - case OP_FLOAT_RM_TOWARD_ZERO: + 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_FLOAT_PLUS_INF: /* No; +oo == fp(#b0 #b11 #b00) */ - case OP_FLOAT_MINUS_INF: /* No; -oo == fp #b1 #b11 #b00) */ - case OP_FLOAT_PLUS_ZERO: /* No; +zero == fp #b0 #b00 #b000) */ - case OP_FLOAT_MINUS_ZERO: /* No; -zero == fp #b1 #b00 #b000) */ - case OP_FLOAT_NAN: /* No; NaN == (fp #b0 #b111111 #b0000001) */ - case OP_FLOAT_VALUE: /* see NaN */ + 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_VALUE: /* see NaN */ return false; - case OP_FLOAT_FP: + 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)); @@ -908,10 +908,10 @@ bool float_decl_plugin::is_unique_value(app* e) const { float_util::float_util(ast_manager & m): m_manager(m), - m_fid(m.mk_family_id("float")), + m_fid(m.mk_family_id("fpa")), m_a_util(m), m_bv_util(m) { - m_plugin = static_cast(m.get_plugin(m_fid)); + m_plugin = static_cast(m.get_plugin(m_fid)); } float_util::~float_util() { @@ -919,7 +919,7 @@ 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); + return m().mk_sort(m_fid, FLOATING_POINT_SORT, 2, ps); } unsigned float_util::get_ebits(sort * s) { @@ -965,16 +965,16 @@ app * float_util::mk_nzero(unsigned ebits, unsigned sbits) { app * float_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_FLOAT_INTERNAL_TO_UBV_UNSPECIFIED, 1, ps, 0, 0, range); + return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 1, ps, 0, 0, range); } app * float_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_FLOAT_INTERNAL_TO_SBV_UNSPECIFIED, 1, ps, 0, 0, range); + return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, 1, ps, 0, 0, range); } app * float_util::mk_internal_to_real_unspecified() { sort * range = m_a_util.mk_real(); - return m().mk_app(get_family_id(), OP_FLOAT_INTERNAL_TO_REAL_UNSPECIFIED, 0, 0, 0, 0, range); + 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/float_decl_plugin.h b/src/ast/fpa_decl_plugin.h similarity index 77% rename from src/ast/float_decl_plugin.h rename to src/ast/fpa_decl_plugin.h index cbcd706cd..b7d59a6af 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -3,7 +3,7 @@ Copyright (c) 2012 Microsoft Corporation Module Name: - float_decl_plugin.h + fpa_decl_plugin.h Abstract: @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#ifndef _FLOAT_DECL_PLUGIN_H_ -#define _FLOAT_DECL_PLUGIN_H_ +#ifndef _fpa_decl_plugin_H_ +#define _fpa_decl_plugin_H_ #include"ast.h" #include"id_gen.h" @@ -25,8 +25,8 @@ Revision History: #include"bv_decl_plugin.h" #include"mpf.h" -enum float_sort_kind { - FLOAT_SORT, +enum fpa_sort_kind { + FLOATING_POINT_SORT, ROUNDING_MODE_SORT, FLOAT16_SORT, FLOAT32_SORT, @@ -34,69 +34,69 @@ enum float_sort_kind { FLOAT128_SORT }; -enum float_op_kind { - OP_FLOAT_RM_NEAREST_TIES_TO_EVEN, - OP_FLOAT_RM_NEAREST_TIES_TO_AWAY, - OP_FLOAT_RM_TOWARD_POSITIVE, - OP_FLOAT_RM_TOWARD_NEGATIVE, - OP_FLOAT_RM_TOWARD_ZERO, +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_FLOAT_VALUE, - OP_FLOAT_PLUS_INF, - OP_FLOAT_MINUS_INF, - OP_FLOAT_NAN, - OP_FLOAT_PLUS_ZERO, - OP_FLOAT_MINUS_ZERO, + OP_FPA_VALUE, + OP_FPA_PLUS_INF, + OP_FPA_MINUS_INF, + OP_FPA_NAN, + OP_FPA_PLUS_ZERO, + OP_FPA_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_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_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_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_PZERO, + OP_FPA_IS_NZERO, + OP_FPA_IS_NEGATIVE, + OP_FPA_IS_POSITIVE, - OP_FLOAT_FP, - OP_FLOAT_TO_FP, - OP_FLOAT_TO_FP_UNSIGNED, - OP_FLOAT_TO_UBV, - OP_FLOAT_TO_SBV, - OP_FLOAT_TO_REAL, + 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_FLOAT_TO_IEEE_BV, + OP_FPA_TO_IEEE_BV, /* Internal use only */ - OP_FLOAT_INTERNAL_BVWRAP, - OP_FLOAT_INTERNAL_BVUNWRAP, - OP_FLOAT_INTERNAL_TO_UBV_UNSPECIFIED, - OP_FLOAT_INTERNAL_TO_SBV_UNSPECIFIED, - OP_FLOAT_INTERNAL_TO_REAL_UNSPECIFIED, + 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 float_decl_plugin : public decl_plugin { +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) {} @@ -172,12 +172,12 @@ class float_decl_plugin : public decl_plugin { unsigned mk_id(mpf const & v); void recycled_id(unsigned id); public: - float_decl_plugin(); + fpa_decl_plugin(); - bool is_float_sort(sort * s) const { return is_sort_of(s, m_family_id, FLOAT_SORT); } + 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 ~float_decl_plugin(); + virtual ~fpa_decl_plugin(); virtual void finalize(); virtual decl_plugin * mk_fresh(); @@ -193,7 +193,7 @@ public: 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) { return is_app_of(n, m_family_id, OP_FPA_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); } @@ -209,7 +209,7 @@ public: class float_util { ast_manager & m_manager; - float_decl_plugin * m_plugin; + fpa_decl_plugin * m_plugin; family_id m_fid; arith_util m_a_util; bv_util m_bv_util; @@ -222,22 +222,22 @@ public: 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; } + 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, FLOAT_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_FLOAT_RM_NEAREST_TIES_TO_EVEN); } - app * mk_round_nearest_ties_to_away() { return m().mk_const(m_fid, OP_FLOAT_RM_NEAREST_TIES_TO_AWAY); } - app * mk_round_toward_positive() { return m().mk_const(m_fid, OP_FLOAT_RM_TOWARD_POSITIVE); } - app * mk_round_toward_negative() { return m().mk_const(m_fid, OP_FLOAT_RM_TOWARD_NEGATIVE); } - app * mk_round_toward_zero() { return m().mk_const(m_fid, OP_FLOAT_RM_TOWARD_ZERO); } + 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); @@ -264,83 +264,83 @@ public: 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); } - app * mk_fp(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FLOAT_FP, arg1, arg2, arg3); } + 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_FLOAT_TO_FP, 2, s->get_parameters(), 1, &bv_t); + 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_FLOAT_TO_FP, 2, s->get_parameters(), 2, args); + 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_FLOAT_TO_FP, 2, s->get_parameters(), 3, args); + 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_FLOAT_TO_FP_UNSIGNED, 2, s->get_parameters(), 2, args); + 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_FLOAT_TO_FP); } + 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_FLOAT_TO_UBV, 1, ps, 2, args); } + 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_FLOAT_TO_SBV, 1, ps, 2, args); + 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_FLOAT_TO_REAL, t); } + 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_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_to_integral(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_ROUND_TO_INTEGRAL, arg1, arg2); } + 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_FLOAT_FMA, 4, args); + 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_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_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_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); } + 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_nzero(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NZERO, arg1); } + app * mk_is_pzero(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_PZERO, arg1); } + app * mk_is_sign_minus(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NEGATIVE, 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_FLOAT_NEG); } + 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_FLOAT_TO_IEEE_BV, arg1); } + 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_FLOAT_INTERNAL_BVWRAP); } - bool is_unwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FLOAT_INTERNAL_BVUNWRAP); } + 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/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/float_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp similarity index 69% rename from src/ast/rewriter/float_rewriter.cpp rename to src/ast/rewriter/fpa_rewriter.cpp index 96561395e..2977b7ab2 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -3,7 +3,7 @@ Copyright (c) 2012 Microsoft Corporation Module Name: - float_rewriter.cpp + fpa_rewriter.cpp Abstract: @@ -16,65 +16,65 @@ Author: Notes: --*/ -#include"float_rewriter.h" +#include"fpa_rewriter.h" -float_rewriter::float_rewriter(ast_manager & m, params_ref const & p): +fpa_rewriter::fpa_rewriter(ast_manager & m, params_ref const & p): m_util(m) { updt_params(p); } -float_rewriter::~float_rewriter() { +fpa_rewriter::~fpa_rewriter() { } -void float_rewriter::updt_params(params_ref const & p) { +void fpa_rewriter::updt_params(params_ref const & p) { } -void float_rewriter::get_param_descrs(param_descrs & r) { +void fpa_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 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_FLOAT_TO_FP: st = mk_to_fp(f, num_args, args, result); break; - case OP_FLOAT_TO_FP_UNSIGNED: st = mk_to_fp_unsigned(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_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_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_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; - case OP_FLOAT_TO_IEEE_BV: SASSERT(num_args == 1); st = mk_to_ieee_bv(args[0], 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_NZERO: SASSERT(num_args == 1); st = mk_is_nzero(args[0], result); break; + case OP_FPA_IS_PZERO: SASSERT(num_args == 1); st = mk_is_pzero(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 float_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { +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()); @@ -159,7 +159,7 @@ br_status float_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * cons return BR_FAILED; } -br_status float_rewriter::mk_to_fp_unsigned(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { +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()); @@ -169,7 +169,7 @@ br_status float_rewriter::mk_to_fp_unsigned(func_decl * f, unsigned num_args, ex return BR_FAILED; } -br_status float_rewriter::mk_add(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { +br_status fpa_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()); @@ -184,13 +184,13 @@ br_status float_rewriter::mk_add(expr * arg1, expr * arg2, expr * arg3, expr_ref return BR_FAILED; } -br_status float_rewriter::mk_sub(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { +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 float_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { +br_status fpa_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()); @@ -205,7 +205,7 @@ br_status float_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref return BR_FAILED; } -br_status float_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { +br_status fpa_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()); @@ -220,7 +220,7 @@ br_status float_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref return BR_FAILED; } -br_status float_rewriter::mk_neg(expr * arg1, expr_ref & result) { +br_status fpa_rewriter::mk_neg(expr * arg1, expr_ref & result) { if (m_util.is_nan(arg1)) { // -nan --> nan result = arg1; @@ -253,7 +253,7 @@ br_status float_rewriter::mk_neg(expr * arg1, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_rem(expr * arg1, expr * arg2, expr_ref & result) { +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_value(arg1, v1) && m_util.is_value(arg2, v2)) { scoped_mpf t(m_util.fm()); @@ -265,7 +265,7 @@ br_status float_rewriter::mk_rem(expr * arg1, expr * arg2, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_abs(expr * arg1, expr_ref & result) { +br_status fpa_rewriter::mk_abs(expr * arg1, expr_ref & result) { if (m_util.is_nan(arg1)) { result = arg1; return BR_DONE; @@ -276,7 +276,7 @@ br_status float_rewriter::mk_abs(expr * arg1, expr_ref & result) { return BR_REWRITE2; } -br_status float_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { +br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { if (m_util.is_nan(arg1)) { result = arg2; return BR_DONE; @@ -296,7 +296,7 @@ br_status float_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { return BR_REWRITE_FULL; } -br_status float_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { +br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { if (m_util.is_nan(arg1)) { result = arg2; return BR_DONE; @@ -316,7 +316,7 @@ br_status float_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { return BR_REWRITE_FULL; } -br_status float_rewriter::mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg4, expr_ref & result) { +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_value(arg1, rm)) { scoped_mpf v2(m_util.fm()), v3(m_util.fm()), v4(m_util.fm()); @@ -331,7 +331,7 @@ br_status float_rewriter::mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * a return BR_FAILED; } -br_status float_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) { +br_status fpa_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()); @@ -346,7 +346,7 @@ br_status float_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_round(expr * arg1, expr * arg2, expr_ref & result) { +br_status fpa_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()); @@ -362,7 +362,7 @@ br_status float_rewriter::mk_round(expr * arg1, expr * arg2, expr_ref & result) } // This the floating point theory == -br_status float_rewriter::mk_float_eq(expr * arg1, expr * arg2, expr_ref & result) { +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_value(arg1, v1) && m_util.is_value(arg2, v2)) { result = (m_util.fm().eq(v1, v2)) ? m().mk_true() : m().mk_false(); @@ -373,16 +373,16 @@ br_status float_rewriter::mk_float_eq(expr * arg1, expr * arg2, expr_ref & resul } // Return (= arg NaN) -app * float_rewriter::mk_eq_nan(expr * arg) { +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 * float_rewriter::mk_neq_nan(expr * arg) { +app * fpa_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) { +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; @@ -418,12 +418,12 @@ br_status float_rewriter::mk_lt(expr * arg1, expr * arg2, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_gt(expr * arg1, expr * arg2, expr_ref & result) { +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 float_rewriter::mk_le(expr * arg1, expr * arg2, expr_ref & result) { +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; @@ -437,12 +437,12 @@ br_status float_rewriter::mk_le(expr * arg1, expr * arg2, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_ge(expr * arg1, expr * arg2, expr_ref & result) { +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 float_rewriter::mk_is_zero(expr * arg1, expr_ref & result) { +br_status fpa_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(); @@ -452,7 +452,7 @@ br_status float_rewriter::mk_is_zero(expr * arg1, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_is_nzero(expr * arg1, expr_ref & result) { +br_status fpa_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(); @@ -462,7 +462,7 @@ br_status float_rewriter::mk_is_nzero(expr * arg1, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) { +br_status fpa_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(); @@ -472,7 +472,7 @@ br_status float_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_is_nan(expr * arg1, expr_ref & result) { +br_status fpa_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(); @@ -482,7 +482,7 @@ br_status float_rewriter::mk_is_nan(expr * arg1, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_is_inf(expr * arg1, expr_ref & result) { +br_status fpa_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(); @@ -492,7 +492,7 @@ br_status float_rewriter::mk_is_inf(expr * arg1, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_is_normal(expr * arg1, expr_ref & result) { +br_status fpa_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(); @@ -502,7 +502,7 @@ br_status float_rewriter::mk_is_normal(expr * arg1, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) { +br_status fpa_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(); @@ -512,7 +512,7 @@ br_status float_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_is_negative(expr * arg1, expr_ref & result) { +br_status fpa_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(); @@ -522,7 +522,7 @@ br_status float_rewriter::mk_is_negative(expr * arg1, expr_ref & result) { return BR_FAILED; } -br_status float_rewriter::mk_is_positive(expr * arg1, expr_ref & result) { +br_status fpa_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(); @@ -534,7 +534,7 @@ br_status float_rewriter::mk_is_positive(expr * arg1, expr_ref & result) { // This the SMT = -br_status float_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) { +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_value(arg1, v1) && m_util.is_value(arg2, v2)) { // Note: == is the floats-equality, here we need normal equality. @@ -548,11 +548,11 @@ br_status float_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result return BR_FAILED; } -br_status float_rewriter::mk_to_ieee_bv(expr * arg1, expr_ref & result) { +br_status fpa_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) { +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; @@ -575,15 +575,15 @@ br_status float_rewriter::mk_fp(expr * arg1, expr * arg2, expr * arg3, expr_ref return BR_FAILED; } -br_status float_rewriter::mk_to_ubv(expr * arg1, expr * arg2, expr_ref & result) { +br_status fpa_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) { +br_status fpa_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) { +br_status fpa_rewriter::mk_to_real(expr * arg1, expr_ref & result) { scoped_mpf fv(m_util.fm()); if (m_util.is_value(arg1, fv)) { @@ -599,4 +599,4 @@ 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/float_rewriter.h b/src/ast/rewriter/fpa_rewriter.h similarity index 95% rename from src/ast/rewriter/float_rewriter.h rename to src/ast/rewriter/fpa_rewriter.h index 31c571f32..34a34b293 100644 --- a/src/ast/rewriter/float_rewriter.h +++ b/src/ast/rewriter/fpa_rewriter.h @@ -22,10 +22,10 @@ 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 { +class fpa_rewriter { float_util m_util; mpf_manager m_fm; @@ -33,8 +33,8 @@ class float_rewriter { 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(); } 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/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 4dd0cc614..d5ee9ff88 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" @@ -556,7 +556,7 @@ bool cmd_context::logic_has_seq() const { return !has_logic() || logic_has_seq_core(m_logic); } -bool cmd_context::logic_has_floats() const { +bool cmd_context::logic_has_fpa() const { return !has_logic() || m_logic == "QF_FP" || m_logic == "QF_FPBV"; } @@ -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(); 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/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/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index bec9cf235..7c4fce5cd 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -82,7 +82,7 @@ namespace smt { } theory_fpa::theory_fpa(ast_manager & m) : - theory(m.mk_family_id("float")), + theory(m.mk_family_id("fpa")), m_converter(m, this), m_rw(m, m_converter, params_ref()), m_th_rw(m), @@ -91,6 +91,9 @@ namespace smt { 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() @@ -207,7 +210,7 @@ namespace smt { bv_srt = m_bv_util.mk_sort(ebits + sbits); } - w = m.mk_func_decl(get_family_id(), OP_FLOAT_INTERNAL_BVWRAP, 0, 0, 1, &e_srt, bv_srt); + 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); } @@ -226,7 +229,7 @@ namespace smt { if (!m_unwraps.find(e_srt, u)) { SASSERT(!m_unwraps.contains(e_srt)); sort * bv_srt = m.get_sort(e); - u = m.mk_func_decl(get_family_id(), OP_FLOAT_INTERNAL_BVUNWRAP, 0, 0, 1, &bv_srt, s); + u = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVUNWRAP, 0, 0, 1, &bv_srt, s); m_unwraps.insert(s, u); m.inc_ref(u); } @@ -268,10 +271,10 @@ namespace smt { } else if (m_float_util.is_float(e)) { SASSERT(eca->get_family_id() == get_family_id()); - float_op_kind k = (float_op_kind)(eca->get_decl_kind()); - SASSERT(k == OP_FLOAT_TO_FP || k == OP_FLOAT_INTERNAL_BVUNWRAP); + fpa_op_kind k = (fpa_op_kind)(eca->get_decl_kind()); + SASSERT(k == OP_FPA_TO_FP || k == OP_FPA_INTERNAL_BVUNWRAP); switch (k) { - case OP_FLOAT_TO_FP: { + case OP_FPA_TO_FP: { SASSERT(eca->get_num_args() == 3); SASSERT(is_sort_of(m.get_sort(eca->get_arg(0)), m_bv_util.get_family_id(), BV_SORT)); SASSERT(is_sort_of(m.get_sort(eca->get_arg(1)), m_bv_util.get_family_id(), BV_SORT)); @@ -388,6 +391,8 @@ namespace smt { 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; @@ -460,11 +465,11 @@ namespace smt { // The corresponding constraints will not be translated and added // via convert(...) and assert_cnstr(...) in initialize_atom(...). // Therefore, we translate and assert them here. - float_op_kind k = (float_op_kind)term->get_decl_kind(); + fpa_op_kind k = (fpa_op_kind)term->get_decl_kind(); switch (k) { - case OP_FLOAT_TO_UBV: - case OP_FLOAT_TO_SBV: - case OP_FLOAT_TO_REAL: { + 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)); @@ -546,7 +551,7 @@ namespace smt { c = m.mk_and(m.mk_eq(x_sgn, y_sgn), m.mk_eq(x_sig, y_sig), - m.mk_eq(x_exp, y_exp)); + m.mk_eq(x_exp, y_exp)); } else c = m.mk_eq(xc, yc); diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 989ad64ff..78ba64111 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -116,7 +116,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { 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_FLOAT_TO_FP)); + SASSERT(a->is_app_of(fu.get_family_id(), OP_FPA_TO_FP)); #ifdef Z3DEBUG SASSERT(to_app(a->get_arg(0))->get_decl()->get_arity() == 0); diff --git a/src/tactic/fpa/qffpa_tactic.cpp b/src/tactic/fpa/qffpa_tactic.cpp index 919cf0c1b..c02166c18 100644 --- a/src/tactic/fpa/qffpa_tactic.cpp +++ b/src/tactic/fpa/qffpa_tactic.cpp @@ -26,21 +26,23 @@ Notes: #include"qffpa_tactic.h" tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { - params_ref sat_simp_p = p; - sat_simp_p .set_bool("elim_and", true); + params_ref simp_p = p; + simp_p.set_bool("arith_lhs", true); + simp_p.set_bool("elim_and", true); - tactic * st = - cond(mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), - and_then(mk_simplify_tactic(m), - mk_smt_tactic()), - 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())); + tactic * st = cond( mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), + and_then(mk_simplify_tactic(m, simp_p), + mk_smt_tactic()), + and_then( + mk_simplify_tactic(m, p), + 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; @@ -70,6 +72,8 @@ struct is_non_qffp_predicate { return; if (is_uninterp_const(n)) return; + if (au.is_real(s) && au.is_numeral(n)) + return; throw found(); } diff --git a/src/tactic/fpa/qffpa_tactic.h b/src/tactic/fpa/qffpa_tactic.h index 660622fb8..3ab95798f 100644 --- a/src/tactic/fpa/qffpa_tactic.h +++ b/src/tactic/fpa/qffpa_tactic.h @@ -3,11 +3,11 @@ Copyright (c) 2012 Microsoft Corporation Module Name: - qffpa_tactic.h + qffp_tactic.h Abstract: - Tactic QF_FPA benchmarks. + Tactic for QF_FP benchmarks. Author: From 5e5758bb25e080cb45ae0bd7c6e0a3593e1f6606 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 13:37:18 +0000 Subject: [PATCH 094/118] More float -> fpa renaming Signed-off-by: Christoph M. Wintersteiger --- src/api/api_context.cpp | 2 +- src/api/api_context.h | 4 +- src/api/api_fpa.cpp | 146 +++++++++--------- src/api/api_numeral.cpp | 10 +- src/ast/ast_smt2_pp.h | 6 +- src/ast/fpa_decl_plugin.cpp | 26 ++-- src/ast/fpa_decl_plugin.h | 6 +- src/ast/rewriter/fpa_rewriter.h | 2 +- src/cmd_context/cmd_context.cpp | 4 +- src/smt/theory_fpa.cpp | 68 ++++---- src/smt/theory_fpa.h | 14 +- src/tactic/fpa/fpa2bv_model_converter.cpp | 2 +- .../fpa/{qffpa_tactic.cpp => qffp_tactic.cpp} | 8 +- .../fpa/{qffpa_tactic.h => qffp_tactic.h} | 8 +- src/tactic/portfolio/default_tactic.cpp | 2 +- src/tactic/portfolio/smt_strategic_solver.cpp | 6 +- 16 files changed, 158 insertions(+), 156 deletions(-) rename src/tactic/fpa/{qffpa_tactic.cpp => qffp_tactic.cpp} (96%) rename src/tactic/fpa/{qffpa_tactic.h => qffp_tactic.h} (82%) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index b83b72e35..3408cdf3c 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -88,7 +88,7 @@ namespace api { m_arith_util(m()), m_bv_util(m()), m_datalog_util(m()), - m_float_util(m()), + m_fpa_util(m()), m_last_result(m()), m_ast_trail(m()), m_replay_stack() { diff --git a/src/api/api_context.h b/src/api/api_context.h index c71b88b61..6312b3f69 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -57,7 +57,7 @@ namespace api { arith_util m_arith_util; bv_util m_bv_util; datalog::dl_decl_util m_datalog_util; - float_util m_float_util; + fpa_util m_fpa_util; // Support for old solver API smt_params m_fparams; @@ -118,7 +118,7 @@ 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; } - float_util & float_util() { return m_float_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; } diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 0f0f68ae1..94dfaaa68 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -29,7 +29,7 @@ extern "C" { LOG_Z3_mk_fpa_rounding_mode_sort(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_sort r = of_sort(ctx->float_util().mk_rm_sort()); + Z3_sort r = of_sort(ctx->fpa_util().mk_rm_sort()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -40,7 +40,7 @@ extern "C" { 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->float_util().mk_round_nearest_ties_to_even()); + Z3_ast r = of_ast(ctx->fpa_util().mk_round_nearest_ties_to_even()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -50,7 +50,7 @@ extern "C" { LOG_Z3_mk_fpa_rne(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_round_nearest_ties_to_even()); + Z3_ast r = of_ast(ctx->fpa_util().mk_round_nearest_ties_to_even()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -61,7 +61,7 @@ extern "C" { 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->float_util().mk_round_nearest_ties_to_away()); + Z3_ast r = of_ast(ctx->fpa_util().mk_round_nearest_ties_to_away()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -71,7 +71,7 @@ extern "C" { LOG_Z3_mk_fpa_rna(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_round_nearest_ties_to_away()); + Z3_ast r = of_ast(ctx->fpa_util().mk_round_nearest_ties_to_away()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -82,7 +82,7 @@ extern "C" { LOG_Z3_mk_fpa_round_toward_positive(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_round_toward_positive()); + Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_positive()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -92,7 +92,7 @@ extern "C" { LOG_Z3_mk_fpa_rtp(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_round_toward_positive()); + Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_positive()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -103,7 +103,7 @@ extern "C" { LOG_Z3_mk_fpa_round_toward_negative(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_round_toward_negative()); + Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_negative()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -113,7 +113,7 @@ extern "C" { LOG_Z3_mk_fpa_rtn(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_round_toward_negative()); + Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_negative()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -124,7 +124,7 @@ extern "C" { LOG_Z3_mk_fpa_round_toward_zero(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_round_toward_zero()); + Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_zero()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -134,7 +134,7 @@ extern "C" { LOG_Z3_mk_fpa_rtz(c); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_round_toward_zero()); + Z3_ast r = of_ast(ctx->fpa_util().mk_round_toward_zero()); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -148,7 +148,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); } api::context * ctx = mk_c(c); - Z3_sort r = of_sort(ctx->float_util().mk_float_sort(ebits, sbits)); + Z3_sort r = of_sort(ctx->fpa_util().mk_float_sort(ebits, sbits)); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -190,7 +190,7 @@ extern "C" { LOG_Z3_mk_fpa_nan(c, s); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_nan(to_sort(s))); + Z3_ast r = of_ast(ctx->fpa_util().mk_nan(to_sort(s))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -200,7 +200,7 @@ extern "C" { 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->float_util().mk_ninf(to_sort(s)) : ctx->float_util().mk_pinf(to_sort(s))); + 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); } @@ -210,7 +210,7 @@ extern "C" { 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->float_util().mk_nzero(to_sort(s)) : ctx->float_util().mk_pzero(to_sort(s))); + 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); } @@ -220,7 +220,7 @@ extern "C" { LOG_Z3_mk_fpa_fp(c, sgn, sig, exp); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_fp(to_expr(sgn), to_expr(sig), to_expr(exp))); + 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); } @@ -230,9 +230,9 @@ extern "C" { LOG_Z3_mk_fpa_numeral_float(c, v, ty); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - scoped_mpf tmp(ctx->float_util().fm()); - ctx->float_util().fm().set(tmp, ctx->float_util().get_ebits(to_sort(ty)), ctx->float_util().get_sbits(to_sort(ty)), v); - Z3_ast r = of_ast(ctx->float_util().mk_value(tmp)); + 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); } @@ -242,9 +242,9 @@ extern "C" { LOG_Z3_mk_fpa_numeral_double(c, v, ty); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - scoped_mpf tmp(ctx->float_util().fm()); - ctx->float_util().fm().set(tmp, ctx->float_util().get_ebits(to_sort(ty)), ctx->float_util().get_sbits(to_sort(ty)), v); - Z3_ast r = of_ast(ctx->float_util().mk_value(tmp)); + 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); } @@ -254,12 +254,12 @@ extern "C" { LOG_Z3_mk_fpa_numeral_int(c, v, ty); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - scoped_mpf tmp(ctx->float_util().fm()); - ctx->float_util().fm().set(tmp, - ctx->float_util().get_ebits(to_sort(ty)), - ctx->float_util().get_sbits(to_sort(ty)), + 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->float_util().mk_value(tmp)); + Z3_ast r = of_ast(ctx->fpa_util().mk_value(tmp)); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -269,12 +269,12 @@ extern "C" { 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->float_util().fm()); - ctx->float_util().fm().set(tmp, - ctx->float_util().get_ebits(to_sort(ty)), - ctx->float_util().get_sbits(to_sort(ty)), + 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->float_util().mk_value(tmp)); + Z3_ast r = of_ast(ctx->fpa_util().mk_value(tmp)); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -284,12 +284,12 @@ extern "C" { 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->float_util().fm()); - ctx->float_util().fm().set(tmp, - ctx->float_util().get_ebits(to_sort(ty)), - ctx->float_util().get_sbits(to_sort(ty)), + 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->float_util().mk_value(tmp)); + Z3_ast r = of_ast(ctx->fpa_util().mk_value(tmp)); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -299,7 +299,7 @@ extern "C" { LOG_Z3_mk_fpa_abs(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_abs(to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_abs(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -309,7 +309,7 @@ extern "C" { LOG_Z3_mk_fpa_neg(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_neg(to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_neg(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -319,7 +319,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_add(to_expr(rm), to_expr(t1), to_expr(t2))); + 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); } @@ -329,7 +329,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_sub(to_expr(rm), to_expr(t1), to_expr(t2))); + 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); } @@ -339,7 +339,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_mul(to_expr(rm), to_expr(t1), to_expr(t2))); + 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); } @@ -349,7 +349,7 @@ extern "C" { LOG_Z3_mk_fpa_add(c, rm, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_div(to_expr(rm), to_expr(t1), to_expr(t2))); + 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); } @@ -359,7 +359,7 @@ extern "C" { 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->float_util().mk_fma(to_expr(rm), to_expr(t1), to_expr(t2), to_expr(t3))); + 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); } @@ -369,7 +369,7 @@ extern "C" { LOG_Z3_mk_fpa_sqrt(c, rm, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_sqrt(to_expr(rm), to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_sqrt(to_expr(rm), to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -379,7 +379,7 @@ extern "C" { LOG_Z3_mk_fpa_rem(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_rem(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->fpa_util().mk_rem(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -389,7 +389,7 @@ extern "C" { 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->float_util().mk_round_to_integral(to_expr(rm), to_expr(t))); + 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); } @@ -399,7 +399,7 @@ extern "C" { LOG_Z3_mk_fpa_min(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_min(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->fpa_util().mk_min(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -409,7 +409,7 @@ extern "C" { LOG_Z3_mk_fpa_max(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_max(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->fpa_util().mk_max(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -419,7 +419,7 @@ extern "C" { LOG_Z3_mk_fpa_leq(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_le(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->fpa_util().mk_le(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -429,7 +429,7 @@ extern "C" { LOG_Z3_mk_fpa_lt(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_lt(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->fpa_util().mk_lt(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -439,7 +439,7 @@ extern "C" { LOG_Z3_mk_fpa_geq(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_ge(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->fpa_util().mk_ge(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -449,7 +449,7 @@ extern "C" { LOG_Z3_mk_fpa_gt(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_gt(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->fpa_util().mk_gt(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -459,7 +459,7 @@ extern "C" { LOG_Z3_mk_fpa_eq(c, t1, t2); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_float_eq(to_expr(t1), to_expr(t2))); + Z3_ast r = of_ast(ctx->fpa_util().mk_float_eq(to_expr(t1), to_expr(t2))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -469,7 +469,7 @@ extern "C" { LOG_Z3_mk_fpa_is_normal(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_is_normal(to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_is_normal(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -479,7 +479,7 @@ extern "C" { LOG_Z3_mk_fpa_is_subnormal(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_is_subnormal(to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_is_subnormal(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -489,7 +489,7 @@ extern "C" { LOG_Z3_mk_fpa_is_zero(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_is_zero(to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_is_zero(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -499,7 +499,7 @@ extern "C" { LOG_Z3_mk_fpa_is_infinite(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_is_inf(to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_is_inf(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -509,7 +509,7 @@ extern "C" { LOG_Z3_mk_fpa_is_nan(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_is_nan(to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_is_nan(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -519,7 +519,7 @@ extern "C" { LOG_Z3_mk_fpa_is_negative(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_is_negative(to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_is_negative(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -529,7 +529,7 @@ extern "C" { LOG_Z3_mk_fpa_is_positive(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_is_positive(to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_is_positive(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -540,7 +540,7 @@ extern "C" { LOG_Z3_mk_fpa_to_fp_bv(c, bv, s); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - float_util & fu = ctx->float_util(); + 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); @@ -556,7 +556,7 @@ extern "C" { LOG_Z3_mk_fpa_to_fp_float(c, rm, t, s); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - float_util & fu = ctx->float_util(); + 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))) { @@ -573,7 +573,7 @@ extern "C" { LOG_Z3_mk_fpa_to_fp_real(c, rm, t, s); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - float_util & fu = ctx->float_util(); + 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))) { @@ -590,7 +590,7 @@ extern "C" { LOG_Z3_mk_fpa_to_fp_signed(c, rm, t, s); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - float_util & fu = ctx->float_util(); + 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))) { @@ -607,7 +607,7 @@ extern "C" { LOG_Z3_mk_fpa_to_fp_unsigned(c, rm, t, s); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - float_util & fu = ctx->float_util(); + 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))) { @@ -624,7 +624,7 @@ extern "C" { 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->float_util().mk_to_ubv(to_expr(rm), to_expr(t), sz)); + 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); } @@ -634,7 +634,7 @@ extern "C" { 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->float_util().mk_to_sbv(to_expr(rm), to_expr(t), sz)); + 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); } @@ -644,7 +644,7 @@ extern "C" { LOG_Z3_mk_fpa_to_real(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_to_real(to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_to_real(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -654,7 +654,7 @@ extern "C" { LOG_Z3_fpa_get_ebits(c, s); RESET_ERROR_CODE(); CHECK_NON_NULL(s, 0); - return mk_c(c)->float_util().get_ebits(to_sort(s)); + return mk_c(c)->fpa_util().get_ebits(to_sort(s)); Z3_CATCH_RETURN(0); } @@ -663,7 +663,7 @@ extern "C" { LOG_Z3_fpa_get_ebits(c, s); RESET_ERROR_CODE(); CHECK_NON_NULL(s, 0); - return mk_c(c)->float_util().get_sbits(to_sort(s)); + return mk_c(c)->fpa_util().get_sbits(to_sort(s)); Z3_CATCH_RETURN(0); } @@ -672,7 +672,7 @@ extern "C" { LOG_Z3_mk_fpa_to_ieee_bv(c, t); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - Z3_ast r = of_ast(ctx->float_util().mk_float_to_ieee_bv(to_expr(t))); + Z3_ast r = of_ast(ctx->fpa_util().mk_float_to_ieee_bv(to_expr(t))); RETURN_Z3(r); Z3_CATCH_RETURN(0); } @@ -682,7 +682,7 @@ extern "C" { LOG_Z3_mk_fpa_to_fp_real_int(c, rm, sig, exp, s); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); - float_util & fu = ctx->float_util(); + 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)) || diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 17a743880..89f01707e 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -59,7 +59,7 @@ extern "C" { RETURN_Z3(0); } sort * _ty = to_sort(ty); - bool is_float = mk_c(c)->float_util().is_float(_ty); + bool is_float = mk_c(c)->fpa_util().is_float(_ty); std::string fixed_num; char const* m = n; while (*m) { @@ -79,7 +79,7 @@ extern "C" { if (_ty->get_family_id() == mk_c(c)->get_fpa_fid()) { // avoid expanding floats into huge rationals. - float_util & fu = mk_c(c)->float_util(); + 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); @@ -149,7 +149,7 @@ extern "C" { return mk_c(c)->autil().is_numeral(e) || mk_c(c)->bvutil().is_numeral(e) || - mk_c(c)->float_util().is_value(e); + mk_c(c)->fpa_util().is_value(e); Z3_CATCH_RETURN(Z3_FALSE); } @@ -191,9 +191,9 @@ extern "C" { } else { // floats are separated from all others to avoid huge rationals. - float_util & fu = mk_c(c)->float_util(); + fpa_util & fu = mk_c(c)->fpa_util(); scoped_mpf tmp(fu.fm()); - if (mk_c(c)->float_util().is_value(to_expr(a), tmp)) { + if (mk_c(c)->fpa_util().is_value(to_expr(a), tmp)) { return mk_c(c)->mk_external_string(fu.fm().to_string(tmp)); } else { diff --git a/src/ast/ast_smt2_pp.h b/src/ast/ast_smt2_pp.h index bc62448c7..8aac71b8c 100644 --- a/src/ast/ast_smt2_pp.h +++ b/src/ast/ast_smt2_pp.h @@ -46,7 +46,7 @@ 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); @@ -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/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index be3e5f3ec..90bbd4901 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -906,7 +906,7 @@ bool fpa_decl_plugin::is_unique_value(app* e) const { } } -float_util::float_util(ast_manager & m): +fpa_util::fpa_util(ast_manager & m): m_manager(m), m_fid(m.mk_family_id("fpa")), m_a_util(m), @@ -914,67 +914,67 @@ float_util::float_util(ast_manager & m): m_plugin = static_cast(m.get_plugin(m_fid)); } -float_util::~float_util() { +fpa_util::~fpa_util() { } -sort * float_util::mk_float_sort(unsigned ebits, unsigned sbits) { +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 float_util::get_ebits(sort * s) { +unsigned fpa_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) { +unsigned fpa_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) { +app * fpa_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_pinf(unsigned ebits, unsigned sbits) { +app * fpa_util::mk_pinf(unsigned ebits, unsigned sbits) { scoped_mpf v(fm()); fm().mk_pinf(ebits, sbits, v); return mk_value(v); } -app * float_util::mk_ninf(unsigned ebits, unsigned sbits) { +app * fpa_util::mk_ninf(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) { +app * fpa_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) { +app * fpa_util::mk_nzero(unsigned ebits, unsigned sbits) { scoped_mpf v(fm()); fm().mk_nzero(ebits, sbits, v); return mk_value(v); } -app * float_util::mk_internal_to_ubv_unspecified(unsigned width) { +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 * float_util::mk_internal_to_sbv_unspecified(unsigned width) { +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 * float_util::mk_internal_to_real_unspecified() { +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 index b7d59a6af..b8d0c0c3e 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -207,15 +207,15 @@ public: virtual parameter translate(parameter const & p, decl_plugin & target); }; -class float_util { +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: - float_util(ast_manager & m); - ~float_util(); + fpa_util(ast_manager & m); + ~fpa_util(); ast_manager & m() const { return m_manager; } mpf_manager & fm() const { return m_plugin->fm(); } diff --git a/src/ast/rewriter/fpa_rewriter.h b/src/ast/rewriter/fpa_rewriter.h index 34a34b293..a10df95ca 100644 --- a/src/ast/rewriter/fpa_rewriter.h +++ b/src/ast/rewriter/fpa_rewriter.h @@ -26,7 +26,7 @@ Notes: #include"mpf.h" class fpa_rewriter { - float_util m_util; + fpa_util m_util; mpf_manager m_fm; app * mk_eq_nan(expr * arg); diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index d5ee9ff88..f5937955d 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -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 diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 7c4fce5cd..055f79b9d 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -51,8 +51,8 @@ namespace smt { 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_float_util.get_ebits(s); - unsigned sbits = m_th.m_float_util.get_sbits(s); + 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_triple(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), m_bv_util.mk_extract(sbits - 2, 0, bv), @@ -87,7 +87,7 @@ namespace smt { m_rw(m, m_converter, params_ref()), m_th_rw(m), m_trail_stack(*this), - m_float_util(m_converter.fu()), + m_fpa_util(m_converter.fu()), m_bv_util(m_converter.bu()), m_arith_util(m_converter.au()) { @@ -189,7 +189,7 @@ namespace smt { } app_ref theory_fpa::wrap(expr * e) { - SASSERT(!m_float_util.is_wrap(e)); + SASSERT(!m_fpa_util.is_wrap(e)); ast_manager & m = get_manager(); context & ctx = get_context(); sort * e_srt = m.get_sort(e); @@ -205,8 +205,8 @@ namespace smt { bv_srt = m_bv_util.mk_sort(3); else { SASSERT(m_converter.is_float(e_srt)); - unsigned ebits = m_float_util.get_ebits(e_srt); - unsigned sbits = m_float_util.get_sbits(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); } @@ -219,7 +219,7 @@ namespace smt { } app_ref theory_fpa::unwrap(expr * e, sort * s) { - SASSERT(!m_float_util.is_unwrap(e)); + SASSERT(!m_fpa_util.is_unwrap(e)); ast_manager & m = get_manager(); context & ctx = get_context(); sort * e_srt = m.get_sort(e); @@ -261,7 +261,7 @@ namespace smt { app_ref eca(to_app(ec), m); TRACE("t_fpa_detail", tout << "eca = " << mk_ismt2_pp(eca, m) << " sort is: " << mk_ismt2_pp(m.get_sort(eca), m) << std::endl;); - if (m_float_util.is_rm(e)) { + if (m_fpa_util.is_rm(e)) { expr_ref bv_rm(m); bv_rm = eca; TRACE("t_fpa_detail", tout << "bvrm = " << mk_ismt2_pp(bv_rm, m) << " sort is: " << mk_ismt2_pp(m.get_sort(bv_rm), m) << std::endl;); @@ -269,7 +269,7 @@ namespace smt { SASSERT(m_bv_util.get_bv_size(bv_rm) == 3); m_th_rw(bv_rm, res); } - else if (m_float_util.is_float(e)) { + else if (m_fpa_util.is_float(e)) { SASSERT(eca->get_family_id() == get_family_id()); fpa_op_kind k = (fpa_op_kind)(eca->get_decl_kind()); SASSERT(k == OP_FPA_TO_FP || k == OP_FPA_INTERNAL_BVUNWRAP); @@ -316,17 +316,17 @@ namespace smt { } expr_ref theory_fpa::convert_unwrap(expr * e) { - SASSERT(m_float_util.is_unwrap(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_float_util.is_rm(srt)) { + if (m_fpa_util.is_rm(srt)) { res = to_app(e)->get_arg(0); } else { - SASSERT(m_float_util.is_float(srt)); - unsigned ebits = m_float_util.get_ebits(srt); - unsigned sbits = m_float_util.get_sbits(srt); + SASSERT(m_fpa_util.is_float(srt)); + unsigned ebits = m_fpa_util.get_ebits(srt); + unsigned sbits = m_fpa_util.get_sbits(srt); expr * bv = to_app(e)->get_arg(0); unsigned bv_sz = m_bv_util.get_bv_size(bv); m_converter.mk_triple(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), @@ -351,11 +351,11 @@ namespace smt { return res; } else { - if (m_float_util.is_unwrap(e)) + if (m_fpa_util.is_unwrap(e)) res = convert_unwrap(e); else if (m.is_bool(e)) res = convert_atom(e); - else if (m_float_util.is_float(e) || m_float_util.is_rm(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); @@ -499,10 +499,10 @@ namespace smt { owner = n->get_owner(); owner_sort = m.get_sort(owner); - if (m_float_util.is_rm(owner_sort)) { + 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_float_util.is_unwrap(owner)) + if (!m_fpa_util.is_unwrap(owner)) { expr_ref valid(m), limit(m); limit = m_bv_util.mk_numeral(4, 3); @@ -511,7 +511,7 @@ namespace smt { } } - if (!ctx.relevancy() && !m_float_util.is_unwrap(owner)) + if (!ctx.relevancy() && !m_fpa_util.is_unwrap(owner)) assert_cnstr(m.mk_eq(unwrap(wrap(owner), owner_sort), owner)); } @@ -523,7 +523,7 @@ namespace smt { mk_ismt2_pp(get_enode(y)->get_owner(), m) << std::endl;); context & ctx = get_context(); - float_util & fu = m_float_util; + fpa_util & fu = m_fpa_util; bv_util & bu = m_bv_util; mpf_manager & mpfm = fu.fm(); @@ -570,7 +570,7 @@ namespace smt { mk_ismt2_pp(get_enode(y)->get_owner(), m) << std::endl;); context & ctx = get_context(); - mpf_manager & mpfm = m_float_util.fm(); + mpf_manager & mpfm = m_fpa_util.fm(); app * xe = get_enode(x)->get_owner(); app * ye = get_enode(y)->get_owner(); @@ -587,7 +587,7 @@ namespace smt { expr_ref c(m); - if (m_float_util.is_float(xe) && m_float_util.is_float(ye)) + if (m_fpa_util.is_float(xe) && m_fpa_util.is_float(ye)) { expr *x_sgn, *x_sig, *x_exp; m_converter.split_triple(xc, x_sgn, x_sig, x_exp); @@ -636,22 +636,22 @@ namespace smt { ast_manager & m = get_manager(); TRACE("t_fpa", tout << "relevant_eh for: " << mk_ismt2_pp(n, m) << "\n";); - mpf_manager & mpfm = m_float_util.fm(); + mpf_manager & mpfm = m_fpa_util.fm(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); - if (m_float_util.is_float(n) || m_float_util.is_rm(n)) { + if (m_fpa_util.is_float(n) || m_fpa_util.is_rm(n)) { sort * s = m.get_sort(n); - if (!m_float_util.is_unwrap(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_float_util.is_rm_value(n, rm)) { + if (m_fpa_util.is_rm_value(n, rm)) { c = m.mk_eq(wrapped, m_bv_util.mk_numeral(rm, 3)); assert_cnstr(c); } - else if (m_float_util.is_value(n, val)) { + else if (m_fpa_util.is_value(n, val)) { unsigned sz = val.get().get_ebits() + val.get().get_sbits(); expr_ref bv_val_e(m); bv_val_e = convert(n); @@ -670,7 +670,7 @@ namespace smt { } } else if (n->get_family_id() == get_family_id()) { - SASSERT(!m_float_util.is_float(n) && !m_float_util.is_rm(n)); + SASSERT(!m_fpa_util.is_float(n) && !m_fpa_util.is_rm(n)); // These are the conversion functions fp.to_* */ } else @@ -714,8 +714,8 @@ namespace smt { // If the owner is not internalized, it doesn't have an enode associated. SASSERT(ctx.e_internalized(owner)); - if (m_float_util.is_rm_value(owner) || - m_float_util.is_value(owner)) + if (m_fpa_util.is_rm_value(owner) || + m_fpa_util.is_value(owner)) return alloc(expr_wrapper_proc, owner); model_value_proc * res = 0; @@ -729,14 +729,14 @@ namespace smt { " (owner " << (!ctx.e_internalized(owner) ? "not" : "is") << " internalized)" << std::endl;); - if (m_float_util.is_rm(owner)) { + 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_float_util.is_float(owner)) { - unsigned ebits = m_float_util.get_ebits(m.get_sort(owner)); - unsigned sbits = m_float_util.get_sbits(m.get_sort(owner)); + 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); vp->add_dependency(ctx.get_enode(wrapped)); res = vp; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index c51b02c28..58af5ad1c 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -29,8 +29,8 @@ Revision History: namespace smt { - class fpa_factory : public value_factory { - float_util m_util; + class fpa_value_actory : 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()); @@ -39,11 +39,11 @@ namespace smt { } public: - fpa_factory(ast_manager & m, family_id fid) : + fpa_value_actory(ast_manager & m, family_id fid) : value_factory(m, fid), m_util(m) {} - virtual ~fpa_factory() {} + virtual ~fpa_value_actory() {} virtual expr * get_some_value(sort * s) { mpf_manager & mpfm = m_util.fm(); @@ -87,10 +87,10 @@ namespace smt { class fpa_value_proc : public model_value_proc { protected: - theory_fpa & m_th; + theory_fpa & m_th; ast_manager & m; - float_util & m_fu; - bv_util & m_bu; + fpa_util & m_fu; + bv_util & m_bu; buffer m_deps; unsigned m_ebits; unsigned m_sbits; diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 78ba64111..dfddfd12f 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(); diff --git a/src/tactic/fpa/qffpa_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp similarity index 96% rename from src/tactic/fpa/qffpa_tactic.cpp rename to src/tactic/fpa/qffp_tactic.cpp index c02166c18..e205a6c5e 100644 --- a/src/tactic/fpa/qffpa_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Tactic for QF_FPA benchmarks. + Tactic for QF_FP benchmarks. Author: @@ -23,7 +23,7 @@ Notes: #include"fpa2bv_tactic.h" #include"smt_tactic.h" -#include"qffpa_tactic.h" +#include"qffp_tactic.h" tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { params_ref simp_p = p; @@ -52,7 +52,7 @@ struct is_non_qffp_predicate { struct found {}; ast_manager & m; bv_util bu; - float_util fu; + fpa_util fu; arith_util au; is_non_qffp_predicate(ast_manager & _m) : m(_m), bu(m), fu(m), au(m) {} @@ -89,4 +89,4 @@ public: probe * mk_is_qffp_probe() { return alloc(is_qffp_probe); } - \ No newline at end of file + diff --git a/src/tactic/fpa/qffpa_tactic.h b/src/tactic/fpa/qffp_tactic.h similarity index 82% rename from src/tactic/fpa/qffpa_tactic.h rename to src/tactic/fpa/qffp_tactic.h index 3ab95798f..2842e3f73 100644 --- a/src/tactic/fpa/qffpa_tactic.h +++ b/src/tactic/fpa/qffp_tactic.h @@ -17,8 +17,8 @@ Notes: --*/ -#ifndef _QFFPA_TACTIC_H_ -#define _QFFPA_TACTIC_H_ +#ifndef _QFFP_TACTIC_H_ +#define _QFFP_TACTIC_H_ #include"params.h" class ast_manager; @@ -27,14 +27,14 @@ class tactic; tactic * mk_qffp_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_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_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/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index a01b547df..79b3e0e95 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" tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { tactic * st = using_params(and_then(mk_simplify_tactic(m), diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 9e0ce6e89..3c62bc80c 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,8 +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_FP" || logic=="QF_FPBV") + 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 From 0cedd32ea2663961d2f439d3858e525ff7a9f9dc Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 13:47:26 +0000 Subject: [PATCH 095/118] More renaming floats -> fpa Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.h | 4 ++-- src/smt/theory_fpa.cpp | 2 +- src/smt/theory_fpa.h | 20 ++++++++++---------- src/tactic/fpa/qffp_tactic.cpp | 7 +++++++ src/tactic/fpa/qffp_tactic.h | 1 + 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index f81edb653..efc4d9179 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -45,7 +45,7 @@ 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; @@ -62,7 +62,7 @@ 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; } diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 055f79b9d..487908173 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -700,7 +700,7 @@ namespace smt { void theory_fpa::init_model(model_generator & mg) { TRACE("t_fpa", tout << "initializing model" << std::endl; display(tout);); - m_factory = alloc(fpa_factory, get_manager(), get_family_id()); + m_factory = alloc(fpa_value_factory, get_manager(), get_family_id()); mg.register_factory(m_factory); } diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 58af5ad1c..33733d7d9 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -29,7 +29,7 @@ Revision History: namespace smt { - class fpa_value_actory : public value_factory { + class fpa_value_factory : public value_factory { fpa_util m_util; virtual app * mk_value_core(mpf const & val, sort * s) { @@ -39,11 +39,11 @@ namespace smt { } public: - fpa_value_actory(ast_manager & m, family_id fid) : + fpa_value_factory(ast_manager & m, family_id fid) : value_factory(m, fid), m_util(m) {} - virtual ~fpa_value_actory() {} + virtual ~fpa_value_factory() {} virtual expr * get_some_value(sort * s) { mpf_manager & mpfm = m_util.fm(); @@ -97,7 +97,7 @@ namespace smt { public: fpa_value_proc(theory_fpa * th, unsigned ebits, unsigned sbits) : - m_th(*th), m_fu(th->m_float_util), m_bu(th->m_bv_util), m(th->get_manager()), + 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() {} @@ -112,15 +112,15 @@ namespace smt { }; class fpa_rm_value_proc : public model_value_proc { - theory_fpa & m_th; + theory_fpa & m_th; ast_manager & m; - float_util & m_fu; - bv_util & m_bu; + 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_float_util), m_bu(th->m_bv_util), m(th->get_manager()) {} + 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)); } @@ -137,8 +137,8 @@ namespace smt { fpa2bv_rewriter m_rw; th_rewriter m_th_rw; th_trail_stack m_trail_stack; - fpa_factory * m_factory; - float_util & m_float_util; + fpa_value_factory * m_factory; + fpa_util & m_fpa_util; bv_util & m_bv_util; arith_util & m_arith_util; obj_map m_wraps; diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index e205a6c5e..5bc006f00 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -48,6 +48,10 @@ tactic * mk_qffp_tactic(ast_manager & m, params_ref const & 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; @@ -90,3 +94,6 @@ 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 index 2842e3f73..5c8caba2b 100644 --- a/src/tactic/fpa/qffp_tactic.h +++ b/src/tactic/fpa/qffp_tactic.h @@ -25,6 +25,7 @@ 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)") From c0a027fc809ba2f205b60571f4d5c16115379835 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 14:07:47 +0000 Subject: [PATCH 096/118] FPA: Elminated nzero/pzero AST kinds Signed-off-by: Christoph M. Wintersteiger --- src/api/api_ast.cpp | 2 -- src/ast/fpa/fpa2bv_rewriter.h | 4 +--- src/ast/fpa_decl_plugin.cpp | 4 ---- src/ast/fpa_decl_plugin.h | 4 ---- src/ast/rewriter/fpa_rewriter.cpp | 2 -- 5 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index c6b413dd4..eed5f7553 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1155,8 +1155,6 @@ extern "C" { 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_PZERO: return Z3_OP_FPA_IS_PZERO; - case OP_FPA_IS_NZERO: return Z3_OP_FPA_IS_NZERO; 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; diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index cbbd9e8a7..c7a987b83 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -143,9 +143,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { 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_NZERO: m_conv.mk_is_nzero(f, num, args, result); return BR_DONE; - case OP_FPA_IS_PZERO: m_conv.mk_is_pzero(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; diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 90bbd4901..52a1a95f7 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -294,8 +294,6 @@ func_decl * fpa_decl_plugin::mk_unary_rel_decl(decl_kind k, unsigned num_paramet symbol name; switch (k) { case OP_FPA_IS_ZERO: name = "fp.isZero"; break; - case OP_FPA_IS_NZERO: name = "fp.isNZero"; break; - case OP_FPA_IS_PZERO: name = "fp.isPZero"; 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; @@ -717,8 +715,6 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, 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_NZERO: - case OP_FPA_IS_PZERO: case OP_FPA_IS_NEGATIVE: case OP_FPA_IS_POSITIVE: case OP_FPA_IS_NAN: diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index b8d0c0c3e..44f0e62c4 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -71,8 +71,6 @@ enum fpa_op_kind { OP_FPA_IS_ZERO, OP_FPA_IS_NORMAL, OP_FPA_IS_SUBNORMAL, - OP_FPA_IS_PZERO, - OP_FPA_IS_NZERO, OP_FPA_IS_NEGATIVE, OP_FPA_IS_POSITIVE, @@ -325,8 +323,6 @@ public: 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_nzero(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NZERO, arg1); } - app * mk_is_pzero(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_PZERO, arg1); } app * mk_is_sign_minus(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NEGATIVE, 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); } diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 2977b7ab2..e7b8c7b34 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -57,8 +57,6 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con 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_NZERO: SASSERT(num_args == 1); st = mk_is_nzero(args[0], result); break; - case OP_FPA_IS_PZERO: SASSERT(num_args == 1); st = mk_is_pzero(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; From c5b220cc124739d0a5498bed7b079a14975d5af5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 14:07:59 +0000 Subject: [PATCH 097/118] FPA: Added AST kind descriptions Signed-off-by: Christoph M. Wintersteiger --- src/api/z3_api.h | 86 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 3c3a5d1c2..c719354b6 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -877,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_VALUE: 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 { @@ -1095,8 +1179,6 @@ typedef enum { Z3_OP_FPA_IS_ZERO, Z3_OP_FPA_IS_NORMAL, Z3_OP_FPA_IS_SUBNORMAL, - Z3_OP_FPA_IS_PZERO, - Z3_OP_FPA_IS_NZERO, Z3_OP_FPA_IS_NEGATIVE, Z3_OP_FPA_IS_POSITIVE, From c0bc2518b007184ad18aa486f8e4f4e61d800fcc Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 14:22:44 +0000 Subject: [PATCH 098/118] Renaming for consistency mk_value -> mk_numeral Signed-off-by: Christoph M. Wintersteiger --- src/api/api_ast.cpp | 2 +- src/api/api_numeral.cpp | 4 +- src/api/z3_api.h | 4 +- src/ast/fpa/fpa2bv_converter.cpp | 22 +++++------ src/ast/fpa_decl_plugin.cpp | 8 ++-- src/ast/fpa_decl_plugin.h | 36 +++++++++--------- src/ast/rewriter/fpa_rewriter.cpp | 62 +++++++++++++++---------------- src/smt/theory_fpa.cpp | 8 ++-- 8 files changed, 73 insertions(+), 73 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index eed5f7553..b9c6230b7 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1127,7 +1127,7 @@ extern "C" { 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_VALUE: return Z3_OP_FPA_VALUE; + 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; diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 89f01707e..7789f1157 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -149,7 +149,7 @@ extern "C" { return mk_c(c)->autil().is_numeral(e) || mk_c(c)->bvutil().is_numeral(e) || - mk_c(c)->fpa_util().is_value(e); + mk_c(c)->fpa_util().is_numeral(e); Z3_CATCH_RETURN(Z3_FALSE); } @@ -193,7 +193,7 @@ extern "C" { // floats are separated from all others to avoid huge rationals. fpa_util & fu = mk_c(c)->fpa_util(); scoped_mpf tmp(fu.fm()); - if (mk_c(c)->fpa_util().is_value(to_expr(a), tmp)) { + 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 { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index c719354b6..a4ad8d90d 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -887,7 +887,7 @@ typedef enum - Z3_OP_FPA_RM_TOWARD_ZERO: Floating-point rounding mode RTZ - - Z3_OP_FPA_VALUE: Floating-point value + - Z3_OP_FPA_NUM: Floating-point value - Z3_OP_FPA_PLUS_INF: Floating-point +oo @@ -1149,7 +1149,7 @@ typedef enum { Z3_OP_FPA_RM_TOWARD_NEGATIVE, Z3_OP_FPA_RM_TOWARD_ZERO, - Z3_OP_FPA_VALUE, + Z3_OP_FPA_NUM, Z3_OP_FPA_PLUS_INF, Z3_OP_FPA_MINUS_INF, Z3_OP_FPA_NAN, diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index dc1a255e8..4c570c1ba 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -80,7 +80,7 @@ void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) { mk_triple(sgn, s, e, 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()); @@ -2177,18 +2177,18 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con 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); + 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_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_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)); diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 52a1a95f7..7d4a77d1c 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -72,7 +72,7 @@ func_decl * fpa_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("fpa"), s, func_decl_info(m_family_id, OP_FPA_VALUE, 1, &p)); + return m_manager->mk_const_decl(symbol("fpa"), s, func_decl_info(m_family_id, OP_FPA_NUM, 1, &p)); } app * fpa_decl_plugin::mk_value(mpf const & v) { @@ -80,7 +80,7 @@ app * fpa_decl_plugin::mk_value(mpf const & v) { } bool fpa_decl_plugin::is_value(expr * n, mpf & val) { - if (is_app_of(n, m_family_id, OP_FPA_VALUE)) { + 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; } @@ -860,7 +860,7 @@ bool fpa_decl_plugin::is_value(app * e) const { case OP_FPA_RM_TOWARD_POSITIVE: case OP_FPA_RM_TOWARD_NEGATIVE: case OP_FPA_RM_TOWARD_ZERO: - case OP_FPA_VALUE: + case OP_FPA_NUM: case OP_FPA_PLUS_INF: case OP_FPA_MINUS_INF: case OP_FPA_PLUS_ZERO: @@ -891,7 +891,7 @@ bool fpa_decl_plugin::is_unique_value(app* e) const { 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_VALUE: /* see NaN */ + case OP_FPA_NUM: /* see NaN */ return false; case OP_FPA_FP: return m_manager->is_unique_value(e->get_arg(0)) && diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index 44f0e62c4..24481d348 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -41,7 +41,7 @@ enum fpa_op_kind { OP_FPA_RM_TOWARD_NEGATIVE, OP_FPA_RM_TOWARD_ZERO, - OP_FPA_VALUE, + OP_FPA_NUM, OP_FPA_PLUS_INF, OP_FPA_MINUS_INF, OP_FPA_NAN, @@ -189,12 +189,12 @@ public: virtual bool is_unique_value(app* e) const; 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_FPA_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); } + func_decl * mk_numeral_decl(mpf const & v); + app * mk_numeral(mpf const & v); + bool is_numeral(expr * n) { return is_app_of(n, m_family_id, OP_FPA_NUM); } + bool is_numeral(expr * n, mpf & val); + bool is_rm_numeral(expr * n, mpf_rounding_mode & val); + bool is_rm_numeral(expr * n) { mpf_rounding_mode t; return is_rm_numeral(n, t); } mpf const & get_value(unsigned id) const { SASSERT(m_value_table.contains(id)); @@ -244,23 +244,23 @@ public: 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_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) { return m_plugin->is_rm_value(n); } - bool is_rm_value(expr * n, mpf_rounding_mode & v) { return m_plugin->is_rm_value(n, v); } + 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_value(n, v) && fm().is_nan(v); } - bool is_pinf(expr * n) { scoped_mpf v(fm()); return is_value(n, v) && fm().is_pinf(v); } - bool is_ninf(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_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) { diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index e7b8c7b34..915d25e50 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -81,7 +81,7 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const if (num_args == 2) { mpf_rounding_mode rm; - if (!m_util.is_rm_value(args[0], rm)) + if (!m_util.is_rm_numeral(args[0], rm)) return BR_FAILED; rational q; @@ -95,7 +95,7 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const // TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); return BR_DONE; } - else if (m_util.is_value(args[1], q_mpf)) { + 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); @@ -116,7 +116,7 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const 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)) + if (!m_util.is_rm_numeral(args[0], rm)) return BR_FAILED; rational q; @@ -169,9 +169,9 @@ br_status fpa_rewriter::mk_to_fp_unsigned(func_decl * f, unsigned num_args, expr br_status fpa_rewriter::mk_add(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { mpf_rounding_mode rm; - if (m_util.is_rm_value(arg1, rm)) { + if (m_util.is_rm_numeral(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)) { + 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); @@ -190,9 +190,9 @@ br_status fpa_rewriter::mk_sub(expr * arg1, expr * arg2, expr * arg3, expr_ref & br_status fpa_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { mpf_rounding_mode rm; - if (m_util.is_rm_value(arg1, rm)) { + if (m_util.is_rm_numeral(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)) { + 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); @@ -205,9 +205,9 @@ br_status fpa_rewriter::mk_mul(expr * arg1, expr * arg2, expr * arg3, expr_ref & br_status fpa_rewriter::mk_div(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { mpf_rounding_mode rm; - if (m_util.is_rm_value(arg1, rm)) { + if (m_util.is_rm_numeral(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)) { + 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); @@ -241,7 +241,7 @@ br_status fpa_rewriter::mk_neg(expr * arg1, expr_ref & result) { } scoped_mpf v1(m_util.fm()); - if (m_util.is_value(arg1, v1)) { + if (m_util.is_numeral(arg1, v1)) { m_util.fm().neg(v1); result = m_util.mk_value(v1); return BR_DONE; @@ -253,7 +253,7 @@ br_status fpa_rewriter::mk_neg(expr * arg1, expr_ref & result) { 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_value(arg1, v1) && m_util.is_value(arg2, v2)) { + 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); @@ -316,9 +316,9 @@ br_status fpa_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { 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_value(arg1, 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_value(arg2, v2) && m_util.is_value(arg3, v3) && m_util.is_value(arg4, v4)) { + 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); @@ -331,9 +331,9 @@ br_status fpa_rewriter::mk_fma(expr * arg1, expr * arg2, expr * arg3, expr * arg br_status fpa_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) { mpf_rounding_mode rm; - if (m_util.is_rm_value(arg1, rm)) { + if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_util.fm()); - if (m_util.is_value(arg2, v2)) { + 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); @@ -346,9 +346,9 @@ br_status fpa_rewriter::mk_sqrt(expr * arg1, expr * arg2, expr_ref & result) { br_status fpa_rewriter::mk_round(expr * arg1, expr * arg2, expr_ref & result) { mpf_rounding_mode rm; - if (m_util.is_rm_value(arg1, rm)) { + if (m_util.is_rm_numeral(arg1, rm)) { scoped_mpf v2(m_util.fm()); - if (m_util.is_value(arg2, v2)) { + 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); @@ -362,7 +362,7 @@ br_status fpa_rewriter::mk_round(expr * arg1, expr * arg2, expr_ref & result) { // 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_value(arg1, v1) && m_util.is_value(arg2, v2)) { + 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; } @@ -407,7 +407,7 @@ br_status fpa_rewriter::mk_lt(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)) { + 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; } @@ -427,7 +427,7 @@ br_status fpa_rewriter::mk_le(expr * arg1, expr * arg2, expr_ref & result) { 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)) { + 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; } @@ -442,7 +442,7 @@ br_status fpa_rewriter::mk_ge(expr * arg1, expr * arg2, expr_ref & result) { br_status fpa_rewriter::mk_is_zero(expr * arg1, expr_ref & result) { scoped_mpf v(m_util.fm()); - if (m_util.is_value(arg1, v)) { + if (m_util.is_numeral(arg1, v)) { result = (m_util.fm().is_zero(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; } @@ -452,7 +452,7 @@ br_status fpa_rewriter::mk_is_zero(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_nzero(expr * arg1, expr_ref & result) { scoped_mpf v(m_util.fm()); - if (m_util.is_value(arg1, v)) { + if (m_util.is_numeral(arg1, v)) { result = (m_util.fm().is_nzero(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; } @@ -462,7 +462,7 @@ br_status fpa_rewriter::mk_is_nzero(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) { scoped_mpf v(m_util.fm()); - if (m_util.is_value(arg1, v)) { + if (m_util.is_numeral(arg1, v)) { result = (m_util.fm().is_pzero(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; } @@ -472,7 +472,7 @@ br_status fpa_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_nan(expr * arg1, expr_ref & result) { scoped_mpf v(m_util.fm()); - if (m_util.is_value(arg1, v)) { + if (m_util.is_numeral(arg1, v)) { result = (m_util.fm().is_nan(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; } @@ -482,7 +482,7 @@ br_status fpa_rewriter::mk_is_nan(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_inf(expr * arg1, expr_ref & result) { scoped_mpf v(m_util.fm()); - if (m_util.is_value(arg1, v)) { + if (m_util.is_numeral(arg1, v)) { result = (m_util.fm().is_inf(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; } @@ -492,7 +492,7 @@ br_status fpa_rewriter::mk_is_inf(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_normal(expr * arg1, expr_ref & result) { scoped_mpf v(m_util.fm()); - if (m_util.is_value(arg1, v)) { + if (m_util.is_numeral(arg1, v)) { result = (m_util.fm().is_normal(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; } @@ -502,7 +502,7 @@ br_status fpa_rewriter::mk_is_normal(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) { scoped_mpf v(m_util.fm()); - if (m_util.is_value(arg1, v)) { + if (m_util.is_numeral(arg1, v)) { result = (m_util.fm().is_denormal(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; } @@ -512,7 +512,7 @@ br_status fpa_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_negative(expr * arg1, expr_ref & result) { scoped_mpf v(m_util.fm()); - if (m_util.is_value(arg1, v)) { + if (m_util.is_numeral(arg1, v)) { result = (m_util.fm().is_neg(v)) ? m().mk_true() : m().mk_false(); return BR_DONE; } @@ -522,7 +522,7 @@ br_status fpa_rewriter::mk_is_negative(expr * arg1, expr_ref & result) { br_status fpa_rewriter::mk_is_positive(expr * arg1, expr_ref & result) { scoped_mpf v(m_util.fm()); - if (m_util.is_value(arg1, v)) { + 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; } @@ -534,7 +534,7 @@ br_status fpa_rewriter::mk_is_positive(expr * arg1, expr_ref & result) { // 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_value(arg1, v1) && m_util.is_value(arg2, v2)) { + 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() : @@ -584,7 +584,7 @@ br_status fpa_rewriter::mk_to_sbv(expr * arg1, expr * arg2, expr_ref & result) { br_status fpa_rewriter::mk_to_real(expr * arg1, expr_ref & result) { scoped_mpf fv(m_util.fm()); - if (m_util.is_value(arg1, fv)) { + 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(); } diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 487908173..158622428 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -647,11 +647,11 @@ namespace smt { wrapped = wrap(n); mpf_rounding_mode rm; scoped_mpf val(mpfm); - if (m_fpa_util.is_rm_value(n, rm)) { + 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_value(n, val)) { + 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); @@ -714,8 +714,8 @@ namespace smt { // If the owner is not internalized, it doesn't have an enode associated. SASSERT(ctx.e_internalized(owner)); - if (m_fpa_util.is_rm_value(owner) || - m_fpa_util.is_value(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; From 33dc6340e16ef1ae15b47495b5472a98edcb2128 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 14:23:13 +0000 Subject: [PATCH 099/118] More renaming mk_value -> mk_numeral Signed-off-by: Christoph M. Wintersteiger --- src/ast/ast_smt2_pp.cpp | 4 ++-- src/ast/fpa/fpa2bv_converter.h | 4 ++-- src/ast/fpa/fpa2bv_rewriter.h | 2 +- src/ast/fpa_decl_plugin.cpp | 14 +++++++------- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 982b80d37..035e228fb 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -228,7 +228,7 @@ format * smt2_pp_environment::pp_float_literal(app * t, bool use_bv_lits, bool u ast_manager & m = get_manager(); format * body = 0; string_buffer<> buf; - VERIFY(get_futil().is_value(t, v)); + VERIFY(get_futil().is_numeral(t, v)); if (fm.is_nan(v)) { buf << "(_ NaN " << v.get().get_ebits() << " " << v.get().get_sbits() << ")"; return mk_string(m, buf.c_str()); @@ -575,7 +575,7 @@ 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)) { + 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)) { diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index efc4d9179..062c56ef2 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -50,7 +50,7 @@ protected: arith_util m_arith_util; mpf_manager & m_mpf_manager; unsynch_mpz_manager & m_mpz_manager; - fpa_decl_plugin * m_plugin; + fpa_decl_plugin * m_plugin; bool m_hi_fp_unspecified; obj_map m_const2bv; @@ -86,7 +86,7 @@ public: 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_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); diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index c7a987b83..75176c9c4 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -120,7 +120,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { 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_VALUE: m_conv.mk_value(f, num, args, 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; diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 7d4a77d1c..a8e805066 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -68,18 +68,18 @@ void fpa_decl_plugin::recycled_id(unsigned id) { m_fm.del(m_values[id]); } -func_decl * fpa_decl_plugin::mk_value_decl(mpf const & v) { +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("fpa"), s, func_decl_info(m_family_id, OP_FPA_NUM, 1, &p)); } -app * fpa_decl_plugin::mk_value(mpf const & v) { - return m_manager->mk_const(mk_value_decl(v)); +app * fpa_decl_plugin::mk_numeral(mpf const & v) { + return m_manager->mk_const(mk_numeral_decl(v)); } -bool fpa_decl_plugin::is_value(expr * n, mpf & val) { +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; @@ -117,7 +117,7 @@ bool fpa_decl_plugin::is_value(expr * n, mpf & val) { return false; } -bool fpa_decl_plugin::is_rm_value(expr * n, mpf_rounding_mode & val) { +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; @@ -260,7 +260,7 @@ func_decl * fpa_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_param case OP_FPA_PLUS_ZERO: m_fm.mk_pzero(ebits, sbits, val); break; } - return mk_value_decl(val); + return mk_numeral_decl(val); } func_decl * fpa_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -846,7 +846,7 @@ 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_value(tmp); + expr * res = this->mk_numeral(tmp); m_fm.del(tmp); return res; } From bcbce8f190d93117abaaefe0a6de94cccda468a7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 16:31:09 +0000 Subject: [PATCH 100/118] FPA Java and .NET API updates Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Context.cs | 1 - src/api/dotnet/Expr.cs | 270 ++++++++++++++++++++++++++++ src/api/dotnet/FPExpr.cs | 12 +- src/api/dotnet/FPNum.cs | 1 - src/api/dotnet/FPRMNum.cs | 49 +++++ src/api/java/Expr.java | 366 +++++++++++++++++++++++++++++++++++++- 6 files changed, 693 insertions(+), 6 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 609db802d..9eb544f8a 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -4161,7 +4161,6 @@ namespace Microsoft.Z3 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 diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 826860eec..5f0c4218c 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -1448,6 +1448,276 @@ 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 IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_NUM; } } + + /// + /// Indicates whether the term is the floating-point rounding numeral roundNearestTiesToEven + /// + public bool IsFPRMNumRoundNearestTiesToEven{ 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 IsFPRMNumRoundNearestTiesToAway{ 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 IsFPRMNumRoundTowardNegative{ 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 IsFPRMNumRoundTowardPositive{ 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 IsFPRMNumRoundTowardZero{ 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 IsFPRMNumRNE{ 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 IsFPRMNumRNA { 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 IsFPRMNumRTN { 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 IsFPRMNumRTP { 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 IsFPRMNumRTZ { 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 IsFPRMNum { + 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 diff --git a/src/api/dotnet/FPExpr.cs b/src/api/dotnet/FPExpr.cs index cbba272d1..bbd557017 100644 --- a/src/api/dotnet/FPExpr.cs +++ b/src/api/dotnet/FPExpr.cs @@ -24,12 +24,22 @@ 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 protected FPExpr(Context ctx) diff --git a/src/api/dotnet/FPNum.cs b/src/api/dotnet/FPNum.cs index ab57d57c3..14c089198 100644 --- a/src/api/dotnet/FPNum.cs +++ b/src/api/dotnet/FPNum.cs @@ -27,7 +27,6 @@ namespace Microsoft.Z3 [ContractVerification(true)] public class FPNum : FPExpr { - #region Internal internal FPNum(Context ctx, IntPtr obj) : base(ctx, obj) diff --git a/src/api/dotnet/FPRMNum.cs b/src/api/dotnet/FPRMNum.cs index 7caa56f9f..628480d96 100644 --- a/src/api/dotnet/FPRMNum.cs +++ b/src/api/dotnet/FPRMNum.cs @@ -27,6 +27,55 @@ namespace Microsoft.Z3 [ContractVerification(true)] 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; } } #region Internal internal FPRMNum(Context ctx, IntPtr obj) diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index 233076516..4bd522b51 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -1709,6 +1709,366 @@ public class Expr extends AST return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FD_LT; } + + /** + * Indicates whether the terms is of floating-point sort. + * @throws Z3Exception + */ + public boolean IsFP() throws Z3Exception { return Z3_sort_kind.fromInt(Native.getSortKind(getContext().nCtx(), Native.getSort(getContext().nCtx(), getNativeObject()))) == Z3_sort_kind.Z3_FLOATING_POINT_SORT; } + + /** + * Indicates whether the terms is of floating-point rounding mode sort. + * @return + * @throws Z3Exception + */ + public boolean IsFPRM() throws Z3Exception { return Z3_sort_kind.fromInt(Native.getSortKind(getContext().nCtx(), Native.getSort(getContext().nCtx(), getNativeObject()))) == Z3_sort_kind.Z3_ROUNDING_MODE_SORT; } + + /** + * Indicates whether the term is a floating-point numeral + * @return + * @throws Z3Exception + */ + public boolean IsFPNumeral() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_NUM; } + + /** + * Indicates whether the term is the floating-point rounding numeral roundNearestTiesToEven + * @return + * @throws Z3Exception + */ + public boolean IsFPRMNumRoundNearestTiesToEven() 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 + * @return + * @throws Z3Exception + */ + public boolean IsFPRMNumRoundNearestTiesToAway() 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 roundTowardNegative + * @return + * @throws Z3Exception + */ + public boolean IsFPRMNumRoundTowardNegative() 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 roundTowardPositive + * @return + * @throws Z3Exception + */ + public boolean IsFPRMNumRoundTowardPositive() 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 roundTowardZero + * @return + * @throws Z3Exception + */ + public boolean IsFPRMNumRoundTowardZero() 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 roundNearestTiesToEven + * @return + * @throws Z3Exception + */ + public boolean IsFPRMNumRNE() 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 + * @return + * @throws Z3Exception + */ + public boolean IsFPRMNumRNA() 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 roundTowardNegative + * @return + * @throws Z3Exception + */ + public boolean IsFPRMNumRTN() 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 roundTowardPositive + * @return + * @throws Z3Exception + */ + public boolean IsFPRMNumRTP() 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 roundTowardZero + * @return + * @throws Z3Exception + */ + public boolean IsFPRMNumRTZ() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; } + + /** + * Indicates whether the term is a floating-point rounding mode numeral + * @return + * @throws Z3Exception + */ + public boolean IsFPRMNum() throws Z3Exception { + return isApp() && + (getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY || + getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN || + getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE || + getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE || + getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO); + } + + /** + * Indicates whether the term is a floating-point +oo + * @return + * @throws Z3Exception + */ + public boolean IsFPPlusInfinity() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_PLUS_INF; } + + /** + * Indicates whether the term is a floating-point -oo + * @return + * @throws Z3Exception + */ + public boolean IsFPMinusInfinity() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MINUS_INF; } + + /** + * Indicates whether the term is a floating-point NaN + * @return + * @throws Z3Exception + */ + public boolean IsFPNaN() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_NAN; } + + /** + * Indicates whether the term is a floating-point +zero + * @return + * @throws Z3Exception + */ + public boolean IsFPPlusZero() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_PLUS_ZERO; } + + /** + * Indicates whether the term is a floating-point -zero + * @return + * @throws Z3Exception + */ + public boolean IsFPMinusZero() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MINUS_ZERO; } + + /** + * Indicates whether the term is a floating-point addition term + * @return + * @throws Z3Exception + */ + public boolean IsFPAdd() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_ADD; } + + + /** + * Indicates whether the term is a floating-point subtraction term + * @return + * @throws Z3Exception + */ + public boolean IsFPSub() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_SUB; } + + /** + * Indicates whether the term is a floating-point negation term + * @return + * @throws Z3Exception + */ + public boolean IsFPNeg() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_NEG; } + + /** + * Indicates whether the term is a floating-point multiplication term + * @return + * @throws Z3Exception + */ + public boolean IsFPMul() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MUL; } + + /** + * Indicates whether the term is a floating-point divison term + * @return + * @throws Z3Exception + */ + public boolean IsFPDiv() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_DIV; } + + /** + * Indicates whether the term is a floating-point remainder term + * @return + * @throws Z3Exception + */ + public boolean IsFPRem() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_REM; } + + /** + * Indicates whether the term is a floating-point term absolute value term + * @return + * @throws Z3Exception + */ + public boolean IsFPAbs() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_ABS; } + + /** + * Indicates whether the term is a floating-point minimum term + * @return + * @throws Z3Exception + */ + public boolean IsFPMin() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MIN; } + + /** + * Indicates whether the term is a floating-point maximum term + * @return + * @throws Z3Exception + */ + public boolean IsFPMax() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MAX; } + + /** + * Indicates whether the term is a floating-point fused multiply-add term + * @return + * @throws Z3Exception + */ + public boolean IsFPFMA() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_FMA; } + + /** + * Indicates whether the term is a floating-point square root term + * @return + * @throws Z3Exception + */ + public boolean IsFPSqrt() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_SQRT; } + + /** + * Indicates whether the term is a floating-point roundToIntegral term + * @return + * @throws Z3Exception + */ + public boolean IsFPRoundToIntegral() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_ROUND_TO_INTEGRAL; } + + /** + * Indicates whether the term is a floating-point equality term + * @return + * @throws Z3Exception + */ + public boolean IsFPEq() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_EQ; } + + /** + * Indicates whether the term is a floating-point less-than term + * @return + * @throws Z3Exception + */ + public boolean IsFPLt() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_LT; } + + /** + * Indicates whether the term is a floating-point greater-than term + * @return + * @throws Z3Exception + */ + public boolean IsFPGt() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_GT; } + + /** + * Indicates whether the term is a floating-point less-than or equal term + * @return + * @throws Z3Exception + */ + public boolean IsFPLe() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_LE; } + + /** + * Indicates whether the term is a floating-point greater-than or erqual term + * @return + * @throws Z3Exception + */ + public boolean IsFPGe() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_GE; } + + /** + * Indicates whether the term is a floating-point isNaN predicate term + * @return + * @throws Z3Exception + */ + public boolean IsFPisNaN() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_NAN; } + + /** + * Indicates whether the term is a floating-point isInf predicate term + * @return + * @throws Z3Exception + */ + public boolean IsFPisInf() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_INF; } + + /** + * Indicates whether the term is a floating-point isZero predicate term + * @return + * @throws Z3Exception + */ + public boolean IsFPisZero() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_ZERO; } + + /** + * Indicates whether the term is a floating-point isNormal term + * @return + * @throws Z3Exception + */ + public boolean IsFPisNormal() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_NORMAL; } + + /** + * Indicates whether the term is a floating-point isSubnormal predicate term + * @return + * @throws Z3Exception + */ + public boolean IsFPisSubnormal() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_SUBNORMAL; } + + /** + * Indicates whether the term is a floating-point isNegative predicate term + * @return + * @throws Z3Exception + */ + public boolean IsFPisNegative() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_NEGATIVE; } + + /** + * Indicates whether the term is a floating-point isPositive predicate term + * @return + * @throws Z3Exception + */ + public boolean IsFPisPositive() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_POSITIVE; } + + /** + * Indicates whether the term is a floating-point constructor term + * @return + * @throws Z3Exception + */ + public boolean IsFPFP() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_FP; } + + /** + * Indicates whether the term is a floating-point conversion term + * @return + * @throws Z3Exception + */ + public boolean IsFPToFp() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_FP; } + + /** + * Indicates whether the term is a floating-point conversion from unsigned bit-vector term + * @return + * @throws Z3Exception + */ + public boolean IsFPToFpUnsigned() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_FP_UNSIGNED; } + + /** + * Indicates whether the term is a floating-point conversion to unsigned bit-vector term + * @return + * @throws Z3Exception + */ + public boolean IsFPToUBV() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_UBV; } + + /** + * Indicates whether the term is a floating-point conversion to signed bit-vector term + * @return + * @throws Z3Exception + */ + public boolean IsFPToSBV() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_SBV; } + + /** + * Indicates whether the term is a floating-point conversion to real term + * @return + * @throws Z3Exception + */ + public boolean IsFPToReal() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_REAL; } + + + /** + * Indicates whether the term is a floating-point conversion to IEEE-754 bit-vector term1 + * @return + * @throws Z3Exception + */ + public boolean IsFPToIEEEBV() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_IEEE_BV; } + + /** * The de-Burijn index of a bound variable. Bound variables are * indexed by de-Bruijn indices. It is perhaps easiest to explain the @@ -1793,8 +2153,8 @@ public class Expr extends AST return new BitVecNum(ctx, obj); case Z3_FLOATING_POINT_SORT: return new FPNum(ctx, obj); - case Z3_FLOATING_POINT_ROUNDING_MODE_SORT: - return new FPRMNum(ctx, obj); + case Z3_ROUNDING_MODE_SORT: + return new FPRMNum(ctx, obj); default: ; } } @@ -1815,7 +2175,7 @@ public class Expr extends AST return new DatatypeExpr(ctx, obj); case Z3_FLOATING_POINT_SORT: return new FPExpr(ctx, obj); - case Z3_FLOATING_POINT_ROUNDING_MODE_SORT: + case Z3_ROUNDING_MODE_SORT: return new FPRMExpr(ctx, obj); default: ; } From ee2c9095c67bd8fee43b1d92a2b1db4d32b0d29c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 17:21:29 +0000 Subject: [PATCH 101/118] .NET FPA API overhaul Signed-off-by: Christoph M. Wintersteiger --- examples/dotnet/Program.cs | 21 +++++++++++---------- src/api/dotnet/AST.cs | 12 ++++-------- src/api/dotnet/ArithExpr.cs | 5 ----- src/api/dotnet/ArrayExpr.cs | 5 ----- src/api/dotnet/BitVecExpr.cs | 1 - src/api/dotnet/BoolExpr.cs | 2 -- src/api/dotnet/DatatypeExpr.cs | 5 ----- src/api/dotnet/EnumSort.cs | 2 +- src/api/dotnet/Expr.cs | 4 ---- src/api/dotnet/FPExpr.cs | 5 ----- src/api/dotnet/FPRMExpr.cs | 5 ----- src/api/dotnet/IntExpr.cs | 5 ----- src/api/dotnet/ListSort.cs | 4 ++-- src/api/dotnet/Quantifier.cs | 4 ++-- src/api/dotnet/RealExpr.cs | 5 ----- src/api/dotnet/Sort.cs | 5 +++-- src/api/dotnet/TupleSort.cs | 2 +- 17 files changed, 24 insertions(+), 68 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index b03cfd28c..0c33d6793 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -2084,25 +2084,26 @@ namespace test_mapi 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); - RealExpr real_val = ctx.MkReal(42); - BitVecExpr bv_val = ctx.MkBV(42, 64); + FPExpr y = (FPExpr)ctx.MkConst(ctx.MkSymbol("y"), double_sort); FPExpr fp_val = ctx.MkFP(42, double_sort); - BoolExpr c1 = ctx.MkEq(x, ctx.MkFPToIEEEBV(fp_val)); - BoolExpr c2 = ctx.MkEq(x, ctx.MkBV(42, 64)); - BoolExpr c3 = ctx.MkEq(fp_val, ctx.MkFPToFP(rm, real_val, double_sort)); - BoolExpr c4 = ctx.MkAnd(c1, c2); - Console.WriteLine("c3 = " + c3); + 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(c3); + s.Assert(c5); + + Console.WriteLine(s); if (s.Check() != Status.SATISFIABLE) throw new TestFailedException(); - Console.WriteLine("OK, model: ", s.Model.ToString()); + Console.WriteLine("OK, model: {0}", s.Model.ToString()); } static void Main(string[] args) 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/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 5f0c4218c..97e57b920 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -1759,10 +1759,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 diff --git a/src/api/dotnet/FPExpr.cs b/src/api/dotnet/FPExpr.cs index bbd557017..85fdf2603 100644 --- a/src/api/dotnet/FPExpr.cs +++ b/src/api/dotnet/FPExpr.cs @@ -42,11 +42,6 @@ namespace Microsoft.Z3 #region Internal /// Constructor for FPExpr - internal protected FPExpr(Context ctx) - : base(ctx) - { - Contract.Requires(ctx != null); - } internal FPExpr(Context ctx, IntPtr obj) : base(ctx, obj) { diff --git a/src/api/dotnet/FPRMExpr.cs b/src/api/dotnet/FPRMExpr.cs index 92fea1ad4..896c3e6b9 100644 --- a/src/api/dotnet/FPRMExpr.cs +++ b/src/api/dotnet/FPRMExpr.cs @@ -32,11 +32,6 @@ namespace Microsoft.Z3 { #region Internal /// Constructor for FPRMExpr - internal protected FPRMExpr(Context ctx) - : base(ctx) - { - Contract.Requires(ctx != null); - } internal FPRMExpr(Context ctx, IntPtr obj) : base(ctx, obj) { diff --git a/src/api/dotnet/IntExpr.cs b/src/api/dotnet/IntExpr.cs index 58bf1b973..622be7bd5 100644 --- a/src/api/dotnet/IntExpr.cs +++ b/src/api/dotnet/IntExpr.cs @@ -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/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); From 7fe9ad5cb4a7829374e04f318d8b1b7bfd8b5b21 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 17:22:02 +0000 Subject: [PATCH 102/118] Java FPA API overhaul Signed-off-by: Christoph M. Wintersteiger --- examples/java/JavaExample.java | 20 ++++++++++---------- src/api/java/AST.java | 12 ++++-------- src/api/java/ArithExpr.java | 5 ----- src/api/java/ArrayExpr.java | 5 ----- src/api/java/BitVecExpr.java | 5 ----- src/api/java/BoolExpr.java | 8 -------- src/api/java/Context.java | 6 +----- src/api/java/DatatypeExpr.java | 5 ----- src/api/java/EnumSort.java | 2 +- src/api/java/Expr.java | 15 +-------------- src/api/java/IntExpr.java | 5 ----- src/api/java/ListSort.java | 2 +- src/api/java/Quantifier.java | 4 ++-- src/api/java/RealExpr.java | 5 ----- src/api/java/Sort.java | 13 ++++--------- src/api/java/TupleSort.java | 2 +- 16 files changed, 25 insertions(+), 89 deletions(-) diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 878ec4693..af8662700 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -2212,29 +2212,29 @@ class JavaExample { 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)); - RealExpr real_val = ctx.mkReal(42); + FPExpr y = (FPExpr)ctx.mkConst(ctx.mkSymbol("y"), double_sort); FPExpr fp_val = ctx.mkFP(42, double_sort); - - BoolExpr c1 = ctx.mkEq(x, ctx.mkFPToIEEEBV(fp_val)); - BoolExpr c2 = ctx.mkEq(x, ctx.mkBV(42, 64)); - BoolExpr c3 = ctx.mkEq(fp_val, ctx.mkFPToFP(rm, real_val, double_sort)); - BoolExpr c4 = ctx.mkAnd(c1, c2); - System.out.println("c3 = " + c3); + + 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(c3); + s.add(c5); if (s.check() != Status.SATISFIABLE) throw new TestFailedException(); - System.out.println("OK, model: " + s.getModel().toString()); + System.out.println("OK, model: " + s.getModel().toString()); } public static void main(String[] args) diff --git a/src/api/java/AST.java b/src/api/java/AST.java index 579d4b24d..5bea58054 100644 --- a/src/api/java/AST.java +++ b/src/api/java/AST.java @@ -213,10 +213,8 @@ public class AST extends Z3Object void incRef(long o) throws Z3Exception { // Console.WriteLine("AST IncRef()"); - if (getContext() == null) - throw new Z3Exception("inc() called on null context"); - if (o == 0) - throw new Z3Exception("inc() called on null AST"); + if (getContext() == null || o == 0) + return; getContext().ast_DRQ().incAndClear(getContext(), o); super.incRef(o); } @@ -224,10 +222,8 @@ public class AST extends Z3Object void decRef(long o) throws Z3Exception { // Console.WriteLine("AST DecRef()"); - if (getContext() == null) - throw new Z3Exception("dec() called on null context"); - if (o == 0) - throw new Z3Exception("dec() called on null AST"); + if (getContext() == null || o == 0) + return; getContext().ast_DRQ().add(o); super.decRef(o); } diff --git a/src/api/java/ArithExpr.java b/src/api/java/ArithExpr.java index 83ec35d01..97873f0b0 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 2d5a5a273..2985d19a2 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 24b1cfdf3..a7c704497 100644 --- a/src/api/java/BitVecExpr.java +++ b/src/api/java/BitVecExpr.java @@ -35,11 +35,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/BoolExpr.java b/src/api/java/BoolExpr.java index 99453496a..8f9d10d18 100644 --- a/src/api/java/BoolExpr.java +++ b/src/api/java/BoolExpr.java @@ -22,14 +22,6 @@ package com.microsoft.z3; **/ public class BoolExpr extends Expr { - /** - * Constructor for BoolExpr - **/ - protected BoolExpr(Context ctx) - { - super(ctx); - } - /** * Constructor for BoolExpr * @throws Z3Exception diff --git a/src/api/java/Context.java b/src/api/java/Context.java index cd3b9bebd..cfbd7c2c8 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -504,14 +504,10 @@ public class Context extends IDisposable **/ public Expr mkConst(Symbol name, Sort range) throws Z3Exception { - checkContextMatch(name); checkContextMatch(range); - return Expr.create( - this, - Native.mkConst(nCtx(), name.getNativeObject(), - range.getNativeObject())); + return Expr.create(this, Native.mkConst(nCtx(), name.getNativeObject(), range.getNativeObject())); } /** diff --git a/src/api/java/DatatypeExpr.java b/src/api/java/DatatypeExpr.java index 806ceacab..d4612e6ff 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 9715b9a97..51bdfe0e8 100644 --- a/src/api/java/EnumSort.java +++ b/src/api/java/EnumSort.java @@ -60,7 +60,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/Expr.java b/src/api/java/Expr.java index 4bd522b51..886c69f08 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -2092,24 +2092,12 @@ public class Expr extends AST return Native.getIndexValue(getContext().nCtx(), getNativeObject()); } - /** - * Constructor for Expr - **/ - protected Expr(Context ctx) - { - super(ctx); - { - } - } - /** * Constructor for Expr **/ protected Expr(Context ctx, long obj) throws Z3Exception { super(ctx, obj); - { - } } void checkNativeObject(long obj) throws Z3Exception @@ -2135,8 +2123,7 @@ public class Expr extends AST if (k == Z3_ast_kind.Z3_QUANTIFIER_AST) return new Quantifier(ctx, obj); long s = Native.getSort(ctx.nCtx(), obj); - Z3_sort_kind sk = Z3_sort_kind - .fromInt(Native.getSortKind(ctx.nCtx(), s)); + Z3_sort_kind sk = Z3_sort_kind.fromInt(Native.getSortKind(ctx.nCtx(), s)); if (Native.isAlgebraicNumber(ctx.nCtx(), obj)) // is this a numeral ast? return new AlgebraicNum(ctx, obj); diff --git a/src/api/java/IntExpr.java b/src/api/java/IntExpr.java index 2e90c3cbf..de3ae222a 100644 --- a/src/api/java/IntExpr.java +++ b/src/api/java/IntExpr.java @@ -25,11 +25,6 @@ public class IntExpr extends ArithExpr /** * Constructor for IntExpr **/ - 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 6188e2999..c699e13e2 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 7d89428c6..fa556e67f 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(), From cad841cff46cd380cec19fff5fc2a66dbef4aa29 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 17:23:13 +0000 Subject: [PATCH 103/118] to_fp_real marked as NIY for now Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 4c570c1ba..743434341 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2064,7 +2064,7 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * unsigned ebits = m_util.get_ebits(s); unsigned sbits = m_util.get_sbits(s); - if (false && m_bv_util.is_numeral(rm) && m_util.au().is_numeral(x)) { + 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(rm), tmp_rat, sz); SASSERT(tmp_rat.is_int32()); @@ -2096,6 +2096,8 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * mk_triple(sgn, s, e, result); } else { + NOT_IMPLEMENTED_YET(); + mpf_manager & fm = fu().fm(); bv_util & bu = m_bv_util; arith_util & au = m_arith_util; @@ -2135,16 +2137,16 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * //dbg_decouple("fpa2bv_to_float_real_inc", inc); //sig = m.mk_ite(inc, bu.mk_bv_add(sig, bv1_s4), sig); - SASSERT(bu.get_bv_size(sgn) == 1); - SASSERT(bu.get_bv_size(sig) == sbits + 4); - SASSERT(bu.get_bv_size(exp) == ebits + 2); + //SASSERT(bu.get_bv_size(sgn) == 1); + //SASSERT(bu.get_bv_size(sig) == sbits + 4); + //SASSERT(bu.get_bv_size(exp) == ebits + 2); - dbg_decouple("fpa2bv_to_float_real_sgn", sgn); - dbg_decouple("fpa2bv_to_float_real_sig", sig); - dbg_decouple("fpa2bv_to_float_real_exp", exp); + //dbg_decouple("fpa2bv_to_float_real_sgn", sgn); + //dbg_decouple("fpa2bv_to_float_real_sig", sig); + //dbg_decouple("fpa2bv_to_float_real_exp", exp); - expr_ref rmr(rm, m); - round(s, rmr, sgn, sig, exp, result); + //expr_ref rmr(rm, m); + //round(s, rmr, sgn, sig, exp, result); } SASSERT(is_well_sorted(m, result)); From 0381e4317ab7e5e2212ac4b36c1ed384456adf39 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 17:54:04 +0000 Subject: [PATCH 104/118] Formatting, mostly tabs. Signed-off-by: Christoph M. Wintersteiger --- src/api/api_numeral.cpp | 2 +- src/ast/ast.cpp | 52 +- src/ast/fpa/fpa2bv_converter.cpp | 2 +- src/ast/rewriter/dl_rewriter.cpp | 48 +- src/duality/duality_profiling.cpp | 22 +- src/duality/duality_rpfp.cpp | 2686 +++++++++++----------- src/muz/base/dl_context.cpp | 12 +- src/muz/duality/duality_dl_interface.cpp | 86 +- src/muz/transforms/dl_transforms.cpp | 2 +- src/tactic/aig/aig.cpp | 14 +- 10 files changed, 1448 insertions(+), 1478 deletions(-) diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 7789f1157..0745a8709 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -173,7 +173,7 @@ extern "C" { if (mk_c(c)->datalog_util().is_numeral(e, v)) { r = rational(v, rational::ui64()); return Z3_TRUE; - } + } return Z3_FALSE; Z3_CATCH_RETURN(Z3_FALSE); } diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 09965be85..5679c951b 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; diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 743434341..f6ce259f2 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3197,7 +3197,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) 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)); 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/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 cdc8fb3b2..6ef6d623a 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,42 +2443,42 @@ 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 { bool operator()(const expr &x, const expr &y){ @@ -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/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 2548d1180..2129a1810 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; 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/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/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index 9fdce96e9..991c4714b 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,9 +1528,9 @@ 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; From 71912830f13f991261220a427fcf06382bb62bfd Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 8 Jan 2015 17:54:44 +0000 Subject: [PATCH 105/118] Formatting, mostly tabs Signed-off-by: Christoph M. Wintersteiger --- src/ast/ast.cpp | 2 +- src/ast/ast_smt_pp.cpp | 2 +- src/ast/bv_decl_plugin.cpp | 14 ++++++------- src/ast/datatype_decl_plugin.cpp | 8 ++++---- src/ast/simplifier/distribute_forall.cpp | 2 +- src/cmd_context/basic_cmds.cpp | 2 +- src/muz/base/dl_boogie_proof.cpp | 2 +- src/muz/base/dl_context.cpp | 26 ++++++++++++------------ src/muz/fp/dl_cmds.cpp | 12 +++++------ src/muz/transforms/dl_mk_bit_blast.cpp | 2 +- src/tactic/aig/aig.cpp | 2 +- 11 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 5679c951b..b134d38cb 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -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_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/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/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/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 2129a1810..7c9c5813b 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -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/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/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index 991c4714b..e3101ad67 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -1531,7 +1531,7 @@ public: catch (aig_exception ex) { dec_ref(r); throw ex; - } + } dec_ref_result(r); return r; } From 46e236487be2fa172a021afce577f133e09acd06 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 9 Jan 2015 11:53:18 +0000 Subject: [PATCH 106/118] Eliminated FPRMNum classes Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Context.cs | 86 +++++++++++++++++----------------- src/api/dotnet/Expr.cs | 24 +++++----- src/api/dotnet/FPRMExpr.cs | 50 ++++++++++++++++++++ src/api/dotnet/FPRMNum.cs | 96 -------------------------------------- src/api/java/Context.java | 40 ++++++++-------- src/api/java/Expr.java | 2 - 6 files changed, 125 insertions(+), 173 deletions(-) delete mode 100644 src/api/dotnet/FPRMNum.cs diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 9eb544f8a..89a89b959 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3456,91 +3456,91 @@ namespace Microsoft.Z3 /// /// Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. /// - public FPRMNum MkFPRoundNearestTiesToEven() + public FPRMExpr MkFPRoundNearestTiesToEven() { - Contract.Ensures(Contract.Result() != null); - return new FPRMNum(this, Native.Z3_mk_fpa_round_nearest_ties_to_even(nCtx)); + 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() + public FPRMExpr MkFPRNE() { - Contract.Ensures(Contract.Result() != null); - return new FPRMNum(this, Native.Z3_mk_fpa_rne(nCtx)); + Contract.Ensures(Contract.Result() != null); + return new FPRMExpr(this, Native.Z3_mk_fpa_rne(nCtx)); } /// /// Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode. /// - public FPRMNum MkFPRoundNearestTiesToAway() + public FPRMExpr MkFPRoundNearestTiesToAway() { - Contract.Ensures(Contract.Result() != null); - return new FPRMNum(this, Native.Z3_mk_fpa_round_nearest_ties_to_away(nCtx)); + Contract.Ensures(Contract.Result() != null); + return new FPRMExpr(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() + public FPRMExpr MkFPRNA() { - Contract.Ensures(Contract.Result() != null); - return new FPRMNum(this, Native.Z3_mk_fpa_rna(nCtx)); + Contract.Ensures(Contract.Result() != null); + return new FPRMExpr(this, Native.Z3_mk_fpa_rna(nCtx)); } /// /// Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode. /// - public FPRMNum MkFPRoundTowardPositive() + public FPRMExpr MkFPRoundTowardPositive() { - Contract.Ensures(Contract.Result() != null); - return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_positive(nCtx)); + Contract.Ensures(Contract.Result() != null); + return new FPRMExpr(this, Native.Z3_mk_fpa_round_toward_positive(nCtx)); } /// /// Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode. /// - public FPRMNum MkFPRTP() + public FPRMExpr MkFPRTP() { - Contract.Ensures(Contract.Result() != null); - return new FPRMNum(this, Native.Z3_mk_fpa_rtp(nCtx)); + Contract.Ensures(Contract.Result() != null); + return new FPRMExpr(this, Native.Z3_mk_fpa_rtp(nCtx)); } /// /// Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode. /// - public FPRMNum MkFPRoundTowardNegative() + public FPRMExpr MkFPRoundTowardNegative() { - Contract.Ensures(Contract.Result() != null); - return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_negative(nCtx)); + Contract.Ensures(Contract.Result() != null); + return new FPRMExpr(this, Native.Z3_mk_fpa_round_toward_negative(nCtx)); } /// /// Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode. /// - public FPRMNum MkFPRTN() + public FPRMExpr MkFPRTN() { - Contract.Ensures(Contract.Result() != null); - return new FPRMNum(this, Native.Z3_mk_fpa_rtn(nCtx)); + Contract.Ensures(Contract.Result() != null); + return new FPRMExpr(this, Native.Z3_mk_fpa_rtn(nCtx)); } /// /// Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode. /// - public FPRMNum MkFPRoundTowardZero() + public FPRMExpr MkFPRoundTowardZero() { - Contract.Ensures(Contract.Result() != null); - return new FPRMNum(this, Native.Z3_mk_fpa_round_toward_zero(nCtx)); + Contract.Ensures(Contract.Result() != null); + return new FPRMExpr(this, Native.Z3_mk_fpa_round_toward_zero(nCtx)); } /// /// Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode. /// - public FPRMNum MkFPRTZ() + public FPRMExpr MkFPRTZ() { - Contract.Ensures(Contract.Result() != null); - return new FPRMNum(this, Native.Z3_mk_fpa_rtz(nCtx)); + Contract.Ensures(Contract.Result() != null); + return new FPRMExpr(this, Native.Z3_mk_fpa_rtz(nCtx)); } #endregion #endregion @@ -3637,7 +3637,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNaN(FPSort s) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_nan(nCtx, s.NativeObject)); } @@ -3648,7 +3648,7 @@ namespace Microsoft.Z3 /// indicates whether the result should be negative. public FPNum MkFPInf(FPSort s, bool negative) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_inf(nCtx, s.NativeObject, negative ? 1 : 0)); } @@ -3659,7 +3659,7 @@ namespace Microsoft.Z3 /// indicates whether the result should be negative. public FPNum MkFPZero(FPSort s, bool negative) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_zero(nCtx, s.NativeObject, negative ? 1 : 0)); } @@ -3670,7 +3670,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(float v, FPSort s) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_numeral_float(nCtx, v, s.NativeObject)); } @@ -3681,7 +3681,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(double v, FPSort s) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_numeral_double(nCtx, v, s.NativeObject)); } @@ -3692,7 +3692,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(int v, FPSort s) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_numeral_int(nCtx, v, s.NativeObject)); } @@ -3705,7 +3705,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(bool sgn, uint sig, int exp, FPSort s) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_numeral_uint_int(nCtx, sgn ? 1 : 0, sig, exp, s.NativeObject)); } @@ -3718,7 +3718,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFPNumeral(bool sgn, UInt64 sig, Int64 exp, FPSort s) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return new FPNum(this, Native.Z3_mk_fpa_numeral_uint64_int64(nCtx, sgn ? 1 : 0, sig, exp, s.NativeObject)); } @@ -3729,7 +3729,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFP(float v, FPSort s) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return MkFPNumeral(v, s); } @@ -3740,7 +3740,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFP(double v, FPSort s) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return MkFPNumeral(v, s); } @@ -3751,7 +3751,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFP(int v, FPSort s) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return MkFPNumeral(v, s); } @@ -3764,7 +3764,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFP(bool sgn, uint sig, int exp, FPSort s) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return MkFPNumeral(sgn, sig, exp, s); } @@ -3777,7 +3777,7 @@ namespace Microsoft.Z3 /// FloatingPoint sort. public FPNum MkFP(bool sgn, UInt64 sig, Int64 exp, FPSort s) { - Contract.Ensures(Contract.Result() != null); + Contract.Ensures(Contract.Result() != null); return MkFPNumeral(sgn, sig, exp, s); } diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 97e57b920..eb1d1c02d 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -1475,57 +1475,57 @@ namespace Microsoft.Z3 /// /// Indicates whether the term is the floating-point rounding numeral roundNearestTiesToEven /// - public bool IsFPRMNumRoundNearestTiesToEven{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN; } } + 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 IsFPRMNumRoundNearestTiesToAway{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY; } } + 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 IsFPRMNumRoundTowardNegative{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE; } } + 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 IsFPRMNumRoundTowardPositive{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE; } } + 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 IsFPRMNumRoundTowardZero{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; } } + 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 IsFPRMNumRNE{ get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN; } } + 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 IsFPRMNumRNA { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY; } } + 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 IsFPRMNumRTN { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE; } } + 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 IsFPRMNumRTP { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE; } } + 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 IsFPRMNumRTZ { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; } } + 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 IsFPRMNum { + public bool IsFPRMExpr { get { return IsApp && (FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY|| @@ -1809,7 +1809,7 @@ namespace Microsoft.Z3 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_FLOATING_POINT_SORT: return new FPNum(ctx, obj); - case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMNum(ctx, obj); + case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMExpr(ctx, obj); } } diff --git a/src/api/dotnet/FPRMExpr.cs b/src/api/dotnet/FPRMExpr.cs index 896c3e6b9..47ea3e670 100644 --- a/src/api/dotnet/FPRMExpr.cs +++ b/src/api/dotnet/FPRMExpr.cs @@ -30,6 +30,56 @@ namespace Microsoft.Z3 /// public class FPRMExpr : Expr { + /// + /// 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; } } + #region Internal /// Constructor for FPRMExpr internal FPRMExpr(Context ctx, IntPtr obj) diff --git a/src/api/dotnet/FPRMNum.cs b/src/api/dotnet/FPRMNum.cs deleted file mode 100644 index 628480d96..000000000 --- a/src/api/dotnet/FPRMNum.cs +++ /dev/null @@ -1,96 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - FPRMNum.cs - -Abstract: - - Z3 Managed API: Floating Point Rounding Mode Numerals - -Author: - - Christoph Wintersteiger (cwinter) 2013-06-10 - -Notes: - ---*/ -using System; -using System.Diagnostics.Contracts; - -namespace Microsoft.Z3 -{ - /// - /// FloatingPoint RoundingMode Numerals - /// - [ContractVerification(true)] - 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; } } - - #region Internal - internal FPRMNum(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/java/Context.java b/src/api/java/Context.java index cfbd7c2c8..29be4aae8 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2865,90 +2865,90 @@ public class Context extends IDisposable * Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. * @throws Z3Exception on error **/ - public FPRMNum mkFPRoundNearestTiesToEven() throws Z3Exception + public FPRMExpr mkFPRoundNearestTiesToEven() throws Z3Exception { - return new FPRMNum(this, Native.mkFpaRoundNearestTiesToEven(nCtx())); + return new FPRMExpr(this, Native.mkFpaRoundNearestTiesToEven(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. * @throws Z3Exception **/ - public FPRMNum mkFPRNE() throws Z3Exception + public FPRMExpr mkFPRNE() throws Z3Exception { - return new FPRMNum(this, Native.mkFpaRne(nCtx())); + return new FPRMExpr(this, Native.mkFpaRne(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode. * @throws Z3Exception **/ - public FPRMNum mkFPRoundNearestTiesToAway() throws Z3Exception + public FPRMExpr mkFPRoundNearestTiesToAway() throws Z3Exception { - return new FPRMNum(this, Native.mkFpaRoundNearestTiesToAway(nCtx())); + return new FPRMExpr(this, Native.mkFpaRoundNearestTiesToAway(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode. * @throws Z3Exception **/ - public FPRMNum mkFPRNA() throws Z3Exception + public FPRMExpr mkFPRNA() throws Z3Exception { - return new FPRMNum(this, Native.mkFpaRna(nCtx())); + return new FPRMExpr(this, Native.mkFpaRna(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode. * @throws Z3Exception **/ - public FPRMNum mkFPRoundTowardPositive() throws Z3Exception + public FPRMExpr mkFPRoundTowardPositive() throws Z3Exception { - return new FPRMNum(this, Native.mkFpaRoundTowardPositive(nCtx())); + return new FPRMExpr(this, Native.mkFpaRoundTowardPositive(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode. * @throws Z3Exception **/ - public FPRMNum mkFPRTP() throws Z3Exception + public FPRMExpr mkFPRTP() throws Z3Exception { - return new FPRMNum(this, Native.mkFpaRtp(nCtx())); + return new FPRMExpr(this, Native.mkFpaRtp(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode. * @throws Z3Exception **/ - public FPRMNum mkFPRoundTowardNegative() throws Z3Exception + public FPRMExpr mkFPRoundTowardNegative() throws Z3Exception { - return new FPRMNum(this, Native.mkFpaRoundTowardNegative(nCtx())); + return new FPRMExpr(this, Native.mkFpaRoundTowardNegative(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode. * @throws Z3Exception **/ - public FPRMNum mkFPRTN() throws Z3Exception + public FPRMExpr mkFPRTN() throws Z3Exception { - return new FPRMNum(this, Native.mkFpaRtn(nCtx())); + return new FPRMExpr(this, Native.mkFpaRtn(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode. * @throws Z3Exception **/ - public FPRMNum mkFPRoundTowardZero() throws Z3Exception + public FPRMExpr mkFPRoundTowardZero() throws Z3Exception { - return new FPRMNum(this, Native.mkFpaRoundTowardZero(nCtx())); + return new FPRMExpr(this, Native.mkFpaRoundTowardZero(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode. * @throws Z3Exception **/ - public FPRMNum mkFPRTZ() throws Z3Exception + public FPRMExpr mkFPRTZ() throws Z3Exception { - return new FPRMNum(this, Native.mkFpaRtz(nCtx())); + return new FPRMExpr(this, Native.mkFpaRtz(nCtx())); } /** FloatingPoint Sorts **/ diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index 886c69f08..49f49a295 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -2140,8 +2140,6 @@ public class Expr extends AST return new BitVecNum(ctx, obj); case Z3_FLOATING_POINT_SORT: return new FPNum(ctx, obj); - case Z3_ROUNDING_MODE_SORT: - return new FPRMNum(ctx, obj); default: ; } } From 3391c9c44c40057eba47d92cc7deceb782de35d8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 9 Jan 2015 11:53:24 +0000 Subject: [PATCH 107/118] typo fix Signed-off-by: Christoph M. Wintersteiger --- src/duality/duality_rpfp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index 6ef6d623a..764fc72ad 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -2478,7 +2478,7 @@ done: expr junct = negate ? Negate(f) : f; lits.push_back(junct); } - }| + } struct TermLt { bool operator()(const expr &x, const expr &y){ From ee0ec7fe3a05e569bcc3906d7721af08d621db46 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 10 Jan 2015 17:28:07 +0000 Subject: [PATCH 108/118] FPA API: numerals, .NET and Java Signed-off-by: Christoph M. Wintersteiger --- src/api/api_fpa.cpp | 89 +++++++++++++++++++++++++++++- src/api/api_numeral.cpp | 83 +++++++++++++++++----------- src/api/dotnet/Context.cs | 36 ++++++------ src/api/dotnet/Expr.cs | 9 ++- src/api/dotnet/FPNum.cs | 57 +++++++++++++++++++ src/api/dotnet/FPRMExpr.cs | 50 ----------------- src/api/dotnet/FPRMNum.cs | 100 +++++++++++++++++++++++++++++++++ src/api/java/Context.java | 40 +++++++------- src/api/java/Expr.java | 110 ++++++++++++++++++++----------------- src/api/java/FPExpr.java | 41 ++++++++++++++ src/api/java/FPNum.java | 86 +++++++++++++++++++++++++++++ src/api/java/FPRMExpr.java | 29 ++++++++++ src/api/java/FPRMNum.java | 90 ++++++++++++++++++++++++++++++ src/api/java/FPRMSort.java | 35 ++++++++++++ src/api/java/FPSort.java | 49 +++++++++++++++++ src/api/z3_fpa.h | 41 ++++++++++++++ 16 files changed, 770 insertions(+), 175 deletions(-) create mode 100644 src/api/dotnet/FPRMNum.cs create mode 100644 src/api/java/FPExpr.java create mode 100644 src/api/java/FPNum.java create mode 100644 src/api/java/FPRMExpr.java create mode 100644 src/api/java/FPRMNum.java create mode 100644 src/api/java/FPRMSort.java create mode 100644 src/api/java/FPSort.java diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 94dfaaa68..219f9b166 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -200,7 +200,8 @@ extern "C" { 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))); + 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); } @@ -210,7 +211,8 @@ extern "C" { 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))); + 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); } @@ -231,7 +233,10 @@ extern "C" { 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); + 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); @@ -667,6 +672,84 @@ extern "C" { 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); + *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 ""; + } + unsigned sbits = val.get().get_sbits(); + scoped_mpq q(mpqm); + mpqm.set(q, mpfm.sig(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 ""; + } + const mpf_exp_t exp = mpfm.exp(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); diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 0745a8709..d5a25dfc2 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -50,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); } @@ -64,20 +64,19 @@ extern "C" { char const* m = n; while (*m) { if (!(('0' <= *m && *m <= '9') || - ('/' == *m) || ('-' == *m) || - (' ' == *m) || ('\n' == *m) || - ('.' == *m) || ('e' == *m) || - ('E' == *m) || - (('p' == *m) && is_float) || - (('P' == *m)) && is_float)) { + ('/' == *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 = 0; - if (_ty->get_family_id() == mk_c(c)->get_fpa_fid()) - { + 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()); @@ -90,23 +89,11 @@ extern "C" { 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); } @@ -114,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); } @@ -127,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); } @@ -146,10 +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)->fpa_util().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); } @@ -193,7 +193,28 @@ extern "C" { // floats are separated from all others to avoid huge rationals. fpa_util & fu = mk_c(c)->fpa_util(); scoped_mpf tmp(fu.fm()); - if (mk_c(c)->fpa_util().is_numeral(to_expr(a), tmp)) { + 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 { diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 89a89b959..70777a6e8 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3465,82 +3465,82 @@ namespace Microsoft.Z3 /// /// Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. /// - public FPRMExpr MkFPRNE() + public FPRMNum MkFPRNE() { Contract.Ensures(Contract.Result() != null); - return new FPRMExpr(this, Native.Z3_mk_fpa_rne(nCtx)); + return new FPRMNum(this, Native.Z3_mk_fpa_rne(nCtx)); } /// /// Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode. /// - public FPRMExpr MkFPRoundNearestTiesToAway() + public FPRMNum MkFPRoundNearestTiesToAway() { Contract.Ensures(Contract.Result() != null); - return new FPRMExpr(this, Native.Z3_mk_fpa_round_nearest_ties_to_away(nCtx)); + 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 FPRMExpr MkFPRNA() + public FPRMNum MkFPRNA() { Contract.Ensures(Contract.Result() != null); - return new FPRMExpr(this, Native.Z3_mk_fpa_rna(nCtx)); + return new FPRMNum(this, Native.Z3_mk_fpa_rna(nCtx)); } /// /// Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode. /// - public FPRMExpr MkFPRoundTowardPositive() + public FPRMNum MkFPRoundTowardPositive() { Contract.Ensures(Contract.Result() != null); - return new FPRMExpr(this, Native.Z3_mk_fpa_round_toward_positive(nCtx)); + 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 FPRMExpr MkFPRTP() + public FPRMNum MkFPRTP() { Contract.Ensures(Contract.Result() != null); - return new FPRMExpr(this, Native.Z3_mk_fpa_rtp(nCtx)); + return new FPRMNum(this, Native.Z3_mk_fpa_rtp(nCtx)); } /// /// Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode. /// - public FPRMExpr MkFPRoundTowardNegative() + public FPRMNum MkFPRoundTowardNegative() { Contract.Ensures(Contract.Result() != null); - return new FPRMExpr(this, Native.Z3_mk_fpa_round_toward_negative(nCtx)); + 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 FPRMExpr MkFPRTN() + public FPRMNum MkFPRTN() { Contract.Ensures(Contract.Result() != null); - return new FPRMExpr(this, Native.Z3_mk_fpa_rtn(nCtx)); + return new FPRMNum(this, Native.Z3_mk_fpa_rtn(nCtx)); } /// /// Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode. /// - public FPRMExpr MkFPRoundTowardZero() + public FPRMNum MkFPRoundTowardZero() { Contract.Ensures(Contract.Result() != null); - return new FPRMExpr(this, Native.Z3_mk_fpa_round_toward_zero(nCtx)); + 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 FPRMExpr MkFPRTZ() + public FPRMNum MkFPRTZ() { Contract.Ensures(Contract.Result() != null); - return new FPRMExpr(this, Native.Z3_mk_fpa_rtz(nCtx)); + return new FPRMNum(this, Native.Z3_mk_fpa_rtz(nCtx)); } #endregion #endregion diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index eb1d1c02d..e3ff27da1 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -1470,7 +1470,12 @@ namespace Microsoft.Z3 /// /// Indicates whether the term is a floating-point numeral /// - public bool IsFPNumeral { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_NUM; } } + 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 @@ -1809,7 +1814,7 @@ namespace Microsoft.Z3 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_FLOATING_POINT_SORT: return new FPNum(ctx, obj); - case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMExpr(ctx, obj); + case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMNum(ctx, obj); } } diff --git a/src/api/dotnet/FPNum.cs b/src/api/dotnet/FPNum.cs index 14c089198..e85687ccf 100644 --- a/src/api/dotnet/FPNum.cs +++ b/src/api/dotnet/FPNum.cs @@ -27,6 +27,63 @@ namespace Microsoft.Z3 [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) diff --git a/src/api/dotnet/FPRMExpr.cs b/src/api/dotnet/FPRMExpr.cs index 47ea3e670..896c3e6b9 100644 --- a/src/api/dotnet/FPRMExpr.cs +++ b/src/api/dotnet/FPRMExpr.cs @@ -30,56 +30,6 @@ namespace Microsoft.Z3 /// public class FPRMExpr : Expr { - /// - /// 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; } } - #region Internal /// Constructor for FPRMExpr internal FPRMExpr(Context ctx, IntPtr obj) 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/java/Context.java b/src/api/java/Context.java index 29be4aae8..cfbd7c2c8 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2865,90 +2865,90 @@ public class Context extends IDisposable * Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. * @throws Z3Exception on error **/ - public FPRMExpr mkFPRoundNearestTiesToEven() throws Z3Exception + public FPRMNum mkFPRoundNearestTiesToEven() throws Z3Exception { - return new FPRMExpr(this, Native.mkFpaRoundNearestTiesToEven(nCtx())); + return new FPRMNum(this, Native.mkFpaRoundNearestTiesToEven(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the NearestTiesToEven rounding mode. * @throws Z3Exception **/ - public FPRMExpr mkFPRNE() throws Z3Exception + public FPRMNum mkFPRNE() throws Z3Exception { - return new FPRMExpr(this, Native.mkFpaRne(nCtx())); + return new FPRMNum(this, Native.mkFpaRne(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode. * @throws Z3Exception **/ - public FPRMExpr mkFPRoundNearestTiesToAway() throws Z3Exception + public FPRMNum mkFPRoundNearestTiesToAway() throws Z3Exception { - return new FPRMExpr(this, Native.mkFpaRoundNearestTiesToAway(nCtx())); + return new FPRMNum(this, Native.mkFpaRoundNearestTiesToAway(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the NearestTiesToAway rounding mode. * @throws Z3Exception **/ - public FPRMExpr mkFPRNA() throws Z3Exception + public FPRMNum mkFPRNA() throws Z3Exception { - return new FPRMExpr(this, Native.mkFpaRna(nCtx())); + return new FPRMNum(this, Native.mkFpaRna(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode. * @throws Z3Exception **/ - public FPRMExpr mkFPRoundTowardPositive() throws Z3Exception + public FPRMNum mkFPRoundTowardPositive() throws Z3Exception { - return new FPRMExpr(this, Native.mkFpaRoundTowardPositive(nCtx())); + return new FPRMNum(this, Native.mkFpaRoundTowardPositive(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardPositive rounding mode. * @throws Z3Exception **/ - public FPRMExpr mkFPRTP() throws Z3Exception + public FPRMNum mkFPRTP() throws Z3Exception { - return new FPRMExpr(this, Native.mkFpaRtp(nCtx())); + return new FPRMNum(this, Native.mkFpaRtp(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode. * @throws Z3Exception **/ - public FPRMExpr mkFPRoundTowardNegative() throws Z3Exception + public FPRMNum mkFPRoundTowardNegative() throws Z3Exception { - return new FPRMExpr(this, Native.mkFpaRoundTowardNegative(nCtx())); + return new FPRMNum(this, Native.mkFpaRoundTowardNegative(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardNegative rounding mode. * @throws Z3Exception **/ - public FPRMExpr mkFPRTN() throws Z3Exception + public FPRMNum mkFPRTN() throws Z3Exception { - return new FPRMExpr(this, Native.mkFpaRtn(nCtx())); + return new FPRMNum(this, Native.mkFpaRtn(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode. * @throws Z3Exception **/ - public FPRMExpr mkFPRoundTowardZero() throws Z3Exception + public FPRMNum mkFPRoundTowardZero() throws Z3Exception { - return new FPRMExpr(this, Native.mkFpaRoundTowardZero(nCtx())); + return new FPRMNum(this, Native.mkFpaRoundTowardZero(nCtx())); } /** * Create a numeral of RoundingMode sort which represents the RoundTowardZero rounding mode. * @throws Z3Exception **/ - public FPRMExpr mkFPRTZ() throws Z3Exception + public FPRMNum mkFPRTZ() throws Z3Exception { - return new FPRMExpr(this, Native.mkFpaRtz(nCtx())); + return new FPRMNum(this, Native.mkFpaRtz(nCtx())); } /** FloatingPoint Sorts **/ diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index 49f49a295..57f53ec6b 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -1714,98 +1714,105 @@ public class Expr extends AST * Indicates whether the terms is of floating-point sort. * @throws Z3Exception */ - public boolean IsFP() throws Z3Exception { return Z3_sort_kind.fromInt(Native.getSortKind(getContext().nCtx(), Native.getSort(getContext().nCtx(), getNativeObject()))) == Z3_sort_kind.Z3_FLOATING_POINT_SORT; } + public boolean isFP() throws Z3Exception { return Z3_sort_kind.fromInt(Native.getSortKind(getContext().nCtx(), Native.getSort(getContext().nCtx(), getNativeObject()))) == Z3_sort_kind.Z3_FLOATING_POINT_SORT; } /** * Indicates whether the terms is of floating-point rounding mode sort. * @return * @throws Z3Exception */ - public boolean IsFPRM() throws Z3Exception { return Z3_sort_kind.fromInt(Native.getSortKind(getContext().nCtx(), Native.getSort(getContext().nCtx(), getNativeObject()))) == Z3_sort_kind.Z3_ROUNDING_MODE_SORT; } + public boolean isFPRM() throws Z3Exception { return Z3_sort_kind.fromInt(Native.getSortKind(getContext().nCtx(), Native.getSort(getContext().nCtx(), getNativeObject()))) == Z3_sort_kind.Z3_ROUNDING_MODE_SORT; } /** * Indicates whether the term is a floating-point numeral * @return * @throws Z3Exception */ - public boolean IsFPNumeral() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_NUM; } + public boolean isFPNumeral() throws Z3Exception { return isFP() && isNumeral(); } + + /** + * Indicates whether the term is a floating-point rounding mode numeral + * @return + * @throws Z3Exception + */ + public boolean isFPRMNumeral() throws Z3Exception { return isFPRM() && isNumeral(); } /** * Indicates whether the term is the floating-point rounding numeral roundNearestTiesToEven * @return * @throws Z3Exception */ - public boolean IsFPRMNumRoundNearestTiesToEven() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN; } + public boolean isFPRMNumRoundNearestTiesToEven() 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 * @return * @throws Z3Exception */ - public boolean IsFPRMNumRoundNearestTiesToAway() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY; } + public boolean isFPRMNumRoundNearestTiesToAway() 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 roundTowardNegative * @return * @throws Z3Exception */ - public boolean IsFPRMNumRoundTowardNegative() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE; } + public boolean isFPRMNumRoundTowardNegative() 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 roundTowardPositive * @return * @throws Z3Exception */ - public boolean IsFPRMNumRoundTowardPositive() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE; } + public boolean isFPRMNumRoundTowardPositive() 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 roundTowardZero * @return * @throws Z3Exception */ - public boolean IsFPRMNumRoundTowardZero() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; } + public boolean isFPRMNumRoundTowardZero() 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 roundNearestTiesToEven * @return * @throws Z3Exception */ - public boolean IsFPRMNumRNE() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN; } + public boolean isFPRMNumRNE() 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 * @return * @throws Z3Exception */ - public boolean IsFPRMNumRNA() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY; } + public boolean isFPRMNumRNA() 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 roundTowardNegative * @return * @throws Z3Exception */ - public boolean IsFPRMNumRTN() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_NEGATIVE; } + public boolean isFPRMNumRTN() 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 roundTowardPositive * @return * @throws Z3Exception */ - public boolean IsFPRMNumRTP() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_POSITIVE; } + public boolean isFPRMNumRTP() 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 roundTowardZero * @return * @throws Z3Exception */ - public boolean IsFPRMNumRTZ() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; } + public boolean isFPRMNumRTZ() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_TOWARD_ZERO; } /** * Indicates whether the term is a floating-point rounding mode numeral * @return * @throws Z3Exception */ - public boolean IsFPRMNum() throws Z3Exception { + public boolean isFPRMNum() throws Z3Exception { return isApp() && (getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY || getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN || @@ -1819,42 +1826,42 @@ public class Expr extends AST * @return * @throws Z3Exception */ - public boolean IsFPPlusInfinity() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_PLUS_INF; } + public boolean isFPPlusInfinity() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_PLUS_INF; } /** * Indicates whether the term is a floating-point -oo * @return * @throws Z3Exception */ - public boolean IsFPMinusInfinity() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MINUS_INF; } + public boolean isFPMinusInfinity() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MINUS_INF; } /** * Indicates whether the term is a floating-point NaN * @return * @throws Z3Exception */ - public boolean IsFPNaN() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_NAN; } + public boolean isFPNaN() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_NAN; } /** * Indicates whether the term is a floating-point +zero * @return * @throws Z3Exception */ - public boolean IsFPPlusZero() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_PLUS_ZERO; } + public boolean isFPPlusZero() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_PLUS_ZERO; } /** * Indicates whether the term is a floating-point -zero * @return * @throws Z3Exception */ - public boolean IsFPMinusZero() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MINUS_ZERO; } + public boolean isFPMinusZero() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MINUS_ZERO; } /** * Indicates whether the term is a floating-point addition term * @return * @throws Z3Exception */ - public boolean IsFPAdd() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_ADD; } + public boolean isFPAdd() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_ADD; } /** @@ -1862,211 +1869,210 @@ public class Expr extends AST * @return * @throws Z3Exception */ - public boolean IsFPSub() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_SUB; } + public boolean isFPSub() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_SUB; } /** * Indicates whether the term is a floating-point negation term * @return * @throws Z3Exception */ - public boolean IsFPNeg() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_NEG; } + public boolean isFPNeg() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_NEG; } /** * Indicates whether the term is a floating-point multiplication term * @return * @throws Z3Exception */ - public boolean IsFPMul() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MUL; } + public boolean isFPMul() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MUL; } /** * Indicates whether the term is a floating-point divison term * @return * @throws Z3Exception */ - public boolean IsFPDiv() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_DIV; } + public boolean isFPDiv() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_DIV; } /** * Indicates whether the term is a floating-point remainder term * @return * @throws Z3Exception */ - public boolean IsFPRem() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_REM; } + public boolean isFPRem() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_REM; } /** * Indicates whether the term is a floating-point term absolute value term * @return * @throws Z3Exception */ - public boolean IsFPAbs() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_ABS; } + public boolean isFPAbs() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_ABS; } /** * Indicates whether the term is a floating-point minimum term * @return * @throws Z3Exception */ - public boolean IsFPMin() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MIN; } + public boolean isFPMin() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MIN; } /** * Indicates whether the term is a floating-point maximum term * @return * @throws Z3Exception */ - public boolean IsFPMax() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MAX; } + public boolean isFPMax() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_MAX; } /** * Indicates whether the term is a floating-point fused multiply-add term * @return * @throws Z3Exception */ - public boolean IsFPFMA() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_FMA; } + public boolean isFPFMA() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_FMA; } /** * Indicates whether the term is a floating-point square root term * @return * @throws Z3Exception */ - public boolean IsFPSqrt() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_SQRT; } + public boolean isFPSqrt() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_SQRT; } /** * Indicates whether the term is a floating-point roundToIntegral term * @return * @throws Z3Exception */ - public boolean IsFPRoundToIntegral() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_ROUND_TO_INTEGRAL; } + public boolean isFPRoundToIntegral() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_ROUND_TO_INTEGRAL; } /** * Indicates whether the term is a floating-point equality term * @return * @throws Z3Exception */ - public boolean IsFPEq() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_EQ; } + public boolean isFPEq() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_EQ; } /** * Indicates whether the term is a floating-point less-than term * @return * @throws Z3Exception */ - public boolean IsFPLt() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_LT; } + public boolean isFPLt() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_LT; } /** * Indicates whether the term is a floating-point greater-than term * @return * @throws Z3Exception */ - public boolean IsFPGt() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_GT; } + public boolean isFPGt() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_GT; } /** * Indicates whether the term is a floating-point less-than or equal term * @return * @throws Z3Exception */ - public boolean IsFPLe() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_LE; } + public boolean isFPLe() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_LE; } /** * Indicates whether the term is a floating-point greater-than or erqual term * @return * @throws Z3Exception */ - public boolean IsFPGe() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_GE; } + public boolean isFPGe() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_GE; } /** * Indicates whether the term is a floating-point isNaN predicate term * @return * @throws Z3Exception */ - public boolean IsFPisNaN() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_NAN; } + public boolean isFPisNaN() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_NAN; } /** * Indicates whether the term is a floating-point isInf predicate term * @return * @throws Z3Exception */ - public boolean IsFPisInf() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_INF; } + public boolean isFPisInf() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_INF; } /** * Indicates whether the term is a floating-point isZero predicate term * @return * @throws Z3Exception */ - public boolean IsFPisZero() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_ZERO; } + public boolean isFPisZero() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_ZERO; } /** * Indicates whether the term is a floating-point isNormal term * @return * @throws Z3Exception */ - public boolean IsFPisNormal() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_NORMAL; } + public boolean isFPisNormal() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_NORMAL; } /** * Indicates whether the term is a floating-point isSubnormal predicate term * @return * @throws Z3Exception */ - public boolean IsFPisSubnormal() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_SUBNORMAL; } + public boolean isFPisSubnormal() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_SUBNORMAL; } /** * Indicates whether the term is a floating-point isNegative predicate term * @return * @throws Z3Exception */ - public boolean IsFPisNegative() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_NEGATIVE; } + public boolean isFPisNegative() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_NEGATIVE; } /** * Indicates whether the term is a floating-point isPositive predicate term * @return * @throws Z3Exception */ - public boolean IsFPisPositive() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_POSITIVE; } + public boolean isFPisPositive() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_IS_POSITIVE; } /** * Indicates whether the term is a floating-point constructor term * @return * @throws Z3Exception */ - public boolean IsFPFP() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_FP; } + public boolean isFPFP() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_FP; } /** * Indicates whether the term is a floating-point conversion term * @return * @throws Z3Exception */ - public boolean IsFPToFp() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_FP; } + public boolean isFPToFp() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_FP; } /** * Indicates whether the term is a floating-point conversion from unsigned bit-vector term * @return * @throws Z3Exception */ - public boolean IsFPToFpUnsigned() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_FP_UNSIGNED; } + public boolean isFPToFpUnsigned() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_FP_UNSIGNED; } /** * Indicates whether the term is a floating-point conversion to unsigned bit-vector term * @return * @throws Z3Exception */ - public boolean IsFPToUBV() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_UBV; } + public boolean isFPToUBV() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_UBV; } /** * Indicates whether the term is a floating-point conversion to signed bit-vector term * @return * @throws Z3Exception */ - public boolean IsFPToSBV() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_SBV; } + public boolean isFPToSBV() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_SBV; } /** * Indicates whether the term is a floating-point conversion to real term * @return * @throws Z3Exception */ - public boolean IsFPToReal() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_REAL; } - + public boolean isFPToReal() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_REAL; } /** * Indicates whether the term is a floating-point conversion to IEEE-754 bit-vector term1 * @return * @throws Z3Exception */ - public boolean IsFPToIEEEBV() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_IEEE_BV; } + public boolean isFPToIEEEBV() throws Z3Exception { return isApp() && getFuncDecl().getDeclKind() == Z3_decl_kind.Z3_OP_FPA_TO_IEEE_BV; } /** @@ -2140,6 +2146,8 @@ public class Expr extends AST return new BitVecNum(ctx, obj); case Z3_FLOATING_POINT_SORT: return new FPNum(ctx, obj); + case Z3_ROUNDING_MODE_SORT: + return new FPRMNum(ctx, obj); default: ; } } 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/z3_fpa.h b/src/api/z3_fpa.h index 043d43e2f..7457ed9a3 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -834,6 +834,47 @@ extern "C" { */ 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. From 4bd8e0f4979c7cebad17207d268ba2e15f27de28 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 11 Jan 2015 18:28:07 +0000 Subject: [PATCH 109/118] FPA API cosmetics Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Context.cs | 12 ++++++------ src/api/java/Context.java | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 70777a6e8..1a36a35dc 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -3758,11 +3758,11 @@ namespace Microsoft.Z3 /// /// Create a numeral of FloatingPoint sort from a sign bit and two integers. /// - /// the sign. - /// the significand. + /// the sign. /// the exponent. + /// the significand. /// FloatingPoint sort. - public FPNum MkFP(bool sgn, uint sig, int exp, FPSort s) + public FPNum MkFP(bool sgn, int exp, uint sig, FPSort s) { Contract.Ensures(Contract.Result() != null); return MkFPNumeral(sgn, sig, exp, s); @@ -3771,11 +3771,11 @@ namespace Microsoft.Z3 /// /// Create a numeral of FloatingPoint sort from a sign bit and two 64-bit integers. /// - /// the sign. - /// the significand. + /// the sign. /// the exponent. + /// the significand. /// FloatingPoint sort. - public FPNum MkFP(bool sgn, UInt64 sig, Int64 exp, FPSort s) + public FPNum MkFP(bool sgn, Int64 exp, UInt64 sig, FPSort s) { Contract.Ensures(Contract.Result() != null); return MkFPNumeral(sgn, sig, exp, s); diff --git a/src/api/java/Context.java b/src/api/java/Context.java index cfbd7c2c8..2b4c47d76 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -3170,7 +3170,7 @@ public class Context extends IDisposable * @param s FloatingPoint sort. * @throws Z3Exception **/ - public FPNum mkFP(boolean sgn, int sig, int exp, FPSort s) throws Z3Exception + public FPNum mkFP(boolean sgn, int exp, int sig, FPSort s) throws Z3Exception { return mkFPNumeral(sgn, sig, exp, s); } @@ -3183,7 +3183,7 @@ public class Context extends IDisposable * @param s FloatingPoint sort. * @throws Z3Exception **/ - public FPNum mkFP(boolean sgn, long sig, long exp, FPSort s) throws Z3Exception + public FPNum mkFP(boolean sgn, long exp, long sig, FPSort s) throws Z3Exception { return mkFPNumeral(sgn, sig, exp, s); } From e0bc704106e15595856ec81419fb299dcb51aa87 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 11 Jan 2015 18:29:12 +0000 Subject: [PATCH 110/118] FPA API bugfixes Signed-off-by: Christoph M. Wintersteiger --- src/api/api_fpa.cpp | 26 +++++++++++++++++++------- src/api/z3_fpa.h | 6 +++--- src/ast/fpa_decl_plugin.cpp | 16 +++++++++++++++- src/util/mpf.h | 17 +++++++++++++++++ 4 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 219f9b166..67ffe12d9 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -217,7 +217,7 @@ extern "C" { Z3_CATCH_RETURN(0); } - Z3_ast Z3_API Z3_mk_fpa_fp(Z3_context c, Z3_ast sgn, Z3_ast sig, Z3_ast exp) { + 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(); @@ -680,7 +680,11 @@ extern "C" { 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); + 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); @@ -694,14 +698,18 @@ extern "C" { 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)) { + 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(val)); + 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); @@ -724,7 +732,11 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } - const mpf_exp_t exp = mpfm.exp(val); + 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()); @@ -740,7 +752,7 @@ extern "C" { 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); + bool r = plugin->is_numeral(to_expr(t), val); if (!r) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; diff --git a/src/api/z3_fpa.h b/src/api/z3_fpa.h index 7457ed9a3..75002e1a5 100644 --- a/src/api/z3_fpa.h +++ b/src/api/z3_fpa.h @@ -273,13 +273,13 @@ extern "C" { of the arguments. \params c logical context. - \params sgn sign - \params sig significand + \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 sig, __in Z3_ast exp); + 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. diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index a8e805066..9900812dd 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -76,7 +76,21 @@ func_decl * fpa_decl_plugin::mk_numeral_decl(mpf const & v) { } app * fpa_decl_plugin::mk_numeral(mpf const & v) { - return m_manager->mk_const(mk_numeral_decl(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) { diff --git a/src/util/mpf.h b/src/util/mpf.h index b919e0371..599e8e743 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -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); From 6c971b130132c8774d5e92b2a331a5a702485382 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sun, 11 Jan 2015 18:29:40 +0000 Subject: [PATCH 111/118] Beginnings of a Python API for FPA Signed-off-by: Christoph M. Wintersteiger --- src/api/python/z3.py | 912 ++++++++++++++++++++++++++++++++++++ src/api/python/z3printer.py | 207 +++++++- 2 files changed, 1114 insertions(+), 5 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index bb0212820..a2f0191cf 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,17 @@ 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: + e = ExprRef(a, ctx) + if e.decl().kind() == Z3_OP_FPA_NUM: + return FPNumRef(a, ctx) + else: + return FPRef(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 +7444,900 @@ 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): + return (self.num_args() == 0 and (Z3_OP_FPA_MINUS_INF or 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 expressions") + 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 expressions") + 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_mul(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) \ No newline at end of file diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py index d1d85d30e..a74a67fa8 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,65 @@ _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 : '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 : '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_NEG : 'fpNeg', 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_NEG : '-', 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 +183,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 +516,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 +553,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 +576,118 @@ 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 _z3_op_to_fpa_pretty_str.has_key(a.decl().kind()): + return to_format(_z3_op_to_fpa_pretty_str.get(a.decl().kind())) + else: + return to_format(a.as_string()) + + 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_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: + op = _z3_op_to_fpa_pretty_str.get(k, None) + if (op == None): + op = _z3_op_to_str.get(k, None) + + n = a.num_args() + + if self.fpa_pretty and 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) + + if _z3_op_to_fpa_normal_str.has_key(k): + op = _z3_op_to_fpa_normal_str.get(k, None) + + 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 +846,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 +1113,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 +1145,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) From caafee0033bf3df860dff3c53694f42075c9978a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 15 Jan 2015 19:18:18 +0000 Subject: [PATCH 112/118] Added simplifier plugin for FP --- src/ast/simplifier/fpa_simplifier_plugin.cpp | 43 ++++++++++++++++++++ src/ast/simplifier/fpa_simplifier_plugin.h | 40 ++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/ast/simplifier/fpa_simplifier_plugin.cpp create mode 100644 src/ast/simplifier/fpa_simplifier_plugin.h 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_ */ From 5344d6f3c02f02aa980f916eb8ae09acba7ae81b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 15 Jan 2015 19:25:49 +0000 Subject: [PATCH 113/118] various bugfixes and extensions for FPA Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 237 ++++++------- src/ast/fpa/fpa2bv_converter.h | 16 +- src/ast/fpa/fpa2bv_rewriter.h | 10 +- src/ast/fpa_decl_plugin.cpp | 12 +- src/ast/fpa_decl_plugin.h | 7 +- src/ast/rewriter/fpa_rewriter.cpp | 10 +- src/smt/asserted_formulas.cpp | 4 +- src/smt/theory_fpa.cpp | 412 +++++++++++++--------- src/tactic/fpa/fpa2bv_model_converter.cpp | 2 +- src/tactic/fpa/qffp_tactic.cpp | 27 +- 10 files changed, 396 insertions(+), 341 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index f6ce259f2..4cdb64d8d 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -44,8 +44,8 @@ fpa2bv_converter::~fpa2bv_converter() { } void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { - SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_FPA_TO_FP)); - SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FPA_TO_FP)); + 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); @@ -64,20 +64,20 @@ 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_FPA_TO_FP)); - SASSERT(is_app_of(f, m_plugin->get_family_id(), OP_FPA_TO_FP)); + 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_triple(t, t_sgn, t_sig, t_exp); - split_triple(f, 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, 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_numeral(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -111,7 +111,7 @@ void fpa2bv_converter::mk_numeral(func_decl * f, unsigned num, expr * const * ar 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;); @@ -158,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); @@ -177,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) @@ -191,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_triple(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); @@ -210,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); @@ -256,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); } } @@ -300,10 +300,10 @@ void fpa2bv_converter::mk_pinf(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(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_ninf(func_decl * f, expr_ref & result) { @@ -313,10 +313,10 @@ void fpa2bv_converter::mk_ninf(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(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) { @@ -326,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) { @@ -339,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) { @@ -352,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, @@ -607,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_triple(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) { @@ -1027,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_triple(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) { @@ -1038,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_triple(x, x_sgn, x_sig, x_exp); - split_triple(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); @@ -1071,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) { @@ -1081,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_triple(x, x_sgn, x_sig, x_exp); - split_triple(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); @@ -1114,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) { @@ -1689,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_triple(x, x_sgn, x_sig, x_exp); - split_triple(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); @@ -1725,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_triple(x, x_sgn, x_sig, x_exp); - split_triple(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); @@ -1863,10 +1863,10 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args int sz = m_bv_util.get_bv_size(bv); SASSERT((unsigned)sz == to_sbits + to_ebits); - 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 && m_bv_util.is_bv(args[0]) && @@ -1895,7 +1895,7 @@ void fpa2bv_converter::mk_to_fp(func_decl * f, unsigned num, expr * const * args 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_triple(args[0], args[2], args[1], result); + mk_fp(args[0], args[1], args[2], result); } else if (num == 3 && m_bv_util.is_bv(args[0]) && @@ -2061,6 +2061,8 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * 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); @@ -2093,11 +2095,9 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v), ebits); mk_bias(unbiased_exp, e); - mk_triple(sgn, s, e, result); + mk_fp(sgn, e, s, result); } - else { - NOT_IMPLEMENTED_YET(); - + else { mpf_manager & fm = fu().fm(); bv_util & bu = m_bv_util; arith_util & au = m_arith_util; @@ -2109,44 +2109,15 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * two = au.mk_numeral(rational(2), false); expr_ref sgn(m), sig(m), exp(m); - sgn = m.mk_ite(au.mk_lt(x, zero), bv1, bv0); - sig = bu.mk_numeral(0, sbits + 4); - mpz const & max_normal_exponent = fm.m_powers2.m1(ebits-1); - exp = bu.mk_numeral(max_normal_exponent, ebits); - - //expr_ref cur_s(m), cur_d(m), cur_r(m), cur_s2(m), bv1_s4(m); - //bv1_s4 = bu.mk_numeral(1, sbits + 4); - //cur_s = x; - //std::string trace_name; - //for (unsigned i = 0; i < sbits + 3; i++) { - // std::stringstream dbg_name; - // dbg_name << "fpa2bv_to_float_real_sig_" << i; - // dbg_decouple(dbg_name.str().c_str(), sig); + 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); - // cur_s = au.mk_div(cur_s, two); - // // cur_r = au.mk_rem(cur_s, two); - // cur_r = au.mk_mod(cur_s, two); - // cur_s2 = bu.mk_bv_shl(sig, bv1_s4); - // sig = m.mk_ite(au.mk_eq(cur_r, zero), - // cur_s2, - // bu.mk_bv_add(cur_s2, bv1_s4)); - //} - //dbg_decouple("fpa2bv_to_float_real_last_cur_s", cur_s); - //expr_ref inc(m); - //inc = m.mk_not(m.mk_eq(cur_s, zero)); - //dbg_decouple("fpa2bv_to_float_real_inc", inc); - //sig = m.mk_ite(inc, bu.mk_bv_add(sig, bv1_s4), sig); - - //SASSERT(bu.get_bv_size(sgn) == 1); - //SASSERT(bu.get_bv_size(sig) == sbits + 4); - //SASSERT(bu.get_bv_size(exp) == ebits + 2); + expr_ref rme(rm, m); + round(s, rme, sgn, sig, exp, result); - //dbg_decouple("fpa2bv_to_float_real_sgn", sgn); - //dbg_decouple("fpa2bv_to_float_real_sig", sig); - //dbg_decouple("fpa2bv_to_float_real_exp", exp); - - //expr_ref rmr(rm, m); - //round(s, rmr, 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)); @@ -2208,7 +2179,7 @@ void fpa2bv_converter::mk_to_real(func_decl * f, unsigned num, expr * const * ar 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_TO_FP)); + SASSERT(is_app_of(args[0], m_plugin->get_family_id(), OP_FPA_FP)); expr * x = args[0]; sort * s = m.get_sort(x); @@ -2565,19 +2536,10 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con 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_triple(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_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - SASSERT(num == 3); - 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_triple(args[0], args[2], args[1], 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) { TRACE("fpa2bv_to_ubv", for (unsigned i = 0; i < num; i++) tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); @@ -2753,6 +2715,10 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg 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); @@ -2777,8 +2743,8 @@ void fpa2bv_converter::mk_to_sbv(func_decl * f, unsigned num, expr * const * arg 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); + 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 ...] @@ -2861,28 +2827,43 @@ expr_ref fpa2bv_converter::mk_to_real_unspecified() { return expr_ref(m_util.mk_internal_to_real_unspecified(), m); } -void fpa2bv_converter::split_triple(expr * e, expr * & sgn, expr * & sig, expr * & exp) const { - SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_TO_FP)); - SASSERT(to_app(e)->get_num_args() == 3); - +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); + 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::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::split_triple(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp) const { - SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_FPA_TO_FP)); +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); expr *e_sgn, *e_sig, *e_exp; - split_triple(e, e_sgn, e_sig, e_exp); + split_fp(e, e_sgn, e_exp, e_sig); sgn = e_sgn; - sig = e_sig; exp = e_exp; + sig = e_sig; } void fpa2bv_converter::mk_is_nan(expr * e, expr_ref & result) { expr * sgn, * sig, * exp; - split_triple(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); @@ -2897,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_triple(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)); @@ -2921,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_FPA_TO_FP)); + 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); @@ -2930,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_FPA_TO_FP)); + 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); @@ -2940,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_triple(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)); @@ -2951,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_triple(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); @@ -2961,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_triple(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); @@ -2971,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_triple(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); @@ -2979,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_triple(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); @@ -3093,7 +3074,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_FPA_TO_FP)); + 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(); @@ -3101,7 +3082,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); - split_triple(e, sgn, sig, exp); + 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); @@ -3134,7 +3119,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) { @@ -3545,7 +3530,7 @@ 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; ); } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 062c56ef2..82fad6ff9 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -72,15 +72,11 @@ 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_FPA_TO_FP, sign, exponent, significand); - } + 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_triple(expr * e, expr * & sgn, expr * & sig, expr * & exp) const; - void split_triple(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp) const; + 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); @@ -125,9 +121,7 @@ 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_fp(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_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); diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h index 75176c9c4..ed885a4cc 100644 --- a/src/ast/fpa/fpa2bv_rewriter.h +++ b/src/ast/fpa/fpa2bv_rewriter.h @@ -259,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_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 9900812dd..8cf158604 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -72,7 +72,7 @@ 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("fpa"), s, func_decl_info(m_family_id, OP_FPA_NUM, 1, &p)); + 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) { @@ -131,6 +131,11 @@ bool fpa_decl_plugin::is_numeral(expr * n, mpf & val) { 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; @@ -156,6 +161,11 @@ bool fpa_decl_plugin::is_rm_numeral(expr * n, mpf_rounding_mode & val) { 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()); diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index 24481d348..fc1521456 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -191,10 +191,10 @@ public: 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) { return is_app_of(n, m_family_id, OP_FPA_NUM); } + 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_rounding_mode t; return is_rm_numeral(n, t); } + bool is_rm_numeral(expr * n); mpf const & get_value(unsigned id) const { SASSERT(m_value_table.contains(id)); @@ -322,8 +322,7 @@ public: 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_sign_minus(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NEGATIVE, 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); } diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 915d25e50..ce7fe5ed6 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -131,7 +131,7 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const 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); + m_util.fm().del(v); return BR_DONE; } else if (bu.is_numeral(args[0], r1, bvs1) && @@ -268,10 +268,8 @@ br_status fpa_rewriter::mk_abs(expr * arg1, expr_ref & result) { 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; + + return BR_FAILED; } br_status fpa_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { @@ -565,7 +563,7 @@ br_status fpa_rewriter::mk_fp(expr * arg1, expr * arg2, expr * arg3, expr_ref & 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;); + TRACE("fp_rewriter", tout << "simplified (fp ...) to " << m_util.fm().to_string(v) << std::endl;); result = m_util.mk_value(v); return BR_DONE; } 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/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 158622428..ac9bd5141 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -54,11 +54,11 @@ namespace smt { 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_triple(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), - m_bv_util.mk_extract(sbits - 2, 0, bv), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), - result); - + 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); @@ -97,62 +97,86 @@ namespace smt { } 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); + dec_ref_map_values(m, m_unwraps); } app * theory_fpa::fpa_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;); + mpf_manager & mpfm = m_fu.fm(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); - unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); - - SASSERT(m_bu.get_bv_size(values[0]) == (m_ebits + m_sbits)); - + unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); app * result; - + scoped_mpz bias(mpzm); mpzm.power(mpz(2), m_ebits - 1, bias); mpzm.dec(bias); - rational all_rat(0); - scoped_mpz all_bits(mpzm); + scoped_mpz sgn_z(mpzm), sig_z(mpzm), exp_z(mpzm); unsigned bv_sz; - bool r = m_bu.is_numeral(values[0], all_rat, bv_sz); - SASSERT(r); - SASSERT(bv_sz == (m_ebits+m_sbits)); - SASSERT(all_rat.is_int()); - mpzm.set(all_bits, all_rat.to_mpq().numerator()); - - scoped_mpz sgn_z(mpzm), sig_z(mpzm), exp_z(mpzm); - mpzm.machine_div2k(all_bits, m_ebits + m_sbits - 1, sgn_z); - mpzm.mod(all_bits, mpfm.m_powers2(m_ebits + m_sbits - 1), all_bits); + if (values.size() == 1) { + SASSERT(m_bu.is_bv(values[0])); + SASSERT(m_bu.get_bv_size(values[0]) == (m_ebits + m_sbits)); - mpzm.machine_div2k(all_bits, m_sbits - 1, exp_z); - mpzm.mod(all_bits, mpfm.m_powers2(m_sbits - 1), all_bits); - - mpzm.set(sig_z, all_bits); + rational all_r(0); + scoped_mpz all_z(mpzm); - TRACE("t_fpa_detail", tout << "sgn=" << mpzm.to_string(sgn_z) << " ; " << - "sig=" << mpzm.to_string(sig_z) << " ; " << - "exp=" << mpzm.to_string(exp_z) << std::endl;); + 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); + 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 [" << - mk_ismt2_pp(values[0], m) << "] --> " << - mk_ismt2_pp(result, m_th.get_manager()) << "\n";); + 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; } @@ -160,8 +184,8 @@ namespace smt { SASSERT(values.size() == 1); ast_manager & m = m_th.get_manager(); - TRACE("t_fpa", tout << "fpa_rm_value_proc::mk_value for: [" << - mk_ismt2_pp(values[0], m) << "]" << std::endl;); + 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]); @@ -199,42 +223,44 @@ namespace smt { if (!m_wraps.find(e_srt, w)) { SASSERT(!m_wraps.contains(e_srt)); - sort * bv_srt = 0; - + 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); + 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); + 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); + m.inc_ref(w); } - return app_ref(m.mk_app(w, e), m); + 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 * e_srt = m.get_sort(e); + sort * bv_srt = m.get_sort(e); func_decl *u; - if (!m_unwraps.find(e_srt, u)) { - SASSERT(!m_unwraps.contains(e_srt)); - sort * bv_srt = m.get_sort(e); + 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(s, u); + m_unwraps.insert(bv_srt, u); m.inc_ref(u); } - return app_ref(m.mk_app(u, e), m); + app_ref res(m); + res = m.mk_app(u, e); + return res; } expr_ref theory_fpa::convert_atom(expr * e) { @@ -244,55 +270,30 @@ namespace smt { m_rw(e, res); m_th_rw(res, res); SASSERT(is_app(res)); - SASSERT(m.is_bool(res)); + SASSERT(m.is_bool(res)); return res; } expr_ref theory_fpa::convert_term(expr * e) { - ast_manager & m = get_manager(); - TRACE("t_fpa_detail", tout << "converting: " << mk_ismt2_pp(e, m) << " sort is: " << mk_ismt2_pp(m.get_sort(e), m) << std::endl;); + ast_manager & m = get_manager(); context & ctx = get_context(); - expr_ref ec(m), res(m); + expr_ref e_conv(m), res(m); proof_ref pr(m); - m_rw(e, ec); + m_rw(e, e_conv); - SASSERT(is_app(ec)); - app_ref eca(to_app(ec), m); - TRACE("t_fpa_detail", tout << "eca = " << mk_ismt2_pp(eca, m) << " sort is: " << mk_ismt2_pp(m.get_sort(eca), m) << std::endl;); - - if (m_fpa_util.is_rm(e)) { - expr_ref bv_rm(m); - bv_rm = eca; - TRACE("t_fpa_detail", tout << "bvrm = " << mk_ismt2_pp(bv_rm, m) << " sort is: " << mk_ismt2_pp(m.get_sort(bv_rm), m) << std::endl;); - SASSERT(is_sort_of(m.get_sort(bv_rm), m_bv_util.get_family_id(), BV_SORT)); - SASSERT(m_bv_util.get_bv_size(bv_rm) == 3); - m_th_rw(bv_rm, res); + 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)) { - SASSERT(eca->get_family_id() == get_family_id()); - fpa_op_kind k = (fpa_op_kind)(eca->get_decl_kind()); - SASSERT(k == OP_FPA_TO_FP || k == OP_FPA_INTERNAL_BVUNWRAP); - switch (k) { - case OP_FPA_TO_FP: { - SASSERT(eca->get_num_args() == 3); - SASSERT(is_sort_of(m.get_sort(eca->get_arg(0)), m_bv_util.get_family_id(), BV_SORT)); - SASSERT(is_sort_of(m.get_sort(eca->get_arg(1)), m_bv_util.get_family_id(), BV_SORT)); - SASSERT(is_sort_of(m.get_sort(eca->get_arg(2)), m_bv_util.get_family_id(), BV_SORT)); - - expr *sgn, *sig, *exp; - expr_ref s_sgn(m), s_sig(m), s_exp(m); - m_converter.split_triple(eca, sgn, sig, exp); - m_th_rw(sgn, s_sgn); - m_th_rw(sig, s_sig); - m_th_rw(exp, s_exp); - - m_converter.mk_triple(s_sgn, s_sig, s_exp, res); - break; - } - default: - res = eca; - } + 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(); @@ -310,7 +311,7 @@ namespace smt { SASSERT(m_arith_util.is_real(e) || m_bv_util.is_bv(e)); - m_rw(e, res); + m_rw(e, res); m_th_rw(res, res); return res; } @@ -327,12 +328,13 @@ namespace smt { SASSERT(m_fpa_util.is_float(srt)); unsigned ebits = m_fpa_util.get_ebits(srt); unsigned sbits = m_fpa_util.get_sbits(srt); - expr * bv = to_app(e)->get_arg(0); - unsigned bv_sz = m_bv_util.get_bv_size(bv); - m_converter.mk_triple(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), - m_bv_util.mk_extract(sbits - 2, 0, bv), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), - res); + 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; } @@ -342,7 +344,7 @@ namespace smt { 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; @@ -401,11 +403,12 @@ namespace smt { 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(); + 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); + 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) { @@ -433,11 +436,10 @@ namespace smt { ctx.set_var_theory(l.var(), get_id()); expr_ref bv_atom(m); - bv_atom = convert(atom); + 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()); - expr_ref atom_iff(m); assert_cnstr(m.mk_iff(atom, bv_atom)); return true; } @@ -447,7 +449,7 @@ namespace smt { 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)); + SASSERT(!ctx.e_internalized(term)); unsigned num_args = term->get_num_args(); for (unsigned i = 0; i < num_args; i++) @@ -455,7 +457,7 @@ namespace smt { 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; @@ -476,9 +478,9 @@ namespace smt { assert_cnstr(mk_side_conditions()); break; } - default: /* ignore */; + default: /* ignore */; } - + return true; } @@ -486,33 +488,33 @@ namespace smt { 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()); + SASSERT(s->get_family_id() == get_family_id()); - if (!is_attached_to_var(n)) + if (!is_attached_to_var(n)) { attach_new_th_var(n); - ast_manager & m = get_manager(); - context & ctx = get_context(); + 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); + 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 (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)); } - - if (!ctx.relevancy() && !m_fpa_util.is_unwrap(owner)) - assert_cnstr(m.mk_eq(unwrap(wrap(owner), owner_sort), owner)); } void theory_fpa::new_eq_eh(theory_var x, theory_var y) { @@ -527,36 +529,40 @@ namespace smt { bv_util & bu = m_bv_util; mpf_manager & mpfm = fu.fm(); - app * xe = get_enode(x)->get_owner(); - app * ye = get_enode(y)->get_owner(); + 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(xe->get_decl()->get_family_id() == get_family_id()); + 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_triple(xc, 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_triple(yc, y_sgn, y_sig, y_exp); + m_converter.split_fp(yc, y_sgn, y_exp, y_sig); - c = m.mk_and(m.mk_eq(x_sgn, y_sgn), - m.mk_eq(x_sig, y_sig), - m.mk_eq(x_exp, y_exp)); + 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); - - assert_cnstr(m.mk_iff(m.mk_eq(xe, ye), c)); + + m_th_rw(c); + assert_cnstr(m.mk_iff(m.mk_eq(xe, ye), c)); assert_cnstr(mk_side_conditions()); return; @@ -572,12 +578,13 @@ namespace smt { context & ctx = get_context(); mpf_manager & mpfm = m_fpa_util.fm(); - app * xe = get_enode(x)->get_owner(); - app * ye = get_enode(y)->get_owner(); + 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(xe->get_decl()->get_family_id() == get_family_id()); + SASSERT(to_app(xe)->get_decl()->get_family_id() == get_family_id()); return; } @@ -590,18 +597,18 @@ namespace smt { if (m_fpa_util.is_float(xe) && m_fpa_util.is_float(ye)) { expr *x_sgn, *x_sig, *x_exp; - m_converter.split_triple(xc, 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_triple(yc, y_sgn, y_sig, y_exp); - - c = m.mk_or(m.mk_not(m.mk_eq(x_sgn, y_sgn)), - m.mk_not(m.mk_eq(x_sig, y_sig)), - m.mk_not(m.mk_eq(x_exp, 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)); - assert_cnstr(m.mk_iff(m.mk_not(m.mk_eq(xe, ye)), c)); + m_th_rw(c); + assert_cnstr(m.mk_iff(m.mk_not(m.mk_eq(xe, ye)), c)); assert_cnstr(mk_side_conditions()); return; @@ -609,7 +616,7 @@ namespace smt { void theory_fpa::push_scope_eh() { theory::push_scope_eh(); - m_trail_stack.push_scope(); + m_trail_stack.push_scope(); } void theory_fpa::pop_scope_eh(unsigned num_scopes) { @@ -628,8 +635,10 @@ namespace smt { expr_ref converted(m); converted = m.mk_and(convert(e), mk_side_conditions()); - if (!is_true) converted = m.mk_not(converted); - assert_cnstr(converted); + 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) { @@ -664,18 +673,17 @@ namespace smt { assert_cnstr(c); } else { - c = m.mk_eq(unwrap(wrapped, m.get_sort(n)), n); + c = m.mk_eq(unwrap(wrapped, m.get_sort(n)), n); assert_cnstr(c); } } } else if (n->get_family_id() == get_family_id()) { - SASSERT(!m_fpa_util.is_float(n) && !m_fpa_util.is_rm(n)); // 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() { @@ -695,6 +703,7 @@ namespace smt { 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; } @@ -705,45 +714,75 @@ namespace smt { } 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()) << "\n";); + 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 * owner = n->get_owner(); + 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)) + m_fpa_util.is_numeral(owner)) { return alloc(expr_wrapper_proc, owner); + } model_value_proc * res = 0; app_ref wrapped(m); wrapped = wrap(owner); - - CTRACE("t_fpa", !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 (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)) { + 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(wrapped)); + 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 - UNREACHABLE(); + 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; } @@ -754,7 +793,7 @@ namespace smt { ast_manager & m = get_manager(); context & ctx = get_context(); - out << "theory variables:" << std::endl; + 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++) { @@ -762,5 +801,32 @@ namespace smt { 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/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index dfddfd12f..5c12cbd8f 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -116,7 +116,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { 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_FPA_TO_FP)); + 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); diff --git a/src/tactic/fpa/qffp_tactic.cpp b/src/tactic/fpa/qffp_tactic.cpp index 5bc006f00..6b081f0a5 100644 --- a/src/tactic/fpa/qffp_tactic.cpp +++ b/src/tactic/fpa/qffp_tactic.cpp @@ -22,6 +22,7 @@ Notes: #include"sat_tactic.h" #include"fpa2bv_tactic.h" #include"smt_tactic.h" +#include"propagate_values_tactic.h" #include"qffp_tactic.h" @@ -30,19 +31,19 @@ tactic * mk_qffp_tactic(ast_manager & m, params_ref const & p) { simp_p.set_bool("arith_lhs", true); simp_p.set_bool("elim_and", true); - tactic * st = cond( mk_or(mk_produce_proofs_probe(), mk_produce_unsat_cores_probe()), - and_then(mk_simplify_tactic(m, simp_p), - mk_smt_tactic()), - and_then( - mk_simplify_tactic(m, p), - 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())); + 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; From c3247d75988d0a3f0c7f4808acb881c1d60621ed Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Sat, 17 Jan 2015 16:36:33 +0000 Subject: [PATCH 114/118] FPA: bugfix for rounding mode bv translation Signed-off-by: Christoph M. Wintersteiger --- src/ast/fpa/fpa2bv_converter.cpp | 6 +++--- src/ast/fpa/fpa2bv_converter.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 4cdb64d8d..1f7ea1186 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -3170,11 +3170,11 @@ 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_FPA_RM_NEAREST_TIES_TO_AWAY: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 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_TOWARD_NEGATIVE: result = m_bv_util.mk_numeral(BV_RM_TO_NEGATIVE, 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(); } diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 82fad6ff9..fa797b610 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -26,7 +26,7 @@ Notes: #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; } From 5619f6b583147b5bdb0218001a05c0f3a47ecf1a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 19 Jan 2015 15:18:12 +0000 Subject: [PATCH 115/118] FPA Python API bugfixes Signed-off-by: Christoph M. Wintersteiger --- src/api/python/z3.py | 19 ++++++-------- src/api/python/z3printer.py | 52 ++++++++++++++++++++----------------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index ee33fbe51..82002c4f7 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -904,12 +904,8 @@ def _to_expr_ref(a, ctx): if sk == Z3_DATATYPE_SORT: return DatatypeRef(a, ctx) if sk == Z3_FLOATING_POINT_SORT: - if k == Z3_APP_AST: - e = ExprRef(a, ctx) - if e.decl().kind() == Z3_OP_FPA_NUM: - return FPNumRef(a, ctx) - else: - return FPRef(a, ctx) + 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: @@ -7817,7 +7813,8 @@ class FPNumRef(FPRef): return self.decl().kind() == Z3_OP_FPA_PLUS_ZERO or self.decl().kind() == Z3_OP_FPA_MINUS_ZERO def isNegative(self): - return (self.num_args() == 0 and (Z3_OP_FPA_MINUS_INF or Z3_OP_FPA_MINUS_ZERO)) or (self.num_args() == 3 and self.arg(0) == BitVecVal(1)) + 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): @@ -7851,7 +7848,7 @@ def is_fp_value(a): 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. @@ -7989,7 +7986,7 @@ def fpAbs(a): FloatingPoint(8, 24) """ if __debug__: - _z3_assert(is_fp(a), "First argument must be Z3 floating-point expressions") + _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): @@ -8004,7 +8001,7 @@ def fpNeg(a): FloatingPoint(8, 24) """ if __debug__: - _z3_assert(is_fp(a), "First argument must be Z3 floating-point expressions") + _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): @@ -8069,7 +8066,7 @@ def fpDiv(rm, a, b): 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) + 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. diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py index a74a67fa8..da49f1719 100644 --- a/src/api/python/z3printer.py +++ b/src/api/python/z3printer.py @@ -71,7 +71,7 @@ _z3_op_to_fpa_normal_str = { 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_NEG : 'fpNeg', Z3_OP_FPA_MIN : 'fpMin', Z3_OP_FPA_MAX : 'fpMax', + 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', @@ -93,9 +93,8 @@ _z3_op_to_fpa_pretty_str = { 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_NEG : '-', Z3_OP_FPA_MUL : '*', - Z3_OP_FPA_DIV : '/', Z3_OP_FPA_REM : '%', - Z3_OP_FPA_NEG: '-', + 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 : '>=' } @@ -578,7 +577,7 @@ class Formatter: def pp_fprm_value(self, a): z3._z3_assert(z3.is_fprm_value(a), 'expected FPRMNumRef') - if self.fpa_pretty and _z3_op_to_fpa_pretty_str.has_key(a.decl().kind()): + 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(a.as_string()) @@ -617,7 +616,7 @@ class Formatter: return compose(r) else: if (a.isNaN()): - return to_format(_z3_op_to_fpa_pretty_str[Z3_OP_NAN]) + 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]) @@ -649,28 +648,33 @@ class Formatter: z3._z3_assert(isinstance(a, z3.FPRef), "type mismatch") k = a.decl().kind() op = '?' - if self.fpa_pretty: - op = _z3_op_to_fpa_pretty_str.get(k, None) - if (op == None): - op = _z3_op_to_str.get(k, None) + 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 and 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) + 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 _z3_op_to_fpa_normal_str.has_key(k): - op = _z3_op_to_fpa_normal_str.get(k, None) + if k in _z3_op_to_fpa_normal_str: + op = _z3_op_to_fpa_normal_str[k] r = [] r.append(to_format(op)) From d8f90802c0933be09377e30fec724e24252c2253 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 19 Jan 2015 18:14:22 +0000 Subject: [PATCH 116/118] Added FPA setup to default kernel setup Signed-off-by: Christoph M. Wintersteiger --- src/smt/smt_setup.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 68e960fb8..d17e4b803 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -813,6 +813,7 @@ namespace smt { setup_AUFLIA(false); setup_datatypes(); setup_bv(); + setup_fpa(); return; } From 052baaabe40d321aea5ec644cefa58ee36788305 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 21 Jan 2015 14:22:35 +0000 Subject: [PATCH 117/118] FPA API bugfixes Signed-off-by: Christoph M. Wintersteiger --- scripts/update_api.py | 2 +- src/ast/fpa/fpa2bv_converter.cpp | 34 +++++++++++++++++++++----------- src/util/mpf.cpp | 2 +- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index a47835904..499cc1a32 100644 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -267,7 +267,7 @@ def param2dotnet(p): elif k == OUT_ARRAY: return "[Out] %s[]" % type2dotnet(param_type(p)) elif k == OUT_MANAGED_ARRAY: - return "[Out] out %s[]" % type2dotnet(param_type(p)) + return "[Out] out %s[]" % type2dotnet(param_type(p)) else: return type2dotnet(param_type(p)) diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 1f7ea1186..110311c4c 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2982,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(); } } @@ -3182,7 +3181,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) 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)); @@ -3485,9 +3484,14 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & 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); @@ -3497,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); + 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); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 511bdb03c..acf6eae39 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1221,7 +1221,7 @@ std::string mpf_manager::to_string(mpf const & x) { m_mpq_manager.display_decimal(ss, r, x.sbits); if (m_mpq_manager.is_int(r)) ss << ".0"; - ss << "p" << exponent; + ss << " " << exponent; res += ss.str(); } } From 079204d1aace9c3a2c239b5ef82370d954871d82 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 21 Jan 2015 14:22:47 +0000 Subject: [PATCH 118/118] FPA Python API cosmetics Signed-off-by: Christoph M. Wintersteiger --- src/api/python/z3.py | 16 ++++++++-------- src/api/python/z3printer.py | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 82002c4f7..fd3d1bdc8 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -7749,7 +7749,7 @@ class FPRMRef(ExprRef): return Z3_ast_to_string(self.ctx_ref(), self.as_ast()) -def RoundNearestTiesToEven (ctx=None): +def RoundNearestTiesToEven(ctx=None): ctx = _get_ctx(ctx) return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_even(ctx.ref()), ctx) @@ -7757,7 +7757,7 @@ 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): +def RoundNearestTiesToAway(ctx=None): ctx = _get_ctx(ctx) return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_away(ctx.ref()), ctx) @@ -7765,27 +7765,27 @@ 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): +def RoundTowardPositive(ctx=None): ctx = _get_ctx(ctx) return FPRMRef(Z3_mk_fpa_round_toward_positive(ctx.ref()), ctx) -def RTP (ctx=None): +def RTP(ctx=None): ctx = _get_ctx(ctx) return FPRMRef(Z3_mk_fpa_round_toward_positive(ctx.ref()), ctx) -def RoundTowardNegative (ctx=None): +def RoundTowardNegative(ctx=None): ctx = _get_ctx(ctx) return FPRMRef(Z3_mk_fpa_round_toward_negative(ctx.ref()), ctx) -def RTN (ctx=None): +def RTN(ctx=None): ctx = _get_ctx(ctx) return FPRMRef(Z3_mk_fpa_round_toward_negative(ctx.ref()), ctx) -def RoundTowardZero (ctx=None): +def RoundTowardZero(ctx=None): ctx = _get_ctx(ctx) return FPRMRef(Z3_mk_fpa_round_toward_zero(ctx.ref()), ctx) -def RTZ (ctx=None): +def RTZ(ctx=None): ctx = _get_ctx(ctx) return FPRMRef(Z3_mk_fpa_round_toward_zero(ctx.ref()), ctx) diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py index da49f1719..ac1607dda 100644 --- a/src/api/python/z3printer.py +++ b/src/api/python/z3printer.py @@ -64,9 +64,9 @@ _z3_precedence = { # FPA operators _z3_op_to_fpa_normal_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_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', @@ -580,7 +580,7 @@ class Formatter: 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(a.as_string()) + 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')