diff --git a/scripts/mk_unix_dist.py b/scripts/mk_unix_dist.py index 999d495a329..0c28058ed18 100644 --- a/scripts/mk_unix_dist.py +++ b/scripts/mk_unix_dist.py @@ -58,7 +58,7 @@ def display_help(): # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', diff --git a/scripts/mk_win_dist.py b/scripts/mk_win_dist.py index 454bba7cae1..cee8c0460ec 100644 --- a/scripts/mk_win_dist.py +++ b/scripts/mk_win_dist.py @@ -63,7 +63,7 @@ def display_help(): # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, GIT_HASH + global FORCE_MK, JAVA_ENABLED, GIT_HASH, DOTNET_ENABLED path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', diff --git a/scripts/update_api.py b/scripts/update_api.py index a06f1fbb188..733d5b1fa29 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1324,36 +1324,80 @@ def mk_z3native_stubs_c(ml_dir): # C interface if len(ap) > 0: ml_wrapper.write(' unsigned _i;\n') - # declare locals, preprocess arrays, strings, in/out arguments - have_context = False + # determine if the function has a context as parameter. + have_context = (len(params) > 0) and (param_type(params[0]) == CONTEXT) + + if have_context and name not in Unwrapped: + ml_wrapper.write(' Z3_error_code ec;\n') + + if result != VOID: + ts = type2str(result) + if ml_has_plus_type(ts): + pts = ml_plus_type(ts) + ml_wrapper.write(' %s z3rv_m;\n' % ts) + ml_wrapper.write(' %s z3rv;\n' % pts) + else: + ml_wrapper.write(' %s z3rv;\n' % ts) + + # declare all required local variables + # To comply with C89, we need to first declare the variables and initialize them + # only afterwards. i = 0 for param in params: if param_type(param) == CONTEXT and i == 0: - ml_wrapper.write(' Z3_context_plus ctx_p = *(Z3_context_plus*) Data_custom_val(a' + str(i) + ');\n') - ml_wrapper.write(' Z3_context _a0 = ctx_p->ctx;\n') - have_context = True + ml_wrapper.write(' Z3_context_plus ctx_p;\n') + ml_wrapper.write(' Z3_context _a0;\n') else: k = param_kind(param) if k == OUT_ARRAY: - ml_wrapper.write(' %s * _a%s = (%s*) malloc(sizeof(%s) * (_a%s));\n' % ( - type2str(param_type(param)), + ml_wrapper.write(' %s * _a%s;\n' % (type2str(param_type(param)), i)) + elif k == OUT_MANAGED_ARRAY: + ml_wrapper.write(' %s * _a%s;\n' % (type2str(param_type(param)), i)) + elif k == IN_ARRAY or k == INOUT_ARRAY: + t = param_type(param) + ts = type2str(t) + ml_wrapper.write(' %s * _a%s;\n' % (ts, i)) + elif k == IN: + t = param_type(param) + ml_wrapper.write(' %s _a%s;\n' % (type2str(t), i)) + elif k == OUT or k == INOUT: + t = param_type(param) + ml_wrapper.write(' %s _a%s;\n' % (type2str(t), i)) + ts = type2str(t) + if ml_has_plus_type(ts): + pts = ml_plus_type(ts) + ml_wrapper.write(' %s _a%dp;\n' % (pts, i)) + i = i + 1 + + + # End of variable declarations in outermost block: + # To comply with C89, no variable declarations may occur in the outermost block + # from that point onwards (breaks builds with at least VC 2012 and prior) + ml_wrapper.write('\n') + + # Declare locals, preprocess arrays, strings, in/out arguments + i = 0 + for param in params: + if param_type(param) == CONTEXT and i == 0: + ml_wrapper.write(' ctx_p = *(Z3_context_plus*) Data_custom_val(a' + str(i) + ');\n') + ml_wrapper.write(' _a0 = ctx_p->ctx;\n') + else: + k = param_kind(param) + if k == OUT_ARRAY: + ml_wrapper.write(' _a%s = (%s*) malloc(sizeof(%s) * (_a%s));\n' % ( i, type2str(param_type(param)), type2str(param_type(param)), param_array_capacity_pos(param))) elif k == OUT_MANAGED_ARRAY: - ml_wrapper.write(' %s * _a%s = 0;\n' % (type2str(param_type(param)), i)) + ml_wrapper.write(' _a%s = 0;\n' % i) elif k == IN_ARRAY or k == INOUT_ARRAY: t = param_type(param) ts = type2str(t) - ml_wrapper.write(' %s * _a%s = (%s*) malloc(sizeof(%s) * _a%s);\n' % (ts, i, ts, ts, param_array_capacity_pos(param))) + ml_wrapper.write(' _a%s = (%s*) malloc(sizeof(%s) * _a%s);\n' % (i, ts, ts, param_array_capacity_pos(param))) elif k == IN: t = param_type(param) - ml_wrapper.write(' %s _a%s = %s;\n' % (type2str(t), i, ml_unwrap(t, type2str(t), 'a' + str(i)))) - elif k == OUT: - ml_wrapper.write(' %s _a%s;\n' % (type2str(param_type(param)), i)) - elif k == INOUT: - ml_wrapper.write(' %s _a%s = a%s;\n' % (type2str(param_type(param)), i, i)) + ml_wrapper.write(' _a%s = %s;\n' % (i, ml_unwrap(t, type2str(t), 'a' + str(i)))) i = i + 1 i = 0 @@ -1375,9 +1419,9 @@ def mk_z3native_stubs_c(ml_dir): # C interface if result != VOID: ts = type2str(result) if ml_has_plus_type(ts): - ml_wrapper.write('%s z3rv_m = ' % ts) + ml_wrapper.write('z3rv_m = ') else: - ml_wrapper.write('%s z3rv = ' % ts) + ml_wrapper.write('z3rv = ') # invoke procedure ml_wrapper.write('%s(' % name) @@ -1397,8 +1441,8 @@ def mk_z3native_stubs_c(ml_dir): # C interface ml_wrapper.write(');\n') if have_context and name not in Unwrapped: - ml_wrapper.write(' int ec = Z3_get_error_code(ctx_p->ctx);\n') - ml_wrapper.write(' if (ec != 0) {\n') + ml_wrapper.write(' ec = Z3_get_error_code(ctx_p->ctx);\n') + ml_wrapper.write(' if (ec != Z3_OK) {\n') ml_wrapper.write(' const char * msg = Z3_get_error_msg(ctx_p->ctx, ec);\n') ml_wrapper.write(' caml_raise_with_string(*caml_named_value("Z3EXCEPTION"), msg);\n') ml_wrapper.write(' }\n') @@ -1408,9 +1452,9 @@ def mk_z3native_stubs_c(ml_dir): # C interface if ml_has_plus_type(ts): pts = ml_plus_type(ts) if name in NULLWrapped: - ml_wrapper.write(' %s z3rv = %s_mk(z3rv_m);\n' % (pts, pts)) + ml_wrapper.write(' z3rv = %s_mk(z3rv_m);\n' % pts) else: - ml_wrapper.write(' %s z3rv = %s_mk(ctx_p, (%s) z3rv_m);\n' % (pts, pts, ml_minus_type(ts))) + ml_wrapper.write(' z3rv = %s_mk(ctx_p, (%s) z3rv_m);\n' % (pts, ml_minus_type(ts))) # convert output params if len(op) > 0: @@ -1450,7 +1494,7 @@ def mk_z3native_stubs_c(ml_dir): # C interface elif is_out_param(p): if ml_has_plus_type(ts): pts = ml_plus_type(ts) - ml_wrapper.write(' %s _a%dp = %s_mk(ctx_p, (%s) _a%d);\n' % (pts, i, pts, ml_minus_type(ts), i)) + ml_wrapper.write(' _a%dp = %s_mk(ctx_p, (%s) _a%d);\n' % (i, pts, ml_minus_type(ts), i)) ml_wrapper.write(' %s\n' % ml_alloc_and_store(pt, '_a%d_val' % i, '_a%dp' % i)) else: ml_wrapper.write(' %s\n' % ml_alloc_and_store(pt, '_a%d_val' % i, '_a%d' % i)) diff --git a/src/ackermannization/ackermannize_bv_tactic.cpp b/src/ackermannization/ackermannize_bv_tactic.cpp index f9c48c2bdca..70230e346b8 100644 --- a/src/ackermannization/ackermannize_bv_tactic.cpp +++ b/src/ackermannization/ackermannize_bv_tactic.cpp @@ -74,6 +74,10 @@ class ackermannize_bv_tactic : public tactic { m_lemma_limit = p.div0_ackermann_limit(); } + virtual void collect_param_descrs(param_descrs & r) { + ackermannize_bv_tactic_params::collect_param_descrs(r); + } + virtual void collect_statistics(statistics & st) const { st.update("ackr-constraints", m_st.m_ackrs_sz); } diff --git a/src/ackermannization/lackr.cpp b/src/ackermannization/lackr.cpp index b1a58c01bf9..461d2080fda 100644 --- a/src/ackermannization/lackr.cpp +++ b/src/ackermannization/lackr.cpp @@ -134,7 +134,6 @@ void lackr::eager_enc() { const fun2terms_map::iterator e = m_fun2terms.end(); for (fun2terms_map::iterator i = m_fun2terms.begin(); i != e; ++i) { checkpoint(); - func_decl* const fd = i->m_key; app_set * const ts = i->get_value(); const app_set::iterator r = ts->end(); for (app_set::iterator j = ts->begin(); j != r; ++j) { @@ -143,8 +142,8 @@ void lackr::eager_enc() { for (; k != r; ++k) { app * const t1 = *j; app * const t2 = *k; - SASSERT(t1->get_decl() == fd); - SASSERT(t2->get_decl() == fd); + SASSERT(t1->get_decl() == i->m_key); + SASSERT(t2->get_decl() == i->m_key); if (t1 == t2) continue; ackr(t1,t2); } diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 34dab3ed697..1f16b2d35ed 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1066,15 +1066,14 @@ extern "C" { case OP_BV2INT: return Z3_OP_BV2INT; case OP_CARRY: return Z3_OP_CARRY; case OP_XOR3: return Z3_OP_XOR3; - case OP_BSMUL_NO_OVFL: - case OP_BUMUL_NO_OVFL: - case OP_BSMUL_NO_UDFL: - case OP_BSDIV_I: - case OP_BUDIV_I: - case OP_BSREM_I: - case OP_BUREM_I: - case OP_BSMOD_I: - return Z3_OP_UNINTERPRETED; + case OP_BSMUL_NO_OVFL: return Z3_OP_BSMUL_NO_OVFL; + case OP_BUMUL_NO_OVFL: return Z3_OP_BUMUL_NO_OVFL; + case OP_BSMUL_NO_UDFL: return Z3_OP_BSMUL_NO_UDFL; + case OP_BSDIV_I: return Z3_OP_BSDIV_I; + case OP_BUDIV_I: return Z3_OP_BUDIV_I; + case OP_BSREM_I: return Z3_OP_BSREM_I; + case OP_BUREM_I: return Z3_OP_BUREM_I; + case OP_BSMOD_I: return Z3_OP_BSMOD_I; default: UNREACHABLE(); return Z3_OP_UNINTERPRETED; @@ -1184,10 +1183,10 @@ extern "C" { 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_MIN_I: return Z3_OP_FPA_MIN_I; + case OP_FPA_INTERNAL_MAX_I: return Z3_OP_FPA_MAX_I; + case OP_FPA_INTERNAL_BV2RM: case OP_FPA_INTERNAL_BVWRAP: - case OP_FPA_INTERNAL_BVUNWRAP: - case OP_FPA_INTERNAL_MIN_I: - case OP_FPA_INTERNAL_MAX_I: case OP_FPA_INTERNAL_MIN_UNSPECIFIED: case OP_FPA_INTERNAL_MAX_UNSPECIFIED: case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 63092b2cf56..10ede0922e2 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -50,14 +50,13 @@ extern "C" { Z3_CATCH; } - Z3_ast Z3_API Z3_model_get_const_interp(Z3_context c, Z3_model m, Z3_func_decl a) { + Z3_ast_opt Z3_API Z3_model_get_const_interp(Z3_context c, Z3_model m, Z3_func_decl a) { Z3_TRY; LOG_Z3_model_get_const_interp(c, m, a); RESET_ERROR_CODE(); CHECK_NON_NULL(m, 0); expr * r = to_model_ref(m)->get_const_interp(to_func_decl(a)); if (!r) { - SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } mk_c(c)->save_ast_trail(r); diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index 73215580e4b..ddcd90cca1f 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -72,7 +72,7 @@ extern "C" { expr * const* no_ps = reinterpret_cast(no_patterns); pattern_validator v(mk_c(c)->m()); for (unsigned i = 0; i < num_patterns; i++) { - if (!v(num_decls, ps[i])) { + if (!v(num_decls, ps[i], 0, 0)) { SET_ERROR_CODE(Z3_INVALID_PATTERN); return 0; } diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 6e85447708a..9fb6648198a 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1582,6 +1582,9 @@ namespace z3 { return static_cast(i) < num_consts() ? get_const_decl(i) : get_func_decl(i - num_consts()); } + // returns interpretation of constant declaration c. + // If c is not assigned any value in the model it returns + // an expression with a null ast reference. expr get_const_interp(func_decl c) const { check_context(*this, c); Z3_ast r = Z3_model_get_const_interp(ctx(), m_model, c); diff --git a/src/api/ml/z3native_stubs.c.pre b/src/api/ml/z3native_stubs.c.pre index d6b2cdab422..5960d5095c0 100644 --- a/src/api/ml/z3native_stubs.c.pre +++ b/src/api/ml/z3native_stubs.c.pre @@ -227,6 +227,7 @@ void Z3_ast_finalize(value v) { int Z3_ast_compare(value v1, value v2) { Z3_ast_plus * a1 = (Z3_ast_plus*)Data_custom_val(v1); Z3_ast_plus * a2 = (Z3_ast_plus*)Data_custom_val(v2); + unsigned id1, id2; /* if the two ASTs belong to different contexts, we take their contexts' addresses to order them (arbitrarily, but fixed) */ @@ -242,8 +243,8 @@ int Z3_ast_compare(value v1, value v2) { return +1; /* Comparison according to AST ids. */ - unsigned id1 = Z3_get_ast_id(a1->cp->ctx, a1->p); - unsigned id2 = Z3_get_ast_id(a2->cp->ctx, a2->p); + id1 = Z3_get_ast_id(a1->cp->ctx, a1->p); + id2 = Z3_get_ast_id(a2->cp->ctx, a2->p); if (id1 == id2) return 0; else if (id1 < id2) @@ -255,7 +256,7 @@ int Z3_ast_compare(value v1, value v2) { int Z3_ast_compare_ext(value v1, value v2) { Z3_ast_plus * a1 = (Z3_ast_plus*)Data_custom_val(v1); unsigned id1; - int id2 = Val_int(v2); + unsigned id2 = (unsigned)Val_int(v2); if (a1->p == NULL && id2 == 0) return 0; if (a1->p == NULL) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 848883ba391..942201b0e86 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -3468,7 +3468,7 @@ def is_bv_value(a): """ return is_bv(a) and _is_numeral(a.ctx, a.as_ast()) -def BV2Int(a): +def BV2Int(a, is_signed=False): """Return the Z3 expression BV2Int(a). >>> b = BitVec('b', 3) @@ -3477,6 +3477,10 @@ def BV2Int(a): >>> x = Int('x') >>> x > BV2Int(b) x > BV2Int(b) + >>> x > BV2Int(b, is_signed=False) + x > BV2Int(b) + >>> x > BV2Int(b, is_signed=True) + x > If(b < 0, BV2Int(b) - 8, BV2Int(b)) >>> solve(x > BV2Int(b), b == 1, x < 3) [b = 1, x = 2] """ @@ -3484,7 +3488,7 @@ def BV2Int(a): _z3_assert(is_bv(a), "Z3 bit-vector expression expected") ctx = a.ctx ## investigate problem with bv2int - return ArithRef(Z3_mk_bv2int(ctx.ref(), a.as_ast(), 0), ctx) + return ArithRef(Z3_mk_bv2int(ctx.ref(), a.as_ast(), is_signed), ctx) def BitVecSort(sz, ctx=None): """Return a Z3 bit-vector sort of the given size. If `ctx=None`, then the global context is used. @@ -5516,7 +5520,10 @@ def get_interp(self, decl): decl = decl.decl() try: if decl.arity() == 0: - r = _to_expr_ref(Z3_model_get_const_interp(self.ctx.ref(), self.model, decl.ast), self.ctx) + _r = Z3_model_get_const_interp(self.ctx.ref(), self.model, decl.ast) + if _r.value is None: + return None + r = _to_expr_ref(_r, self.ctx) if is_as_array(r): return self.get_interp(get_as_array_func(r)) else: diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 7c846cc99be..114490015f3 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1060,6 +1060,15 @@ typedef enum { Z3_OP_CARRY, Z3_OP_XOR3, + Z3_OP_BSMUL_NO_OVFL, + Z3_OP_BUMUL_NO_OVFL, + Z3_OP_BSMUL_NO_UDFL, + Z3_OP_BSDIV_I, + Z3_OP_BUDIV_I, + Z3_OP_BSREM_I, + Z3_OP_BUREM_I, + Z3_OP_BSMOD_I, + // Proofs Z3_OP_PR_UNDEF = 0x500, Z3_OP_PR_TRUE, @@ -1205,6 +1214,9 @@ typedef enum { Z3_OP_FPA_TO_IEEE_BV, + Z3_OP_FPA_MIN_I, + Z3_OP_FPA_MAX_I, + Z3_OP_UNINTERPRETED } Z3_decl_kind; diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 0365a267ea2..fcf9365e33f 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1495,6 +1495,7 @@ void ast_manager::copy_families_plugins(ast_manager const & from) { if (m_family_manager.has_family(fid)) tout << get_family_id(fid_name) << "\n";); if (!m_family_manager.has_family(fid)) { family_id new_fid = mk_family_id(fid_name); + (void)new_fid; TRACE("copy_families_plugins", tout << "new target fid created: " << new_fid << " fid_name: " << fid_name << "\n";); } TRACE("copy_families_plugins", tout << "target fid: " << get_family_id(fid_name) << "\n";); diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index d837ebb2243..eb15910bc81 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -462,7 +462,7 @@ func_decl * datatype_decl_plugin::mk_update_field( } range = domain[0]; func_decl_info info(m_family_id, k, num_parameters, parameters); - return m.mk_func_decl(symbol("update_field"), arity, domain, range, info); + return m.mk_func_decl(symbol("update-field"), arity, domain, range, info); } func_decl * datatype_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 51d33c896b6..8ef6fb557bd 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -109,7 +109,7 @@ class datatype_decl_plugin : public decl_plugin { parameters[o] - (int) m - number of constructors parameters[o+1] - (int) k_1 - offset for constructor definition ... - parameters[o+m] - (int) k_m - offset ofr constructor definition + parameters[o+m] - (int) k_m - offset for constructor definition for each offset k_i at parameters[o+s] for some s in 0..m-1 parameters[k_i] - (symbol) name of the constructor diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index aefa6294ae0..bd07b5bdc5b 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -33,6 +33,9 @@ fpa2bv_converter::fpa2bv_converter(ast_manager & m) : m_util(m), m_bv_util(m), m_arith_util(m), + m_array_util(m), + m_dt_util(m), + m_seq_util(m), m_mpf_manager(m_util.fm()), m_mpz_manager(m_mpf_manager.mpz_manager()), m_hi_fp_unspecified(true), @@ -46,11 +49,10 @@ fpa2bv_converter::~fpa2bv_converter() { void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { if (is_float(a) && is_float(b)) { - 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)); + SASSERT(m_util.is_fp(a) && m_util.is_fp(b)); TRACE("fpa2bv", tout << "mk_eq a=" << mk_ismt2_pp(a, m) << std::endl; - tout << "mk_eq b=" << mk_ismt2_pp(b, m) << std::endl;); + tout << "mk_eq b=" << mk_ismt2_pp(b, m) << std::endl;); expr_ref eq_sgn(m), eq_exp(m), eq_sig(m); m_simp.mk_eq(to_app(a)->get_arg(0), to_app(b)->get_arg(0), eq_sgn); @@ -77,11 +79,10 @@ void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { m_simp.mk_or(both_are_nan, both_the_same, result); } else if (is_rm(a) && is_rm(b)) { - SASSERT(is_app_of(a, m_plugin->get_family_id(), OP_FPA_INTERNAL_RM)); - SASSERT(is_app_of(b, m_plugin->get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(b) && m_util.is_bv2rm(a)); TRACE("fpa2bv", tout << "mk_eq_rm a=" << mk_ismt2_pp(a, m) << std::endl; - tout << "mk_eq_rm b=" << mk_ismt2_pp(b, m) << std::endl;); + tout << "mk_eq_rm b=" << mk_ismt2_pp(b, m) << std::endl;); m_simp.mk_eq(to_app(a)->get_arg(0), to_app(b)->get_arg(0), result); } @@ -90,8 +91,7 @@ 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_FP)); - SASSERT(is_app_of(f, m_plugin->get_family_id(), OP_FPA_FP)); + SASSERT(m_util.is_fp(t) && m_util.is_fp(f)); expr *t_sgn, *t_sig, *t_exp; expr *f_sgn, *f_sig, *f_exp; @@ -103,7 +103,7 @@ void fpa2bv_converter::mk_ite(expr * c, expr * t, expr * f, expr_ref & result) { m_simp.mk_ite(c, t_sig, f_sig, s); m_simp.mk_ite(c, t_exp, f_exp, e); - mk_fp(sgn, e, s, result); + result = m_util.mk_fp(sgn, e, s); } void fpa2bv_converter::mk_distinct(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -152,7 +152,7 @@ void fpa2bv_converter::mk_numeral(func_decl * f, unsigned num, expr * const * ar mk_bias(e, biased_exp); - mk_fp(bv_sgn, biased_exp, bv_sig, result); + result = m_util.mk_fp(bv_sgn, biased_exp, bv_sig); TRACE("fpa2bv_dbg", tout << "value of [" << sign << " " << m_mpz_manager.to_string(sig) << " " << exp << "] is " << mk_ismt2_pp(result, m) << std::endl;); @@ -199,7 +199,7 @@ void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) { SASSERT(m_bv_util.get_bv_size(e) == ebits); #endif - mk_fp(sgn, e, s, result); + result = m_util.mk_fp(sgn, e, s); m_const2bv.insert(f, result); m.inc_ref(f); @@ -218,89 +218,81 @@ 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_fp(sgn, e, s, result); + result = m_util.mk_fp(sgn, e, s); } -void fpa2bv_converter::mk_uninterpreted_output(sort * rng, func_decl * fbv, expr_ref_buffer & new_args, expr_ref & result) { +void fpa2bv_converter::mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result) { if (m_util.is_float(rng)) { unsigned ebits = m_util.get_ebits(rng); unsigned sbits = m_util.get_sbits(rng); unsigned bv_sz = ebits + sbits; app_ref na(m); - na = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); - mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, na), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, na), - m_bv_util.mk_extract(sbits - 2, 0, na), - result); + na = m.mk_app(fbv, fbv->get_arity(), new_args); + result = m_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, na), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, na), + m_bv_util.mk_extract(sbits - 2, 0, na)); } else if (m_util.is_rm(rng)) { app_ref na(m); - na = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); - mk_rm(na, result); + na = m.mk_app(fbv, fbv->get_arity(), new_args); + result = m_util.mk_bv2rm(na); } else - result = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); + result = m.mk_app(fbv, fbv->get_arity(), new_args); } -void fpa2bv_converter::mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) +func_decl * fpa2bv_converter::get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity) { + func_decl * res; + if (!m_uf2bvuf.find(f, res)) { + res = m.mk_fresh_func_decl(f->get_name(), symbol("bv"), arity, f->get_domain(), bv_rng); + m_uf2bvuf.insert(f, res); + m.inc_ref(f); + m.inc_ref(res); + TRACE("fpa2bv", tout << "New UF func_decl: " << std::endl << mk_ismt2_pp(res, m) << std::endl;); + } + return res; +} +void fpa2bv_converter::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { TRACE("fpa2bv", tout << "UF: " << mk_ismt2_pp(f, m) << std::endl; ); - SASSERT(f->get_arity() == num); - expr_ref_buffer new_args(m); - - for (unsigned i = 0; i < num; i++) { - if (is_float(args[i])) { - expr * sgn, *exp, *sig; - split_fp(args[i], sgn, exp, sig); - expr * args[3] = { sgn, exp, sig }; - new_args.push_back(m_bv_util.mk_concat(3, args)); - } - else if (is_rm(args[i])) { - SASSERT(is_app_of(args[i], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); - new_args.push_back(to_app(args[i])->get_arg(0)); - } - else - new_args.push_back(args[i]); + expr_ref fapp(m), feq(m); + sort_ref rng(m); + app_ref bv_app(m), flt_app(m); + rng = f->get_range(); + fapp = m.mk_app(f, num, args); + if (m_util.is_float(rng)) { + sort_ref bv_rng(m); + expr_ref new_eq(m); + unsigned ebits = m_util.get_ebits(rng); + unsigned sbits = m_util.get_sbits(rng); + unsigned bv_sz = ebits+sbits; + bv_rng = m_bv_util.mk_sort(bv_sz); + func_decl * bv_f = get_bv_uf(f, bv_rng, num); + bv_app = m.mk_app(bv_f, num, args); + flt_app = m_util.mk_fp(m_bv_util.mk_extract(bv_sz-1, bv_sz-1, bv_app), + m_bv_util.mk_extract(sbits+ebits-2, sbits-1, bv_app), + m_bv_util.mk_extract(sbits-2, 0, bv_app)); + new_eq = m.mk_eq(fapp, flt_app); + m_extra_assertions.push_back(new_eq); + result = flt_app; } - - func_decl * fd; - if (m_uf2bvuf.find(f, fd)) - mk_uninterpreted_output(f->get_range(), fd, new_args, result); - else { - sort_ref_buffer new_domain(m); - - for (unsigned i = 0; i < f->get_arity(); i++) { - sort * di = f->get_domain()[i]; - if (is_float(di)) - new_domain.push_back(m_bv_util.mk_sort(m_util.get_sbits(di) + m_util.get_ebits(di))); - else if (is_rm(di)) - new_domain.push_back(m_bv_util.mk_sort(3)); - else - new_domain.push_back(di); - } - - sort * orig_rng = f->get_range(); - sort_ref rng(orig_rng, m); - if (m_util.is_float(orig_rng)) - rng = m_bv_util.mk_sort(m_util.get_ebits(orig_rng) + m_util.get_sbits(orig_rng)); - else if (m_util.is_rm(orig_rng)) - rng = m_bv_util.mk_sort(3); - - func_decl_ref fbv(m); - fbv = m.mk_fresh_func_decl(new_domain.size(), new_domain.c_ptr(), rng); - TRACE("fpa2bv", tout << "New UF func_decl : " << mk_ismt2_pp(fbv, m) << std::endl;); - - m_uf2bvuf.insert(f, fbv); - m.inc_ref(f); - m.inc_ref(fbv); - - mk_uninterpreted_output(f->get_range(), fbv, new_args, result); + else if (m_util.is_rm(rng)) { + sort_ref bv_rng(m); + expr_ref new_eq(m); + bv_rng = m_bv_util.mk_sort(3); + func_decl * bv_f = get_bv_uf(f, bv_rng, num); + bv_app = m.mk_app(bv_f, num, args); + flt_app = m_util.mk_bv2rm(bv_app); + new_eq = m.mk_eq(fapp, flt_app); + m_extra_assertions.push_back(new_eq); + result = flt_app; } + else + result = fapp; TRACE("fpa2bv", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; ); - SASSERT(is_well_sorted(m, result)); } @@ -323,7 +315,7 @@ void fpa2bv_converter::mk_rm_const(func_decl * f, expr_ref & result) { #endif , m_bv_util.mk_sort(3)); - mk_rm(bv3, result); + result = m_util.mk_bv2rm(bv3); m_rm_const2bv.insert(f, result); m.inc_ref(f); m.inc_ref(result); @@ -344,10 +336,7 @@ void fpa2bv_converter::mk_pinf(sort * s, expr_ref & result) { unsigned ebits = m_util.get_ebits(s); expr_ref top_exp(m); mk_top_exp(ebits, top_exp); - mk_fp(m_bv_util.mk_numeral(0, 1), - top_exp, - m_bv_util.mk_numeral(0, sbits-1), - result); + result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), top_exp, m_bv_util.mk_numeral(0, sbits-1)); } void fpa2bv_converter::mk_ninf(func_decl * f, expr_ref & result) { @@ -360,10 +349,7 @@ void fpa2bv_converter::mk_ninf(sort * s, expr_ref & result) { unsigned ebits = m_util.get_ebits(s); expr_ref top_exp(m); mk_top_exp(ebits, top_exp); - mk_fp(m_bv_util.mk_numeral(1, 1), - top_exp, - m_bv_util.mk_numeral(0, sbits-1), - result); + result = m_util.mk_fp(m_bv_util.mk_numeral(1, 1), top_exp, m_bv_util.mk_numeral(0, sbits-1)); } void fpa2bv_converter::mk_nan(func_decl * f, expr_ref & result) { @@ -376,10 +362,7 @@ void fpa2bv_converter::mk_nan(sort * s, expr_ref & result) { unsigned ebits = m_util.get_ebits(s); expr_ref top_exp(m); mk_top_exp(ebits, top_exp); - mk_fp(m_bv_util.mk_numeral(0, 1), - top_exp, - m_bv_util.mk_numeral(1, sbits - 1), - result); + result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), top_exp, m_bv_util.mk_numeral(1, sbits - 1)); } void fpa2bv_converter::mk_nzero(func_decl * f, expr_ref & result) { @@ -392,10 +375,7 @@ void fpa2bv_converter::mk_nzero(sort * s, expr_ref & result) { unsigned ebits = m_util.get_ebits(s); expr_ref bot_exp(m); mk_bot_exp(ebits, bot_exp); - mk_fp(m_bv_util.mk_numeral(1, 1), - bot_exp, - m_bv_util.mk_numeral(0, sbits - 1), - result); + result = m_util.mk_fp(m_bv_util.mk_numeral(1, 1), bot_exp, m_bv_util.mk_numeral(0, sbits - 1)); } void fpa2bv_converter::mk_pzero(func_decl * f, expr_ref & result) { @@ -408,10 +388,7 @@ void fpa2bv_converter::mk_pzero(sort * s, expr_ref & result) { unsigned ebits = m_util.get_ebits(s); expr_ref bot_exp(m); mk_bot_exp(ebits, bot_exp); - mk_fp(m_bv_util.mk_numeral(0, 1), - bot_exp, - m_bv_util.mk_numeral(0, sbits-1), - result); + result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), bot_exp, m_bv_util.mk_numeral(0, sbits-1)); } void fpa2bv_converter::mk_zero(sort * s, expr_ref & sgn, expr_ref & result) { @@ -430,10 +407,7 @@ void fpa2bv_converter::mk_one(sort * s, expr_ref & sign, expr_ref & result) { SASSERT(is_float(s)); unsigned sbits = m_util.get_sbits(s); unsigned ebits = m_util.get_ebits(s); - mk_fp(sign, - m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1), ebits), - m_bv_util.mk_numeral(0, sbits-1), - result); + result = m_util.mk_fp(sign, m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1), ebits), m_bv_util.mk_numeral(0, sbits-1)); } void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, @@ -548,7 +522,7 @@ void fpa2bv_converter::add_core(unsigned sbits, unsigned ebits, void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(args[0])); expr_ref rm(m), x(m), y(m); rm = to_app(args[0])->get_arg(0); @@ -713,12 +687,12 @@ void fpa2bv_converter::mk_neg(sort * srt, expr_ref & x, expr_ref & result) { nsgn = m_bv_util.mk_bv_not(sgn); expr_ref r_sgn(m); m_simp.mk_ite(c, sgn, nsgn, r_sgn); - mk_fp(r_sgn, e, sig, result); + result = m_util.mk_fp(r_sgn, e, sig); } void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(args[0])); expr_ref rm(m), x(m), y(m); rm = to_app(args[0])->get_arg(0); @@ -868,7 +842,7 @@ void fpa2bv_converter::mk_mul(sort * s, expr_ref & rm, expr_ref & x, expr_ref & void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 3); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(args[0])); expr_ref rm(m), x(m), y(m); rm = to_app(args[0])->get_arg(0); x = args[1]; @@ -1130,7 +1104,7 @@ void fpa2bv_converter::mk_abs(func_decl * f, unsigned num, expr * const * args, SASSERT(num == 1); expr * sgn, * s, * e; split_fp(args[0], sgn, e, s); - mk_fp(m_bv_util.mk_numeral(0, 1), e, s, result); + result = m_util.mk_fp(m_bv_util.mk_numeral(0, 1), e, s); } void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -1182,13 +1156,13 @@ void fpa2bv_converter::mk_min_i(func_decl * f, unsigned num, expr * const * args SASSERT(is_well_sorted(m, result)); } -expr_ref fpa2bv_converter::mk_min_unspecified(func_decl * f, expr * x, expr * y) { +expr_ref fpa2bv_converter::mk_min_max_unspecified(func_decl * f, expr * x, expr * y) { unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); expr_ref res(m); - // The only cases in which min is unspecified for is when the arguments are +0.0 and -0.0. - // There is no "hardware interpretation" for fp.min. + // The only cases in which min/max is unspecified for is when the arguments are +0.0 and -0.0. + // There is no "hardware interpretation" for fp.min/fp.max. std::pair decls(0, 0); if (!m_specials.find(f, decls)) { @@ -1201,19 +1175,13 @@ expr_ref fpa2bv_converter::mk_min_unspecified(func_decl * f, expr * x, expr * y) } expr_ref pn(m), np(m); - mk_fp(decls.first, - m_bv_util.mk_numeral(0, ebits), - m_bv_util.mk_numeral(0, sbits - 1), - pn); - mk_fp(decls.second, - m_bv_util.mk_numeral(0, ebits), - m_bv_util.mk_numeral(0, sbits - 1), - np); - - expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m); + pn = m_util.mk_fp(decls.first, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); + np = m_util.mk_fp(decls.second, m_bv_util.mk_numeral(0, ebits), m_bv_util.mk_numeral(0, sbits - 1)); + + expr_ref x_is_pzero(m), y_is_nzero(m), xyzero(m); mk_is_pzero(x, x_is_pzero); - mk_is_nzero(y, x_is_nzero); - m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero); + mk_is_nzero(y, y_is_nzero); + m_simp.mk_and(x_is_pzero, y_is_nzero, xyzero); mk_ite(xyzero, pn, np, res); return res; @@ -1269,46 +1237,9 @@ void fpa2bv_converter::mk_max_i(func_decl * f, unsigned num, expr * const * args SASSERT(is_well_sorted(m, result)); } -expr_ref fpa2bv_converter::mk_max_unspecified(func_decl * f, expr * x, expr * y) { - unsigned ebits = m_util.get_ebits(f->get_range()); - unsigned sbits = m_util.get_sbits(f->get_range()); - expr_ref res(m); - - // The only cases in which max is unspecified for is when the arguments are +0.0 and -0.0. - // There is no "hardware interpretation" for fp.max. - - std::pair decls(0, 0); - if (!m_specials.find(f, decls)) { - decls.first = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); - decls.second = m.mk_fresh_const(0, m_bv_util.mk_sort(1)); - m_specials.insert(f, decls); - m.inc_ref(f); - m.inc_ref(decls.first); - m.inc_ref(decls.second); - } - - expr_ref pn(m), np(m); - mk_fp(decls.first, - m_bv_util.mk_numeral(0, ebits), - m_bv_util.mk_numeral(0, sbits - 1), - pn); - mk_fp(decls.second, - m_bv_util.mk_numeral(0, ebits), - m_bv_util.mk_numeral(0, sbits - 1), - np); - - expr_ref x_is_pzero(m), x_is_nzero(m), xyzero(m); - mk_is_pzero(x, x_is_pzero); - mk_is_nzero(y, x_is_nzero); - m_simp.mk_and(x_is_pzero, x_is_nzero, xyzero); - mk_ite(xyzero, pn, np, res); - - return res; -} - void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 4); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(args[0])); // fusedma means (x * y) + z expr_ref rm(m), x(m), y(m), z(m); @@ -1626,7 +1557,7 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args, void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(args[0])); expr_ref rm(m), x(m); rm = to_app(args[0])->get_arg(0); @@ -1775,7 +1706,7 @@ void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 2); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(args[0])); expr_ref rm(m), x(m); rm = to_app(args[0])->get_arg(0); @@ -1928,8 +1859,7 @@ void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & tie_pttrn = m_bv_util.mk_concat(one_1, m_bv_util.mk_numeral(0, sbits-1)); m_simp.mk_eq(rem, tie_pttrn, tie2); div_last = m_bv_util.mk_extract(0, 0, div); - tie2_c = m.mk_ite(tie2, m.mk_or(m.mk_and(rm_is_rte, m.mk_eq(div_last, one_1)), - m.mk_and(rm_is_rta, m.mk_eq(div_last, zero_1))), + tie2_c = m.mk_ite(tie2, m.mk_or(m.mk_and(rm_is_rte, m.mk_eq(div_last, one_1)), rm_is_rta), m_bv_util.mk_ule(tie_pttrn, rem)); m_simp.mk_ite(tie2_c, div_p1, div, v51); @@ -2187,10 +2117,9 @@ 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_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); + result = m_util.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)); } else if (num == 2 && m_util.is_rm(args[0]) && @@ -2219,7 +2148,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_fp(args[0], args[1], args[2], result); + result = m_util.mk_fp(args[0], args[1], args[2]); } else if (num == 3 && m_util.is_rm(args[0]) && @@ -2235,14 +2164,17 @@ 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_float(func_decl * f, sort * s, expr * rm, expr * x, expr_ref & result) { + SASSERT(m_util.is_bv2rm(rm)); + mk_to_fp_float(s, to_app(rm)->get_arg(0), x, result); +} + +void fpa2bv_converter::mk_to_fp_float(sort * to_srt, 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); - - SASSERT(is_app_of(rm, m_util.get_family_id(), OP_FPA_INTERNAL_RM)); - expr * bv_rm = to_app(rm)->get_arg(0); + unsigned to_sbits = m_util.get_sbits(to_srt); + unsigned to_ebits = m_util.get_ebits(to_srt); if (from_sbits == to_sbits && from_ebits == to_ebits) result = x; @@ -2253,20 +2185,20 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * one1 = m_bv_util.mk_numeral(1, 1); expr_ref ninf(m), pinf(m); - mk_pinf(f, pinf); - mk_ninf(f, ninf); + mk_pinf(to_srt, pinf); + mk_ninf(to_srt, ninf); // NaN -> NaN mk_is_nan(x, c1); - mk_nan(f, v1); + mk_nan(to_srt, v1); // +0 -> +0 mk_is_pzero(x, c2); - mk_pzero(f, v2); + mk_pzero(to_srt, v2); // -0 -> -0 mk_is_nzero(x, c3); - mk_nzero(f, v3); + mk_nzero(to_srt, v3); // +oo -> +oo mk_is_pinf(x, c4); @@ -2380,8 +2312,8 @@ void fpa2bv_converter::mk_to_fp_float(func_decl * f, sort * s, expr * rm, expr * dbg_decouple("fpa2bv_to_float_res_exp", res_exp); expr_ref rounded(m); - expr_ref rm_e(bv_rm, m); - round(s, rm_e, res_sgn, res_sig, res_exp, rounded); + expr_ref rm_e(rm, m); + round(to_srt, rm_e, res_sgn, res_sig, res_exp, rounded); expr_ref is_neg(m), sig_inf(m); m_simp.mk_eq(sgn, one1, is_neg); @@ -2405,7 +2337,7 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * "x: " << mk_ismt2_pp(x, m) << std::endl;); SASSERT(m_util.is_float(s)); SASSERT(au().is_real(x) || au().is_int(x)); - SASSERT(is_app_of(rm, m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(rm)); expr * bv_rm = to_app(rm)->get_arg(0); unsigned ebits = m_util.get_ebits(s); @@ -2443,7 +2375,7 @@ 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, exp); - mk_fp(sgn, exp, sig, result); + result = m_util.mk_fp(sgn, exp, sig); } } else if (m_util.au().is_numeral(x)) { @@ -2476,32 +2408,32 @@ void fpa2bv_converter::mk_to_fp_real(func_decl * f, sort * s, expr * rm, expr * sig = m_bv_util.mk_numeral(m_util.fm().sig(v_nta), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_nta), ebits); mk_bias(unbiased_exp, exp); - mk_fp(sgn, exp, sig, v1); + v1 = m_util.mk_fp(sgn, exp, sig); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_nte)) ? 1 : 0, 1); sig = m_bv_util.mk_numeral(m_util.fm().sig(v_nte), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_nte), ebits); mk_bias(unbiased_exp, exp); - mk_fp(sgn, exp, sig, v2); + v2 = m_util.mk_fp(sgn, exp, sig); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tp)) ? 1 : 0, 1); sig = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tp), ebits); mk_bias(unbiased_exp, exp); - mk_fp(sgn, exp, sig, v3); + v3 = m_util.mk_fp(sgn, exp, sig); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tn)) ? 1 : 0, 1); sig = m_bv_util.mk_numeral(m_util.fm().sig(v_tn), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tn), ebits); mk_bias(unbiased_exp, exp); - mk_fp(sgn, exp, sig, v4); + v4 = m_util.mk_fp(sgn, exp, sig); sgn = m_bv_util.mk_numeral((m_util.fm().sgn(v_tp)) ? 1 : 0, 1); sig = m_bv_util.mk_numeral(m_util.fm().sig(v_tp), sbits - 1); unbiased_exp = m_bv_util.mk_numeral(m_util.fm().exp(v_tp), ebits); mk_bias(unbiased_exp, exp); - mk_fp(sgn, exp, sig, result); + result = m_util.mk_fp(sgn, exp, sig); mk_ite(rm_tn, v4, result, result); mk_ite(rm_tp, v3, result, result); mk_ite(rm_nte, v2, result, result); @@ -2540,7 +2472,7 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(args[0])); expr * bv_rm = to_app(args[0])->get_arg(0); rational e; @@ -2698,7 +2630,7 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const SASSERT(num == 2); SASSERT(m_util.is_float(f->get_range())); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(args[0])); SASSERT(m_bv_util.is_bv(args[1])); expr_ref rm(m), x(m); @@ -2840,7 +2772,7 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con SASSERT(num == 2); SASSERT(m_util.is_float(f->get_range())); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(args[0])); SASSERT(m_bv_util.is_bv(args[1])); expr_ref rm(m), x(m); @@ -2992,7 +2924,7 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl;); SASSERT(num == 2); - SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_util.is_bv2rm(args[0])); SASSERT(m_util.is_float(args[1])); expr * rm = to_app(args[0])->get_arg(0); @@ -3242,29 +3174,16 @@ expr_ref fpa2bv_converter::mk_to_ieee_bv_unspecified(unsigned ebits, unsigned sb return result; } -void fpa2bv_converter::mk_rm(expr * bv3, expr_ref & result) { - SASSERT(m_bv_util.is_bv(bv3) && m_bv_util.get_bv_size(bv3) == 3); - result = m.mk_app(m_util.get_family_id(), OP_FPA_INTERNAL_RM, 0, 0, 1, &bv3, m_util.mk_rm_sort()); -} - -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); + result = m_util.mk_fp(args[0], args[1], args[2]); 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(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); sgn = to_app(e)->get_arg(0); exp = to_app(e)->get_arg(1); @@ -3272,7 +3191,7 @@ void fpa2bv_converter::split_fp(expr * e, expr * & sgn, expr * & exp, expr * & s } 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(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); expr *e_sgn, *e_sig, *e_exp; split_fp(e, e_sgn, e_exp, e_sig); @@ -3322,7 +3241,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_FP)); + SASSERT(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); expr * a0 = to_app(e)->get_arg(0); expr_ref zero(m); @@ -3331,7 +3250,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_FP)); + SASSERT(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); expr * a0 = to_app(e)->get_arg(0); expr_ref one(m); @@ -3500,7 +3419,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_FP)); + SASSERT(m_util.is_fp(e)); SASSERT(to_app(e)->get_num_args() == 3); sort * srt = to_app(e)->get_decl()->get_range(); @@ -3597,9 +3516,9 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref TRACE("fpa2bv_unpack", tout << "UNPACK EXP = " << mk_ismt2_pp(exp, m) << std::endl; ); } -void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) +void fpa2bv_converter::mk_rounding_mode(decl_kind k, expr_ref & result) { - switch(f->get_decl_kind()) + switch(k) { case OP_FPA_RM_NEAREST_TIES_TO_EVEN: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3); break; case OP_FPA_RM_NEAREST_TIES_TO_AWAY: result = m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3); break; @@ -3609,16 +3528,16 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) default: UNREACHABLE(); } - mk_rm(result, result); + result = m_util.mk_bv2rm(result); } void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef Z3DEBUG return; // CMW: This works only for quantifier-free formulas. - if (is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP)) { + if (m_util.is_fp(e)) { expr_ref new_bv(m); - expr *e_sgn, *e_sig, *e_exp; + expr *e_sgn, *e_sig, *e_exp; split_fp(e, e_sgn, e_exp, e_sig); unsigned ebits = m_bv_util.get_bv_size(e_exp); unsigned sbits = m_bv_util.get_bv_size(e_sig) + 1; @@ -4007,7 +3926,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_fp(res_sgn, res_exp, res_sig, result); + result = m_util.mk_fp(res_sgn, res_exp, res_sig); 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 b6a6bdbb37f..d056a364231 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -24,6 +24,11 @@ Module Name: #include"ref_util.h" #include"fpa_decl_plugin.h" #include"bv_decl_plugin.h" +#include"array_decl_plugin.h" +#include"datatype_decl_plugin.h" +#include"dl_decl_plugin.h" +#include"pb_decl_plugin.h" +#include"seq_decl_plugin.h" #include"basic_simplifier_plugin.h" class fpa2bv_converter { @@ -33,6 +38,9 @@ class fpa2bv_converter { fpa_util m_util; bv_util m_bv_util; arith_util m_arith_util; + array_util m_array_util; + datatype_util m_dt_util; + seq_util m_seq_util; mpf_manager & m_mpf_manager; unsynch_mpz_manager & m_mpz_manager; fpa_decl_plugin * m_plugin; @@ -40,7 +48,7 @@ class fpa2bv_converter { obj_map m_const2bv; obj_map m_rm_const2bv; - obj_map m_uf2bvuf; + obj_map m_uf2bvuf; obj_map > m_specials; @@ -59,12 +67,9 @@ class fpa2bv_converter { bool is_rm(expr * e) { return is_app(e) && m_util.is_rm(e); } 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_rm(expr * bv3, expr_ref & result); - - void mk_fp(expr * sign, expr * exponent, expr * significand, expr_ref & result); + void mk_fp(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - + void split_fp(expr * e, expr * & sgn, expr * & exp, expr * & sig) const; void split_fp(expr * e, expr_ref & sgn, expr_ref & exp, expr_ref & sig) const; @@ -72,11 +77,11 @@ class fpa2bv_converter { void mk_ite(expr * c, expr * t, expr * f, expr_ref & result); void mk_distinct(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_rounding_mode(func_decl * f, expr_ref & result); + void mk_rounding_mode(decl_kind k, 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); - virtual void mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + virtual void mk_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_pinf(func_decl * f, expr_ref & result); @@ -128,11 +133,10 @@ class fpa2bv_converter { void mk_min(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_min_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - virtual expr_ref mk_min_unspecified(func_decl * f, expr * x, expr * y); + virtual expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y); void mk_max(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_max_i(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - virtual expr_ref mk_max_unspecified(func_decl * f, expr * x, expr * y); expr_ref mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); expr_ref mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); @@ -144,6 +148,9 @@ class fpa2bv_converter { void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector m_extra_assertions; + bool is_special(func_decl * f) { return m_specials.contains(f); } + bool is_uf2bvuf(func_decl * f) { return m_uf2bvuf.contains(f); } + protected: void mk_one(func_decl *f, expr_ref & sign, expr_ref & result); @@ -183,7 +190,11 @@ class fpa2bv_converter { void mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result); - void mk_uninterpreted_output(sort * rng, func_decl * fbv, expr_ref_buffer & new_args, expr_ref & result); + sort_ref replace_float_sorts(sort * s); + func_decl_ref replace_function(func_decl * f); + expr_ref replace_float_arg(expr * a); + void mk_function_output(sort * rng, func_decl * fbv, expr * const * new_args, expr_ref & result); + func_decl * get_bv_uf(func_decl * f, sort * bv_rng, unsigned arity); private: void mk_nan(sort * s, expr_ref & result); @@ -201,6 +212,8 @@ class fpa2bv_converter { void mk_div(sort * s, expr_ref & bv_rm, expr_ref & x, expr_ref & y, expr_ref & result); void mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & result); void mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & x, expr_ref & result); + + void mk_to_fp_float(sort * s, expr * rm, expr * x, expr_ref & result); }; #endif diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp index 27fc8ebc766..62281226e61 100644 --- a/src/ast/fpa/fpa2bv_rewriter.cpp +++ b/src/ast/fpa/fpa2bv_rewriter.cpp @@ -56,7 +56,10 @@ bool fpa2bv_rewriter_cfg::max_steps_exceeded(unsigned num_steps) const { br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - TRACE("fpa2bv_rw", tout << "APP: " << f->get_name() << std::endl; ); + TRACE("fpa2bv_rw", tout << "func: " << f->get_name() << std::endl; + tout << "args: " << std::endl; + for (unsigned i = 0; i < num; i++) + tout << mk_ismt2_pp(args[i], m()) << std::endl;); if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_float(f->get_range())) { m_conv.mk_const(f, result); @@ -71,7 +74,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co if (m().is_eq(f)) { SASSERT(num == 2); TRACE("fpa2bv_rw", tout << "(= " << mk_ismt2_pp(args[0], m()) << " " << - mk_ismt2_pp(args[1], m()) << ")" << std::endl;); + mk_ismt2_pp(args[1], m()) << ")" << std::endl;); SASSERT(m().get_sort(args[0]) == m().get_sort(args[1])); sort * ds = f->get_domain()[0]; if (m_conv.is_float(ds)) { @@ -83,7 +86,7 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co return BR_DONE; } return BR_FAILED; - } + } else if (m().is_ite(f)) { SASSERT(num == 3); if (m_conv.is_float(args[1])) { @@ -100,14 +103,14 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co } return BR_FAILED; } - + if (m_conv.is_float_family(f)) { switch (f->get_decl_kind()) { 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_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f->get_decl_kind(), 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; @@ -147,14 +150,14 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_REWRITE_FULL; case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_REWRITE_FULL; - case OP_FPA_INTERNAL_MIN_UNSPECIFIED: result = m_conv.mk_min_unspecified(f, args[0], args[1]); return BR_DONE; - case OP_FPA_INTERNAL_MAX_UNSPECIFIED: result = m_conv.mk_max_unspecified(f, args[0], args[1]); return BR_DONE; + case OP_FPA_INTERNAL_MIN_UNSPECIFIED: + case OP_FPA_INTERNAL_MAX_UNSPECIFIED: result = m_conv.mk_min_max_unspecified(f, args[0], args[1]); return BR_DONE; case OP_FPA_INTERNAL_MIN_I: m_conv.mk_min_i(f, num, args, result); return BR_DONE; case OP_FPA_INTERNAL_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE; - case OP_FPA_INTERNAL_RM: case OP_FPA_INTERNAL_BVWRAP: - case OP_FPA_INTERNAL_BVUNWRAP: + case OP_FPA_INTERNAL_BV2RM: + case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: @@ -166,19 +169,11 @@ br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * co NOT_IMPLEMENTED_YET(); } } - else { + else + { SASSERT(!m_conv.is_float_family(f)); - bool is_float_uf = m_conv.is_float(f->get_range()) || m_conv.is_rm(f->get_range()); - - for (unsigned i = 0; i < f->get_arity(); i++) { - sort * di = f->get_domain()[i]; - is_float_uf |= m_conv.is_float(di) || m_conv.is_rm(di); - } - - if (is_float_uf) { - m_conv.mk_uninterpreted_function(f, num, args, result); - return BR_DONE; - } + m_conv.mk_function(f, num, args, result); + return BR_DONE; } return BR_FAILED; @@ -249,17 +244,15 @@ bool fpa2bv_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & res expr_ref new_exp(m()); sort * s = t->get_sort(); - if (m_conv.is_float(s)) - { - expr_ref new_var(m()); - 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_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); - } + if (m_conv.is_float(s)) { + expr_ref new_var(m()); + 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)); + new_exp = m_conv.fu().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)); + } else new_exp = m().mk_var(t->get_idx(), s); diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 511d36e671e..6c8b7ac6fcd 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -676,7 +676,7 @@ func_decl * fpa_decl_plugin::mk_to_ieee_bv(decl_kind k, unsigned num_parameters, return m_manager->mk_func_decl(name, 1, domain, bv_srt, func_decl_info(m_family_id, k)); } -func_decl * fpa_decl_plugin::mk_internal_rm(decl_kind k, unsigned num_parameters, parameter const * parameters, +func_decl * fpa_decl_plugin::mk_internal_bv2rm(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_rm"); @@ -691,7 +691,7 @@ func_decl * fpa_decl_plugin::mk_internal_rm(decl_kind k, unsigned num_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) { + unsigned arity, sort * const * domain, sort * range) { if (arity != 1) m_manager->raise_exception("invalid number of arguments to bv_wrap"); if (!is_float_sort(domain[0]) && !is_rm_sort(domain[0])) @@ -711,18 +711,6 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param } } -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 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 or RoundingMode sort"); - - return m_manager->mk_func_decl(symbol("bv_unwrap"), 1, domain, range, func_decl_info(m_family_id, k, num_parameters, parameters)); -} - func_decl * fpa_decl_plugin::mk_internal_to_ubv_unspecified( decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { @@ -847,12 +835,10 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_TO_IEEE_BV: return mk_to_ieee_bv(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_RM: - return mk_internal_rm(k, num_parameters, parameters, arity, domain, range); case OP_FPA_INTERNAL_BVWRAP: - return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_INTERNAL_BVUNWRAP: - return mk_internal_bv_unwrap(k, num_parameters, parameters, arity, domain, range); + return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); + case OP_FPA_INTERNAL_BV2RM: + return mk_internal_bv2rm(k, num_parameters, parameters, arity, domain, range); case OP_FPA_INTERNAL_MIN_I: case OP_FPA_INTERNAL_MAX_I: @@ -1027,12 +1013,12 @@ sort * fpa_util::mk_float_sort(unsigned ebits, unsigned sbits) { return m().mk_sort(m_fid, FLOATING_POINT_SORT, 2, ps); } -unsigned fpa_util::get_ebits(sort * s) { +unsigned fpa_util::get_ebits(sort * s) const { SASSERT(is_float(s)); return static_cast(s->get_parameter(0).get_int()); } -unsigned fpa_util::get_sbits(sort * s) { +unsigned fpa_util::get_sbits(sort * s) const { SASSERT(is_float(s)); return static_cast(s->get_parameter(1).get_int()); } @@ -1090,3 +1076,64 @@ app * fpa_util::mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits) sort * range = m_a_util.mk_real(); return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, 2, ps, 0, 0, range); } + +bool fpa_util::contains_floats(ast * a) { + switch (a->get_kind()) { + case AST_APP: { + app * aa = to_app(a); + if (contains_floats(aa->get_decl())) + return true; + else + for (unsigned i = 0; i < aa->get_num_args(); i++) + if (contains_floats(aa->get_arg(i))) + return true; + break; + } + case AST_VAR: + return contains_floats(to_var(a)->get_sort()); + break; + case AST_QUANTIFIER: { + quantifier * q = to_quantifier(a); + for (unsigned i = 0; i < q->get_num_children(); i++) + if (contains_floats(q->get_child(i))) + return true; + for (unsigned i = 0; i < q->get_num_decls(); i++) + if (contains_floats(q->get_decl_sort(i))) + return true; + if (contains_floats(q->get_expr())) + return true; + break; + } + case AST_SORT: { + sort * s = to_sort(a); + if (is_float(s) || is_rm(s)) + return true; + else { + for (unsigned i = 0; i < s->get_num_parameters(); i++) { + parameter const & pi = s->get_parameter(i); + if (pi.is_ast() && contains_floats(pi.get_ast())) + return true; + } + } + break; + } + case AST_FUNC_DECL: { + func_decl * f = to_func_decl(a); + for (unsigned i = 0; i < f->get_arity(); i++) + if (contains_floats(f->get_domain(i))) + return true; + if (contains_floats(f->get_range())) + return true; + for (unsigned i = 0; i < f->get_num_parameters(); i++) { + parameter const & pi = f->get_parameter(i); + if (pi.is_ast() && contains_floats(pi.get_ast())) + return true; + } + break; + } + default: + UNREACHABLE(); + } + + return false; +} diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index a351b261035..ee7325014f8 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -87,9 +87,8 @@ enum fpa_op_kind { OP_FPA_TO_IEEE_BV, /* Internal use only */ - OP_FPA_INTERNAL_RM, // Internal conversion from (_ BitVec 3) to RoundingMode OP_FPA_INTERNAL_BVWRAP, - OP_FPA_INTERNAL_BVUNWRAP, + OP_FPA_INTERNAL_BV2RM, OP_FPA_INTERNAL_MIN_I, OP_FPA_INTERNAL_MAX_I, @@ -165,8 +164,8 @@ class fpa_decl_plugin : public decl_plugin { 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_internal_rm(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + func_decl * mk_internal_bv2rm(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, @@ -256,12 +255,13 @@ class fpa_util { sort * mk_float_sort(unsigned ebits, unsigned sbits); sort * mk_rm_sort() { return m().mk_sort(m_fid, ROUNDING_MODE_SORT); } - bool is_float(sort * s) { return is_sort_of(s, m_fid, FLOATING_POINT_SORT); } - bool is_rm(sort * s) { return is_sort_of(s, m_fid, ROUNDING_MODE_SORT); } - bool is_float(expr * e) { return is_float(m_manager.get_sort(e)); } - bool is_rm(expr * e) { return is_rm(m_manager.get_sort(e)); } - unsigned get_ebits(sort * s); - unsigned get_sbits(sort * s); + bool is_float(sort * s) const { return is_sort_of(s, m_fid, FLOATING_POINT_SORT); } + bool is_rm(sort * s) const { return is_sort_of(s, m_fid, ROUNDING_MODE_SORT); } + bool is_float(expr * e) const { return is_float(m_manager.get_sort(e)); } + bool is_rm(expr * e) const { return is_rm(m_manager.get_sort(e)); } + bool is_fp(expr * e) const { return is_app_of(e, m_fid, OP_FPA_FP); } + unsigned get_ebits(sort * s) const; + unsigned get_sbits(sort * s) const; 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); } @@ -294,7 +294,13 @@ class fpa_util { 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 * sgn, expr * exp, expr * sig) { return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig); } + app * mk_fp(expr * sgn, expr * exp, expr * sig) { + SASSERT(m_bv_util.is_bv(sgn) && m_bv_util.get_bv_size(sgn) == 1); + SASSERT(m_bv_util.is_bv(exp)); + SASSERT(m_bv_util.is_bv(sig)); + return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig); + } + app * mk_to_fp(sort * s, expr * bv_t) { SASSERT(is_float(s) && s->get_num_parameters() == 2); return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 1, &bv_t); @@ -362,13 +368,39 @@ class fpa_util { app * mk_to_ieee_bv(expr * arg1) { return m().mk_app(m_fid, OP_FPA_TO_IEEE_BV, arg1); } + app * mk_bv2rm(expr * bv3) { + SASSERT(m_bv_util.is_bv(bv3) && m_bv_util.get_bv_size(bv3) == 3); + return m().mk_app(m_fid, OP_FPA_INTERNAL_BV2RM, 0, 0, 1, &bv3, mk_rm_sort()); + } app * mk_internal_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned width); app * mk_internal_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned width); app * mk_internal_to_ieee_bv_unspecified(unsigned ebits, unsigned sbits); app * mk_internal_to_real_unspecified(unsigned ebits, unsigned sbits); - 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); } + bool is_bvwrap(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BVWRAP); } + bool is_bvwrap(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BVWRAP; } + bool is_bv2rm(expr * e) const { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_BV2RM); } + bool is_bv2rm(func_decl * f) const { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_BV2RM; } + + bool is_min_interpreted(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_I); } + bool is_min_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED); } + bool is_max_interpreted(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_I); } + bool is_max_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED); } + bool is_to_ubv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED); } + bool is_to_sbv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED); } + bool is_to_ieee_bv_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED); } + bool is_to_real_unspecified(expr * e) { return is_app_of(e, get_family_id(), OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED); } + + bool is_min_interpreted(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_I; } + bool is_min_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MIN_UNSPECIFIED; } + bool is_max_interpreted(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_I; } + bool is_max_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_MAX_UNSPECIFIED; } + bool is_to_ubv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED; } + bool is_to_sbv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED; } + bool is_to_ieee_bv_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED; } + bool is_to_real_unspecified(func_decl * f) { return f->get_family_id() == get_family_id() && f->get_decl_kind() == OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED; } + + bool contains_floats(ast * a); }; #endif diff --git a/src/ast/normal_forms/nnf.cpp b/src/ast/normal_forms/nnf.cpp index 6b10e8c10ed..e15e26bf209 100644 --- a/src/ast/normal_forms/nnf.cpp +++ b/src/ast/normal_forms/nnf.cpp @@ -200,14 +200,14 @@ typedef default_exception nnf_exception; struct nnf::imp { struct frame { - expr * m_curr; + expr_ref m_curr; unsigned m_i:28; unsigned m_pol:1; // pos/neg polarity unsigned m_in_q:1; // true if m_curr is nested in a quantifier unsigned m_new_child:1; unsigned m_cache_result:1; unsigned m_spos; // top of the result stack, when the frame was created. - frame(expr * n, bool pol, bool in_q, bool cache_res, unsigned spos): + frame(expr_ref& n, bool pol, bool in_q, bool cache_res, unsigned spos): m_curr(n), m_i(0), m_pol(pol), @@ -225,7 +225,7 @@ struct nnf::imp { #define POS_Q_CIDX 3 // positive polarity and nested in a quantifier ast_manager & m_manager; - svector m_frame_stack; + vector m_frame_stack; expr_ref_vector m_result_stack; typedef act_cache cache; @@ -324,7 +324,8 @@ struct nnf::imp { } void push_frame(expr * t, bool pol, bool in_q, bool cache_res) { - m_frame_stack.push_back(frame(t, pol, in_q, cache_res, m_result_stack.size())); + expr_ref tr(t, m()); + m_frame_stack.push_back(frame(tr, pol, in_q, cache_res, m_result_stack.size())); } static unsigned get_cache_idx(bool pol, bool in_q) { diff --git a/src/ast/rewriter/bv_trailing.cpp b/src/ast/rewriter/bv_trailing.cpp index 414854f3a76..cf50ab0e247 100644 --- a/src/ast/rewriter/bv_trailing.cpp +++ b/src/ast/rewriter/bv_trailing.cpp @@ -67,9 +67,10 @@ struct bv_trailing::imp { } expr_ref out1(m); expr_ref out2(m); - const unsigned rm1 = remove_trailing(e1, min, out1, TRAILING_DEPTH); - const unsigned rm2 = remove_trailing(e2, min, out2, TRAILING_DEPTH); - SASSERT(rm1 == min && rm2 == min); + DEBUG_CODE( + const unsigned rm1 = remove_trailing(e1, min, out1, TRAILING_DEPTH); + const unsigned rm2 = remove_trailing(e2, min, out2, TRAILING_DEPTH); + SASSERT(rm1 == min && rm2 == min);); const bool are_eq = m.are_equal(out1, out2); result = are_eq ? m.mk_true() : m.mk_eq(out1, out2); return are_eq ? BR_DONE : BR_REWRITE2; @@ -122,9 +123,8 @@ struct bv_trailing::imp { expr_ref tmp(m); for (unsigned i = 0; i < num; ++i) { expr * const curr = a->get_arg(i); - const unsigned crm = remove_trailing(curr, to_rm, tmp, depth - 1); + VERIFY(to_rm == remove_trailing(curr, to_rm, tmp, depth - 1)); new_args.push_back(tmp); - SASSERT(crm == to_rm); } result = m.mk_app(m_util.get_fid(), OP_BADD, new_args.size(), new_args.c_ptr()); return to_rm; diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 619d5ffbf19..b8d9c232fc5 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -98,18 +98,15 @@ br_status fpa_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con case OP_FPA_INTERNAL_MIN_UNSPECIFIED: case OP_FPA_INTERNAL_MAX_UNSPECIFIED: SASSERT(num_args == 2); st = BR_FAILED; break; + + case OP_FPA_INTERNAL_BVWRAP: SASSERT(num_args == 1); st = mk_bvwrap(args[0], result); break; + case OP_FPA_INTERNAL_BV2RM: SASSERT(num_args == 1); st = mk_bv2rm(args[0], result); break; - case OP_FPA_INTERNAL_RM: - SASSERT(num_args == 1); st = mk_rm(args[0], result); break; case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED: case OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED: st = BR_FAILED; - - case OP_FPA_INTERNAL_BVWRAP: - case OP_FPA_INTERNAL_BVUNWRAP: - st = BR_FAILED; break; default: @@ -722,7 +719,7 @@ br_status fpa_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) return BR_FAILED; } -br_status fpa_rewriter::mk_rm(expr * arg, expr_ref & result) { +br_status fpa_rewriter::mk_bv2rm(expr * arg, expr_ref & result) { bv_util bu(m()); rational bv_val; unsigned sz = 0; @@ -892,3 +889,34 @@ br_status fpa_rewriter::mk_to_real(expr * arg, expr_ref & result) { return BR_FAILED; } + +br_status fpa_rewriter::mk_bvwrap(expr * arg, expr_ref & result) { + if (is_app_of(arg, m_util.get_family_id(), OP_FPA_FP)) { + bv_util bu(m()); + SASSERT(to_app(arg)->get_num_args() == 3); + sort_ref fpsrt(m()); + fpsrt = to_app(arg)->get_decl()->get_range(); + expr_ref a0(m()), a1(m()), a2(m()); + a0 = to_app(arg)->get_arg(0); + a1 = to_app(arg)->get_arg(1); + a2 = to_app(arg)->get_arg(2); + if (bu.is_extract(a0) && bu.is_extract(a1) && bu.is_extract(a2)) { + unsigned w0 = bu.get_extract_high(a0) - bu.get_extract_low(a0) + 1; + unsigned w1 = bu.get_extract_high(a1) - bu.get_extract_low(a1) + 1; + unsigned w2 = bu.get_extract_high(a2) - bu.get_extract_low(a2) + 1; + unsigned cw = w0 + w1 + w2; + if (cw == m_util.get_ebits(fpsrt) + m_util.get_sbits(fpsrt)) { + expr_ref aa0(m()), aa1(m()), aa2(m()); + aa0 = to_app(a0)->get_arg(0); + aa1 = to_app(a1)->get_arg(0); + aa2 = to_app(a2)->get_arg(0); + if (aa0 == aa1 && aa1 == aa2 && bu.get_bv_size(aa0) == cw) { + result = aa0; + return BR_DONE; + } + } + } + } + + return BR_FAILED; +} diff --git a/src/ast/rewriter/fpa_rewriter.h b/src/ast/rewriter/fpa_rewriter.h index 3afc31a9f28..0d9c6a380e7 100644 --- a/src/ast/rewriter/fpa_rewriter.h +++ b/src/ast/rewriter/fpa_rewriter.h @@ -78,7 +78,7 @@ class fpa_rewriter { 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, expr * arg1, expr * arg2, expr_ref & result); - br_status mk_rm(expr * arg, expr_ref & result); + br_status mk_bv2rm(expr * arg, expr_ref & result); br_status mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result); br_status mk_to_fp_unsigned(expr * arg1, expr * arg2, expr_ref & result); br_status mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); @@ -89,6 +89,8 @@ class fpa_rewriter { br_status mk_to_ubv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result); br_status mk_to_sbv_unspecified(unsigned ebits, unsigned sbits, unsigned with, expr_ref & result); br_status mk_to_real_unspecified(unsigned ebits, unsigned sbits, expr_ref & result); + + br_status mk_bvwrap(expr * arg, expr_ref & result); }; #endif diff --git a/src/ast/rewriter/rewriter.cpp b/src/ast/rewriter/rewriter.cpp index 2b5e7e006bd..c7b110dff68 100644 --- a/src/ast/rewriter/rewriter.cpp +++ b/src/ast/rewriter/rewriter.cpp @@ -173,6 +173,7 @@ void rewriter_core::elim_reflex_prs(unsigned spos) { rewriter_core::rewriter_core(ast_manager & m, bool proof_gen): m_manager(m), m_proof_gen(proof_gen), + m_cancel_check(true), m_result_stack(m), m_result_pr_stack(m), m_num_qvars(0) { diff --git a/src/ast/rewriter/rewriter.h b/src/ast/rewriter/rewriter.h index 44f436fa898..401d00d8997 100644 --- a/src/ast/rewriter/rewriter.h +++ b/src/ast/rewriter/rewriter.h @@ -48,6 +48,7 @@ class rewriter_core { }; ast_manager & m_manager; bool m_proof_gen; + bool m_cancel_check; typedef act_cache cache; ptr_vector m_cache_stack; cache * m_cache; // current cache. @@ -114,6 +115,7 @@ class rewriter_core { ast_manager & m() const { return m_manager; } void reset(); void cleanup(); + void set_cancel_check(bool f) { m_cancel_check = f; } #ifdef _TRACE void display_stack(std::ostream & out, unsigned pp_depth); #endif diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 4d55632d3e7..eaf5713ee1d 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -595,7 +595,7 @@ void rewriter_tpl::set_inv_bindings(unsigned num_bindings, expr * const template template void rewriter_tpl::main_loop(expr * t, expr_ref & result, proof_ref & result_pr) { - if (m().canceled()) { + if (m_cancel_check && m().canceled()) { throw rewriter_exception(m().limit().get_cancel_msg()); } SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size()); @@ -629,7 +629,7 @@ template void rewriter_tpl::resume_core(expr_ref & result, proof_ref & result_pr) { SASSERT(!frame_stack().empty()); while (!frame_stack().empty()) { - if (m().canceled()) { + if (m_cancel_check && m().canceled()) { throw rewriter_exception(m().limit().get_cancel_msg()); } SASSERT(!ProofGen || result_stack().size() == result_pr_stack().size()); diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index ab711dde760..6f6daf8dfb4 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -212,14 +212,11 @@ struct th_rewriter_cfg : public default_rewriter_cfg { // auxiliary function for pull_ite_core expr * mk_eq_value(expr * lhs, expr * value) { - SASSERT(m().is_value(value)); - if (m().is_value(lhs)) { - if (m().are_equal(lhs, value)) { - return m().mk_true(); - } - else if (m().are_distinct(lhs, value)) { - return m().mk_false(); - } + if (m().are_equal(lhs, value)) { + return m().mk_true(); + } + else if (m().are_distinct(lhs, value)) { + return m().mk_false(); } return m().mk_eq(lhs, value); } diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 708da560293..21af0773a4a 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -277,13 +277,12 @@ bool seq_decl_plugin::is_sort_param(sort* s, unsigned& idx) { } bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) { - ast_manager& m = *m_manager; if (s == sP) return true; unsigned i; if (is_sort_param(sP, i)) { if (binding.size() <= i) binding.resize(i+1); if (binding[i] && (binding[i] != s)) return false; - TRACE("seq_verbose", tout << "setting binding @ " << i << " to " << mk_pp(s, m) << "\n";); + TRACE("seq_verbose", tout << "setting binding @ " << i << " to " << mk_pp(s, *m_manager) << "\n";); binding[i] = s; return true; } @@ -302,7 +301,7 @@ bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) { return true; } else { - TRACE("seq", tout << "Could not match " << mk_pp(s, m) << " and " << mk_pp(sP, m) << "\n";); + TRACE("seq", tout << "Could not match " << mk_pp(s, *m_manager) << " and " << mk_pp(sP, *m_manager) << "\n";); return false; } } diff --git a/src/ast/simplifier/simplifier.cpp b/src/ast/simplifier/simplifier.cpp index 895aa529bd6..63731c6794b 100644 --- a/src/ast/simplifier/simplifier.cpp +++ b/src/ast/simplifier/simplifier.cpp @@ -63,6 +63,7 @@ void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) { m_need_reset = true; reinitialize(); expr * s_orig = s; + (void)s_orig; expr * old_s; expr * result; proof * result_proof; diff --git a/src/cmd_context/cmd_context_to_goal.cpp b/src/cmd_context/cmd_context_to_goal.cpp index 26cb2766b1e..c0b4379aaa1 100644 --- a/src/cmd_context/cmd_context_to_goal.cpp +++ b/src/cmd_context/cmd_context_to_goal.cpp @@ -31,8 +31,7 @@ void assert_exprs_from(cmd_context const & ctx, goal & t) { ptr_vector::const_iterator it = ctx.begin_assertions(); ptr_vector::const_iterator end = ctx.end_assertions(); ptr_vector::const_iterator it2 = ctx.begin_assertion_names(); - ptr_vector::const_iterator end2 = ctx.end_assertion_names(); - SASSERT(end - it == end2 - it2); + SASSERT(end - it == ctx.end_assertion_names() - it2); for (; it != end; ++it, ++it2) { t.assert_expr(*it, proofs_enabled ? m.mk_asserted(*it) : 0, m.mk_leaf(*it2)); } diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp index c47662ddf0b..c86ff9f62dd 100755 --- a/src/duality/duality_rpfp.cpp +++ b/src/duality/duality_rpfp.cpp @@ -2365,8 +2365,7 @@ namespace Duality { Term CanonIneqTerm(const Term &p){ Term term,bound; Term ps = p.simplify(); - bool ok = IsCanonIneq(ps,term,bound); - assert(ok); + VERIFY(IsCanonIneq(ps,term,bound)); return term - bound; } diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index ebb5e00c8df..4f674198902 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -342,6 +342,7 @@ class iz3translation_full : public iz3translation { else cls1.push_back(cls2[j]); } + (void)found_pivot2; assert(found_pivot2); return; } diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp index f20f16a082c..95d66f61788 100755 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -362,6 +362,7 @@ class iz3translation_direct : public iz3translation { else cls1.push_back(cls2[j]); } + (void)found_pivot2; assert(found_pivot2); return; } diff --git a/src/math/euclid/euclidean_solver.cpp b/src/math/euclid/euclidean_solver.cpp index af11d43044d..b33dbf3aab1 100644 --- a/src/math/euclid/euclidean_solver.cpp +++ b/src/math/euclid/euclidean_solver.cpp @@ -580,8 +580,8 @@ struct euclidean_solver::imp { void substitute_most_recent_solution(var x) { SASSERT(!m_solution.empty()); - equation & eq = *(m_solution.back()); - TRACE("euclidean_solver", tout << "applying solution for x" << x << "\n"; display(tout, eq); tout << "\n";); + TRACE("euclidean_solver", tout << "applying solution for x" << x << "\n"; + display(tout, *(m_solution.back())); tout << "\n";); occs & use_list = m_occs[x]; occs::iterator it = use_list.begin(); occs::iterator end = use_list.end(); diff --git a/src/math/grobner/grobner.cpp b/src/math/grobner/grobner.cpp index 309e0c777b0..0c96dfde3cd 100644 --- a/src/math/grobner/grobner.cpp +++ b/src/math/grobner/grobner.cpp @@ -249,6 +249,7 @@ void grobner::update_order() { } bool grobner::var_lt::operator()(expr * v1, expr * v2) const { + if (v1 == v2) return false; int w1 = 0; int w2 = 0; m_var2weight.find(v1, w1); @@ -268,6 +269,8 @@ bool grobner::monomial_lt::operator()(monomial * m1, monomial * m2) const { for (; it1 != end1; ++it1, ++it2) { expr * v1 = *it1; expr * v2 = *it2; + if (v1 == v2) + continue; if (m_var_lt(v1, v2)) return true; if (v1 != v2) @@ -670,7 +673,7 @@ grobner::equation * grobner::simplify(equation const * source, equation * target simplify(target); } } - while (simplified); + while (simplified && !m_manager.canceled()); TRACE("grobner", tout << "result: "; display_equation(tout, *target);); return result ? target : 0; } @@ -697,7 +700,10 @@ grobner::equation * grobner::simplify_using_processed(equation * eq) { simplified = true; eq = new_eq; } - } + if (m_manager.canceled()) { + return 0; + } + } } while (simplified); TRACE("grobner", tout << "simplification result: "; display_equation(tout, *eq);); @@ -749,13 +755,13 @@ grobner::equation * grobner::pick_next() { /** \brief Use the given equation to simplify processed terms. */ -void grobner::simplify_processed(equation * eq) { +bool grobner::simplify_processed(equation * eq) { ptr_buffer to_insert; ptr_buffer to_remove; ptr_buffer to_delete; equation_set::iterator it = m_processed.begin(); equation_set::iterator end = m_processed.end(); - for (; it != end; ++it) { + for (; it != end && !m_manager.canceled(); ++it) { equation * curr = *it; m_changed_leading_term = false; // if the leading term is simplified, then the equation has to be moved to m_to_process @@ -795,6 +801,7 @@ void grobner::simplify_processed(equation * eq) { end1 = to_delete.end(); for (; it1 != end1; ++it1) del_equation(*it1); + return !m_manager.canceled(); } /** @@ -944,7 +951,8 @@ bool grobner::compute_basis_step() { m_equations_to_unfreeze.push_back(eq); eq = new_eq; } - simplify_processed(eq); + if (m_manager.canceled()) return false; + if (!simplify_processed(eq)) return false; superpose(eq); m_processed.insert(eq); simplify_to_process(eq); @@ -954,7 +962,7 @@ bool grobner::compute_basis_step() { bool grobner::compute_basis(unsigned threshold) { compute_basis_init(); - while (m_num_new_equations < threshold) { + while (m_num_new_equations < threshold && !m_manager.canceled()) { if (compute_basis_step()) return true; } return false; diff --git a/src/math/grobner/grobner.h b/src/math/grobner/grobner.h index 6084bf77d63..770f0a538bd 100644 --- a/src/math/grobner/grobner.h +++ b/src/math/grobner/grobner.h @@ -175,7 +175,7 @@ class grobner { equation * pick_next(); - void simplify_processed(equation * eq); + bool simplify_processed(equation * eq); void simplify_to_process(equation * eq); diff --git a/src/math/polynomial/upolynomial.cpp b/src/math/polynomial/upolynomial.cpp index 78ce912f4f3..aa26ccf4ce8 100644 --- a/src/math/polynomial/upolynomial.cpp +++ b/src/math/polynomial/upolynomial.cpp @@ -2759,6 +2759,7 @@ namespace upolynomial { bool manager::refine_core(unsigned sz, numeral const * p, int sign_a, mpbq_manager & bqm, mpbq & a, mpbq & b) { SASSERT(sign_a == eval_sign_at(sz, p, a)); int sign_b = -sign_a; + (void)sign_b; SASSERT(sign_b == eval_sign_at(sz, p, b)); SASSERT(sign_a == -sign_b); SASSERT(sign_a != 0 && sign_b != 0); @@ -2810,9 +2811,8 @@ namespace upolynomial { bool manager::refine(unsigned sz, numeral const * p, mpbq_manager & bqm, mpbq & a, mpbq & b, unsigned prec_k) { int sign_a = eval_sign_at(sz, p, a); - int sign_b = -sign_a; - SASSERT(eval_sign_at(sz, p, b) == sign_b); - SASSERT(sign_a != 0 && sign_b != 0); + SASSERT(eval_sign_at(sz, p, b) == -sign_a); + SASSERT(sign_a != 0); return refine_core(sz, p, sign_a, bqm, a, b, prec_k); } @@ -2928,6 +2928,7 @@ namespace upolynomial { SASSERT(sign_a == eval_sign_at(sz, p, a)); } int sign_b = -sign_a; + (void) sign_b; SASSERT(sign_b == eval_sign_at(sz, p, b)); SASSERT(sign_a != 0 && sign_b != 0); if (has_zero_roots(sz, p)) { diff --git a/src/math/polynomial/upolynomial_factorization.cpp b/src/math/polynomial/upolynomial_factorization.cpp index b36658bba13..5a7aefa186d 100644 --- a/src/math/polynomial/upolynomial_factorization.cpp +++ b/src/math/polynomial/upolynomial_factorization.cpp @@ -371,9 +371,10 @@ void zp_square_free_factor(zp_manager & upm, numeral_vector const & f, zp_factor bool zp_factor(zp_manager & upm, numeral_vector const & f, zp_factors & factors) { - unsigned p = get_p_from_manager(upm.m()); - TRACE("polynomial::factorization", tout << "polynomial::factor("; upm.display(tout, f); tout << ") over Z_" << p << endl;); + TRACE("polynomial::factorization", + unsigned p = get_p_from_manager(upm.m()); + tout << "polynomial::factor("; upm.display(tout, f); tout << ") over Z_" << p << endl;); // get the sq-free parts (all of them will be monic) zp_factors sq_free_factors(upm); @@ -435,6 +436,7 @@ bool zp_factor_square_free_berlekamp(zp_manager & upm, numeral_vector const & f, // process the null space vectors (skip first one, it's [1, 0, ..., 0]) while generating the factors unsigned d = upm.degree(f); + (void)d; scoped_numeral_vector v_k(zpm); while (Q_I.next_null_space_vector(v_k)) { diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index e5db201a86a..06ba38b4a69 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -34,8 +34,7 @@ std::ostream& operator<<(std::ostream& out, opt::ineq_type ie) { namespace opt { - model_based_opt::model_based_opt(): - m_objective_id(0) + model_based_opt::model_based_opt() { m_rows.push_back(row()); } @@ -448,5 +447,132 @@ namespace opt { set_row(m_objective_id, coeffs, c, t_le); } + void model_based_opt::get_live_rows(vector& rows) { + for (unsigned i = 0; i < m_rows.size(); ++i) { + if (m_rows[i].m_alive) { + rows.push_back(m_rows[i]); + } + } + } + + // + // pick glb and lub representative. + // The representative is picked such that it + // represents the fewest inequalities. + // The constraints that enforce a glb or lub are not forced. + // The constraints that separate the glb from ub or the lub from lb + // are not forced. + // In other words, suppose there are + // . N inequalities of the form t <= x + // . M inequalities of the form s >= x + // . t0 is glb among N under valuation. + // . s0 is lub among M under valuation. + // If N < M + // create the inequalities: + // t <= t0 for each t other than t0 (N-1 inequalities). + // t0 <= s for each s (M inequalities). + // If N >= M the construction is symmetric. + // + void model_based_opt::project(unsigned x) { + unsigned_vector& lub_rows = m_lub; + unsigned_vector& glb_rows = m_glb; + unsigned lub_index = UINT_MAX, glb_index = UINT_MAX; + bool lub_strict = false, glb_strict = false; + rational lub_val, glb_val; + rational const& x_val = m_var2value[x]; + unsigned_vector const& row_ids = m_var2row_ids[x]; + uint_set visited; + lub_rows.reset(); + glb_rows.reset(); + // select the lub and glb. + for (unsigned i = 0; i < row_ids.size(); ++i) { + unsigned row_id = row_ids[i]; + if (visited.contains(row_id)) { + continue; + } + visited.insert(row_id); + row& r = m_rows[row_id]; + if (!r.m_alive) { + continue; + } + rational a = get_coefficient(row_id, x); + if (a.is_zero()) { + continue; + } + if (r.m_type == t_eq) { + solve_for(row_id, x); + return; + } + if (a.is_pos()) { + rational lub_value = x_val - (r.m_value/a); + if (lub_rows.empty() || + lub_value < lub_val || + (lub_value == lub_val && r.m_type == t_lt && !lub_strict)) { + lub_val = lub_value; + lub_index = row_id; + lub_strict = r.m_type == t_lt; + } + lub_rows.push_back(row_id); + } + else { + SASSERT(a.is_neg()); + rational glb_value = x_val - (r.m_value/a); + if (glb_rows.empty() || + glb_value > glb_val || + (glb_value == glb_val && r.m_type == t_lt && !glb_strict)) { + glb_val = glb_value; + glb_index = row_id; + glb_strict = r.m_type == t_lt; + } + glb_rows.push_back(row_id); + } + } + unsigned row_index = (lub_rows.size() <= glb_rows.size())? lub_index : glb_index; + glb_rows.append(lub_rows); + if (row_index == UINT_MAX) { + for (unsigned i = 0; i < glb_rows.size(); ++i) { + unsigned row_id = glb_rows[i]; + SASSERT(m_rows[row_id].m_alive); + SASSERT(!get_coefficient(row_id, x).is_zero()); + m_rows[row_id].m_alive = false; + } + } + else { + rational coeff = get_coefficient(row_index, x); + for (unsigned i = 0; i < glb_rows.size(); ++i) { + unsigned row_id = glb_rows[i]; + if (row_id != row_index) { + resolve(row_index, coeff, row_id, x); + } + } + m_rows[row_index].m_alive = false; + } + } + + void model_based_opt::solve_for(unsigned row_id1, unsigned x) { + rational a = get_coefficient(row_id1, x); + row& r1 = m_rows[row_id1]; + SASSERT(!a.is_zero()); + SASSERT(r1.m_type == t_eq); + SASSERT(r1.m_alive); + unsigned_vector const& row_ids = m_var2row_ids[x]; + uint_set visited; + visited.insert(row_id1); + for (unsigned i = 0; i < row_ids.size(); ++i) { + unsigned row_id2 = row_ids[i]; + if (!visited.contains(row_id2)) { + visited.insert(row_id2); + resolve(row_id1, a, row_id2, x); + } + } + r1.m_alive = false; + } + + void model_based_opt::project(unsigned num_vars, unsigned const* vars) { + for (unsigned i = 0; i < num_vars; ++i) { + project(vars[i]); + } + } + } diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index b48a96edbb0..e4ba288c88d 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -48,7 +48,6 @@ namespace opt { } }; }; - private: struct row { row(): m_type(t_le), m_value(0), m_alive(false) {} vector m_vars; // variables with coefficients @@ -58,11 +57,14 @@ namespace opt { bool m_alive; // rows can be marked dead if they have been processed. }; + private: + vector m_rows; - unsigned m_objective_id; + static const unsigned m_objective_id = 0; vector m_var2row_ids; vector m_var2value; vector m_new_vars; + unsigned_vector m_lub, m_glb; bool invariant(); bool invariant(unsigned index, row const& r); @@ -81,6 +83,10 @@ namespace opt { void update_values(unsigned_vector const& bound_vars, unsigned_vector const& bound_trail); + void project(unsigned var); + + void solve_for(unsigned row_id, unsigned x); + public: model_based_opt(); @@ -106,6 +112,17 @@ namespace opt { // inf_eps maximize(); + + // + // Project set of variables from inequalities. + // + void project(unsigned num_vars, unsigned const* vars); + + // + // Extract current rows (after projection). + // + void get_live_rows(vector& rows); + void display(std::ostream& out) const; void display(std::ostream& out, row const& r) const; diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index 6ca4048ad87..cb86e2a8516 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -998,6 +998,7 @@ namespace simplex { template bool simplex::well_formed_row(row const& r) const { var_t s = m_row2base[r.id()]; + (void)s; SASSERT(m_vars[s].m_base2row == r.id()); SASSERT(m_vars[s].m_is_base); // SASSERT(m.is_neg(m_vars[s].m_base_coeff)); diff --git a/src/math/simplex/sparse_matrix_def.h b/src/math/simplex/sparse_matrix_def.h index 09a8a922503..b050e45e1bf 100644 --- a/src/math/simplex/sparse_matrix_def.h +++ b/src/math/simplex/sparse_matrix_def.h @@ -509,12 +509,13 @@ namespace simplex { dead.insert(i); continue; } - SASSERT(!vars.contains(e.m_var)); - SASSERT(!m.is_zero(e.m_coeff)); - SASSERT(e.m_var != dead_id); - col_entry const& c = m_columns[e.m_var].m_entries[e.m_col_idx]; - SASSERT((unsigned)c.m_row_id == row_id); - SASSERT((unsigned)c.m_row_idx == i); + DEBUG_CODE( + SASSERT(!vars.contains(e.m_var)); + SASSERT(!m.is_zero(e.m_coeff)); + SASSERT(e.m_var != dead_id); + col_entry const& c = m_columns[e.m_var].m_entries[e.m_col_idx]; + SASSERT((unsigned)c.m_row_id == row_id); + SASSERT((unsigned)c.m_row_idx == i);); vars.insert(e.m_var); } int idx = r.m_first_free_idx; @@ -541,10 +542,11 @@ namespace simplex { continue; } SASSERT(!rows.contains(c.m_row_id)); - _row const& row = m_rows[c.m_row_id]; - _row_entry const& r = row.m_entries[c.m_row_idx]; - SASSERT(r.m_var == v); - SASSERT((unsigned)r.m_col_idx == i); + DEBUG_CODE( + _row const& row = m_rows[c.m_row_id]; + _row_entry const& r = row.m_entries[c.m_row_idx]; + SASSERT(r.m_var == v); + SASSERT((unsigned)r.m_col_idx == i);); rows.insert(c.m_row_id); } int idx = col.m_first_free_idx; diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index e67e3cb5ecf..74f6a18c1a4 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -114,7 +114,8 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { result_pr = 0; family_id fid = f->get_family_id(); - if (num == 0 && (fid == null_family_id || m().get_plugin(f->get_family_id())->is_considered_uninterpreted(f))) { + bool is_uninterp = fid != null_family_id && m().get_plugin(fid)->is_considered_uninterpreted(f); + if (num == 0 && (fid == null_family_id || is_uninterp)) { expr * val = m_model.get_const_interp(f); if (val != 0) { result = val; @@ -150,7 +151,7 @@ struct evaluator_cfg : public default_rewriter_cfg { st = m_f_rw.mk_eq_core(args[0], args[1], result); else if (s_fid == m_seq_rw.get_fid()) st = m_seq_rw.mk_eq_core(args[0], args[1], result); - else if (fid == m_ar_rw.get_fid()) + else if (s_fid == m_ar_rw.get_fid()) st = mk_array_eq(args[0], args[1], result); if (st != BR_FAILED) return st; @@ -258,6 +259,8 @@ struct evaluator_cfg : public default_rewriter_cfg { br_status mk_array_eq(expr* a, expr* b, expr_ref& result) { + return BR_FAILED; + // disabled until made more efficient if (a == b) { result = m().mk_true(); return BR_DONE; @@ -270,6 +273,7 @@ struct evaluator_cfg : public default_rewriter_cfg { conj.push_back(m().mk_eq(else1, else2)); args1.push_back(a); args2.push_back(b); + // TBD: this is too inefficient. for (unsigned i = 0; i < stores.size(); ++i) { args1.resize(1); args1.append(stores[i].size() - 1, stores[i].c_ptr()); args2.resize(1); args2.append(stores[i].size() - 1, stores[i].c_ptr()); @@ -361,6 +365,7 @@ struct model_evaluator::imp : public rewriter_tpl { false, // no proofs for evaluator m_cfg), m_cfg(md.get_manager(), md, p) { + set_cancel_check(false); } }; diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 74c909c02cf..a90d420cb7b 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -188,9 +188,8 @@ 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() && get_engine() != DUALITY_ENGINE) { + throw default_exception("pop operation is only supported by duality engine"); } m_trail.pop_scope(1); } diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 2a6ff04d4cd..049c34343c0 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -219,9 +219,17 @@ class dl_query_cmd : public parametric_cmd { virtual void set_next_arg(cmd_context & ctx, func_decl* t) { m_target = t; + if (t->get_family_id() != null_family_id) { + throw cmd_exception("Invalid query argument, expected uinterpreted function name, but argument is interpreted"); + } + datalog::context& dlctx = m_dl_ctx->dlctx(); + if (!dlctx.get_predicates().contains(t)) { + throw cmd_exception("Invalid query argument, expected a predicate registered as a relation"); + } } virtual void prepare(cmd_context & ctx) { + ctx.m(); // ensure manager is initialized. parametric_cmd::prepare(ctx); m_target = 0; } @@ -292,6 +300,7 @@ class dl_query_cmd : public parametric_cmd { break; case datalog::OK: + (void)query_exn; SASSERT(query_exn); break; @@ -383,6 +392,7 @@ class dl_declare_rel_cmd : public cmd { virtual unsigned get_arity() const { return VAR_ARITY; } virtual void prepare(cmd_context & ctx) { + ctx.m(); // ensure manager is initialized. m_arg_idx = 0; m_query_arg_idx = 0; m_domain = 0; @@ -443,6 +453,7 @@ class dl_declare_var_cmd : public cmd { virtual unsigned get_arity() const { return 2; } virtual void prepare(cmd_context & ctx) { + ctx.m(); // ensure manager is initialized. m_arg_idx = 0; } virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 0565cb23bd1..54d9ada89df 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -923,6 +923,7 @@ namespace pdr { if (p->get_decl_kind() == PR_ASSERTED && bs.contains(m.get_fact(p))) { expr* fact = m.get_fact(p); + (void)p0; TRACE("farkas_learner", tout << mk_ll_pp(p0,m) << "\n"; tout << "Add: " << mk_pp(p,m) << "\n";); diff --git a/src/muz/rel/dl_external_relation.cpp b/src/muz/rel/dl_external_relation.cpp index f3250947345..e9c24abd34d 100644 --- a/src/muz/rel/dl_external_relation.cpp +++ b/src/muz/rel/dl_external_relation.cpp @@ -338,9 +338,8 @@ namespace datalog { : m_plugin(p), m_condition(condition, p.get_ast_manager()), m_filter_fn(p.get_ast_manager()) { - ast_manager& m = p.get_ast_manager(); p.mk_filter_fn(relation_sort, condition, m_filter_fn); - SASSERT(m.is_bool(condition)); + SASSERT(p.get_ast_manager().is_bool(condition)); } virtual void operator()(relation_base & r) { diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp index 86fef433b9c..879e2969981 100644 --- a/src/muz/rel/dl_finite_product_relation.cpp +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -1566,13 +1566,12 @@ namespace datalog { return; } - finite_product_relation_plugin & plugin = r.get_plugin(); - if(!m_neg_intersection_join) { - } scoped_rel intersection = get((*m_neg_intersection_join)(r, neg)); - SASSERT(&intersection->get_plugin()==&plugin); //the result of join is also finite product - SASSERT(r.get_signature()==intersection->get_signature()); + DEBUG_CODE( + finite_product_relation_plugin & plugin = r.get_plugin(); + SASSERT(&intersection->get_plugin()==&plugin); //the result of join is also finite product + SASSERT(r.get_signature()==intersection->get_signature());); table_base & r_table = r.get_table(); table_plugin & tplugin = r_table.get_plugin(); relation_manager & rmgr = r.get_manager(); diff --git a/src/muz/rel/karr_relation.cpp b/src/muz/rel/karr_relation.cpp index 3b9198dc640..0baa297bc31 100644 --- a/src/muz/rel/karr_relation.cpp +++ b/src/muz/rel/karr_relation.cpp @@ -173,6 +173,7 @@ namespace datalog { else { processed = false; } + (void)processed; TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n"; if (processed) matrix::display_ineq(tout, row, M.b.back(), M.eq.back()); ); diff --git a/src/muz/rel/udoc_relation.cpp b/src/muz/rel/udoc_relation.cpp index dda674131ee..22e70a3676e 100644 --- a/src/muz/rel/udoc_relation.cpp +++ b/src/muz/rel/udoc_relation.cpp @@ -404,7 +404,7 @@ namespace datalog { rename_fn(udoc_relation const& t, unsigned cycle_len, const unsigned * cycle) : convenient_relation_rename_fn(t.get_signature(), cycle_len, cycle) { udoc_plugin& p = t.get_plugin(); - ast_manager& m = p.get_ast_manager(); + relation_signature const& sig1 = t.get_signature(); relation_signature const& sig2 = get_result_signature(); unsigned_vector permutation0, column_info; @@ -429,6 +429,7 @@ namespace datalog { SASSERT(column == t.get_num_bits()); TRACE("doc", + ast_manager& m = p.get_ast_manager(); sig1.output(m, tout << "sig1: "); tout << "\n"; sig2.output(m, tout << "sig2: "); tout << "\n"; tout << "permute: "; diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 6d1225641ab..98172f0413b 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -70,13 +70,12 @@ namespace datalog { func_interp* f = model->get_func_interp(p); if (!f) continue; expr_ref body(m); - unsigned arity_p = p->get_arity(); unsigned arity_q = q->get_arity(); TRACE("dl", model_v2_pp(tout, *model); tout << mk_pp(p, m) << "\n"; tout << mk_pp(q, m) << "\n";); - SASSERT(0 < arity_p); + SASSERT(0 < p->get_arity()); SASSERT(f); model->register_decl(p, f->copy()); func_interp* g = alloc(func_interp, m, arity_q); diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index 57948a2ff76..caff79d2ee7 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -71,9 +71,8 @@ namespace datalog { svector const& is_bound = m_bound[i]; func_interp* f = old_model->get_func_interp(p); expr_ref body(m); - unsigned arity_p = p->get_arity(); unsigned arity_q = q->get_arity(); - SASSERT(0 < arity_p); + SASSERT(0 < p->get_arity()); func_interp* g = alloc(func_interp, m, arity_q); if (f) { @@ -98,7 +97,7 @@ namespace datalog { TRACE("dl", tout << mk_pp(body, m) << "\n";); // 2. replace bound variables by constants. - expr_ref_vector consts(m), bound(m), free(m); + expr_ref_vector consts(m), bound(m), _free(m); svector names; ptr_vector bound_sorts; for (unsigned i = 0; i < sorts.size(); ++i) { @@ -111,7 +110,7 @@ namespace datalog { bound_sorts.push_back(s); } else { - free.push_back(consts.back()); + _free.push_back(consts.back()); } } rep(body); @@ -124,8 +123,8 @@ namespace datalog { TRACE("dl", tout << mk_pp(body, m) << "\n";); // 4. replace remaining constants by variables. - for (unsigned i = 0; i < free.size(); ++i) { - rep.insert(free[i].get(), m.mk_var(i, m.get_sort(free[i].get()))); + for (unsigned i = 0; i < _free.size(); ++i) { + rep.insert(_free[i].get(), m.mk_var(i, m.get_sort(_free[i].get()))); } rep(body); g->set_else(body); diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index 23480eed4ab..92a80375eb5 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -1165,8 +1165,7 @@ namespace nlsat { if (max_var(new_lit) < max) { // The conflicting core may have redundant literals. // We should check whether new_lit is true in the current model, and discard it if that is the case - lbool val = m_solver.value(new_lit); - SASSERT(val != l_undef); + VERIFY(m_solver.value(new_lit) != l_undef); if (m_solver.value(new_lit) == l_false) add_literal(new_lit); new_lit = true_literal; diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index 68609cb3fef..44e1128d14d 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -102,14 +102,14 @@ namespace nlsat { // Check if the intervals are valid, ordered, and are disjoint. bool check_interval_set(anum_manager & am, unsigned sz, interval const * ints) { - for (unsigned i = 0; i < sz; i++) { - interval const & curr = ints[i]; - SASSERT(check_interval(am, curr)); - if (i < sz - 1) { - interval const & next = ints[i+1]; - SASSERT(check_no_overlap(am, curr, next)); - } - } + DEBUG_CODE( + for (unsigned i = 0; i < sz; i++) { + interval const & curr = ints[i]; + SASSERT(check_interval(am, curr)); + if (i < sz - 1) { + SASSERT(check_no_overlap(am, curr, ints[i+1])); + } + }); return true; } diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index ae3f1252b19..4f9854d8776 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -1728,27 +1728,28 @@ namespace nlsat { // ----------------------- bool check_watches() const { - for (var x = 0; x < num_vars(); x++) { - clause_vector const & cs = m_watches[x]; - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause const & c = *(cs[i]); - SASSERT(max_var(c) == x); - } - } + DEBUG_CODE( + for (var x = 0; x < num_vars(); x++) { + clause_vector const & cs = m_watches[x]; + unsigned sz = cs.size(); + for (unsigned i = 0; i < sz; i++) { + SASSERT(max_var(*(cs[i])) == x); + } + }); return true; } bool check_bwatches() const { - for (bool_var b = 0; b < m_bwatches.size(); b++) { - clause_vector const & cs = m_bwatches[b]; - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause const & c = *(cs[i]); - SASSERT(max_var(c) == null_var); - SASSERT(max_bvar(c) == b); - } - } + DEBUG_CODE( + for (bool_var b = 0; b < m_bwatches.size(); b++) { + clause_vector const & cs = m_bwatches[b]; + unsigned sz = cs.size(); + for (unsigned i = 0; i < sz; i++) { + clause const & c = *(cs[i]); + SASSERT(max_var(c) == null_var); + SASSERT(max_bvar(c) == b); + } + }); return true; } diff --git a/src/opt/hitting_sets.cpp b/src/opt/hitting_sets.cpp index 8bbad6683a9..678d7924e1d 100644 --- a/src/opt/hitting_sets.cpp +++ b/src/opt/hitting_sets.cpp @@ -762,6 +762,7 @@ namespace opt { } bool invariant() { + DEBUG_CODE( for (unsigned i = 0; i < m_fwatch.size(); ++i) { for (unsigned j = 0; j < m_fwatch[i].size(); ++j) { set const& S = *m_F[m_fwatch[i][j]]; @@ -773,7 +774,7 @@ namespace opt { set const& S = *m_T[m_twatch[i][j]]; SASSERT(S[0] == i || S[1] == i); } - } + }); return true; } diff --git a/src/opt/opt_cmds.cpp b/src/opt/opt_cmds.cpp index f5d98e498ba..8822f4e77ba 100644 --- a/src/opt/opt_cmds.cpp +++ b/src/opt/opt_cmds.cpp @@ -137,74 +137,12 @@ class min_maximize_cmd : public cmd { } }; -class alternate_min_max_cmd : public cmd { - app_ref_vector* m_vars; - svector m_is_max; - unsigned m_position; -public: - alternate_min_max_cmd(): - cmd("min-max"), - m_vars(0), - m_position(0) - {} - - virtual void reset(cmd_context & ctx) { - dealloc(m_vars); - m_is_max.reset(); - m_position = 0; - } - virtual char const * get_usage() const { return "(min | max | var)+ "; } - virtual char const * get_descr(cmd_context & ctx) const { return "check sat modulo alternating min-max objectives";} - virtual unsigned get_arity() const { return 2; } - virtual void prepare(cmd_context & ctx) {} - virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { - switch (m_position) { - case 0: return CPK_SYMBOL_LIST; - case 1: return CPK_EXPR; - default: return CPK_SYMBOL; - } - } - - virtual void set_next_arg(cmd_context & ctx, unsigned num, symbol const * slist) { - bool is_max = false; - for (unsigned i = 0; i < num; ++i) { - if (slist[i] == symbol("max")) { - is_max = true; - } - else if (slist[i] == symbol("min")) { - is_max = false; - } - else { - m_is_max.push_back(is_max); - if (!m_vars) m_vars = alloc(app_ref_vector, ctx.m()); - m_vars->push_back(ctx.m().mk_const(ctx.find_func_decl(slist[i]))); - } - } - ++m_position; - } - - virtual void set_next_arg(cmd_context & ctx, expr * t) { - if (!is_app(t)) { - throw cmd_exception("malformed objective term: it cannot be a quantifier or bound variable"); - } - ++m_position; - if (!m_vars) m_vars = alloc(app_ref_vector, ctx.m()); - get_opt(ctx).min_max(to_app(t), *m_vars, m_is_max); - } - - virtual void failure_cleanup(cmd_context & ctx) { - reset(ctx); - } - - virtual void execute(cmd_context & ctx) { } -}; void install_opt_cmds(cmd_context & ctx) { ctx.insert(alloc(assert_soft_cmd)); ctx.insert(alloc(min_maximize_cmd, true)); ctx.insert(alloc(min_maximize_cmd, false)); - ctx.insert(alloc(alternate_min_max_cmd)); } diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 4d65b9a2503..0b71fff1c9d 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -212,20 +212,6 @@ namespace opt { m_hard_constraints.append(s.m_hard); } - lbool context::min_max(app* t, app_ref_vector const& vars, svector const& is_max) { - clear_state(); - init_solver(); - import_scoped_state(); - normalize(); - internalize(); - update_solver(); - solver& s = get_solver(); - s.assert_expr(m_hard_constraints); - std::cout << "min-max is TBD\n"; - return l_undef; - } - - lbool context::optimize() { if (m_pareto) { return execute_pareto(); @@ -238,12 +224,12 @@ namespace opt { import_scoped_state(); normalize(); internalize(); + update_solver(); #if 0 if (is_qsat_opt()) { return run_qsat_opt(); } #endif - update_solver(); solver& s = get_solver(); s.assert_expr(m_hard_constraints); display_benchmark(); @@ -1314,6 +1300,9 @@ namespace opt { } get_memory_statistics(stats); get_rlimit_statistics(m.limit(), stats); + if (m_qmax) { + m_qmax->collect_statistics(stats); + } } void context::collect_param_descrs(param_descrs & r) { @@ -1454,6 +1443,9 @@ namespace opt { m_objectives[0].m_type != O_MINIMIZE) { return false; } + if (!m_arith.is_real(m_objectives[0].m_term)) { + return false; + } for (unsigned i = 0; i < m_hard_constraints.size(); ++i) { if (has_quantifiers(m_hard_constraints[i].get())) { return true; @@ -1470,11 +1462,21 @@ namespace opt { term = m_arith.mk_uminus(term); } inf_eps value; - lbool result = qe::maximize(m_hard_constraints, term, value, m_model, m_params); + m_qmax = alloc(qe::qmax, m, m_params); + lbool result = (*m_qmax)(m_hard_constraints, term, value, m_model); if (result != l_undef && obj.m_type == O_MINIMIZE) { value.neg(); } - if (result != l_undef) { + m_optsmt.setup(*m_opt_solver.get()); + if (result == l_undef) { + if (obj.m_type == O_MINIMIZE) { + m_optsmt.update_upper(obj.m_index, value); + } + else { + m_optsmt.update_lower(obj.m_index, value); + } + } + else { m_optsmt.update_lower(obj.m_index, value); m_optsmt.update_upper(obj.m_index, value); } diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index b7dceb67448..07fe5326832 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -28,7 +28,7 @@ Module Name: #include "arith_decl_plugin.h" #include "bv_decl_plugin.h" #include "cmd_context.h" - +#include "qsat.h" namespace opt { @@ -145,6 +145,7 @@ namespace opt { ref m_solver; ref m_sat_solver; scoped_ptr m_pareto; + scoped_ptr m_qmax; sref_vector m_box_models; unsigned m_box_index; params_ref m_params; @@ -172,7 +173,6 @@ namespace opt { virtual ~context(); unsigned add_soft_constraint(expr* f, rational const& w, symbol const& id); unsigned add_objective(app* t, bool is_max); - lbool min_max(app* t, app_ref_vector const& vars, svector const& is_max); void add_hard_constraint(expr* f); diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index eff70e48e65..fccc7fa1c5d 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -344,6 +344,10 @@ namespace opt { } expr_ref opt_solver::mk_ge(unsigned var, inf_eps const& val) { + if (!val.is_finite()) + { + return expr_ref(val.is_pos() ? m.mk_false() : m.mk_true(), m); + } smt::theory_opt& opt = get_optimizer(); smt::theory_var v = m_objective_vars[var]; diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index e92ab4f97ba..d2363b36e72 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -34,6 +34,7 @@ Module Name: #include "arith_decl_plugin.h" #include "theory_arith.h" #include "ast_pp.h" +#include "ast_util.h" #include "model_pp.h" #include "th_rewriter.h" #include "opt_params.hpp" @@ -93,6 +94,158 @@ namespace opt { return l_true; } + /* + Enumerate locally optimal assignments until fixedpoint. + */ + lbool optsmt::geometric_opt() { + lbool is_sat = l_true; + + expr_ref bound(m); + + vector lower(m_lower); + unsigned steps = 0; + unsigned step_incs = 0; + rational delta_per_step(1); + unsigned num_scopes = 0; + unsigned delta_index = 0; // index of objective to speed up. + + while (!m.canceled()) { + SASSERT(delta_per_step.is_int()); + SASSERT(delta_per_step.is_pos()); + is_sat = m_s->check_sat(0, 0); + if (is_sat == l_true) { + bound = update_lower(); + if (!get_max_delta(lower, delta_index)) { + delta_per_step = rational::one(); + } + else if (steps > step_incs) { + delta_per_step *= rational(2); + ++step_incs; + steps = 0; + } + else { + ++steps; + } + if (delta_per_step > rational::one()) { + m_s->push(); + ++num_scopes; + // only try to improve delta_index. + bound = m_s->mk_ge(delta_index, m_lower[delta_index] + inf_eps(delta_per_step)); + } + TRACE("opt", tout << delta_per_step << " " << bound << "\n";); + m_s->assert_expr(bound); + } + else if (is_sat == l_false && delta_per_step > rational::one()) { + steps = 0; + step_incs = 0; + delta_per_step = rational::one(); + SASSERT(num_scopes > 0); + --num_scopes; + m_s->pop(1); + } + else { + break; + } + } + m_s->pop(num_scopes); + + if (m.canceled() || is_sat == l_undef) { + return l_undef; + } + + // set the solution tight. + for (unsigned i = 0; i < m_lower.size(); ++i) { + m_upper[i] = m_lower[i]; + } + + return l_true; + } + + + lbool optsmt::geometric_lex(unsigned obj_index, bool is_maximize) { + arith_util arith(m); + bool is_int = arith.is_int(m_objs[obj_index].get()); + lbool is_sat = l_true; + expr_ref bound(m); + + for (unsigned i = 0; i < obj_index; ++i) { + commit_assignment(i); + } + + unsigned steps = 0; + unsigned step_incs = 0; + rational delta_per_step(1); + unsigned num_scopes = 0; + + while (!m.canceled()) { + SASSERT(delta_per_step.is_int()); + SASSERT(delta_per_step.is_pos()); + is_sat = m_s->check_sat(0, 0); + if (is_sat == l_true) { + m_s->maximize_objective(obj_index, bound); + m_s->get_model(m_model); + m_s->get_labels(m_labels); + inf_eps obj = m_s->saved_objective_value(obj_index); + update_lower_lex(obj_index, obj, is_maximize); + if (!is_int || !m_lower[obj_index].is_finite()) { + delta_per_step = rational(1); + } + else if (steps > step_incs) { + delta_per_step *= rational(2); + ++step_incs; + steps = 0; + } + else { + ++steps; + } + if (delta_per_step > rational::one()) { + m_s->push(); + ++num_scopes; + bound = m_s->mk_ge(obj_index, obj + inf_eps(delta_per_step)); + } + TRACE("opt", tout << delta_per_step << " " << bound << "\n";); + m_s->assert_expr(bound); + } + else if (is_sat == l_false && delta_per_step > rational::one()) { + steps = 0; + step_incs = 0; + delta_per_step = rational::one(); + SASSERT(num_scopes > 0); + --num_scopes; + m_s->pop(1); + } + else { + break; + } + } + m_s->pop(num_scopes); + + if (m.canceled() || is_sat == l_undef) { + return l_undef; + } + + // set the solution tight. + m_upper[obj_index] = m_lower[obj_index]; + for (unsigned i = obj_index+1; i < m_lower.size(); ++i) { + m_lower[i] = inf_eps(rational(-1), inf_rational(0)); + } + return l_true; + } + + bool optsmt::get_max_delta(vector const& lower, unsigned& idx) { + arith_util arith(m); + inf_eps max_delta; + for (unsigned i = 0; i < m_lower.size(); ++i) { + if (arith.is_int(m_objs[i].get())) { + inf_eps delta = m_lower[i] - lower[i]; + if (m_lower[i].is_finite() && delta > max_delta) { + max_delta = delta; + } + } + } + return max_delta.is_pos(); + } + /* Enumerate locally optimal assignments until fixedpoint. */ @@ -122,6 +275,7 @@ namespace opt { } lbool optsmt::symba_opt() { + smt::theory_opt& opt = m_s->get_optimizer(); if (typeid(smt::theory_inf_arith) != typeid(opt)) { @@ -138,7 +292,7 @@ namespace opt { } - fml = m.mk_or(ors.size(), ors.c_ptr()); + fml = mk_or(ors); tmp = m.mk_fresh_const("b", m.mk_bool_sort()); fml = m.mk_implies(tmp, fml); vars[0] = tmp; @@ -163,7 +317,7 @@ namespace opt { } } set_max(m_lower, m_s->get_objective_values(), disj); - fml = m.mk_or(ors.size(), ors.c_ptr()); + fml = mk_or(ors); tmp = m.mk_fresh_const("b", m.mk_bool_sort()); fml = m.mk_implies(tmp, fml); vars[0] = tmp; @@ -176,13 +330,30 @@ namespace opt { } } } - bound = m.mk_or(m_lower_fmls.size(), m_lower_fmls.c_ptr()); + bound = mk_or(m_lower_fmls); m_s->assert_expr(bound); if (m.canceled()) { return l_undef; } - return basic_opt(); + return geometric_opt(); + } + + void optsmt::update_lower_lex(unsigned idx, inf_eps const& v, bool is_maximize) { + if (v > m_lower[idx]) { + m_lower[idx] = v; + IF_VERBOSE(1, + if (is_maximize) + verbose_stream() << "(optsmt lower bound: " << v << ")\n"; + else + verbose_stream() << "(optsmt upper bound: " << (-v) << ")\n"; + ); + expr_ref tmp(m); + for (unsigned i = idx+1; i < m_vars.size(); ++i) { + m_s->maximize_objective(i, tmp); + m_lower[i] = m_s->saved_objective_value(i); + } + } } void optsmt::update_lower(unsigned idx, inf_eps const& v) { @@ -196,28 +367,22 @@ namespace opt { m_upper[idx] = v; } + std::ostream& operator<<(std::ostream& out, vector const& vs) { + for (unsigned i = 0; i < vs.size(); ++i) { + out << vs[i] << " "; + } + return out; + } + expr_ref optsmt::update_lower() { expr_ref_vector disj(m); m_s->get_model(m_model); m_s->get_labels(m_labels); m_s->maximize_objectives(disj); set_max(m_lower, m_s->get_objective_values(), disj); - TRACE("opt", - for (unsigned i = 0; i < m_lower.size(); ++i) { - tout << m_lower[i] << " "; - } - tout << "\n"; - model_pp(tout, *m_model); - ); - IF_VERBOSE(2, verbose_stream() << "(optsmt.lower "; - for (unsigned i = 0; i < m_lower.size(); ++i) { - verbose_stream() << m_lower[i] << " "; - } - verbose_stream() << ")\n";); - IF_VERBOSE(3, verbose_stream() << disj << "\n";); - IF_VERBOSE(3, model_pp(verbose_stream(), *m_model);); - - return expr_ref(m.mk_or(disj.size(), disj.c_ptr()), m); + TRACE("opt", model_pp(tout << m_lower << "\n", *m_model);); + IF_VERBOSE(2, verbose_stream() << "(optsmt.lower " << m_lower << ")\n";); + return mk_or(disj); } lbool optsmt::update_upper() { @@ -312,12 +477,21 @@ namespace opt { TRACE("opt", tout << "optsmt:lex\n";); solver::scoped_push _push(*m_s); SASSERT(obj_index < m_vars.size()); - return basic_lex(obj_index, is_maximize); + if (is_maximize && m_optsmt_engine == symbol("farkas")) { + return farkas_opt(); + } + else if (is_maximize && m_optsmt_engine == symbol("symba")) { + return symba_opt(); + } + else { + return geometric_lex(obj_index, is_maximize); + } } + // deprecated lbool optsmt::basic_lex(unsigned obj_index, bool is_maximize) { lbool is_sat = l_true; - expr_ref block(m), tmp(m); + expr_ref bound(m); for (unsigned i = 0; i < obj_index; ++i) { commit_assignment(i); @@ -326,25 +500,13 @@ namespace opt { is_sat = m_s->check_sat(0, 0); if (is_sat != l_true) break; - m_s->maximize_objective(obj_index, block); + m_s->maximize_objective(obj_index, bound); m_s->get_model(m_model); m_s->get_labels(m_labels); inf_eps obj = m_s->saved_objective_value(obj_index); - if (obj > m_lower[obj_index]) { - m_lower[obj_index] = obj; - IF_VERBOSE(1, - if (is_maximize) - verbose_stream() << "(optsmt lower bound: " << obj << ")\n"; - else - verbose_stream() << "(optsmt upper bound: " << (-obj) << ")\n"; - ); - for (unsigned i = obj_index+1; i < m_vars.size(); ++i) { - m_s->maximize_objective(i, tmp); - m_lower[i] = m_s->saved_objective_value(i); - } - } - TRACE("opt", tout << "strengthen bound: " << block << "\n";); - m_s->assert_expr(block); + update_lower_lex(obj_index, obj, is_maximize); + TRACE("opt", tout << "strengthen bound: " << bound << "\n";); + m_s->assert_expr(bound); // TBD: only works for simplex // blocking formula should be extracted based @@ -365,6 +527,7 @@ namespace opt { } + /** Takes solver with hard constraints added. Returns an optimal assignment to objective functions. @@ -383,7 +546,7 @@ namespace opt { is_sat = symba_opt(); } else { - is_sat = basic_opt(); + is_sat = geometric_opt(); } return is_sat; } diff --git a/src/opt/optsmt.h b/src/opt/optsmt.h index e01c586817e..f90bd1c8189 100644 --- a/src/opt/optsmt.h +++ b/src/opt/optsmt.h @@ -69,19 +69,28 @@ namespace opt { void reset(); private: + + bool get_max_delta(vector const& lower, unsigned& idx); lbool basic_opt(); + lbool geometric_opt(); + lbool symba_opt(); lbool basic_lex(unsigned idx, bool is_maximize); + lbool geometric_lex(unsigned idx, bool is_maximize); + lbool farkas_opt(); void set_max(vector& dst, vector const& src, expr_ref_vector& fmls); expr_ref update_lower(); + void update_lower_lex(unsigned idx, inf_eps const& r, bool is_maximize); + + lbool update_upper(); diff --git a/src/parsers/smt/smtparser.cpp b/src/parsers/smt/smtparser.cpp index d2619054198..f50e8b33962 100644 --- a/src/parsers/smt/smtparser.cpp +++ b/src/parsers/smt/smtparser.cpp @@ -1574,7 +1574,7 @@ class smtparser : public parser { } } expr * p = m_manager.mk_pattern(ts.size(), (app*const*)(ts.c_ptr())); - if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p))) { + if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p, children[0]->line(), children[0]->pos()))) { set_error("invalid pattern", children[0]); return false; } @@ -1583,7 +1583,7 @@ class smtparser : public parser { else if (children[0]->string() == symbol("ex_act") && ts.size() == 1) { app * sk_hack = m_manager.mk_app(m_sk_hack, 1, ts.c_ptr()); expr * p = m_manager.mk_pattern(1, &sk_hack); - if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p))) { + if (!p || (!ignore_user_patterns() && !m_pattern_validator(num_bindings, p, children[0]->line(), children[0]->pos()))) { set_error("invalid pattern", children[0]); return false; } diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 2e98a4072eb..17a931cc3ae 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -473,6 +473,7 @@ namespace smt2 { void parse_sexpr() { unsigned stack_pos = sexpr_stack().size(); + (void)stack_pos; unsigned num_frames = 0; do { unsigned line = m_scanner.get_line(); @@ -631,6 +632,7 @@ namespace smt2 { void parse_psort() { unsigned stack_pos = psort_stack().size(); + (void)stack_pos; unsigned num_frames = 0; do { if (curr_is_identifier()) { @@ -693,6 +695,7 @@ namespace smt2 { void parse_sort(char const* context) { unsigned stack_pos = sort_stack().size(); + (void)stack_pos; unsigned num_frames = 0; do { if (curr_is_identifier()) { @@ -1605,7 +1608,7 @@ namespace smt2 { unsigned j = begin_pats; for (unsigned i = begin_pats; i < end_pats; i++) { expr * pat = pattern_stack().get(i); - if (!pat_validator()(num_decls, pat)) { + if (!pat_validator()(num_decls, pat, m_scanner.get_line(), m_scanner.get_pos())) { if (!ignore_bad_patterns()) throw parser_exception("invalid pattern"); continue; diff --git a/src/parsers/util/pattern_validation.cpp b/src/parsers/util/pattern_validation.cpp index 3d59c221304..0e90e81269b 100644 --- a/src/parsers/util/pattern_validation.cpp +++ b/src/parsers/util/pattern_validation.cpp @@ -31,16 +31,19 @@ struct pattern_validation_functor { bool m_found_a_var; family_id m_bfid; family_id m_lfid; + unsigned m_line, m_pos; pattern_validation_functor(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, - family_id bfid, family_id lfid): + family_id bfid, family_id lfid, unsigned line, unsigned pos): m_found_vars(found_vars), m_num_bindings(num_bindings), m_num_new_bindings(num_new_bindings), m_result(true), m_found_a_var(false), m_bfid(bfid), - m_lfid(lfid) { + m_lfid(lfid), + m_line(line), + m_pos(pos) { } bool is_forbidden(func_decl const * decl) { @@ -55,7 +58,7 @@ struct pattern_validation_functor { void operator()(app * n) { func_decl * decl = to_app(n)->get_decl(); if (is_forbidden(decl)) { - warning_msg("'%s' cannot be used in patterns.", decl->get_name().str().c_str()); + warning_msg("(%d,%d): '%s' cannot be used in patterns.", m_line, m_pos, decl->get_name().str().c_str()); m_result = false; } } @@ -63,7 +66,7 @@ struct pattern_validation_functor { void operator()(var * v) { unsigned idx = to_var(v)->get_idx(); if (idx >= m_num_bindings) { - warning_msg("free variables cannot be used in patterns."); + warning_msg("(%d,%d): free variables cannot be used in patterns.", m_line, m_pos); m_result = false; return; } @@ -76,30 +79,30 @@ struct pattern_validation_functor { void operator()(quantifier * q) { m_result = false; } }; -bool pattern_validator::process(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, expr * n) { +bool pattern_validator::process(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, expr * n, unsigned line, unsigned pos) { // I'm traversing the DAG as a tree, this is not a problem since pattern are supposed to be small ASTs. if (n->get_kind() == AST_VAR) { - warning_msg("invalid pattern: variable."); + warning_msg("(%d,%d): invalid pattern: variable.", line, pos); return false; } - pattern_validation_functor f(found_vars, num_bindings, num_new_bindings, m_bfid, m_lfid); + pattern_validation_functor f(found_vars, num_bindings, num_new_bindings, m_bfid, m_lfid, line, pos); for_each_expr(f, n); if (!f.m_result) return false; if (!f.m_found_a_var) { - warning_msg("pattern does not contain any variable."); + warning_msg("(%d,%d): pattern does not contain any variable.", line, pos); return false; } return true; } -bool pattern_validator::operator()(unsigned num_bindings, unsigned num_new_bindings, expr * n) { +bool pattern_validator::operator()(unsigned num_bindings, unsigned num_new_bindings, expr * n, unsigned line, unsigned pos) { uint_set found_vars; - if (!process(found_vars, num_bindings, num_new_bindings, n)) + if (!process(found_vars, num_bindings, num_new_bindings, n, line, pos)) return false; bool r = found_vars.num_elems() == num_new_bindings; if (!r) - warning_msg("pattern does not contain all quantified variables."); + warning_msg("(%d,%d): pattern does not contain all quantified variables.", line, pos); return r; } diff --git a/src/parsers/util/pattern_validation.h b/src/parsers/util/pattern_validation.h index 6c2ad73b701..939781936d8 100644 --- a/src/parsers/util/pattern_validation.h +++ b/src/parsers/util/pattern_validation.h @@ -27,7 +27,7 @@ class pattern_validator { family_id m_bfid; family_id m_lfid; - bool process(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, expr * n); + bool process(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, expr * n, unsigned line, unsigned pos); public: pattern_validator(ast_manager const & m): @@ -35,8 +35,8 @@ class pattern_validator { m_lfid(m.get_label_family_id()) { } - bool operator()(unsigned num_bindings, unsigned num_new_bindings, expr * n); - bool operator()(unsigned num_new_bindings, expr * n) { return operator()(UINT_MAX, num_new_bindings, n); } + bool operator()(unsigned num_bindings, unsigned num_new_bindings, expr * n, unsigned line, unsigned pos); + bool operator()(unsigned num_new_bindings, expr * n, unsigned line, unsigned pos) { return operator()(UINT_MAX, num_new_bindings, n, line, pos); } }; #endif /* PATTERN_VALIDATION_H_ */ diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index e05bed9a78a..fbff2e583c9 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -435,12 +435,11 @@ namespace qe { }; class div_rewriter_cfg : public default_rewriter_cfg { - nlqsat& s; ast_manager& m; arith_util a; vector
m_divs; public: - div_rewriter_cfg(nlqsat& s): s(s), m(s.m), a(s.m) {} + div_rewriter_cfg(nlqsat& s): m(s.m), a(s.m) {} ~div_rewriter_cfg() {} br_status reduce_app(func_decl* f, unsigned sz, expr* const* args, expr_ref& result, proof_ref& pr) { if (is_decl_of(f, a.get_family_id(), OP_DIV) && sz == 2 && !a.is_numeral(args[1]) && is_ground(args[0]) && is_ground(args[1])) { diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 1df22e385f1..721e389423a 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -861,11 +861,12 @@ namespace qe { void operator()(expr_ref& fml, atom_set& pos, atom_set& neg) { expr_ref orig(fml); - ast_manager& m = fml.get_manager(); m_nnf_core(fml); m_normalize_literals(fml); m_collect_atoms(fml, pos, neg); - TRACE("qe", tout << mk_ismt2_pp(orig, m) << "\n-->\n" << mk_ismt2_pp(fml, m) << "\n";); + TRACE("qe", + ast_manager& m = fml.get_manager(); + tout << mk_ismt2_pp(orig, m) << "\n-->\n" << mk_ismt2_pp(fml, m) << "\n";); } void reset() { @@ -1899,8 +1900,7 @@ namespace qe { // The variable v is to be assigned a value in a range. // void constrain_assignment() { - expr* fml = m_current->fml(); - SASSERT(fml); + SASSERT(m_current->fml()); rational k; app* x; if (!find_min_weight(x, k)) { diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 60111a47306..38d46fefef0 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -24,11 +24,12 @@ Revision History: #include "ast_util.h" #include "arith_decl_plugin.h" #include "ast_pp.h" +#include "model_v2_pp.h" #include "th_rewriter.h" #include "expr_functors.h" -#include "model_v2_pp.h" #include "expr_safe_replace.h" #include "model_based_opt.h" +#include "model_evaluator.h" namespace qe { @@ -51,13 +52,6 @@ namespace qe { } return is_divides(a, e1, e2, k, t) || is_divides(a, e2, e1, k, t); } - - -#if 0 - obj_map m_expr2var; - ptr_vector m_var2expr; - -#endif struct arith_project_plugin::imp { @@ -70,6 +64,7 @@ namespace qe { expr_ref_vector m_div_terms; vector m_div_divisors, m_div_coeffs; expr_ref_vector m_new_lits; + expr_ref_vector m_trail; rational m_delta, m_u; scoped_ptr m_var; unsigned m_num_pos, m_num_neg; @@ -88,104 +83,130 @@ namespace qe { } } - void insert_mul(expr* x, rational const& v, obj_map& ts) - { + void insert_mul(expr* x, rational const& v, obj_map& ts) { rational w; if (ts.find(x, w)) { ts.insert(x, w + v); } else { + TRACE("qe", tout << "Adding variable " << mk_pp(x, m) << "\n";); ts.insert(x, v); } } - void linearize(model& model, opt::model_based_opt& mbo, expr* lit, obj_map& tids) { + // + // extract linear inequalities from literal 'lit' into the model-based optimization manager 'mbo'. + // It uses the current model to choose values for conditionals and it primes mbo with the current + // interpretation of sub-expressions that are treated as variables for mbo. + // + bool linearize(opt::model_based_opt& mbo, model& model, expr* lit, expr_ref_vector& fmls, obj_map& tids) { obj_map ts; rational c(0), mul(1); expr_ref t(m); opt::ineq_type ty = opt::t_le; expr* e1, *e2; + DEBUG_CODE(expr_ref val(m); VERIFY(model.eval(lit, val) && m.is_true(val));); + bool is_not = m.is_not(lit, lit); if (is_not) { mul.neg(); } SASSERT(!m.is_not(lit)); - if (a.is_le(lit, e1, e2) || a.is_ge(lit, e2, e1)) { - if (is_not) mul.neg(); - linearize(model, mul, e1, c, ts); - linearize(model, -mul, e2, c, ts); + if ((a.is_le(lit, e1, e2) || a.is_ge(lit, e2, e1)) && a.is_real(e1)) { + linearize(mbo, model, mul, e1, c, fmls, ts, tids); + linearize(mbo, model, -mul, e2, c, fmls, ts, tids); ty = is_not ? opt::t_lt : opt::t_le; } - else if (a.is_lt(lit, e1, e2) || a.is_gt(lit, e2, e1)) { - if (is_not) mul.neg(); - linearize(model, mul, e1, c, ts); - linearize(model, -mul, e2, c, ts); + else if ((a.is_lt(lit, e1, e2) || a.is_gt(lit, e2, e1)) && a.is_real(e1)) { + linearize(mbo, model, mul, e1, c, fmls, ts, tids); + linearize(mbo, model, -mul, e2, c, fmls, ts, tids); ty = is_not ? opt::t_le: opt::t_lt; } - else if (m.is_eq(lit, e1, e2) && !is_not && is_arith(e1)) { - linearize(model, mul, e1, c, ts); - linearize(model, -mul, e2, c, ts); + else if (m.is_eq(lit, e1, e2) && !is_not && a.is_real(e1)) { + linearize(mbo, model, mul, e1, c, fmls, ts, tids); + linearize(mbo, model, -mul, e2, c, fmls, ts, tids); ty = opt::t_eq; } - else if (m.is_distinct(lit) && !is_not && is_arith(to_app(lit)->get_arg(0))) { - UNREACHABLE(); + else if (m.is_eq(lit, e1, e2) && is_not && a.is_real(e1)) { + expr_ref val1(m), val2(m); + rational r1, r2; + VERIFY(model.eval(e1, val1) && a.is_numeral(val1, r1)); + VERIFY(model.eval(e2, val2) && a.is_numeral(val2, r2)); + SASSERT(r1 != r2); + if (r2 < r1) { + std::swap(e1, e2); + } + ty = opt::t_lt; + linearize(mbo, model, mul, e1, c, fmls, ts, tids); + linearize(mbo, model, -mul, e2, c, fmls, ts, tids); + } + else if (m.is_distinct(lit) && !is_not && a.is_real(to_app(lit)->get_arg(0))) { + TRACE("qe", tout << "TBD: handle distinc\n";); + return false; } - else if (m.is_distinct(lit) && is_not && is_arith(to_app(lit)->get_arg(0))) { - UNREACHABLE(); + else if (m.is_distinct(lit) && is_not && a.is_real(to_app(lit)->get_arg(0))) { + TRACE("qe", tout << "TBD: handle negation of distinc\n";); + return false; } - else if (m.is_eq(lit, e1, e2) && is_not && is_arith(e1)) { - UNREACHABLE(); - } else { - return; + TRACE("qe", tout << "Skipping " << mk_pp(lit, m) << "\n";); + return false; } - if (ty == opt::t_lt && is_int()) { +#if 0 + TBD for integers + if (ty == opt::t_lt && false) { c += rational(1); ty = opt::t_le; } +#endif vars coeffs; - extract_coefficients(ts, tids, coeffs); + extract_coefficients(mbo, model, ts, tids, coeffs); mbo.add_constraint(coeffs, c, ty); + return true; } - void linearize(model& model, rational const& mul, expr* t, rational& c, obj_map& ts) { + // + // convert linear arithmetic term into an inequality for mbo. + // + void linearize(opt::model_based_opt& mbo, model& model, rational const& mul, expr* t, rational& c, + expr_ref_vector& fmls, obj_map& ts, obj_map& tids) { expr* t1, *t2, *t3; rational mul1; expr_ref val(m); if (a.is_mul(t, t1, t2) && is_numeral(model, t1, mul1)) { - linearize(model, mul* mul1, t2, c, ts); + linearize(mbo, model, mul* mul1, t2, c, fmls, ts, tids); } else if (a.is_mul(t, t1, t2) && is_numeral(model, t2, mul1)) { - linearize(model, mul* mul1, t1, c, ts); + linearize(mbo, model, mul* mul1, t1, c, fmls, ts, tids); } else if (a.is_add(t)) { app* ap = to_app(t); for (unsigned i = 0; i < ap->get_num_args(); ++i) { - linearize(model, mul, ap->get_arg(i), c, ts); + linearize(mbo, model, mul, ap->get_arg(i), c, fmls, ts, tids); } } else if (a.is_sub(t, t1, t2)) { - linearize(model, mul, t1, c, ts); - linearize(model, -mul, t2, c, ts); + linearize(mbo, model, mul, t1, c, fmls, ts, tids); + linearize(mbo, model, -mul, t2, c, fmls, ts, tids); } else if (a.is_uminus(t, t1)) { - linearize(model, -mul, t1, c, ts); + linearize(mbo, model, -mul, t1, c, fmls, ts, tids); } else if (a.is_numeral(t, mul1)) { c += mul*mul1; } - else if (extract_mod(model, t, val)) { - insert_mul(val, mul, ts); - } else if (m.is_ite(t, t1, t2, t3)) { VERIFY(model.eval(t1, val)); SASSERT(m.is_true(val) || m.is_false(val)); TRACE("qe", tout << mk_pp(t1, m) << " := " << val << "\n";); if (m.is_true(val)) { - linearize(model, mul, t2, c, ts); + linearize(mbo, model, mul, t2, c, fmls, ts, tids); + fmls.push_back(t1); } else { - linearize(model, mul, t3, c, ts); + expr_ref not_t1(mk_not(m, t1), m); + fmls.push_back(not_t1); + linearize(mbo, model, mul, t3, c, fmls, ts, tids); } } else { @@ -193,6 +214,9 @@ namespace qe { } } + // + // extract linear terms from t into c and ts. + // void is_linear(model& model, rational const& mul, expr* t, rational& c, expr_ref_vector& ts) { expr* t1, *t2, *t3; rational mul1; @@ -245,7 +269,9 @@ namespace qe { } } - + // + // extract linear inequalities from literal lit. + // bool is_linear(model& model, expr* lit, bool& found_eq) { rational c(0), mul(1); expr_ref t(m); @@ -421,6 +447,7 @@ namespace qe { return a.is_int(e) || a.is_real(e); } + expr_ref add(expr_ref_vector const& ts) { switch (ts.size()) { case 0: @@ -647,6 +674,9 @@ namespace qe { bool new_max = true; rational max_r, r; expr_ref val(m); + model_evaluator eval(mdl); + eval.set_model_completion(true); + bool is_int = a.is_int(m_var->x()); for (unsigned i = 0; i < num_ineqs(); ++i) { rational const& ac = m_ineq_coeffs[i]; @@ -658,7 +688,7 @@ namespace qe { // ac < 0: x + t/ac > 0 <=> x > max { - t/ac | ac < 0 } = max { t/|ac| | ac < 0 } // if (ac.is_pos() == do_pos) { - VERIFY(mdl.eval(ineq_term(i), val)); + eval(ineq_term(i), val); VERIFY(a.is_numeral(val, r)); r /= abs(ac); new_max = @@ -937,7 +967,7 @@ namespace qe { } imp(ast_manager& m): - m(m), a(m), m_rw(m), m_ineq_terms(m), m_div_terms(m), m_new_lits(m) { + m(m), a(m), m_rw(m), m_ineq_terms(m), m_div_terms(m), m_new_lits(m), m_trail(m) { params_ref params; params.set_bool("gcd_rouding", true); m_rw.updt_params(params); @@ -964,11 +994,115 @@ namespace qe { } typedef opt::model_based_opt::var var; + typedef opt::model_based_opt::row row; typedef vector vars; - - opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound) { + + void operator()(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { + bool has_real = false; + for (unsigned i = 0; !has_real && i < vars.size(); ++i) { + has_real = a.is_real(vars[i].get()); + } + if (!has_real) { + return; + } + + opt::model_based_opt mbo; + obj_map tids; + m_trail.reset(); + unsigned j = 0; + for (unsigned i = 0; i < fmls.size(); ++i) { + if (!linearize(mbo, model, fmls[i].get(), fmls, tids)) { + if (i != j) { + fmls[j] = fmls[i].get(); + } + ++j; + } + } + fmls.resize(j); + + // fmls holds residue, + // mbo holds linear inequalities that are in scope + // collect variables in residue an in tids. + // filter variables that are absent from residue. + // project those. + // collect result of projection + // return those to fmls. + + expr_mark var_mark, fmls_mark; + for (unsigned i = 0; i < vars.size(); ++i) { + app* v = vars[i].get(); + var_mark.mark(v); + if (a.is_real(v) && !tids.contains(v)) { + tids.insert(v, tids.size()); + } + } + for (unsigned i = 0; i < fmls.size(); ++i) { + fmls_mark.mark(fmls[i].get()); + } + obj_map::iterator it = tids.begin(), end = tids.end(); + ptr_vector index2expr; + for (; it != end; ++it) { + expr* e = it->m_key; + if (!var_mark.is_marked(e)) { + mark_rec(fmls_mark, e); + } + index2expr.setx(it->m_value, e, 0); + } + j = 0; + unsigned_vector real_vars; + for (unsigned i = 0; i < vars.size(); ++i) { + app* v = vars[i].get(); + if (a.is_real(v) && !fmls_mark.is_marked(v)) { + real_vars.push_back(tids.find(v)); + } + else { + if (i != j) { + vars[j] = v; + } + ++j; + } + } + vars.resize(j); + mbo.project(real_vars.size(), real_vars.c_ptr()); + vector rows; + mbo.get_live_rows(rows); + + for (unsigned i = 0; i < rows.size(); ++i) { + expr_ref_vector ts(m); + expr_ref t(m), s(m); + row const& r = rows[i]; + for (j = 0; j < r.m_vars.size(); ++j) { + var const& v = r.m_vars[j]; + t = index2expr[v.m_id]; + if (!v.m_coeff.is_one()) { + t = a.mk_mul(t, a.mk_numeral(v.m_coeff, v.m_coeff.is_int())); + } + ts.push_back(t); + } + if (ts.empty()) { + continue; + } + s = a.mk_numeral(-r.m_coeff, r.m_coeff.is_int()); + if (ts.size() == 1) { + t = ts[0].get(); + } + else { + t = a.mk_add(ts.size(), ts.c_ptr()); + } + switch (r.m_type) { + case opt::t_lt: t = a.mk_lt(t, s); break; + case opt::t_le: t = a.mk_le(t, s); break; + case opt::t_eq: t = a.mk_eq(t, s); break; + } + fmls.push_back(t); + } + } + + opt::inf_eps maximize(expr_ref_vector const& fmls0, model& mdl, app* t, expr_ref& bound) { + m_trail.reset(); SASSERT(a.is_real(t)); + expr_ref_vector fmls(fmls0); opt::model_based_opt mbo; opt::inf_eps value; obj_map ts; @@ -977,13 +1111,14 @@ namespace qe { // extract objective function. vars coeffs; rational c(0), mul(1); - linearize(mdl, mul, t, c, ts); - extract_coefficients(ts, tids, coeffs); + linearize(mbo, mdl, mul, t, c, fmls, ts, tids); + extract_coefficients(mbo, mdl, ts, tids, coeffs); mbo.set_objective(coeffs, c); // extract linear constraints + for (unsigned i = 0; i < fmls.size(); ++i) { - linearize(mdl, mbo, fmls[i], tids); + linearize(mbo, mdl, fmls[i].get(), fmls, tids); } // find optimal value @@ -1021,14 +1156,23 @@ namespace qe { return value; } - void extract_coefficients(obj_map const& ts, obj_map& tids, vars& coeffs) { + void extract_coefficients(opt::model_based_opt& mbo, model& model, obj_map const& ts, obj_map& tids, vars& coeffs) { coeffs.reset(); obj_map::iterator it = ts.begin(), end = ts.end(); for (; it != end; ++it) { unsigned id; if (!tids.find(it->m_key, id)) { - id = tids.size(); + rational r; + expr_ref val(m); + if (model.eval(it->m_key, val) && a.is_numeral(val, r)) { + id = mbo.add_var(r); + } + else { + TRACE("qe", tout << "extraction of coefficients cancelled\n";); + return; + } tids.insert(it->m_key, id); + m_trail.push_back(it->m_key); } coeffs.push_back(var(id, it->m_value)); } @@ -1048,6 +1192,10 @@ namespace qe { return (*m_imp)(model, var, vars, lits); } + void arith_project_plugin::operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { + (*m_imp)(model, vars, lits); + } + bool arith_project_plugin::solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) { return m_imp->solve(model, vars, lits); } diff --git a/src/qe/qe_arith.h b/src/qe/qe_arith.h index b89d16d0402..f71156b1e23 100644 --- a/src/qe/qe_arith.h +++ b/src/qe/qe_arith.h @@ -29,6 +29,8 @@ namespace qe { virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits); virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits); virtual family_id get_family_id(); + virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits); + opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound); }; diff --git a/src/qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp index 8bb3fa6e2da..38861df658a 100644 --- a/src/qe/qe_arith_plugin.cpp +++ b/src/qe/qe_arith_plugin.cpp @@ -1153,21 +1153,20 @@ namespace qe { bool get_bound(contains_app& contains_x, app* a) { - ast_manager& m = m_util.get_manager(); - app* x = contains_x.x(); - if (m_mark.is_marked(a) || + bool has_bound = + m_mark.is_marked(a) || get_le_bound(contains_x, a) || get_lt_bound(contains_x, a) || get_divides(contains_x, a) || - get_nested_divs(contains_x, a)) { - TRACE("qe_verbose", tout << "Bound for " << mk_pp(x, m) << " within " << mk_pp(a, m) << "\n";); + get_nested_divs(contains_x, a); + if (has_bound) { m_mark.mark(a, true); - return true; - } - else { - TRACE("qe", tout << "No bound for " << mk_pp(x, m) << " within " << mk_pp(a, m) << "\n";); - return false; } + TRACE("qe_verbose", + ast_manager& m = m_util.get_manager(); + app* x = contains_x.x(); + tout << has_bound << " bound for " << mk_pp(x, m) << " within " << mk_pp(a, m) << "\n";); + return has_bound; } unsigned lt_size() { return m_lt_terms.size(); } @@ -2323,7 +2322,6 @@ namespace qe { unsigned sz = bounds.size(is_strict, !is_lower); bool is_strict_real = !is_eq_ctx && m_util.is_real(x) && !is_strict_ctx; bool strict_resolve = is_strict || is_strict_ctx || is_strict_real; - app* atm = bounds.atoms(is_strict_ctx, is_lower)[index]; for (unsigned i = 0; i < sz; ++i) { app* e = bounds.atoms(is_strict, !is_lower)[i]; @@ -2341,6 +2339,7 @@ namespace qe { m_ctx.add_constraint(true, mk_not(e), tmp); TRACE("qe_verbose", + app* atm = bounds.atoms(is_strict_ctx, is_lower)[index]; tout << mk_pp(atm, m) << " "; tout << mk_pp(e, m) << " ==>\n"; tout << mk_pp(tmp, m) << "\n"; diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 7d5f3800eb8..2bacb3a4f1a 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -28,10 +28,26 @@ Revision History: #include "th_rewriter.h" #include "model_v2_pp.h" #include "expr_functors.h" +#include "for_each_expr.h" using namespace qe; +struct noop_op_proc { + void operator()(expr*) {} +}; + + +void project_plugin::mark_rec(expr_mark& visited, expr* e) { + for_each_expr_proc fe; + for_each_expr(fe, visited, e); +} + +void project_plugin::mark_rec(expr_mark& visited, expr_ref_vector const& es) { + for (unsigned i = 0; i < es.size(); ++i) { + mark_rec(visited, es[i]); + } +} /** \brief return two terms that are equal in the model. @@ -106,6 +122,7 @@ void project_plugin::push_back(expr_ref_vector& lits, expr* e) { class mbp::impl { ast_manager& m; + th_rewriter m_rw; ptr_vector m_plugins; expr_mark m_visited; @@ -130,7 +147,6 @@ class mbp::impl { is_var.mark(vars[i].get()); } expr_ref tmp(m), t(m), v(m); - th_rewriter rw(m); for (unsigned i = 0; i < lits.size(); ++i) { expr* e = lits[i].get(), *l, *r; if (m.is_eq(e, l, r) && reduce_eq(is_var, l, r, v, t)) { @@ -141,7 +157,7 @@ class mbp::impl { is_rem.mark(v); for (unsigned j = 0; j < lits.size(); ++j) { sub(lits[j].get(), tmp); - rw(tmp); + m_rw(tmp); lits[j] = tmp; } } @@ -177,6 +193,26 @@ class mbp::impl { } + void filter_variables(model& model, app_ref_vector& vars, expr_ref_vector& lits, expr_ref_vector& unused_lits) { + expr_mark lit_visited; + project_plugin::mark_rec(lit_visited, lits); + + unsigned j = 0; + for (unsigned i = 0; i < vars.size(); ++i) { + app* var = vars[i].get(); + if (lit_visited.is_marked(var)) { + if (i != j) { + vars[j] = vars[i].get(); + } + ++j; + } + } + if (vars.size() != j) { + vars.resize(j); + } + } + + void extract_bools(model& model, expr_ref_vector& fmls, expr* fml) { TRACE("qe", tout << "extract bools: " << mk_pp(fml, m) << "\n";); ptr_vector todo; @@ -210,6 +246,42 @@ class mbp::impl { } } + void project_bools(model& model, app_ref_vector& vars, expr_ref_vector& fmls) { + expr_safe_replace sub(m); + expr_ref val(m); + unsigned j = 0; + for (unsigned i = 0; i < vars.size(); ++i) { + app* var = vars[i].get(); + if (m.is_bool(var)) { + VERIFY(model.eval(var, val)); + sub.insert(var, val); + } + else { + if (j != i) { + vars[j] = vars[i].get(); + } + ++j; + } + } + if (j != vars.size()) { + vars.resize(j); + j = 0; + for (unsigned i = 0; i < fmls.size(); ++i) { + sub(fmls[i].get(), val); + m_rw(val); + if (!m.is_true(val)) { + if (j != i) { + fmls[j] = fmls[i].get(); + } + ++j; + } + } + if (j != fmls.size()) { + fmls.resize(j); + } + } + } + public: @@ -333,7 +405,7 @@ class mbp::impl { m_visited.reset(); } - impl(ast_manager& m):m(m) { + impl(ast_manager& m):m(m), m_rw(m) { add_plugin(alloc(arith_project_plugin, m)); add_plugin(alloc(datatype_project_plugin, m)); add_plugin(alloc(array_project_plugin, m)); @@ -359,14 +431,21 @@ class mbp::impl { void operator()(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls) { expr_ref val(m), tmp(m); app_ref var(m); - th_rewriter rw(m); + expr_ref_vector unused_fmls(m); bool progress = true; - TRACE("qe", tout << vars << " " << fmls << "\n";); - while (progress && !vars.empty()) { - preprocess_solve(model, vars, fmls); + preprocess_solve(model, vars, fmls); + filter_variables(model, vars, fmls, unused_fmls); + project_bools(model, vars, fmls); + while (progress && !vars.empty() && !fmls.empty()) { app_ref_vector new_vars(m); progress = false; - while (!vars.empty()) { + for (unsigned i = 0; i < m_plugins.size(); ++i) { + project_plugin* p = m_plugins[i]; + if (p) { + (*p)(model, vars, fmls); + } + } + while (!vars.empty() && !fmls.empty()) { var = vars.back(); vars.pop_back(); project_plugin* p = get_plugin(var); @@ -377,7 +456,7 @@ class mbp::impl { new_vars.push_back(var); } } - if (!progress && !new_vars.empty() && force_elim) { + if (!progress && !new_vars.empty() && !fmls.empty() && force_elim) { var = new_vars.back(); new_vars.pop_back(); expr_safe_replace sub(m); @@ -385,7 +464,7 @@ class mbp::impl { sub.insert(var, val); for (unsigned i = 0; i < fmls.size(); ++i) { sub(fmls[i].get(), tmp); - rw(tmp); + m_rw(tmp); if (m.is_true(tmp)) { project_plugin::erase(fmls, i); } @@ -396,9 +475,17 @@ class mbp::impl { progress = true; } vars.append(new_vars); + if (progress) { + preprocess_solve(model, vars, fmls); + } } + if (fmls.empty()) { + vars.reset(); + } + fmls.append(unused_fmls); TRACE("qe", tout << vars << " " << fmls << "\n";); } + }; mbp::mbp(ast_manager& m) { diff --git a/src/qe/qe_mbp.h b/src/qe/qe_mbp.h index 332659c0b13..6c28555b0e4 100644 --- a/src/qe/qe_mbp.h +++ b/src/qe/qe_mbp.h @@ -37,12 +37,15 @@ namespace qe { virtual bool operator()(model& model, app* var, app_ref_vector& vars, expr_ref_vector& lits) = 0; virtual bool solve(model& model, app_ref_vector& vars, expr_ref_vector& lits) = 0; virtual family_id get_family_id() = 0; + virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits) { }; static expr_ref pick_equality(ast_manager& m, model& model, expr* t); static void partition_values(model& model, expr_ref_vector const& vals, expr_ref_vector& lits); static void partition_args(model& model, app_ref_vector const& sels, expr_ref_vector& lits); static void erase(expr_ref_vector& lits, unsigned& i); static void push_back(expr_ref_vector& lits, expr* lit); + static void mark_rec(expr_mark& visited, expr* e); + static void mark_rec(expr_mark& visited, expr_ref_vector const& es); }; class mbp { diff --git a/src/qe/qe_sat_tactic.cpp b/src/qe/qe_sat_tactic.cpp index 455c1d08ee9..c2912692cee 100644 --- a/src/qe/qe_sat_tactic.cpp +++ b/src/qe/qe_sat_tactic.cpp @@ -603,8 +603,7 @@ namespace qe { m_solver.assert_expr(m.mk_iff(proxies.back(), m_assignments[i].get())); TRACE("qe", tout << "assignment: " << mk_pp(m_assignments[i].get(), m) << "\n";); } - lbool is_sat = m_solver.check(proxies.size(), proxies.c_ptr()); - SASSERT(is_sat == l_false); + VERIFY(l_false == m_solver.check(proxies.size(), proxies.c_ptr())); unsigned core_size = m_solver.get_unsat_core_size(); for (unsigned i = 0; i < core_size; ++i) { core.push_back(proxy_map.find(m_solver.get_unsat_core_expr(i))); diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 74b1101fe1a..a9ca9e99db1 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -33,6 +33,7 @@ Revision History: #include "label_rewriter.h" #include "expr_replacer.h" #include "th_rewriter.h" +#include "model_evaluator.h" namespace qe { @@ -154,12 +155,14 @@ namespace qe { if (level == 0) { return; } + model_evaluator eval(*mdl); + expr_ref val(m); for (unsigned j = 0; j < m_preds[level - 1].size(); ++j) { app* p = m_preds[level - 1][j].get(); TRACE("qe", tout << "process level: " << level - 1 << ": " << mk_pp(p, m) << "\n";); - VERIFY(mdl->eval(p, val)); + eval(p, val); if (m.is_false(val)) { m_asms.push_back(m.mk_not(p)); @@ -179,7 +182,7 @@ namespace qe { (lvl.m_fa == i && (lvl.m_ex == UINT_MAX || lvl.m_ex < level)) || (lvl.m_ex == i && (lvl.m_fa == UINT_MAX || lvl.m_fa < level)); if (use) { - VERIFY(mdl->eval(p, val)); + eval(p, val); if (m.is_false(val)) { asms.push_back(m.mk_not(p)); } @@ -503,13 +506,11 @@ namespace qe { } class kernel { - ast_manager& m; smt_params m_smtp; smt::kernel m_kernel; public: kernel(ast_manager& m): - m(m), m_kernel(m, m_smtp) { m_smtp.m_model = true; @@ -550,8 +551,7 @@ namespace qe { unsigned m_num_rounds; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } - }; - + }; ast_manager& m; params_ref m_params; @@ -569,6 +569,9 @@ namespace qe { qsat_mode m_mode; app_ref_vector m_avars; // variables to project app_ref_vector m_free_vars; + app* m_objective; + opt::inf_eps* m_value; + bool m_was_sat; /** @@ -578,6 +581,7 @@ namespace qe { lbool check_sat() { while (true) { ++m_stats.m_num_rounds; + IF_VERBOSE(3, verbose_stream() << "(check-qsat level: " << m_level << " round: " << m_stats.m_num_rounds << ")\n";); check_cancel(); expr_ref_vector asms(m_asms); m_pred_abs.get_assumptions(m_model.get(), asms); @@ -706,96 +710,7 @@ namespace qe { for (unsigned i = 0; i < vars.size(); ++i) { m_pred_abs.fmc()->insert(vars[i]->get_decl()); } - } - -#if 0 - void hoist_ite(expr_ref& fml) { - app* ite; - scoped_ptr replace = mk_default_expr_replacer(m); - th_rewriter rewriter(m); - while (find_ite(fml, ite)) { - expr* cond, *th, *el; - VERIFY(m.is_ite(ite, cond, th, el)); - expr_ref tmp1(fml, m), tmp2(fml, m); - replace->apply_substitution(cond, m.mk_true(), tmp1); - replace->apply_substitution(cond, m.mk_false(), tmp2); - fml = m.mk_ite(cond, tmp1, tmp2); - rewriter(fml); - } - } - - bool find_ite(expr* e, app*& ite) { - ptr_vector todo; - todo.push_back(e); - ast_mark visited; - while(!todo.empty()) { - e = todo.back(); - todo.pop_back(); - if (visited.is_marked(e)) { - continue; - } - visited.mark(e, true); - if (m.is_ite(e) && !m.is_bool(e)) { - ite = to_app(e); - return true; - } - if (is_app(e)) { - app* a = to_app(e); - todo.append(a->get_num_args(), a->get_args()); - } - } - return false; - } - - // slower - void hoist_ite2(expr_ref& fml) { - obj_map result; - expr_ref_vector trail(m); - ptr_vector todo, args; - todo.push_back(fml); - - while (!todo.empty()) { - expr* e = todo.back(); - if (result.contains(e)) { - todo.pop_back(); - continue; - } - if (!is_app(e)) { - todo.pop_back(); - result.insert(e, e); - continue; - } - app* a = to_app(e); - expr* r; - unsigned sz = a->get_num_args(); - args.reset(); - for (unsigned i = 0; i < sz; ++i) { - if (result.find(a->get_arg(i), r)) { - args.push_back(r); - } - else { - todo.push_back(a->get_arg(i)); - } - } - if (sz == args.size()) { - r = m.mk_app(a->get_decl(), args.size(), args.c_ptr()); - trail.push_back(r); - if (m.is_bool(e) && m.get_basic_family_id() != a->get_family_id()) { - expr_ref fml(r, m); - hoist_ite(fml); - trail.push_back(fml); - r = fml; - } - result.insert(e, r); - todo.pop_back(); - } - } - fml = result.find(fml); - } -#endif - - - + } void initialize_levels() { // initialize levels. @@ -827,11 +742,7 @@ namespace qe { void display(std::ostream& out) const { out << "level: " << m_level << "\n"; for (unsigned i = 0; i < m_vars.size(); ++i) { - for (unsigned j = 0; j < m_vars[i].size(); ++j) { - expr* v = m_vars[i][j]; - out << mk_pp(v, m) << " "; - } - out << "\n"; + out << m_vars[i] << "\n"; } m_pred_abs.display(out); } @@ -1162,7 +1073,10 @@ namespace qe { m_level(0), m_mode(mode), m_avars(m), - m_free_vars(m) + m_free_vars(m), + m_objective(0), + m_value(0), + m_was_sat(false) { reset(); } @@ -1257,6 +1171,9 @@ namespace qe { void collect_statistics(statistics & st) const { st.copy(m_st); + m_fa.k().collect_statistics(st); + m_ex.k().collect_statistics(st); + m_pred_abs.collect_statistics(st); st.update("qsat num rounds", m_stats.m_num_rounds); m_pred_abs.collect_statistics(st); } @@ -1264,7 +1181,7 @@ namespace qe { void reset_statistics() { m_stats.reset(); m_fa.k().reset_statistics(); - m_ex.k().reset_statistics(); + m_ex.k().reset_statistics(); } void cleanup() { @@ -1281,16 +1198,12 @@ namespace qe { return alloc(qsat, m, m_params, m_mode); } - app* m_objective; - opt::inf_eps m_value; - bool m_was_sat; - lbool maximize(expr_ref_vector const& fmls, app* t, model_ref& mdl, opt::inf_eps& value) { expr_ref_vector defs(m); - expr_ref fml = negate_core(fmls); + expr_ref fml = mk_and(fmls); hoist(fml); m_objective = t; - m_value = opt::inf_eps(); + m_value = &value; m_was_sat = false; m_pred_abs.abstract_atoms(fml, defs); fml = m_pred_abs.mk_abstract(fml); @@ -1314,20 +1227,25 @@ namespace qe { if (s == "ok") { s = m_fa.k().last_failure_as_string(); } + throw tactic_exception(s.c_str()); } - value = m_value; return l_true; } void maximize(expr_ref_vector const& core, model& mdl) { + SASSERT(m_value); + SASSERT(m_objective); TRACE("qe", tout << "maximize: " << core << "\n";); m_was_sat |= !core.empty(); expr_ref bound(m); - m_value = m_mbp.maximize(core, mdl, m_objective, bound); + *m_value = m_mbp.maximize(core, mdl, m_objective, bound); + IF_VERBOSE(0, verbose_stream() << "(maximize " << *m_value << " bound: " << bound << ")\n";); m_ex.assert_expr(bound); } + + }; lbool maximize(expr_ref_vector const& fmls, app* t, opt::inf_eps& value, model_ref& mdl, params_ref const& p) { @@ -1335,6 +1253,31 @@ namespace qe { qsat qs(m, p, qsat_maximize); return qs.maximize(fmls, t, mdl, value); } + + + struct qmax::imp { + qsat m_qsat; + imp(ast_manager& m, params_ref const& p): + m_qsat(m, p, qsat_maximize) + {} + }; + + qmax::qmax(ast_manager& m, params_ref const& p) { + m_imp = alloc(imp, m, p); + } + + qmax::~qmax() { + dealloc(m_imp); + } + + lbool qmax::operator()(expr_ref_vector const& fmls, app* t, opt::inf_eps& value, model_ref& mdl) { + return m_imp->m_qsat.maximize(fmls, t, mdl, value); + } + + void qmax::collect_statistics(statistics& st) const { + m_imp->m_qsat.collect_statistics(st); + }; + }; tactic * mk_qsat_tactic(ast_manager& m, params_ref const& p) { @@ -1352,94 +1295,3 @@ tactic * mk_qe_rec_tactic(ast_manager& m, params_ref const& p) { -#if 0 - - class min_max_opt { - struct imp; - imp* m_imp; - public: - min_max_opt(ast_manager& m); - ~min_max_opt(); - void add(expr* e); - void add(expr_ref_vector const& fmls); - lbool check(svector const& is_max, app_ref_vector const& vars, app* t); - }; - - struct min_max_opt::imp { - ast_manager& m; - expr_ref_vector m_fmls; - pred_abs m_pred_abs; - qe::mbp m_mbp; - kernel m_kernel; - vector m_vars; - - imp(ast_manager& m): - m(m), - m_fmls(m), - m_pred_abs(m), - m_mbp(m), - m_kernel(m) {} - - void add(expr* e) { - m_fmls.push_back(e); - } - - lbool check(svector const& is_max, app_ref_vector const& vars, app* t) { - // Assume this is the only call to check. - expr_ref_vector defs(m); - app_ref_vector free_vars(m), vars1(m); - expr_ref fml = mk_and(m_fmls); - m_pred_abs.get_free_vars(fml, free_vars); - m_pred_abs.abstract_atoms(fml, defs); - fml = m_pred_abs.mk_abstract(fml); - m_kernel.assert_expr(mk_and(defs)); - m_kernel.assert_expr(fml); - obj_hashtable var_set; - for (unsigned i = 0; i < vars.size(); ++i) { - var_set.insert(vars[i]); - } - for (unsigned i = 0; i < free_vars.size(); ++i) { - app* v = free_vars[i].get(); - if (!var_set.contains(v)) { - vars1.push_back(v); - } - } - bool is_m = is_max[0]; - for (unsigned i = 0; i < vars.size(); ++i) { - if (is_m != is_max[i]) { - m_vars.push_back(vars1); - vars1.reset(); - is_m = is_max[i]; - } - vars1.push_back(vars[i]); - } - - // TBD - - return l_undef; - } - }; - - min_max_opt::min_max_opt(ast_manager& m) { - m_imp = alloc(imp, m); - } - - min_max_opt::~min_max_opt() { - dealloc(m_imp); - } - - void min_max_opt::add(expr* e) { - m_imp->add(e); - } - - void min_max_opt::add(expr_ref_vector const& fmls) { - for (unsigned i = 0; i < fmls.size(); ++i) { - add(fmls[i]); - } - } - - lbool min_max_opt::check(svector const& is_max, app_ref_vector const& vars, app* t) { - return m_imp->check(is_max, vars, t); - } - -#endif diff --git a/src/qe/qsat.h b/src/qe/qsat.h index 456711c4f3b..66676da054b 100644 --- a/src/qe/qsat.h +++ b/src/qe/qsat.h @@ -114,6 +114,16 @@ namespace qe { void collect_statistics(statistics& st) const; }; + class qmax { + struct imp; + imp* m_imp; + public: + qmax(ast_manager& m, params_ref const& p = params_ref()); + ~qmax(); + lbool operator()(expr_ref_vector const& fmls, app* t, opt::inf_eps& value, model_ref& mdl); + void collect_statistics(statistics& st) const; + }; + lbool maximize(expr_ref_vector const& fmls, app* t, opt::inf_eps& value, model_ref& mdl, params_ref const& p); } diff --git a/src/sat/sat_bceq.cpp b/src/sat/sat_bceq.cpp index a194cdfd8d9..9ff286aaa91 100644 --- a/src/sat/sat_bceq.cpp +++ b/src/sat/sat_bceq.cpp @@ -345,10 +345,11 @@ namespace sat { } void bceq::verify_sweep() { - for (unsigned i = 0; i < m_L.size(); ++i) { - uint64 b = eval_clause(*m_L[i]); - SASSERT((~b) == 0); - } + DEBUG_CODE( + for (unsigned i = 0; i < m_L.size(); ++i) { + uint64 b = eval_clause(*m_L[i]); + SASSERT((~b) == 0); + }); } struct u64_hash { unsigned operator()(uint64 u) const { return (unsigned)u; } }; diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 2881c03aeb2..eabc4fdb1f7 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -52,6 +52,7 @@ namespace sat { bool clause::check_approx() const { var_approx_set curr = m_approx; + (void)curr; const_cast(this)->update_approx(); SASSERT(may_eq(curr, m_approx)); return true; diff --git a/src/sat/sat_clause_set.cpp b/src/sat/sat_clause_set.cpp index ca8e9d84140..1c424cce3b6 100644 --- a/src/sat/sat_clause_set.cpp +++ b/src/sat/sat_clause_set.cpp @@ -35,6 +35,8 @@ namespace sat { unsigned id = c.id(); if (id >= m_id2pos.size()) return; + if (empty()) + return; unsigned pos = m_id2pos[id]; if (pos == UINT_MAX) return; @@ -52,12 +54,17 @@ namespace sat { clause & clause_set::erase() { SASSERT(!empty()); clause & c = *m_set.back(); - m_id2pos[c.id()] = UINT_MAX; + SASSERT(c.id() < m_id2pos.size()); + SASSERT(m_id2pos[c.id()] == m_set.size()-1); + if (c.id() < m_id2pos.size()) { + m_id2pos[c.id()] = UINT_MAX; + } m_set.pop_back(); return c; } bool clause_set::check_invariant() const { + DEBUG_CODE( { clause_vector::const_iterator it = m_set.begin(); clause_vector::const_iterator end = m_set.end(); @@ -77,7 +84,7 @@ namespace sat { SASSERT(pos < m_set.size()); SASSERT(m_set[pos]->id() == id); } - } + }); return true; } diff --git a/src/sat/sat_integrity_checker.cpp b/src/sat/sat_integrity_checker.cpp index d0052b8c220..c60fb86cb3c 100644 --- a/src/sat/sat_integrity_checker.cpp +++ b/src/sat/sat_integrity_checker.cpp @@ -40,8 +40,7 @@ namespace sat { if (it->is_clause()) { if (it->get_clause_offset() == cls_off) { // the blocked literal must be in the clause. - literal l = it->get_blocked_literal(); - SASSERT(c.contains(l)); + SASSERT(c.contains(it->get_blocked_literal())); return true; } } @@ -154,12 +153,14 @@ namespace sat { } bool integrity_checker::check_watches() const { + DEBUG_CODE( vector::const_iterator it = s.m_watches.begin(); vector::const_iterator end = s.m_watches.end(); for (unsigned l_idx = 0; it != end; ++it, ++l_idx) { - literal l = ~to_literal(l_idx); + literal l = ~to_literal(l_idx); watch_list const & wlist = *it; - CTRACE("sat_bug", s.was_eliminated(l.var()) && !wlist.empty(), + CTRACE("sat_bug", + s.was_eliminated(l.var()) && !wlist.empty(), tout << "l: " << l << "\n"; s.display_watches(tout); s.display(tout);); @@ -179,7 +180,7 @@ namespace sat { tout << "\n"; sat::display(tout, s.m_cls_allocator, s.get_wlist(~(it2->get_literal()))); tout << "\n";); - SASSERT(s.get_wlist(~(it2->get_literal())).contains(watched(l, it2->is_learned()))); + SASSERT(s.get_wlist(~(it2->get_literal())).contains(watched(l, it2->is_learned()))); break; case watched::TERNARY: SASSERT(!s.was_eliminated(it2->get_literal1().var())); @@ -193,7 +194,7 @@ namespace sat { break; } } - } + }); return true; } diff --git a/src/sat/sat_sls.cpp b/src/sat/sat_sls.cpp index 76e222f026c..7efc0ce0b6a 100644 --- a/src/sat/sat_sls.cpp +++ b/src/sat/sat_sls.cpp @@ -269,35 +269,36 @@ namespace sat { } void sls::check_invariant() { - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause const& c = *m_clauses[i]; - bool is_sat = c.satisfied_by(m_model); - SASSERT(is_sat != m_false.contains(i)); - SASSERT(is_sat == (m_num_true[i] > 0)); - } + DEBUG_CODE( + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause const& c = *m_clauses[i]; + bool is_sat = c.satisfied_by(m_model); + SASSERT(is_sat != m_false.contains(i)); + SASSERT(is_sat == (m_num_true[i] > 0)); + }); } void sls::check_use_list() { - - for (unsigned i = 0; i < m_clauses.size(); ++i) { - clause const& c = *m_clauses[i]; - for (unsigned j = 0; j < c.size(); ++j) { - unsigned idx = c[j].index(); - SASSERT(m_use_list[idx].contains(i)); + DEBUG_CODE( + for (unsigned i = 0; i < m_clauses.size(); ++i) { + clause const& c = *m_clauses[i]; + for (unsigned j = 0; j < c.size(); ++j) { + unsigned idx = c[j].index(); + SASSERT(m_use_list[idx].contains(i)); + } } - } - for (unsigned i = 0; i < m_use_list.size(); ++i) { - literal lit = to_literal(i); - for (unsigned j = 0; j < m_use_list[i].size(); ++j) { - clause const& c = *m_clauses[m_use_list[i][j]]; - bool found = false; - for (unsigned k = 0; !found && k < c.size(); ++k) { - found = c[k] == lit; + for (unsigned i = 0; i < m_use_list.size(); ++i) { + literal lit = to_literal(i); + for (unsigned j = 0; j < m_use_list[i].size(); ++j) { + clause const& c = *m_clauses[m_use_list[i][j]]; + bool found = false; + for (unsigned k = 0; !found && k < c.size(); ++k) { + found = c[k] == lit; + } + SASSERT(found); } - SASSERT(found); - } - } + }); } void sls::display(std::ostream& out) const { @@ -556,8 +557,7 @@ namespace sat { void wsls::recompute_hscores(literal lit) { SASSERT(value_at(lit, m_model) == l_true); - bool_var v = lit.var(); - TRACE("sat", tout << v << " := " << m_hscore[v] << "\n";); + TRACE("sat", tout << lit.var() << " := " << m_hscore[lit.var()] << "\n";); unsigned_vector const& use1 = get_use(lit); unsigned sz = use1.size(); for (unsigned i = 0; i < sz; ++i) { @@ -647,28 +647,29 @@ namespace sat { // The hscore is the reward for flipping the truth value of variable v. // hscore(v) = Sum weight(c) for num_true(c) = 0 and v in c // - Sum weight(c) for num_true(c) = 1 and (v in c, M(v) or !v in c and !M(v)) - for (unsigned v = 0; v < s.num_vars(); ++v) { - int hs = compute_hscore(v); - CTRACE("sat", hs != m_hscore[v], display(tout << v << " - computed: " << hs << " - assigned: " << m_hscore[v] << "\n");); - SASSERT(m_hscore[v] == hs); - } - - // The score(v) is the reward on soft clauses for flipping v. - for (unsigned j = 0; j < m_soft.size(); ++j) { - unsigned v = m_soft[j].var(); - double ss = (l_true == value_at(m_soft[j], m_model))?(-m_weights[j]):m_weights[j]; - SASSERT(m_sscore[v] == ss); - } - - // m_H are values such that m_hscore > 0 and sscore = 0. - for (bool_var v = 0; v < m_hscore.size(); ++v) { - SASSERT((m_hscore[v] > 0 && !m_tabu[v] && m_sscore[v] == 0) == m_H.contains(v)); - } - - // m_S are values such that hscore = 0, sscore > 0 - for (bool_var v = 0; v < m_sscore.size(); ++v) { - SASSERT((m_hscore[v] == 0 && m_sscore[v] > 0 && !m_tabu[v]) == m_S.contains(v)); - } + DEBUG_CODE( + for (unsigned v = 0; v < s.num_vars(); ++v) { + int hs = compute_hscore(v); + CTRACE("sat", hs != m_hscore[v], display(tout << v << " - computed: " << hs << " - assigned: " << m_hscore[v] << "\n");); + SASSERT(m_hscore[v] == hs); + } + + // The score(v) is the reward on soft clauses for flipping v. + for (unsigned j = 0; j < m_soft.size(); ++j) { + unsigned v = m_soft[j].var(); + double ss = (l_true == value_at(m_soft[j], m_model))?(-m_weights[j]):m_weights[j]; + SASSERT(m_sscore[v] == ss); + } + + // m_H are values such that m_hscore > 0 and sscore = 0. + for (bool_var v = 0; v < m_hscore.size(); ++v) { + SASSERT((m_hscore[v] > 0 && !m_tabu[v] && m_sscore[v] == 0) == m_H.contains(v)); + } + + // m_S are values such that hscore = 0, sscore > 0 + for (bool_var v = 0; v < m_sscore.size(); ++v) { + SASSERT((m_hscore[v] == 0 && m_sscore[v] > 0 && !m_tabu[v]) == m_S.contains(v)); + }); } void wsls::display(std::ostream& out) const { diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f636c726b20..78067238a24 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -80,8 +80,7 @@ namespace sat { SASSERT(!src.was_eliminated(v)); bool ext = src.m_external[v] != 0; bool dvar = src.m_decision[v] != 0; - bool_var new_v = mk_var(ext, dvar); - SASSERT(v == new_v); + VERIFY(v == mk_var(ext, dvar)); } } { @@ -407,9 +406,8 @@ namespace sat { unsigned num_lits = cls.size(); for (unsigned i = 1; i < num_lits; i++) { literal l = cls[i]; - lbool val = value(l); - CTRACE("sat", val != l_false, tout << l << ":=" << val;); - SASSERT(val == l_false); + CTRACE("sat", value(l) != l_false, tout << l << ":=" << value(l);); + SASSERT(value(l) == l_false); if (max_false_idx == UINT_MAX || lvl(l) > lvl(cls[max_false_idx])) max_false_idx = i; } diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index daaed13ac59..f55945ce47d 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -739,6 +739,7 @@ class dl_graph { if (idx2 < idx1) { std::swap(idx1,idx2); } + (void) max_idx; SASSERT(idx1 < idx2 && idx2 < edges.size()); SASSERT(max_idx < edges.size()); dst = get_source(edges[idx2]); diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 764176ea0b0..0d7f6a3a689 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -1856,6 +1856,7 @@ namespace smt { ptr_vector m_used_enodes; unsigned m_curr_used_enodes_size; ptr_vector m_pattern_instances; // collect the pattern instances... used for computing min_top_generation and max_top_generation + unsigned_vector m_min_top_generation, m_max_top_generation; pool m_pool; @@ -2034,28 +2035,26 @@ namespace smt { // init(t) must be invoked before execute_core void execute_core(code_tree * t, enode * n); - // Return the min generation of the enodes in m_pattern_instances. - unsigned get_min_top_generation() const { - SASSERT(!m_pattern_instances.empty()); - unsigned min = m_pattern_instances[0]->get_generation(); - for (unsigned i = 1; i < m_pattern_instances.size(); i++) { - unsigned curr = m_pattern_instances[i]->get_generation(); - if (min > curr) - min = curr; - } - return min; - } + // Return the min, max generation of the enodes in m_pattern_instances. - // Return the max generation of the enodes in m_pattern_instances. - unsigned get_max_top_generation() const { + void get_min_max_top_generation(unsigned& min, unsigned& max) { SASSERT(!m_pattern_instances.empty()); - unsigned max = m_pattern_instances[0]->get_generation(); - for (unsigned i = 1; i < m_pattern_instances.size(); i++) { + if (m_min_top_generation.empty()) { + min = max = m_pattern_instances[0]->get_generation(); + m_min_top_generation.push_back(min); + m_max_top_generation.push_back(max); + } + else { + min = m_min_top_generation.back(); + max = m_max_top_generation.back(); + } + for (unsigned i = m_min_top_generation.size(); i < m_pattern_instances.size(); ++i) { unsigned curr = m_pattern_instances[i]->get_generation(); - if (max < curr) - max = curr; + min = std::min(min, curr); + m_min_top_generation.push_back(min); + max = std::max(max, curr); + m_max_top_generation.push_back(max); } - return max; } }; @@ -2278,6 +2277,8 @@ namespace smt { TRACE("mam_execute_core", tout << "EXEC " << t->get_root_lbl()->get_name() << "\n";); SASSERT(m_context.is_relevant(n)); m_pattern_instances.reset(); + m_min_top_generation.reset(); + m_max_top_generation.reset(); m_pattern_instances.push_back(n); m_max_generation = n->get_generation(); @@ -2289,8 +2290,10 @@ namespace smt { m_pc = t->get_root(); m_registers[0] = n; m_top = 0; + main_loop: + TRACE("mam_int", display_pc_info(tout);); #ifdef _PROFILE_MAM const_cast(m_pc)->m_counter++; @@ -2497,8 +2500,11 @@ namespace smt { case YIELD1: m_bindings[0] = m_registers[static_cast(m_pc)->m_bindings[0]]; -#define ON_MATCH(NUM) \ +#define ON_MATCH(NUM) \ m_max_generation = std::max(m_max_generation, get_max_generation(NUM, m_bindings.begin())); \ + if (m_context.get_cancel_flag()) { \ + return; \ + } \ m_mam.on_match(static_cast(m_pc)->m_qa, \ static_cast(m_pc)->m_pat, \ NUM, \ @@ -2770,9 +2776,12 @@ namespace smt { if (m_app->get_num_args() == c->m_num_args && m_context.is_relevant(m_app)) { // update the pattern instance SASSERT(!m_pattern_instances.empty()); + if (m_pattern_instances.size() == m_max_top_generation.size()) { + m_max_top_generation.pop_back(); + m_min_top_generation.pop_back(); + } m_pattern_instances.pop_back(); m_pattern_instances.push_back(m_app); - // continue succeeded update_max_generation(m_app); TRACE("mam_int", tout << "continue next candidate:\n" << mk_ll_pp(m_app->get_owner(), m_ast_manager);); @@ -3932,7 +3941,9 @@ namespace smt { SASSERT(bindings[i]->get_generation() <= max_generation); } #endif - m_context.add_instance(qa, pat, num_bindings, bindings, max_generation, m_interpreter.get_min_top_generation(), m_interpreter.get_max_top_generation(), used_enodes); + unsigned min_gen, max_gen; + m_interpreter.get_min_max_top_generation(min_gen, max_gen); + m_context.add_instance(qa, pat, num_bindings, bindings, max_generation, min_gen, max_gen, used_enodes); } virtual bool is_shared(enode * n) const { diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 35dd19087eb..711cdc33600 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -367,8 +367,7 @@ namespace smt { unsigned sz = m_delayed_entries.size(); for (unsigned i = 0; i < sz; i++) { entry & e = m_delayed_entries[i]; - fingerprint * f = e.m_qb; - TRACE("qi_queue", tout << f << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); + TRACE("qi_queue", tout << e.m_qb << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); if (!e.m_instantiated && e.m_cost <= m_params.m_qi_lazy_threshold && (!init || e.m_cost < min_cost)) { init = true; min_cost = e.m_cost; @@ -378,12 +377,10 @@ namespace smt { bool result = true; for (unsigned i = 0; i < sz; i++) { entry & e = m_delayed_entries[i]; - fingerprint * f = e.m_qb; - quantifier * qa = static_cast(f->get_data()); - TRACE("qi_queue", tout << f << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); + TRACE("qi_queue", tout << e.m_qb << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); if (!e.m_instantiated && e.m_cost <= min_cost) { TRACE("qi_queue", - tout << "lazy quantifier instantiation...\n" << mk_pp(qa, m_manager) << "\ncost: " << e.m_cost << "\n";); + tout << "lazy quantifier instantiation...\n" << mk_pp(static_cast(e.m_qb->get_data()), m_manager) << "\ncost: " << e.m_cost << "\n";); result = false; m_instantiated_trail.push_back(i); m_stats.m_num_lazy_instances++; @@ -396,12 +393,10 @@ namespace smt { bool result = true; for (unsigned i = 0; i < m_delayed_entries.size(); i++) { entry & e = m_delayed_entries[i]; - fingerprint * f = e.m_qb; - quantifier * qa = static_cast(f->get_data()); - TRACE("qi_queue", tout << f << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); + TRACE("qi_queue", tout << e.m_qb << ", cost: " << e.m_cost << ", instantiated: " << e.m_instantiated << "\n";); if (!e.m_instantiated && e.m_cost <= m_params.m_qi_lazy_threshold) { TRACE("qi_queue", - tout << "lazy quantifier instantiation...\n" << mk_pp(qa, m_manager) << "\ncost: " << e.m_cost << "\n";); + tout << "lazy quantifier instantiation...\n" << mk_pp(static_cast(e.m_qb->get_data()), m_manager) << "\ncost: " << e.m_cost << "\n";); result = false; m_instantiated_trail.push_back(i); m_stats.m_num_lazy_instances++; diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 86593b0f2ce..e3c2be12320 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -99,9 +99,10 @@ namespace smt { This method may update m_antecedents, m_todo_js and m_todo_eqs. */ void conflict_resolution::eq_justification2literals(enode * lhs, enode * rhs, eq_justification js) { - ast_manager& m = get_manager(); SASSERT(m_antecedents); - TRACE("conflict_detail", tout << mk_pp(lhs->get_owner(), m) << " = " << mk_pp(rhs->get_owner(), m); + TRACE("conflict_detail", + ast_manager& m = get_manager(); + tout << mk_pp(lhs->get_owner(), m) << " = " << mk_pp(rhs->get_owner(), m); switch (js.get_kind()) { case eq_justification::AXIOM: tout << " axiom\n"; break; case eq_justification::EQUATION: diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 7d07f39971a..07f4440ff5c 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -2259,6 +2259,7 @@ namespace smt { } unsigned ilvl = 0; + (void)ilvl; for (unsigned j = 0; j < num; j++) { expr * atom = cls->get_atom(j); bool sign = cls->get_atom_sign(j); @@ -2855,8 +2856,7 @@ namespace smt { propagate(); if (was_consistent && inconsistent()) { // logical context became inconsistent during user PUSH - bool res = resolve_conflict(); // build the proof - SASSERT(!res); + VERIFY(!resolve_conflict()); // build the proof } push_scope(); m_base_scopes.push_back(base_scope()); @@ -3110,8 +3110,7 @@ namespace smt { else { TRACE("after_internalization", display(tout);); if (inconsistent()) { - bool res = resolve_conflict(); // build the proof - SASSERT(!res); + VERIFY(!resolve_conflict()); // build the proof r = l_false; } else { @@ -3197,8 +3196,7 @@ namespace smt { init_assumptions(num_assumptions, assumptions); TRACE("after_internalization", display(tout);); if (inconsistent()) { - bool res = resolve_conflict(); // build the proof - SASSERT(!res); + VERIFY(!resolve_conflict()); // build the proof mk_unsat_core(); r = l_false; } diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 1f8f6dabe50..5dc0dd8ecaf 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -2899,15 +2899,16 @@ namespace smt { } bool check_satisfied_residue_invariant() { - qsset::iterator it = m_satisfied.begin(); - qsset::iterator end = m_satisfied.end(); - for (; it != end; ++it) { - quantifier * q = *it; - SASSERT(!m_residue.contains(q)); - quantifier_info * qi = get_qinfo(q); - SASSERT(qi != 0); - SASSERT(qi->get_the_one() != 0); - } + DEBUG_CODE( + qsset::iterator it = m_satisfied.begin(); + qsset::iterator end = m_satisfied.end(); + for (; it != end; ++it) { + quantifier * q = *it; + SASSERT(!m_residue.contains(q)); + quantifier_info * qi = get_qinfo(q); + SASSERT(qi != 0); + SASSERT(qi->get_the_one() != 0); + }); return true; } @@ -3544,14 +3545,10 @@ namespace smt { // // Since we only care about q (and its bindings), it only makes sense to restrict the variables of q. bool asserted_something = false; - quantifier * flat_q = get_flat_quantifier(q); unsigned num_decls = q->get_num_decls(); - unsigned flat_num_decls = flat_q->get_num_decls(); - unsigned num_sks = sks.size(); // Remark: sks were created for the flat version of q. - SASSERT(num_sks == flat_num_decls); - SASSERT(flat_num_decls >= num_decls); - SASSERT(num_sks >= num_decls); + SASSERT(get_flat_quantifier(q)->get_num_decls() == sks.size()); + SASSERT(sks.size() >= num_decls); for (unsigned i = 0; i < num_decls; i++) { expr * sk = sks.get(num_decls - i - 1); instantiation_set const * s = get_uvar_inst_set(q, i); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 72004f8b020..163452d47c4 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -813,7 +813,7 @@ namespace smt { continue; if (proofs_enabled()) { new_bound.push_lit(l, ante.lit_coeffs()[i]); - } + } else { new_bound.push_lit(l, numeral::zero()); lits.insert(l.index()); @@ -1342,6 +1342,7 @@ namespace smt { tout << "v" << x_i << " "; tout << (has_shared?"shared":"not shared") << "\n";); + (void) empty_column; SASSERT(!safe_gain(min_gain, max_gain) || empty_column || (unbounded_gain(max_gain) == (x_i == null_theory_var))); @@ -1784,7 +1785,7 @@ namespace smt { template typename theory_arith::max_min_t theory_arith::max_min(theory_var v, bool max, bool maintain_integrality, bool& has_shared) { expr* e = get_enode(v)->get_owner(); - + (void)e; SASSERT(!maintain_integrality || valid_assignment()); SASSERT(satisfy_bounds()); SASSERT(!is_quasi_base(v)); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 8a83b93bdf3..95c7fdfad50 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -1866,7 +1866,7 @@ namespace smt { template template void theory_arith::pivot(theory_var x_i, theory_var x_j, numeral const & a_ij, bool apply_gcd_test) { - TRACE("arith_pivot", tout << "pivoting: v" << x_i << ", v" << x_j << "\n";); + TRACE("arith_pivoting", tout << "pivoting: v" << x_i << ", v" << x_j << "\n";); m_stats.m_pivots++; SASSERT(is_base(x_i) || is_quasi_base(x_i)); SASSERT(x_i != x_j); @@ -2067,14 +2067,14 @@ namespace smt { theory_var max = get_num_vars(); theory_var result = max; row const & r = m_rows[get_var_row(x_i)]; - int n; int best_col_sz = INT_MAX; int best_so_far = INT_MAX; - - typename vector::const_iterator it = r.begin_entries(); + int n = 0; + typename vector::const_iterator it = r.begin_entries(); typename vector::const_iterator end = r.end_entries(); - - for (; it != end; ++it) { + + for (; it != end; ++it) { + if (!it->is_dead()) { theory_var x_j = it->m_var; numeral const & a_ij = it->m_coeff; @@ -2090,14 +2090,14 @@ namespace smt { best_so_far = num; best_col_sz = col_sz; n = 1; - } + } else if (num == best_so_far && col_sz == best_col_sz) { n++; if (m_random()%n == 0) { result = x_j; out_a_ij = a_ij; } - } + } } } } @@ -2174,6 +2174,7 @@ namespace smt { inf_numeral curr_error; typename var_heap::iterator it = m_to_patch.begin(); typename var_heap::iterator end = m_to_patch.end(); + //unsigned n = 0; for (; it != end; ++it) { theory_var v = *it; if (below_lower(v)) @@ -2188,7 +2189,16 @@ namespace smt { << ", best_error: " << best_error << ", curr_error: " << curr_error << "\n";); best = v; best_error = curr_error; + //n = 2; + } +#if 0 + else if (false && n > 0 && curr_error == best_error) { + n++; + if (m_random()%n == 0) { + best = v; + } } +#endif } if (best == null_theory_var) m_to_patch.clear(); // all variables are satisfied diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index c60efe1b1f7..5e0539787df 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -75,8 +75,7 @@ namespace smt { ast_manager& m = get_manager(); context& ctx = get_context(); theory_var r = theory_array_base::mk_var(n); - theory_var r2 = m_find.mk_var(); - SASSERT(r == r2); + VERIFY(r == static_cast(m_find.mk_var())); SASSERT(r == static_cast(m_var_data.size())); m_var_data.push_back(alloc(var_data)); var_data * d = m_var_data[r]; diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 3d6e341fae5..2945c8c9355 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -457,8 +457,7 @@ namespace smt { void theory_bv::fixed_var_eh(theory_var v) { numeral val; - bool r = get_fixed_value(v, val); - SASSERT(r); + VERIFY(get_fixed_value(v, val)); unsigned sz = get_bv_size(v); value_sort_pair key(val, sz); theory_var v2; @@ -554,9 +553,8 @@ namespace smt { void theory_bv::internalize_bv2int(app* n) { SASSERT(!get_context().e_internalized(n)); - ast_manager & m = get_manager(); context& ctx = get_context(); - TRACE("bv", tout << mk_bounded_pp(n, m) << "\n";); + TRACE("bv", tout << mk_bounded_pp(n, get_manager()) << "\n";); process_args(n); mk_enode(n); if (!ctx.relevancy()) { @@ -1142,9 +1140,8 @@ namespace smt { } void theory_bv::assign_eh(bool_var v, bool is_true) { - context & ctx = get_context(); atom * a = get_bv2a(v); - TRACE("bv", tout << "assert: v" << v << " #" << ctx.bool_var2expr(v)->get_id() << " is_true: " << is_true << "\n";); + TRACE("bv", tout << "assert: v" << v << " #" << get_context().bool_var2expr(v)->get_id() << " is_true: " << is_true << "\n";); if (a->is_bit()) { // The following optimization is not correct. // Boolean variables created for performing bit-blasting are reused. diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 02b8f9514ff..8e140661bf9 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -198,8 +198,7 @@ namespace smt { theory_var theory_datatype::mk_var(enode * n) { theory_var r = theory::mk_var(n); - theory_var r2 = m_find.mk_var(); - SASSERT(r == r2); + VERIFY(r == static_cast(m_find.mk_var())); SASSERT(r == static_cast(m_var_data.size())); m_var_data.push_back(alloc(var_data)); var_data * d = m_var_data[r]; diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index cca78e9c0e4..98f94c6d28a 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -273,8 +273,7 @@ bool theory_diff_logic::internalize_atom(app * n, bool gate_ctx) { template void theory_diff_logic::internalize_eq_eh(app * atom, bool_var v) { context & ctx = get_context(); - ast_manager& m = get_manager(); - TRACE("arith", tout << mk_pp(atom, m) << "\n";); + TRACE("arith", tout << mk_pp(atom, get_manager()) << "\n";); app * lhs = to_app(atom->get_arg(0)); app * rhs = to_app(atom->get_arg(1)); app * s; @@ -606,7 +605,6 @@ void theory_diff_logic::new_edge(dl_var src, dl_var dst, unsigned num_edges atom* a = 0; m_bool_var2atom.find(bv, a); SASSERT(a); - edge_id e_id = a->get_pos(); literal_vector lits; for (unsigned i = 0; i < num_edges; ++i) { @@ -616,7 +614,7 @@ void theory_diff_logic::new_edge(dl_var src, dl_var dst, unsigned num_edges TRACE("dl_activity", tout << mk_pp(le, get_manager()) << "\n"; - tout << "edge: " << e_id << "\n"; + tout << "edge: " << a->get_pos() << "\n"; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n"; ); @@ -927,18 +925,19 @@ void theory_diff_logic::display(std::ostream & out) const { template bool theory_diff_logic::is_consistent() const { - context& ctx = get_context(); - for (unsigned i = 0; i < m_atoms.size(); ++i) { - atom* a = m_atoms[i]; - bool_var bv = a->get_bool_var(); - lbool asgn = ctx.get_assignment(bv); - if (ctx.is_relevant(ctx.bool_var2expr(bv)) && asgn != l_undef) { - SASSERT((asgn == l_true) == a->is_true()); - int edge_id = a->get_asserted_edge(); - SASSERT(m_graph.is_enabled(edge_id)); - SASSERT(m_graph.is_feasible(edge_id)); - } - } + DEBUG_CODE( + context& ctx = get_context(); + for (unsigned i = 0; i < m_atoms.size(); ++i) { + atom* a = m_atoms[i]; + bool_var bv = a->get_bool_var(); + lbool asgn = ctx.get_assignment(bv); + if (ctx.is_relevant(ctx.bool_var2expr(bv)) && asgn != l_undef) { + SASSERT((asgn == l_true) == a->is_true()); + int edge_id = a->get_asserted_edge(); + SASSERT(m_graph.is_enabled(edge_id)); + SASSERT(m_graph.is_feasible(edge_id)); + } + }); return m_graph.is_feasible(); } @@ -1194,9 +1193,9 @@ theory_diff_logic::maximize(theory_var v, expr_ref& blocker, bool& has_shar ast_manager& m = get_manager(); update_simplex(S); - objective_term const& objective = m_objectives[v]; TRACE("arith", + objective_term const& objective = m_objectives[v]; for (unsigned i = 0; i < objective.size(); ++i) { tout << "Coefficient " << objective[i].second << " of theory_var " << objective[i].first << "\n"; diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 23e1f746d01..f2145c85be7 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -52,13 +52,11 @@ 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_fpa_util.get_ebits(s); unsigned sbits = m_th.m_fpa_util.get_sbits(s); - SASSERT(bv_sz == ebits + sbits); - m_th.m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), - m_bv_util.mk_extract(sbits - 2, 0, bv), - result); + SASSERT(bv_sz == m_th.m_fpa_util.get_ebits(s) + sbits); + result = m_util.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)); SASSERT(m_th.m_fpa_util.is_float(result)); m_const2bv.insert(f, result); m.inc_ref(f); @@ -77,62 +75,32 @@ namespace smt { SASSERT(is_rm(f->get_range())); expr_ref bv(m); bv = m_th.wrap(m.mk_const(f)); - mk_rm(bv, result); + result = m_util.mk_bv2rm(bv); m_rm_const2bv.insert(f, result); m.inc_ref(f); m.inc_ref(result); } } - void theory_fpa::fpa2bv_converter_wrapped::mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - // TODO: This introduces temporary variables/func_decls that should be filtered in the end. - fpa2bv_converter::mk_uninterpreted_function(f, num, args, result); + void theory_fpa::fpa2bv_converter_wrapped::mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + // Note: this introduces new UFs that should be filtered afterwards. + return fpa2bv_converter::mk_function(f, num, args, result); } - expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_min_unspecified(func_decl * f, expr * x, expr * y) { - // The only cases in which min is unspecified for is when the arguments are +0.0 and -0.0. - unsigned ebits = m_util.get_ebits(f->get_range()); - unsigned sbits = m_util.get_sbits(f->get_range()); - unsigned bv_sz = ebits + sbits; - expr_ref res(m); + expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_min_max_unspecified(func_decl * f, expr * x, expr * y) { - expr * args[] = { x, y }; - func_decl * w = m.mk_func_decl(m_th.get_family_id(), OP_FPA_INTERNAL_MIN_UNSPECIFIED, 0, 0, 2, args, f->get_range()); - expr_ref a(m), wrapped(m); - a = m.mk_app(w, x, y); + expr_ref a(m), wrapped(m), wu(m), wu_eq(m); + a = m.mk_app(f, x, y); wrapped = m_th.wrap(a); - m_th.m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, wrapped), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, wrapped), - m_bv_util.mk_extract(sbits - 2, 0, wrapped), - res); + wu = m_th.unwrap(wrapped, f->get_range()); + wu_eq = m.mk_eq(wu, a); + m_extra_assertions.push_back(wu_eq); expr_ref sc(m); - m_th.m_converter.mk_is_zero(res, sc); + m_th.m_converter.mk_is_zero(wu, sc); m_extra_assertions.push_back(sc); - return res; - } - expr_ref theory_fpa::fpa2bv_converter_wrapped::mk_max_unspecified(func_decl * f, expr * x, expr * y) { - // The only cases in which max is unspecified for is when the arguments are +0.0 and -0.0. - unsigned ebits = m_util.get_ebits(f->get_range()); - unsigned sbits = m_util.get_sbits(f->get_range()); - unsigned bv_sz = ebits + sbits; - expr_ref res(m); - - expr * args[] = { x, y }; - func_decl * w = m.mk_func_decl(m_th.get_family_id(), OP_FPA_INTERNAL_MAX_UNSPECIFIED, 0, 0, 2, args, f->get_range()); - expr_ref a(m), wrapped(m); - a = m.mk_app(w, x, y); - wrapped = m_th.wrap(a); - m_th.m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, wrapped), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, wrapped), - m_bv_util.mk_extract(sbits - 2, 0, wrapped), - res); - - expr_ref sc(m); - m_th.m_converter.mk_is_zero(res, sc); - m_extra_assertions.push_back(sc); - return res; + return wu; } theory_fpa::theory_fpa(ast_manager & m) : @@ -159,12 +127,10 @@ namespace smt { 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); } else { SASSERT(m_conversions.empty()); SASSERT(m_wraps.empty()); - SASSERT(m_unwraps.empty()); } m_is_initialized = false; @@ -176,10 +142,10 @@ namespace smt { } app * theory_fpa::fpa_value_proc::mk_value(model_generator & mg, ptr_vector & values) { - ast_manager & m = m_th.get_manager(); - - TRACE("t_fpa_detail", for (unsigned i = 0; i < values.size(); i++) - tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;); + TRACE("t_fpa_detail", + ast_manager & m = m_th.get_manager(); + 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_mpz_manager & mpzm = mpfm.mpz_manager(); @@ -199,8 +165,7 @@ namespace smt { rational all_r(0); scoped_mpz all_z(mpzm); - bool r = m_bu.is_numeral(values[0], all_r, bv_sz); - SASSERT(r); + VERIFY(m_bu.is_numeral(values[0], all_r, bv_sz)); SASSERT(bv_sz == (m_ebits + m_sbits)); SASSERT(all_r.is_int()); mpzm.set(all_z, all_r.to_mpq().numerator()); @@ -222,6 +187,7 @@ namespace smt { SASSERT(r && bv_sz == m_ebits); r = m_bu.is_numeral(values[2], sig_r, bv_sz); SASSERT(r && bv_sz == m_sbits - 1); + (void)r; SASSERT(mpzm.is_one(sgn_r.to_mpq().denominator())); SASSERT(mpzm.is_one(exp_r.to_mpq().denominator())); @@ -241,28 +207,28 @@ namespace smt { mpfm.set(f, m_ebits, m_sbits, mpzm.is_one(sgn_z), mpzm.get_int64(exp_u), sig_z); result = m_fu.mk_value(f); - TRACE("t_fpa", tout << "fpa_value_proc::mk_value [" << + TRACE("t_fpa", tout << "result: [" << mpzm.to_string(sgn_z) << "," << mpzm.to_string(exp_z) << "," << mpzm.to_string(sig_z) << "] --> " << - mk_ismt2_pp(result, m_th.get_manager()) << "\n";); + mk_ismt2_pp(result, m_th.get_manager()) << std::endl;); return result; } app * theory_fpa::fpa_rm_value_proc::mk_value(model_generator & mg, ptr_vector & values) { SASSERT(values.size() == 1); - ast_manager & m = m_th.get_manager(); - TRACE("t_fpa_detail", for (unsigned i = 0; i < values.size(); i++) + TRACE("t_fpa_detail", + ast_manager & m = m_th.get_manager(); + for (unsigned i = 0; i < values.size(); i++) tout << "value[" << i << "] = " << mk_ismt2_pp(values[i], m) << std::endl;); app * result = 0; unsigned bv_sz; rational val(0); - bool r = m_bu.is_numeral(values[0], val, bv_sz); - SASSERT(r); + VERIFY(m_bu.is_numeral(values[0], val, bv_sz)); SASSERT(bv_sz == 3); switch (val.get_uint64()) @@ -275,64 +241,82 @@ namespace smt { 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 << "result: " << mk_ismt2_pp(result, m_th.get_manager()) << std::endl;); return result; } app_ref theory_fpa::wrap(expr * e) { - SASSERT(!m_fpa_util.is_wrap(e)); + SASSERT(m_fpa_util.is_float(e) || m_fpa_util.is_rm(e)); + SASSERT(!m_fpa_util.is_bvwrap(e)); ast_manager & m = get_manager(); - sort * e_srt = m.get_sort(e); + app_ref res(m); - func_decl *w; + if (m_fpa_util.is_fp(e)) { + expr * cargs[3] = { to_app(e)->get_arg(0), to_app(e)->get_arg(1), to_app(e)->get_arg(2) }; + res = m_bv_util.mk_concat(3, cargs); + m_th_rw((expr_ref&)res); + } + else { + sort * e_srt = m.get_sort(e); + func_decl * w; - if (!m_wraps.find(e_srt, w)) { - SASSERT(!m_wraps.contains(e_srt)); + if (!m_wraps.find(e_srt, w)) { + SASSERT(!m_wraps.contains(e_srt)); + + sort * bv_srt; + if (m_converter.is_rm(e_srt)) + bv_srt = m_bv_util.mk_sort(3); + else { + SASSERT(m_converter.is_float(e_srt)); + unsigned ebits = m_fpa_util.get_ebits(e_srt); + unsigned sbits = m_fpa_util.get_sbits(e_srt); + bv_srt = m_bv_util.mk_sort(ebits + sbits); + } - sort * bv_srt; - if (m_converter.is_rm(e_srt)) - bv_srt = m_bv_util.mk_sort(3); - else { - SASSERT(m_converter.is_float(e_srt)); - unsigned ebits = m_fpa_util.get_ebits(e_srt); - unsigned sbits = m_fpa_util.get_sbits(e_srt); - bv_srt = m_bv_util.mk_sort(ebits + sbits); + w = m.mk_func_decl(get_family_id(), OP_FPA_INTERNAL_BVWRAP, 0, 0, 1, &e_srt, bv_srt); + m_wraps.insert(e_srt, w); + m.inc_ref(w); } - 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); + res = m.mk_app(w, e); } - 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(); - sort * bv_srt = m.get_sort(e); + SASSERT(!m_fpa_util.is_fp(e)); + SASSERT(m_bv_util.is_bv(e)); + SASSERT(m_fpa_util.is_float(s) || m_fpa_util.is_rm(s)); + ast_manager & m = get_manager(); + app_ref res(m); - func_decl *u; + unsigned bv_sz = m_bv_util.get_bv_size(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(bv_srt, u); - m.inc_ref(u); + if (m_fpa_util.is_rm(s)) { + SASSERT(bv_sz == 3); + res = m.mk_ite(m.mk_eq(e, m_bv_util.mk_numeral(BV_RM_TIES_TO_AWAY, 3)), m_fpa_util.mk_round_nearest_ties_to_away(), + m.mk_ite(m.mk_eq(e, m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3)), m_fpa_util.mk_round_nearest_ties_to_even(), + m.mk_ite(m.mk_eq(e, m_bv_util.mk_numeral(BV_RM_TO_NEGATIVE, 3)), m_fpa_util.mk_round_toward_negative(), + m.mk_ite(m.mk_eq(e, m_bv_util.mk_numeral(BV_RM_TO_POSITIVE, 3)), m_fpa_util.mk_round_toward_positive(), + m_fpa_util.mk_round_toward_zero())))); } - - app_ref res(m); - res = m.mk_app(u, e); + else { + SASSERT(m_fpa_util.is_float(s)); + unsigned sbits = m_fpa_util.get_sbits(s); + SASSERT(bv_sz == m_fpa_util.get_ebits(s) + sbits); + res = m_fpa_util.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, e), + m_bv_util.mk_extract(bv_sz - 2, sbits - 1, e), + m_bv_util.mk_extract(sbits - 2, 0, e)); + } + return res; } expr_ref theory_fpa::convert_atom(expr * e) { ast_manager & m = get_manager(); - TRACE("t_fpa_detail", tout << "converting atom: " << mk_ismt2_pp(e, get_manager()) << "\n";); + TRACE("t_fpa_detail", tout << "converting atom: " << mk_ismt2_pp(e, get_manager()) << std::endl;); expr_ref res(m); proof_ref pr(m); m_rw(e, res); @@ -350,133 +334,39 @@ namespace smt { proof_ref pr(m); m_rw(e, e_conv); - if (is_app(e_conv) && to_app(e_conv)->get_family_id() != get_family_id()) { - if (!m_fpa_util.is_float(e_conv)) - m_th_rw(e_conv, res); - else { - expr_ref bv(m); - bv = wrap(e_conv); - unsigned bv_sz = m_bv_util.get_bv_size(bv); - unsigned ebits = m_fpa_util.get_ebits(m.get_sort(e_conv)); - unsigned sbits = m_fpa_util.get_sbits(m.get_sort(e_conv)); - SASSERT(bv_sz == ebits + sbits); - 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); - } - } - else if (m_fpa_util.is_rm(e)) { - SASSERT(is_app_of(e_conv, get_family_id(), OP_FPA_INTERNAL_RM)); + TRACE("t_fpa_detail", tout << "term: " << mk_ismt2_pp(e, get_manager()) << std::endl; + tout << "converted term: " << mk_ismt2_pp(e_conv, get_manager()) << std::endl;); + + if (m_fpa_util.is_rm(e)) { + SASSERT(m_fpa_util.is_bv2rm(e_conv)); expr_ref bv_rm(m); - bv_rm = to_app(e_conv)->get_arg(0); - m_th_rw(bv_rm); - m_converter.mk_rm(bv_rm, res); + m_th_rw(to_app(e_conv)->get_arg(0), bv_rm); + res = m_fpa_util.mk_bv2rm(bv_rm); } else if (m_fpa_util.is_float(e)) { - SASSERT(is_app_of(e_conv, get_family_id(), OP_FPA_FP)); + SASSERT(m_fpa_util.is_fp(e_conv)); 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); + res = m_fpa_util.mk_fp(sgn, exp, sig); } else UNREACHABLE(); - - SASSERT(res.get() != 0); + return res; } -#if 0 - expr_ref theory_fpa::convert_uf(expr * e) { - SASSERT(is_app(e)); - ast_manager & m = get_manager(); - expr_ref res(m); - - app * a = to_app(e); - func_decl * f = a->get_decl(); - sort * const * domain = f->get_domain(); - unsigned arity = f->get_arity(); - - expr_ref_buffer new_args(m); - expr_ref unwrapped(m); - - for (unsigned i = 0; i < arity; i++) { - expr * ai = a->get_arg(i); - if (m_fpa_util.is_float(ai) || m_fpa_util.is_rm(ai)) { - if (m_fpa_util.is_unwrap(ai)) - unwrapped = ai; - else { - // unwrapped = unwrap(wrap(ai), domain[i]); - // assert_cnstr(m.mk_eq(unwrapped, ai)); - // assert_cnstr(); - unwrapped = convert_term(ai); - } - - new_args.push_back(unwrapped); - TRACE("t_fpa_detail", tout << "UF arg(" << i << ") = " << mk_ismt2_pp(unwrapped, get_manager()) << "\n";); - } - else - new_args.push_back(ai); - } - - sort * rng = f->get_range(); - if (m_fpa_util.is_float(rng)) { - unsigned sbits = m_fpa_util.get_sbits(rng); - unsigned bv_sz = m_fpa_util.get_ebits(rng) + sbits; - expr_ref wrapped(m); - wrapped = wrap(m.mk_app(f, new_args.size(), new_args.c_ptr())); - - m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, wrapped), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, wrapped), - m_bv_util.mk_extract(sbits - 2, 0, wrapped), - res); - } - else - res = m.mk_app(f, new_args.size(), new_args.c_ptr()); - - TRACE("t_fpa_detail", tout << "UF call = " << mk_ismt2_pp(res, get_manager()) << "\n";); - return res; - } -#endif - expr_ref theory_fpa::convert_conversion_term(expr * e) { + SASSERT(to_app(e)->get_family_id() == get_family_id()); /* This is for the conversion functions fp.to_* */ - ast_manager & m = get_manager(); - expr_ref res(m); - proof_ref pr(m); - - SASSERT(m_arith_util.is_real(e) || m_bv_util.is_bv(e)); - + expr_ref res(get_manager()); m_rw(e, res); m_th_rw(res, res); return res; } - expr_ref theory_fpa::convert_unwrap(expr * e) { - SASSERT(m_fpa_util.is_unwrap(e)); - ast_manager & m = get_manager(); - sort * srt = m.get_sort(e); - expr_ref res(m); - if (m_fpa_util.is_rm(srt)) { - m_converter.mk_rm(to_app(e)->get_arg(0), res); - } - else { - SASSERT(m_fpa_util.is_float(srt)); - unsigned sbits = m_fpa_util.get_sbits(srt); - expr_ref bv(m); - bv = to_app(e)->get_arg(0); - unsigned bv_sz = m_bv_util.get_bv_size(bv); - m_converter.mk_fp(m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv), - m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv), - m_bv_util.mk_extract(sbits - 2, 0, bv), - res); - } - return res; - } - expr_ref theory_fpa::convert(expr * e) { ast_manager & m = get_manager(); @@ -491,16 +381,14 @@ namespace smt { mk_ismt2_pp(res, m) << std::endl;); } else { - if (m_fpa_util.is_unwrap(e)) - res = convert_unwrap(e); + if (m_fpa_util.is_fp(e)) + res = e; else if (m.is_bool(e)) res = convert_atom(e); else if (m_fpa_util.is_float(e) || m_fpa_util.is_rm(e)) res = convert_term(e); - else if (m_arith_util.is_real(e) || m_bv_util.is_bv(e)) + else res = convert_conversion_term(e); - else - UNREACHABLE(); TRACE("t_fpa_detail", tout << "converted; caching:" << std::endl; tout << mk_ismt2_pp(e, m) << std::endl << " -> " << std::endl << @@ -534,7 +422,7 @@ namespace smt { m_th_rw(res); - CTRACE("t_fpa", !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) << std::endl;); return res; } @@ -546,18 +434,17 @@ namespace smt { literal lit(ctx.get_literal(e)); ctx.mark_as_relevant(lit); ctx.mk_th_axiom(get_id(), 1, &lit); - TRACE("t_fpa_detail", tout << "done asserting " << mk_ismt2_pp(e, get_manager()) << "\n";); } void theory_fpa::attach_new_th_var(enode * n) { context & ctx = get_context(); theory_var v = mk_var(n); ctx.attach_th_var(n, this, v); - TRACE("t_fpa_detail", tout << "new theory var: " << mk_ismt2_pp(n->get_owner(), get_manager()) << " := " << v << "\n";); + 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";); + TRACE("t_fpa_internalize", tout << "internalizing atom: " << mk_ismt2_pp(atom, get_manager()) << std::endl;); SASSERT(atom->get_family_id() == get_family_id()); ast_manager & m = get_manager(); @@ -582,11 +469,12 @@ namespace smt { } bool theory_fpa::internalize_term(app * term) { + TRACE("t_fpa_internalize", 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", 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++) @@ -595,28 +483,28 @@ 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; - - attach_new_th_var(e); - - // The conversion operators fp.to_* appear in non-FP constraints. - // The corresponding constraints will not be translated and added - // via convert(...) and assert_cnstr(...) in initialize_atom(...). - // Therefore, we translate and assert them here. - fpa_op_kind k = (fpa_op_kind)term->get_decl_kind(); - switch (k) { - case OP_FPA_TO_UBV: - case OP_FPA_TO_SBV: - case OP_FPA_TO_REAL: - case OP_FPA_TO_IEEE_BV: { - expr_ref conv(m); - conv = convert(term); - assert_cnstr(m.mk_eq(term, conv)); - assert_cnstr(mk_side_conditions()); - break; - } - default: /* ignore */; + if (!is_attached_to_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. + fpa_op_kind k = (fpa_op_kind)term->get_decl_kind(); + switch (k) { + case OP_FPA_TO_FP: + case OP_FPA_TO_UBV: + case OP_FPA_TO_SBV: + case OP_FPA_TO_REAL: + case OP_FPA_TO_IEEE_BV: { + expr_ref conv(m); + conv = convert(term); + assert_cnstr(m.mk_eq(term, conv)); + assert_cnstr(mk_side_conditions()); + break; + } + default: /* ignore */; + } } return true; @@ -625,33 +513,30 @@ namespace smt { 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(s->get_family_id() == get_family_id()); + SASSERT(m_fpa_util.is_float(s) || m_fpa_util.is_rm(s)); + SASSERT(m_fpa_util.is_float(n->get_owner()) || m_fpa_util.is_rm(n->get_owner())); + SASSERT(n->get_owner()->get_decl()->get_range() == s); ast_manager & m = get_manager(); - context & ctx = get_context(); - - app_ref owner(m); - owner = n->get_owner(); - - SASSERT(owner->get_decl()->get_range() == s); - - if ((m_fpa_util.is_float(s) || m_fpa_util.is_rm(s)) && - !is_attached_to_var(n)) { + context & ctx = get_context(); + app_ref owner(n->get_owner(), m); + if (!is_attached_to_var(n)) { attach_new_th_var(n); if (m_fpa_util.is_rm(s)) { // 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)) { + if (!m_fpa_util.is_bv2rm(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), s), owner)); + + if (!ctx.relevancy()) + relevant_eh(owner); } } @@ -660,9 +545,9 @@ namespace smt { enode * e_x = get_enode(x); enode * e_y = get_enode(y); - TRACE("t_fpa", tout << "new eq: " << x << " = " << y << std::endl;); - TRACE("t_fpa_detail", tout << mk_ismt2_pp(e_x->get_owner(), m) << " = " << - mk_ismt2_pp(e_y->get_owner(), m) << std::endl;); + TRACE("t_fpa", tout << "new eq: " << x << " = " << y << std::endl; + tout << mk_ismt2_pp(e_x->get_owner(), m) << std::endl << " = " << std::endl << + mk_ismt2_pp(e_y->get_owner(), m) << std::endl;); fpa_util & fu = m_fpa_util; @@ -670,7 +555,7 @@ namespace smt { xe = e_x->get_owner(); ye = e_y->get_owner(); - if (m_fpa_util.is_wrap(xe) || m_fpa_util.is_wrap(ye)) + if (m_fpa_util.is_bvwrap(xe) || m_fpa_util.is_bvwrap(ye)) return; expr_ref xc(m), yc(m); @@ -700,9 +585,9 @@ namespace smt { enode * e_x = get_enode(x); enode * e_y = get_enode(y); - 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;); + TRACE("t_fpa", tout << "new diseq: " << x << " != " << y << std::endl; + tout << mk_ismt2_pp(e_x->get_owner(), m) << std::endl << " != " << std::endl << + mk_ismt2_pp(e_y->get_owner(), m) << std::endl;); fpa_util & fu = m_fpa_util; @@ -710,7 +595,7 @@ namespace smt { xe = e_x->get_owner(); ye = e_y->get_owner(); - if (m_fpa_util.is_wrap(xe) || m_fpa_util.is_wrap(ye)) + if (m_fpa_util.is_bvwrap(xe) || m_fpa_util.is_bvwrap(ye)) return; expr_ref xc(m), yc(m); @@ -746,7 +631,6 @@ namespace smt { void theory_fpa::pop_scope_eh(unsigned num_scopes) { m_trail_stack.pop_scope(num_scopes); TRACE("t_fpa", tout << "pop " << num_scopes << "; now " << m_trail_stack.get_num_scopes() << "\n";); - // unsigned num_old_vars = get_old_num_vars(num_scopes); theory::pop_scope_eh(num_scopes); } @@ -773,7 +657,7 @@ namespace smt { mpf_manager & mpfm = m_fpa_util.fm(); if (m_fpa_util.is_float(n) || m_fpa_util.is_rm(n)) { - if (!m_fpa_util.is_unwrap(n)) { + if (!m_fpa_util.is_fp(n)) { expr_ref wrapped(m), c(m); wrapped = wrap(n); mpf_rounding_mode rm; @@ -794,8 +678,10 @@ namespace smt { assert_cnstr(c); } else { - c = m.mk_eq(unwrap(wrapped, m.get_sort(n)), n); - assert_cnstr(c); + expr_ref wu(m); + wu = m.mk_eq(unwrap(wrapped, m.get_sort(n)), n); + TRACE("t_fpa", tout << "w/u eq: " << std::endl << mk_ismt2_pp(wu, get_manager()) << std::endl;); + assert_cnstr(wu); } } } @@ -818,7 +704,6 @@ namespace smt { 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(); } @@ -831,7 +716,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_value_factory, get_manager(), get_family_id()); - mg.register_factory(m_factory); + mg.register_factory(m_factory); } model_value_proc * theory_fpa::mk_value(enode * n, model_generator & mg) { @@ -863,7 +748,7 @@ namespace smt { " (owner " << (!ctx.e_internalized(owner) ? "not" : "is") << " internalized)" << std::endl;); - if (is_app_of(owner, get_family_id(), OP_FPA_FP)) { + if (m_fpa_util.is_fp(owner)) { SASSERT(to_app(owner)->get_num_args() == 3); app_ref a0(m), a1(m), a2(m); a0 = to_app(owner->get_arg(0)); @@ -881,7 +766,7 @@ namespace smt { mk_ismt2_pp(a2, m) << " eq. cls. #" << get_enode(a2)->get_root()->get_owner()->get_id() << std::endl;); res = vp; } - else if (is_app_of(owner, get_family_id(), OP_FPA_INTERNAL_RM)) { + else if (m_fpa_util.is_bv2rm(owner)) { SASSERT(to_app(owner)->get_num_args() == 1); app_ref a0(m); a0 = to_app(owner->get_arg(0)); @@ -966,4 +851,27 @@ namespace smt { out << r->get_id() << " --> " << mk_ismt2_pp(n, m) << std::endl; } } + + bool theory_fpa::include_func_interp(func_decl * f) { + TRACE("t_fpa", tout << "f = " << mk_ismt2_pp(f, get_manager()) << std::endl;); + + if (f->get_family_id() == get_family_id()) { + bool include = + m_fpa_util.is_min_unspecified(f) || + m_fpa_util.is_max_unspecified(f) || + m_fpa_util.is_to_ubv_unspecified(f) || + m_fpa_util.is_to_sbv_unspecified(f) || + m_fpa_util.is_to_ieee_bv_unspecified(f) || + m_fpa_util.is_to_real_unspecified(f); + if (include && !m_is_added_to_model.contains(f)) { + m_is_added_to_model.insert(f); + return true; + } + return false; + } + else if (m_converter.is_uf2bvuf(f) || m_converter.is_special(f)) + return false; + else + return true; + } }; diff --git a/src/smt/theory_fpa.h b/src/smt/theory_fpa.h index 1b0fc6c54a4..0a3ed94c68d 100644 --- a/src/smt/theory_fpa.h +++ b/src/smt/theory_fpa.h @@ -82,11 +82,10 @@ namespace smt { 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); - virtual void mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + virtual void mk_rm_const(func_decl * f, expr_ref & result); + virtual void mk_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - virtual expr_ref mk_min_unspecified(func_decl * f, expr * x, expr * y); - virtual expr_ref mk_max_unspecified(func_decl * f, expr * x, expr * y); + virtual expr_ref mk_min_max_unspecified(func_decl * f, expr * x, expr * y); }; class fpa_value_proc : public model_value_proc { @@ -112,7 +111,7 @@ namespace smt { result.append(m_deps); } - virtual app * mk_value(model_generator & mg, ptr_vector & values); + virtual app * mk_value(model_generator & mg, ptr_vector & values); }; class fpa_rm_value_proc : public model_value_proc { @@ -145,10 +144,10 @@ namespace smt { fpa_util & m_fpa_util; bv_util & m_bv_util; arith_util & m_arith_util; - obj_map m_wraps; - obj_map m_unwraps; + obj_map m_wraps; obj_map m_conversions; bool m_is_initialized; + obj_hashtable m_is_added_to_model; virtual final_check_status final_check_eh(); virtual bool internalize_atom(app * atom, bool gate_ctx); @@ -163,6 +162,7 @@ namespace smt { virtual char const * get_name() const { return "fpa"; } virtual model_value_proc * mk_value(enode * n, model_generator & mg); + virtual bool include_func_interp(func_decl * f); void assign_eh(bool_var v, bool is_true); virtual void relevant_eh(app * n); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index a1aebf3e1b8..a85f9aa8097 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -787,8 +787,7 @@ namespace smt { } for (unsigned i = 0; i < ineqs->size(); ++i) { - ineq* c = (*ineqs)[i]; - SASSERT(c->is_ge()); + SASSERT((*ineqs)[i]->is_ge()); if (assign_watch_ge(v, is_true, *ineqs, i)) { // i was removed from watch list. --i; @@ -1064,7 +1063,7 @@ namespace smt { } #endif else { - IF_VERBOSE(3, display(verbose_stream() << "no propagation ", c, true);); + IF_VERBOSE(14, display(verbose_stream() << "no propagation ", c, true);); } } @@ -1638,7 +1637,7 @@ namespace smt { // same order as the assignment stack. // It is not a correctness bug but causes to miss lemmas. // - IF_VERBOSE(2, display_resolved_lemma(verbose_stream());); + IF_VERBOSE(12, display_resolved_lemma(verbose_stream());); TRACE("pb", display_resolved_lemma(tout);); return false; } @@ -1736,12 +1735,12 @@ namespace smt { // 3x + 3y + z + u >= 4 // ~x /\ ~y => z + u >= - IF_VERBOSE(4, display(verbose_stream() << "lemma1: ", m_lemma);); + IF_VERBOSE(14, display(verbose_stream() << "lemma1: ", m_lemma);); hoist_maximal_values(); lbool is_true = m_lemma.normalize(false); m_lemma.prune(false); - IF_VERBOSE(4, display(verbose_stream() << "lemma2: ", m_lemma);); + IF_VERBOSE(14, display(verbose_stream() << "lemma2: ", m_lemma);); //unsigned l_size = m_ineq_literals.size() + ((is_true==l_false)?0:m_lemma.size()); //if (s_min_l_size >= l_size) { // verbose_stream() << "(pb.conflict min size: " << l_size << ")\n"; @@ -1834,13 +1833,12 @@ namespace smt { void theory_pb::validate_assign(ineq const& c, literal_vector const& lits, literal l) const { uint_set nlits; - context& ctx = get_context(); for (unsigned i = 0; i < lits.size(); ++i) { - SASSERT(ctx.get_assignment(lits[i]) == l_true); + SASSERT(get_context().get_assignment(lits[i]) == l_true); nlits.insert((~lits[i]).index()); } - SASSERT(ctx.get_assignment(l) == l_undef); - SASSERT(ctx.get_assignment(c.lit()) == l_true); + SASSERT(get_context().get_assignment(l) == l_undef); + SASSERT(get_context().get_assignment(c.lit()) == l_true); nlits.insert(l.index()); numeral sum = numeral::zero(); for (unsigned i = 0; i < c.size(); ++i) { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index a8811b1793a..8a1ee29461d 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1830,6 +1830,7 @@ bool theory_seq::solve_ne(unsigned idx) { } else { + if (!updated) { for (unsigned j = 0; j < i; ++j) { new_ls.push_back(n.ls(j)); @@ -1933,6 +1934,7 @@ bool theory_seq::solve_ne(unsigned idx) { return updated; } + bool theory_seq::solve_nc(unsigned idx) { nc const& n = m_ncs[idx]; @@ -2212,7 +2214,6 @@ bool theory_seq::add_itos_axiom(expr* e) { if (get_value(n, val)) { if (!m_itos_axioms.contains(val)) { m_itos_axioms.insert(val); - app_ref e1(m_util.str.mk_string(symbol(val.to_string().c_str())), m); expr_ref n1(arith_util(m).mk_numeral(val, true), m); add_axiom(mk_eq(m_util.str.mk_itos(n1), e1, false)); @@ -2380,7 +2381,7 @@ void theory_seq::init_model(expr_ref_vector const& es) { } void theory_seq::init_model(model_generator & mg) { - m_factory = alloc(seq_factory, get_manager(), get_family_id()); + m_factory = alloc(seq_factory, get_manager(), get_family_id(), mg.get_model()); mg.register_factory(m_factory); for (unsigned j = 0; j < m_nqs.size(); ++j) { ne const& n = m_nqs[j]; @@ -2469,7 +2470,9 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { for (unsigned i = 0; i < concats.size(); ++i) { expr* c = concats[i], *c1; if (m_util.str.is_unit(c, c1)) { - sv->add_dependency(ctx.get_enode(c1)); + if (ctx.e_internalized(c1)) { + sv->add_dependency(ctx.get_enode(c1)); + } } else if (m_util.str.is_string(c)) { sv->add_string(c); @@ -2578,6 +2581,7 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { } expr* e = m_rep.find(e0, deps); expr* e1, *e2, *e3; + context& ctx = get_context(); if (m_util.str.is_concat(e, e1, e2)) { result = mk_concat(expand(e1, deps), expand(e2, deps)); } @@ -2602,6 +2606,47 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { else if (m_util.str.is_index(e, e1, e2, e3)) { result = m_util.str.mk_index(expand(e1, deps), expand(e2, deps), e3); } + else if (m.is_ite(e, e1, e2, e3)) { + literal lit(mk_literal(e1)); + switch (ctx.get_assignment(lit)) { + case l_true: + deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(lit))); + result = expand(e2, deps); + break; + case l_false: + deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(~lit))); + result = expand(e3, deps); + break; + case l_undef: + result = e; + break; + } + } + else if (m_util.str.is_itos(e, e1)) { + rational val; + if (get_value(e1, val)) { + expr_ref num(m), res(m); + num = m_autil.mk_numeral(val, true); + if (!ctx.e_internalized(num)) { + ctx.internalize(num, false); + } + enode* n1 = ctx.get_enode(num); + enode* n2 = ctx.get_enode(e1); + res = m_util.str.mk_string(symbol(val.to_string().c_str())); + if (n1->get_root() == n2->get_root()) { + result = res; + deps = m_dm.mk_join(deps, m_dm.mk_leaf(assumption(n1, n2))); + } + else { + add_axiom(~mk_eq(num, e1, false), mk_eq(e, res, false)); + add_axiom(mk_eq(num, e1, false), ~mk_eq(e, res, false)); + result = e; + } + } + else { + result = e; + } + } else { result = e; } @@ -2821,6 +2866,7 @@ void theory_seq::add_elim_string_axiom(expr* n) { - len(unit(u)) = 1 if x = unit(u) - len(str) = str.length() if x = str - len(empty) = 0 if x = empty + - len(int.to.str(i)) >= 1 if x = int.to.str(i) and more generally if i = 0 then 1 else 1+floor(log(|i|)) - len(x) >= 0 otherwise */ void theory_seq::add_length_axiom(expr* n) { @@ -2835,16 +2881,17 @@ void theory_seq::add_length_axiom(expr* n) { m_rewrite(len); SASSERT(n != len); add_axiom(mk_eq(len, n, false)); - if (!ctx.at_base_level()) { - m_trail_stack.push(push_replay(alloc(replay_axiom, m, n))); - } + } + else if (m_util.str.is_itos(x)) { + add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(1)))); } else { add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0)))); - if (!ctx.at_base_level()) { - m_trail_stack.push(push_replay(alloc(replay_axiom, m, n))); - } } + if (!ctx.at_base_level()) { + m_trail_stack.push(push_replay(alloc(replay_axiom, m, n))); + } + } @@ -3181,8 +3228,7 @@ void theory_seq::add_at_axiom(expr* e) { step(s, idx, re, i, j, t) -> nth(s, idx) == t & len(s) > idx */ void theory_seq::propagate_step(literal lit, expr* step) { - context& ctx = get_context(); - SASSERT(ctx.get_assignment(lit) == l_true); + SASSERT(get_context().get_assignment(lit) == l_true); expr* re, *acc, *s, *idx, *i, *j; VERIFY(is_step(step, s, idx, re, i, j, acc)); TRACE("seq", tout << mk_pp(step, m) << " -> " << mk_pp(acc, m) << "\n";); @@ -3202,9 +3248,8 @@ void theory_seq::propagate_step(literal lit, expr* step) { lit => s = (nth s 0) ++ (nth s 1) ++ ... ++ (nth s idx) ++ (tail s idx) */ void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) { - context& ctx = get_context(); rational r; - SASSERT(ctx.get_assignment(lit) == l_true); + SASSERT(get_context().get_assignment(lit) == l_true); VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); unsigned _idx = r.get_unsigned(); expr_ref head(m), tail(m), conc(m), len1(m), len2(m); @@ -3680,7 +3725,6 @@ expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned rej(s, idx, re, i) -> len(s) > idx if i is final */ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { - context& ctx = get_context(); expr *s, * idx, *re; unsigned src; eautomaton* aut = 0; @@ -3691,7 +3735,7 @@ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { } if (m_util.str.is_length(idx)) return; SASSERT(m_autil.is_numeral(idx)); - SASSERT(ctx.get_assignment(lit) == l_true); + SASSERT(get_context().get_assignment(lit) == l_true); bool is_final = aut->is_final_state(src); if (is_final == is_acc) { propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h index be17fe5ac69..27c72cc974d 100644 --- a/src/smt/theory_seq_empty.h +++ b/src/smt/theory_seq_empty.h @@ -25,6 +25,7 @@ Revision History: namespace smt { class seq_factory : public value_factory { typedef hashtable symbol_set; + proto_model& m_model; ast_manager& m; seq_util u; symbol_set m_strings; @@ -34,8 +35,9 @@ namespace smt { expr_ref_vector m_trail; public: - seq_factory(ast_manager & m, family_id fid): + seq_factory(ast_manager & m, family_id fid, proto_model& md): value_factory(m, fid), + m_model(md), m(m), u(m), m_next(0), @@ -78,6 +80,17 @@ namespace smt { v2 = u.str.mk_string(symbol("b")); return true; } + sort* ch; + if (u.is_seq(s, ch)) { + if (m_model.get_some_values(ch, v1, v2)) { + v1 = u.str.mk_unit(v1); + v2 = u.str.mk_unit(v2); + return true; + } + else { + return false; + } + } NOT_IMPLEMENTED_YET(); return false; } @@ -92,7 +105,7 @@ namespace smt { return u.str.mk_string(sym); } } - sort* seq = 0; + sort* seq = 0, *ch = 0; if (u.is_re(s, seq)) { expr* v0 = get_fresh_value(seq); return u.re.mk_to_re(v0); @@ -102,7 +115,11 @@ namespace smt { //return u.str.mk_char(zstring(s), 0); return u.str.mk_char(zstring("a"), 0); } - NOT_IMPLEMENTED_YET(); + if (u.is_seq(s, ch)) { + expr* v = m_model.get_fresh_value(ch); + return u.str.mk_unit(v); + } + UNREACHABLE(); return 0; } virtual void register_value(expr* n) { @@ -126,7 +143,7 @@ namespace smt { public: theory_seq_empty(ast_manager& m):theory(m.mk_family_id("seq")), m_used(false) {} virtual void init_model(model_generator & mg) { - mg.register_factory(alloc(seq_factory, get_manager(), get_family_id())); + mg.register_factory(alloc(seq_factory, get_manager(), get_family_id(), mg.get_model())); } }; diff --git a/src/smt/theory_wmaxsat.cpp b/src/smt/theory_wmaxsat.cpp index 9ed944d2c39..e52475d06e2 100644 --- a/src/smt/theory_wmaxsat.cpp +++ b/src/smt/theory_wmaxsat.cpp @@ -260,7 +260,6 @@ void theory_wmaxsat::block() { return; } ++m_stats.m_num_blocks; - ast_manager& m = get_manager(); context& ctx = get_context(); literal_vector lits; compare_cost compare_cost(*this); @@ -274,6 +273,7 @@ void theory_wmaxsat::block() { lits.push_back(~literal(m_var2bool[costs[i]])); } TRACE("opt", + ast_manager& m = get_manager(); tout << "block: "; for (unsigned i = 0; i < lits.size(); ++i) { expr_ref tmp(m); diff --git a/src/solver/solver_na2as.cpp b/src/solver/solver_na2as.cpp index 704038ffd02..2ca6e187c10 100644 --- a/src/solver/solver_na2as.cpp +++ b/src/solver/solver_na2as.cpp @@ -71,12 +71,14 @@ void solver_na2as::push() { } void solver_na2as::pop(unsigned n) { - pop_core(n); - unsigned lvl = m_scopes.size(); - SASSERT(n <= lvl); - unsigned new_lvl = lvl - n; - restore_assumptions(m_scopes[new_lvl]); - m_scopes.shrink(new_lvl); + if (n > 0) { + pop_core(n); + unsigned lvl = m_scopes.size(); + SASSERT(n <= lvl); + unsigned new_lvl = lvl - n; + restore_assumptions(m_scopes[new_lvl]); + m_scopes.shrink(new_lvl); + } } void solver_na2as::restore_assumptions(unsigned old_sz) { diff --git a/src/tactic/arith/fm_tactic.cpp b/src/tactic/arith/fm_tactic.cpp index 698128e2676..eae3ab5e6e9 100644 --- a/src/tactic/arith/fm_tactic.cpp +++ b/src/tactic/arith/fm_tactic.cpp @@ -156,6 +156,7 @@ class fm_tactic : public tactic { r = c; } } + (void)found; SASSERT(found); return is_lower ? LOWER : UPPER; } diff --git a/src/tactic/arith/lia2card_tactic.cpp b/src/tactic/arith/lia2card_tactic.cpp index f36a93e6d1b..4c2e0deadc8 100644 --- a/src/tactic/arith/lia2card_tactic.cpp +++ b/src/tactic/arith/lia2card_tactic.cpp @@ -300,6 +300,7 @@ class lia2card_tactic : public tactic { bool get_sum(expr* x, rational const& mul, expr_ref_vector& conds, expr_ref_vector& args, vector& coeffs, rational& coeff) { expr *y, *z, *u; rational r, q; + if (!is_app(x)) return false; app* f = to_app(x); bool ok = true; if (a.is_add(x)) { diff --git a/src/tactic/bv/bvarray2uf_rewriter.cpp b/src/tactic/bv/bvarray2uf_rewriter.cpp index d4e738ed71e..db60f3fcd40 100644 --- a/src/tactic/bv/bvarray2uf_rewriter.cpp +++ b/src/tactic/bv/bvarray2uf_rewriter.cpp @@ -163,6 +163,59 @@ br_status bvarray2uf_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr result = m_manager.mk_distinct_expanded(num, args); res = BR_REWRITE1; } + else if (m_manager.is_term_ite(f) && is_bv_array(f->get_range())) { + expr_ref c(args[0], m_manager); + func_decl_ref f_t(mk_uf_for_array(args[1]), m_manager); + func_decl_ref f_f(mk_uf_for_array(args[2]), m_manager); + + TRACE("bvarray2uf_rw", tout << "(ite " << c << ", " << f_t->get_name() + << ", " << f_f->get_name() << ")" << std::endl;); + + sort * sorts[1] = { get_index_sort(m_manager.get_sort(args[1])) }; + symbol names[1] = { symbol("x") }; + var_ref x(m_manager.mk_var(0, sorts[0]), m_manager); + + app_ref f_a(m_manager), f_ta(m_manager), f_fa(m_manager); + f_a = m_manager.mk_app(f, num, args); + f_ta = m_manager.mk_app(f_t, x.get()); + f_fa = m_manager.mk_app(f_f, x.get()); + + app_ref e(m_manager); + func_decl_ref itefd(m_manager); + e = m_manager.mk_ite(c, f_ta, f_fa); + + func_decl * bv_f = 0; + if (!m_arrays_fs.find(f_a, bv_f)) { + sort * domain = get_index_sort(args[1]); + sort * range = get_value_sort(args[1]); + bv_f = m_manager.mk_fresh_func_decl("f_t", "", 1, &domain, range); + TRACE("bvarray2uf_rw", tout << mk_ismt2_pp(e, m_manager) << " -> " << bv_f->get_name() << std::endl; ); + if (is_uninterp_const(e)) { + if (m_emc) + m_emc->insert(e->get_decl(), + m_array_util.mk_as_array(m_manager.get_sort(e), bv_f)); + } + else if (m_fmc) + m_fmc->insert(bv_f); + m_arrays_fs.insert(e, bv_f); + m_manager.inc_ref(e); + m_manager.inc_ref(bv_f); + } + + expr_ref q(m_manager), body(m_manager); + body = m_manager.mk_eq(m_manager.mk_app(bv_f, x), e); + q = m_manager.mk_forall(1, sorts, names, body); + extra_assertions.push_back(q); + + result = m_array_util.mk_as_array(f->get_range(), bv_f); + + TRACE("bvarray2uf_rw", tout << "result: " << mk_ismt2_pp(result, m_manager) << ")" << std::endl;); + res = BR_DONE; + + } + else if (f->get_family_id() == m_manager.get_basic_family_id() && is_bv_array(f->get_range())) { + NOT_IMPLEMENTED_YET(); + } else if (f->get_family_id() == null_family_id) { TRACE("bvarray2uf_rw", tout << "UF APP: " << f->get_name() << std::endl; ); diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index 627e33a7bb0..20d8bbbcc8f 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -17,6 +17,7 @@ Module Name: --*/ #include"ast_smt2_pp.h" +#include"fpa_rewriter.h" #include"fpa2bv_model_converter.h" void fpa2bv_model_converter::display(std::ostream & out) { @@ -54,6 +55,7 @@ void fpa2bv_model_converter::display(std::ostream & out) { out << mk_ismt2_pp(it->m_value.first, m, indent) << "; " << mk_ismt2_pp(it->m_value.second, m, indent) << ")"; } + out << ")"; } model_converter * fpa2bv_model_converter::translate(ast_translation & translator) { @@ -101,17 +103,15 @@ model_converter * fpa2bv_model_converter::translate(ast_translation & translator return res; } -expr_ref fpa2bv_model_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) const { - fpa_util fu(m); - bv_util bu(m); - unsynch_mpz_manager & mpzm = fu.fm().mpz_manager(); - unsynch_mpq_manager & mpqm = fu.fm().mpq_manager(); +expr_ref fpa2bv_model_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) { + unsynch_mpz_manager & mpzm = m_fpa_util.fm().mpz_manager(); + unsynch_mpq_manager & mpqm = m_fpa_util.fm().mpq_manager(); expr_ref res(m); mpf fp_val; - unsigned ebits = fu.get_ebits(s); - unsigned sbits = fu.get_sbits(s); + unsigned ebits = m_fpa_util.get_ebits(s); + unsigned sbits = m_fpa_util.get_sbits(s); unsigned sgn_sz = 1; unsigned exp_sz = ebits; @@ -119,47 +119,44 @@ expr_ref fpa2bv_model_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, rational sgn_q(0), sig_q(0), exp_q(0); - if (sgn) bu.is_numeral(sgn, sgn_q, sgn_sz); - if (exp) bu.is_numeral(exp, exp_q, exp_sz); - if (sig) bu.is_numeral(sig, sig_q, sig_sz); + if (sgn) m_bv_util.is_numeral(sgn, sgn_q, sgn_sz); + if (exp) m_bv_util.is_numeral(exp, exp_q, exp_sz); + if (sig) m_bv_util.is_numeral(sig, sig_q, sig_sz); // un-bias exponent rational exp_unbiased_q; - exp_unbiased_q = exp_q - fu.fm().m_powers2.m1(ebits - 1); + exp_unbiased_q = exp_q - m_fpa_util.fm().m_powers2.m1(ebits - 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()); - fu.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z); + m_fpa_util.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z); mpzm.del(sig_z); - res = fu.mk_value(fp_val); + res = m_fpa_util.mk_value(fp_val); TRACE("fpa2bv_mc", tout << "[" << mk_ismt2_pp(sgn, m) << " " << mk_ismt2_pp(exp, m) << " " << mk_ismt2_pp(sig, m) << "] == " << mk_ismt2_pp(res, m) << std::endl;); - fu.fm().del(fp_val); + m_fpa_util.fm().del(fp_val); return res; } -expr_ref fpa2bv_model_converter::convert_bv2fp(model * bv_mdl, sort * s, expr * bv) const { - fpa_util fu(m); - bv_util bu(m); +expr_ref fpa2bv_model_converter::convert_bv2fp(model * bv_mdl, sort * s, expr * bv) { + SASSERT(m_bv_util.is_bv(bv)); - SASSERT(bu.is_bv(bv)); - - unsigned ebits = fu.get_ebits(s); - unsigned sbits = fu.get_sbits(s); + unsigned ebits = m_fpa_util.get_ebits(s); + unsigned sbits = m_fpa_util.get_sbits(s); unsigned bv_sz = sbits + ebits; expr_ref sgn(m), exp(m), sig(m); - sgn = bu.mk_extract(bv_sz - 1, bv_sz - 1, bv); - exp = bu.mk_extract(bv_sz - 2, sbits - 1, bv); - sig = bu.mk_extract(sbits - 2, 0, bv); + sgn = m_bv_util.mk_extract(bv_sz - 1, bv_sz - 1, bv); + exp = m_bv_util.mk_extract(bv_sz - 2, sbits - 1, bv); + sig = m_bv_util.mk_extract(sbits - 2, 0, bv); expr_ref v_sgn(m), v_exp(m), v_sig(m); bv_mdl->eval(sgn, v_sgn); @@ -169,33 +166,28 @@ expr_ref fpa2bv_model_converter::convert_bv2fp(model * bv_mdl, sort * s, expr * return convert_bv2fp(s, v_sgn, v_exp, v_sig); } -expr_ref fpa2bv_model_converter::convert_bv2rm(expr * eval_v) const { - fpa_util fu(m); - bv_util bu(m); +expr_ref fpa2bv_model_converter::convert_bv2rm(expr * bv_rm) { expr_ref res(m); rational bv_val(0); unsigned sz = 0; - if (bu.is_numeral(eval_v, bv_val, sz)) { + if (m_bv_util.is_numeral(bv_rm, bv_val, sz)) { SASSERT(bv_val.is_uint64()); switch (bv_val.get_uint64()) { - case BV_RM_TIES_TO_AWAY: res = fu.mk_round_nearest_ties_to_away(); break; - case BV_RM_TIES_TO_EVEN: res = fu.mk_round_nearest_ties_to_even(); break; - case BV_RM_TO_NEGATIVE: res = fu.mk_round_toward_negative(); break; - case BV_RM_TO_POSITIVE: res = fu.mk_round_toward_positive(); break; + case BV_RM_TIES_TO_AWAY: res = m_fpa_util.mk_round_nearest_ties_to_away(); break; + case BV_RM_TIES_TO_EVEN: res = m_fpa_util.mk_round_nearest_ties_to_even(); break; + case BV_RM_TO_NEGATIVE: res = m_fpa_util.mk_round_toward_negative(); break; + case BV_RM_TO_POSITIVE: res = m_fpa_util.mk_round_toward_positive(); break; case BV_RM_TO_ZERO: - default: res = fu.mk_round_toward_zero(); + default: res = m_fpa_util.mk_round_toward_zero(); } } return res; } -expr_ref fpa2bv_model_converter::convert_bv2rm(model * bv_mdl, func_decl * var, expr * val) const { - fpa_util fu(m); - bv_util bu(m); +expr_ref fpa2bv_model_converter::convert_bv2rm(model * bv_mdl, expr * val) { expr_ref res(m); - expr_ref eval_v(m); if (val && bv_mdl->eval(val, eval_v, true)) @@ -204,10 +196,110 @@ expr_ref fpa2bv_model_converter::convert_bv2rm(model * bv_mdl, func_decl * var, return res; } -void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { - fpa_util fu(m); - bv_util bu(m); +expr_ref fpa2bv_model_converter::rebuild_floats(model * bv_mdl, sort * s, expr * e) { + expr_ref result(m); + TRACE("fpa2bv_mc", tout << "rebuild floats in " << mk_ismt2_pp(s, m) << " for " << mk_ismt2_pp(e, m) << std::endl;); + + if (m_fpa_util.is_float(s)) { + if (m_fpa_util.is_numeral(e)) { + result = e; + } + else { + SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == (m_fpa_util.get_ebits(s) + m_fpa_util.get_sbits(s))); + result = convert_bv2fp(bv_mdl, s, e); + } + } + else if (m_fpa_util.is_rm(s)) { + if (m_fpa_util.is_rm_numeral(e)) { + result = e; + } + else { + SASSERT(m_bv_util.is_bv(e) && m_bv_util.get_bv_size(e) == 3); + result = convert_bv2rm(bv_mdl, e); + } + } + else if (is_app(e)) { + app * a = to_app(e); + expr_ref_vector new_args(m); + for (unsigned i = 0; i < a->get_num_args(); i++) + new_args.push_back(rebuild_floats(bv_mdl, a->get_decl()->get_domain()[i], a->get_arg(i))); + result = m.mk_app(a->get_decl(), new_args.size(), new_args.c_ptr()); + } + return result; +} + +fpa2bv_model_converter::array_model fpa2bv_model_converter::convert_array_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) { + SASSERT(f->get_arity() == 0); + array_util arr_util(m); + + array_model am(m); + sort_ref_vector array_domain(m); + unsigned arity = f->get_range()->get_num_parameters()-1; + + expr_ref as_arr_mdl(m); + as_arr_mdl = bv_mdl->get_const_interp(bv_f); + if (as_arr_mdl == 0) return am; + TRACE("fpa2bv_mc", tout << "arity=0 func_interp for " << mk_ismt2_pp(f, m) << " := " << mk_ismt2_pp(as_arr_mdl, m) << std::endl;); + SASSERT(arr_util.is_as_array(as_arr_mdl)); + for (unsigned i = 0; i < arity; i++) + array_domain.push_back(to_sort(f->get_range()->get_parameter(i).get_ast())); + sort * rng = to_sort(f->get_range()->get_parameter(arity).get_ast()); + + bv_f = arr_util.get_as_array_func_decl(to_app(as_arr_mdl)); + + am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng); + am.new_float_fi = convert_func_interp(am.new_float_fd, bv_f, bv_mdl); + am.bv_fd = bv_f; + am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd); + return am; +} + +func_interp * fpa2bv_model_converter::convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl) { + SASSERT(f->get_arity() > 0); + func_interp * result = 0; + sort * rng = f->get_range(); + sort * const * dmn = f->get_domain(); + + unsigned arity = bv_f->get_arity(); + func_interp * bv_fi = bv_mdl->get_func_interp(bv_f); + + if (bv_fi != 0) { + fpa_rewriter rw(m); + expr_ref ai(m); + result = alloc(func_interp, m, arity); + + for (unsigned i = 0; i < bv_fi->num_entries(); i++) { + func_entry const * bv_fe = bv_fi->get_entry(i); + expr * const * bv_args = bv_fe->get_args(); + expr_ref_buffer new_args(m); + + for (unsigned j = 0; j < arity; j++) { + sort * ft_dj = dmn[j]; + expr * bv_aj = bv_args[j]; + ai = rebuild_floats(bv_mdl, ft_dj, bv_aj); + m_th_rw(ai); + new_args.push_back(ai); + } + + expr_ref bv_fres(m), ft_fres(m); + bv_fres = bv_fe->get_result(); + ft_fres = rebuild_floats(bv_mdl, rng, bv_fres); + m_th_rw(ft_fres); + result->insert_new_entry(new_args.c_ptr(), ft_fres); + } + + expr_ref bv_els(m), ft_els(m); + bv_els = bv_fi->get_else(); + ft_els = rebuild_floats(bv_mdl, rng, bv_els); + m_th_rw(ft_els); + result->set_else(ft_els); + } + + return result; +} + +void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { TRACE("fpa2bv_mc", tout << "BV Model: " << std::endl; for (unsigned i = 0; i < bv_mdl->get_num_constants(); i++) tout << bv_mdl->get_constant(i)->get_name() << " --> " << @@ -233,8 +325,8 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { it++) { func_decl * f = it->m_key; expr_ref pzero(m), nzero(m); - pzero = fu.mk_pzero(f->get_range()); - nzero = fu.mk_nzero(f->get_range()); + pzero = m_fpa_util.mk_pzero(f->get_range()); + nzero = m_fpa_util.mk_nzero(f->get_range()); expr_ref pn(m), np(m); bv_mdl->eval(it->m_value.first, pn, true); @@ -244,8 +336,8 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { rational pn_num, np_num; unsigned bv_sz; - bu.is_numeral(pn, pn_num, bv_sz); - bu.is_numeral(np, np_num, bv_sz); + m_bv_util.is_numeral(pn, pn_num, bv_sz); + m_bv_util.is_numeral(np, np_num, bv_sz); func_interp * flt_fi = alloc(func_interp, m, f->get_arity()); expr * pn_args[2] = { pzero, nzero }; @@ -263,7 +355,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { { func_decl * var = it->m_key; app * val = to_app(it->m_value); - SASSERT(fu.is_float(var->get_range())); + SASSERT(m_fpa_util.is_float(var->get_range())); SASSERT(var->get_range()->get_num_parameters() == 2); expr_ref sgn(m), sig(m), exp(m); @@ -271,7 +363,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { bv_mdl->eval(val->get_arg(1), exp, true); bv_mdl->eval(val->get_arg(2), sig, true); - SASSERT(val->is_app_of(fu.get_family_id(), OP_FPA_FP)); + SASSERT(val->is_app_of(m_fpa_util.get_family_id(), OP_FPA_FP)); #ifdef Z3DEBUG SASSERT(to_app(val->get_arg(0))->get_decl()->get_arity() == 0); @@ -301,79 +393,43 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { it++) { func_decl * var = it->m_key; - SASSERT(fu.is_rm(var->get_range())); + SASSERT(m_fpa_util.is_rm(var->get_range())); expr * val = it->m_value; - SASSERT(is_app_of(val, fu.get_family_id(), OP_FPA_INTERNAL_RM)); + SASSERT(m_fpa_util.is_bv2rm(val)); expr * bvval = to_app(val)->get_arg(0); expr_ref fv(m); - fv = convert_bv2rm(bv_mdl, var, bvval); + fv = convert_bv2rm(bv_mdl, bvval); TRACE("fpa2bv_mc", tout << var->get_name() << " == " << mk_ismt2_pp(fv, m) << ")" << std::endl;); float_mdl->register_decl(var, fv); seen.insert(to_app(bvval)->get_decl()); } for (obj_map::iterator it = m_uf2bvuf.begin(); - it != m_uf2bvuf.end(); - it++) { + it != m_uf2bvuf.end(); + it++) { seen.insert(it->m_value); - func_decl * f = it->m_key; - unsigned arity = f->get_arity(); - sort * rng = f->get_range(); - - if (arity > 0) { - func_interp * flt_fi = alloc(func_interp, m, f->get_arity()); - - func_interp * bv_fi = bv_mdl->get_func_interp(it->m_value); - SASSERT(bv_fi->args_are_values()); - - for (unsigned i = 0; i < bv_fi->num_entries(); i++) { - func_entry const * bv_fe = bv_fi->get_entry(i); - expr * const * bv_args = bv_fe->get_args(); - expr_ref_buffer new_args(m); - - for (unsigned j = 0; j < arity; j++) { - sort * dj = f->get_domain(j); - expr * aj = bv_args[j]; - if (fu.is_float(dj)) - new_args.push_back(convert_bv2fp(bv_mdl, dj, aj)); - else if (fu.is_rm(dj)) { - expr_ref fv(m); - fv = convert_bv2rm(aj); - new_args.push_back(fv); - } - else - new_args.push_back(aj); - } - - expr_ref ret(m); - ret = bv_fe->get_result(); - if (fu.is_float(rng)) - ret = convert_bv2fp(bv_mdl, rng, ret); - else if (fu.is_rm(rng)) - ret = convert_bv2rm(ret); - - flt_fi->insert_new_entry(new_args.c_ptr(), ret); + func_decl * f = it->m_key; + if (f->get_arity() == 0) + { + array_util au(m); + if (au.is_array(f->get_range())) { + array_model am = convert_array_func_interp(f, it->m_value, bv_mdl); + if (am.new_float_fd) float_mdl->register_decl(am.new_float_fd, am.new_float_fi); + if (am.result) float_mdl->register_decl(f, am.result); + if (am.bv_fd) seen.insert(am.bv_fd); } - - expr_ref els(m); - els = bv_fi->get_else(); - if (fu.is_float(rng)) - els = convert_bv2fp(bv_mdl, rng, els); - else if (fu.is_rm(rng)) - els = convert_bv2rm(els); - - flt_fi->set_else(els); - - float_mdl->register_decl(f, flt_fi); - } + else { + // Just keep. + SASSERT(!m_fpa_util.is_float(f->get_range()) && !m_fpa_util.is_rm(f->get_range())); + expr_ref val(m); + bv_mdl->eval(it->m_value, val); + if (val) float_mdl->register_decl(f, val); + } + } else { - func_decl * bvf = it->m_value; - expr_ref c(m), e(m); - c = m.mk_const(bvf); - bv_mdl->eval(c, e, true); - float_mdl->register_decl(f, e); - TRACE("fpa2bv_mc", tout << "model value for " << mk_ismt2_pp(f, m) << " is " << mk_ismt2_pp(e, m) << std::endl;); + func_interp * fmv = convert_func_interp(f, it->m_value, bv_mdl); + if (fmv) float_mdl->register_decl(f, fmv); } } diff --git a/src/tactic/fpa/fpa2bv_model_converter.h b/src/tactic/fpa/fpa2bv_model_converter.h index 854543f24d3..0e92841de37 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.h +++ b/src/tactic/fpa/fpa2bv_model_converter.h @@ -19,18 +19,27 @@ Module Name: #ifndef FPA2BV_MODEL_CONVERTER_H_ #define FPA2BV_MODEL_CONVERTER_H_ +#include"th_rewriter.h" #include"fpa2bv_converter.h" #include"model_converter.h" class fpa2bv_model_converter : public model_converter { - ast_manager & m; + ast_manager & m; + fpa_util m_fpa_util; + bv_util m_bv_util; + th_rewriter m_th_rw; + obj_map m_const2bv; obj_map m_rm_const2bv; obj_map m_uf2bvuf; obj_map > m_specials; public: - fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv) : m(m) { + fpa2bv_model_converter(ast_manager & m, fpa2bv_converter const & conv) : + m(m), + m_fpa_util(m), + m_bv_util(m), + m_th_rw(m) { for (obj_map::iterator it = conv.m_const2bv.begin(); it != conv.m_const2bv.end(); it++) @@ -95,13 +104,31 @@ class fpa2bv_model_converter : public model_converter { virtual model_converter * translate(ast_translation & translator); protected: - fpa2bv_model_converter(ast_manager & m) : m(m){ } + fpa2bv_model_converter(ast_manager & m) : + m(m), + m_fpa_util(m), + m_bv_util(m), + m_th_rw(m) {} void convert(model * bv_mdl, model * float_mdl); - expr_ref convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig) const; - expr_ref convert_bv2fp(model * bv_mdl, sort * s, expr * bv) const; - expr_ref convert_bv2rm(expr * eval_v) const; - expr_ref convert_bv2rm(model * bv_mdl, func_decl * var, expr * val) const; + expr_ref convert_bv2fp(sort * s, expr * sgn, expr * exp, expr * sig); + expr_ref convert_bv2fp(model * bv_mdl, sort * s, expr * bv); + expr_ref convert_bv2rm(expr * eval_v); + expr_ref convert_bv2rm(model * bv_mdl, expr * val); + + func_interp * convert_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl); + expr_ref rebuild_floats(model * bv_mdl, sort * s, expr * e); + + class array_model { + public: + func_decl * new_float_fd; + func_interp * new_float_fi; + func_decl * bv_fd; + expr_ref result; + array_model(ast_manager & m) : new_float_fd(0), new_float_fi(0), bv_fd(0), result(m) {} + }; + + array_model convert_array_func_interp(func_decl * f, func_decl * bv_f, model * bv_mdl); }; diff --git a/src/test/model_based_opt.cpp b/src/test/model_based_opt.cpp index 8c414863841..b5b8e2953ae 100644 --- a/src/test/model_based_opt.cpp +++ b/src/test/model_based_opt.cpp @@ -216,6 +216,77 @@ static void test4() { std::cout << "u: " << mbo.get_value(u) << "\n"; } +static void test5() { + opt::model_based_opt mbo; + unsigned x = mbo.add_var(rational(2)); + unsigned y = mbo.add_var(rational(3)); + unsigned z = mbo.add_var(rational(4)); + unsigned u = mbo.add_var(rational(5)); + + add_ineq(mbo, x, 1, y, -1, 0, opt::t_le); + add_ineq(mbo, x, 1, z, -1, 0, opt::t_le); + add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); + add_ineq(mbo, z, 1, u, -1, 1, opt::t_le); + + unsigned vars[2] = { y, z }; + mbo.project(1, vars); + mbo.display(std::cout); + + mbo.project(1, vars); + mbo.display(std::cout); + + mbo.project(1, vars+1); + mbo.display(std::cout); + + vector rows; + mbo.get_live_rows(rows); +} + + +static void test6() { + opt::model_based_opt mbo; + unsigned x0 = mbo.add_var(rational(1)); + unsigned x = mbo.add_var(rational(2)); + unsigned y = mbo.add_var(rational(3)); + unsigned z = mbo.add_var(rational(4)); + unsigned u = mbo.add_var(rational(5)); + unsigned v = mbo.add_var(rational(6)); + unsigned w = mbo.add_var(rational(6)); + + add_ineq(mbo, x0, 1, y, -1, 0, opt::t_le); + add_ineq(mbo, x, 1, y, -1, 0, opt::t_le); + add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); + add_ineq(mbo, y, 1, z, -1, 1, opt::t_le); + add_ineq(mbo, y, 1, v, -1, 1, opt::t_le); + add_ineq(mbo, y, 1, w, -1, 1, opt::t_le); + + mbo.display(std::cout); + mbo.project(1, &y); + mbo.display(std::cout); +} + +static void test7() { + opt::model_based_opt mbo; + unsigned x0 = mbo.add_var(rational(2)); + unsigned x = mbo.add_var(rational(1)); + unsigned y = mbo.add_var(rational(3)); + unsigned z = mbo.add_var(rational(4)); + unsigned u = mbo.add_var(rational(5)); + unsigned v = mbo.add_var(rational(6)); + unsigned w = mbo.add_var(rational(6)); + + add_ineq(mbo, x0, 1, y, -1, 0, opt::t_le); + add_ineq(mbo, x, 1, y, -1, 0, opt::t_lt); + add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); + add_ineq(mbo, y, 1, z, -1, 1, opt::t_le); + add_ineq(mbo, y, 1, v, -1, 1, opt::t_le); + add_ineq(mbo, y, 1, w, -1, 1, opt::t_lt); + + mbo.display(std::cout); + mbo.project(1, &y); + mbo.display(std::cout); +} + // test with mix of upper and lower bounds void tst_model_based_opt() { @@ -224,4 +295,8 @@ void tst_model_based_opt() { test2(); test3(); test4(); + test5(); + test6(); + test7(); + } diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index a1b5c28598f..f14ccf3e2e2 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -280,12 +280,170 @@ static void test2(char const *ex) { ctx.assert_expr(pr1); ctx.assert_expr(npr2); VERIFY(l_false == ctx.check()); - ctx.pop(1); + ctx.pop(1); +} + +typedef opt::model_based_opt::var var_t; + +static void mk_var(unsigned x, app_ref& v) { + ast_manager& m = v.get_manager(); + arith_util a(m); + std::ostringstream strm; + strm << "v" << x; + v = m.mk_const(symbol(strm.str().c_str()), a.mk_real()); +} + +static void mk_term(vector const& vars, rational const& coeff, app_ref& term) { + ast_manager& m = term.get_manager(); + expr_ref_vector ts(m); + arith_util a(m); + + for (unsigned i = 0; i < vars.size(); ++i) { + app_ref var(m); + mk_var(vars[i].m_id, var); + rational coeff = vars[i].m_coeff; + ts.push_back(a.mk_mul(a.mk_numeral(coeff, false), var)); + } + ts.push_back(a.mk_numeral(coeff, a.mk_real())); + term = a.mk_add(ts.size(), ts.c_ptr()); +} + +static void add_random_ineq( + expr_ref_vector& fmls, + opt::model_based_opt& mbo, + random_gen& r, + svector const& values, + unsigned max_vars, + unsigned max_coeff) +{ + ast_manager& m = fmls.get_manager(); + arith_util a(m); + + unsigned num_vars = values.size(); + uint_set used_vars; + vector vars; + int value = 0; + for (unsigned i = 0; i < max_vars; ++i) { + unsigned x = r(num_vars); + if (used_vars.contains(x)) { + continue; + } + used_vars.insert(x); + int coeff = r(max_coeff + 1); + if (coeff == 0) { + continue; + } + unsigned sign = r(2); + coeff = sign == 0 ? coeff : -coeff; + vars.push_back(var_t(x, rational(coeff))); + value += coeff*values[x]; + } + unsigned abs_value = value < 0 ? - value : value; + // value + k <= 0 + // k <= - value + // range for k is 2*|value| + // k <= - value - range + opt::ineq_type rel = opt::t_le; + + int coeff = 0; + if (r(4) == 0) { + rel = opt::t_eq; + coeff = -value; + } + else { + if (abs_value > 0) { + coeff = -value - r(2*abs_value); + } + else { + coeff = 0; + } + if (coeff != -value && r(3) == 0) { + rel = opt::t_lt; + } + } + expr_ref fml(m); + app_ref t1(m); + app_ref t2(a.mk_numeral(rational(0), a.mk_real()), m); + mk_term(vars, rational(coeff), t1); + switch (rel) { + case opt::t_eq: + fml = m.mk_eq(t1, t2); + break; + case opt::t_lt: + fml = a.mk_lt(t1, t2); + break; + case opt::t_le: + fml = a.mk_le(t1, t2); + break; + } + fmls.push_back(fml); + mbo.add_constraint(vars, rational(coeff), rel); +} + +static void test_maximize(opt::model_based_opt& mbo, ast_manager& m, unsigned num_vars, expr_ref_vector const& fmls, app* t) { + qe::arith_project_plugin plugin(m); + model mdl(m); + expr_ref bound(m); + arith_util a(m); + for (unsigned i = 0; i < num_vars; ++i) { + app_ref var(m); + mk_var(i, var); + rational val = mbo.get_value(i); + mdl.register_decl(var->get_decl(), a.mk_numeral(val, false)); + } + opt::inf_eps value1 = plugin.maximize(fmls, mdl, t, bound); + opt::inf_eps value2 = mbo.maximize(); + std::cout << "optimal: " << value1 << " " << value2 << "\n"; + mbo.display(std::cout); +} + +static void check_random_ineqs(random_gen& r, ast_manager& m, unsigned num_vars, unsigned max_value, unsigned num_ineqs, unsigned max_vars, unsigned max_coeff) { + opt::model_based_opt mbo; + expr_ref_vector fmls(m); + + svector values; + for (unsigned i = 0; i < num_vars; ++i) { + values.push_back(r(max_value + 1)); + mbo.add_var(rational(values.back())); + } + for (unsigned i = 0; i < num_ineqs; ++i) { + add_random_ineq(fmls, mbo, r, values, max_vars, max_coeff); + } + + vector vars; + vars.reset(); + vars.push_back(var_t(0, rational(2))); + vars.push_back(var_t(1, rational(-2))); + mbo.set_objective(vars, rational(0)); + + + mbo.display(std::cout); + app_ref t(m); + mk_term(vars, rational(0), t); + test_maximize(mbo, m, num_vars, fmls, t); + for (unsigned i = 0; i < values.size(); ++i) { + std::cout << i << ": " << values[i] << " -> " << mbo.get_value(i) << "\n"; + } +} + +static void check_random_ineqs() { + random_gen r(1); + ast_manager m; + reg_decl_plugins(m); + + for (unsigned i = 0; i < 100; ++i) { + check_random_ineqs(r, m, 4, 5, 5, 3, 6); + } } + + + void tst_qe_arith() { + check_random_ineqs(); + return; // enable_trace("qe"); testI(example8); testR(example7); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index de215c95834..0fcff0da0ef 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -1092,10 +1092,11 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o bool tie = m_mpz_manager.eq(rem, shiftm1_p); bool less_than_tie = m_mpz_manager.lt(rem, shiftm1_p); bool more_than_tie = m_mpz_manager.gt(rem, shiftm1_p); + (void)less_than_tie; TRACE("mpf_dbg", tout << "tie= " << tie << "; tie = " << more_than_tie << std::endl;); if (tie) { if ((rm == MPF_ROUND_NEAREST_TEVEN && m_mpz_manager.is_odd(div)) || - (rm == MPF_ROUND_NEAREST_TAWAY && m_mpz_manager.is_even(div))) { + (rm == MPF_ROUND_NEAREST_TAWAY)) { TRACE("mpf_dbg", tout << "div++ (1)" << std::endl;); m_mpz_manager.inc(div); } @@ -1214,11 +1215,194 @@ void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) { } } +void mpf_manager::renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, mpz & sig) { + if (m_mpz_manager.is_zero(sig)) + return; + + const mpz & pg = m_powers2(sbits); + while (m_mpz_manager.ge(sig, pg)) { + m_mpz_manager.machine_div2k(sig, 1); + exp++; + } + + const mpz & pl = m_powers2(sbits-1); + while (m_mpz_manager.lt(sig, pl)) { + m_mpz_manager.mul2k(sig, 1); + exp--; + } +} + +void mpf_manager::partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & exp_diff, bool partial) { + unsigned ebits = x.ebits; + unsigned sbits = x.sbits; + + SASSERT(-1 <= exp_diff && exp_diff < INT64_MAX); + SASSERT(exp_diff < ebits+sbits || partial); + + signed int D = (signed int)(exp_diff); + mpf_exp_t N = sbits-1; + + TRACE("mpf_dbg_rem", tout << "x=" << to_string(x) << std::endl; + tout << "y=" << to_string(y) << std::endl; + tout << "d=" << D << std::endl; + tout << "partial=" << partial << std::endl;); + + SASSERT(m_mpz_manager.lt(x.significand, m_powers2(sbits))); + SASSERT(m_mpz_manager.ge(x.significand, m_powers2(sbits - 1))); + SASSERT(m_mpz_manager.lt(y.significand, m_powers2(sbits))); + SASSERT(m_mpz_manager.ge(y.significand, m_powers2(sbits - 1))); + + // 1. Compute a/b + bool x_div_y_sgn = x.sign != y.sign; + mpf_exp_t x_div_y_exp = D; + scoped_mpz x_sig_shifted(m_mpz_manager), x_div_y_sig_lrg(m_mpz_manager), x_div_y_rem(m_mpz_manager); + scoped_mpz x_rem_y_sig(m_mpz_manager); + m_mpz_manager.mul2k(x.significand, 2*sbits + 2, x_sig_shifted); + m_mpz_manager.machine_div_rem(x_sig_shifted, y.significand, x_div_y_sig_lrg, x_div_y_rem); // rem useful? + // x/y is in x_diuv_y_sig_lrg and has sbits+3 extra bits. + + TRACE("mpf_dbg_rem", tout << "X/Y_exp=" << x_div_y_exp << std::endl; + tout << "X/Y_sig_lrg=" << m_mpz_manager.to_string(x_div_y_sig_lrg) << std::endl; + tout << "X/Y_rem=" << m_mpz_manager.to_string(x_div_y_rem) << std::endl; + tout << "X/Y~=" << to_string_hexfloat(x_div_y_sgn, x_div_y_exp, x_div_y_sig_lrg, ebits, sbits, sbits+3) << std::endl;); + + // 2. Round a/b to integer Q/QQ + bool Q_sgn = x_div_y_sgn; + mpf_exp_t Q_exp = x_div_y_exp; + scoped_mpz Q_sig(m_mpz_manager), Q_rem(m_mpz_manager); + unsigned Q_shft = (sbits-1) + (sbits+3) - (unsigned) (partial ? N :Q_exp); + if (partial) { + // Round according to MPF_ROUND_TOWARD_ZERO + SASSERT(0 < N && N < Q_exp && Q_exp < INT_MAX); + m_mpz_manager.machine_div2k(x_div_y_sig_lrg, Q_shft, Q_sig); + } + else { + // Round according to MPF_ROUND_NEAREST_TEVEN + m_mpz_manager.machine_div_rem(x_div_y_sig_lrg, m_powers2(Q_shft), Q_sig, Q_rem); + const mpz & shiftm1_p = m_powers2(Q_shft-1); + bool tie = m_mpz_manager.eq(Q_rem, shiftm1_p); + bool more_than_tie = m_mpz_manager.gt(Q_rem, shiftm1_p); + TRACE("mpf_dbg_rem", tout << "tie= " << tie << "; >tie= " << more_than_tie << std::endl;); + if ((tie && m_mpz_manager.is_odd(Q_sig)) || more_than_tie) + m_mpz_manager.inc(Q_sig); + } + m_mpz_manager.mul2k(Q_sig, Q_shft); + m_mpz_manager.machine_div2k(Q_sig, sbits+3); + renormalize(ebits, sbits, Q_exp, Q_sig); + + TRACE("mpf_dbg_rem", tout << "Q_exp=" << Q_exp << std::endl; + tout << "Q_sig=" << m_mpz_manager.to_string(Q_sig) << std::endl; + tout << "Q=" << to_string_hexfloat(Q_sgn, Q_exp, Q_sig, ebits, sbits, 0) << std::endl;); + + if ((D == -1 || partial) && m_mpz_manager.is_zero(Q_sig)) + return; // This means x % y = x. + + // no extra bits in Q_sig. + SASSERT(!m_mpz_manager.is_zero(Q_sig)); + SASSERT(m_mpz_manager.lt(Q_sig, m_powers2(sbits))); + SASSERT(m_mpz_manager.ge(Q_sig, m_powers2(sbits - 1))); + + + // 3. Compute Y*Q / Y*QQ*2^{D-N} + bool YQ_sgn = y.sign ^ Q_sgn; + scoped_mpz YQ_sig(m_mpz_manager); + mpf_exp_t YQ_exp = Q_exp + y.exponent; + m_mpz_manager.mul(y.significand, Q_sig, YQ_sig); + renormalize(ebits, 2*sbits-1, YQ_exp, YQ_sig); // YQ_sig has `sbits-1' extra bits. + + TRACE("mpf_dbg_rem", tout << "YQ_sgn=" << YQ_sgn << std::endl; + tout << "YQ_exp=" << YQ_exp << std::endl; + tout << "YQ_sig=" << m_mpz_manager.to_string(YQ_sig) << std::endl; + tout << "YQ=" << to_string_hexfloat(YQ_sgn, YQ_exp, YQ_sig, ebits, sbits, sbits-1) << std::endl;); + + // `sbits-1' extra bits in YQ_sig. + SASSERT(m_mpz_manager.lt(YQ_sig, m_powers2(2*sbits-1))); + SASSERT(m_mpz_manager.ge(YQ_sig, m_powers2(2*sbits-2)) || YQ_exp <= mk_bot_exp(ebits)); + + // 4. Compute X-Y*Q + mpf_exp_t X_YQ_exp = x.exponent; + scoped_mpz X_YQ_sig(m_mpz_manager); + mpf_exp_t exp_delta = exp(x) - YQ_exp; + TRACE("mpf_dbg_rem", tout << "exp_delta=" << exp_delta << std::endl;); + SASSERT(INT_MIN < exp_delta && exp_delta <= INT_MAX); + scoped_mpz minuend(m_mpz_manager), subtrahend(m_mpz_manager); + + scoped_mpz x_sig_lrg(m_mpz_manager); + m_mpz_manager.mul2k(x.significand, sbits-1, x_sig_lrg); // sbits-1 extra bits into x + + m_mpz_manager.set(minuend, x_sig_lrg); + m_mpz_manager.set(subtrahend, YQ_sig); + + SASSERT(m_mpz_manager.lt(minuend, m_powers2(2*sbits-1))); + SASSERT(m_mpz_manager.ge(minuend, m_powers2(2*sbits-2))); + SASSERT(m_mpz_manager.lt(subtrahend, m_powers2(2*sbits-1))); + SASSERT(m_mpz_manager.ge(subtrahend, m_powers2(2*sbits-2))); + + if (exp_delta != 0) { + scoped_mpz sticky_rem(m_mpz_manager); + m_mpz_manager.set(sticky_rem, 0); + if (exp_delta > sbits+5) + sticky_rem.swap(subtrahend); + else if (exp_delta > 0) + m_mpz_manager.machine_div_rem(subtrahend, m_powers2((unsigned)exp_delta), subtrahend, sticky_rem); + else { + SASSERT(exp_delta < 0); + exp_delta = -exp_delta; + m_mpz_manager.mul2k(subtrahend, (int)exp_delta); + } + if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(subtrahend)) + m_mpz_manager.inc(subtrahend); + TRACE("mpf_dbg_rem", tout << "aligned subtrahend=" << m_mpz_manager.to_string(subtrahend) << std::endl;); + } + + m_mpz_manager.sub(minuend, subtrahend, X_YQ_sig); + TRACE("mpf_dbg_rem", tout << "X_YQ_sig'=" << m_mpz_manager.to_string(X_YQ_sig) << std::endl;); + + bool neg = m_mpz_manager.is_neg(X_YQ_sig); + if (neg) m_mpz_manager.neg(X_YQ_sig); + bool X_YQ_sgn = ((!x.sign && !YQ_sgn && neg) || + (x.sign && YQ_sgn && !neg) || + (x.sign && !YQ_sgn)); + + // 5. Rounding + if (m_mpz_manager.is_zero(X_YQ_sig)) + mk_zero(ebits, sbits, x.sign, x); + else { + renormalize(ebits, 2*sbits-1, X_YQ_exp, X_YQ_sig); + + TRACE("mpf_dbg_rem", tout << "minuend=" << m_mpz_manager.to_string(minuend) << std::endl; + tout << "subtrahend=" << m_mpz_manager.to_string(subtrahend) << std::endl; + tout << "X_YQ_sgn=" << X_YQ_sgn << std::endl; + tout << "X_YQ_exp=" << X_YQ_exp << std::endl; + tout << "X_YQ_sig=" << m_mpz_manager.to_string(X_YQ_sig) << std::endl; + tout << "X-YQ=" << to_string_hexfloat(X_YQ_sgn, X_YQ_exp, X_YQ_sig, ebits, sbits, sbits-1) << std::endl;); + + // `sbits-1' extra bits in X_YQ_sig + SASSERT(m_mpz_manager.lt(X_YQ_sig, m_powers2(2*sbits-1))); + scoped_mpz rnd_bits(m_mpz_manager); + m_mpz_manager.machine_div_rem(X_YQ_sig, m_powers2(sbits-1), X_YQ_sig, rnd_bits); + TRACE("mpf_dbg_rem", tout << "final sticky=" << m_mpz_manager.to_string(rnd_bits) << std::endl; ); + + // Round to nearest, ties to even. + if (m_mpz_manager.eq(rnd_bits, mpz(32))) { // tie. + if (m_mpz_manager.is_odd(X_YQ_sig)) { + m_mpz_manager.inc(X_YQ_sig); + } + } + else if (m_mpz_manager.gt(rnd_bits, mpz(32))) + m_mpz_manager.inc(X_YQ_sig); + + set(x, ebits, sbits, X_YQ_sgn, X_YQ_exp, X_YQ_sig); + } + + TRACE("mpf_dbg_rem", tout << "partial remainder = " << to_string_hexfloat(x) << std::endl;); +} + void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { SASSERT(x.sbits == y.sbits && x.ebits == y.ebits); - TRACE("mpf_dbg", tout << "X = " << to_string(x) << std::endl;); - TRACE("mpf_dbg", tout << "Y = " << to_string(y) << std::endl;); + TRACE("mpf_dbg_rem", tout << "X = " << to_string(x) << "=" << to_string_hexfloat(x) << std::endl; + tout << "Y = " << to_string(y) << "=" << to_string_hexfloat(y) << std::endl;); if (is_nan(x) || is_nan(y)) mk_nan(x.ebits, x.sbits, o); @@ -1231,58 +1415,35 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { else if (is_zero(x)) set(o, x); else { - // This is a generalized version of the algorithm for FPREM1 in the Intel + SASSERT(is_regular(x) && is_regular(y)); + + // This is a generalized version of the algorithm for FPREM1 in the `Intel // 64 and IA-32 Architectures Software Developer's Manual', - // Section 3-402 Vol. 2A FPREM1-Partial Remainder'. + // Section 3-402 Vol. 2A `FPREM1-Partial Remainder'. scoped_mpf ST0(*this), ST1(*this); set(ST0, x); set(ST1, y); + unpack(ST0, true); + unpack(ST1, true); - const mpf_exp_t B = x.sbits-1; // max bits per iteration. + const mpf_exp_t B = x.sbits; mpf_exp_t D; do { - D = ST0.exponent() - ST1.exponent(); - TRACE("mpf_dbg_rem", tout << "st0=" << to_string_hexfloat(ST0) << std::endl; - tout << "st1=" << to_string_hexfloat(ST1) << std::endl; - tout << "D=" << D << std::endl;); - - if (D < B) { - scoped_mpf ST0_DIV_ST1(*this), Q(*this), ST1_MUL_Q(*this), ST0p(*this); - div(MPF_ROUND_NEAREST_TEVEN, ST0, ST1, ST0_DIV_ST1); - round_to_integral(MPF_ROUND_NEAREST_TEVEN, ST0_DIV_ST1, Q); - mul(MPF_ROUND_NEAREST_TEVEN, ST1, Q, ST1_MUL_Q); - sub(MPF_ROUND_NEAREST_TEVEN, ST0, ST1_MUL_Q, ST0p); - TRACE("mpf_dbg_rem", tout << "ST0/ST1=" << to_string_hexfloat(ST0_DIV_ST1) << std::endl; - tout << "Q=" << to_string_hexfloat(Q) << std::endl; - tout << "ST1*Q=" << to_string_hexfloat(ST1_MUL_Q) << std::endl; - tout << "ST0'=" << to_string_hexfloat(ST0p) << std::endl;); - set(ST0, ST0p); + if (ST0.exponent() < ST1.exponent() - 1) { + D = 0; } else { - const mpf_exp_t N = B; - scoped_mpf ST0_DIV_ST1(*this), QQ(*this), ST1_MUL_QQ(*this), ST0p(*this); - div(MPF_ROUND_TOWARD_ZERO, ST0, ST1, ST0_DIV_ST1); - ST0_DIV_ST1.get().exponent -= D - N; - round_to_integral(MPF_ROUND_TOWARD_ZERO, ST0_DIV_ST1, QQ); - mul(MPF_ROUND_NEAREST_TEVEN, ST1, QQ, ST1_MUL_QQ); - ST1_MUL_QQ.get().exponent += D - N; - sub(MPF_ROUND_NEAREST_TEVEN, ST0, ST1_MUL_QQ, ST0p); - TRACE("mpf_dbg_rem", tout << "ST0/ST1/2^{D-N}=" << to_string_hexfloat(ST0_DIV_ST1) << std::endl; - tout << "QQ=" << to_string_hexfloat(QQ) << std::endl; - tout << "ST1*QQ*2^{D-N}=" << to_string_hexfloat(ST1_MUL_QQ) << std::endl; - tout << "ST0'=" << to_string_hexfloat(ST0p) << std::endl;); - SASSERT(!eq(ST0, ST0p)); - set(ST0, ST0p); + D = ST0.exponent() - ST1.exponent(); + partial_remainder(ST0.get(), ST1.get(), D, (D >= B)); } + } while (D >= B && !ST0.is_zero()); - SASSERT(ST0.exponent() - ST1.exponent() <= D); - } while (D >= B); - - set(o, ST0); - if (is_zero(o)) - o.sign = x.sign; + m_mpz_manager.mul2k(ST0.significand(), 3); + set(o, x.ebits, x.sbits, MPF_ROUND_TOWARD_ZERO, ST0); + round(MPF_ROUND_NEAREST_TEVEN, o); } + TRACE("mpf_dbg_rem", tout << "R = " << to_string(o) << "=" << to_string_hexfloat(o) << std::endl; ); TRACE("mpf_dbg", tout << "REMAINDER = " << to_string(o) << std::endl;); } @@ -1365,7 +1526,7 @@ std::string mpf_manager::to_string(mpf const & x) { } //DEBUG_CODE( - // res += " " + to_string_hexfloat(x); + // res += " " + to_string_raw(x); //); return res; @@ -1407,6 +1568,19 @@ std::string mpf_manager::to_string_raw(mpf const & x) { return res; } +std::string mpf_manager::to_string_hexfloat(bool sgn, mpf_exp_t exp, scoped_mpz const & sig, unsigned ebits, unsigned sbits, unsigned rbits) { + scoped_mpf q(*this); + scoped_mpz q_sig(m_mpz_manager); + m_mpz_manager.set(q_sig, sig); + if (rbits != 0) m_mpz_manager.div(q_sig, m_powers2(rbits), q_sig); // restore scale + if (m_mpz_manager.ge(q_sig, m_powers2(sbits-1))) + m_mpz_manager.sub(q_sig, m_powers2(sbits-1), q_sig); // strip hidden bit + else if (exp == mk_min_exp(ebits)) + exp = mk_bot_exp(ebits); + set(q, ebits, sbits, sgn, exp, q_sig); + return to_string(q.get()); +} + std::string mpf_manager::to_string_hexfloat(mpf const & x) { std::stringstream ss(""); std::ios::fmtflags ff = ss.setf(std::ios_base::hex | std::ios_base::uppercase | @@ -1715,6 +1889,7 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { const mpz & p_m1 = m_powers2(o.sbits+2); const mpz & p_m2 = m_powers2(o.sbits+3); + (void)p_m1; TRACE("mpf_dbg", tout << "p_m1 = " << m_mpz_manager.to_string(p_m1) << std::endl << "p_m2 = " << m_mpz_manager.to_string(p_m2) << std::endl;); @@ -1906,7 +2081,7 @@ void mpf_manager::round_sqrt(mpf_rounding_mode rm, mpf & o) { bool round = !m_mpz_manager.is_even(o.significand); m_mpz_manager.machine_div2k(o.significand, 1); bool last = !m_mpz_manager.is_even(o.significand); - + (void)last; bool inc = false; // Specialized rounding for sqrt, as there are no negative cases (or half-way cases?) diff --git a/src/util/mpf.h b/src/util/mpf.h index 1bd0ac95235..31523c3ed2b 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -185,9 +185,6 @@ class mpf_manager { void mk_pinf(unsigned ebits, unsigned sbits, mpf & o); void mk_ninf(unsigned ebits, unsigned sbits, mpf & o); - std::string to_string_raw(mpf const & a); - std::string to_string_hexfloat(mpf const & a); - unsynch_mpz_manager & mpz_manager(void) { return m_mpz_manager; } unsynch_mpq_manager & mpq_manager(void) { return m_mpq_manager; } @@ -226,6 +223,9 @@ class mpf_manager { void round(mpf_rounding_mode rm, mpf & o); void round_sqrt(mpf_rounding_mode rm, mpf & o); + void renormalize(unsigned ebits, unsigned sbits, mpf_exp_t & exp, mpz & sig); + void partial_remainder(mpf & x, mpf const & y, mpf_exp_t const & exp_diff, bool partial); + void mk_round_inf(mpf_rounding_mode rm, mpf & o); // Convert x into a mpz numeral. zm is the manager that owns o. @@ -284,6 +284,9 @@ class mpf_manager { } }; + std::string to_string_raw(mpf const & a); + std::string to_string_hexfloat(mpf const & a); + std::string to_string_hexfloat(bool sgn, mpf_exp_t exp, scoped_mpz const & sig, unsigned ebits, unsigned sbits, unsigned rbits); public: powers2 m_powers2; }; @@ -291,6 +294,7 @@ class mpf_manager { class scoped_mpf : public _scoped_numeral { friend class mpf_manager; mpz & significand() { return get().significand; } + const mpz & significand() const { return get().significand; } bool sign() const { return get().sign; } mpf_exp_t exponent() const { return get().exponent; } unsigned sbits() const { return get().sbits; } diff --git a/src/util/mpff.cpp b/src/util/mpff.cpp index e5d3cf24c87..d26b3743c42 100644 --- a/src/util/mpff.cpp +++ b/src/util/mpff.cpp @@ -1395,6 +1395,7 @@ unsigned mpff_manager::prev_power_of_two(mpff const & a) { bool mpff_manager::check(mpff const & n) const { // n is zero or the most significand bit of the most significand word is 1. unsigned * s = sig(n); + (void)s; SASSERT(is_zero(n) || (s[m_precision - 1] & MIN_MSW) != 0); // if n is zero, then the sign must be 0 SASSERT(!is_zero(n) || n.m_sign == 0); diff --git a/src/util/mpn.cpp b/src/util/mpn.cpp index 0c1744a09ff..df69ce76d99 100644 --- a/src/util/mpn.cpp +++ b/src/util/mpn.cpp @@ -274,13 +274,12 @@ void mpn_manager::div_unnormalize(mpn_sbuffer & numer, mpn_sbuffer & denom, bool mpn_manager::div_1(mpn_sbuffer & numer, mpn_digit const denom, mpn_digit * quot) const { - mpn_double_digit q_hat, temp, r_hat, ms; + mpn_double_digit q_hat, temp, ms; mpn_digit borrow; for (size_t j = numer.size()-1; j > 0; j--) { temp = (((mpn_double_digit)numer[j]) << DIGIT_BITS) | ((mpn_double_digit)numer[j-1]); q_hat = temp / (mpn_double_digit) denom; - r_hat = temp % (mpn_double_digit) denom; if (q_hat >= BASE) { UNREACHABLE(); // is this reachable with normalized v? } @@ -294,11 +293,13 @@ bool mpn_manager::div_1(mpn_sbuffer & numer, mpn_digit const denom, quot[j-1]--; numer[j] = numer[j-1] + denom; } - TRACE("mpn_div1", tout << "j=" << j << " q_hat=" << q_hat << " r_hat=" << r_hat; - tout << " ms=" << ms; - tout << " new numer="; display_raw(tout, numer.c_ptr(), numer.size()); - tout << " borrow=" << borrow; - tout << std::endl; ); + TRACE("mpn_div1", + mpn_double_digit r_hat = temp % (mpn_double_digit) denom; + tout << "j=" << j << " q_hat=" << q_hat << " r_hat=" << r_hat; + tout << " ms=" << ms; + tout << " new numer="; display_raw(tout, numer.c_ptr(), numer.size()); + tout << " borrow=" << borrow; + tout << std::endl; ); } return true; // return rem != 0?