From e5f03f999abb3af7743163975301bbfc9f9b6d34 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 4 Mar 2013 20:21:14 +0000 Subject: [PATCH 001/281] FPA: Added conversion operator float -> float. Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 23 ++-- src/ast/rewriter/float_rewriter.cpp | 23 ++-- src/tactic/fpa/fpa2bv_converter.cpp | 169 ++++++++++++++++++++++++++-- src/util/mpf.cpp | 2 +- 4 files changed, 188 insertions(+), 29 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index f2d6591dc..62ec3a4cf 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -353,27 +353,22 @@ func_decl * float_decl_plugin::mk_to_float(decl_kind k, unsigned num_parameters, sort * fp = mk_float_sort(domain[2]->get_parameter(0).get_int(), domain[1]->get_parameter(0).get_int()+1); symbol name("asFloat"); return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); - } + } else { // .. Otherwise we only know how to convert rationals/reals. if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) m_manager->raise_exception("expecting two integer parameters to asFloat"); if (arity != 2 && arity != 3) m_manager->raise_exception("invalid number of arguments to asFloat operator"); - if (!is_rm_sort(domain[0]) || domain[1] != m_real_sort) + if (arity == 3 && domain[2] != m_int_sort) + m_manager->raise_exception("sort mismatch"); + if (!is_rm_sort(domain[0]) || + !(domain[1] == m_real_sort || is_sort_of(domain[1], m_family_id, FLOAT_SORT))) m_manager->raise_exception("sort mismatch"); - if (arity == 2) { - sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); - symbol name("asFloat"); - return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); - } - else { - if (domain[2] != m_int_sort) - m_manager->raise_exception("sort mismatch"); - sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); - symbol name("asFloat"); - return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); - } + + sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); + symbol name("asFloat"); + return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); } } diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 482e280e3..18fea6c47 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -77,14 +77,23 @@ br_status float_rewriter::mk_to_float(func_decl * f, unsigned num_args, expr * c return BR_FAILED; rational q; - if (!m_util.au().is_numeral(args[1], q)) + mpf q_mpf; + if (m_util.au().is_numeral(args[1], q)) { + mpf v; + m_util.fm().set(v, ebits, sbits, rm, q.to_mpq()); + result = m_util.mk_value(v); + m_util.fm().del(v); + return BR_DONE; + } + else if (m_util.is_value(args[1], q_mpf)) { + mpf v; + m_util.fm().set(v, ebits, sbits, rm, q_mpf); + result = m_util.mk_value(v); + m_util.fm().del(v); + return BR_DONE; + } + else return BR_FAILED; - - mpf v; - m_util.fm().set(v, ebits, sbits, rm, q.to_mpq()); - result = m_util.mk_value(v); - m_util.fm().del(v); - return BR_DONE; } else if (num_args == 3 && m_util.is_rm(m().get_sort(args[0])) && diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 2600cb3ec..37eaa365a 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1403,23 +1403,176 @@ void fpa2bv_converter::mk_is_sign_minus(func_decl * f, unsigned num, expr * cons } void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - if (num == 3 && m_bv_util.is_bv(args[0]) && - m_bv_util.is_bv(args[1]) && m_bv_util.is_bv(args[2])) { + TRACE("fpa2bv_to_float", for (unsigned i=0; i < num; i++) + tout << "arg" << i << " = " << mk_ismt2_pp(args[i], m) << std::endl; ); + + if (num == 3 && + m_bv_util.is_bv(args[0]) && + m_bv_util.is_bv(args[1]) && + m_bv_util.is_bv(args[2])) { // Theoretically, the user could have thrown in it's own triple of bit-vectors. // Just keep it here, as there will be something else that uses it. mk_triple(args[0], args[1], args[2], result); } + else if (num == 2 && is_app(args[1]) && m_util.is_float(m.get_sort(args[1]))) { + // We also support float to float conversion + expr_ref rm(m), x(m); + rm = args[0]; + x = args[1]; + + expr_ref c1(m), c2(m), c3(m), c4(m), c5(m); + expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m); + expr_ref one1(m); + + one1 = m_bv_util.mk_numeral(1, 1); + expr_ref ninf(m), pinf(m); + mk_plus_inf(f, pinf); + mk_minus_inf(f, ninf); + + // NaN -> NaN + mk_is_nan(x, c1); + mk_nan(f, v1); + + // +0 -> +0 + mk_is_pzero(x, c2); + mk_pzero(f, v2); + + // -0 -> -0 + mk_is_nzero(x, c3); + mk_nzero(f, v3); + + // +oo -> +oo + mk_is_pinf(x, c4); + v4 = pinf; + + // -oo -> -oo + mk_is_ninf(x, c5); + v5 = ninf; + + // otherwise: the actual conversion with rounding. + sort * s = f->get_range(); + expr_ref sgn(m), sig(m), exp(m); + unpack(x, sgn, sig, exp, true); + + expr_ref res_sgn(m), res_sig(m), res_exp(m); + + res_sgn = sgn; + + unsigned from_sbits = m_util.get_sbits(m.get_sort(args[1])); + unsigned from_ebits = m_util.get_ebits(m.get_sort(args[1])); + unsigned to_sbits = m_util.get_sbits(s); + unsigned to_ebits = m_util.get_ebits(s); + + SASSERT(m_bv_util.get_bv_size(sgn) == 1); + SASSERT(m_bv_util.get_bv_size(sig) == from_sbits); + SASSERT(m_bv_util.get_bv_size(exp) == from_ebits); + + if (from_sbits < (to_sbits + 3)) + // make sure that sig has at least to_sbits + 3 + res_sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, to_sbits+3-from_sbits)); + else if (from_sbits > (to_sbits + 3)) + { + // collapse the extra bits into a sticky bit. + expr_ref sticky(m), low(m), high(m); + low = m_bv_util.mk_extract(from_sbits - to_sbits - 3, 0, sig); + high = m_bv_util.mk_extract(from_sbits - 1, from_sbits - to_sbits - 2, sig); + unsigned high_sz = m_bv_util.get_bv_size(high); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, low); + res_sig = m_bv_util.mk_concat(high, sticky); + } + else + res_sig = sig; + + res_sig = m_bv_util.mk_zero_extend(1, res_sig); // extra zero in the front for the rounder. + unsigned sig_sz = m_bv_util.get_bv_size(res_sig); + SASSERT(sig_sz == to_sbits+4); + + expr_ref exponent_overflow(m); + exponent_overflow = m.mk_false(); + + if (from_ebits < (to_ebits + 2)) + res_exp = m_bv_util.mk_sign_extend(to_ebits+2-from_ebits, exp); + else if (from_ebits > (to_ebits + 2)) + { + expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), or_eq(m), not_or_eq(m), and_eq(m); + expr_ref no_ovf(m), zero1(m), s_is_one(m), s_is_zero(m); + high = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, exp); + low = m_bv_util.mk_extract(to_ebits+1, 0, exp); + lows = m_bv_util.mk_extract(to_ebits+1, to_ebits+1, low); + + high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high); + high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high); + + zero1 = m_bv_util.mk_numeral(0, 1); + m_simp.mk_eq(high_red_and, one1, and_eq); + m_simp.mk_eq(high_red_or, zero1, or_eq); + m_simp.mk_eq(lows, zero1, s_is_zero); + m_simp.mk_eq(lows, one1, s_is_one); + + expr_ref c2(m); + m_simp.mk_ite(or_eq, s_is_one, m.mk_false(), c2); + m_simp.mk_ite(and_eq, s_is_zero, c2, exponent_overflow); + + // Note: Upon overflow, we _could_ try to shift the significand around... + + res_exp = low; + } + else + res_exp = exp; + + SASSERT(m_bv_util.get_bv_size(res_exp) == to_ebits+2); + + expr_ref rounded(m); + round(s, rm, res_sgn, res_sig, res_exp, rounded); + + expr_ref is_neg(m), sig_inf(m); + m_simp.mk_eq(sgn, one1, is_neg); + mk_ite(is_neg, ninf, pinf, sig_inf); + + dbg_decouple("fpa2bv_to_float_exp_ovf", exponent_overflow); + + mk_ite(exponent_overflow, sig_inf, rounded, v6); + + // And finally, we tie them together. + mk_ite(c5, v5, v6, result); + mk_ite(c4, v4, result, result); + mk_ite(c3, v3, result, result); + mk_ite(c2, v2, result, result); + mk_ite(c1, v1, result, result); + } else { + // .. other than that, we only support rationals for asFloat SASSERT(num == 2); SASSERT(m_util.is_float(f->get_range())); unsigned ebits = m_util.get_ebits(f->get_range()); - unsigned sbits = m_util.get_sbits(f->get_range()); - - SASSERT(m_util.is_rm(to_app(args[0])->get_decl()->get_range())); + unsigned sbits = m_util.get_sbits(f->get_range()); + + //SASSERT(m_bv_util.is_numeral(args[0])); + //rational tmp_rat; unsigned sz; + //m_bv_util.is_numeral(to_expr(args[0]), tmp_rat, sz); + //SASSERT(tmp_rat.is_int32()); + //SASSERT(sz == 3); + //BV_RM_VAL rm = (BV_RM_VAL) tmp_rat.get_unsigned(); + + /*mpf_rounding_mode rm; + switch(bv_rm) + { + case BV_RM_TIES_TO_AWAY: rm = MPF_ROUND_NEAREST_TAWAY; break; + case BV_RM_TIES_TO_EVEN: rm = MPF_ROUND_NEAREST_TEVEN; break; + case BV_RM_TO_NEGATIVE: rm = MPF_ROUND_TOWARD_NEGATIVE; break; + case BV_RM_TO_POSITIVE: rm = MPF_ROUND_TOWARD_POSITIVE; break; + case BV_RM_TO_ZERO: rm = MPF_ROUND_TOWARD_ZERO; break; + default: UNREACHABLE(); + }*/ + + SASSERT(m_util.au().is_numeral(args[1])); + + sort * rm_rng = to_app(args[0])->get_decl()->get_range(); + SASSERT(m_util.is_rm(rm_rng)); mpf_rounding_mode rm = static_cast(to_app(args[1])->get_decl_kind()); - + rational q; - SASSERT(m_util.au().is_numeral(args[1])); + SASSERT(m_util.au().is_numeral(args[1])); m_util.au().is_numeral(args[1], q); mpf v; @@ -1433,6 +1586,8 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a m_util.fm().del(v); } + + SASSERT(is_well_sorted(m, result)); } void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 9618ffbce..dfac97626 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -367,7 +367,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode o.ebits = ebits; o.sbits = sbits; - signed ds = sbits - x.sbits; + signed ds = sbits - x.sbits + 4; // plus rounding bits if (ds > 0) { m_mpz_manager.mul2k(o.significand, ds); From 35906889b60753ca34b931c0465607d46d3d1c88 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 5 Mar 2013 13:49:42 +0000 Subject: [PATCH 002/281] FPA: compilation bugfixes Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 37eaa365a..42fdd0a62 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1476,8 +1476,7 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a expr_ref sticky(m), low(m), high(m); low = m_bv_util.mk_extract(from_sbits - to_sbits - 3, 0, sig); high = m_bv_util.mk_extract(from_sbits - 1, from_sbits - to_sbits - 2, sig); - unsigned high_sz = m_bv_util.get_bv_size(high); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, low); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, low.get()); res_sig = m_bv_util.mk_concat(high, sticky); } else @@ -1494,24 +1493,24 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a res_exp = m_bv_util.mk_sign_extend(to_ebits+2-from_ebits, exp); else if (from_ebits > (to_ebits + 2)) { - expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), or_eq(m), not_or_eq(m), and_eq(m); + expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), h_or_eq(m), h_and_eq(m); expr_ref no_ovf(m), zero1(m), s_is_one(m), s_is_zero(m); high = m_bv_util.mk_extract(from_ebits - 1, to_ebits + 2, exp); low = m_bv_util.mk_extract(to_ebits+1, 0, exp); lows = m_bv_util.mk_extract(to_ebits+1, to_ebits+1, low); - high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high); - high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high); + high_red_or = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, high.get()); + high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high.get()); zero1 = m_bv_util.mk_numeral(0, 1); - m_simp.mk_eq(high_red_and, one1, and_eq); - m_simp.mk_eq(high_red_or, zero1, or_eq); + m_simp.mk_eq(high_red_and, one1, h_and_eq); + m_simp.mk_eq(high_red_or, zero1, h_or_eq); m_simp.mk_eq(lows, zero1, s_is_zero); m_simp.mk_eq(lows, one1, s_is_one); expr_ref c2(m); - m_simp.mk_ite(or_eq, s_is_one, m.mk_false(), c2); - m_simp.mk_ite(and_eq, s_is_zero, c2, exponent_overflow); + m_simp.mk_ite(h_or_eq, s_is_one, m.mk_false(), c2); + m_simp.mk_ite(h_and_eq, s_is_zero, c2, exponent_overflow); // Note: Upon overflow, we _could_ try to shift the significand around... @@ -2416,4 +2415,4 @@ model_converter * mk_fpa2bv_model_converter(ast_manager & m, obj_map const & const2bv, obj_map const & rm_const2bv) { return alloc(fpa2bv_model_converter, m, const2bv, rm_const2bv); -} \ No newline at end of file +} From 9a4331995e1e3b2fe779becfbb9185e3bda113c7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 5 Mar 2013 14:11:50 +0000 Subject: [PATCH 003/281] FPA: bugfix for bitblaster. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 42fdd0a62..d7d4458f8 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1546,14 +1546,14 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); - //SASSERT(m_bv_util.is_numeral(args[0])); - //rational tmp_rat; unsigned sz; - //m_bv_util.is_numeral(to_expr(args[0]), tmp_rat, sz); - //SASSERT(tmp_rat.is_int32()); - //SASSERT(sz == 3); - //BV_RM_VAL rm = (BV_RM_VAL) tmp_rat.get_unsigned(); + SASSERT(m_bv_util.is_numeral(args[0])); + rational tmp_rat; unsigned sz; + m_bv_util.is_numeral(to_expr(args[0]), tmp_rat, sz); + SASSERT(tmp_rat.is_int32()); + SASSERT(sz == 3); + BV_RM_VAL bv_rm = (BV_RM_VAL) tmp_rat.get_unsigned(); - /*mpf_rounding_mode rm; + mpf_rounding_mode rm; switch(bv_rm) { case BV_RM_TIES_TO_AWAY: rm = MPF_ROUND_NEAREST_TAWAY; break; @@ -1562,14 +1562,10 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a case BV_RM_TO_POSITIVE: rm = MPF_ROUND_TOWARD_POSITIVE; break; case BV_RM_TO_ZERO: rm = MPF_ROUND_TOWARD_ZERO; break; default: UNREACHABLE(); - }*/ + } SASSERT(m_util.au().is_numeral(args[1])); - sort * rm_rng = to_app(args[0])->get_decl()->get_range(); - SASSERT(m_util.is_rm(rm_rng)); - mpf_rounding_mode rm = static_cast(to_app(args[1])->get_decl_kind()); - rational q; SASSERT(m_util.au().is_numeral(args[1])); m_util.au().is_numeral(args[1], q); From bdc675b1dfef87fcffeb7f3e5143128492d3bd89 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 5 Mar 2013 09:04:03 -0800 Subject: [PATCH 004/281] Fix bug reported at http://stackoverflow.com/questions/15226944/segmentation-fault-in-z3 Signed-off-by: Leonardo de Moura --- RELEASE_NOTES | 2 ++ src/ast/macros/macro_util.cpp | 15 +++++++++++---- src/model/model_v2_pp.cpp | 5 +++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 7aaaf2f8d..643c9b26f 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -63,6 +63,8 @@ Version 4.3.2 - Fixed bug reported at http://z3.codeplex.com/workitem/23 (Thanks to Paul Jackson). +- Fixed bug reported at http://stackoverflow.com/questions/15226944/segmentation-fault-in-z3 (Thanks to Tianhai Liu). + Version 4.3.1 ============= diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index e9b9c831e..bd21aa1ac 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -597,8 +597,9 @@ void hint_to_macro_head(ast_manager & m, app * head, unsigned num_decls, app_ref is_hint_head(head, vars) must also return true */ bool macro_util::is_poly_hint(expr * n, app * head, expr * exception) { - TRACE("macro_util_hint", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n" - << mk_pp(exception, m_manager) << "\n";); + TRACE("macro_util_hint", tout << "is_poly_hint n:\n" << mk_pp(n, m_manager) << "\nhead:\n" << mk_pp(head, m_manager) << "\nexception:\n"; + if (exception) tout << mk_pp(exception, m_manager); else tout << ""; + tout << "\n";); ptr_buffer vars; if (!is_hint_head(head, vars)) { TRACE("macro_util_hint", tout << "failed because head is not hint head\n";); @@ -792,7 +793,10 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a mk_add(args.size(), args.c_ptr(), m_manager.get_sort(arg), rest); expr_ref def(m_manager); mk_sub(rhs, rest, def); - add_arith_macro_candidate(to_app(arg), num_decls, def, atom, is_ineq, _is_poly_hint, r); + // If is_poly_hint, rhs may contain variables that do not occur in to_app(arg). + // So, we should re-check. + if (!_is_poly_hint || is_poly_hint(def, to_app(arg), 0)) + add_arith_macro_candidate(to_app(arg), num_decls, def, atom, is_ineq, _is_poly_hint, r); } else if (is_times_minus_one(arg, neg_arg) && is_app(neg_arg)) { f = to_app(neg_arg)->get_decl(); @@ -810,7 +814,10 @@ void macro_util::collect_arith_macro_candidates(expr * lhs, expr * rhs, expr * a mk_add(args.size(), args.c_ptr(), m_manager.get_sort(arg), rest); expr_ref def(m_manager); mk_sub(rest, rhs, def); - add_arith_macro_candidate(to_app(neg_arg), num_decls, def, atom, is_ineq, _is_poly_hint, r); + // If is_poly_hint, rhs may contain variables that do not occur in to_app(neg_arg). + // So, we should re-check. + if (!_is_poly_hint || is_poly_hint(def, to_app(neg_arg), 0)) + add_arith_macro_candidate(to_app(neg_arg), num_decls, def, atom, is_ineq, _is_poly_hint, r); } } } diff --git a/src/model/model_v2_pp.cpp b/src/model/model_v2_pp.cpp index 9073ddece..4600ccc9e 100644 --- a/src/model/model_v2_pp.cpp +++ b/src/model/model_v2_pp.cpp @@ -80,3 +80,8 @@ void model_v2_pp(std::ostream & out, model_core const & md, bool partial) { display_constants(out, md); display_functions(out, md, partial); } + +// debugging support +void pp(model_core const & md) { + model_v2_pp(std::cout, md, false); +} From e5307300de9829dfe3568224d10d05d62bdd6c86 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 6 Mar 2013 15:04:58 +0000 Subject: [PATCH 005/281] FPA: bugfixes in mul() and abs() Signed-off-by: Christoph M. Wintersteiger --- src/ast/rewriter/float_rewriter.cpp | 2 +- src/tactic/fpa/fpa2bv_converter.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 18fea6c47..10311598b 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -227,7 +227,7 @@ br_status float_rewriter::mk_abs(expr * arg1, expr_ref & result) { return BR_DONE; } sort * s = m().get_sort(arg1); - result = m().mk_ite(m_util.mk_lt(arg1, m_util.mk_pzero(s)), + result = m().mk_ite(m_util.mk_is_sign_minus(arg1), m_util.mk_uminus(arg1), arg1); return BR_REWRITE2; diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index d7d4458f8..79f86ac46 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -610,11 +610,11 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, expr_ref h_p(m), l_p(m), rbits(m); h_p = m_bv_util.mk_extract(2*sbits-1, sbits, product); - l_p = m_bv_util.mk_extract(2*sbits-1, sbits, product); + l_p = m_bv_util.mk_extract(sbits-1, 0, product); if (sbits >= 4) { expr_ref sticky(m); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits-4, 0, l_p)); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits-4, 0, l_p)); rbits = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-3, l_p), sticky); } else @@ -2094,11 +2094,11 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & expr * round_sticky[2] = { round, sticky }; last_or_sticky = m_bv_util.mk_bv_or(2, last_sticky); round_or_sticky = m_bv_util.mk_bv_or(2, round_sticky); - not_round = m_bv_util.mk_bv_not(round); + not_round = m_bv_util.mk_bv_not(round); not_lors = m_bv_util.mk_bv_not(last_or_sticky); not_rors = m_bv_util.mk_bv_not(round_or_sticky); not_sgn = m_bv_util.mk_bv_not(sgn); - expr * round_lors[2] = { not_round, not_lors }; + expr * round_lors[2] = { not_round, not_lors}; expr * pos_args[2] = { sgn, not_rors }; expr * neg_args[2] = { not_sgn, not_rors }; From f9aeeeef367ecafff815c9758e30a50e75c0d24d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Mar 2013 08:29:29 -0800 Subject: [PATCH 006/281] LRA tactic Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_context.cpp | 113 ++++++++++++++++++++----- src/muz_qe/pdr_context.h | 4 +- src/muz_qe/qe_sat_tactic.h | 2 +- src/tactic/smtlogics/quant_tactics.cpp | 8 +- 4 files changed, 99 insertions(+), 28 deletions(-) diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 73bffd4e4..348bf9154 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -723,24 +723,17 @@ namespace pdr { m_closed = true; } - expr_ref model_node::get_trace() const { + expr_ref model_node::get_trace(context const& ctx) { pred_transformer& p = pt(); ast_manager& m = p.get_manager(); - manager& pm = p.get_pdr_manager(); - TRACE("pdr", model_smt2_pp(tout, m, get_model(), 0);); - func_decl* f = p.head(); - unsigned arity = f->get_arity(); - model_ref model = get_model_ptr(); - expr_ref_vector args(m); - expr_ref v(m); - model_evaluator mev(m); - - for (unsigned i = 0; i < arity; ++i) { - v = m.mk_const(pm.o2n(p.sig(i),0)); - expr_ref e = mev.eval(model, v); - args.push_back(e); - } - return expr_ref(m.mk_app(f, args.size(), args.c_ptr()), m); + datalog::context& dctx = ctx.get_context(); + datalog::rule_manager& rm = dctx.get_rule_manager(); + datalog::rule_ref r0(rm), r1(rm); + expr_ref_vector binding(m); + expr_ref fml(m); + mk_instantiate(r0, r1, binding); + r1->to_formula(fml); + return fml; } static bool is_ini(datalog::rule const& r) { @@ -961,21 +954,95 @@ namespace pdr { return out; } - expr_ref model_search::get_trace() const { + expr_ref model_search::get_trace(context const& ctx) const { pred_transformer& pt = get_root().pt(); ast_manager& m = pt.get_manager(); manager& pm = pt.get_pdr_manager(); - expr_ref result(m.mk_true(),m); expr_ref_vector rules(m); - ptr_vector nodes; - nodes.push_back(m_root); + expr_ref_vector binding(m); + ptr_vector todo; + datalog::rule_ref r0(rm), r1(rm), r2(rm); + model_node* n = m_root; + todo.push_back(n); + while (!todo.empty()) { + n = todo.back(); + ptr_vector const& chs = n->children(); + rls.push_back(0); + for (unsigned i = 0; i < chs.size(); ++i) { + todo.push_back(chs[i]); + } + if (!chs.empty()) { + continue; + } + expr_ref fml0(m); + binding.reset(); + n->mk_instantiate(r0, r1, binding); + r0->to_formula(fml0); + datalog::rule_ref reduced_rule(rm), r3(rm); + reduced_rule = rls[0]; + // check if binding is identity. + bool binding_is_id = true; + for (unsigned i = 0; binding_is_id && i < binding.size(); ++i) { + expr* v = binding[i].get(); + binding_is_id = is_var(v) && to_var(v)->get_idx() == i; + } + if (rls.size() > 1 || !binding_is_id) { + expr_ref tmp(m); + vector substs; + svector > positions; + substs.push_back(binding); // TODO base substitution. + for (unsigned i = 1; i < rls.size(); ++i) { + datalog::rule& src = *rls[i]; + bool unified = unifier.unify_rules(*reduced_rule, 0, src); + if (!unified) { + IF_VERBOSE(0, + verbose_stream() << "Could not unify rules: "; + reduced_rule->display(dctx, verbose_stream()); + src.display(dctx, verbose_stream());); + } + expr_ref_vector sub1 = unifier.get_rule_subst(*reduced_rule, true); + TRACE("pdr", + for (unsigned k = 0; k < sub1.size(); ++k) { + tout << mk_pp(sub1[k].get(), m) << " "; + } + tout << "\n"; + ); + + for (unsigned j = 0; j < substs.size(); ++j) { + for (unsigned k = 0; k < substs[j].size(); ++k) { + var_subst(m, false)(substs[j][k].get(), sub1.size(), sub1.c_ptr(), tmp); + substs[j][k] = tmp; + } + while (substs[j].size() < sub1.size()) { + substs[j].push_back(sub1[substs[j].size()].get()); + } + } + + positions.push_back(std::make_pair(i,0)); + substs.push_back(unifier.get_rule_subst(src, false)); + VERIFY(unifier.apply(*reduced_rule.get(), 0, src, r3)); + reduced_rule = r3; + } + + expr_ref fml_concl(m); + reduced_rule->to_formula(fml_concl); + p1 = m.mk_hyper_resolve(pfs.size(), pfs.c_ptr(), fml_concl, positions, substs); + + } + cache.insert(n->state(), p1); + rules.insert(n->state(), reduced_rule); + trail.push_back(p1); + rules_trail.push_back(reduced_rule); + todo.pop_back(); + } + while (!nodes.empty()) { model_node* current = nodes.back(); nodes.pop_back(); - rules.push_back(current->get_trace()); + rules.push_back(current->get_trace(ctx)); nodes.append(current->children()); } - return pm.mk_and(rules); + return expr_ref(m.mk_and(rules.size(), rules.c_ptr()), m); } proof_ref model_search::get_proof_trace(context const& ctx) const { @@ -1594,7 +1661,7 @@ namespace pdr { proof_ref pr = get_proof(); return expr_ref(pr.get(), m); } - return m_search.get_trace(); + return m_search.get_trace(*this); } expr_ref context::mk_unsat_answer() const { diff --git a/src/muz_qe/pdr_context.h b/src/muz_qe/pdr_context.h index 7491327dd..412577fb4 100644 --- a/src/muz_qe/pdr_context.h +++ b/src/muz_qe/pdr_context.h @@ -223,7 +223,7 @@ namespace pdr { void set_rule(datalog::rule const* r) { m_rule = r; } datalog::rule* get_rule(); - expr_ref get_trace() const; + expr_ref get_trace(context const& ctx); void mk_instantiate(datalog::rule_ref& r0, datalog::rule_ref& r1, expr_ref_vector& binding); std::ostream& display(std::ostream& out, unsigned indent); @@ -253,7 +253,7 @@ namespace pdr { void set_root(model_node* n); model_node& get_root() const { return *m_root; } std::ostream& display(std::ostream& out) const; - expr_ref get_trace() const; + expr_ref get_trace(context const& ctx) const; proof_ref get_proof_trace(context const& ctx) const; void backtrack_level(bool uses_level, model_node& n); }; diff --git a/src/muz_qe/qe_sat_tactic.h b/src/muz_qe/qe_sat_tactic.h index c539216be..15228c534 100644 --- a/src/muz_qe/qe_sat_tactic.h +++ b/src/muz_qe/qe_sat_tactic.h @@ -26,7 +26,7 @@ Revision History: namespace qe { - tactic * mk_sat_tactic(ast_manager& m, params_ref const& p); + tactic * mk_sat_tactic(ast_manager& m, params_ref const& p = params_ref()); }; /* diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index 85f53eff0..937b0229e 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -22,6 +22,7 @@ Revision History: #include"solve_eqs_tactic.h" #include"elim_uncnstr_tactic.h" #include"qe_tactic.h" +#include"qe_sat_tactic.h" #include"ctx_simplify_tactic.h" #include"smt_tactic.h" @@ -98,8 +99,11 @@ tactic * mk_aufnira_tactic(ast_manager & m, params_ref const & p) { tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) { tactic * st = and_then(mk_quant_preprocessor(m), - mk_qe_tactic(m), - mk_smt_tactic()); + or_else(try_for(mk_smt_tactic(), 100), + try_for(qe::mk_sat_tactic(m), 1000), + try_for(mk_smt_tactic(), 1000), + and_then(mk_qe_tactic(m), mk_smt_tactic()))); + st->updt_params(p); return st; } From 3810374cdd42b999f96bbe9b69b927baa6c437ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Mar 2013 15:20:11 -0800 Subject: [PATCH 007/281] LRA Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_context.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 98f7920ea..30665c6e5 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -732,22 +732,6 @@ namespace pdr { m_closed = true; } -<<<<<<< HEAD - expr_ref model_node::get_trace(context const& ctx) { - pred_transformer& p = pt(); - ast_manager& m = p.get_manager(); - datalog::context& dctx = ctx.get_context(); - datalog::rule_manager& rm = dctx.get_rule_manager(); - datalog::rule_ref r0(rm), r1(rm); - expr_ref_vector binding(m); - expr_ref fml(m); - mk_instantiate(r0, r1, binding); - r1->to_formula(fml); - return fml; - } - -======= ->>>>>>> bdc675b1dfef87fcffeb7f3e5143128492d3bd89 static bool is_ini(datalog::rule const& r) { return r.get_uninterpreted_tail_size() == 0; } From ab73c20757c9f57ea708aabac264f019f1b75725 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 10 Mar 2013 17:53:18 -0700 Subject: [PATCH 008/281] add Karr linear invariants as transformer Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_context.cpp | 62 +-- src/muz_qe/dl_context.h | 6 +- src/muz_qe/dl_mk_array_blast.h | 2 +- src/muz_qe/dl_mk_karr_invariants.cpp | 612 +++++++++++++++++++++++++++ src/muz_qe/dl_mk_karr_invariants.h | 79 ++++ src/muz_qe/dl_rule.cpp | 9 + src/muz_qe/dl_rule.h | 1 + src/muz_qe/dl_rule_transformer.cpp | 39 +- src/muz_qe/dl_rule_transformer.h | 25 +- src/muz_qe/fixedpoint_params.pyg | 1 + src/muz_qe/hilbert_basis.cpp | 1 + src/muz_qe/pdr_context.cpp | 4 + src/muz_qe/pdr_util.cpp | 43 +- src/muz_qe/pdr_util.h | 2 + 14 files changed, 830 insertions(+), 56 deletions(-) create mode 100644 src/muz_qe/dl_mk_karr_invariants.cpp create mode 100644 src/muz_qe/dl_mk_karr_invariants.h diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 7c9d2c965..53231e7b0 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -45,6 +45,7 @@ Revision History: #include"dl_mk_partial_equiv.h" #include"dl_mk_bit_blast.h" #include"dl_mk_array_blast.h" +#include"dl_mk_karr_invariants.h" #include"datatype_decl_plugin.h" #include"expr_abstract.h" @@ -223,6 +224,7 @@ namespace datalog { m_rewriter(m), m_var_subst(m), m_rule_manager(*this), + m_transf(*this), m_trail(*this), m_pinned(m), m_vars(m), @@ -825,23 +827,23 @@ namespace datalog { } void context::transform_rules(model_converter_ref& mc, proof_converter_ref& pc) { - rule_transformer transf(*this); - transf.register_plugin(alloc(mk_filter_rules,*this)); - transf.register_plugin(alloc(mk_simple_joins,*this)); + m_transf.reset(); + m_transf.register_plugin(alloc(mk_filter_rules,*this)); + m_transf.register_plugin(alloc(mk_simple_joins,*this)); if (unbound_compressor()) { - transf.register_plugin(alloc(mk_unbound_compressor,*this)); + m_transf.register_plugin(alloc(mk_unbound_compressor,*this)); } if (similarity_compressor()) { - transf.register_plugin(alloc(mk_similarity_compressor, *this, + m_transf.register_plugin(alloc(mk_similarity_compressor, *this, similarity_compressor_threshold())); } - transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this)); + m_transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this)); - transform_rules(transf, mc, pc); + transform_rules(m_transf, mc, pc); } - + void context::transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc) { SASSERT(m_closed); //we must finish adding rules before we start transforming them TRACE("dl", display_rules(tout);); @@ -862,32 +864,33 @@ namespace datalog { void context::apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc) { ensure_closed(); - datalog::rule_transformer transf(*this); - transf.register_plugin(alloc(datalog::mk_coi_filter, *this)); - transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this)); + m_transf.reset(); + m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this)); + m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 35005)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 35000)); - transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34990)); - transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34980)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 35005)); + m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 35000)); + m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34990)); + m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34980)); //and another round of inlining - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34975)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34970)); - transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34960)); - transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34950)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34975)); + m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34970)); + m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34960)); + m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34950)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34940)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34930)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34920)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34910)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34900)); - transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890)); - transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34940)); + m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34930)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34920)); + m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34910)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34900)); + m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890)); + m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); - transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); - transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); - transform_rules(transf, mc, pc); + m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); + m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); + m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); + transform_rules(m_transf, mc, pc); } void context::collect_params(param_descrs& p) { @@ -928,6 +931,7 @@ namespace datalog { void context::cancel() { m_cancel = true; + m_transf.cancel(); if (m_pdr.get()) m_pdr->cancel(); if (m_bmc.get()) m_bmc->cancel(); if (m_rel.get()) m_rel->cancel(); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index 98380c9c8..b587daf7f 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -45,11 +45,10 @@ Revision History: #include"proof_converter.h" #include"model2expr.h" #include"smt_params.h" +#include"dl_rule_transformer.h" namespace datalog { - class rule_transformer; - enum execution_result { OK, TIMEOUT, @@ -85,6 +84,7 @@ namespace datalog { th_rewriter m_rewriter; var_subst m_var_subst; rule_manager m_rule_manager; + rule_transformer m_transf; trail_stack m_trail; ast_ref_vector m_pinned; @@ -314,7 +314,7 @@ namespace datalog { void ensure_opened(); void transform_rules(model_converter_ref& mc, proof_converter_ref& pc); - void transform_rules(rule_transformer& trans, model_converter_ref& mc, proof_converter_ref& pc); + void transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc); void replace_rules(rule_set & rs); void apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc); diff --git a/src/muz_qe/dl_mk_array_blast.h b/src/muz_qe/dl_mk_array_blast.h index 1618e4fa8..c0bb39da0 100644 --- a/src/muz_qe/dl_mk_array_blast.h +++ b/src/muz_qe/dl_mk_array_blast.h @@ -49,7 +49,7 @@ namespace datalog { public: /** - \brief Create rule transformer that extracts universal quantifiers (over recursive predicates). + \brief Create rule transformer that removes array stores and selects by ackermannization. */ mk_array_blast(context & ctx, unsigned priority); diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp new file mode 100644 index 000000000..4ed959137 --- /dev/null +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -0,0 +1,612 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_karr_invariants.cpp + +Abstract: + + Extract integer linear invariants. + + The linear invariants are extracted according to Karr's method. + A short description is in + Nikolaj Bjørner, Anca Browne and Zohar Manna. Automatic Generation + of Invariants and Intermediate Assertions, in CP 95. + + The algorithm is here adapted to Horn clauses. + The idea is to maintain two data-structures for each recursive relation. + We call them R and RD + - R - set of linear congruences that are true of R. + - RD - the dual basis of of solutions for R. + + RD is updated by accumulating basis vectors for solutions + to R (the homogeneous dual of R) + R is updated from the inhomogeneous dual of RD. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-09 + +Revision History: + +--*/ + +#include"dl_mk_karr_invariants.h" + +namespace datalog { + + mk_karr_invariants::mk_karr_invariants(context & ctx, unsigned priority): + rule_transformer::plugin(priority, false), + m_ctx(ctx), + m(ctx.get_manager()), + rm(ctx.get_rule_manager()), + a(m) { + } + + mk_karr_invariants::~mk_karr_invariants() { + obj_map::iterator it = m_constraints.begin(), end = m_constraints.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + it = m_dual_constraints.begin(); + end = m_dual_constraints.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + } + + mk_karr_invariants::matrix& mk_karr_invariants::matrix::operator=(matrix const& other) { + reset(); + append(other); + return *this; + } + + void mk_karr_invariants::matrix::display(std::ostream& out) const { + for (unsigned i = 0; i < A.size(); ++i) { + for (unsigned j = 0; j < A[i].size(); ++j) { + out << A[i][j] << " "; + } + out << (eq[i]?" = ":" >= ") << -b[i] << "\n"; + } + } + + bool mk_karr_invariants::is_linear(expr* e, vector& row, rational& b, rational const& mul) { + if (!a.is_int(e)) { + return false; + } + if (is_var(e)) { + row[to_var(e)->get_idx()] += mul; + return true; + } + if (!is_app(e)) { + return false; + } + rational n; + if (a.is_numeral(e, n)) { + b += mul*n; + return true; + } + if (a.is_add(e)) { + for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { + if (!is_linear(to_app(e)->get_arg(i), row, b, mul)) { + return false; + } + } + return true; + } + expr* e1, *e2; + if (a.is_sub(e, e1, e2)) { + return is_linear(e1, row, b, mul) && is_linear(e2, row, b, -mul); + } + if (a.is_mul(e, e1, e2) && a.is_numeral(e1, n)) { + return is_linear(e2, row, b, mul*n); + } + if (a.is_mul(e, e1, e2) && a.is_numeral(e2, n)) { + return is_linear(e1, row, b, mul*n); + } + if (a.is_uminus(e, e1)) { + return is_linear(e1, row, b, -mul); + } + return false; + } + + mk_karr_invariants::matrix* mk_karr_invariants::get_constraints(func_decl* p) { + matrix* result = 0; + m_constraints.find(p, result); + return result; + } + + mk_karr_invariants::matrix& mk_karr_invariants::get_dual_constraints(func_decl* p) { + matrix* result = 0; + if (!m_dual_constraints.find(p, result)) { + result = alloc(matrix); + m_dual_constraints.insert(p, result); + } + return *result; + } + + bool mk_karr_invariants::is_eq(expr* e, var*& v, rational& n) { + expr* e1, *e2; + if (!m.is_eq(e, e1, e2)) { + return false; + } + if (!is_var(e1)) { + std::swap(e1, e2); + } + if (!is_var(e1)) { + return false; + } + v = to_var(e1); + if (!a.is_numeral(e2, n)) { + return false; + } + return true; + } + + bool mk_karr_invariants::get_transition_relation(rule const& r, matrix& M) { + unsigned num_vars = rm.get_var_counter().get_max_var(r)+1; + unsigned arity = r.get_decl()->get_arity(); + unsigned num_columns = arity + num_vars; + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + M.reset(); + + for (unsigned i = 0; i < utsz; ++i) { + matrix const* Mp = get_constraints(r.get_decl(i)); + if (!Mp) { + return false; + } + TRACE("dl", Mp->display(tout << "Intersect\n");); + intersect_matrix(r.get_tail(i), *Mp, num_columns, M); + } + + rational one(1), mone(-1); + expr* e1, *e2, *en; + var* v, *w; + rational n1, n2; + expr_ref_vector conjs(m); + for (unsigned i = utsz; i < tsz; ++i) { + conjs.push_back(r.get_tail(i)); + } + datalog::flatten_and(conjs); + + for (unsigned i = 0; i < conjs.size(); ++i) { + expr* e = conjs[i].get(); + rational b(0); + vector row; + row.resize(num_columns, rational(0)); + bool processed = true; + if (m.is_eq(e, e1, e2) && is_linear(e1, row, b, one) && is_linear(e2, row, b, mone)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(true); + } + else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(false); + } + else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b + rational(1)); + M.eq.push_back(false); + } + else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(false); + } + else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b + rational(1)); + M.eq.push_back(false); + } + else if (m.is_or(e, e1, e2) && is_eq(e1, v, n1) && is_eq(e2, w, n2) && v == w) { + if (n1 > n2) { + std::swap(n1, n2); + } + SASSERT(n1 <= n2); + row[v->get_idx()] = rational(1); + // v - n1 >= 0 + M.A.push_back(row); + M.b.push_back(-n1); + M.eq.push_back(false); + // -v + n2 >= 0 + row[v->get_idx()] = rational(-1); + M.A.push_back(row); + M.b.push_back(n2); + M.eq.push_back(false); + } + else { + processed = false; + } + TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n";); + } + // intersect with the head predicate. + app* head = r.get_head(); + unsigned sz0 = M.A.size(); + for (unsigned i = 0; i < arity; ++i) { + rational n; + expr* arg = head->get_arg(i); + if (!a.is_int(arg)) { + // no-op + } + else if (is_var(arg)) { + vector row; + row.resize(num_columns, rational(0)); + unsigned idx = to_var(arg)->get_idx(); + row[idx] = rational(-1); + row[num_vars + i] = rational(1); + M.A.push_back(row); + M.b.push_back(rational(0)); + M.eq.push_back(true); + } + else if (a.is_numeral(arg, n)) { + vector row; + row.resize(num_columns, rational(0)); + row[num_vars + i] = rational(1); + M.A.push_back(row); + M.b.push_back(-n); + M.eq.push_back(true); + } + else { + UNREACHABLE(); + } + } + if (M.A.size() == sz0) { + return false; + } + + TRACE("dl", M.display(tout << r.get_decl()->get_name() << "\n");); + matrix MD; + dualizeI(MD, M); + M.reset(); + // project for variables in head. + for (unsigned i = 0; i < MD.size(); ++i) { + vector row; + row.append(arity, MD.A[i].c_ptr() + num_vars); + M.A.push_back(row); + M.b.push_back(MD.b[i]); + M.eq.push_back(true); + } + + return true; + } + + void mk_karr_invariants::intersect_matrix(app* p, matrix const& Mp, unsigned num_columns, matrix& M) { + for (unsigned j = 0; j < Mp.size(); ++j) { + rational b = Mp.b[j], n; + vector row; + row.resize(num_columns, rational(0)); + for (unsigned i = 0; i < p->get_num_args(); ++i) { + expr* arg = p->get_arg(i); + if (!a.is_int(arg)) { + // no-op + } + else if (is_var(arg)) { + unsigned idx = to_var(arg)->get_idx(); + row[idx] += Mp.A[j][i]; + } + else if (a.is_numeral(arg, n)) { + b += Mp.A[j][i]*n; + } + else { + UNREACHABLE(); + } + } + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(Mp.eq[j]); + } + } + + // treat src as a homogeneous matrix. + void mk_karr_invariants::dualizeH(matrix& dst, matrix const& src) { + dst.reset(); + if (src.size() == 0) { + return; + } + m_hb.reset(); + for (unsigned i = 0; i < src.size(); ++i) { + vector v(src.A[i]); + v.append(src.b[i]); + if (src.eq[i]) { + m_hb.add_eq(v, rational(0)); + } + else { + m_hb.add_ge(v, rational(0)); + } + } + for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) { + m_hb.set_is_int(i); + } + lbool is_sat = m_hb.saturate(); + TRACE("dl", m_hb.display(tout);); + SASSERT(is_sat == l_true); + unsigned basis_size = m_hb.get_basis_size(); + bool first_initial = true; + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + m_hb.get_basis_solution(i, soln, is_initial); + if (!is_initial) { + dst.b.push_back(soln.back()); + dst.eq.push_back(true); + soln.pop_back(); + dst.A.push_back(soln); + } + } + } + + // treat src as an inhomegeneous matrix. + void mk_karr_invariants::dualizeI(matrix& dst, matrix const& src) { + m_hb.reset(); + for (unsigned i = 0; i < src.size(); ++i) { + if (src.eq[i]) { + m_hb.add_eq(src.A[i], -src.b[i]); + } + else { + m_hb.add_ge(src.A[i], -src.b[i]); + } + } + for (unsigned i = 0; !src.A.empty() && i < src.A[0].size(); ++i) { + m_hb.set_is_int(i); + } + lbool is_sat = m_hb.saturate(); + TRACE("dl", m_hb.display(tout);); + SASSERT(is_sat == l_true); + dst.reset(); + unsigned basis_size = m_hb.get_basis_size(); + bool first_initial = true; + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + m_hb.get_basis_solution(i, soln, is_initial); + if (is_initial && first_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(1)); + dst.eq.push_back(true); + first_initial = false; + } + else if (!is_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(0)); + dst.eq.push_back(true); + } + } + } + + void mk_karr_invariants::update_body(rule_set& rules, rule& r){ + func_decl* p = r.get_decl(); + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + app_ref_vector tail(m); + for (unsigned i = 0; i < tsz; ++i) { + tail.push_back(r.get_tail(i)); + } + for (unsigned i = 0; i < utsz; ++i) { + func_decl* q = r.get_decl(i); + matrix* N = get_constraints(q); + if (!N) { + continue; + } + expr_ref zero(m), lhs(m); + zero = a.mk_numeral(rational(0), true); + for (unsigned j = 0; j < N->size(); ++j) { + rational n; + SASSERT(N->A[j].size() == q->get_arity()); + expr_ref_vector sum(m); + for (unsigned k = 0; k < N->A[j].size(); ++k) { + n = N->A[j][k]; + if (!n.is_zero()) { + expr* arg = r.get_tail(i)->get_arg(k); + sum.push_back(a.mk_mul(a.mk_numeral(n, true), arg)); + } + } + n = N->b[j]; + if (!n.is_zero()) { + sum.push_back(a.mk_numeral(n, true)); + } + lhs = a.mk_add(sum.size(), sum.c_ptr()); + if (N->eq[j]) { + tail.push_back(m.mk_eq(lhs, zero)); + } + else { + tail.push_back(a.mk_ge(lhs, zero)); + } + } + } + rule* new_rule = &r; + if (tail.size() != tsz) { + new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name()); + } + rules.add_rule(new_rule); + } + + class mk_karr_invariants::add_invariant_model_converter : public model_converter { + ast_manager& m; + arith_util a; + func_decl_ref_vector m_funcs; + ptr_vector m_invs; + public: + + add_invariant_model_converter(ast_manager& m): m(m), a(m), m_funcs(m) {} + + virtual ~add_invariant_model_converter() { + for (unsigned i = 0; i < m_invs.size(); ++i) { + dealloc(m_invs[i]); + } + } + + void add(func_decl* p, matrix& M) { + m_funcs.push_back(p); + m_invs.push_back(alloc(matrix, M)); + } + + virtual void operator()(model_ref & mr) { + for (unsigned i = 0; i < m_funcs.size(); ++i) { + func_decl* p = m_funcs[i].get(); + func_interp* f = mr->get_func_interp(p); + expr_ref body(m); + unsigned arity = p->get_arity(); + SASSERT(0 < arity); + if (f) { + matrix const& M = *m_invs[i]; + mk_body(M, body); + SASSERT(f->num_entries() == 0); + if (!f->is_partial()) { + body = m.mk_and(f->get_else(), body); + } + } + else { + f = alloc(func_interp, m, arity); + mr->register_decl(p, f); + body = m.mk_false(); // fragile: assume that relation was pruned by being infeasible. + } + f->set_else(body); + } + } + + virtual model_converter * translate(ast_translation & translator) { + add_invariant_model_converter* mc = alloc(add_invariant_model_converter, m); + for (unsigned i = 0; i < m_funcs.size(); ++i) { + mc->add(translator(m_funcs[i].get()), *m_invs[i]); + } + return mc; + } + + private: + void mk_body(matrix const& M, expr_ref& body) { + expr_ref_vector conj(m); + for (unsigned i = 0; i < M.size(); ++i) { + mk_body(M.A[i], M.b[i], M.eq[i], conj); + } + body = m.mk_and(conj.size(), conj.c_ptr()); + } + + void mk_body(vector const& row, rational const& b, bool is_eq, expr_ref_vector& conj) { + expr_ref_vector sum(m); + expr_ref zero(m), lhs(m); + zero = a.mk_numeral(rational(0), true); + + for (unsigned i = 0; i < row.size(); ++i) { + if (row[i].is_zero()) { + continue; + } + var* var = m.mk_var(i, a.mk_int()); + if (row[i].is_one()) { + sum.push_back(var); + } + else { + sum.push_back(a.mk_mul(a.mk_numeral(row[i], true), var)); + } + } + if (!b.is_zero()) { + sum.push_back(a.mk_numeral(b, true)); + } + lhs = a.mk_add(sum.size(), sum.c_ptr()); + if (is_eq) { + conj.push_back(m.mk_eq(lhs, zero)); + } + else { + conj.push_back(a.mk_ge(lhs, zero)); + } + } + + }; + + void mk_karr_invariants::cancel() { + rule_transformer::plugin::cancel(); + m_hb.set_cancel(true); + } + + rule_set * mk_karr_invariants::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { + if (!m_ctx.get_params().karr()) { + return 0; + } + rule_set::iterator it = source.begin(), end = source.end(); + for (; it != end; ++it) { + rule const& r = **it; + if (r.has_negation()) { + return 0; + } + } + bool change = true, non_empty = false; + while (!m_cancel && change) { + change = false; + it = source.begin(); + for (; it != end; ++it) { + rule const& r = **it; + TRACE("dl", r.display(m_ctx, tout);); + matrix MD, P; + if (!get_transition_relation(r, MD)) { + continue; + } + non_empty = true; + func_decl* p = r.get_decl(); + matrix& ND = get_dual_constraints(p); + matrix* N = get_constraints(p); + ND.append(MD); + dualizeH(P, ND); + + TRACE("dl", + MD.display(tout << "MD\n"); + P.display(tout << "P\n");); + + if (!N) { + change = true; + N = alloc(matrix, P); + m_constraints.insert(p, N); + } + else if (P.size() != N->size()) { + change = true; + *N = P; + } + } + } + + if (!non_empty) { + return 0; + } + + if (m_cancel) { + return 0; + } + + TRACE("dl", + rule_set::decl2rules::iterator git = source.begin_grouped_rules(); + rule_set::decl2rules::iterator gend = source.end_grouped_rules(); + for (; git != gend; ++git) { + func_decl* p = git->m_key; + matrix* M = get_constraints(p); + tout << p->get_name() << "\n"; + if (M) { + M->display(tout); + } + }); + + rule_set* rules = alloc(rule_set, m_ctx); + it = source.begin(); + for (; it != end; ++it) { + update_body(*rules, **it); + } + if (mc) { + add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m); + rule_set::decl2rules::iterator git = source.begin_grouped_rules(); + rule_set::decl2rules::iterator gend = source.end_grouped_rules(); + for (; git != gend; ++git) { + func_decl* p = git->m_key; + matrix* M = get_constraints(p); + if (M) { + kmc->add(p, *M); + } + } + mc = concat(mc.get(), kmc); + } + TRACE("dl", rules->display(tout);); + return rules; + } + +}; + diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h new file mode 100644 index 000000000..3b82578a4 --- /dev/null +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -0,0 +1,79 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_karr_invariants.h + +Abstract: + + Extract integer linear invariants. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-08 + +Revision History: + +--*/ +#ifndef _DL_MK_KARR_INVARIANTS_H_ +#define _DL_MK_KARR_INVARIANTS_H_ + +#include"dl_context.h" +#include"dl_rule_set.h" +#include"dl_rule_transformer.h" +#include"arith_decl_plugin.h" +#include"hilbert_basis.h" + +namespace datalog { + + /** + \brief Rule transformer that strengthens bodies with invariants. + */ + class mk_karr_invariants : public rule_transformer::plugin { + + struct matrix { + vector > A; + vector b; + svector eq; + unsigned size() const { return A.size(); } + void reset() { A.reset(); b.reset(); eq.reset(); } + matrix& operator=(matrix const& other); + void append(matrix const& other) { A.append(other.A); b.append(other.b); eq.append(other.eq); } + void display(std::ostream& out) const; + }; + class add_invariant_model_converter; + + context& m_ctx; + ast_manager& m; + rule_manager& rm; + arith_util a; + obj_map m_constraints; + obj_map m_dual_constraints; + hilbert_basis m_hb; + + bool is_linear(expr* e, vector& row, rational& b, rational const& mul); + bool is_eq(expr* e, var*& v, rational& n); + bool get_transition_relation(rule const& r, matrix& M); + void intersect_matrix(app* p, matrix const& Mp, unsigned num_columns, matrix& M); + matrix* get_constraints(func_decl* p); + matrix& get_dual_constraints(func_decl* p); + void dualizeH(matrix& dst, matrix const& src); + void dualizeI(matrix& dst, matrix const& src); + void update_body(rule_set& rules, rule& r); + + public: + mk_karr_invariants(context & ctx, unsigned priority); + + virtual ~mk_karr_invariants(); + + virtual void cancel(); + + rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + + }; + +}; + +#endif /* _DL_MK_KARR_INVARIANTS_H_ */ + diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index d34f8a67f..3814d0b62 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -927,6 +927,15 @@ namespace datalog { return exist || univ; } + bool rule::has_negation() const { + for (unsigned i = 0; i < get_uninterpreted_tail_size(); ++i) { + if (is_neg_tail(i)) { + return true; + } + } + return false; + } + void rule::get_used_vars(used_vars& used) const { used.process(get_head()); unsigned sz = get_tail_size(); diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index a9e360344..c01b36162 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -237,6 +237,7 @@ namespace datalog { bool has_uninterpreted_non_predicates(func_decl*& f) const; void has_quantifiers(bool& existential, bool& universal) const; bool has_quantifiers() const; + bool has_negation() const; /** \brief Store in d the (direct) dependencies of the given rule. diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index 5f52e0a39..a246d9d61 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -16,40 +16,55 @@ Author: Revision History: --*/ + #include #include #include"dl_context.h" - #include"dl_rule_transformer.h" namespace datalog { rule_transformer::rule_transformer(context & ctx) - : m_context(ctx), m_rule_manager(m_context.get_rule_manager()), m_dirty(false) { + : m_context(ctx), m_rule_manager(m_context.get_rule_manager()), m_dirty(false), m_cancel(false) { } rule_transformer::~rule_transformer() { - plugin_vector::iterator it=m_plugins.begin(); - plugin_vector::iterator end=m_plugins.end(); + reset(); + } + + void rule_transformer::reset() { + plugin_vector::iterator it = m_plugins.begin(); + plugin_vector::iterator end = m_plugins.end(); for(; it!=end; ++it) { dealloc(*it); } + m_plugins.reset(); + m_dirty = false; + m_cancel = false; + } + + void rule_transformer::cancel() { + m_cancel = true; + plugin_vector::iterator it = m_plugins.begin(); + plugin_vector::iterator end = m_plugins.end(); + for(; it!=end; ++it) { + (*it)->cancel(); + } } struct rule_transformer::plugin_comparator { bool operator()(rule_transformer::plugin * p1, rule_transformer::plugin * p2) { - return p1->get_priority()>p2->get_priority(); + return p1->get_priority() > p2->get_priority(); } }; void rule_transformer::ensure_ordered() { - if (!m_dirty) { - return; + if (m_dirty) { + std::sort(m_plugins.begin(), m_plugins.end(), plugin_comparator()); + m_dirty = false; } - std::sort(m_plugins.begin(), m_plugins.end(), plugin_comparator()); - m_dirty=false; } void rule_transformer::register_plugin(plugin * p) { @@ -67,9 +82,9 @@ namespace datalog { tout<<"init:\n"; rules.display(tout); ); - plugin_vector::iterator it=m_plugins.begin(); - plugin_vector::iterator end=m_plugins.end(); - for(; it!=end; ++it) { + plugin_vector::iterator it = m_plugins.begin(); + plugin_vector::iterator end = m_plugins.end(); + for(; it!=end && !m_cancel; ++it) { plugin & p = **it; rule_set * new_rules = p(rules, mc, pc); diff --git a/src/muz_qe/dl_rule_transformer.h b/src/muz_qe/dl_rule_transformer.h index 1cc41a146..cf1a9be75 100644 --- a/src/muz_qe/dl_rule_transformer.h +++ b/src/muz_qe/dl_rule_transformer.h @@ -28,6 +28,8 @@ Revision History: namespace datalog { + class context; + class rule_transformer { public: class plugin; @@ -37,9 +39,10 @@ namespace datalog { typedef svector plugin_vector; struct plugin_comparator; - context & m_context; - rule_manager & m_rule_manager; - bool m_dirty; + context & m_context; + rule_manager & m_rule_manager; + bool m_dirty; + volatile bool m_cancel; svector m_plugins; void ensure_ordered(); @@ -47,6 +50,13 @@ namespace datalog { rule_transformer(context & ctx); ~rule_transformer(); + + /** + \brief Reset all registered transformers. + */ + void reset(); + + void cancel(); /** \brief Add a plugin for rule transformation. @@ -72,6 +82,8 @@ namespace datalog { void attach(rule_transformer & transformer) { m_transformer = &transformer; } protected: + volatile bool m_cancel; + /** \brief Create a plugin object for rule_transformer. @@ -79,7 +91,8 @@ namespace datalog { (higher priority plugins will be applied first). */ plugin(unsigned priority, bool can_destratify_negation = false) : m_priority(priority), - m_can_destratify_negation(can_destratify_negation), m_transformer(0) {} + m_can_destratify_negation(can_destratify_negation), m_transformer(0), m_cancel(false) {} + public: virtual ~plugin() {} @@ -96,8 +109,10 @@ namespace datalog { model_converter_ref& mc, proof_converter_ref& pc) = 0; + virtual void cancel() { m_cancel = true; } + /** - Removes duplicate tails. + Removes duplicate tails. */ static void remove_duplicate_tails(app_ref_vector& tail, svector& tail_neg); diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index c2cfadd14..7a3316c56 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -41,6 +41,7 @@ def_module_params('fixedpoint', ('simplify_formulas_pre', BOOL, False, "PDR: simplify derived formulas before inductive propagation"), ('simplify_formulas_post', BOOL, False, "PDR: simplify derived formulas after inductive propagation"), ('slice', BOOL, True, "PDR: simplify clause set using slicing"), + ('karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), ('coalesce_rules', BOOL, False, "BMC: coalesce rules"), ('use_multicore_generalizer', BOOL, False, "PDR: extract multiple cores for blocking states"), ('use_inductive_generalizer', BOOL, True, "PDR: generalize lemmas using induction strengthening"), diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index e7c7928a3..9fbd8cc2e 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -686,6 +686,7 @@ void hilbert_basis::reset() { m_passive2->reset(); m_zero.reset(); m_index->reset(); + m_ints.reset(); m_cancel = false; } diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 30665c6e5..8bdff1800 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1425,6 +1425,7 @@ namespace pdr { bool ok = checker.check(pr, side_conditions); if (!ok) { msg << "proof validation failed"; + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); throw default_exception(msg.str()); } for (unsigned i = 0; i < side_conditions.size(); ++i) { @@ -1437,6 +1438,7 @@ namespace pdr { lbool res = solver.check(); if (res != l_false) { msg << "rule validation failed when checking: " << mk_pp(cond, m); + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); throw default_exception(msg.str()); } } @@ -1488,6 +1490,7 @@ namespace pdr { lbool res = solver.check(); if (res != l_false) { msg << "rule validation failed when checking: " << mk_pp(tmp, m); + IF_VERBOSE(0, verbose_stream() << msg.str() << "\n";); throw default_exception(msg.str()); } } @@ -1595,6 +1598,7 @@ namespace pdr { catch (unknown_exception) { return l_undef; } + UNREACHABLE(); return l_undef; } diff --git a/src/muz_qe/pdr_util.cpp b/src/muz_qe/pdr_util.cpp index 1ea705e6e..237cf9415 100644 --- a/src/muz_qe/pdr_util.cpp +++ b/src/muz_qe/pdr_util.cpp @@ -32,7 +32,6 @@ Notes: #include "for_each_expr.h" #include "smt_params.h" #include "model.h" -#include "model_v2_pp.h" #include "ref_vector.h" #include "rewriter.h" #include "rewriter_def.h" @@ -42,6 +41,7 @@ Notes: #include "pdr_util.h" #include "arith_decl_plugin.h" #include "expr_replacer.h" +#include "model_smt2_pp.h" namespace pdr { @@ -510,13 +510,24 @@ namespace pdr { set_x(e); } } + + void model_evaluator::eval_exprs(expr_ref_vector& es) { + model_ref mr(m_model); + for (unsigned j = 0; j < es.size(); ++j) { + if (m_array.is_as_array(es[j].get())) { + es[j] = eval(mr, es[j].get()); + } + } + } bool model_evaluator::extract_array_func_interp(expr* a, vector& stores, expr_ref& else_case) { SASSERT(m_array.is_array(a)); + TRACE("pdr", tout << mk_pp(a, m) << "\n";); while (m_array.is_store(a)) { expr_ref_vector store(m); store.append(to_app(a)->get_num_args()-1, to_app(a)->get_args()+1); + eval_exprs(store); stores.push_back(store); a = to_app(a)->get_arg(0); } @@ -526,7 +537,7 @@ namespace pdr { return true; } - if (m_array.is_as_array(a)) { + while (m_array.is_as_array(a)) { func_decl* f = m_array.get_as_array_func_decl(to_app(a)); func_interp* g = m_model->get_func_interp(f); unsigned sz = g->num_entries(); @@ -538,20 +549,30 @@ namespace pdr { store.push_back(fe->get_result()); for (unsigned j = 0; j < store.size(); ++j) { if (!is_ground(store[j].get())) { + TRACE("pdr", tout << "could not extract array interpretation: " << mk_pp(a, m) << "\n" << mk_pp(store[j].get(), m) << "\n";); return false; } } + eval_exprs(store); stores.push_back(store); } else_case = g->get_else(); if (!else_case) { + TRACE("pdr", tout << "no else case " << mk_pp(a, m) << "\n";); return false; } if (!is_ground(else_case)) { + TRACE("pdr", tout << "non-ground else case " << mk_pp(a, m) << "\n" << mk_pp(else_case, m) << "\n";); return false; } + if (m_array.is_as_array(else_case)) { + model_ref mr(m_model); + else_case = eval(mr, else_case); + } + TRACE("pdr", tout << "else case: " << mk_pp(else_case, m) << "\n";); return true; } + TRACE("pdr", tout << "no translation: " << mk_pp(a, m) << "\n";); return false; } @@ -570,7 +591,8 @@ namespace pdr { } sort* s = m.get_sort(arg1); sort* r = get_array_range(s); - if (!r->is_infinite() && !r->is_very_big()) { + // give up evaluating finite domain/range arrays + if (!r->is_infinite() && !r->is_very_big() && !s->is_infinite() && !s->is_very_big()) { TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); set_x(e); return; @@ -591,6 +613,9 @@ namespace pdr { << mk_pp(else1, m) << " " << mk_pp(else2, m) << "\n";); set_false(e); } + else if (m_array.is_array(else1)) { + eval_array_eq(e, else1, else2); + } else { TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); set_x(e); @@ -614,18 +639,23 @@ namespace pdr { if (w1 == w2) { continue; } - else if (m.is_value(w1) && m.is_value(w2)) { + if (m.is_value(w1) && m.is_value(w2)) { TRACE("pdr", tout << "Equality evaluation: " << mk_pp(e, m) << "\n"; tout << mk_pp(s1, m) << " |-> " << mk_pp(w1, m) << "\n"; tout << mk_pp(s2, m) << " |-> " << mk_pp(w2, m) << "\n";); set_false(e); - return; + } + else if (m_array.is_array(w1)) { + eval_array_eq(e, w1, w2); + if (is_true(e)) { + continue; + } } else { TRACE("pdr", tout << "equality is unknown: " << mk_pp(e, m) << "\n";); set_x(e); - return; } + return; } set_true(e); } @@ -869,6 +899,7 @@ namespace pdr { } if (is_x(form)) { IF_VERBOSE(0, verbose_stream() << "formula undetermined in model: " << mk_pp(form, m) << "\n";); + TRACE("pdr", model_smt2_pp(tout, m, *m_model, 0);); has_x = true; } } diff --git a/src/muz_qe/pdr_util.h b/src/muz_qe/pdr_util.h index 220e56b3c..ddbf0d122 100644 --- a/src/muz_qe/pdr_util.h +++ b/src/muz_qe/pdr_util.h @@ -104,6 +104,8 @@ namespace pdr { bool check_model(ptr_vector const & formulas); bool extract_array_func_interp(expr* a, vector& stores, expr_ref& else_case); + + void eval_exprs(expr_ref_vector& es); public: model_evaluator(ast_manager& m) : m(m), m_arith(m), m_array(m), m_refs(m) {} From 21f69c2b3abc349f1412dba74c78fecc585a1987 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 12 Mar 2013 12:27:08 +0000 Subject: [PATCH 009/281] Java API build bugfix. Thanks to Fabian Emmes for reporting this. Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 09aada950..06120e2c4 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -281,7 +281,7 @@ def check_java(): print("Finding jni.h...") if JNI_HOME != None: - if not os.path.exists(path.join(JNI_HOME, 'jni.h')): + if not os.path.exists(os.path.join(JNI_HOME, 'jni.h')): raise MKException("Failed to detect jni.h '%s'; the environment variable JNI_HOME is probably set to the wrong path." % os.path.join(JNI_HOME)) else: # Search for jni.h in the library directories... From 39b9da71184ce12c479ed251d683a546834dbc22 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 13 Mar 2013 19:02:48 -0700 Subject: [PATCH 010/281] Fix bug in smt_model_finder, it was producing the incorrect instantiation set. Signed-off-by: Leonardo de Moura --- src/smt/smt_model_finder.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index e69b7a1b6..2716f6ac0 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -1924,7 +1924,8 @@ namespace smt { m_mutil.mk_add(t1, t2, r); } - bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t) const { + bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t, bool & inv) const { + inv = false; // true if invert the sign TRACE("is_var_and_ground", tout << "is_var_and_ground: " << mk_ismt2_pp(lhs, m_manager) << " " << mk_ismt2_pp(rhs, m_manager) << "\n";); if (is_var(lhs) && is_ground(rhs)) { v = to_var(lhs); @@ -1939,7 +1940,6 @@ namespace smt { return true; } else { - bool inv = false; // true if invert the sign expr_ref tmp(m_manager); if (is_var_plus_ground(lhs, inv, v, tmp) && is_ground(rhs)) { if (inv) @@ -1959,6 +1959,11 @@ namespace smt { return false; } + bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t) const { + bool inv; + return is_var_and_ground(lhs, rhs, v, t, inv); + } + bool is_x_eq_t_atom(expr * n, var * & v, expr_ref & t) const { if (!is_app(n)) return false; @@ -2011,22 +2016,28 @@ namespace smt { if (sign) { bool r = is_le_ge(atom) && is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, t); CTRACE("is_x_gle_t", r, tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n" - << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n";); + << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n"; + tout << "sign: " << sign << "\n";); return r; } else { if (is_le_ge(atom)) { expr_ref tmp(m_manager); - if (is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, tmp)) { + bool le = is_le(atom); + bool inv = false; + if (is_var_and_ground(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1), v, tmp, inv)) { + if (inv) + le = !le; sort * s = m_manager.get_sort(tmp); expr_ref one(m_manager); one = mk_one(s); - if (is_le(atom)) + if (le) mk_add(tmp, one, t); else mk_sub(tmp, one, t); TRACE("is_x_gle_t", tout << "is_x_gle_t: " << mk_ismt2_pp(atom, m_manager) << "\n--->\n" - << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n";); + << mk_ismt2_pp(v, m_manager) << " " << mk_ismt2_pp(t, m_manager) << "\n"; + tout << "sign: " << sign << "\n";); return true; } } From fed2ad2300ee49e82aa3059ec17557005f2ac022 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 5 Feb 2013 09:44:41 -0800 Subject: [PATCH 011/281] Fix nontermination bug Signed-off-by: Leonardo de Moura --- src/smt/smt_model_finder.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 2716f6ac0..f3d0ca3bb 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -1535,8 +1535,23 @@ namespace smt { n1->insert_exception(m_t); } - virtual void populate_inst_sets(quantifier * q, auf_solver & s, context * ctx) { - // do nothing... + virtual void populate_inst_sets(quantifier * q, auf_solver & slv, context * ctx) { + unsigned num_vars = q->get_num_decls(); + ast_manager & m = ctx->get_manager(); + sort * s = q->get_decl_sort(num_vars - m_var_i - 1); + if (m.is_uninterp(s)) { + // For uninterpreted sorst, we add all terms in the context. + // See Section 4.1 in the paper "Complete Quantifier Instantiation" + node * S_q_i = slv.get_uvar(q, m_var_i); + ptr_vector::const_iterator it = ctx->begin_enodes(); + ptr_vector::const_iterator end = ctx->end_enodes(); + for (; it != end; ++it) { + enode * n = *it; + if (ctx->is_relevant(n) && get_sort(n->get_owner()) == s) { + S_q_i->insert(n->get_owner(), n->get_generation()); + } + } + } } }; From b8598225bf0f261154457f76cdb318024f8a5114 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 18 Mar 2013 09:20:25 -0700 Subject: [PATCH 012/281] fix definition of bit_vector::empty() Signed-off-by: Nuno Lopes --- src/util/bit_vector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index f451ae70f..9560af7e2 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -106,7 +106,7 @@ public: } bool empty() const { - return m_num_bits != 0; + return m_num_bits == 0; } unsigned num_words() const { From d1ffeb36b0b6691f9de65cb2e9367da684734a5c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Mar 2013 21:37:44 -0700 Subject: [PATCH 013/281] fix warning messages for unused variables Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_base.cpp | 73 ++++++++-------------------- src/muz_qe/dl_mk_karr_invariants.cpp | 2 - src/muz_qe/dl_relation_manager.cpp | 15 +++--- src/muz_qe/horn_tactic.cpp | 1 - src/muz_qe/rel_context.cpp | 11 ++--- 5 files changed, 32 insertions(+), 70 deletions(-) diff --git a/src/muz_qe/dl_base.cpp b/src/muz_qe/dl_base.cpp index 89ebc7e4e..dd817754f 100644 --- a/src/muz_qe/dl_base.cpp +++ b/src/muz_qe/dl_base.cpp @@ -325,9 +325,20 @@ namespace datalog { return res; } + /** + \brief Default method for complementation. + + It assumes that the compiler creates only tables with + at most one column (0 or 1 columns). + Complementation of tables with more than one columns + is transformed into a cross product of complements and/or + difference. + + */ table_base * table_base::complement(func_decl* p, const table_element * func_columns) const { const table_signature & sig = get_signature(); SASSERT(sig.functional_columns()==0 || func_columns!=0); + SASSERT(sig.first_functional() <= 1); table_base * res = get_plugin().mk_empty(sig); @@ -335,16 +346,14 @@ namespace datalog { fact.resize(sig.first_functional()); fact.append(sig.functional_columns(), func_columns); - if(sig.first_functional()==0) { - if(empty()) { + if (sig.first_functional() == 0) { + if (empty()) { res->add_fact(fact); } return res; } - if(sig.first_functional()!=1) { //now we support only tables with one non-functional column - NOT_IMPLEMENTED_YET(); - } + VERIFY(sig.first_functional() == 1); uint64 upper_bound = get_signature()[0]; bool empty_table = empty(); @@ -356,51 +365,13 @@ namespace datalog { warning_msg(buffer.str().c_str()); } - for(table_element i=0; iadd_fact(fact); } } return res; -#if 0 - svector var_arg_indexes(arity); - var_arg_indexes.fill(0); - - svector var_arg_domain_sizes = s; - - unsigned var_cnt=var_arg_indexes.size(); - table_fact fact; - fact.resize(arity); - fact.fill(0); - unsigned depth=arity; - - while(true) { - if(depth==arity) { - SASSERT(!res->contains_fact(fact)); - if(empty_table || !contains_fact(fact)) { - res->add_fact(fact); - } - depth--; - } - else if(fact[depth]==s[depth]-1) { - val_indexes[depth]=0; - if(depth==0) { - break; - } - depth--; - } - else { - SASSERT(val_indexes[depth] soln; @@ -378,7 +377,6 @@ namespace datalog { } void mk_karr_invariants::update_body(rule_set& rules, rule& r){ - func_decl* p = r.get_decl(); unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); app_ref_vector tail(m); diff --git a/src/muz_qe/dl_relation_manager.cpp b/src/muz_qe/dl_relation_manager.cpp index 76d538b08..3407f8fbe 100644 --- a/src/muz_qe/dl_relation_manager.cpp +++ b/src/muz_qe/dl_relation_manager.cpp @@ -243,15 +243,14 @@ namespace datalog { relation_plugin & relation_manager::get_appropriate_plugin(const relation_signature & s) { relation_plugin * res = try_get_appropriate_plugin(s); - if(!res) { + if (!res) { throw default_exception("no suitable plugin found for given relation signature"); - throw 0; } return *res; } table_plugin * relation_manager::try_get_appropriate_plugin(const table_signature & t) { - if(m_favourite_table_plugin && m_favourite_table_plugin->can_handle_signature(t)) { + if (m_favourite_table_plugin && m_favourite_table_plugin->can_handle_signature(t)) { return m_favourite_table_plugin; } table_plugin_vector::iterator tpit = m_table_plugins.begin(); @@ -346,7 +345,7 @@ namespace datalog { return p->mk_empty(s); } - if(mk_empty_table_relation(s, res)) { + if (mk_empty_table_relation(s, res)) { return res; } @@ -884,10 +883,10 @@ namespace datalog { SASSERT(plugin->can_handle_signature(res_sign)); table_base * res = plugin->mk_empty(res_sign); - unsigned t1cols=t1.get_signature().size(); - unsigned t2cols=t2.get_signature().size(); - unsigned t1first_func=t1.get_signature().first_functional(); - unsigned t2first_func=t2.get_signature().first_functional(); + unsigned t1cols = t1.get_signature().size(); + unsigned t2cols = t2.get_signature().size(); + unsigned t1first_func = t1.get_signature().first_functional(); + unsigned t2first_func = t2.get_signature().first_functional(); table_base::iterator els1it = t1.begin(); table_base::iterator els1end = t1.end(); diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index c22474a7c..b588b07ba 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -233,7 +233,6 @@ class horn_tactic : public tactic { lbool is_reachable = m_ctx.query(q); g->inc_depth(); - bool produce_models = g->models_enabled(); bool produce_proofs = g->proofs_enabled(); result.push_back(g.get()); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 1b4042ab9..00ac51e9f 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -31,9 +31,6 @@ Revision History: #include"dl_sparse_table.h" #include"dl_table.h" #include"dl_table_relation.h" -#ifndef _EXTERNAL_RELEASE -#include"dl_skip_table.h" -#endif namespace datalog { @@ -44,16 +41,16 @@ namespace datalog { m_answer(m), m_cancel(false), m_last_result_relation(0) { + + // register plugins for builtin tables + get_rmanager().register_plugin(alloc(sparse_table_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(hashtable_table_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(bitvector_table_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(equivalence_table_plugin, get_rmanager())); -#ifndef _EXTERNAL_RELEASE - get_rmanager().register_plugin(alloc(skip_table_plugin, get_rmanager())); -#endif - //register plugins for builtin relations + // register plugins for builtin relations get_rmanager().register_plugin(alloc(bound_relation_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(interval_relation_plugin, get_rmanager())); From d4d3ba104eae18e4815bb92fbf1081cbee75d186 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Mar 2013 21:41:00 -0700 Subject: [PATCH 014/281] fix compiler warning for unused variable Signed-off-by: Nikolaj Bjorner --- src/muz_qe/horn_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index b588b07ba..633aeaa81 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -169,7 +169,6 @@ class horn_tactic : public tactic { SASSERT(g->is_well_sorted()); mc = 0; pc = 0; core = 0; tactic_report report("horn", *g); - bool produce_models = g->models_enabled(); bool produce_proofs = g->proofs_enabled(); if (produce_proofs) { @@ -233,6 +232,7 @@ class horn_tactic : public tactic { lbool is_reachable = m_ctx.query(q); g->inc_depth(); + bool produce_models = g->models_enabled(); bool produce_proofs = g->proofs_enabled(); result.push_back(g.get()); From 7e9f4e264dbd027e6060ba12834914f2dfd8b0ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Mar 2013 21:46:42 -0700 Subject: [PATCH 015/281] working on separating horn simplificaiton Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/quant_hoist.cpp | 37 +++- src/ast/rewriter/quant_hoist.h | 8 + src/muz_qe/dl_bmc_engine.cpp | 14 +- src/muz_qe/dl_context.cpp | 14 +- src/muz_qe/dl_context.h | 14 +- src/muz_qe/dl_rule.cpp | 13 +- src/muz_qe/dl_rule.h | 8 + src/muz_qe/dl_util.cpp | 161 +----------------- src/muz_qe/dl_util.h | 76 --------- src/muz_qe/horn_tactic.cpp | 6 +- src/muz_qe/pdr_dl_interface.cpp | 34 ++-- src/muz_qe/rel_context.cpp | 12 +- src/shell/datalog_frontend.cpp | 4 +- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 54 ++++-- 14 files changed, 160 insertions(+), 295 deletions(-) diff --git a/src/ast/rewriter/quant_hoist.cpp b/src/ast/rewriter/quant_hoist.cpp index b64e71866..e4275ab9c 100644 --- a/src/ast/rewriter/quant_hoist.cpp +++ b/src/ast/rewriter/quant_hoist.cpp @@ -25,7 +25,7 @@ Revision History: #include "bool_rewriter.h" #include "var_subst.h" #include "ast_pp.h" - +#include "ast_counter.h" // // Bring quantifiers of common type into prenex form. @@ -215,6 +215,37 @@ private: break; } } + + unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { + unsigned index = var_counter().get_next_var(fml); + while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) { + quantifier* q = to_quantifier(fml); + index += q->get_num_decls(); + if (names) { + names->append(q->get_num_decls(), q->get_decl_names()); + } + fml = q->get_expr(); + } + if (!has_quantifiers(fml)) { + return index; + } + app_ref_vector vars(m); + pull_quantifier(is_forall, fml, vars); + if (vars.empty()) { + return index; + } + // replace vars by de-bruijn indices + expr_safe_replace rep(m); + for (unsigned i = 0; i < vars.size(); ++i) { + app* v = vars[i].get(); + if (names) { + names->push_back(v->get_decl()->get_name()); + } + rep.insert(v, m.mk_var(index++,m.get_sort(v))); + } + rep(fml); + return index; + } }; quantifier_hoister::quantifier_hoister(ast_manager& m) { @@ -237,3 +268,7 @@ void quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, app_ref_ m_impl->pull_quantifier(is_forall, fml, vars); } +unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { + return m_impl->pull_quantifier(is_forall, fml, names); +} + diff --git a/src/ast/rewriter/quant_hoist.h b/src/ast/rewriter/quant_hoist.h index 878f7840d..70a79a0e2 100644 --- a/src/ast/rewriter/quant_hoist.h +++ b/src/ast/rewriter/quant_hoist.h @@ -59,6 +59,14 @@ public: The list of variables is empty if there are no top-level universal/existential quantifier. */ void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars); + + /** + \brief Pull top-most universal (is_forall true) or existential (is_forall=false) quantifier up. + Return an expression with de-Bruijn indices and the list of names that were used. + Return index of maximal variable. + */ + + unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names); }; #endif diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp index 80fcdea4a..a7c1bf7eb 100644 --- a/src/muz_qe/dl_bmc_engine.cpp +++ b/src/muz_qe/dl_bmc_engine.cpp @@ -1413,20 +1413,22 @@ namespace datalog { datalog::rule_set old_rules(m_ctx.get_rules()); datalog::rule_ref_vector query_rules(rule_manager); datalog::rule_ref query_rule(rule_manager); - rule_manager.mk_query(query, m_query_pred, query_rules, query_rule); - m_ctx.add_rules(query_rules); - expr_ref bg_assertion = m_ctx.get_background_assertion(); - model_converter_ref mc = datalog::mk_skip_model_converter(); m_pc = datalog::mk_skip_proof_converter(); + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(m_pc); + rule_manager.mk_query(query, m_query_pred, query_rules, query_rule); + m_ctx.add_rules(query_rules); + expr_ref bg_assertion = m_ctx.get_background_assertion(); + m_ctx.set_output_predicate(m_query_pred); - m_ctx.apply_default_transformation(mc, m_pc); + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, m_pc); + m_ctx.transform_rules(transformer); m_query_pred = slice->get_predicate(m_query_pred.get()); m_ctx.set_output_predicate(m_query_pred); } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 53231e7b0..eb782aac8 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -474,6 +474,8 @@ namespace datalog { void context::flush_add_rules() { datalog::rule_manager& rm = get_rule_manager(); datalog::rule_ref_vector rules(rm); + rm.set_model_converter(m_mc); + rm.set_proof_converter(m_pc); for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { rm.mk_rule(m_rule_fmls[i].get(), rules, m_rule_names[i]); } @@ -826,7 +828,7 @@ namespace datalog { m_closed = false; } - void context::transform_rules(model_converter_ref& mc, proof_converter_ref& pc) { + void context::transform_rules() { m_transf.reset(); m_transf.register_plugin(alloc(mk_filter_rules,*this)); m_transf.register_plugin(alloc(mk_simple_joins,*this)); @@ -841,13 +843,13 @@ namespace datalog { } m_transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this)); - transform_rules(m_transf, mc, pc); + transform_rules(m_transf); } - void context::transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc) { + void context::transform_rules(rule_transformer& transf) { SASSERT(m_closed); //we must finish adding rules before we start transforming them TRACE("dl", display_rules(tout);); - if (transf(m_rule_set, mc, pc)) { + if (transf(m_rule_set, m_mc, m_pc)) { //we have already ensured the negation is stratified and transformations //should not break the stratification m_rule_set.ensure_closed(); @@ -862,7 +864,7 @@ namespace datalog { m_rule_set.add_rules(rs); } - void context::apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc) { + void context::apply_default_transformation() { ensure_closed(); m_transf.reset(); m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this)); @@ -890,7 +892,7 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); - transform_rules(m_transf, mc, pc); + transform_rules(m_transf); } void context::collect_params(param_descrs& p) { diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index b587daf7f..7ca6b278c 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -85,6 +85,8 @@ namespace datalog { var_subst m_var_subst; rule_manager m_rule_manager; rule_transformer m_transf; + model_converter_ref m_mc; + proof_converter_ref m_pc; trail_stack m_trail; ast_ref_vector m_pinned; @@ -110,6 +112,8 @@ namespace datalog { DL_ENGINE m_engine; volatile bool m_cancel; + + bool is_fact(app * head) const; bool has_sort_domain(relation_sort s) const; sort_domain & get_sort_domain(relation_sort s); @@ -313,11 +317,15 @@ namespace datalog { void reopen(); void ensure_opened(); - void transform_rules(model_converter_ref& mc, proof_converter_ref& pc); - void transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc); + void set_model_converter(model_converter_ref& mc) { m_mc = mc; } + void set_proof_converter(proof_converter_ref& pc) { m_pc = pc; } + + void transform_rules(); + void transform_rules(rule_transformer::plugin* plugin); + void transform_rules(rule_transformer& transf); void replace_rules(rule_set & rs); - void apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc); + void apply_default_transformation(); void collect_params(param_descrs& r); diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 3814d0b62..0b626d72e 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -56,16 +56,16 @@ namespace datalog { void rule_manager::inc_ref(rule * r) { if (r) { - SASSERT(r->m_ref_cnt!=UINT_MAX); + SASSERT(r->m_ref_cnt != UINT_MAX); r->m_ref_cnt++; } } void rule_manager::dec_ref(rule * r) { if (r) { - SASSERT(r->m_ref_cnt>0); + SASSERT(r->m_ref_cnt > 0); r->m_ref_cnt--; - if (r->m_ref_cnt==0) { + if (r->m_ref_cnt == 0) { r->deallocate(m); } } @@ -103,8 +103,13 @@ namespace datalog { m_memoize_disj.reset(); m_refs.reset(); bind_variables(fml, true, fml1); - remove_labels(fml1); + unsigned num_rules = rules.size(); mk_rule_core(fml1, rules, name); + if (m_pc) { + // big-step proof + // m.mk_cnf_star(fml1, conj, 0, 0); + // + } } // diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index c01b36162..ebd93d090 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -24,6 +24,9 @@ Revision History: #include"dl_costs.h" #include"dl_util.h" #include"used_vars.h" +#include"proof_converter.h" +#include"model_converter.h" +#include"ast_counter.h" namespace datalog { @@ -48,12 +51,17 @@ namespace datalog { var_counter m_var_counter; obj_map m_memoize_disj; expr_ref_vector m_refs; + model_converter_ref m_mc; + proof_converter_ref m_pc; // only the context can create a rule_manager friend class context; explicit rule_manager(context& ctx); + void set_model_converter(model_converter_ref& mc) { m_mc = mc; } + void set_proof_converter(proof_converter_ref& pc) { m_pc = pc; } + /** \brief Move functions from predicate tails into the interpreted tail by introducing new variables. */ diff --git a/src/muz_qe/dl_util.cpp b/src/muz_qe/dl_util.cpp index 4a406578c..3b5ca7658 100644 --- a/src/muz_qe/dl_util.cpp +++ b/src/muz_qe/dl_util.cpp @@ -431,166 +431,6 @@ namespace datalog { } } - void counter::update(unsigned el, int delta) { - int & counter = get(el); - SASSERT(!m_stay_non_negative || counter>=0); - SASSERT(!m_stay_non_negative || static_cast(counter)>=-delta); - counter += delta; - } - - int & counter::get(unsigned el) { - return m_data.insert_if_not_there2(el, 0)->get_data().m_value; - } - - counter & counter::count(unsigned sz, const unsigned * els, int delta) { - for(unsigned i=0; im_value>0 ) { - cnt++; - } - } - return cnt; - } - - void counter::collect_positive(idx_set & acc) const { - iterator eit = begin(); - iterator eend = end(); - for(; eit!=eend; ++eit) { - if(eit->m_value>0) { acc.insert(eit->m_key); } - } - } - - bool counter::get_max_positive(unsigned & res) const { - bool found = false; - iterator eit = begin(); - iterator eend = end(); - for(; eit!=eend; ++eit) { - if( eit->m_value>0 && (!found || eit->m_key>res) ) { - found = true; - res = eit->m_key; - } - } - return found; - } - - unsigned counter::get_max_positive() const { - unsigned max_pos; - VERIFY(get_max_positive(max_pos)); - return max_pos; - } - - int counter::get_max_counter_value() const { - int res = 0; - iterator eit = begin(); - iterator eend = end(); - for (; eit!=eend; ++eit) { - if( eit->m_value>res ) { - res = eit->m_value; - } - } - return res; - } - - void var_counter::count_vars(ast_manager & m, const app * pred, int coef) { - unsigned n = pred->get_num_args(); - for (unsigned i = 0; i < n; i++) { - m_sorts.reset(); - ::get_free_vars(pred->get_arg(i), m_sorts); - for (unsigned j = 0; j < m_sorts.size(); ++j) { - if (m_sorts[j]) { - update(j, coef); - } - } - } - } - - void var_counter::count_vars(ast_manager & m, const rule * r, int coef) { - count_vars(m, r->get_head(), 1); - unsigned n = r->get_tail_size(); - for (unsigned i = 0; i < n; i++) { - count_vars(m, r->get_tail(i), coef); - } - } - - unsigned var_counter::get_max_var(bool& has_var) { - has_var = false; - unsigned max_var = 0; - while (!m_todo.empty()) { - expr* e = m_todo.back(); - unsigned scope = m_scopes.back(); - m_todo.pop_back(); - m_scopes.pop_back(); - if (m_visited.is_marked(e)) { - continue; - } - m_visited.mark(e, true); - switch(e->get_kind()) { - case AST_QUANTIFIER: { - quantifier* q = to_quantifier(e); - m_todo.push_back(q->get_expr()); - m_scopes.push_back(scope + q->get_num_decls()); - break; - } - case AST_VAR: { - if (to_var(e)->get_idx() >= scope + max_var) { - has_var = true; - max_var = to_var(e)->get_idx() - scope; - } - break; - } - case AST_APP: { - app* a = to_app(e); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - m_todo.push_back(a->get_arg(i)); - m_scopes.push_back(scope); - } - break; - } - default: - UNREACHABLE(); - break; - } - } - m_visited.reset(); - return max_var; - } - - unsigned var_counter::get_max_var(const rule & r) { - m_todo.push_back(r.get_head()); - m_scopes.push_back(0); - unsigned n = r.get_tail_size(); - bool has_var = false; - for (unsigned i = 0; i < n; i++) { - m_todo.push_back(r.get_tail(i)); - m_scopes.push_back(0); - } - return get_max_var(has_var); - } - - unsigned var_counter::get_max_var(expr* e) { - bool has_var = false; - m_todo.push_back(e); - m_scopes.push_back(0); - return get_max_var(has_var); - } - - unsigned var_counter::get_next_var(expr* e) { - bool has_var = false; - m_todo.push_back(e); - m_scopes.push_back(0); - unsigned mv = get_max_var(has_var); - if (has_var) mv++; - return mv; - } void del_rule(horn_subsume_model_converter* mc, rule& r) { if (mc) { @@ -614,6 +454,7 @@ namespace datalog { } } + void resolve_rule(replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx, expr_ref_vector const& s1, expr_ref_vector const& s2, rule const& res) { if (!pc) return; diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index 69be7e9ac..4314b87f3 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -411,82 +411,6 @@ namespace datalog { } - class counter { - protected: - typedef u_map map_impl; - map_impl m_data; - const bool m_stay_non_negative; - public: - typedef map_impl::iterator iterator; - - counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} - - iterator begin() const { return m_data.begin(); } - iterator end() const { return m_data.end(); } - - void update(unsigned el, int delta); - int & get(unsigned el); - /** - \brief Increase values of elements in \c els by \c delta. - - The function returns a reference to \c *this to allow for expressions like - counter().count(sz, arr).get_positive_count() - */ - counter & count(unsigned sz, const unsigned * els, int delta = 1); - counter & count(const unsigned_vector & els, int delta = 1) { - return count(els.size(), els.c_ptr(), delta); - } - - void collect_positive(idx_set & acc) const; - unsigned get_positive_count() const; - bool get_max_positive(unsigned & res) const; - unsigned get_max_positive() const; - /** - Since the default counter value of a counter is zero, the result is never negative. - */ - int get_max_counter_value() const; - }; - - class var_counter : public counter { - ptr_vector m_sorts; - expr_fast_mark1 m_visited; - ptr_vector m_todo; - unsigned_vector m_scopes; - unsigned get_max_var(bool & has_var); - - public: - var_counter(bool stay_non_negative = true) : counter(stay_non_negative) {} - void count_vars(ast_manager & m, const app * t, int coef = 1); - void count_vars(ast_manager & m, const rule * r, int coef = 1); - unsigned get_max_var(const rule& r); - unsigned get_max_var(expr* e); - unsigned get_next_var(expr* e); - }; - - class ast_counter { - typedef obj_map map_impl; - map_impl m_data; - bool m_stay_non_negative; - public: - typedef map_impl::iterator iterator; - - ast_counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} - - iterator begin() const { return m_data.begin(); } - iterator end() const { return m_data.end(); } - - int & get(ast * el) { - return m_data.insert_if_not_there2(el, 0)->get_data().m_value; - } - void update(ast * el, int delta){ - get(el)+=delta; - SASSERT(!m_stay_non_negative || get(el)>=0); - } - - void inc(ast * el) { update(el, 1); } - void dec(ast * el) { update(el, -1); } - }; - void del_rule(horn_subsume_model_converter* mc, rule& r); void resolve_rule(replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx, diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index c22474a7c..7596f8915 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -284,13 +284,15 @@ class horn_tactic : public tactic { func_decl* query_pred = to_app(q)->get_decl(); m_ctx.set_output_predicate(query_pred); m_ctx.get_rules(); // flush adding rules. - m_ctx.apply_default_transformation(mc, pc); + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(pc); + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, pc); + m_ctx.transform_rules(transformer); } expr_substitution sub(m); diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index 54a40f8b8..3498b7969 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -89,12 +89,19 @@ lbool dl_interface::query(expr * query) { func_decl_ref query_pred(m); datalog::rule_ref_vector query_rules(rule_manager); datalog::rule_ref query_rule(rule_manager); + model_converter_ref mc = datalog::mk_skip_model_converter(); + proof_converter_ref pc; + if (m_ctx.get_params().generate_proof_trace()) { + pc = datalog::mk_skip_proof_converter(); + } + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(pc); rule_manager.mk_query(query, query_pred, query_rules, query_rule); m_ctx.add_rules(query_rules); expr_ref bg_assertion = m_ctx.get_background_assertion(); check_reset(); - + TRACE("pdr", if (!m.is_true(bg_assertion)) { tout << "axioms:\n"; @@ -105,19 +112,15 @@ lbool dl_interface::query(expr * query) { m_ctx.display_rules(tout); ); - model_converter_ref mc = datalog::mk_skip_model_converter(); - proof_converter_ref pc; - if (m_ctx.get_params().generate_proof_trace()) { - pc = datalog::mk_skip_proof_converter(); - } m_ctx.set_output_predicate(query_pred); - m_ctx.apply_default_transformation(mc, pc); + + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, pc); + m_ctx.transform_rules(transformer); query_pred = slice->get_predicate(query_pred.get()); m_ctx.set_output_predicate(query_pred); @@ -134,22 +137,25 @@ lbool dl_interface::query(expr * query) { if (m_ctx.get_params().unfold_rules() > 0) { unsigned num_unfolds = m_ctx.get_params().unfold_rules(); - datalog::rule_transformer transformer1(m_ctx), transformer2(m_ctx); + datalog::rule_transformer transf1(m_ctx), transf2(m_ctx); + transf1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); + transf2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); if (m_ctx.get_params().coalesce_rules()) { - transformer1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); - m_ctx.transform_rules(transformer1, mc, pc); + m_ctx.transform_rules(transf1); } - transformer2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); while (num_unfolds > 0) { - m_ctx.transform_rules(transformer2, mc, pc); + m_ctx.transform_rules(transf2); --num_unfolds; } } // remove universal quantifiers from body. + + + datalog::mk_extract_quantifiers* extract_quantifiers = alloc(datalog::mk_extract_quantifiers, m_ctx); datalog::rule_transformer extract_q_tr(m_ctx); extract_q_tr.register_plugin(extract_quantifiers); - m_ctx.transform_rules(extract_q_tr, mc, pc); + m_ctx.transform_rules(extract_q_tr); IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 1b4042ab9..bd09e67a6 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -106,9 +106,7 @@ namespace datalog { TRACE("dl", m_context.display(tout);); while (true) { - model_converter_ref mc; // Ignored in Datalog mode - proof_converter_ref pc; // Ignored in Datalog mode - m_context.transform_rules(mc, pc); + m_context.transform_rules(); compiler::compile(m_context, m_context.get_rules(), rules_code, termination_code); TRACE("dl", rules_code.display(*this, tout); ); @@ -266,14 +264,12 @@ namespace datalog { reset_negated_tables(); if (m_context.generate_explanations()) { - model_converter_ref mc; // ignored in Datalog mode - proof_converter_ref pc; // ignored in Datalog mode rule_transformer transformer(m_context); //expl_plugin is deallocated when transformer goes out of scope mk_explanations * expl_plugin = alloc(mk_explanations, m_context, m_context.explanations_on_relation_level()); transformer.register_plugin(expl_plugin); - m_context.transform_rules(transformer, mc, pc); + m_context.transform_rules(transformer); //we will retrieve the predicate with explanations instead of the original query predicate query_pred = expl_plugin->get_e_decl(query_pred); @@ -283,11 +279,9 @@ namespace datalog { } if (m_context.magic_sets_for_queries()) { - model_converter_ref mc; // Ignored in Datalog mode - proof_converter_ref pc; // Ignored in Datalog mode rule_transformer transformer(m_context); transformer.register_plugin(alloc(mk_magic_sets, m_context, qrule.get())); - m_context.transform_rules(transformer, mc, pc); + m_context.transform_rules(transformer); } lbool res = saturate(); diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 44a9d9b66..07052609e 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -200,9 +200,7 @@ unsigned read_datalog(char const * file) { timeout = UINT_MAX; } do { - model_converter_ref mc; // ignored - proof_converter_ref pc; // ignored - ctx.transform_rules(mc, pc); + ctx.transform_rules(); datalog::compiler::compile(ctx, ctx.get_rules(), rules_code, termination_code); diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index 25c41c2a2..0092cdd38 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -92,7 +92,34 @@ protected: ptr_vector fmls; g.get_formulas(fmls); fml = m.mk_and(fmls.size(), fmls.c_ptr()); + m_solver.push(); reduce(fml); + m_solver.pop(1); + SASSERT(m_solver.get_scope_level() == 0); + TRACE("ctx_solver_simplify_tactic", + for (unsigned i = 0; i < fmls.size(); ++i) { + tout << mk_pp(fmls[i], m) << "\n"; + } + tout << "=>\n"; + tout << mk_pp(fml, m) << "\n";); + DEBUG_CODE( + { + m_solver.push(); + expr_ref fml1(m); + fml1 = m.mk_and(fmls.size(), fmls.c_ptr()); + fml1 = m.mk_iff(fml, fml1); + fml1 = m.mk_not(fml1); + m_solver.assert_expr(fml1); + lbool is_sat = m_solver.check(); + TRACE("ctx_solver_simplify_tactic", tout << "is non-equivalence sat?: " << is_sat << "\n";); + if (is_sat != l_false) { + TRACE("ctx_solver_simplify_tactic", + tout << "result is not equivalent to input\n"; + tout << mk_pp(fml1, m) << "\n";); + UNREACHABLE(); + } + m_solver.pop(1); + }); g.reset(); g.assert_expr(fml, 0, 0); IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(ctx-solver-simplify :num-steps " << m_num_steps << ")\n";); @@ -106,21 +133,22 @@ protected: svector is_checked; svector parent_ids, self_ids; expr_ref_vector fresh_vars(m), trail(m); - expr_ref res(m); + expr_ref res(m), tmp(m); obj_map > cache; unsigned id = 1; - expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); expr* n2, *fml; unsigned path_id = 0, self_pos = 0; app * a; unsigned sz; std::pair path_r; ptr_vector found; + expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + trail.push_back(n); fml = result.get(); - m_solver.assert_expr(m.mk_not(m.mk_iff(fml, n))); + tmp = m.mk_not(m.mk_iff(fml, n)); + m_solver.assert_expr(tmp); - trail.push_back(n); todo.push_back(fml); names.push_back(n); is_checked.push_back(false); @@ -144,6 +172,7 @@ protected: goto done; } if (m.is_bool(e) && !checked && simplify_bool(n, res)) { + TRACE("ctx_solver_simplify_tactic", tout << "simplified: " << mk_pp(e, m) << " |-> " << mk_pp(res, m) << "\n";); goto done; } if (!is_app(e)) { @@ -176,7 +205,7 @@ protected: found.push_back(arg); if (path_r.first == self_pos) { - TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << "\n";); + TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << " |-> " << mk_pp(path_r.second, m) << "\n";); args.push_back(path_r.second); } else { @@ -188,11 +217,11 @@ protected: } else if (!n2 && !found.contains(arg)) { n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + trail.push_back(n2); todo.push_back(arg); parent_ids.push_back(self_pos); self_ids.push_back(0); names.push_back(n2); - trail.push_back(n2); args.push_back(n2); is_checked.push_back(false); } @@ -205,7 +234,8 @@ protected: // child needs to be visited. if (n2) { m_solver.push(); - m_solver.assert_expr(m.mk_eq(res, n)); + tmp = m.mk_eq(res, n); + m_solver.assert_expr(tmp); continue; } @@ -229,7 +259,7 @@ protected: } bool simplify_bool(expr* n, expr_ref& res) { - + expr_ref tmp(m); m_solver.push(); m_solver.assert_expr(n); lbool is_sat = m_solver.check(); @@ -240,7 +270,8 @@ protected: } m_solver.push(); - m_solver.assert_expr(m.mk_not(n)); + tmp = m.mk_not(n); + m_solver.assert_expr(tmp); is_sat = m_solver.check(); m_solver.pop(1); if (is_sat == l_false) { @@ -254,7 +285,7 @@ protected: expr_ref local_simplify(app* a, expr* n, unsigned& id, unsigned index) { SASSERT(index < a->get_num_args()); SASSERT(m.is_bool(a->get_arg(index))); - expr_ref n2(m), result(m); + expr_ref n2(m), result(m), tmp(m); n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); ptr_buffer args; for (unsigned i = 0; i < a->get_num_args(); ++i) { @@ -267,7 +298,8 @@ protected: } m_mk_app(a->get_decl(), args.size(), args.c_ptr(), result); m_solver.push(); - m_solver.assert_expr(m.mk_eq(result, n)); + tmp = m.mk_eq(result, n); + m_solver.assert_expr(tmp); if (!simplify_bool(n2, result)) { result = a; } From b0787024c72f8966004df580002ca2e7de8f83b3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Mar 2013 09:47:52 -0700 Subject: [PATCH 016/281] Move ast_counter to location for common utilities. It depends on get_free_vars, so is in rewriter directory Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_compiler.cpp | 4 +- src/muz_qe/dl_mk_explanations.cpp | 4 +- src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 6 +- src/muz_qe/dl_mk_karr_invariants.cpp | 2 +- src/muz_qe/dl_mk_rule_inliner.cpp | 8 +- src/muz_qe/dl_mk_similarity_compressor.cpp | 6 +- src/muz_qe/dl_mk_simple_joins.cpp | 4 +- src/muz_qe/dl_rule.cpp | 2 +- src/muz_qe/dl_rule.h | 4 +- src/muz_qe/dl_util.cpp | 150 +----------------- src/muz_qe/dl_util.h | 84 +--------- src/muz_qe/pdr_context.cpp | 6 +- src/muz_qe/pdr_quantifiers.cpp | 4 +- src/muz_qe/tab_context.cpp | 2 +- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 54 +++++-- 15 files changed, 78 insertions(+), 262 deletions(-) diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index 44a449779..cc56df4b7 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -384,8 +384,8 @@ namespace datalog { void compiler::get_local_indexes_for_projection(rule * r, unsigned_vector & res) { SASSERT(r->get_positive_tail_size()==2); ast_manager & m = m_context.get_manager(); - var_counter counter; - counter.count_vars(m, r); + rule_counter counter; + counter.count_rule_vars(m, r); app * t1 = r->get_tail(0); app * t2 = r->get_tail(1); counter.count_vars(m, t1, -1); diff --git a/src/muz_qe/dl_mk_explanations.cpp b/src/muz_qe/dl_mk_explanations.cpp index b4683bdbe..464ec838e 100644 --- a/src/muz_qe/dl_mk_explanations.cpp +++ b/src/muz_qe/dl_mk_explanations.cpp @@ -708,8 +708,8 @@ namespace datalog { } rule * mk_explanations::get_e_rule(rule * r) { - var_counter ctr; - ctr.count_vars(m_manager, r); + rule_counter ctr; + ctr.count_rule_vars(m_manager, r); unsigned max_var; unsigned next_var = ctr.get_max_positive(max_var) ? (max_var+1) : 0; unsigned head_var = next_var++; diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index d028c8751..d1b7f15dd 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -35,7 +35,7 @@ namespace datalog { // ----------------------------------- void mk_interp_tail_simplifier::rule_substitution::reset(rule * r) { - unsigned var_cnt = m_context.get_rule_manager().get_var_counter().get_max_var(*r)+1; + unsigned var_cnt = m_context.get_rule_manager().get_counter().get_max_rule_var(*r)+1; m_subst.reset(); m_subst.reserve(1, var_cnt); m_rule = r; @@ -541,8 +541,8 @@ namespace datalog { rule_ref pro_var_eq_result(m_context.get_rule_manager()); if (propagate_variable_equivalences(res, pro_var_eq_result)) { - SASSERT(var_counter().get_max_var(*r.get())==0 || - var_counter().get_max_var(*r.get()) > var_counter().get_max_var(*pro_var_eq_result.get())); + SASSERT(rule_counter().get_max_rule_var(*r.get())==0 || + rule_counter().get_max_rule_var(*r.get()) > rule_counter().get_max_rule_var(*pro_var_eq_result.get())); r = pro_var_eq_result; goto start; } diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index f690346bc..9c034c890 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -145,7 +145,7 @@ namespace datalog { } bool mk_karr_invariants::get_transition_relation(rule const& r, matrix& M) { - unsigned num_vars = rm.get_var_counter().get_max_var(r)+1; + unsigned num_vars = rm.get_counter().get_max_rule_var(r)+1; unsigned arity = r.get_decl()->get_arity(); unsigned num_columns = arity + num_vars; unsigned utsz = r.get_uninterpreted_tail_size(); diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp index 0919e2ff0..1404c9c8c 100644 --- a/src/muz_qe/dl_mk_rule_inliner.cpp +++ b/src/muz_qe/dl_mk_rule_inliner.cpp @@ -65,8 +65,8 @@ namespace datalog { // ----------------------------------- bool rule_unifier::unify_rules(const rule& tgt, unsigned tgt_idx, const rule& src) { - var_counter& vc = m_rm.get_var_counter(); - unsigned var_cnt = std::max(vc.get_max_var(tgt), vc.get_max_var(src))+1; + rule_counter& vc = m_rm.get_counter(); + unsigned var_cnt = std::max(vc.get_max_rule_var(tgt), vc.get_max_rule_var(src))+1; m_subst.reset(); m_subst.reserve(2, var_cnt); @@ -733,7 +733,7 @@ namespace datalog { } // initialize substitution. - var_counter& vc = m_rm.get_var_counter(); + rule_counter& vc = m_rm.get_counter(); unsigned max_var = 0; for (unsigned i = 0; i < sz; ++i) { rule* r = acc[i].get(); @@ -820,7 +820,7 @@ namespace datalog { del_rule(r2, j); } - max_var = std::max(max_var, vc.get_max_var(*r.get())); + max_var = std::max(max_var, vc.get_max_rule_var(*r.get())); m_subst.reserve_vars(max_var+1); } diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index 42a5ba367..a040a623a 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -372,10 +372,10 @@ namespace datalog { new_negs.push_back(r->is_neg_tail(i)); } - var_counter var_ctr; - var_ctr.count_vars(m_manager, r); + rule_counter ctr; + ctr.count_rule_vars(m_manager, r); unsigned max_var_idx, new_var_idx_base; - if(var_ctr.get_max_positive(max_var_idx)) { + if(ctr.get_max_positive(max_var_idx)) { new_var_idx_base = max_var_idx+1; } else { diff --git a/src/muz_qe/dl_mk_simple_joins.cpp b/src/muz_qe/dl_mk_simple_joins.cpp index 363a4f0f7..77c6c2951 100644 --- a/src/muz_qe/dl_mk_simple_joins.cpp +++ b/src/muz_qe/dl_mk_simple_joins.cpp @@ -310,8 +310,8 @@ namespace datalog { } void register_rule(rule * r) { - var_counter counter; - counter.count_vars(m, r, 1); + rule_counter counter; + counter.count_rule_vars(m, r, 1); ptr_vector & rule_content = m_rules_content.insert_if_not_there2(r, ptr_vector())->get_data().m_value; diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 3814d0b62..de41e4774 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -705,7 +705,7 @@ namespace datalog { bool_rewriter(m).mk_and(tails_with_unbound.size(), tails_with_unbound.c_ptr(), unbound_tail); unsigned q_var_cnt = unbound_vars.num_elems(); - unsigned max_var = m_var_counter.get_max_var(*r); + unsigned max_var = m_counter.get_max_rule_var(*r); expr_ref_vector subst(m); diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index c01b36162..4afc08edb 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -45,7 +45,7 @@ namespace datalog { { ast_manager& m; context& m_ctx; - var_counter m_var_counter; + rule_counter m_counter; obj_map m_memoize_disj; expr_ref_vector m_refs; @@ -162,7 +162,7 @@ namespace datalog { static bool is_forall(ast_manager& m, expr* e, quantifier*& q); - var_counter& get_var_counter() { return m_var_counter; } + rule_counter& get_counter() { return m_counter; } }; diff --git a/src/muz_qe/dl_util.cpp b/src/muz_qe/dl_util.cpp index 4a406578c..bde03e765 100644 --- a/src/muz_qe/dl_util.cpp +++ b/src/muz_qe/dl_util.cpp @@ -431,89 +431,8 @@ namespace datalog { } } - void counter::update(unsigned el, int delta) { - int & counter = get(el); - SASSERT(!m_stay_non_negative || counter>=0); - SASSERT(!m_stay_non_negative || static_cast(counter)>=-delta); - counter += delta; - } - - int & counter::get(unsigned el) { - return m_data.insert_if_not_there2(el, 0)->get_data().m_value; - } - - counter & counter::count(unsigned sz, const unsigned * els, int delta) { - for(unsigned i=0; im_value>0 ) { - cnt++; - } - } - return cnt; - } - - void counter::collect_positive(idx_set & acc) const { - iterator eit = begin(); - iterator eend = end(); - for(; eit!=eend; ++eit) { - if(eit->m_value>0) { acc.insert(eit->m_key); } - } - } - - bool counter::get_max_positive(unsigned & res) const { - bool found = false; - iterator eit = begin(); - iterator eend = end(); - for(; eit!=eend; ++eit) { - if( eit->m_value>0 && (!found || eit->m_key>res) ) { - found = true; - res = eit->m_key; - } - } - return found; - } - - unsigned counter::get_max_positive() const { - unsigned max_pos; - VERIFY(get_max_positive(max_pos)); - return max_pos; - } - - int counter::get_max_counter_value() const { - int res = 0; - iterator eit = begin(); - iterator eend = end(); - for (; eit!=eend; ++eit) { - if( eit->m_value>res ) { - res = eit->m_value; - } - } - return res; - } - - void var_counter::count_vars(ast_manager & m, const app * pred, int coef) { - unsigned n = pred->get_num_args(); - for (unsigned i = 0; i < n; i++) { - m_sorts.reset(); - ::get_free_vars(pred->get_arg(i), m_sorts); - for (unsigned j = 0; j < m_sorts.size(); ++j) { - if (m_sorts[j]) { - update(j, coef); - } - } - } - } - - void var_counter::count_vars(ast_manager & m, const rule * r, int coef) { + + void rule_counter::count_rule_vars(ast_manager & m, const rule * r, int coef) { count_vars(m, r->get_head(), 1); unsigned n = r->get_tail_size(); for (unsigned i = 0; i < n; i++) { @@ -521,50 +440,7 @@ namespace datalog { } } - unsigned var_counter::get_max_var(bool& has_var) { - has_var = false; - unsigned max_var = 0; - while (!m_todo.empty()) { - expr* e = m_todo.back(); - unsigned scope = m_scopes.back(); - m_todo.pop_back(); - m_scopes.pop_back(); - if (m_visited.is_marked(e)) { - continue; - } - m_visited.mark(e, true); - switch(e->get_kind()) { - case AST_QUANTIFIER: { - quantifier* q = to_quantifier(e); - m_todo.push_back(q->get_expr()); - m_scopes.push_back(scope + q->get_num_decls()); - break; - } - case AST_VAR: { - if (to_var(e)->get_idx() >= scope + max_var) { - has_var = true; - max_var = to_var(e)->get_idx() - scope; - } - break; - } - case AST_APP: { - app* a = to_app(e); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - m_todo.push_back(a->get_arg(i)); - m_scopes.push_back(scope); - } - break; - } - default: - UNREACHABLE(); - break; - } - } - m_visited.reset(); - return max_var; - } - - unsigned var_counter::get_max_var(const rule & r) { + unsigned rule_counter::get_max_rule_var(const rule & r) { m_todo.push_back(r.get_head()); m_scopes.push_back(0); unsigned n = r.get_tail_size(); @@ -576,22 +452,6 @@ namespace datalog { return get_max_var(has_var); } - unsigned var_counter::get_max_var(expr* e) { - bool has_var = false; - m_todo.push_back(e); - m_scopes.push_back(0); - return get_max_var(has_var); - } - - unsigned var_counter::get_next_var(expr* e) { - bool has_var = false; - m_todo.push_back(e); - m_scopes.push_back(0); - unsigned mv = get_max_var(has_var); - if (has_var) mv++; - return mv; - } - void del_rule(horn_subsume_model_converter* mc, rule& r) { if (mc) { ast_manager& m = mc->get_manager(); @@ -678,10 +538,6 @@ namespace datalog { proof_converter* mk_skip_proof_converter() { return alloc(skip_proof_converter); } - unsigned get_max_var(const rule & r, ast_manager & m) { - var_counter ctr; - return ctr.get_max_var(r); - } void reverse_renaming(ast_manager & m, const expr_ref_vector & src, expr_ref_vector & tgt) { SASSERT(tgt.empty()); diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index 69be7e9ac..45d327d44 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -27,6 +27,7 @@ Revision History: #include"replace_proof_converter.h" #include"substitution.h" #include"fixedpoint_params.hpp" +#include"ast_counter.h" namespace datalog { @@ -411,80 +412,12 @@ namespace datalog { } - class counter { - protected: - typedef u_map map_impl; - map_impl m_data; - const bool m_stay_non_negative; + + class rule_counter : public var_counter { public: - typedef map_impl::iterator iterator; - - counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} - - iterator begin() const { return m_data.begin(); } - iterator end() const { return m_data.end(); } - - void update(unsigned el, int delta); - int & get(unsigned el); - /** - \brief Increase values of elements in \c els by \c delta. - - The function returns a reference to \c *this to allow for expressions like - counter().count(sz, arr).get_positive_count() - */ - counter & count(unsigned sz, const unsigned * els, int delta = 1); - counter & count(const unsigned_vector & els, int delta = 1) { - return count(els.size(), els.c_ptr(), delta); - } - - void collect_positive(idx_set & acc) const; - unsigned get_positive_count() const; - bool get_max_positive(unsigned & res) const; - unsigned get_max_positive() const; - /** - Since the default counter value of a counter is zero, the result is never negative. - */ - int get_max_counter_value() const; - }; - - class var_counter : public counter { - ptr_vector m_sorts; - expr_fast_mark1 m_visited; - ptr_vector m_todo; - unsigned_vector m_scopes; - unsigned get_max_var(bool & has_var); - - public: - var_counter(bool stay_non_negative = true) : counter(stay_non_negative) {} - void count_vars(ast_manager & m, const app * t, int coef = 1); - void count_vars(ast_manager & m, const rule * r, int coef = 1); - unsigned get_max_var(const rule& r); - unsigned get_max_var(expr* e); - unsigned get_next_var(expr* e); - }; - - class ast_counter { - typedef obj_map map_impl; - map_impl m_data; - bool m_stay_non_negative; - public: - typedef map_impl::iterator iterator; - - ast_counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} - - iterator begin() const { return m_data.begin(); } - iterator end() const { return m_data.end(); } - - int & get(ast * el) { - return m_data.insert_if_not_there2(el, 0)->get_data().m_value; - } - void update(ast * el, int delta){ - get(el)+=delta; - SASSERT(!m_stay_non_negative || get(el)>=0); - } - - void inc(ast * el) { update(el, 1); } - void dec(ast * el) { update(el, -1); } + rule_counter(bool stay_non_negative = true): var_counter(stay_non_negative) {} + void count_rule_vars(ast_manager & m, const rule * r, int coef = 1); + unsigned get_max_rule_var(const rule& r); }; void del_rule(horn_subsume_model_converter* mc, rule& r); @@ -497,11 +430,6 @@ namespace datalog { proof_converter* mk_skip_proof_converter(); - /** - Return maximal variable number, or zero is there isn't any - */ - // unsigned get_max_var(const rule & r, ast_manager & m); - void reverse_renaming(ast_manager & m, const expr_ref_vector & src, expr_ref_vector & tgt); /** diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 8bdff1800..d6718c33c 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -968,11 +968,11 @@ namespace pdr { unsigned deltas[2]; datalog::rule_ref rule(rm), r0(rm); model_node* n = m_root; - datalog::var_counter& vc = rm.get_var_counter(); + datalog::rule_counter& vc = rm.get_counter(); substitution subst(m); unifier unif(m); rule = n->get_rule(); - unsigned max_var = vc.get_max_var(*rule); + unsigned max_var = vc.get_max_rule_var(*rule); predicates.push_back(rule->get_head()); children.append(n); bool first = true; @@ -983,7 +983,7 @@ namespace pdr { children.pop_back(); n->mk_instantiate(r0, rule, binding); - max_var = std::max(max_var, vc.get_max_var(*rule)); + max_var = std::max(max_var, vc.get_max_rule_var(*rule)); subst.reset(); subst.reserve(2, max_var+1); deltas[0] = 0; diff --git a/src/muz_qe/pdr_quantifiers.cpp b/src/muz_qe/pdr_quantifiers.cpp index 5cc97893a..4a7b4b995 100644 --- a/src/muz_qe/pdr_quantifiers.cpp +++ b/src/muz_qe/pdr_quantifiers.cpp @@ -612,8 +612,8 @@ namespace pdr { datalog::rule_set::iterator it = m_rules.begin(), end = m_rules.end(); for (; it != end; ++it) { datalog::rule* r = *it; - datalog::var_counter vc(true); - unsigned max_var = vc.get_max_var(*r); + datalog::rule_counter vc(true); + unsigned max_var = vc.get_max_rule_var(*r); app_ref_vector body(m); for (unsigned i = 0; i < m_instantiations.size(); ++i) { if (r == m_instantiated_rules[i]) { diff --git a/src/muz_qe/tab_context.cpp b/src/muz_qe/tab_context.cpp index 72727bea8..681d3d4b2 100644 --- a/src/muz_qe/tab_context.cpp +++ b/src/muz_qe/tab_context.cpp @@ -317,7 +317,7 @@ namespace tb { for (unsigned i = utsz; i < tsz; ++i) { fmls.push_back(r->get_tail(i)); } - m_num_vars = 1 + r.get_manager().get_var_counter().get_max_var(*r); + m_num_vars = 1 + r.get_manager().get_counter().get_max_rule_var(*r); m_head = r->get_head(); m_predicates.reset(); for (unsigned i = 0; i < utsz; ++i) { diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index 25c41c2a2..0092cdd38 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -92,7 +92,34 @@ protected: ptr_vector fmls; g.get_formulas(fmls); fml = m.mk_and(fmls.size(), fmls.c_ptr()); + m_solver.push(); reduce(fml); + m_solver.pop(1); + SASSERT(m_solver.get_scope_level() == 0); + TRACE("ctx_solver_simplify_tactic", + for (unsigned i = 0; i < fmls.size(); ++i) { + tout << mk_pp(fmls[i], m) << "\n"; + } + tout << "=>\n"; + tout << mk_pp(fml, m) << "\n";); + DEBUG_CODE( + { + m_solver.push(); + expr_ref fml1(m); + fml1 = m.mk_and(fmls.size(), fmls.c_ptr()); + fml1 = m.mk_iff(fml, fml1); + fml1 = m.mk_not(fml1); + m_solver.assert_expr(fml1); + lbool is_sat = m_solver.check(); + TRACE("ctx_solver_simplify_tactic", tout << "is non-equivalence sat?: " << is_sat << "\n";); + if (is_sat != l_false) { + TRACE("ctx_solver_simplify_tactic", + tout << "result is not equivalent to input\n"; + tout << mk_pp(fml1, m) << "\n";); + UNREACHABLE(); + } + m_solver.pop(1); + }); g.reset(); g.assert_expr(fml, 0, 0); IF_VERBOSE(TACTIC_VERBOSITY_LVL, verbose_stream() << "(ctx-solver-simplify :num-steps " << m_num_steps << ")\n";); @@ -106,21 +133,22 @@ protected: svector is_checked; svector parent_ids, self_ids; expr_ref_vector fresh_vars(m), trail(m); - expr_ref res(m); + expr_ref res(m), tmp(m); obj_map > cache; unsigned id = 1; - expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); expr* n2, *fml; unsigned path_id = 0, self_pos = 0; app * a; unsigned sz; std::pair path_r; ptr_vector found; + expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + trail.push_back(n); fml = result.get(); - m_solver.assert_expr(m.mk_not(m.mk_iff(fml, n))); + tmp = m.mk_not(m.mk_iff(fml, n)); + m_solver.assert_expr(tmp); - trail.push_back(n); todo.push_back(fml); names.push_back(n); is_checked.push_back(false); @@ -144,6 +172,7 @@ protected: goto done; } if (m.is_bool(e) && !checked && simplify_bool(n, res)) { + TRACE("ctx_solver_simplify_tactic", tout << "simplified: " << mk_pp(e, m) << " |-> " << mk_pp(res, m) << "\n";); goto done; } if (!is_app(e)) { @@ -176,7 +205,7 @@ protected: found.push_back(arg); if (path_r.first == self_pos) { - TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << "\n";); + TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << " |-> " << mk_pp(path_r.second, m) << "\n";); args.push_back(path_r.second); } else { @@ -188,11 +217,11 @@ protected: } else if (!n2 && !found.contains(arg)) { n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + trail.push_back(n2); todo.push_back(arg); parent_ids.push_back(self_pos); self_ids.push_back(0); names.push_back(n2); - trail.push_back(n2); args.push_back(n2); is_checked.push_back(false); } @@ -205,7 +234,8 @@ protected: // child needs to be visited. if (n2) { m_solver.push(); - m_solver.assert_expr(m.mk_eq(res, n)); + tmp = m.mk_eq(res, n); + m_solver.assert_expr(tmp); continue; } @@ -229,7 +259,7 @@ protected: } bool simplify_bool(expr* n, expr_ref& res) { - + expr_ref tmp(m); m_solver.push(); m_solver.assert_expr(n); lbool is_sat = m_solver.check(); @@ -240,7 +270,8 @@ protected: } m_solver.push(); - m_solver.assert_expr(m.mk_not(n)); + tmp = m.mk_not(n); + m_solver.assert_expr(tmp); is_sat = m_solver.check(); m_solver.pop(1); if (is_sat == l_false) { @@ -254,7 +285,7 @@ protected: expr_ref local_simplify(app* a, expr* n, unsigned& id, unsigned index) { SASSERT(index < a->get_num_args()); SASSERT(m.is_bool(a->get_arg(index))); - expr_ref n2(m), result(m); + expr_ref n2(m), result(m), tmp(m); n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); ptr_buffer args; for (unsigned i = 0; i < a->get_num_args(); ++i) { @@ -267,7 +298,8 @@ protected: } m_mk_app(a->get_decl(), args.size(), args.c_ptr(), result); m_solver.push(); - m_solver.assert_expr(m.mk_eq(result, n)); + tmp = m.mk_eq(result, n); + m_solver.assert_expr(tmp); if (!simplify_bool(n2, result)) { result = a; } From 5455704af2a320d0abaff376f4970ed02ebf1f07 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Mar 2013 15:00:23 -0700 Subject: [PATCH 017/281] move quantifier hoist routines to quant_hoist Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/ast_counter.cpp | 165 ++++++++++++++++++ src/ast/rewriter/ast_counter.h | 107 ++++++++++++ .../rewriter}/expr_safe_replace.cpp | 0 .../rewriter}/expr_safe_replace.h | 0 src/ast/rewriter/quant_hoist.cpp | 64 +++++-- src/ast/rewriter/quant_hoist.h | 8 + src/muz_qe/dl_rule.cpp | 42 +---- src/muz_qe/dl_rule.h | 2 - 8 files changed, 335 insertions(+), 53 deletions(-) create mode 100644 src/ast/rewriter/ast_counter.cpp create mode 100644 src/ast/rewriter/ast_counter.h rename src/{muz_qe => ast/rewriter}/expr_safe_replace.cpp (100%) rename src/{muz_qe => ast/rewriter}/expr_safe_replace.h (100%) diff --git a/src/ast/rewriter/ast_counter.cpp b/src/ast/rewriter/ast_counter.cpp new file mode 100644 index 000000000..c542abb60 --- /dev/null +++ b/src/ast/rewriter/ast_counter.cpp @@ -0,0 +1,165 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + ast_counter.cpp + +Abstract: + + Routines for counting features of terms, such as free variables. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-18. + +Revision History: + +--*/ + +#include "ast_counter.h" +#include "var_subst.h" + +void counter::update(unsigned el, int delta) { + int & counter = get(el); + SASSERT(!m_stay_non_negative || counter>=0); + SASSERT(!m_stay_non_negative || static_cast(counter)>=-delta); + counter += delta; +} + +int & counter::get(unsigned el) { + return m_data.insert_if_not_there2(el, 0)->get_data().m_value; +} + +counter & counter::count(unsigned sz, const unsigned * els, int delta) { + for(unsigned i=0; im_value>0 ) { + cnt++; + } + } + return cnt; +} + +void counter::collect_positive(uint_set & acc) const { + iterator eit = begin(); + iterator eend = end(); + for(; eit!=eend; ++eit) { + if(eit->m_value>0) { acc.insert(eit->m_key); } + } +} + +bool counter::get_max_positive(unsigned & res) const { + bool found = false; + iterator eit = begin(); + iterator eend = end(); + for(; eit!=eend; ++eit) { + if( eit->m_value>0 && (!found || eit->m_key>res) ) { + found = true; + res = eit->m_key; + } + } + return found; +} + +unsigned counter::get_max_positive() const { + unsigned max_pos; + VERIFY(get_max_positive(max_pos)); + return max_pos; +} + +int counter::get_max_counter_value() const { + int res = 0; + iterator eit = begin(); + iterator eend = end(); + for (; eit!=eend; ++eit) { + if( eit->m_value>res ) { + res = eit->m_value; + } + } + return res; +} + +void var_counter::count_vars(ast_manager & m, const app * pred, int coef) { + unsigned n = pred->get_num_args(); + for (unsigned i = 0; i < n; i++) { + m_sorts.reset(); + ::get_free_vars(pred->get_arg(i), m_sorts); + for (unsigned j = 0; j < m_sorts.size(); ++j) { + if (m_sorts[j]) { + update(j, coef); + } + } + } +} + + +unsigned var_counter::get_max_var(bool& has_var) { + has_var = false; + unsigned max_var = 0; + while (!m_todo.empty()) { + expr* e = m_todo.back(); + unsigned scope = m_scopes.back(); + m_todo.pop_back(); + m_scopes.pop_back(); + if (m_visited.is_marked(e)) { + continue; + } + m_visited.mark(e, true); + switch(e->get_kind()) { + case AST_QUANTIFIER: { + quantifier* q = to_quantifier(e); + m_todo.push_back(q->get_expr()); + m_scopes.push_back(scope + q->get_num_decls()); + break; + } + case AST_VAR: { + if (to_var(e)->get_idx() >= scope + max_var) { + has_var = true; + max_var = to_var(e)->get_idx() - scope; + } + break; + } + case AST_APP: { + app* a = to_app(e); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + m_todo.push_back(a->get_arg(i)); + m_scopes.push_back(scope); + } + break; + } + default: + UNREACHABLE(); + break; + } + } + m_visited.reset(); + return max_var; +} + + +unsigned var_counter::get_max_var(expr* e) { + bool has_var = false; + m_todo.push_back(e); + m_scopes.push_back(0); + return get_max_var(has_var); +} + +unsigned var_counter::get_next_var(expr* e) { + bool has_var = false; + m_todo.push_back(e); + m_scopes.push_back(0); + unsigned mv = get_max_var(has_var); + if (has_var) mv++; + return mv; +} + diff --git a/src/ast/rewriter/ast_counter.h b/src/ast/rewriter/ast_counter.h new file mode 100644 index 000000000..2a581c302 --- /dev/null +++ b/src/ast/rewriter/ast_counter.h @@ -0,0 +1,107 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + ast_counter.h + +Abstract: + + Routines for counting features of terms, such as free variables. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-18. + Krystof Hoder (t-khoder) 2010-10-10. + +Revision History: + + Hoisted from dl_util.h 2013-03-18. + +--*/ + + +#ifndef _AST_COUNTER_H_ +#define _AST_COUNTER_H_ + +#include "ast.h" +#include "map.h" +#include "uint_set.h" + +class counter { +protected: + typedef u_map map_impl; + map_impl m_data; + const bool m_stay_non_negative; +public: + typedef map_impl::iterator iterator; + + counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} + + iterator begin() const { return m_data.begin(); } + iterator end() const { return m_data.end(); } + void update(unsigned el, int delta); + int & get(unsigned el); + + /** + \brief Increase values of elements in \c els by \c delta. + + The function returns a reference to \c *this to allow for expressions like + counter().count(sz, arr).get_positive_count() + */ + counter & count(unsigned sz, const unsigned * els, int delta = 1); + counter & count(const unsigned_vector & els, int delta = 1) { + return count(els.size(), els.c_ptr(), delta); + } + + void collect_positive(uint_set & acc) const; + unsigned get_positive_count() const; + + bool get_max_positive(unsigned & res) const; + unsigned get_max_positive() const; + + /** + Since the default counter value of a counter is zero, the result is never negative. + */ + int get_max_counter_value() const; +}; + +class var_counter : public counter { +protected: + ptr_vector m_sorts; + expr_fast_mark1 m_visited; + ptr_vector m_todo; + unsigned_vector m_scopes; + unsigned get_max_var(bool & has_var); +public: + var_counter(bool stay_non_negative = true): counter(stay_non_negative) {} + void count_vars(ast_manager & m, const app * t, int coef = 1); + unsigned get_max_var(expr* e); + unsigned get_next_var(expr* e); +}; + +class ast_counter { + typedef obj_map map_impl; + map_impl m_data; + bool m_stay_non_negative; + public: + typedef map_impl::iterator iterator; + + ast_counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} + + iterator begin() const { return m_data.begin(); } + iterator end() const { return m_data.end(); } + + int & get(ast * el) { + return m_data.insert_if_not_there2(el, 0)->get_data().m_value; + } + void update(ast * el, int delta){ + get(el) += delta; + SASSERT(!m_stay_non_negative || get(el) >= 0); + } + + void inc(ast * el) { update(el, 1); } + void dec(ast * el) { update(el, -1); } +}; + +#endif diff --git a/src/muz_qe/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp similarity index 100% rename from src/muz_qe/expr_safe_replace.cpp rename to src/ast/rewriter/expr_safe_replace.cpp diff --git a/src/muz_qe/expr_safe_replace.h b/src/ast/rewriter/expr_safe_replace.h similarity index 100% rename from src/muz_qe/expr_safe_replace.h rename to src/ast/rewriter/expr_safe_replace.h diff --git a/src/ast/rewriter/quant_hoist.cpp b/src/ast/rewriter/quant_hoist.cpp index b64e71866..9e8db0d11 100644 --- a/src/ast/rewriter/quant_hoist.cpp +++ b/src/ast/rewriter/quant_hoist.cpp @@ -25,7 +25,8 @@ Revision History: #include "bool_rewriter.h" #include "var_subst.h" #include "ast_pp.h" - +#include "ast_counter.h" +#include "expr_safe_replace.h" // // Bring quantifiers of common type into prenex form. @@ -42,7 +43,7 @@ public: void operator()(expr* fml, app_ref_vector& vars, bool& is_fa, expr_ref& result) { quantifier_type qt = Q_none_pos; - pull_quantifiers(fml, qt, vars, result); + pull_quantifier(fml, qt, vars, result); TRACE("qe_verbose", tout << mk_pp(fml, m) << "\n"; tout << mk_pp(result, m) << "\n";); @@ -52,7 +53,7 @@ public: void pull_exists(expr* fml, app_ref_vector& vars, expr_ref& result) { quantifier_type qt = Q_exists_pos; - pull_quantifiers(fml, qt, vars, result); + pull_quantifier(fml, qt, vars, result); TRACE("qe_verbose", tout << mk_pp(fml, m) << "\n"; tout << mk_pp(result, m) << "\n";); @@ -61,7 +62,7 @@ public: void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars) { quantifier_type qt = is_forall?Q_forall_pos:Q_exists_pos; expr_ref result(m); - pull_quantifiers(fml, qt, vars, result); + pull_quantifier(fml, qt, vars, result); TRACE("qe_verbose", tout << mk_pp(fml, m) << "\n"; tout << mk_pp(result, m) << "\n";); @@ -78,7 +79,37 @@ public: expr * const * exprs = (expr* const*) (vars.c_ptr() + vars.size()- nd); instantiate(m, q, exprs, result); } - + + unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { + unsigned index = var_counter().get_next_var(fml); + while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) { + quantifier* q = to_quantifier(fml); + index += q->get_num_decls(); + if (names) { + names->append(q->get_num_decls(), q->get_decl_names()); + } + fml = q->get_expr(); + } + if (!has_quantifiers(fml)) { + return index; + } + app_ref_vector vars(m); + pull_quantifier(is_forall, fml, vars); + if (vars.empty()) { + return index; + } + // replace vars by de-bruijn indices + expr_safe_replace rep(m); + for (unsigned i = 0; i < vars.size(); ++i) { + app* v = vars[i].get(); + if (names) { + names->push_back(v->get_decl()->get_name()); + } + rep.insert(v, m.mk_var(index++,m.get_sort(v))); + } + rep(fml); + return index; + } private: @@ -143,7 +174,7 @@ private: } - void pull_quantifiers(expr* fml, quantifier_type& qt, app_ref_vector& vars, expr_ref& result) { + void pull_quantifier(expr* fml, quantifier_type& qt, app_ref_vector& vars, expr_ref& result) { if (!has_quantifiers(fml)) { result = fml; @@ -159,7 +190,7 @@ private: if (m.is_and(fml)) { num_args = a->get_num_args(); for (unsigned i = 0; i < num_args; ++i) { - pull_quantifiers(a->get_arg(i), qt, vars, tmp); + pull_quantifier(a->get_arg(i), qt, vars, tmp); args.push_back(tmp); } m_rewriter.mk_and(args.size(), args.c_ptr(), result); @@ -167,25 +198,25 @@ private: else if (m.is_or(fml)) { num_args = to_app(fml)->get_num_args(); for (unsigned i = 0; i < num_args; ++i) { - pull_quantifiers(to_app(fml)->get_arg(i), qt, vars, tmp); + pull_quantifier(to_app(fml)->get_arg(i), qt, vars, tmp); args.push_back(tmp); } m_rewriter.mk_or(args.size(), args.c_ptr(), result); } else if (m.is_not(fml)) { - pull_quantifiers(to_app(fml)->get_arg(0), negate(qt), vars, tmp); + pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp); negate(qt); result = m.mk_not(tmp); } else if (m.is_implies(fml)) { - pull_quantifiers(to_app(fml)->get_arg(0), negate(qt), vars, tmp); + pull_quantifier(to_app(fml)->get_arg(0), negate(qt), vars, tmp); negate(qt); - pull_quantifiers(to_app(fml)->get_arg(1), qt, vars, result); + pull_quantifier(to_app(fml)->get_arg(1), qt, vars, result); result = m.mk_implies(tmp, result); } else if (m.is_ite(fml)) { - pull_quantifiers(to_app(fml)->get_arg(1), qt, vars, tmp); - pull_quantifiers(to_app(fml)->get_arg(2), qt, vars, result); + pull_quantifier(to_app(fml)->get_arg(1), qt, vars, tmp); + pull_quantifier(to_app(fml)->get_arg(2), qt, vars, result); result = m.mk_ite(to_app(fml)->get_arg(0), tmp, result); } else { @@ -203,7 +234,7 @@ private: } set_quantifier_type(qt, q->is_forall()); extract_quantifier(q, vars, tmp); - pull_quantifiers(tmp, qt, vars, result); + pull_quantifier(tmp, qt, vars, result); break; } case AST_VAR: @@ -215,6 +246,8 @@ private: break; } } + + }; quantifier_hoister::quantifier_hoister(ast_manager& m) { @@ -237,3 +270,6 @@ void quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, app_ref_ m_impl->pull_quantifier(is_forall, fml, vars); } +unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { + return m_impl->pull_quantifier(is_forall, fml, names); +} diff --git a/src/ast/rewriter/quant_hoist.h b/src/ast/rewriter/quant_hoist.h index 878f7840d..70a79a0e2 100644 --- a/src/ast/rewriter/quant_hoist.h +++ b/src/ast/rewriter/quant_hoist.h @@ -59,6 +59,14 @@ public: The list of variables is empty if there are no top-level universal/existential quantifier. */ void pull_quantifier(bool is_forall, expr_ref& fml, app_ref_vector& vars); + + /** + \brief Pull top-most universal (is_forall true) or existential (is_forall=false) quantifier up. + Return an expression with de-Bruijn indices and the list of names that were used. + Return index of maximal variable. + */ + + unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names); }; #endif diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index de41e4774..59a245cc4 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -107,41 +107,6 @@ namespace datalog { mk_rule_core(fml1, rules, name); } - // - // Hoist quantifier from rule (universal) or query (existential) - // - unsigned rule_manager::hoist_quantifier(bool is_forall, expr_ref& fml, svector* names) { - - unsigned index = var_counter().get_next_var(fml); - while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) { - quantifier* q = to_quantifier(fml); - index += q->get_num_decls(); - if (names) { - names->append(q->get_num_decls(), q->get_decl_names()); - } - fml = q->get_expr(); - } - if (!has_quantifiers(fml)) { - return index; - } - app_ref_vector vars(m); - quantifier_hoister qh(m); - qh.pull_quantifier(is_forall, fml, vars); - if (vars.empty()) { - return index; - } - // replace vars by de-bruijn indices - expr_safe_replace rep(m); - for (unsigned i = 0; i < vars.size(); ++i) { - app* v = vars[i].get(); - if (names) { - names->push_back(v->get_decl()->get_name()); - } - rep.insert(v, m.mk_var(index++,m.get_sort(v))); - } - rep(fml); - return index; - } void rule_manager::mk_rule_core(expr* _fml, rule_ref_vector& rules, symbol const& name) { app_ref_vector body(m); @@ -149,7 +114,8 @@ namespace datalog { expr_ref e(m), fml(_fml, m); svector is_negated; TRACE("dl_rule", tout << mk_pp(fml, m) << "\n";); - unsigned index = hoist_quantifier(true, fml, 0); + quantifier_hoister qh(m); + unsigned index = qh.pull_quantifier(true, fml, 0); check_app(fml); head = to_app(fml); @@ -225,7 +191,8 @@ namespace datalog { // Add implicit variables. // Remove existential prefix. bind_variables(query, false, q); - hoist_quantifier(false, q, &names); + quantifier_hoister qh(m); + qh.pull_quantifier(false, q, &names); // retrieve free variables. get_free_vars(q, vars); if (vars.contains(static_cast(0))) { @@ -1115,3 +1082,4 @@ namespace datalog { }; + diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index 4afc08edb..a8c6e0314 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -81,8 +81,6 @@ namespace datalog { void mk_rule_core(expr* fml, rule_ref_vector& rules, symbol const& name); - unsigned hoist_quantifier(bool is_forall, expr_ref& fml, svector* names); - /** \brief Perform cheap quantifier elimination to reduce the number of variables in the interpreted tail. */ From babfc701a60fc1cf5c1321b77c194a041490b251 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Mar 2013 10:36:36 -0700 Subject: [PATCH 018/281] make model and proof converters a reference Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_bmc_engine.cpp | 6 ++++-- src/muz_qe/dl_context.cpp | 12 ++++++------ src/muz_qe/dl_context.h | 11 ++++++++--- src/muz_qe/horn_tactic.cpp | 6 ++++-- src/muz_qe/pdr_dl_interface.cpp | 12 +++++++----- src/muz_qe/rel_context.cpp | 12 +++--------- src/shell/datalog_frontend.cpp | 4 +--- 7 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp index 80fcdea4a..200338b86 100644 --- a/src/muz_qe/dl_bmc_engine.cpp +++ b/src/muz_qe/dl_bmc_engine.cpp @@ -1420,13 +1420,15 @@ namespace datalog { model_converter_ref mc = datalog::mk_skip_model_converter(); m_pc = datalog::mk_skip_proof_converter(); m_ctx.set_output_predicate(m_query_pred); - m_ctx.apply_default_transformation(mc, m_pc); + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(m_pc); + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, m_pc); + m_ctx.transform_rules(transformer); m_query_pred = slice->get_predicate(m_query_pred.get()); m_ctx.set_output_predicate(m_query_pred); } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 53231e7b0..839aa93f9 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -826,7 +826,7 @@ namespace datalog { m_closed = false; } - void context::transform_rules(model_converter_ref& mc, proof_converter_ref& pc) { + void context::transform_rules() { m_transf.reset(); m_transf.register_plugin(alloc(mk_filter_rules,*this)); m_transf.register_plugin(alloc(mk_simple_joins,*this)); @@ -841,13 +841,13 @@ namespace datalog { } m_transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this)); - transform_rules(m_transf, mc, pc); + transform_rules(m_transf); } - void context::transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc) { + void context::transform_rules(rule_transformer& transf) { SASSERT(m_closed); //we must finish adding rules before we start transforming them TRACE("dl", display_rules(tout);); - if (transf(m_rule_set, mc, pc)) { + if (transf(m_rule_set, m_mc, m_pc)) { //we have already ensured the negation is stratified and transformations //should not break the stratification m_rule_set.ensure_closed(); @@ -862,7 +862,7 @@ namespace datalog { m_rule_set.add_rules(rs); } - void context::apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc) { + void context::apply_default_transformation() { ensure_closed(); m_transf.reset(); m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this)); @@ -890,7 +890,7 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); - transform_rules(m_transf, mc, pc); + transform_rules(m_transf); } void context::collect_params(param_descrs& p) { diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index b587daf7f..f9a1f1737 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -97,6 +97,8 @@ namespace datalog { expr_ref_vector m_rule_fmls; svector m_rule_names; expr_ref_vector m_background; + model_converter_ref m_mc; + proof_converter_ref m_pc; scoped_ptr m_pdr; scoped_ptr m_bmc; @@ -313,11 +315,14 @@ namespace datalog { void reopen(); void ensure_opened(); - void transform_rules(model_converter_ref& mc, proof_converter_ref& pc); - void transform_rules(rule_transformer& transf, model_converter_ref& mc, proof_converter_ref& pc); + void set_model_converter(model_converter_ref& mc) { m_mc = mc; } + void set_proof_converter(proof_converter_ref& pc) { m_pc = pc; } + + void transform_rules(); // model_converter_ref& mc, proof_converter_ref& pc); + void transform_rules(rule_transformer& transf); // , model_converter_ref& mc, proof_converter_ref& pc); void replace_rules(rule_set & rs); - void apply_default_transformation(model_converter_ref& mc, proof_converter_ref& pc); + void apply_default_transformation(); // model_converter_ref& mc, proof_converter_ref& pc); void collect_params(param_descrs& r); diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 633aeaa81..c87874b29 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -282,14 +282,16 @@ class horn_tactic : public tactic { func_decl* query_pred = to_app(q)->get_decl(); m_ctx.set_output_predicate(query_pred); + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(pc); m_ctx.get_rules(); // flush adding rules. - m_ctx.apply_default_transformation(mc, pc); + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, pc); + m_ctx.transform_rules(transformer); } expr_substitution sub(m); diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index 54a40f8b8..b55f302ed 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -111,13 +111,15 @@ lbool dl_interface::query(expr * query) { pc = datalog::mk_skip_proof_converter(); } m_ctx.set_output_predicate(query_pred); - m_ctx.apply_default_transformation(mc, pc); + m_ctx.set_model_converter(mc); + m_ctx.set_proof_converter(pc); + m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); - m_ctx.transform_rules(transformer, mc, pc); + m_ctx.transform_rules(transformer); query_pred = slice->get_predicate(query_pred.get()); m_ctx.set_output_predicate(query_pred); @@ -137,11 +139,11 @@ lbool dl_interface::query(expr * query) { datalog::rule_transformer transformer1(m_ctx), transformer2(m_ctx); if (m_ctx.get_params().coalesce_rules()) { transformer1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); - m_ctx.transform_rules(transformer1, mc, pc); + m_ctx.transform_rules(transformer1); } transformer2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); while (num_unfolds > 0) { - m_ctx.transform_rules(transformer2, mc, pc); + m_ctx.transform_rules(transformer2); --num_unfolds; } } @@ -149,7 +151,7 @@ lbool dl_interface::query(expr * query) { datalog::mk_extract_quantifiers* extract_quantifiers = alloc(datalog::mk_extract_quantifiers, m_ctx); datalog::rule_transformer extract_q_tr(m_ctx); extract_q_tr.register_plugin(extract_quantifiers); - m_ctx.transform_rules(extract_q_tr, mc, pc); + m_ctx.transform_rules(extract_q_tr); IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 00ac51e9f..8e22a704c 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -103,9 +103,7 @@ namespace datalog { TRACE("dl", m_context.display(tout);); while (true) { - model_converter_ref mc; // Ignored in Datalog mode - proof_converter_ref pc; // Ignored in Datalog mode - m_context.transform_rules(mc, pc); + m_context.transform_rules(); compiler::compile(m_context, m_context.get_rules(), rules_code, termination_code); TRACE("dl", rules_code.display(*this, tout); ); @@ -263,14 +261,12 @@ namespace datalog { reset_negated_tables(); if (m_context.generate_explanations()) { - model_converter_ref mc; // ignored in Datalog mode - proof_converter_ref pc; // ignored in Datalog mode rule_transformer transformer(m_context); //expl_plugin is deallocated when transformer goes out of scope mk_explanations * expl_plugin = alloc(mk_explanations, m_context, m_context.explanations_on_relation_level()); transformer.register_plugin(expl_plugin); - m_context.transform_rules(transformer, mc, pc); + m_context.transform_rules(transformer); //we will retrieve the predicate with explanations instead of the original query predicate query_pred = expl_plugin->get_e_decl(query_pred); @@ -280,11 +276,9 @@ namespace datalog { } if (m_context.magic_sets_for_queries()) { - model_converter_ref mc; // Ignored in Datalog mode - proof_converter_ref pc; // Ignored in Datalog mode rule_transformer transformer(m_context); transformer.register_plugin(alloc(mk_magic_sets, m_context, qrule.get())); - m_context.transform_rules(transformer, mc, pc); + m_context.transform_rules(transformer); } lbool res = saturate(); diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 44a9d9b66..07052609e 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -200,9 +200,7 @@ unsigned read_datalog(char const * file) { timeout = UINT_MAX; } do { - model_converter_ref mc; // ignored - proof_converter_ref pc; // ignored - ctx.transform_rules(mc, pc); + ctx.transform_rules(); datalog::compiler::compile(ctx, ctx.get_rules(), rules_code, termination_code); From ea2b17d83b9edd5363e298dd653b01f4343c218d Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 20 Mar 2013 10:40:52 -0700 Subject: [PATCH 019/281] remove debug code Signed-off-by: Nuno Lopes --- src/muz_qe/dl_check_table.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/muz_qe/dl_check_table.cpp b/src/muz_qe/dl_check_table.cpp index d7dfbe1ae..18d5feb39 100644 --- a/src/muz_qe/dl_check_table.cpp +++ b/src/muz_qe/dl_check_table.cpp @@ -287,9 +287,6 @@ namespace datalog { bool check_table::well_formed() const { get_plugin().m_count++; - if (get_plugin().m_count == 497) { - std::cout << "here\n"; - } iterator it = m_tocheck->begin(), end = m_tocheck->end(); for (; it != end; ++it) { table_fact fact; From 39d72462516084a9c0fa1d33ec43b5e43a5d263c Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 20 Mar 2013 15:47:56 -0700 Subject: [PATCH 020/281] fix overloading of complement from base_table Signed-off-by: Nuno Lopes --- src/muz_qe/dl_check_table.cpp | 4 ++-- src/muz_qe/dl_check_table.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/muz_qe/dl_check_table.cpp b/src/muz_qe/dl_check_table.cpp index 18d5feb39..5081654b5 100644 --- a/src/muz_qe/dl_check_table.cpp +++ b/src/muz_qe/dl_check_table.cpp @@ -351,8 +351,8 @@ namespace datalog { return result; } - table_base * check_table::complement(func_decl* p) const { - check_table* result = alloc(check_table, get_plugin(), get_signature(), m_tocheck->complement(p), m_checker->complement(p)); + table_base * check_table::complement(func_decl* p, const table_element * func_columns) const { + check_table* result = alloc(check_table, get_plugin(), get_signature(), m_tocheck->complement(p, func_columns), m_checker->complement(p, func_columns)); return result; } diff --git a/src/muz_qe/dl_check_table.h b/src/muz_qe/dl_check_table.h index 6f098f8bc..7126bde66 100644 --- a/src/muz_qe/dl_check_table.h +++ b/src/muz_qe/dl_check_table.h @@ -119,7 +119,7 @@ namespace datalog { virtual void add_fact(const table_fact & f); virtual void remove_fact(const table_element* fact); virtual bool contains_fact(const table_fact & f) const; - virtual table_base * complement(func_decl* p) const; + virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const; virtual table_base * clone() const; virtual iterator begin() const { SASSERT(well_formed()); return m_tocheck->begin(); } From b2d4aa085973aee81bfa8e0edccd25066d755ce2 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Mar 2013 01:14:08 +0100 Subject: [PATCH 021/281] fix crash in qe_lite::is_var_eq Signed-off-by: unknown --- src/muz_qe/qe_lite.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp index 5f018895c..435768c08 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/muz_qe/qe_lite.cpp @@ -201,9 +201,15 @@ namespace eq { return (*m_is_variable)(e); } - bool is_neg_var(ast_manager & m, expr * e) { + bool is_neg_var(ast_manager & m, expr * e, var*& v) { expr* e1; - return m.is_not(e, e1) && is_variable(e1); + if (m.is_not(e, e1) && is_variable(e1)) { + v = to_var(e1); + return true; + } + else { + return false; + } } @@ -328,18 +334,19 @@ namespace eq { bool is_var_eq(expr * e, ptr_vector& vs, expr_ref_vector & ts) { expr* lhs, *rhs; + var* v; // (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases if (m.is_eq(e, lhs, rhs) || m.is_iff(e, lhs, rhs)) { // (iff (not VAR) t) (iff t (not VAR)) cases if (!is_variable(lhs) && !is_variable(rhs) && m.is_bool(lhs)) { - if (!is_neg_var(m, lhs)) { + if (!is_neg_var(m, lhs, v)) { std::swap(lhs, rhs); } - if (!is_neg_var(m, lhs)) { + if (!is_neg_var(m, lhs, v)) { return false; } - vs.push_back(to_var(lhs)); + vs.push_back(v); ts.push_back(m.mk_not(rhs)); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; @@ -378,9 +385,9 @@ namespace eq { } // VAR = false case - if (is_neg_var(m, e)) { + if (is_neg_var(m, e, v)) { ts.push_back(m.mk_false()); - vs.push_back(to_var(to_app(e)->get_arg(0))); + vs.push_back(v); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; } From 54d9fb5c4b20844bb4540284abea459a0efa6dfb Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Mar 2013 01:25:22 +0100 Subject: [PATCH 022/281] Revert "fix crash in qe_lite::is_var_eq" This reverts commit b2d4aa085973aee81bfa8e0edccd25066d755ce2. --- src/muz_qe/qe_lite.cpp | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp index 435768c08..5f018895c 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/muz_qe/qe_lite.cpp @@ -201,15 +201,9 @@ namespace eq { return (*m_is_variable)(e); } - bool is_neg_var(ast_manager & m, expr * e, var*& v) { + bool is_neg_var(ast_manager & m, expr * e) { expr* e1; - if (m.is_not(e, e1) && is_variable(e1)) { - v = to_var(e1); - return true; - } - else { - return false; - } + return m.is_not(e, e1) && is_variable(e1); } @@ -334,19 +328,18 @@ namespace eq { bool is_var_eq(expr * e, ptr_vector& vs, expr_ref_vector & ts) { expr* lhs, *rhs; - var* v; // (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases if (m.is_eq(e, lhs, rhs) || m.is_iff(e, lhs, rhs)) { // (iff (not VAR) t) (iff t (not VAR)) cases if (!is_variable(lhs) && !is_variable(rhs) && m.is_bool(lhs)) { - if (!is_neg_var(m, lhs, v)) { + if (!is_neg_var(m, lhs)) { std::swap(lhs, rhs); } - if (!is_neg_var(m, lhs, v)) { + if (!is_neg_var(m, lhs)) { return false; } - vs.push_back(v); + vs.push_back(to_var(lhs)); ts.push_back(m.mk_not(rhs)); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; @@ -385,9 +378,9 @@ namespace eq { } // VAR = false case - if (is_neg_var(m, e, v)) { + if (is_neg_var(m, e)) { ts.push_back(m.mk_false()); - vs.push_back(v); + vs.push_back(to_var(to_app(e)->get_arg(0))); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; } From c824178e7e83cdc05336ccf721f88b04772f9d4f Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 22 Mar 2013 11:50:41 -0700 Subject: [PATCH 023/281] bit_vector: fix operator==() for the case that num_bits is a multiple of 32 Signed-off-by: Nuno Lopes --- src/util/bit_vector.cpp | 3 ++- src/util/bit_vector.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index 210d230bc..2328a5849 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -116,7 +116,7 @@ void bit_vector::shift_right(unsigned k) { } } -bool bit_vector::operator==(bit_vector const & source) { +bool bit_vector::operator==(bit_vector const & source) const { if (m_num_bits != source.m_num_bits) return false; unsigned n = num_words(); @@ -129,6 +129,7 @@ bool bit_vector::operator==(bit_vector const & source) { } unsigned bit_rest = source.m_num_bits % 32; unsigned mask = (1 << bit_rest) - 1; + if (mask == 0) mask = UINT_MAX; return (m_data[i] & mask) == (source.m_data[i] & mask); } diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 9560af7e2..2e7becee7 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -171,9 +171,9 @@ public: resize(sz, val); } - bool operator==(bit_vector const & other); + bool operator==(bit_vector const & other) const; - bool operator!=(bit_vector const & other) { return !operator==(other); } + bool operator!=(bit_vector const & other) const { return !operator==(other); } bit_vector & operator=(bit_vector const & source) { m_num_bits = source.m_num_bits; From 7e0723e42bc9aac806f6b354319a388dc49f7f66 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 22 Mar 2013 11:51:28 -0700 Subject: [PATCH 024/281] add unit test for previous commit Signed-off-by: Nuno Lopes --- src/test/bit_vector.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/test/bit_vector.cpp b/src/test/bit_vector.cpp index 2b67c3a71..7d3f96ae4 100644 --- a/src/test/bit_vector.cpp +++ b/src/test/bit_vector.cpp @@ -276,12 +276,35 @@ static void tst_bv_reset() { } } +static void tst_eq() { + bit_vector b1, b2, b3; + b1.resize(32); + b2.resize(32); + b3.resize(32); + + b1.set(3, true); + SASSERT(b1 != b2); + SASSERT(!(b1 == b2)); + SASSERT(b2 == b3); + + b3.set(3, true); + SASSERT(b1 == b3); + SASSERT(!(b1 != b3)); + + b2.set(31, true); + b3.set(31); + b3.unset(3); + SASSERT(b2 == b3); + SASSERT(!(b2 != b3)); +} + void tst_bit_vector() { tst_crash(); tst_shift(); tst_or(); tst_and(); tst_bv_reset(); + tst_eq(); return; tst2(); for (unsigned i = 0; i < 20; i++) { From 26f4d3be202606ff0189aefc103de187caf06d5d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Mar 2013 14:11:54 -0700 Subject: [PATCH 025/281] significant update to Horn routines: add module hnf to extract Horn normal form (removed from rule_manager). Associate proof objects with rules to track (all) rewrites, so that proof traces can be tracked back to original rules after transformations Signed-off-by: Nikolaj Bjorner --- src/api/z3_api.h | 2 +- src/ast/rewriter/quant_hoist.cpp | 30 +- src/ast/rewriter/quant_hoist.h | 2 +- src/muz_qe/dl_base.cpp | 2 +- src/muz_qe/dl_bmc_engine.cpp | 40 ++- src/muz_qe/dl_bmc_engine.h | 1 - src/muz_qe/dl_cmds.cpp | 4 +- src/muz_qe/dl_context.cpp | 32 +- src/muz_qe/dl_context.h | 13 +- src/muz_qe/dl_mk_array_blast.cpp | 18 +- src/muz_qe/dl_mk_array_blast.h | 3 +- src/muz_qe/dl_mk_bit_blast.cpp | 119 ++++++- src/muz_qe/dl_mk_bit_blast.h | 2 +- src/muz_qe/dl_mk_coalesce.cpp | 20 +- src/muz_qe/dl_mk_coalesce.h | 3 +- src/muz_qe/dl_mk_coi_filter.cpp | 3 +- src/muz_qe/dl_mk_coi_filter.h | 3 +- src/muz_qe/dl_mk_explanations.cpp | 4 +- src/muz_qe/dl_mk_explanations.h | 2 +- src/muz_qe/dl_mk_extract_quantifiers.cpp | 12 +- src/muz_qe/dl_mk_extract_quantifiers.h | 2 +- src/muz_qe/dl_mk_filter_rules.cpp | 6 +- src/muz_qe/dl_mk_filter_rules.h | 2 +- src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 7 +- src/muz_qe/dl_mk_interp_tail_simplifier.h | 2 +- src/muz_qe/dl_mk_karr_invariants.cpp | 5 +- src/muz_qe/dl_mk_karr_invariants.h | 2 +- src/muz_qe/dl_mk_magic_sets.cpp | 4 +- src/muz_qe/dl_mk_magic_sets.h | 2 +- src/muz_qe/dl_mk_partial_equiv.cpp | 4 +- src/muz_qe/dl_mk_partial_equiv.h | 2 +- src/muz_qe/dl_mk_rule_inliner.cpp | 14 +- src/muz_qe/dl_mk_rule_inliner.h | 4 +- src/muz_qe/dl_mk_similarity_compressor.cpp | 4 +- src/muz_qe/dl_mk_similarity_compressor.h | 2 +- src/muz_qe/dl_mk_simple_joins.cpp | 9 +- src/muz_qe/dl_mk_simple_joins.h | 2 +- src/muz_qe/dl_mk_slice.cpp | 15 +- src/muz_qe/dl_mk_slice.h | 2 +- src/muz_qe/dl_mk_subsumption_checker.cpp | 13 +- src/muz_qe/dl_mk_subsumption_checker.h | 2 +- src/muz_qe/dl_mk_unbound_compressor.cpp | 5 +- src/muz_qe/dl_mk_unbound_compressor.h | 2 +- src/muz_qe/dl_mk_unfold.cpp | 15 +- src/muz_qe/dl_mk_unfold.h | 3 +- src/muz_qe/dl_rule.cpp | 333 ++++++++++---------- src/muz_qe/dl_rule.h | 45 ++- src/muz_qe/dl_rule_transformer.cpp | 4 +- src/muz_qe/dl_rule_transformer.h | 6 +- src/muz_qe/dl_util.cpp | 38 +++ src/muz_qe/dl_util.h | 3 + src/muz_qe/equiv_proof_converter.cpp | 18 +- src/muz_qe/horn_tactic.cpp | 14 +- src/muz_qe/pdr_context.cpp | 49 ++- src/muz_qe/pdr_context.h | 7 +- src/muz_qe/pdr_dl_interface.cpp | 13 +- src/muz_qe/pdr_generalizers.cpp | 6 +- src/muz_qe/qe_lite.cpp | 8 +- src/muz_qe/tab_context.cpp | 13 +- src/util/vector.h | 17 - 60 files changed, 591 insertions(+), 428 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index ea3b05e40..6d59cf650 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -701,7 +701,7 @@ typedef enum over Boolean connectives 'and' and 'or'. - - Z3_OP_PR_NFF_NEG: Proof for a (negative) NNF step. Examples: + - Z3_OP_PR_NNF_NEG: Proof for a (negative) NNF step. Examples: \nicebox{ T1: (not s_1) ~ r_1 ... diff --git a/src/ast/rewriter/quant_hoist.cpp b/src/ast/rewriter/quant_hoist.cpp index 9e8db0d11..57b693aca 100644 --- a/src/ast/rewriter/quant_hoist.cpp +++ b/src/ast/rewriter/quant_hoist.cpp @@ -80,7 +80,7 @@ public: instantiate(m, q, exprs, result); } - unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { + unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names) { unsigned index = var_counter().get_next_var(fml); while (is_quantifier(fml) && (is_forall == to_quantifier(fml)->is_forall())) { quantifier* q = to_quantifier(fml); @@ -88,6 +88,9 @@ public: if (names) { names->append(q->get_num_decls(), q->get_decl_names()); } + if (sorts) { + sorts->append(q->get_num_decls(), q->get_decl_sorts()); + } fml = q->get_expr(); } if (!has_quantifiers(fml)) { @@ -100,12 +103,29 @@ public: } // replace vars by de-bruijn indices expr_safe_replace rep(m); + svector bound_names; + ptr_vector bound_sorts; for (unsigned i = 0; i < vars.size(); ++i) { app* v = vars[i].get(); if (names) { - names->push_back(v->get_decl()->get_name()); + bound_names.push_back(v->get_decl()->get_name()); } - rep.insert(v, m.mk_var(index++,m.get_sort(v))); + if (sorts) { + bound_sorts.push_back(m.get_sort(v)); + } + rep.insert(v, m.mk_var(index++, m.get_sort(v))); + } + if (names && !bound_names.empty()) { + bound_names.reverse(); + bound_names.append(*names); + names->reset(); + names->append(bound_names); + } + if (sorts && !bound_sorts.empty()) { + bound_sorts.reverse(); + bound_sorts.append(*sorts); + sorts->reset(); + sorts->append(bound_sorts); } rep(fml); return index; @@ -270,6 +290,6 @@ void quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, app_ref_ m_impl->pull_quantifier(is_forall, fml, vars); } -unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, svector* names) { - return m_impl->pull_quantifier(is_forall, fml, names); +unsigned quantifier_hoister::pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names) { + return m_impl->pull_quantifier(is_forall, fml, sorts, names); } diff --git a/src/ast/rewriter/quant_hoist.h b/src/ast/rewriter/quant_hoist.h index 70a79a0e2..dc586d437 100644 --- a/src/ast/rewriter/quant_hoist.h +++ b/src/ast/rewriter/quant_hoist.h @@ -66,7 +66,7 @@ public: Return index of maximal variable. */ - unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names); + unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names); }; #endif diff --git a/src/muz_qe/dl_base.cpp b/src/muz_qe/dl_base.cpp index dd817754f..0f250d76c 100644 --- a/src/muz_qe/dl_base.cpp +++ b/src/muz_qe/dl_base.cpp @@ -233,7 +233,7 @@ namespace datalog { table_fact row; for(; it!=iend; ++it) { it->get_fact(row); - to_remove.append(row); + to_remove.push_back(row); } remove_facts(to_remove.size(), to_remove.c_ptr()); } diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp index 200338b86..2961b3f54 100644 --- a/src/muz_qe/dl_bmc_engine.cpp +++ b/src/muz_qe/dl_bmc_engine.cpp @@ -307,7 +307,7 @@ namespace datalog { r1->to_formula(concl); scoped_proof _sp(m); - proof* p = m.mk_asserted(fml); + proof* p = r->get_proof(); proof* premises[2] = { pr, p }; positions.push_back(std::make_pair(0, 1)); @@ -320,7 +320,7 @@ namespace datalog { else { r2->to_formula(concl); scoped_proof _sp(m); - proof* p = m.mk_asserted(fml); + proof* p = r->get_proof(); if (sub.empty()) { pr = p; } @@ -340,7 +340,7 @@ namespace datalog { pred = r->get_decl(0); } scoped_proof _sp(m); - apply(m, b.m_pc.get(), pr); + apply(m, b.m_ctx.get_proof_converter().get(), pr); b.m_answer = pr; return l_true; } @@ -474,6 +474,9 @@ namespace datalog { } proof_ref get_proof(model_ref& md, func_decl* pred, app* prop, unsigned level) { + if (b.m_cancel) { + return proof_ref(0, m); + } TRACE("bmc", tout << "Predicate: " << pred->get_name() << "\n";); expr_ref prop_r(m), prop_v(m), fml(m), prop_body(m), tmp(m), body(m); @@ -497,7 +500,7 @@ namespace datalog { SASSERT(r); r->to_formula(fml); IF_VERBOSE(1, verbose_stream() << mk_pp(fml, m) << "\n";); - prs.push_back(m.mk_asserted(fml)); + prs.push_back(r->get_proof()); unsigned sz = r->get_uninterpreted_tail_size(); ptr_vector rule_vars; @@ -536,8 +539,9 @@ namespace datalog { model_ref md; b.m_solver.get_model(md); IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0);); - proof_ref pr = get_proof(md, b.m_query_pred, to_app(level_query), level); - apply(m, b.m_pc.get(), pr); + proof_ref pr(m); + pr = get_proof(md, b.m_query_pred, to_app(level_query), level); + apply(m, b.m_ctx.get_proof_converter().get(), pr); b.m_answer = pr; } @@ -1034,7 +1038,7 @@ namespace datalog { var_subst vs(m, false); mk_subst(*rules[i], path, trace, sub); rules[i]->to_formula(fml); - prs.push_back(m.mk_asserted(fml)); + prs.push_back(rules[i]->get_proof()); unsigned sz = trace->get_num_args(); if (sub.empty() && sz == 0) { pr = prs[0].get(); @@ -1112,7 +1116,6 @@ namespace datalog { } void mk_answer(model_ref& md, expr_ref& trace, expr_ref& path) { - proof_ref pr(m); IF_VERBOSE(2, model_smt2_pp(verbose_stream(), m, *md, 0);); md->eval(trace, trace); md->eval(path, path); @@ -1120,7 +1123,11 @@ namespace datalog { for (unsigned i = 0; i < b.m_solver.size(); ++i) { verbose_stream() << mk_pp(b.m_solver.get_formulas()[i], m) << "\n"; }); - b.m_answer = get_proof(md, to_app(trace), to_app(path)); + scoped_proof _sp(m); + proof_ref pr(m); + pr = get_proof(md, to_app(trace), to_app(path)); + apply(m, b.m_ctx.get_proof_converter().get(), pr); + b.m_answer = pr; } }; @@ -1155,6 +1162,9 @@ namespace datalog { private: void get_model(unsigned level) { + if (b.m_cancel) { + return; + } rule_manager& rm = b.m_ctx.get_rule_manager(); expr_ref level_query = mk_level_predicate(b.m_query_pred, level); model_ref md; @@ -1212,7 +1222,7 @@ namespace datalog { r1->to_formula(concl); scoped_proof _sp(m); - proof* p = m.mk_asserted(fml); + proof* p = r->get_proof(); proof* premises[2] = { pr, p }; positions.push_back(std::make_pair(0, 1)); @@ -1225,7 +1235,7 @@ namespace datalog { else { r2->to_formula(concl); scoped_proof _sp(m); - proof* p = m.mk_asserted(fml); + proof* p = r->get_proof(); if (sub.empty()) { pr = p; } @@ -1245,7 +1255,7 @@ namespace datalog { pred = r->get_decl(0); } scoped_proof _sp(m); - apply(m, b.m_pc.get(), pr); + apply(m, b.m_ctx.get_proof_converter().get(), pr); b.m_answer = pr; } @@ -1409,6 +1419,7 @@ namespace datalog { m_ctx.ensure_opened(); m_rules.reset(); + datalog::rule_manager& rule_manager = m_ctx.get_rule_manager(); datalog::rule_set old_rules(m_ctx.get_rules()); datalog::rule_ref_vector query_rules(rule_manager); @@ -1417,11 +1428,8 @@ namespace datalog { m_ctx.add_rules(query_rules); expr_ref bg_assertion = m_ctx.get_background_assertion(); - model_converter_ref mc = datalog::mk_skip_model_converter(); - m_pc = datalog::mk_skip_proof_converter(); + m_ctx.set_output_predicate(m_query_pred); - m_ctx.set_model_converter(mc); - m_ctx.set_proof_converter(m_pc); m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { diff --git a/src/muz_qe/dl_bmc_engine.h b/src/muz_qe/dl_bmc_engine.h index 06901a160..5911f5f72 100644 --- a/src/muz_qe/dl_bmc_engine.h +++ b/src/muz_qe/dl_bmc_engine.h @@ -39,7 +39,6 @@ namespace datalog { func_decl_ref m_query_pred; expr_ref m_answer; volatile bool m_cancel; - proof_converter_ref m_pc; void checkpoint(); diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp index c88e7346e..d49a8a671 100644 --- a/src/muz_qe/dl_cmds.cpp +++ b/src/muz_qe/dl_cmds.cpp @@ -262,8 +262,10 @@ public: case datalog::OK: break; + default: - UNREACHABLE(); + // exception was raised. + break; } break; } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 839aa93f9..7d9fe8d7e 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -231,6 +231,7 @@ namespace datalog { m_rule_set(*this), m_rule_fmls(m), m_background(m), + m_mc(0), m_closed(false), m_saturation_was_run(false), m_last_answer(m), @@ -474,8 +475,11 @@ namespace datalog { void context::flush_add_rules() { datalog::rule_manager& rm = get_rule_manager(); datalog::rule_ref_vector rules(rm); + scoped_proof_mode _scp(m, generate_proof_trace()?PGM_FINE:PGM_DISABLED); for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { - rm.mk_rule(m_rule_fmls[i].get(), rules, m_rule_names[i]); + expr* fml = m_rule_fmls[i].get(); + proof* p = generate_proof_trace()?m.mk_asserted(fml):0; + rm.mk_rule(fml, p, rules, m_rule_names[i]); } add_rules(rules); m_rule_fmls.reset(); @@ -489,7 +493,11 @@ namespace datalog { void context::update_rule(expr* rl, symbol const& name) { datalog::rule_manager& rm = get_rule_manager(); datalog::rule_ref_vector rules(rm); - rm.mk_rule(rl, rules, name); + proof* p = 0; + if (generate_proof_trace()) { + p = m.mk_asserted(rl); + } + rm.mk_rule(rl, p, rules, name); if (rules.size() != 1) { std::stringstream strm; strm << "Rule " << name << " has a non-trivial body. It cannot be modified"; @@ -683,7 +691,7 @@ namespace datalog { todo.push_back(e2); } else if (is_quantifier(e)) { - todo.append(to_quantifier(e)->get_expr()); + todo.push_back(to_quantifier(e)->get_expr()); } else if ((m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) && m.is_true(e1)) { @@ -737,6 +745,9 @@ namespace datalog { UNREACHABLE(); break; } + if (generate_proof_trace() && !r->get_proof()) { + m_rule_manager.mk_rule_asserted_proof(*r.get()); + } } void context::add_rule(rule_ref& r) { @@ -847,7 +858,7 @@ namespace datalog { void context::transform_rules(rule_transformer& transf) { SASSERT(m_closed); //we must finish adding rules before we start transforming them TRACE("dl", display_rules(tout);); - if (transf(m_rule_set, m_mc, m_pc)) { + if (transf(m_rule_set, m_mc)) { //we have already ensured the negation is stratified and transformations //should not break the stratification m_rule_set.ensure_closed(); @@ -887,9 +898,9 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890)); m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); - m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); - m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); - m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); + m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 34870)); + m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 34860)); + m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 34850)); transform_rules(m_transf); } @@ -1035,6 +1046,8 @@ namespace datalog { } void context::new_query() { + m_mc = mk_skip_model_converter(); + flush_add_rules(); m_last_status = OK; m_last_answer = 0; @@ -1146,6 +1159,7 @@ namespace datalog { switch(get_engine()) { case DATALOG_ENGINE: return false; + case PDR_ENGINE: case QPDR_ENGINE: ensure_pdr(); m_pdr->display_certificate(out); @@ -1239,7 +1253,7 @@ namespace datalog { ptr_vector sorts; get_free_vars(m_rule_fmls[i].get(), sorts); if (!sorts.empty()) { - rm.mk_rule(m_rule_fmls[i].get(), rule_refs, m_rule_names[i]); + rm.mk_rule(m_rule_fmls[i].get(), 0, rule_refs, m_rule_names[i]); m_rule_fmls[i] = m_rule_fmls.back(); m_rule_names[i] = m_rule_names.back(); m_rule_fmls.pop_back(); @@ -1256,7 +1270,7 @@ namespace datalog { } for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { rules.push_back(m_rule_fmls[i].get()); - names.push_back(m_rule_names[i]); + names.push_back(m_rule_names[i]); } } diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index f9a1f1737..778cccc0c 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -42,7 +42,6 @@ Revision History: #include"params.h" #include"trail.h" #include"model_converter.h" -#include"proof_converter.h" #include"model2expr.h" #include"smt_params.h" #include"dl_rule_transformer.h" @@ -142,6 +141,7 @@ namespace datalog { var_subst & get_var_subst() { return m_var_subst; } dl_decl_util & get_decl_util() { return m_decl_util; } + bool generate_proof_trace() const { return m_params.generate_proof_trace(); } bool output_profile() const { return m_params.output_profile(); } bool fix_unbound_vars() const { return m_params.fix_unbound_vars(); } symbol default_table() const { return m_params.default_table(); } @@ -315,14 +315,15 @@ namespace datalog { void reopen(); void ensure_opened(); - void set_model_converter(model_converter_ref& mc) { m_mc = mc; } - void set_proof_converter(proof_converter_ref& pc) { m_pc = pc; } + model_converter_ref& get_model_converter() { return m_mc; } + proof_converter_ref& get_proof_converter() { return m_pc; } + void add_proof_converter(proof_converter* pc) { m_pc = concat(m_pc.get(), pc); } - void transform_rules(); // model_converter_ref& mc, proof_converter_ref& pc); - void transform_rules(rule_transformer& transf); // , model_converter_ref& mc, proof_converter_ref& pc); + void transform_rules(); + void transform_rules(rule_transformer& transf); void replace_rules(rule_set & rs); - void apply_default_transformation(); // model_converter_ref& mc, proof_converter_ref& pc); + void apply_default_transformation(); void collect_params(param_descrs& r); diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp index b22fdf7ef..537b0b5ac 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz_qe/dl_mk_array_blast.cpp @@ -197,25 +197,18 @@ namespace datalog { } fml2 = m.mk_implies(body, head); - rm.mk_rule(fml2, new_rules, r.name()); + proof_ref p(m); + rm.mk_rule(fml2, p, new_rules, r.name()); SASSERT(new_rules.size() == 1); TRACE("dl", new_rules[0]->display(m_ctx, tout << "new rule\n");); rules.add_rule(new_rules[0].get()); - if (m_pc) { - new_rules[0]->to_formula(fml2); - m_pc->insert(fml1, fml2); - } + rm.mk_rule_rewrite_proof(r, *new_rules[0].get()); return true; } - rule_set * mk_array_blast::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - ref epc; - if (pc) { - epc = alloc(equiv_proof_converter, m); - } - m_pc = epc.get(); + rule_set * mk_array_blast::operator()(rule_set const & source, model_converter_ref& mc) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::iterator it = source.begin(), end = source.end(); @@ -227,9 +220,6 @@ namespace datalog { dealloc(rules); rules = 0; } - if (pc) { - pc = concat(pc.get(), epc.get()); - } return rules; } diff --git a/src/muz_qe/dl_mk_array_blast.h b/src/muz_qe/dl_mk_array_blast.h index c0bb39da0..94eb64601 100644 --- a/src/muz_qe/dl_mk_array_blast.h +++ b/src/muz_qe/dl_mk_array_blast.h @@ -37,7 +37,6 @@ namespace datalog { rule_manager& rm; params_ref m_params; th_rewriter m_rewriter; - equiv_proof_converter* m_pc; typedef obj_map defs_t; @@ -55,7 +54,7 @@ namespace datalog { virtual ~mk_array_blast(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 1fa93a0ca..1e984f254 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -21,7 +21,8 @@ Revision History: #include "bit_blaster_rewriter.h" #include "rewriter_def.h" #include "ast_pp.h" - +#include "expr_safe_replace.h" +#include "filter_model_converter.h" namespace datalog { @@ -35,6 +36,73 @@ namespace datalog { // P(bv(x,y)) :- P_bv(x,y) // Query + // this model converter should be composed with a filter converter + // that gets rid of the new functions. + class bit_blast_model_converter : public model_converter { + ast_manager& m; + bv_util m_bv; + func_decl_ref_vector m_old_funcs; + func_decl_ref_vector m_new_funcs; + public: + bit_blast_model_converter(ast_manager& m): + m(m), + m_bv(m), + m_old_funcs(m), + m_new_funcs(m) {} + + void insert(func_decl* old_f, func_decl* new_f) { + m_old_funcs.push_back(old_f); + m_new_funcs.push_back(new_f); + } + + virtual model_converter * translate(ast_translation & translator) { + return alloc(bit_blast_model_converter, m); + } + + virtual void operator()(model_ref & model) { + for (unsigned i = 0; i < m_new_funcs.size(); ++i) { + func_decl* p = m_new_funcs[i].get(); + func_decl* q = m_old_funcs[i].get(); + func_interp* f = 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); + model->register_decl(p, f); + func_interp* g = alloc(func_interp, m, arity_q); + + if (f) { + body = f->get_interp(); + SASSERT(!f->is_partial()); + SASSERT(body); + } + else { + body = m.mk_false(); + } + unsigned idx = 0; + expr_ref arg(m), proj(m); + expr_safe_replace sub(m); + for (unsigned j = 0; j < arity_q; ++j) { + sort* s = q->get_domain(j); + arg = m.mk_var(j, s); + if (m_bv.is_bv_sort(s)) { + expr* args[1] = { arg }; + unsigned sz = m_bv.get_bv_size(s); + for (unsigned k = 0; k < sz; ++k) { + proj = m.mk_app(m_bv.get_family_id(), OP_BIT2BOOL, 1, args); + sub.insert(m.mk_var(idx++, m.mk_bool_sort()), proj); + } + } + else { + sub.insert(m.mk_var(idx++, s), arg); + } + } + sub(body); + g->set_else(body); + model->register_decl(q, g); + } + } + }; class expand_mkbv_cfg : public default_rewriter_cfg { @@ -43,7 +111,8 @@ namespace datalog { ast_manager& m; bv_util m_util; expr_ref_vector m_args, m_f_vars, m_g_vars; - func_decl_ref_vector m_pinned; + func_decl_ref_vector m_old_funcs; + func_decl_ref_vector m_new_funcs; obj_map m_pred2blast; @@ -57,10 +126,14 @@ namespace datalog { m_args(m), m_f_vars(m), m_g_vars(m), - m_pinned(m) + m_old_funcs(m), + m_new_funcs(m) {} ~expand_mkbv_cfg() {} + + func_decl_ref_vector const& old_funcs() const { return m_old_funcs; } + func_decl_ref_vector const& new_funcs() const { return m_new_funcs; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { rule_manager& rm = m_context.get_rule_manager(); @@ -105,13 +178,18 @@ namespace datalog { domain.push_back(m.get_sort(m_args[i].get())); } g = m_context.mk_fresh_head_predicate(f->get_name(), symbol("bv"), m_args.size(), domain.c_ptr(), f); - m_pinned.push_back(g); + m_old_funcs.push_back(f); + m_new_funcs.push_back(g); m_pred2blast.insert(f, g); // Create rule f(mk_mkbv(args)) :- g(args) fml = m.mk_implies(m.mk_app(g, m_g_vars.size(), m_g_vars.c_ptr()), m.mk_app(f, m_f_vars.size(), m_f_vars.c_ptr())); - rm.mk_rule(fml, m_rules, g->get_name()); + proof_ref pr(m); + if (m_context.generate_proof_trace()) { + pr = m.mk_asserted(fml); // or a def? + } + rm.mk_rule(fml, pr, m_rules, g->get_name()); } result = m.mk_app(g, m_args.size(), m_args.c_ptr()); result_pr = 0; @@ -170,14 +248,11 @@ namespace datalog { m_blaster.updt_params(m_params); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * operator()(rule_set const & source, model_converter_ref& mc) { + // TODO pc if (!m_context.get_params().bit_blast()) { return 0; } - if (m_context.get_engine() != PDR_ENGINE) { - return 0; - } rule_manager& rm = m_context.get_rule_manager(); unsigned sz = source.get_num_rules(); expr_ref fml(m); @@ -185,9 +260,13 @@ namespace datalog { rule_set * result = alloc(rule_set, m_context); for (unsigned i = 0; i < sz; ++i) { rule * r = source.get_rule(i); - r->to_formula(fml); + r->to_formula(fml); if (blast(fml)) { - rm.mk_rule(fml, m_rules, r->name()); + proof_ref pr(m); + if (m_context.generate_proof_trace()) { + pr = m.mk_asserted(fml); // loses original proof of r. + } + rm.mk_rule(fml, pr, m_rules, r->name()); } else { m_rules.push_back(r); @@ -197,6 +276,18 @@ namespace datalog { for (unsigned i = 0; i < m_rules.size(); ++i) { result->add_rule(m_rules.get(i)); } + + if (mc) { + filter_model_converter* fmc = alloc(filter_model_converter, m); + bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m); + func_decl_ref_vector const& old_funcs = m_rewriter.m_cfg.old_funcs(); + func_decl_ref_vector const& new_funcs = m_rewriter.m_cfg.new_funcs(); + for (unsigned i = 0; i < old_funcs.size(); ++i) { + fmc->insert(new_funcs[i]); + bvmc->insert(old_funcs[i], new_funcs[i]); + } + mc = concat(mc.get(), concat(bvmc, fmc)); + } return result; } @@ -210,8 +301,8 @@ namespace datalog { dealloc(m_impl); } - rule_set * mk_bit_blast::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - return (*m_impl)(source, mc, pc); + rule_set * mk_bit_blast::operator()(rule_set const & source, model_converter_ref& mc) { + return (*m_impl)(source, mc); } }; diff --git a/src/muz_qe/dl_mk_bit_blast.h b/src/muz_qe/dl_mk_bit_blast.h index e16c2058b..3a6de75e3 100644 --- a/src/muz_qe/dl_mk_bit_blast.h +++ b/src/muz_qe/dl_mk_bit_blast.h @@ -44,7 +44,7 @@ namespace datalog { mk_bit_blast(context & ctx, unsigned priority = 35000); ~mk_bit_blast(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_coalesce.cpp b/src/muz_qe/dl_mk_coalesce.cpp index 222881bc4..de5388312 100644 --- a/src/muz_qe/dl_mk_coalesce.cpp +++ b/src/muz_qe/dl_mk_coalesce.cpp @@ -133,7 +133,7 @@ namespace datalog { tail.push_back(to_app(fml)); is_neg.push_back(false); res = rm.mk(head, tail.size(), tail.c_ptr(), is_neg.c_ptr(), tgt->name()); - if (m_pc) { + if (m_ctx.generate_proof_trace()) { src.to_formula(fml1); tgt->to_formula(fml2); res->to_formula(fml); @@ -142,12 +142,13 @@ namespace datalog { sort* domain[3] = { ps, ps, m.mk_bool_sort() }; func_decl* merge = m.mk_func_decl(symbol("merge-clauses"), 3, domain, ps); // TBD: ad-hoc proof rule expr* args[3] = { m.mk_asserted(fml1), m.mk_asserted(fml2), fml }; - m_pc->insert(m.mk_app(merge, 3, args)); + // ...m_pc->insert(m.mk_app(merge, 3, args)); #else svector > pos; vector substs; - proof* p = m.mk_asserted(fml1); - m_pc->insert(m.mk_hyper_resolve(1, &p, fml, pos, substs)); + proof* p = src.get_proof(); + p = m.mk_hyper_resolve(1, &p, fml, pos, substs); + res->set_proof(m, p); #endif } tgt = res; @@ -170,13 +171,7 @@ namespace datalog { return true; } - rule_set * mk_coalesce::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - m_pc = 0; - ref rpc; - if (pc) { - rpc = alloc(replace_proof_converter, m); - m_pc = rpc.get(); - } + rule_set * mk_coalesce::operator()(rule_set const & source, model_converter_ref& mc) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::decl2rules::iterator it = source.begin_grouped_rules(), end = source.end_grouped_rules(); for (; it != end; ++it) { @@ -195,9 +190,6 @@ namespace datalog { rules->add_rule(r1.get()); } } - if (pc) { - pc = concat(pc.get(), rpc.get()); - } return rules; } diff --git a/src/muz_qe/dl_mk_coalesce.h b/src/muz_qe/dl_mk_coalesce.h index 4259d31fe..ab0b74479 100644 --- a/src/muz_qe/dl_mk_coalesce.h +++ b/src/muz_qe/dl_mk_coalesce.h @@ -37,7 +37,6 @@ namespace datalog { rule_manager& rm; expr_ref_vector m_sub1, m_sub2; unsigned m_idx; - replace_proof_converter* m_pc; void mk_pred(app_ref& pred, app* p1, app* p2); @@ -53,7 +52,7 @@ namespace datalog { */ mk_coalesce(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_coi_filter.cpp b/src/muz_qe/dl_mk_coi_filter.cpp index 04d654120..915dd4306 100644 --- a/src/muz_qe/dl_mk_coi_filter.cpp +++ b/src/muz_qe/dl_mk_coi_filter.cpp @@ -35,8 +35,7 @@ namespace datalog { rule_set * mk_coi_filter::operator()( rule_set const & source, - model_converter_ref& mc, - proof_converter_ref& pc) + model_converter_ref& mc) { if (source.get_num_rules()==0) { return 0; diff --git a/src/muz_qe/dl_mk_coi_filter.h b/src/muz_qe/dl_mk_coi_filter.h index b8fb37964..2191048d3 100644 --- a/src/muz_qe/dl_mk_coi_filter.h +++ b/src/muz_qe/dl_mk_coi_filter.h @@ -40,8 +40,7 @@ namespace datalog { rule_set * operator()(rule_set const & source, - model_converter_ref& mc, - proof_converter_ref& pc); + model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_explanations.cpp b/src/muz_qe/dl_mk_explanations.cpp index 464ec838e..af5b1d97a 100644 --- a/src/muz_qe/dl_mk_explanations.cpp +++ b/src/muz_qe/dl_mk_explanations.cpp @@ -875,8 +875,8 @@ namespace datalog { } } - rule_set * mk_explanations::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - SASSERT(!mc && !pc); + rule_set * mk_explanations::operator()(rule_set const & source, model_converter_ref& mc) { + SASSERT(!mc); if(source.get_num_rules()==0) { return 0; } diff --git a/src/muz_qe/dl_mk_explanations.h b/src/muz_qe/dl_mk_explanations.h index 36fb1a3a1..40606f8df 100644 --- a/src/muz_qe/dl_mk_explanations.h +++ b/src/muz_qe/dl_mk_explanations.h @@ -82,7 +82,7 @@ namespace datalog { return get_union_decl(m_context); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); static expr* get_explanation(relation_base const& r); }; diff --git a/src/muz_qe/dl_mk_extract_quantifiers.cpp b/src/muz_qe/dl_mk_extract_quantifiers.cpp index 35f7485d5..a3d5cc2ab 100644 --- a/src/muz_qe/dl_mk_extract_quantifiers.cpp +++ b/src/muz_qe/dl_mk_extract_quantifiers.cpp @@ -168,7 +168,15 @@ namespace datalog { fml = m.mk_implies(m.mk_and(fmls.size(), fmls.c_ptr()), r.get_head()); TRACE("dl", tout << "new rule\n" << mk_pp(fml, m) << "\n";); rule_ref_vector rules(rm); - rm.mk_rule(fml, rules, r.name()); + proof_ref pr(m); + if (m_ctx.generate_proof_trace()) { + scoped_proof _scp(m); + expr_ref fml1(m); + r.to_formula(fml1); + pr = m.mk_rewrite(fml1, fml); + pr = m.mk_modus_ponens(r.get_proof(), pr); + } + rm.mk_rule(fml, pr, rules, r.name()); for (unsigned i = 0; i < rules.size(); ++i) { new_rules.add_rule(rules[i].get()); m_quantifiers.insert(rules[i].get(), alloc(quantifier_ref_vector, qs)); @@ -347,7 +355,7 @@ namespace datalog { m_quantifiers.reset(); } - rule_set * mk_extract_quantifiers::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { + rule_set * mk_extract_quantifiers::operator()(rule_set const & source, model_converter_ref& mc) { reset(); rule_set::iterator it = source.begin(), end = source.end(); for (; !m_has_quantifiers && it != end; ++it) { diff --git a/src/muz_qe/dl_mk_extract_quantifiers.h b/src/muz_qe/dl_mk_extract_quantifiers.h index b32dbc32d..7d2f7b149 100644 --- a/src/muz_qe/dl_mk_extract_quantifiers.h +++ b/src/muz_qe/dl_mk_extract_quantifiers.h @@ -77,7 +77,7 @@ namespace datalog { void set_query(func_decl* q); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); bool has_quantifiers() { return m_has_quantifiers; } diff --git a/src/muz_qe/dl_mk_filter_rules.cpp b/src/muz_qe/dl_mk_filter_rules.cpp index 4f01a3651..46fde4bc2 100644 --- a/src/muz_qe/dl_mk_filter_rules.cpp +++ b/src/muz_qe/dl_mk_filter_rules.cpp @@ -90,6 +90,7 @@ namespace datalog { rule * filter_rule = m_context.get_rule_manager().mk(filter_head, 1, &filter_tail, (const bool *)0); filter_rule->set_accounting_parent_object(m_context, m_current); m_result->add_rule(filter_rule); + m_context.get_rule_manager().mk_rule_asserted_proof(*filter_rule); } else { dealloc(key); @@ -135,12 +136,13 @@ namespace datalog { } new_is_negated.push_back(r->is_neg_tail(i)); } - if(rule_modified) { + if (rule_modified) { remove_duplicate_tails(new_tail, new_is_negated); SASSERT(new_tail.size() == new_is_negated.size()); rule * new_rule = m_context.get_rule_manager().mk(new_head, new_tail.size(), new_tail.c_ptr(), new_is_negated.c_ptr()); new_rule->set_accounting_parent_object(m_context, m_current); m_result->add_rule(new_rule); + m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *new_rule); m_modified = true; } else { @@ -148,7 +150,7 @@ namespace datalog { } } - rule_set * mk_filter_rules::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { + rule_set * mk_filter_rules::operator()(rule_set const & source, model_converter_ref& mc) { // TODO mc, pc m_tail2filter.reset(); m_result = alloc(rule_set, m_context); diff --git a/src/muz_qe/dl_mk_filter_rules.h b/src/muz_qe/dl_mk_filter_rules.h index cd1d10997..daa72e36f 100644 --- a/src/muz_qe/dl_mk_filter_rules.h +++ b/src/muz_qe/dl_mk_filter_rules.h @@ -72,7 +72,7 @@ namespace datalog { /** \brief Return a new rule set where only filter rules contain atoms with repeated variables and/or values. */ - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index d1b7f15dd..a48b7b32f 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -554,11 +554,13 @@ namespace datalog { bool mk_interp_tail_simplifier::transform_rules(const rule_set & orig, rule_set & tgt) { bool modified = false; + rule_manager& rm = m_context.get_rule_manager(); rule_set::iterator rit = orig.begin(); rule_set::iterator rend = orig.end(); for (; rit!=rend; ++rit) { - rule_ref new_rule(m_context.get_rule_manager()); + rule_ref new_rule(rm); if (transform_rule(*rit, new_rule)) { + rm.mk_rule_rewrite_proof(**rit, *new_rule.get()); bool is_modified = *rit != new_rule; modified |= is_modified; tgt.add_rule(new_rule); @@ -570,8 +572,7 @@ namespace datalog { return modified; } - rule_set * mk_interp_tail_simplifier::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_interp_tail_simplifier::operator()(rule_set const & source, model_converter_ref& mc) { if (source.get_num_rules() == 0) { return 0; } diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.h b/src/muz_qe/dl_mk_interp_tail_simplifier.h index 5e4fd8fbc..4cb14914a 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.h +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.h @@ -93,7 +93,7 @@ namespace datalog { */ bool transform_rule(rule * r, rule_ref& res); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 9c034c890..18b152589 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -310,7 +310,7 @@ namespace datalog { m_hb.reset(); for (unsigned i = 0; i < src.size(); ++i) { vector v(src.A[i]); - v.append(src.b[i]); + v.push_back(src.b[i]); if (src.eq[i]) { m_hb.add_eq(v, rational(0)); } @@ -420,6 +420,7 @@ namespace datalog { new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name()); } rules.add_rule(new_rule); + rm.mk_rule_rewrite_proof(r, *new_rule); // should be weakening rule. } class mk_karr_invariants::add_invariant_model_converter : public model_converter { @@ -519,7 +520,7 @@ namespace datalog { m_hb.set_cancel(true); } - rule_set * mk_karr_invariants::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { + rule_set * mk_karr_invariants::operator()(rule_set const & source, model_converter_ref& mc) { if (!m_ctx.get_params().karr()) { return 0; } diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index 3b82578a4..7cd26d495 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -69,7 +69,7 @@ namespace datalog { virtual void cancel(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; diff --git a/src/muz_qe/dl_mk_magic_sets.cpp b/src/muz_qe/dl_mk_magic_sets.cpp index 373a90969..990040ab8 100644 --- a/src/muz_qe/dl_mk_magic_sets.cpp +++ b/src/muz_qe/dl_mk_magic_sets.cpp @@ -317,8 +317,8 @@ namespace datalog { m_rules.push_back(r); } - rule_set * mk_magic_sets::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - SASSERT(!mc && !pc); + rule_set * mk_magic_sets::operator()(rule_set const & source, model_converter_ref& mc) { + SASSERT(!mc); unsigned init_rule_cnt = source.get_num_rules(); { func_decl_set intentional; diff --git a/src/muz_qe/dl_mk_magic_sets.h b/src/muz_qe/dl_mk_magic_sets.h index f98ad55a3..3f50e6713 100644 --- a/src/muz_qe/dl_mk_magic_sets.h +++ b/src/muz_qe/dl_mk_magic_sets.h @@ -121,7 +121,7 @@ namespace datalog { */ mk_magic_sets(context & ctx, rule * goal_rule); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_partial_equiv.cpp b/src/muz_qe/dl_mk_partial_equiv.cpp index 367a15743..b55f5294e 100644 --- a/src/muz_qe/dl_mk_partial_equiv.cpp +++ b/src/muz_qe/dl_mk_partial_equiv.cpp @@ -86,8 +86,8 @@ namespace datalog { } - rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source, model_converter_ref& mc) { + // TODO mc if (source.get_num_rules() == 0) { return 0; diff --git a/src/muz_qe/dl_mk_partial_equiv.h b/src/muz_qe/dl_mk_partial_equiv.h index 8fef4aea9..c44d59e8c 100644 --- a/src/muz_qe/dl_mk_partial_equiv.h +++ b/src/muz_qe/dl_mk_partial_equiv.h @@ -35,7 +35,7 @@ namespace datalog { m(ctx.get_manager()), m_context(ctx) {} - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); private: diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp index 1404c9c8c..047ed768f 100644 --- a/src/muz_qe/dl_mk_rule_inliner.cpp +++ b/src/muz_qe/dl_mk_rule_inliner.cpp @@ -181,10 +181,10 @@ namespace datalog { } if (m_unifier.apply(tgt, tail_index, src, res)) { - if (m_pc) { + if (m_context.generate_proof_trace()) { expr_ref_vector s1 = m_unifier.get_rule_subst(tgt, true); expr_ref_vector s2 = m_unifier.get_rule_subst(src, false); - datalog::resolve_rule(m_pc, tgt, src, tail_index, s1, s2, *res.get()); + datalog::resolve_rule(tgt, src, tail_index, s1, s2, *res.get()); } return true; } @@ -837,11 +837,10 @@ namespace datalog { return done_something; } - rule_set * mk_rule_inliner::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { + rule_set * mk_rule_inliner::operator()(rule_set const & source, model_converter_ref& mc) { bool something_done = false; ref hsmc; - ref hpc; if (source.get_num_rules() == 0) { return 0; @@ -858,11 +857,7 @@ namespace datalog { if (mc) { hsmc = alloc(horn_subsume_model_converter, m); } - if (pc) { - hpc = alloc(replace_proof_converter, m); - } m_mc = hsmc.get(); - m_pc = hpc.get(); scoped_ptr res = alloc(rule_set, m_context); @@ -889,9 +884,6 @@ namespace datalog { if (mc) { mc = concat(mc.get(), hsmc.get()); } - if (pc) { - pc = concat(pc.get(), hpc.get()); - } } return res.detach(); diff --git a/src/muz_qe/dl_mk_rule_inliner.h b/src/muz_qe/dl_mk_rule_inliner.h index 6d5448cd6..a58b3b473 100644 --- a/src/muz_qe/dl_mk_rule_inliner.h +++ b/src/muz_qe/dl_mk_rule_inliner.h @@ -114,7 +114,6 @@ namespace datalog { ast_counter m_tail_pred_ctr; rule_set m_inlined_rules; horn_subsume_model_converter* m_mc; - replace_proof_converter* m_pc; //used in try_to_inline_rule and do_eager_inlining @@ -188,7 +187,6 @@ namespace datalog { m_pinned(m_rm), m_inlined_rules(m_context), m_mc(0), - m_pc(0), m_unifier(ctx), m_head_index(m), m_tail_index(m), @@ -198,7 +196,7 @@ namespace datalog { {} virtual ~mk_rule_inliner() { } - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index a040a623a..dfd0a4d81 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -500,8 +500,8 @@ namespace datalog { } } - rule_set * mk_similarity_compressor::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_similarity_compressor::operator()(rule_set const & source, model_converter_ref& mc) { + // TODO mc m_modified = false; unsigned init_rule_cnt = source.get_num_rules(); SASSERT(m_rules.empty()); diff --git a/src/muz_qe/dl_mk_similarity_compressor.h b/src/muz_qe/dl_mk_similarity_compressor.h index ad4a5e246..d1ded01e7 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.h +++ b/src/muz_qe/dl_mk_similarity_compressor.h @@ -69,7 +69,7 @@ namespace datalog { public: mk_similarity_compressor(context & ctx, unsigned threshold_count); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_simple_joins.cpp b/src/muz_qe/dl_mk_simple_joins.cpp index 77c6c2951..f19e34fec 100644 --- a/src/muz_qe/dl_mk_simple_joins.cpp +++ b/src/muz_qe/dl_mk_simple_joins.cpp @@ -706,19 +706,20 @@ namespace datalog { negs.c_ptr()); new_rule->set_accounting_parent_object(m_context, orig_r); - + m_context.get_rule_manager().mk_rule_rewrite_proof(*orig_r, *new_rule); result->add_rule(new_rule); } - while(!m_introduced_rules.empty()) { + while (!m_introduced_rules.empty()) { result->add_rule(m_introduced_rules.back()); + m_context.get_rule_manager().mk_rule_asserted_proof(*m_introduced_rules.back()); m_introduced_rules.pop_back(); } return result; } }; - rule_set * mk_simple_joins::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_simple_joins::operator()(rule_set const & source, model_converter_ref& mc) { + // TODO mc rule_set rs_aux_copy(m_context); rs_aux_copy.add_rules(source); if(!rs_aux_copy.is_closed()) { diff --git a/src/muz_qe/dl_mk_simple_joins.h b/src/muz_qe/dl_mk_simple_joins.h index 5431c4117..df8d3f55c 100644 --- a/src/muz_qe/dl_mk_simple_joins.h +++ b/src/muz_qe/dl_mk_simple_joins.h @@ -53,7 +53,7 @@ namespace datalog { public: mk_simple_joins(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_slice.cpp b/src/muz_qe/dl_mk_slice.cpp index 84b732280..0adab78ce 100644 --- a/src/muz_qe/dl_mk_slice.cpp +++ b/src/muz_qe/dl_mk_slice.cpp @@ -164,10 +164,8 @@ namespace datalog { TRACE("dl", tout << "does not have fact\n" << mk_pp(fact, m) << "\n";); return false; } - expr_ref fml(m); proof_ref new_p(m); - r->to_formula(fml); - new_p = m.mk_asserted(fml); + new_p = r->get_proof(); m_pinned_exprs.push_back(new_p); m_todo.pop_back(); m_new_proof.insert(p, new_p); @@ -784,6 +782,9 @@ namespace datalog { rm.fix_unbound_vars(new_rule, false); TRACE("dl", r.display(m_ctx, tout << "replacing:\n"); new_rule->display(m_ctx, tout << "by:\n");); + if (m_ctx.generate_proof_trace()) { + rm.mk_rule_asserted_proof(*new_rule.get()); + } } else { new_rule = &r; @@ -801,7 +802,7 @@ namespace datalog { } } - rule_set * mk_slice::operator()(rule_set const & src, model_converter_ref& mc, proof_converter_ref& pc) { + rule_set * mk_slice::operator()(rule_set const & src, model_converter_ref& mc) { for (unsigned i = 0; i < src.get_num_rules(); ++i) { if (src.get_rule(i)->has_quantifiers()) { return 0; @@ -809,8 +810,8 @@ namespace datalog { } ref spc; ref smc; - if (pc) { - spc = alloc(slice_proof_converter, m_ctx); + if (m_ctx.generate_proof_trace()) { + spc = alloc(slice_proof_converter, m_ctx); } if (mc) { smc = alloc(slice_model_converter, *this, m); @@ -834,7 +835,7 @@ namespace datalog { m_mc->add_sliceable(it->m_key, it->m_value); } } - pc = concat(pc.get(), spc.get()); + m_ctx.add_proof_converter(spc.get()); mc = concat(mc.get(), smc.get()); return result; } diff --git a/src/muz_qe/dl_mk_slice.h b/src/muz_qe/dl_mk_slice.h index 26a8175f2..4290ee4b9 100644 --- a/src/muz_qe/dl_mk_slice.h +++ b/src/muz_qe/dl_mk_slice.h @@ -102,7 +102,7 @@ namespace datalog { virtual ~mk_slice() { } - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); func_decl* get_predicate(func_decl* p) { func_decl* q = p; m_predicates.find(p, q); return q; } diff --git a/src/muz_qe/dl_mk_subsumption_checker.cpp b/src/muz_qe/dl_mk_subsumption_checker.cpp index 19c28c036..2f0d56475 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.cpp +++ b/src/muz_qe/dl_mk_subsumption_checker.cpp @@ -166,7 +166,8 @@ namespace datalog { res = m_context.get_rule_manager().mk(head, tail.size(), tail.c_ptr(), tail_neg.c_ptr()); res->set_accounting_parent_object(m_context, r); m_context.get_rule_manager().fix_unbound_vars(res, true); - + m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *res.get()); + return true; } @@ -208,10 +209,10 @@ namespace datalog { continue; } rule * defining_rule; - TRUSTME(m_total_relation_defining_rules.find(head_pred, defining_rule)); - if(defining_rule) { + VERIFY(m_total_relation_defining_rules.find(head_pred, defining_rule)); + if (defining_rule) { rule_ref totality_rule(m_context.get_rule_manager()); - TRUSTME(transform_rule(defining_rule, subs_index, totality_rule)); + VERIFY(transform_rule(defining_rule, subs_index, totality_rule)); if(defining_rule!=totality_rule) { modified = true; } @@ -331,8 +332,8 @@ namespace datalog { } } - rule_set * mk_subsumption_checker::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_subsumption_checker::operator()(rule_set const & source, model_converter_ref& mc) { + // TODO mc m_have_new_total_rule = false; collect_ground_unconditional_rule_heads(source); diff --git a/src/muz_qe/dl_mk_subsumption_checker.h b/src/muz_qe/dl_mk_subsumption_checker.h index ce33e7574..a95f08c5d 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.h +++ b/src/muz_qe/dl_mk_subsumption_checker.h @@ -84,7 +84,7 @@ namespace datalog { reset_dealloc_values(m_ground_unconditional_rule_heads); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_unbound_compressor.cpp b/src/muz_qe/dl_mk_unbound_compressor.cpp index e3db82759..54b6f4ebe 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.cpp +++ b/src/muz_qe/dl_mk_unbound_compressor.cpp @@ -238,6 +238,7 @@ namespace datalog { unsigned new_rule_index = m_rules.size(); m_rules.push_back(new_rule); + m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *new_rule.get()); m_head_occurrence_ctr.inc(new_rule->get_head()->get_decl()); @@ -333,8 +334,8 @@ namespace datalog { } } - rule_set * mk_unbound_compressor::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - // TODO mc, pc + rule_set * mk_unbound_compressor::operator()(rule_set const & source, model_converter_ref& mc) { + // TODO mc m_modified = false; m_context.get_rel_context().get_rmanager().collect_non_empty_predicates(m_non_empty_rels); diff --git a/src/muz_qe/dl_mk_unbound_compressor.h b/src/muz_qe/dl_mk_unbound_compressor.h index 0e13bad75..256be180d 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.h +++ b/src/muz_qe/dl_mk_unbound_compressor.h @@ -82,7 +82,7 @@ namespace datalog { public: mk_unbound_compressor(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_mk_unfold.cpp b/src/muz_qe/dl_mk_unfold.cpp index d26a0a290..7af82110a 100644 --- a/src/muz_qe/dl_mk_unfold.cpp +++ b/src/muz_qe/dl_mk_unfold.cpp @@ -42,29 +42,20 @@ namespace datalog { if (m_unify.unify_rules(r, tail_idx, r2) && m_unify.apply(r, tail_idx, r2, new_rule)) { expr_ref_vector s1 = m_unify.get_rule_subst(r, true); - expr_ref_vector s2 = m_unify.get_rule_subst(r2, false); - resolve_rule(m_pc, r, r2, tail_idx, s1, s2, *new_rule.get()); + expr_ref_vector s2 = m_unify.get_rule_subst(r2, false); + resolve_rule(r, r2, tail_idx, s1, s2, *new_rule.get()); expand_tail(*new_rule.get(), tail_idx+r2.get_uninterpreted_tail_size(), src, dst); } } } } - rule_set * mk_unfold::operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc) { - m_pc = 0; - ref rpc; - if (pc) { - rpc = alloc(replace_proof_converter, m); - m_pc = rpc.get(); - } + rule_set * mk_unfold::operator()(rule_set const & source, model_converter_ref& mc) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::iterator it = source.begin(), end = source.end(); for (; it != end; ++it) { expand_tail(**it, 0, source, *rules); } - if (pc) { - pc = concat(pc.get(), rpc.get()); - } return rules; } diff --git a/src/muz_qe/dl_mk_unfold.h b/src/muz_qe/dl_mk_unfold.h index 3d20686a7..90aefa86e 100644 --- a/src/muz_qe/dl_mk_unfold.h +++ b/src/muz_qe/dl_mk_unfold.h @@ -35,7 +35,6 @@ namespace datalog { ast_manager& m; rule_manager& rm; rule_unifier m_unify; - replace_proof_converter* m_pc; void expand_tail(rule& r, unsigned tail_idx, rule_set const& src, rule_set& dst); @@ -45,7 +44,7 @@ namespace datalog { */ mk_unfold(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc, proof_converter_ref& pc); + rule_set * operator()(rule_set const & source, model_converter_ref& mc); }; }; diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 59a245cc4..1896e7e64 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -42,13 +42,13 @@ Revision History: #include"bool_rewriter.h" #include"qe_lite.h" #include"expr_safe_replace.h" +#include"hnf.h" namespace datalog { rule_manager::rule_manager(context& ctx) : m(ctx.get_manager()), - m_ctx(ctx), - m_refs(ctx.get_manager()) {} + m_ctx(ctx) {} bool rule_manager::is_predicate(func_decl * f) const { return m_ctx.is_predicate(f); @@ -89,72 +89,32 @@ namespace datalog { } }; - void rule_manager::remove_labels(expr_ref& fml) { + void rule_manager::remove_labels(expr_ref& fml, proof_ref& pr) { expr_ref tmp(m); remove_label_cfg r_cfg(m); rewriter_tpl rwr(m, false, r_cfg); rwr(fml, tmp); + if (pr && fml != tmp) { + + pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp)); + } fml = tmp; } - void rule_manager::mk_rule(expr* fml, rule_ref_vector& rules, symbol const& name) { + void rule_manager::mk_rule(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name) { + scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); + proof_ref pr(p, m); expr_ref fml1(m); - m_memoize_disj.reset(); - m_refs.reset(); bind_variables(fml, true, fml1); - remove_labels(fml1); - mk_rule_core(fml1, rules, name); + if (fml1 != fml && pr) { + pr = m.mk_asserted(fml1); + } + remove_labels(fml1, pr); + mk_rule_core_new(fml1, pr, rules, name); } - - void rule_manager::mk_rule_core(expr* _fml, rule_ref_vector& rules, symbol const& name) { - app_ref_vector body(m); - app_ref head(m); - expr_ref e(m), fml(_fml, m); - svector is_negated; - TRACE("dl_rule", tout << mk_pp(fml, m) << "\n";); - quantifier_hoister qh(m); - unsigned index = qh.pull_quantifier(true, fml, 0); - check_app(fml); - head = to_app(fml); - - while (m.is_implies(head)) { - e = head->get_arg(0); - th_rewriter th_rwr(m); - th_rwr(e); - body.push_back(ensure_app(e)); - e = to_app(head)->get_arg(1); - check_app(e); - head = to_app(e.get()); - } - symbol head_name = (name == symbol::null)?head->get_decl()->get_name():name; - flatten_body(body); - if (body.size() == 1 && m.is_or(body[0].get()) && contains_predicate(body[0].get())) { - app* _or = to_app(body[0].get()); - for (unsigned i = 0; i < _or->get_num_args(); ++i) { - e = m.mk_implies(_or->get_arg(i), head); - mk_rule_core(e, rules, head_name); - } - return; - } - - eliminate_disjunctions(body, rules, head_name); - eliminate_quantifier_body(body, rules, head_name); - hoist_compound(index, head, body); - unsigned sz = body.size(); - for (unsigned i = 0; i < sz; ++i) { - app_ref b(body[i].get(), m); - hoist_compound(index, b, body); - body[i] = b; - } - TRACE("dl_rule", - tout << mk_pp(head, m) << " :- "; - for (unsigned i = 0; i < body.size(); ++i) { - tout << mk_pp(body[i].get(), m) << " "; - } - tout << "\n";); - + void rule_manager::mk_negations(app_ref_vector& body, svector& is_negated) { for (unsigned i = 0; i < body.size(); ++i) { expr* e = body[i].get(), *e1; if (m.is_not(e, e1) && is_predicate(e1)) { @@ -165,23 +125,105 @@ namespace datalog { else { is_negated.push_back(false); } - } - check_valid_rule(head, body.size(), body.c_ptr()); + } + } - rules.push_back(mk(head.get(), body.size(), body.c_ptr(), is_negated.c_ptr(), name)); - - if (m_ctx.fix_unbound_vars()) { - unsigned rule_cnt = rules.size(); - for (unsigned i=0; i is_negated; + unsigned index = extract_horn(fml, body, head); + hoist_compound_predicates(index, head, body); + TRACE("dl_rule", + tout << mk_pp(head, m) << " :- "; + for (unsigned i = 0; i < body.size(); ++i) { + tout << mk_pp(body[i].get(), m) << " "; + } + tout << "\n";); + + + mk_negations(body, is_negated); + check_valid_rule(head, body.size(), body.c_ptr()); + + rule_ref r(*this); + r = mk(head.get(), body.size(), body.c_ptr(), is_negated.c_ptr(), name); + + expr_ref fml1(m); + if (p) { + r->to_formula(fml1); + if (fml1 == fml) { + // no-op. + } + else if (is_quantifier(fml1)) { + p = m.mk_modus_ponens(p, m.mk_symmetry(m.mk_der(to_quantifier(fml1), fml))); + } + else { + p = m.mk_modus_ponens(p, m.mk_rewrite(fml, fml1)); + } + } + + if (m_ctx.fix_unbound_vars()) { + fix_unbound_vars(r, true); + } + + if (p) { + expr_ref fml2(m); + r->to_formula(fml2); + if (fml1 != fml2) { + p = m.mk_modus_ponens(p, m.mk_rewrite(fml1, fml2)); + } + r->set_proof(m, p); + } + rules.push_back(r); + } + + unsigned rule_manager::extract_horn(expr* fml, app_ref_vector& body, app_ref& head) { + expr* e1, *e2; + unsigned index = m_counter.get_next_var(fml); + if (::is_forall(fml)) { + index += to_quantifier(fml)->get_num_decls(); + fml = to_quantifier(fml)->get_expr(); + } + if (m.is_implies(fml, e1, e2)) { + expr_ref_vector es(m); + head = ensure_app(e2); + datalog::flatten_and(e1, es); + for (unsigned i = 0; i < es.size(); ++i) { + body.push_back(ensure_app(es[i].get())); + } + } + else { + head = ensure_app(fml); + } + return index; + } + + void rule_manager::hoist_compound_predicates(unsigned index, app_ref& head, app_ref_vector& body) { + unsigned sz = body.size(); + hoist_compound(index, head, body); + for (unsigned i = 0; i < sz; ++i) { + app_ref b(body[i].get(), m); + hoist_compound(index, b, body); + body[i] = b; + } + } + + void rule_manager::mk_query(expr* query, func_decl_ref& qpred, rule_ref_vector& query_rules, rule_ref& query_rule) { ptr_vector vars; svector names; @@ -192,7 +234,7 @@ namespace datalog { // Remove existential prefix. bind_variables(query, false, q); quantifier_hoister qh(m); - qh.pull_quantifier(false, q, &names); + qh.pull_quantifier(false, q, 0, &names); // retrieve free variables. get_free_vars(q, vars); if (vars.contains(static_cast(0))) { @@ -250,7 +292,12 @@ namespace datalog { rule_expr = m.mk_forall(vars.size(), vars.c_ptr(), names.c_ptr(), impl); } - mk_rule(rule_expr, query_rules); + scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); + proof_ref pr(m); + if (m_ctx.generate_proof_trace()) { + pr = m.mk_asserted(rule_expr); + } + mk_rule(rule_expr, pr, query_rules); SASSERT(query_rules.size() >= 1); query_rule = query_rules.back(); } @@ -330,73 +377,6 @@ namespace datalog { return false; } - void rule_manager::eliminate_disjunctions(app_ref_vector::element_ref& body, rule_ref_vector& rules, symbol const& name) { - - app* b = body.get(); - expr* e1; - bool negate_args = false; - bool is_disj = false; - unsigned num_disj = 0; - expr* const* disjs = 0; - if (!contains_predicate(b)) { - return; - } - TRACE("dl_rule", tout << mk_ismt2_pp(b, m) << "\n";); - if (m.is_or(b)) { - is_disj = true; - negate_args = false; - num_disj = b->get_num_args(); - disjs = b->get_args(); - } - if (m.is_not(b, e1) && m.is_and(e1)) { - is_disj = true; - negate_args = true; - num_disj = to_app(e1)->get_num_args(); - disjs = to_app(e1)->get_args(); - } - if (is_disj) { - ptr_vector sorts0, sorts1; - get_free_vars(b, sorts0); - expr_ref_vector args(m); - for (unsigned i = 0; i < sorts0.size(); ++i) { - if (sorts0[i]) { - args.push_back(m.mk_var(i,sorts0[i])); - sorts1.push_back(sorts0[i]); - } - } - app* old_head = 0; - if (m_memoize_disj.find(b, old_head)) { - body = old_head; - } - else { - app_ref head(m); - func_decl_ref f(m); - f = m.mk_fresh_func_decl(name.str().c_str(),"", sorts1.size(), sorts1.c_ptr(), m.mk_bool_sort()); - m_ctx.register_predicate(f); - head = m.mk_app(f, args.size(), args.c_ptr()); - - for (unsigned i = 0; i < num_disj; ++i) { - expr_ref fml(m); - expr* e = disjs[i]; - if (negate_args) e = m.mk_not(e); - fml = m.mk_implies(e,head); - mk_rule_core(fml, rules, name); - } - m_memoize_disj.insert(b, head); - m_refs.push_back(b); - m_refs.push_back(head); - // update the body to be the newly introduced head relation - body = head; - } - } - } - - void rule_manager::eliminate_disjunctions(app_ref_vector& body, rule_ref_vector& rules, symbol const& name) { - for (unsigned i = 0; i < body.size(); ++i) { - app_ref_vector::element_ref t = body[i]; - eliminate_disjunctions(t, rules, name); - } - } bool rule_manager::is_forall(ast_manager& m, expr* e, quantifier*& q) { expr* e1, *e2; @@ -415,40 +395,6 @@ namespace datalog { return false; } - void rule_manager::eliminate_quantifier_body(app_ref_vector::element_ref& body, rule_ref_vector& rules, symbol const& name) { - quantifier* q; - if (is_forall(m, body.get(), q) && contains_predicate(q)) { - expr* e = q->get_expr(); - if (!is_predicate(e)) { - ptr_vector sorts0, sorts1; - get_free_vars(e, sorts0); - expr_ref_vector args(m); - for (unsigned i = 0; i < sorts0.size(); ++i) { - if (sorts0[i]) { - args.push_back(m.mk_var(i,sorts0[i])); - sorts1.push_back(sorts0[i]); - } - } - app_ref head(m), fml(m); - func_decl_ref f(m); - f = m.mk_fresh_func_decl(name.str().c_str(),"", sorts1.size(), sorts1.c_ptr(), m.mk_bool_sort()); - m_ctx.register_predicate(f); - head = m.mk_app(f, args.size(), args.c_ptr()); - fml = m.mk_implies(e, head); - mk_rule_core(fml, rules, name); - // update the body to be the newly introduced head relation - body = m.mk_eq(m.mk_true(), m.update_quantifier(q, head)); - } - } - } - - void rule_manager::eliminate_quantifier_body(app_ref_vector& body, rule_ref_vector& rules, symbol const& name) { - for (unsigned i = 0; i < body.size(); ++i) { - app_ref_vector::element_ref t = body[i]; - eliminate_quantifier_body(t, rules, name); - } - } - app_ref rule_manager::ensure_app(expr* e) { SASSERT(m.is_bool(e)); @@ -476,6 +422,7 @@ namespace datalog { r->m_head = head; r->m_name = name; r->m_tail_size = n; + r->m_proof = 0; m.inc_ref(r->m_head); app * * uninterp_tail = r->m_tail; //grows upwards @@ -533,6 +480,11 @@ namespace datalog { if (normalize) { r->norm_vars(*this); } + DEBUG_CODE(ptr_vector sorts; + ::get_free_vars(head, sorts); + for (unsigned i = 0; i < n; ++i) { + ::get_free_vars(tail[i], sorts); + }); return r; } @@ -754,6 +706,27 @@ namespace datalog { r->set_accounting_parent_object(m_ctx, old_r); } + void rule_manager::mk_rule_rewrite_proof(rule& old_rule, rule& new_rule) { + if (&old_rule != &new_rule && + !new_rule.get_proof() && + old_rule.get_proof()) { + expr_ref fml(m); + new_rule.to_formula(fml); + scoped_proof _sc(m); + proof* p = m.mk_rewrite(m.get_fact(old_rule.get_proof()), fml); + new_rule.set_proof(m, m.mk_modus_ponens(old_rule.get_proof(), p)); + } + } + + void rule_manager::mk_rule_asserted_proof(rule& r) { + if (m_ctx.generate_proof_trace()) { + scoped_proof _scp(m); + expr_ref fml(m); + r.to_formula(fml); + r.set_proof(m, m.mk_asserted(fml)); + } + } + void rule_manager::substitute(rule_ref& r, unsigned sz, expr*const* es) { expr_ref tmp(m); app_ref new_head(m); @@ -812,10 +785,23 @@ namespace datalog { for (unsigned i = 0; i < n; i++) { m.dec_ref(get_tail(i)); } + if (m_proof) { + m.dec_ref(m_proof); + } this->~rule(); m.get_allocator().deallocate(get_obj_size(n), this); } + void rule::set_proof(ast_manager& m, proof* p) { + if (p) { + m.inc_ref(p); + } + if (m_proof) { + m.dec_ref(m_proof); + } + m_proof = p; + } + bool rule::is_in_tail(const func_decl * p, bool only_positive) const { unsigned len = only_positive ? get_positive_tail_size() : get_uninterpreted_tail_size(); for (unsigned i = 0; i < len; i++) { @@ -993,6 +979,9 @@ namespace datalog { out << '}'; } out << '\n'; + if (m_proof) { + out << mk_pp(m_proof, m) << '\n'; + } } void rule::to_formula(expr_ref& fml) const { diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index a8c6e0314..5b1338b22 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -43,11 +43,9 @@ namespace datalog { */ class rule_manager { - ast_manager& m; - context& m_ctx; - rule_counter m_counter; - obj_map m_memoize_disj; - expr_ref_vector m_refs; + ast_manager& m; + context& m_ctx; + rule_counter m_counter; // only the context can create a rule_manager friend class context; @@ -57,19 +55,13 @@ namespace datalog { /** \brief Move functions from predicate tails into the interpreted tail by introducing new variables. */ + void hoist_compound_predicates(unsigned num_bound, app_ref& head, app_ref_vector& body); + void hoist_compound(unsigned& num_bound, app_ref& fml, app_ref_vector& body); void flatten_body(app_ref_vector& body); - void remove_labels(expr_ref& fml); - - void eliminate_disjunctions(app_ref_vector::element_ref& body, rule_ref_vector& rules, symbol const& name); - - void eliminate_disjunctions(app_ref_vector& body, rule_ref_vector& rules, symbol const& name); - - void eliminate_quantifier_body(app_ref_vector::element_ref& body, rule_ref_vector& rules, symbol const& name); - - void eliminate_quantifier_body(app_ref_vector& body, rule_ref_vector& rules, symbol const& name); + void remove_labels(expr_ref& fml, proof_ref& pr); app_ref ensure_app(expr* e); @@ -81,6 +73,16 @@ namespace datalog { void mk_rule_core(expr* fml, rule_ref_vector& rules, symbol const& name); + void mk_negations(app_ref_vector& body, svector& is_negated); + + void mk_rule_core_new(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name); + + void mk_rule_core2(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name); + + static expr_ref mk_implies(app_ref_vector const& body, expr* head); + + unsigned extract_horn(expr* fml, app_ref_vector& body, app_ref& head); + /** \brief Perform cheap quantifier elimination to reduce the number of variables in the interpreted tail. */ @@ -99,7 +101,7 @@ namespace datalog { The formula is of the form (forall (...) (forall (...) (=> (and ...) head))) */ - void mk_rule(expr* fml, rule_ref_vector& rules, symbol const& name = symbol::null); + void mk_rule(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name = symbol::null); /** \brief Create a Datalog query from an expression. @@ -129,7 +131,15 @@ namespace datalog { /** make sure there are not non-quantified variables that occur only in interpreted predicates */ void fix_unbound_vars(rule_ref& r, bool try_quantifier_elimination); + /** + \brief add proof that new rule is obtained by rewriting old rule. + */ + void mk_rule_rewrite_proof(rule& old_rule, rule& new_rule); + /** + \brief tag rule as asserted. + */ + void mk_rule_asserted_proof(rule& r); /** \brief apply substitution to variables of rule. @@ -168,6 +178,7 @@ namespace datalog { friend class rule_manager; app * m_head; + proof* m_proof; unsigned m_tail_size:20; // unsigned m_reserve:12; unsigned m_ref_cnt; @@ -199,6 +210,10 @@ namespace datalog { void get_used_vars(used_vars& uv) const; public: + + proof * get_proof() const { return m_proof; } + + void set_proof(ast_manager& m, proof* p); app * get_head() const { return m_head; } diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index a246d9d61..5ecbf2b45 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -73,7 +73,7 @@ namespace datalog { m_dirty=true; } - bool rule_transformer::operator()(rule_set & rules, model_converter_ref& mc, proof_converter_ref& pc) { + bool rule_transformer::operator()(rule_set & rules, model_converter_ref& mc) { ensure_ordered(); bool modified = false; @@ -87,7 +87,7 @@ namespace datalog { for(; it!=end && !m_cancel; ++it) { plugin & p = **it; - rule_set * new_rules = p(rules, mc, pc); + rule_set * new_rules = p(rules, mc); if (!new_rules) { continue; } diff --git a/src/muz_qe/dl_rule_transformer.h b/src/muz_qe/dl_rule_transformer.h index cf1a9be75..3b2140caf 100644 --- a/src/muz_qe/dl_rule_transformer.h +++ b/src/muz_qe/dl_rule_transformer.h @@ -24,7 +24,6 @@ Revision History: #include"dl_rule.h" #include"dl_rule_set.h" #include"model_converter.h" -#include"proof_converter.h" namespace datalog { @@ -69,7 +68,7 @@ namespace datalog { \brief Transform the rule set using the registered transformation plugins. If the rule set has changed, return true; otherwise return false. */ - bool operator()(rule_set & rules, model_converter_ref& mc, proof_converter_ref& pc); + bool operator()(rule_set & rules, model_converter_ref& mc); }; class rule_transformer::plugin { @@ -106,8 +105,7 @@ namespace datalog { The caller takes ownership of the returned \c rule_set object. */ virtual rule_set * operator()(rule_set const & source, - model_converter_ref& mc, - proof_converter_ref& pc) = 0; + model_converter_ref& mc) = 0; virtual void cancel() { m_cancel = true; } diff --git a/src/muz_qe/dl_util.cpp b/src/muz_qe/dl_util.cpp index bde03e765..28634d30e 100644 --- a/src/muz_qe/dl_util.cpp +++ b/src/muz_qe/dl_util.cpp @@ -511,6 +511,44 @@ namespace datalog { pc->insert(pr); } + void resolve_rule(rule const& r1, rule const& r2, unsigned idx, + expr_ref_vector const& s1, expr_ref_vector const& s2, rule& res) { + if (!r1.get_proof()) { + return; + } + SASSERT(r2.get_proof()); + ast_manager& m = s1.get_manager(); + expr_ref fml(m); + res.to_formula(fml); + vector substs; + svector > positions; + substs.push_back(s1); + substs.push_back(s2); + + scoped_proof _sc(m); + proof_ref pr(m); + proof_ref_vector premises(m); + premises.push_back(r1.get_proof()); + premises.push_back(r2.get_proof()); + positions.push_back(std::make_pair(idx+1, 0)); + + TRACE("dl", + tout << premises[0]->get_id() << " " << mk_pp(premises[0].get(), m) << "\n"; + for (unsigned i = 0; i < s1.size(); ++i) { + tout << mk_pp(s1[i], m) << " "; + } + tout << "\n"; + tout << premises[1]->get_id() << " " << mk_pp(premises[1].get(), m) << "\n"; + for (unsigned i = 0; i < s2.size(); ++i) { + tout << mk_pp(s2[i], m) << " "; + } + tout << "\n"; + ); + + pr = m.mk_hyper_resolve(2, premises.c_ptr(), fml, positions, substs); + res.set_proof(m, pr); + } + class skip_model_converter : public model_converter { public: skip_model_converter() {} diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index 45d327d44..e53e6c998 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -425,6 +425,9 @@ namespace datalog { void resolve_rule(replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx, expr_ref_vector const& s1, expr_ref_vector const& s2, rule const& res); + void resolve_rule(rule const& r1, rule const& r2, unsigned idx, + expr_ref_vector const& s1, expr_ref_vector const& s2, rule& res); + model_converter* mk_skip_model_converter(); proof_converter* mk_skip_proof_converter(); diff --git a/src/muz_qe/equiv_proof_converter.cpp b/src/muz_qe/equiv_proof_converter.cpp index 53db01900..98ea88044 100644 --- a/src/muz_qe/equiv_proof_converter.cpp +++ b/src/muz_qe/equiv_proof_converter.cpp @@ -22,12 +22,14 @@ Revision History: #include "dl_util.h" void equiv_proof_converter::insert(expr* fml1, expr* fml2) { - datalog::scoped_proof _sp(m); - proof_ref p1(m), p2(m), p3(m); - p1 = m.mk_asserted(fml1); - p2 = m.mk_rewrite(fml1, fml2); - p3 = m.mk_modus_ponens(p1, p2); - TRACE("proof_converter", tout << mk_pp(p3.get(), m) << "\n";); - SASSERT(m.has_fact(p3)); - m_replace.insert(p3); + if (fml1 != fml2) { + datalog::scoped_proof _sp(m); + proof_ref p1(m), p2(m), p3(m); + p1 = m.mk_asserted(fml1); + p2 = m.mk_rewrite(fml1, fml2); + p3 = m.mk_modus_ponens(p1, p2); + TRACE("proof_converter", tout << mk_pp(p3.get(), m) << "\n";); + SASSERT(m.has_fact(p3)); + m_replace.insert(p3); + } } diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index c87874b29..02c41c091 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -113,8 +113,8 @@ class horn_tactic : public tactic { todo.append(to_app(a)->get_num_args(), to_app(a)->get_args()); } else if (m.is_ite(a)) { - todo.append(to_app(a)->get_arg(1)); - todo.append(to_app(a)->get_arg(2)); + todo.push_back(to_app(a)->get_arg(1)); + todo.push_back(to_app(a)->get_arg(2)); } else if (is_predicate(a)) { register_predicate(a); @@ -270,20 +270,10 @@ class horn_tactic : public tactic { proof_converter_ref & pc) { expr_ref fml(m); - bool produce_models = g->models_enabled(); - bool produce_proofs = g->proofs_enabled(); - if (produce_models) { - mc = datalog::mk_skip_model_converter(); - } - if (produce_proofs) { - pc = datalog::mk_skip_proof_converter(); - } func_decl* query_pred = to_app(q)->get_decl(); m_ctx.set_output_predicate(query_pred); - m_ctx.set_model_converter(mc); - m_ctx.set_proof_converter(pc); m_ctx.get_rules(); // flush adding rules. m_ctx.apply_default_transformation(); diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index d6718c33c..d4027d73d 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -950,16 +950,45 @@ namespace pdr { return out; } + /** + \brief Ensure that all nodes in the tree have associated models. + get_trace and get_proof_trace rely on models to extract rules. + */ + void model_search::update_models() { + obj_map models; + ptr_vector todo; + todo.push_back(m_root); + while (!todo.empty()) { + model_node* n = todo.back(); + if (n->get_model_ptr()) { + models.insert(n->state(), n->get_model_ptr()); + } + todo.pop_back(); + todo.append(n->children().size(), n->children().c_ptr()); + } + + todo.push_back(m_root); + while (!todo.empty()) { + model_node* n = todo.back(); + model* md = 0; + if (!n->get_model_ptr() && models.find(n->state(), md)) { + model_ref mr(md); + n->set_model(mr); + } + todo.pop_back(); + todo.append(n->children().size(), n->children().c_ptr()); + } + } + /** Extract trace comprising of constraints and predicates that are satisfied from facts to the query. The resulting trace */ - expr_ref model_search::get_trace(context const& ctx) const { + expr_ref model_search::get_trace(context const& ctx) { pred_transformer& pt = get_root().pt(); ast_manager& m = pt.get_manager(); manager& pm = pt.get_pdr_manager(); - datalog::context& dctx = ctx.get_context(); datalog::rule_manager& rm = dctx.get_rule_manager(); expr_ref_vector constraints(m), predicates(m); @@ -974,13 +1003,15 @@ namespace pdr { rule = n->get_rule(); unsigned max_var = vc.get_max_rule_var(*rule); predicates.push_back(rule->get_head()); - children.append(n); + children.push_back(n); bool first = true; + update_models(); while (!children.empty()) { SASSERT(children.size() == predicates.size()); expr_ref_vector binding(m); n = children.back(); children.pop_back(); + TRACE("pdr", n->display(tout, 0);); n->mk_instantiate(r0, rule, binding); max_var = std::max(max_var, vc.get_max_rule_var(*rule)); @@ -1026,7 +1057,7 @@ namespace pdr { return pm.mk_and(constraints); } - proof_ref model_search::get_proof_trace(context const& ctx) const { + proof_ref model_search::get_proof_trace(context const& ctx) { pred_transformer& pt = get_root().pt(); ast_manager& m = pt.get_manager(); datalog::context& dctx = ctx.get_context(); @@ -1042,8 +1073,10 @@ namespace pdr { proof* pr = 0; unifier.set_normalize(false); todo.push_back(m_root); + update_models(); while (!todo.empty()) { model_node* n = todo.back(); + TRACE("pdr", n->display(tout, 0);); if (cache.find(n->state(), pr)) { todo.pop_back(); continue; @@ -1066,12 +1099,14 @@ namespace pdr { continue; } proof_ref rl(m); - expr_ref fml0(m); expr_ref_vector binding(m); n->mk_instantiate(r0, r1, binding); - r0->to_formula(fml0); proof_ref p1(m), p2(m); - p1 = m.mk_asserted(fml0); + p1 = r0->get_proof(); + if (!p1) { + r0->display(dctx, std::cout); + } + SASSERT(p1); pfs[0] = p1; rls[0] = r1; TRACE("pdr", diff --git a/src/muz_qe/pdr_context.h b/src/muz_qe/pdr_context.h index 32f13cdd4..6aa02ef10 100644 --- a/src/muz_qe/pdr_context.h +++ b/src/muz_qe/pdr_context.h @@ -240,6 +240,7 @@ namespace pdr { void erase_leaf(model_node& n); void remove_node(model_node& n); void enqueue_leaf(model_node& n); // add leaf to priority queue. + void update_models(); public: model_search(bool bfs): m_bfs(bfs), m_root(0) {} ~model_search(); @@ -253,8 +254,8 @@ namespace pdr { void set_root(model_node* n); model_node& get_root() const { return *m_root; } std::ostream& display(std::ostream& out) const; - expr_ref get_trace(context const& ctx) const; - proof_ref get_proof_trace(context const& ctx) const; + expr_ref get_trace(context const& ctx); + proof_ref get_proof_trace(context const& ctx); void backtrack_level(bool uses_level, model_node& n); }; @@ -299,7 +300,7 @@ namespace pdr { decl2rel m_rels; // Map from relation predicate to fp-operator. func_decl_ref m_query_pred; pred_transformer* m_query; - model_search m_search; + mutable model_search m_search; lbool m_last_result; unsigned m_inductive_lvl; ptr_vector m_core_generalizers; diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index b55f302ed..08f7acfdd 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -85,6 +85,7 @@ lbool dl_interface::query(expr * query) { m_pred2slice.reset(); ast_manager& m = m_ctx.get_manager(); datalog::rule_manager& rule_manager = m_ctx.get_rule_manager(); + datalog::rule_set old_rules(m_ctx.get_rules()); func_decl_ref query_pred(m); datalog::rule_ref_vector query_rules(rule_manager); @@ -105,14 +106,8 @@ lbool dl_interface::query(expr * query) { m_ctx.display_rules(tout); ); - model_converter_ref mc = datalog::mk_skip_model_converter(); - proof_converter_ref pc; - if (m_ctx.get_params().generate_proof_trace()) { - pc = datalog::mk_skip_proof_converter(); - } + m_ctx.set_output_predicate(query_pred); - m_ctx.set_model_converter(mc); - m_ctx.set_proof_converter(pc); m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { @@ -164,8 +159,8 @@ lbool dl_interface::query(expr * query) { datalog::scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode. - m_context->set_proof_converter(pc); - m_context->set_model_converter(mc); + m_context->set_proof_converter(m_ctx.get_proof_converter()); + m_context->set_model_converter(m_ctx.get_model_converter()); m_context->set_query(query_pred); m_context->set_axioms(bg_assertion); m_context->update_rules(m_pdr_rules); diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index 4cdfb186e..1b8ea22f9 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -228,11 +228,13 @@ namespace pdr { is_lower = !is_lower; } + vector bound; + bound.push_back(std::make_pair(x, i)); if (is_lower) { - m_lb.insert(abs(r), std::make_pair(x, i)); + m_lb.insert(abs(r), bound); } else { - m_ub.insert(abs(r), std::make_pair(x, i)); + m_ub.insert(abs(r), bound); } } diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp index 5f018895c..be3f80f92 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/muz_qe/qe_lite.cpp @@ -2492,7 +2492,13 @@ class qe_lite_tactic : public tactic { new_f = f; m_qe(new_f, new_pr); if (produce_proofs) { - new_pr = m.mk_modus_ponens(g->pr(i), new_pr); + expr* fact = m.get_fact(new_pr); + if (to_app(fact)->get_arg(0) != to_app(fact)->get_arg(1)) { + new_pr = m.mk_modus_ponens(g->pr(i), new_pr); + } + else { + new_pr = g->pr(i); + } } g->update(i, new_f, new_pr, g->dep(i)); } diff --git a/src/muz_qe/tab_context.cpp b/src/muz_qe/tab_context.cpp index 681d3d4b2..9ee059f44 100644 --- a/src/muz_qe/tab_context.cpp +++ b/src/muz_qe/tab_context.cpp @@ -1644,9 +1644,7 @@ namespace datalog { void resolve_rule(replace_proof_converter& pc, tb::clause const& r1, tb::clause const& r2, expr_ref_vector const& s1, expr_ref_vector const& s2, tb::clause const& res) const { unsigned idx = r1.get_predicate_index(); - expr_ref fml1 = r1.to_formula(); - expr_ref fml2 = r2.to_formula(); - expr_ref fml3 = res.to_formula(); + expr_ref fml = res.to_formula(); vector substs; svector > positions; substs.push_back(s1); @@ -1654,13 +1652,12 @@ namespace datalog { scoped_proof _sc(m); proof_ref pr(m); proof_ref_vector premises(m); - premises.push_back(m.mk_asserted(fml1)); - premises.push_back(m.mk_asserted(fml2)); + premises.push_back(m.mk_asserted(r1.to_formula())); + premises.push_back(m.mk_asserted(r2.to_formula())); positions.push_back(std::make_pair(idx+1, 0)); - pr = m.mk_hyper_resolve(2, premises.c_ptr(), fml3, positions, substs); + pr = m.mk_hyper_resolve(2, premises.c_ptr(), fml, positions, substs); pc.insert(pr); - } - + } }; tab::tab(context& ctx): diff --git a/src/util/vector.h b/src/util/vector.h index a9d36b202..704452d0f 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -151,23 +151,6 @@ public: } } - vector(T const & e) : - m_data(0) { - push_back(e); - } - - vector(T const & t1, T const & t2) : - m_data(0) { - push_back(t1); - push_back(t2); - } - - vector(T const & t1, T const & t2, T const & t3) : - m_data(0) { - push_back(t1); - push_back(t2); - push_back(t3); - } ~vector() { destroy(); From 7c3ca302f0e50650fe6afdce8013e189a5659539 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Mar 2013 16:56:47 -0700 Subject: [PATCH 026/281] missing hnf Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/quant_hoist.h | 2 +- src/muz_qe/dl_util.cpp | 3 - src/muz_qe/hnf.cpp | 487 ++++++++++++++++++++++++++++++++ src/muz_qe/hnf.h | 49 ++++ src/muz_qe/horn_tactic.cpp | 5 - src/muz_qe/pdr_dl_interface.cpp | 21 -- 6 files changed, 537 insertions(+), 30 deletions(-) create mode 100644 src/muz_qe/hnf.cpp create mode 100644 src/muz_qe/hnf.h diff --git a/src/ast/rewriter/quant_hoist.h b/src/ast/rewriter/quant_hoist.h index df643950a..50cbd1ba4 100644 --- a/src/ast/rewriter/quant_hoist.h +++ b/src/ast/rewriter/quant_hoist.h @@ -66,7 +66,7 @@ public: Return index of maximal variable. */ - unsigned pull_quantifier(bool is_forall, expr_ref& fml, svector* names); + unsigned pull_quantifier(bool is_forall, expr_ref& fml, ptr_vector* sorts, svector* names); }; diff --git a/src/muz_qe/dl_util.cpp b/src/muz_qe/dl_util.cpp index 74c16a6ea..6d93dd84c 100644 --- a/src/muz_qe/dl_util.cpp +++ b/src/muz_qe/dl_util.cpp @@ -431,8 +431,6 @@ namespace datalog { } } -<<<<<<< HEAD -======= void rule_counter::count_rule_vars(ast_manager & m, const rule * r, int coef) { count_vars(m, r->get_head(), 1); @@ -453,7 +451,6 @@ namespace datalog { } return get_max_var(has_var); } ->>>>>>> 26f4d3be202606ff0189aefc103de187caf06d5d void del_rule(horn_subsume_model_converter* mc, rule& r) { if (mc) { diff --git a/src/muz_qe/hnf.cpp b/src/muz_qe/hnf.cpp new file mode 100644 index 000000000..88e28699e --- /dev/null +++ b/src/muz_qe/hnf.cpp @@ -0,0 +1,487 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + hnf.cpp + +Abstract: + + Horn normal form conversion. + +Author: + + Nikolaj Bjorner (nbjorner) 3-20-2013 + +Notes: + + Convert formula + + (forall x f(x)) + + into conjunction + + (f1 xy) (f2 xy) (f3 xy) + + such that + + (forall x f(x)) ~ /\ (forall xy (f_i xy)) + + modulo definitions that are introduced. + + + Convert proof with + asserted (forall xy (f' xy)) + + To: + (forall xy (f' xy)) by mp~ 1, 2 + 1. asserted/def-intro (forall xy (f xy)) + 2. (forall xy (f xy)) ~ (forall xy (f' xy)) by trans, 3, 4 + 3. (forall xy (f xy)) ~ (forall xy (f1 xy)) by pull quantifiers (rewrite) + 4. (forall xy (f1 xy)) ~ (forall xy (f' xy)) by oeq_quant_intro 5 + 5. f1 xy ~ f' xy by sub-proof. + + +--*/ +#include"hnf.h" +#include"warning.h" +#include"used_vars.h" +#include"well_sorted.h" +#include"var_subst.h" +#include"name_exprs.h" +#include"act_cache.h" +#include"cooperate.h" +#include"ast_pp.h" +#include"quant_hoist.h" +#include"dl_util.h" +#include"for_each_ast.h" +#include"for_each_expr.h" + +class hnf::imp { + ast_manager& m; + bool m_produce_proofs; + volatile bool m_cancel; + expr_ref_vector m_todo; + proof_ref_vector m_proofs; + expr_ref_vector m_refs; + symbol m_name; + svector m_names; + ptr_vector m_sorts; + quantifier_hoister m_qh; + obj_map m_memoize_disj; + obj_map m_memoize_proof; + func_decl_ref_vector m_fresh_predicates; + +public: + imp(ast_manager & m): + m(m), + m_produce_proofs(false), + m_cancel(false), + m_todo(m), + m_proofs(m), + m_refs(m), + m_qh(m), + m_name("P"), + m_fresh_predicates(m) { + } + + void operator()(expr * n, + proof* p, + expr_ref_vector& result, + proof_ref_vector& ps) { + expr_ref fml(m); + proof_ref pr(m); + m_todo.reset(); + m_proofs.reset(); + m_refs.reset(); + m_memoize_disj.reset(); + m_memoize_proof.reset(); + m_fresh_predicates.reset(); + m_todo.push_back(n); + m_proofs.push_back(p); + m_produce_proofs = p != 0; + while (!m_todo.empty() && !m_cancel) { + fml = m_todo.back(); + pr = m_proofs.back(); + m_todo.pop_back(); + m_proofs.pop_back(); + mk_horn(fml, pr); + if (fml) { + result.push_back(fml); + ps.push_back(pr); + } + } + TRACE("hnf", + tout << mk_pp(n, m) << "\n==>\n"; + for (unsigned i = 0; i < result.size(); ++i) { + tout << mk_pp(result[i].get(), m) << "\n"; + }); + } + + void set_cancel(bool f) { + m_cancel = f; + } + + void set_name(symbol const& n) { + m_name = n; + } + + func_decl_ref_vector const& get_fresh_predicates() { + return m_fresh_predicates; + } + + void reset() { + m_cancel = false; + m_todo.reset(); + m_proofs.reset(); + m_refs.reset(); + m_memoize_disj.reset(); + m_memoize_proof.reset(); + m_fresh_predicates.reset(); + } + + ast_manager& get_manager() { return m; } + +private: + + bool produce_proofs() const { + return m_produce_proofs; + } + + bool is_predicate(expr* p) const { + return is_app(p) && is_predicate(to_app(p)->get_decl()); + } + + bool is_predicate(func_decl* f) const { + return m.is_bool(f->get_range()) && f->get_family_id() == null_family_id; + } + + class contains_predicate_proc { + imp const& m; + public: + struct found {}; + contains_predicate_proc(imp const& m): m(m) {} + void operator()(var * n) {} + void operator()(quantifier * n) {} + void operator()(app* n) { + if (m.is_predicate(n)) throw found(); + } + }; + + bool contains_predicate(expr* fml) const { + contains_predicate_proc proc(*this); + try { + quick_for_each_expr(proc, fml); + } + catch (contains_predicate_proc::found) { + return true; + } + return false; + } + + + void mk_horn(expr_ref& fml, proof_ref& premise) { + expr* e1, *e2; + expr_ref_vector body(m); + proof_ref_vector defs(m); + expr_ref fml0(m), fml1(m), fml2(m), head(m); + proof_ref p(m); + fml0 = fml; + m_names.reset(); + m_sorts.reset(); + m_qh.pull_quantifier(true, fml0, &m_sorts, &m_names); + if (premise){ + fml1 = bind_variables(fml0); + if (!m_sorts.empty()) { + proof* p1 = m.mk_pull_quant(fml, to_quantifier(fml1)); + premise = mk_modus_ponens(premise, p1); + } + } + head = fml0; + while (m.is_implies(head, e1, e2)) { + body.push_back(e1); + head = e2; + } + datalog::flatten_and(body); + if (premise) { + p = m.mk_rewrite(fml0, mk_implies(body, head)); + } + + // + // Case: + // A \/ B -> C + // => + // A -> C + // B -> C + // + if (body.size() == 1 && m.is_or(body[0].get()) && contains_predicate(body[0].get())) { + app* _or = to_app(body[0].get()); + unsigned sz = _or->get_num_args(); + expr* const* args = _or->get_args(); + for (unsigned i = 0; i < sz; ++i) { + m_todo.push_back(bind_variables(m.mk_implies(args[i], head))); + m_proofs.push_back(0); + } + + if (premise) { + expr_ref f1 = bind_variables(mk_implies(body, head)); + expr* f2 = m.mk_and(sz, m_todo.c_ptr()+m_todo.size()-sz); + proof_ref p2(m), p3(m); + p2 = m.mk_def_axiom(m.mk_iff(f1, f2)); + p3 = mk_quant_intro(fml, f1, p); + p2 = mk_transitivity(p3, p2); + p2 = mk_modus_ponens(premise, p2); + for (unsigned i = 0; i < sz; ++i) { + m_proofs[m_proofs.size()-sz+i] = m.mk_and_elim(p2, i); + } + } + fml = 0; + return; + } + + + eliminate_disjunctions(body, defs); + p = mk_congruence(p, body, head, defs); + + eliminate_quantifier_body(body, defs); + p = mk_congruence(p, body, head, defs); + + fml2 = mk_implies(body, head); + + fml = bind_variables(fml2); + + if (premise) { + SASSERT(p); + p = mk_quant_intro(fml1, fml, p); + premise = mk_modus_ponens(premise, p); + } + } + + proof* mk_quant_intro(expr* e1, expr* e2, proof* p) { + if (m_sorts.empty()) { + return p; + } + quantifier* q1 = to_quantifier(e1); + quantifier* q2 = to_quantifier(e2); + if (m.is_iff(m.get_fact(p))) { + return m.mk_quant_intro(q1, q2, p); + } + if (m.is_oeq(m.get_fact(p))) { + return m.mk_oeq_quant_intro(q1, q2, p); + } + UNREACHABLE(); + return p; + } + + + void eliminate_disjunctions(expr_ref_vector::element_ref& body, proof_ref_vector& proofs) { + expr* b = body.get(); + expr* e1; + bool negate_args = false; + bool is_disj = false; + unsigned num_disj = 0; + expr* const* disjs = 0; + if (!contains_predicate(b)) { + return; + } + TRACE("hnf", tout << mk_pp(b, m) << "\n";); + if (m.is_or(b)) { + is_disj = true; + negate_args = false; + num_disj = to_app(b)->get_num_args(); + disjs = to_app(b)->get_args(); + } + if (m.is_not(b, e1) && m.is_and(e1)) { + is_disj = true; + negate_args = true; + num_disj = to_app(e1)->get_num_args(); + disjs = to_app(e1)->get_args(); + } + if (is_disj) { + app* old_head = 0; + if (m_memoize_disj.find(b, old_head)) { + body = old_head; + } + else { + app_ref head = mk_fresh_head(b); + proof_ref_vector defs(m); + for (unsigned i = 0; i < num_disj; ++i) { + expr* e = disjs[i]; + if (negate_args) { + e = m.mk_not(e); + } + m_todo.push_back(bind_variables(m.mk_implies(e, head))); + m_proofs.push_back(0); + if (produce_proofs()) { + defs.push_back(m.mk_def_intro(m_todo.back())); + m_proofs[m_proofs.size()-1] = defs.back(); + } + } + if (produce_proofs()) { + proof* p = m.mk_apply_defs(body.get(), head, defs.size(), defs.c_ptr()); + m_refs.push_back(p); + m_memoize_proof.insert(b, p); + } + m_memoize_disj.insert(b, head); + m_refs.push_back(b); + m_refs.push_back(head); + // update the body to be the newly introduced head relation + body = head; + } + + if (produce_proofs()) { + proofs.push_back(m_memoize_proof.find(b)); + } + } + } + + app_ref mk_fresh_head(expr* e) { + ptr_vector sorts0, sorts1; + get_free_vars(e, sorts0); + expr_ref_vector args(m); + for (unsigned i = 0; i < sorts0.size(); ++i) { + if (sorts0[i]) { + args.push_back(m.mk_var(i, sorts0[i])); + sorts1.push_back(sorts0[i]); + } + } + func_decl_ref f(m); + f = m.mk_fresh_func_decl(m_name.str().c_str(), "", sorts1.size(), sorts1.c_ptr(), m.mk_bool_sort()); + m_fresh_predicates.push_back(f); + return app_ref(m.mk_app(f, args.size(), args.c_ptr()), m); + } + + void eliminate_disjunctions(expr_ref_vector& body, proof_ref_vector& proofs) { + for (unsigned i = 0; i < body.size(); ++i) { + eliminate_disjunctions(body[i], proofs); + } + } + + void eliminate_quantifier_body(expr_ref_vector::element_ref& body, proof_ref_vector& proofs) { + if (is_forall(body.get()) && contains_predicate(body.get())) { + quantifier* q = to_quantifier(body.get()); + expr* e = q->get_expr(); + if (!is_predicate(e)) { + app_ref head = mk_fresh_head(e); + m_todo.push_back(bind_variables(m.mk_implies(e, head))); + m_proofs.push_back(0); + body = m.update_quantifier(q, head); + if (produce_proofs()) { + proof* def_intro = m.mk_def_intro(m_todo.back()); + proof* def_proof = m.mk_apply_def(e, head, def_intro); + proofs.push_back(m.mk_nnf_neg(q, body.get(), 1, &def_proof)); + m_proofs[m_proofs.size()-1] = def_intro; + } + } + } + } + + void eliminate_quantifier_body(expr_ref_vector& body, proof_ref_vector& proofs) { + for (unsigned i = 0; i < body.size(); ++i) { + eliminate_quantifier_body(body[i], proofs); + } + } + + app_ref mk_implies(expr_ref_vector const& body, expr* head) { + switch (body.size()) { + case 0: + return app_ref(to_app(head), m); + case 1: + return app_ref(m.mk_implies(body[0], head), m); + default: + return app_ref(m.mk_implies(m.mk_and(body.size(), body.c_ptr()), head), m); + } + } + + + proof_ref mk_congruence(proof* p1, expr_ref_vector const& body, expr* head, proof_ref_vector& defs) { + if (defs.empty()) { + return proof_ref(p1, m); + } + else { + SASSERT(p1); + proof_ref p2(m), p3(m); + app_ref fml = mk_implies(body, head); + expr* fact = m.get_fact(p1); + if (m.is_iff(fact)) { + p1 = m.mk_iff_oeq(p1); + fact = m.get_fact(p1); + } + VERIFY (m.is_oeq(fact) || m.is_eq(fact)); + app* e2 = to_app(to_app(fact)->get_arg(1)); + p2 = m.mk_oeq_congruence(e2, fml, defs.size(), defs.c_ptr()); + p3 = mk_transitivity(p1, p2); + defs.reset(); + return proof_ref(p3, m); + } + } + + proof_ref mk_modus_ponens(proof* premise, proof* eq) { + proof_ref result(m); + result = m.mk_modus_ponens(premise, eq); + if (m.get_fact(premise) == m.get_fact(result)) { + result = premise; + } + return result; + } + + proof* mk_transitivity(proof* p1, proof* p2) { + if (p1) { + app* f = to_app(m.get_fact(p1)); + if (f->get_arg(0) == f->get_arg(1)) { + return p2; + } + } + if (p2) { + app* f = to_app(m.get_fact(p2)); + if (f->get_arg(0) == f->get_arg(1)) { + return p1; + } + } + return m.mk_transitivity(p1, p2); + } + + expr_ref bind_variables(expr* e) { + SASSERT(m_sorts.size() == m_names.size()); + if (m_sorts.empty()) { + return expr_ref(e, m); + } + return expr_ref(m.mk_forall(m_sorts.size(), m_sorts.c_ptr(), m_names.c_ptr(), e), m); + } + +}; + +hnf::hnf(ast_manager & m) { + m_imp = alloc(imp, m); +} + +hnf::~hnf() { + dealloc(m_imp); +} + +void hnf::operator()(expr * n, proof* p, expr_ref_vector & rs, proof_ref_vector& ps) { + m_imp->operator()(n, p, rs, ps); + TRACE("hnf", + ast_manager& m = rs.get_manager(); + tout << mk_ismt2_pp(n, m) << "\nHNF result:\n"; + for (unsigned i = 0; i < rs.size(); ++i) { + tout << mk_pp(rs[i].get(), m) << "\n"; + } + ); +} + +void hnf::set_cancel(bool f) { + m_imp->set_cancel(f); +} + +void hnf::set_name(symbol const& n) { + m_imp->set_name(n); +} + +void hnf::reset() { + m_imp->reset(); +} + +func_decl_ref_vector const& hnf::get_fresh_predicates() { + return m_imp->get_fresh_predicates(); +} diff --git a/src/muz_qe/hnf.h b/src/muz_qe/hnf.h new file mode 100644 index 000000000..37339540b --- /dev/null +++ b/src/muz_qe/hnf.h @@ -0,0 +1,49 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + hnf.h + +Abstract: + + Horn normal form convertion. +Author: + + +Notes: + + Very similar to NNF. + +--*/ + +#ifndef _HNF_H_ +#define _HNF_H_ + +#include"ast.h" +#include"params.h" +#include"defined_names.h" +#include"proof_converter.h" + +class hnf { + class imp; + imp * m_imp; +public: + hnf(ast_manager & m); + ~hnf(); + + void operator()(expr * n, // [IN] expression that should be put into Horn NF + proof* p, // [IN] proof of n + expr_ref_vector & rs, // [OUT] resultant (conjunction) of expressions + proof_ref_vector& ps // [OUT] proofs of rs + ); + + void cancel() { set_cancel(true); } + void reset_cancel() { set_cancel(false); } + void set_cancel(bool f); + void set_name(symbol const& name); + void reset(); + func_decl_ref_vector const& get_fresh_predicates(); +}; + +#endif /* _HNF_H_ */ diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 98c21288e..02c41c091 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -275,11 +275,6 @@ class horn_tactic : public tactic { func_decl* query_pred = to_app(q)->get_decl(); m_ctx.set_output_predicate(query_pred); m_ctx.get_rules(); // flush adding rules. -<<<<<<< HEAD - m_ctx.set_model_converter(mc); - m_ctx.set_proof_converter(pc); -======= ->>>>>>> 26f4d3be202606ff0189aefc103de187caf06d5d m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index 033057683..e2232dafe 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -90,13 +90,6 @@ lbool dl_interface::query(expr * query) { func_decl_ref query_pred(m); datalog::rule_ref_vector query_rules(rule_manager); datalog::rule_ref query_rule(rule_manager); - model_converter_ref mc = datalog::mk_skip_model_converter(); - proof_converter_ref pc; - if (m_ctx.get_params().generate_proof_trace()) { - pc = datalog::mk_skip_proof_converter(); - } - m_ctx.set_model_converter(mc); - m_ctx.set_proof_converter(pc); rule_manager.mk_query(query, query_pred, query_rules, query_rule); m_ctx.add_rules(query_rules); expr_ref bg_assertion = m_ctx.get_background_assertion(); @@ -113,13 +106,8 @@ lbool dl_interface::query(expr * query) { m_ctx.display_rules(tout); ); -<<<<<<< HEAD - m_ctx.set_output_predicate(query_pred); - -======= m_ctx.set_output_predicate(query_pred); ->>>>>>> 26f4d3be202606ff0189aefc103de187caf06d5d m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { @@ -147,19 +135,10 @@ lbool dl_interface::query(expr * query) { transf1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); transf2.register_plugin(alloc(datalog::mk_unfold, m_ctx)); if (m_ctx.get_params().coalesce_rules()) { -<<<<<<< HEAD m_ctx.transform_rules(transf1); -======= - transformer1.register_plugin(alloc(datalog::mk_coalesce, m_ctx)); - m_ctx.transform_rules(transformer1); ->>>>>>> 26f4d3be202606ff0189aefc103de187caf06d5d } while (num_unfolds > 0) { -<<<<<<< HEAD m_ctx.transform_rules(transf2); -======= - m_ctx.transform_rules(transformer2); ->>>>>>> 26f4d3be202606ff0189aefc103de187caf06d5d --num_unfolds; } } From 2633dc56abc23dc078b58694eb725fbe38954450 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Sun, 24 Mar 2013 08:59:43 -0700 Subject: [PATCH 027/281] Fix non ASCII character Signed-off-by: Leonardo de Moura --- scripts/mk_util.py | 1 + src/muz_qe/dl_mk_karr_invariants.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 06120e2c4..257b1b295 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -520,6 +520,7 @@ def parse_options(): # Return a list containing a file names included using '#include' in # the given C/C++ file named fname. def extract_c_includes(fname): + print(fname) result = [] # We look for well behaved #include directives std_inc_pat = re.compile("[ \t]*#include[ \t]*\"(.*)\"[ \t]*") diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 18b152589..d44b31979 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -11,7 +11,7 @@ Abstract: The linear invariants are extracted according to Karr's method. A short description is in - Nikolaj Bjørner, Anca Browne and Zohar Manna. Automatic Generation + Nikolaj Bjorner, Anca Browne and Zohar Manna. Automatic Generation of Invariants and Intermediate Assertions, in CP 95. The algorithm is here adapted to Horn clauses. From 5aa84c28a6dc9778e12e7b9d05fc8d5b2e309ed9 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Sun, 24 Mar 2013 09:00:19 -0700 Subject: [PATCH 028/281] Remove trace msg Signed-off-by: Leonardo de Moura --- scripts/mk_util.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 257b1b295..06120e2c4 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -520,7 +520,6 @@ def parse_options(): # Return a list containing a file names included using '#include' in # the given C/C++ file named fname. def extract_c_includes(fname): - print(fname) result = [] # We look for well behaved #include directives std_inc_pat = re.compile("[ \t]*#include[ \t]*\"(.*)\"[ \t]*") From 9d0b0df9859918f96d0c413db68200538064f41f Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Sun, 24 Mar 2013 09:07:51 -0700 Subject: [PATCH 029/281] Fix gcc compilation errors Signed-off-by: Leonardo de Moura --- src/muz_qe/hnf.cpp | 6 ++++-- src/util/bit_vector.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/muz_qe/hnf.cpp b/src/muz_qe/hnf.cpp index 88e28699e..47370e0e6 100644 --- a/src/muz_qe/hnf.cpp +++ b/src/muz_qe/hnf.cpp @@ -353,7 +353,8 @@ private: void eliminate_disjunctions(expr_ref_vector& body, proof_ref_vector& proofs) { for (unsigned i = 0; i < body.size(); ++i) { - eliminate_disjunctions(body[i], proofs); + expr_ref_vector::element_ref r = body[i]; + eliminate_disjunctions(r, proofs); } } @@ -378,7 +379,8 @@ private: void eliminate_quantifier_body(expr_ref_vector& body, proof_ref_vector& proofs) { for (unsigned i = 0; i < body.size(); ++i) { - eliminate_quantifier_body(body[i], proofs); + expr_ref_vector::element_ref r = body[i]; + eliminate_quantifier_body(r, proofs); } } diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index 2328a5849..e3a2bc331 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -16,7 +16,7 @@ Author: Revision History: --*/ - +#include #include"bit_vector.h" #include"trace.h" From 6084cbd065292449ff97b931e42a3fb64fd93029 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2013 11:25:43 -0700 Subject: [PATCH 030/281] fix build breaks Signed-off-by: Nikolaj Bjorner --- src/test/karr.cpp | 2 +- src/util/bit_vector.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/karr.cpp b/src/test/karr.cpp index f6e572670..3ac427a88 100644 --- a/src/test/karr.cpp +++ b/src/test/karr.cpp @@ -43,7 +43,7 @@ namespace karr { hilbert_basis hb; for (unsigned i = 0; i < src.size(); ++i) { vector v(src.A[i]); - v.append(src.b[i]); + v.push_back(src.b[i]); hb.add_eq(v, rational(0)); } for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) { diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index 2328a5849..3b470a3ce 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include"bit_vector.h" +#include"util.h" #include"trace.h" #define DEFAULT_CAPACITY 2 From e61fa50dc320bd6f335a572817873c149aec6192 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2013 11:26:46 -0700 Subject: [PATCH 031/281] fix build breaks Signed-off-by: Nikolaj Bjorner --- src/util/bit_vector.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index a24774279..e3a2bc331 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -18,7 +18,6 @@ Revision History: --*/ #include #include"bit_vector.h" -#include"util.h" #include"trace.h" #define DEFAULT_CAPACITY 2 From a71bb549c616b4546c8793e71fed9148984d6c5e Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Sun, 24 Mar 2013 14:59:29 -0700 Subject: [PATCH 032/281] Add option :bv-sort-ac true Signed-off-by: Leonardo de Moura --- src/ast/ast_lt.cpp | 10 ++++++++++ src/ast/ast_lt.h | 1 + src/ast/rewriter/bv_rewriter.cpp | 10 ++++++++-- src/ast/rewriter/bv_rewriter.h | 1 + src/ast/rewriter/bv_rewriter_params.pyg | 3 ++- 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/ast/ast_lt.cpp b/src/ast/ast_lt.cpp index 1bf153f4f..2fba4f7a6 100644 --- a/src/ast/ast_lt.cpp +++ b/src/ast/ast_lt.cpp @@ -134,6 +134,16 @@ bool lt(ast * n1, ast * n2) { } } +bool is_sorted(unsigned num, expr * const * ns) { + for (unsigned i = 1; i < num; i++) { + ast * prev = ns[i-1]; + ast * curr = ns[i]; + if (lt(curr, prev)) + return false; + } + return true; +} + bool lex_lt(unsigned num, ast * const * n1, ast * const * n2) { for (unsigned i = 0; i < num; i ++) { if (n1[i] == n2[i]) diff --git a/src/ast/ast_lt.h b/src/ast/ast_lt.h index 5eb268997..b405ab229 100644 --- a/src/ast/ast_lt.h +++ b/src/ast/ast_lt.h @@ -22,6 +22,7 @@ Revision History: class ast; bool lt(ast * n1, ast * n2); +bool is_sorted(unsigned num, expr * const * ns); struct ast_to_lt { bool operator()(ast * n1, ast * n2) const { return lt(n1, n2); } diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 44efe0199..11b09003b 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -64,6 +64,7 @@ void bv_rewriter::updt_local_params(params_ref const & _p) { m_split_concat_eq = p.split_concat_eq(); m_udiv2mul = p.udiv2mul(); m_bvnot2arith = p.bvnot2arith(); + m_bv_sort_ac = p.bv_sort_ac(); m_mkbv2num = _p.get_bool("mkbv2num", false); } @@ -1315,7 +1316,7 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re return BR_REWRITE2; } - if (!flattened && !merged && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero()))) { + if (!flattened && !merged && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero())) && (!m_bv_sort_ac || is_sorted(num, args))) { return BR_FAILED; } @@ -1331,6 +1332,8 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re result = new_args[0]; return BR_DONE; default: + if (m_bv_sort_ac) + std::sort(new_args.begin(), new_args.end(), ast_to_lt()); result = m_util.mk_bv_or(new_args.size(), new_args.c_ptr()); return BR_DONE; } @@ -1456,7 +1459,8 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r return BR_REWRITE3; } - if (!merged && !flattened && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero() && v1 != (rational::power_of_two(sz) - numeral(1))))) + if (!merged && !flattened && (num_coeffs == 0 || (num_coeffs == 1 && !v1.is_zero() && v1 != (rational::power_of_two(sz) - numeral(1)))) && + (!m_bv_sort_ac || is_sorted(num, args))) return BR_FAILED; ptr_buffer new_args; @@ -1497,6 +1501,8 @@ br_status bv_rewriter::mk_bv_xor(unsigned num, expr * const * args, expr_ref & r } __fallthrough; default: + if (m_bv_sort_ac) + std::sort(new_args.begin(), new_args.end(), ast_to_lt()); result = m_util.mk_bv_xor(new_args.size(), new_args.c_ptr()); return BR_DONE; } diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index a94fd18c1..6d8c21666 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -68,6 +68,7 @@ class bv_rewriter : public poly_rewriter { bool m_split_concat_eq; bool m_udiv2mul; bool m_bvnot2arith; + bool m_bv_sort_ac; bool is_zero_bit(expr * x, unsigned idx); diff --git a/src/ast/rewriter/bv_rewriter_params.pyg b/src/ast/rewriter/bv_rewriter_params.pyg index d9ee9f7a3..5feece753 100644 --- a/src/ast/rewriter/bv_rewriter_params.pyg +++ b/src/ast/rewriter/bv_rewriter_params.pyg @@ -8,5 +8,6 @@ def_module_params(module_name='rewriter', ("elim_sign_ext", BOOL, True, "expand sign-ext operator using concat and extract"), ("hi_div0", BOOL, True, "use the 'hardware interpretation' for division by zero (for bit-vector terms)"), ("mul2concat", BOOL, False, "replace multiplication by a power of two into a concatenation"), - ("bvnot2arith", BOOL, False, "replace (bvnot x) with (bvsub -1 x)") + ("bvnot2arith", BOOL, False, "replace (bvnot x) with (bvsub -1 x)"), + ("bv_sort_ac", BOOL, False, "sort the arguments of all AC operators") )) From bbe93ef61096578a11ee531e9a18b4a247b50089 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 24 Mar 2013 18:26:22 -0700 Subject: [PATCH 033/281] fix build warning, make context simplifier traverse subterms Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/float_rewriter.cpp | 1 - src/muz_qe/hnf.cpp | 2 +- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 70 +++++++++++++------ 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 10311598b..70ba09581 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -226,7 +226,6 @@ br_status float_rewriter::mk_abs(expr * arg1, expr_ref & result) { result = arg1; return BR_DONE; } - sort * s = m().get_sort(arg1); result = m().mk_ite(m_util.mk_is_sign_minus(arg1), m_util.mk_uminus(arg1), arg1); diff --git a/src/muz_qe/hnf.cpp b/src/muz_qe/hnf.cpp index 47370e0e6..5a7d1c4ba 100644 --- a/src/muz_qe/hnf.cpp +++ b/src/muz_qe/hnf.cpp @@ -80,8 +80,8 @@ public: m_todo(m), m_proofs(m), m_refs(m), - m_qh(m), m_name("P"), + m_qh(m), m_fresh_predicates(m) { } diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index 0092cdd38..5668ca455 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -33,10 +33,14 @@ class ctx_solver_simplify_tactic : public tactic { arith_util m_arith; mk_simplified_app m_mk_app; func_decl_ref m_fn; + obj_map m_fns; unsigned m_num_steps; + volatile bool m_cancel; public: ctx_solver_simplify_tactic(ast_manager & m, params_ref const & p = params_ref()): - m(m), m_params(p), m_solver(m, m_front_p), m_arith(m), m_mk_app(m), m_fn(m), m_num_steps(0) { + m(m), m_params(p), m_solver(m, m_front_p), + m_arith(m), m_mk_app(m), m_fn(m), m_num_steps(0), + m_cancel(false) { sort* i_sort = m_arith.mk_int(); m_fn = m.mk_func_decl(symbol(0xbeef101), i_sort, m.mk_bool_sort()); } @@ -45,7 +49,13 @@ public: return alloc(ctx_solver_simplify_tactic, m, m_params); } - virtual ~ctx_solver_simplify_tactic() {} + virtual ~ctx_solver_simplify_tactic() { + obj_map::iterator it = m_fns.begin(), end = m_fns.end(); + for (; it != end; ++it) { + m.dec_ref(it->m_value); + } + m_fns.reset(); + } virtual void updt_params(params_ref const & p) { m_solver.updt_params(p); @@ -76,15 +86,18 @@ public: virtual void cleanup() { reset_statistics(); m_solver.reset(); + m_cancel = false; } + protected: + virtual void set_cancel(bool f) { m_solver.set_cancel(f); + m_cancel = false; } void reduce(goal& g) { SASSERT(g.is_well_sorted()); - m_num_steps = 0; expr_ref fml(m); tactic_report report("ctx-solver-simplify", g); if (g.inconsistent()) @@ -134,15 +147,16 @@ protected: svector parent_ids, self_ids; expr_ref_vector fresh_vars(m), trail(m); expr_ref res(m), tmp(m); - obj_map > cache; + obj_map > cache; unsigned id = 1; - expr* n2, *fml; + expr_ref n2(m), fml(m); unsigned path_id = 0, self_pos = 0; app * a; unsigned sz; std::pair path_r; ptr_vector found; - expr* n = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + expr_ref_vector args(m); + expr_ref n = mk_fresh(id, m.mk_bool_sort()); trail.push_back(n); fml = result.get(); @@ -156,9 +170,9 @@ protected: self_ids.push_back(0); m_solver.push(); - while (!todo.empty()) { + while (!todo.empty() && !m_cancel) { expr_ref res(m); - ptr_buffer args; + args.reset(); expr* e = todo.back(); unsigned pos = parent_ids.back(); n = names.back(); @@ -167,10 +181,6 @@ protected: if (cache.contains(e)) { goto done; } - if (!m.is_bool(e)) { - res = e; - goto done; - } if (m.is_bool(e) && !checked && simplify_bool(n, res)) { TRACE("ctx_solver_simplify_tactic", tout << "simplified: " << mk_pp(e, m) << " |-> " << mk_pp(res, m) << "\n";); goto done; @@ -193,14 +203,11 @@ protected: found.reset(); // arguments already simplified. for (unsigned i = 0; i < sz; ++i) { expr* arg = a->get_arg(i); - if (!m.is_bool(arg)) { - args.push_back(arg); - } - else if (cache.find(arg, path_r) && !found.contains(arg)) { + if (cache.find(arg, path_r) && !found.contains(arg)) { // // This is a single traversal version of the context // simplifier. It simplifies only the first occurrence of - // a formula with respect to the context. + // a sub-term with respect to the context. // found.push_back(arg); @@ -208,15 +215,18 @@ protected: TRACE("ctx_solver_simplify_tactic", tout << "cached " << mk_pp(arg, m) << " |-> " << mk_pp(path_r.second, m) << "\n";); args.push_back(path_r.second); } - else { + else if (m.is_bool(arg)) { res = local_simplify(a, n, id, i); TRACE("ctx_solver_simplify_tactic", tout << "Already cached: " << path_r.first << " " << mk_pp(res, m) << "\n";); + args.push_back(res); + } + else { args.push_back(arg); } } else if (!n2 && !found.contains(arg)) { - n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + n2 = mk_fresh(id, m.get_sort(arg)); trail.push_back(n2); todo.push_back(arg); parent_ids.push_back(self_pos); @@ -254,8 +264,10 @@ protected: is_checked.pop_back(); m_solver.pop(1); } - VERIFY(cache.find(fml, path_r)); - result = path_r.second; + if (!m_cancel) { + VERIFY(cache.find(fml, path_r)); + result = path_r.second; + } } bool simplify_bool(expr* n, expr_ref& res) { @@ -282,11 +294,25 @@ protected: return false; } + expr_ref mk_fresh(unsigned& id, sort* s) { + func_decl* fn; + if (m.is_bool(s)) { + fn = m_fn; + } + else if (!m_fns.find(s, fn)) { + fn = m.mk_func_decl(symbol(0xbeef101 + id), m_arith.mk_int(), s); + m.inc_ref(fn); + m_fns.insert(s, fn); + } + return expr_ref(m.mk_app(fn, m_arith.mk_numeral(rational(id++), true)), m); + } + + expr_ref local_simplify(app* a, expr* n, unsigned& id, unsigned index) { SASSERT(index < a->get_num_args()); SASSERT(m.is_bool(a->get_arg(index))); expr_ref n2(m), result(m), tmp(m); - n2 = m.mk_app(m_fn, m_arith.mk_numeral(rational(id++), true)); + n2 = mk_fresh(id, m.get_sort(a->get_arg(index))); ptr_buffer args; for (unsigned i = 0; i < a->get_num_args(); ++i) { if (i == index) { From b427958b9eef053488a57f67cc0125c5f0141e55 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 25 Mar 2013 09:53:11 -0700 Subject: [PATCH 034/281] qe_lite> fix crash in is_var_eq() (by me & Nikolaj) Signed-off-by: Nuno Lopes --- src/muz_qe/qe_lite.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp index be3f80f92..ff49584ff 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/muz_qe/qe_lite.cpp @@ -201,9 +201,15 @@ namespace eq { return (*m_is_variable)(e); } - bool is_neg_var(ast_manager & m, expr * e) { + bool is_neg_var(ast_manager & m, expr * e, var*& v) { expr* e1; - return m.is_not(e, e1) && is_variable(e1); + if (m.is_not(e, e1) && is_variable(e1)) { + v = to_var(e1); + return true; + } + else { + return false; + } } @@ -328,18 +334,19 @@ namespace eq { bool is_var_eq(expr * e, ptr_vector& vs, expr_ref_vector & ts) { expr* lhs, *rhs; + var* v; // (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases if (m.is_eq(e, lhs, rhs) || m.is_iff(e, lhs, rhs)) { // (iff (not VAR) t) (iff t (not VAR)) cases if (!is_variable(lhs) && !is_variable(rhs) && m.is_bool(lhs)) { - if (!is_neg_var(m, lhs)) { + if (!is_neg_var(m, lhs, v)) { std::swap(lhs, rhs); } - if (!is_neg_var(m, lhs)) { + if (!is_neg_var(m, lhs, v)) { return false; } - vs.push_back(to_var(lhs)); + vs.push_back(v); ts.push_back(m.mk_not(rhs)); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; @@ -378,9 +385,9 @@ namespace eq { } // VAR = false case - if (is_neg_var(m, e)) { + if (is_neg_var(m, e, v)) { ts.push_back(m.mk_false()); - vs.push_back(to_var(to_app(e)->get_arg(0))); + vs.push_back(v); TRACE("qe_lite", tout << mk_pp(e, m) << "\n";); return true; } From df35da1acfece2af81c7bcbab774a86b835f80b2 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 25 Mar 2013 10:48:48 -0700 Subject: [PATCH 035/281] rule_manager::mk(): default initialization of m_proof to null Signed-off-by: Nuno Lopes --- src/muz_qe/dl_rule.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index a13229e7a..14a316e48 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -502,6 +502,7 @@ namespace datalog { r->m_tail_size = n; r->m_positive_cnt = source->m_positive_cnt; r->m_uninterp_cnt = source->m_uninterp_cnt; + r->m_proof = 0; m.inc_ref(r->m_head); for (unsigned i = 0; i < n; i++) { r->m_tail[i] = source->m_tail[i]; From 9abcde9a358f883befbcad910e880263182e5577 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 25 Mar 2013 14:42:18 -0700 Subject: [PATCH 036/281] Fix typos Signed-off-by: Leonardo de Moura --- src/smt/asserted_formulas.cpp | 2 +- src/tactic/bv/max_bv_sharing_tactic.cpp | 2 +- src/tactic/core/propagate_values_tactic.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 3155d9c58..c5d3c08cf 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -653,7 +653,7 @@ void asserted_formulas::propagate_values() { // will be (silently) eliminated, and models produced by Z3 will not contain them. flush_cache(); } - TRACE("propagate_values", tout << "afer:\n"; display(tout);); + TRACE("propagate_values", tout << "after:\n"; display(tout);); } void asserted_formulas::propagate_booleans() { diff --git a/src/tactic/bv/max_bv_sharing_tactic.cpp b/src/tactic/bv/max_bv_sharing_tactic.cpp index 251e2b754..f60487d60 100644 --- a/src/tactic/bv/max_bv_sharing_tactic.cpp +++ b/src/tactic/bv/max_bv_sharing_tactic.cpp @@ -269,7 +269,7 @@ class max_bv_sharing_tactic : public tactic { m_rw.cfg().cleanup(); g->inc_depth(); result.push_back(g.get()); - TRACE("qe", g->display(tout);); + TRACE("max_bv_sharing", g->display(tout);); SASSERT(g->is_well_sorted()); } }; diff --git a/src/tactic/core/propagate_values_tactic.cpp b/src/tactic/core/propagate_values_tactic.cpp index 6d9e6ccbd..1e358177f 100644 --- a/src/tactic/core/propagate_values_tactic.cpp +++ b/src/tactic/core/propagate_values_tactic.cpp @@ -165,7 +165,7 @@ class propagate_values_tactic : public tactic { m_occs(*m_goal); while (true) { - TRACE("propagate_values", m_goal->display(tout);); + TRACE("propagate_values", tout << "while(true) loop\n"; m_goal->display(tout);); if (forward) { for (; m_idx < size; m_idx++) { process_current(); @@ -201,14 +201,14 @@ class propagate_values_tactic : public tactic { if (round >= m_max_rounds) break; IF_VERBOSE(100, verbose_stream() << "starting new round, goal size: " << m_goal->num_exprs() << std::endl;); - TRACE("propgate_values", tout << "round finished\n"; m_goal->display(tout); tout << "\n";); + TRACE("propagate_values", tout << "round finished\n"; m_goal->display(tout); tout << "\n";); } end: m_goal->elim_redundancies(); m_goal->inc_depth(); result.push_back(m_goal); SASSERT(m_goal->is_well_sorted()); - TRACE("propagate_values", m_goal->display(tout);); + TRACE("propagate_values", tout << "end\n"; m_goal->display(tout);); TRACE("propagate_values_core", m_goal->display_with_dependencies(tout);); m_goal = 0; } From da83a6b28c01bbe9b2dfb25d734d2b2fa6c906d9 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 25 Mar 2013 14:48:22 -0700 Subject: [PATCH 037/281] dl_bit_blasting: run simplifier before bit-blasting, in order to comply with its precondition Signed-off-by: Nuno Lopes --- src/muz_qe/dl_mk_bit_blast.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 1e984f254..e6612022f 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -23,6 +23,7 @@ Revision History: #include "ast_pp.h" #include "expr_safe_replace.h" #include "filter_model_converter.h" +#include "dl_mk_interp_tail_simplifier.h" namespace datalog { @@ -212,18 +213,23 @@ namespace datalog { ast_manager & m; params_ref m_params; rule_ref_vector m_rules; + mk_interp_tail_simplifier m_simplifier; bit_blaster_rewriter m_blaster; expand_mkbv m_rewriter; - bool blast(expr_ref& fml) { + bool blast(rule *r, expr_ref& fml) { proof_ref pr(m); - expr_ref fml1(m), fml2(m); - m_blaster(fml, fml1, pr); - m_rewriter(fml1, fml2); - TRACE("dl", tout << mk_pp(fml, m) << " -> " << mk_pp(fml1, m) << " -> " << mk_pp(fml2, m) << "\n";); - if (fml2 != fml) { - fml = fml2; + expr_ref fml1(m), fml2(m), fml3(m); + rule_ref r2(m_context.get_rule_manager()); + // We need to simplify rule before bit-blasting. + m_simplifier.transform_rule(r, r2); + r2->to_formula(fml1); + m_blaster(fml1, fml2, pr); + m_rewriter(fml2, fml3); + TRACE("dl", tout << mk_pp(fml, m) << " -> " << mk_pp(fml2, m) << " -> " << mk_pp(fml3, m) << "\n";); + if (fml3 != fml) { + fml = fml3; return true; } else { @@ -241,6 +247,7 @@ namespace datalog { m(ctx.get_manager()), m_params(ctx.get_params().p), m_rules(ctx.get_rule_manager()), + m_simplifier(ctx), m_blaster(ctx.get_manager(), m_params), m_rewriter(ctx.get_manager(), ctx, m_rules) { m_params.set_bool("blast_full", true); @@ -261,12 +268,12 @@ namespace datalog { for (unsigned i = 0; i < sz; ++i) { rule * r = source.get_rule(i); r->to_formula(fml); - if (blast(fml)) { + if (blast(r, fml)) { proof_ref pr(m); if (m_context.generate_proof_trace()) { pr = m.mk_asserted(fml); // loses original proof of r. } - rm.mk_rule(fml, pr, m_rules, r->name()); + rm.mk_rule(fml, pr, m_rules, r->name()); } else { m_rules.push_back(r); From f32eaee62ef61ae8fb6d09593bb71f551413c10f Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 25 Mar 2013 15:40:52 -0700 Subject: [PATCH 038/281] Replace std::sort with std::stable_sort when the given relation is just a partial order. This change avoids discrepancies when using different implmentations of std::sort. Signed-off-by: Leonardo de Moura --- src/ast/simplifier/poly_simplifier_plugin.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ast/simplifier/poly_simplifier_plugin.cpp b/src/ast/simplifier/poly_simplifier_plugin.cpp index 13e5748dc..402b078a8 100644 --- a/src/ast/simplifier/poly_simplifier_plugin.cpp +++ b/src/ast/simplifier/poly_simplifier_plugin.cpp @@ -18,6 +18,7 @@ Author: #include"ast_pp.h" #include"ast_util.h" #include"ast_smt2_pp.h" +#include"ast_ll_pp.h" poly_simplifier_plugin::poly_simplifier_plugin(symbol const & fname, ast_manager & m, decl_kind add, decl_kind mul, decl_kind uminus, decl_kind sub, decl_kind num): @@ -173,7 +174,7 @@ void poly_simplifier_plugin::mk_monomial(unsigned num_args, expr * * args, expr_ result = args[0]; break; default: - std::sort(args, args + num_args, monomial_element_lt_proc(*this)); + std::stable_sort(args, args + num_args, monomial_element_lt_proc(*this)); result = mk_mul(num_args, args); SASSERT(wf_monomial(result)); break; @@ -465,7 +466,9 @@ void poly_simplifier_plugin::mk_sum_of_monomials(expr_ref_vector & monomials, ex result = monomials.get(0); break; default: { - std::sort(monomials.c_ptr(), monomials.c_ptr() + monomials.size(), monomial_lt_proc(*this)); + TRACE("mk_sum_sort", tout << "before\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";); + std::stable_sort(monomials.c_ptr(), monomials.c_ptr() + monomials.size(), monomial_lt_proc(*this)); + TRACE("mk_sum_sort", tout << "after\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";); if (is_simple_sum_of_monomials(monomials)) { mk_sum_of_monomials_core(monomials.size(), monomials.c_ptr(), result); return; From 25a41d48dc7367d9042661562380664dbd606e2e Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 25 Mar 2013 15:41:52 -0700 Subject: [PATCH 039/281] speedup bit_vector::num_words() Proof of equivalence w.r.t. previous code: http://rise4fun.com/Z3/aiLV Signed-off-by: Nuno Lopes --- src/util/bit_vector.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 2e7becee7..1d6083717 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -37,7 +37,8 @@ class bit_vector { } static unsigned num_words(unsigned num_bits) { - return (num_bits % 32) == 0 ? (num_bits / 32) : ((num_bits / 32) + 1); + // return (num_bits % 32) == 0 ? (num_bits / 32) : ((num_bits / 32) + 1); + return (num_bits + 31) / 32; } void expand_to(unsigned new_capacity); From b417ca657d388a3f635b19f371b5d3975835f412 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 25 Mar 2013 16:52:08 -0700 Subject: [PATCH 040/281] Fix set_interruptable usage Signed-off-by: Leonardo de Moura --- src/api/api_algebraic.cpp | 4 ++-- src/api/api_ast.cpp | 2 +- src/api/api_datalog.cpp | 4 ++-- src/api/api_polynomial.cpp | 2 +- src/api/api_solver.cpp | 2 +- src/api/api_solver_old.cpp | 4 ++-- src/api/api_tactic.cpp | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/api/api_algebraic.cpp b/src/api/api_algebraic.cpp index 7716cbb59..d03a6aff4 100644 --- a/src/api/api_algebraic.cpp +++ b/src/api/api_algebraic.cpp @@ -373,7 +373,7 @@ extern "C" { scoped_anum_vector roots(_am); { cancel_eh eh(_am); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); scoped_timer timer(mk_c(c)->params().m_timeout, &eh); vector_var2anum v2a(as); _am.isolate_roots(_p, v2a, roots); @@ -408,7 +408,7 @@ extern "C" { } { cancel_eh eh(_am); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); scoped_timer timer(mk_c(c)->params().m_timeout, &eh); vector_var2anum v2a(as); int r = _am.eval_sign_at(_p, v2a); diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index e93e1a178..680b59c68 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -681,7 +681,7 @@ extern "C" { th_rewriter m_rw(m, p); expr_ref result(m); cancel_eh eh(m_rw); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); scoped_timer timer(timeout, &eh); diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 28fe3ed33..0f100e747 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -266,7 +266,7 @@ extern "C" { lbool r = l_undef; cancel_eh eh(*to_fixedpoint_ref(d)); unsigned timeout = to_fixedpoint(d)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_timer timer(timeout, &eh); try { @@ -291,7 +291,7 @@ extern "C" { lbool r = l_undef; unsigned timeout = to_fixedpoint(d)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); cancel_eh eh(*to_fixedpoint_ref(d)); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_timer timer(timeout, &eh); try { diff --git a/src/api/api_polynomial.cpp b/src/api/api_polynomial.cpp index 3148f972b..25d4ca292 100644 --- a/src/api/api_polynomial.cpp +++ b/src/api/api_polynomial.cpp @@ -67,7 +67,7 @@ extern "C" { expr_ref _r(mk_c(c)->m()); { cancel_eh eh(pm); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); scoped_timer timer(mk_c(c)->params().m_timeout, &eh); pm.psc_chain(_p, _q, v_x, rs); } diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 9ace149af..ac30a0c21 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -243,7 +243,7 @@ extern "C" { unsigned timeout = to_solver(s)->m_params.get_uint("timeout", mk_c(c)->get_timeout()); bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", false); cancel_eh eh(*to_solver_ref(s)); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); lbool result; { scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); diff --git a/src/api/api_solver_old.cpp b/src/api/api_solver_old.cpp index c89f89873..e0533fbd9 100644 --- a/src/api/api_solver_old.cpp +++ b/src/api/api_solver_old.cpp @@ -73,7 +73,7 @@ extern "C" { RESET_ERROR_CODE(); CHECK_SEARCHING(c); cancel_eh eh(mk_c(c)->get_smt_kernel()); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); flet _model(mk_c(c)->fparams().m_model, true); lbool result; try { @@ -123,7 +123,7 @@ extern "C" { expr * const* _assumptions = to_exprs(assumptions); flet _model(mk_c(c)->fparams().m_model, true); cancel_eh eh(mk_c(c)->get_smt_kernel()); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); lbool result; result = mk_c(c)->get_smt_kernel().check(num_assumptions, _assumptions); if (result != l_false && m) { diff --git a/src/api/api_tactic.cpp b/src/api/api_tactic.cpp index 5bce218e6..911360047 100644 --- a/src/api/api_tactic.cpp +++ b/src/api/api_tactic.cpp @@ -410,7 +410,7 @@ extern "C" { to_tactic_ref(t)->updt_params(p); - api::context::set_interruptable(*(mk_c(c)), eh); + api::context::set_interruptable si(*(mk_c(c)), eh); { scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); scoped_timer timer(timeout, &eh); From 00e79e6b6b25d5dbb908559bc2c6807830068f96 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Mar 2013 17:31:11 -0700 Subject: [PATCH 041/281] test hilbert-basis with fdds and checked integers Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_bit_blast.cpp | 7 +- src/muz_qe/fdd.cpp | 311 +++++++++++++++++++++++++++++++++ src/muz_qe/fdd.h | 169 ++++++++++++++++++ src/muz_qe/heap_trie.h | 12 +- src/muz_qe/hilbert_basis.cpp | 184 ++++++++++++------- src/muz_qe/hilbert_basis.h | 40 +++-- src/test/fdd.cpp | 87 +++++++++ src/test/heap_trie.cpp | 3 +- src/test/hilbert_basis.cpp | 7 + src/test/main.cpp | 1 + src/util/checked_int64.h | 231 ++++++++++++++++++++++++ 11 files changed, 969 insertions(+), 83 deletions(-) create mode 100644 src/muz_qe/fdd.cpp create mode 100644 src/muz_qe/fdd.h create mode 100644 src/test/fdd.cpp create mode 100644 src/util/checked_int64.h diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 1e984f254..ccba0d69f 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -212,6 +212,7 @@ namespace datalog { ast_manager & m; params_ref m_params; rule_ref_vector m_rules; + th_rewriter m_theory_rewriter; bit_blaster_rewriter m_blaster; expand_mkbv m_rewriter; @@ -219,6 +220,7 @@ namespace datalog { bool blast(expr_ref& fml) { proof_ref pr(m); expr_ref fml1(m), fml2(m); + m_theory_rewriter(fml); m_blaster(fml, fml1, pr); m_rewriter(fml1, fml2); TRACE("dl", tout << mk_pp(fml, m) << " -> " << mk_pp(fml1, m) << " -> " << mk_pp(fml2, m) << "\n";); @@ -241,8 +243,9 @@ namespace datalog { m(ctx.get_manager()), m_params(ctx.get_params().p), m_rules(ctx.get_rule_manager()), - m_blaster(ctx.get_manager(), m_params), - m_rewriter(ctx.get_manager(), ctx, m_rules) { + m_theory_rewriter(m, m_params), + m_blaster(m, m_params), + m_rewriter(m, ctx, m_rules) { m_params.set_bool("blast_full", true); m_params.set_bool("blast_quant", true); m_blaster.updt_params(m_params); diff --git a/src/muz_qe/fdd.cpp b/src/muz_qe/fdd.cpp new file mode 100644 index 000000000..afb5206cc --- /dev/null +++ b/src/muz_qe/fdd.cpp @@ -0,0 +1,311 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + fdd.cpp + +Abstract: + + Finite decision diagram trie. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-07-03. + +Revision History: + + +--*/ + +#include "fdd.h" +#include "hash.h" +#include "bit_vector.h" +#include "trace.h" + +#define OFFSET_OF(ty, field) (unsigned char*)(&((ty*)(0))->field) - (unsigned char*)(ty*)(0) + +using namespace fdd; + +unsigned node::get_hash() const { + return string_hash((char*)this, OFFSET_OF(node, m_ref_count), 11); +} + +bool node::operator==(node const& other) const { + return + m_var == other.m_var && + m_lo == other.m_lo && + m_hi == other.m_hi; +} + + +// ------------------------------------------ +// manager + +manager::manager() : + m_false(0), + m_true(1), + m_root(m_false), + m_alloc_node(2) +{ + m_nodes.push_back(node()); // false + m_nodes.push_back(node()); // true + inc_ref(m_false); + inc_ref(m_true); + alloc_node(); // pre-allocate a node. +} + +manager::~manager() { +} + +void manager::alloc_node() { + unsigned index; + while (!m_free.empty()) { + index = m_free.back(); + node& n = m_nodes[index]; + m_free.pop_back(); + if (n.get_ref_count() == 0) { + if (!is_leaf(n.lo())) { + m_free.push_back(n.lo()); + } + if (!is_leaf(n.hi())) { + m_free.push_back(n.hi()); + } + m_alloc_node = index; + m_table.erase(n); + return; + } + } + index = m_nodes.size(); + m_nodes.push_back(node()); + m_alloc_node = index; +} + +node_id manager::mk_node(unsigned var, node_id lo, node_id hi) { + if (lo == hi) { + return lo; + } + node n(var, lo, hi); + unsigned index = m_alloc_node; + + node_id result = m_table.insert_if_not_there(n, index).m_value; + + if (result == index) { + alloc_node(); + m_nodes[result] = n; + inc_ref(lo); + inc_ref(hi); + } + + TRACE("mtdd", tout << "mk_node: " << var << " " << lo << " " << hi << " -> " << result << "\n";); + + return result; +} + + +void manager::inc_ref(node_id n) { + TRACE("mtdd", tout << "incref: " << n << "\n";); + if (!is_leaf(n)) { + m_nodes[n].inc_ref(); + } +} + +void manager::dec_ref(node_id n) { + if (!is_leaf(n) && 0 == m_nodes[n].dec_ref()) { + m_free.push_back(n); + } +} + +void manager::setup_keys(Key const* keys) { + for (unsigned i = 0; i < m_num_keys; ++i) { + m_keys[i] = (uint64)keys[i]; + m_sign[i] = keys[i] < 0; + } + +} + +void manager::insert(Key const* keys) { + setup_keys(keys); + node_id result = insert_sign(m_num_idx + m_num_keys, m_root); + inc_ref(result); + dec_ref(m_root); + m_root = result; +} + +node_id manager::insert_sign(unsigned idx, node_id n) { + if (idx > m_num_idx) { + --idx; + bool s = idx2sign(idx); + node nd = m_nodes[n]; + if (!is_leaf(n) && nd.var() == idx) { + if (s) { + return mk_node(idx, insert_sign(idx, nd.lo()), nd.hi()); + } + else { + return mk_node(idx, nd.lo(), insert_sign(idx, nd.hi())); + } + } + else { + if (s) { + return mk_node(idx, insert_sign(idx, n), n); + } + else { + return mk_node(idx, n, insert_sign(idx, n)); + } + } + } + SASSERT(m_num_idx == idx); + return insert(idx, n); +} + +node_id manager::insert(unsigned idx, node_id n) { + node_id result; + SASSERT(0 <= idx && idx <= m_num_idx); + TRACE("mtdd", tout << "insert: " << idx << " " << n << "\n";); + if (is_leaf(n)) { + while (idx > 0) { + --idx; + if (idx2bit(idx) && !is_dont_care(idx2key(idx))) { + return mk_node(idx, n, insert(idx, n)); + } + } + return m_true; + } + + SASSERT(0 < idx); + --idx; + + config c(m_dont_cares, idx, n); + insert_cache::key_data & kd = m_insert_cache.insert_if_not_there2(c, 0)->get_data(); + if (kd.m_value != 0) { + return kd.m_value; + } + + node nd = m_nodes[n]; + SASSERT(idx >= nd.var()); + unsigned idx0 = idx; + while (idx > nd.var()) { + if (idx2bit(idx) && !is_dont_care(idx2key(idx))) { + return mk_node(idx, n, insert(idx, n)); + } + --idx; + } + SASSERT(nd.var() == idx); + unsigned key = idx2key(idx); + if (is_dont_care(key)) { + result = mk_node(idx, insert(idx, nd.lo()), insert(idx, nd.hi())); + } + else { + bool bit = idx2bit(idx); + node_id lo, hi; + if (bit) { + hi = insert(idx, nd.hi()); + lo = nd.lo(); + } + else { + lo = insert(idx, nd.lo()); + scoped_dont_cares _set(*this, key); + hi = insert(idx, nd.hi()); + } + result = mk_node(idx, lo, hi); + } + kd.m_value = result; + return result; +} + +void manager::set_dont_care(unsigned key) { + SASSERT(!is_dont_care(key)); + m_dont_cares |= (1ull << key); +} + +void manager::unset_dont_care(unsigned key) { + m_dont_cares &= ~(1ull << key); +} + +bool manager::is_dont_care(unsigned key) const { + return 0 != (m_dont_cares & (1ull << key)); +} + +void manager::collect_statistics(statistics& st) const { + st.update("fdd.num_nodes", m_nodes.size()); +} + + +void manager::reset(unsigned num_keys) { + m_num_keys = num_keys; + m_num_idx = m_num_keys * m_num_bits; + m_dont_cares = 0; + m_sign.resize(num_keys); + m_keys.resize(num_keys); + SASSERT(num_keys <= 8*sizeof(m_dont_cares)); +} + + + +bool manager::find_le(Key const* keys) { + setup_keys(keys); + unsigned idx = m_num_idx + m_num_keys; + node_id n = m_root; + node nc = m_nodes[n]; + while (n > 1 && idx > m_num_idx) { + --idx; + if (nc.var() == idx) { + if (idx2sign(idx)) { + n = nc.lo(); + } + else { + n = nc.hi(); + } + nc = m_nodes[n]; + } + } + while (n > 1) { + SASSERT(idx > 0); + --idx; + while (nc.var() < idx) { + if (idx2bit(idx)) { + set_dont_care(idx2key(idx)); + } + --idx; + } + if (is_dont_care(idx2key(idx)) || idx2bit(idx)) { + n = nc.hi(); + } + else { + n = nc.lo(); + } + nc = m_nodes[n]; + } + m_dont_cares = 0; + return n == 1; +} + + +std::ostream& manager::display(std::ostream& out, node_id n) const{ + svector mark; + svector nodes; + nodes.push_back(n); + while (!nodes.empty()) { + n = nodes.back(); + nodes.pop_back(); + if (mark.size() <= n) { + mark.resize(n+1, false); + } + node const& nc = m_nodes[n]; + if (is_leaf(n) || mark[n]) { + continue; + } + nodes.push_back(nc.lo()); + nodes.push_back(nc.hi()); + mark[n] = true; + + if (nc.var() >= m_num_idx) { + out << n << " if " << idx2key(nc.var()) << " then " << nc.hi() << " else " << nc.lo() << "\n"; + } + else { + out << n << " if " << idx2key(nc.var()) << ":" << idx2bitnum(nc.var()) << " then " << nc.hi() << " else " << nc.lo() << "\n"; + } + } + return out; +} + diff --git a/src/muz_qe/fdd.h b/src/muz_qe/fdd.h new file mode 100644 index 000000000..e6808375c --- /dev/null +++ b/src/muz_qe/fdd.h @@ -0,0 +1,169 @@ +/*++ +Copyright (c) 2007 Microsoft Corporation + +Module Name: + + fdd.h + +Abstract: + + Finite decision diagram. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-07-03. + +Revision History: + + +--*/ + +#ifndef __FDD_H__ +#define __FDD_H__ + +#include "hashtable.h" +#include "hash.h" +#include "map.h" +#include "vector.h" +#include "statistics.h" + +namespace fdd { + + + typedef unsigned node_id; + + class node { + unsigned m_var; + node_id m_lo; + node_id m_hi; + unsigned m_ref_count; + void reset(); + public: + node() : m_var(0), m_hi(0), m_lo(0), m_ref_count(0) {} + node(unsigned var, node_id l, node_id h): m_var(var), m_lo(l), m_hi(h), m_ref_count(0) {} + + unsigned get_hash() const; + bool operator==(node const& other) const; + + void inc_ref() { ++m_ref_count; } + unsigned dec_ref() { return --m_ref_count; } + unsigned get_ref_count() const { return m_ref_count; } + node_id lo() const { return m_lo; } + node_id hi() const { return m_hi; } + unsigned var() const { return m_var; } + + struct hash { unsigned operator()(node const& n) const { return n.get_hash(); } }; + struct eq { bool operator()(node const& l, node const& r) const { return l == r; } }; + std::ostream& display(std::ostream& out) const { return out << m_var << " " << m_lo << " " << m_hi << ""; } + }; + + inline std::ostream& operator<<(std::ostream& out, node const& n) { return n.display(out); } + + class config { + uint64 m_dont_cares; + unsigned m_idx; + node_id m_node; + public: + + config(): m_dont_cares(0), m_idx(0), m_node(0) {} + + config(uint64 dont_cares, unsigned idx, node_id n): + m_dont_cares(dont_cares), + m_idx(idx), + m_node(n) + {} + + struct hash { + unsigned operator()(config const& c) const { + return string_hash((char*)&c, sizeof(c), 12); + }; + }; + + struct eq { + bool operator()(config const& a, config const& b) const { + return + a.m_dont_cares == b.m_dont_cares && + a.m_idx == b.m_idx && + a.m_node == b.m_node; + } + }; + }; + + + class manager { + public: + typedef int64 Key; + private: + typedef map node_table; + typedef map insert_cache; + node_table m_table; + insert_cache m_insert_cache; + svector m_nodes; + unsigned_vector m_free; + unsigned m_alloc_node; + node_id m_false; + node_id m_true; + node_id m_root; + + static const unsigned m_num_bits = 64; + unsigned m_num_keys; + unsigned m_num_idx; // = m_num_keys * m_num_bits + + // state associated with insert. + svector m_keys; + svector m_sign; + + uint64 m_dont_cares; + + public: + manager(); + ~manager(); + + void reset(unsigned num_keys); + + void insert(Key const* keys); + + bool find_le(Key const* keys); + + void collect_statistics(statistics& st) const; + void reset_statistics() {} + unsigned size() const { return m_nodes.size(); } + + void display(std::ostream& out) const { display(out, m_root); } + + private: + void dec_ref(node_id n); + void inc_ref(node_id n); + node_id mk_node(unsigned var, node_id lo, node_id hi); + inline unsigned get_ref_count(node_id n) { return m_nodes[n].get_ref_count(); } + + std::ostream& display(std::ostream& out, node_id n) const; + + void setup_keys(Key const* keys); + node_id insert(unsigned idx, node_id n); + node_id insert_sign(unsigned idx, node_id n); + bool is_dont_care(unsigned idx) const; + + void set_dont_care(unsigned key); + void unset_dont_care(unsigned key); + + struct scoped_dont_cares { + manager& m; + unsigned m_key; + scoped_dont_cares(manager& m, unsigned key):m(m), m_key(key) { m.set_dont_care(key); } + ~scoped_dont_cares() { m.unset_dont_care(m_key); } + }; + + void alloc_node(); + + unsigned idx2key(unsigned i) const { return i % m_num_keys; } + unsigned idx2bitnum(unsigned i) const { SASSERT(i < m_num_idx); return (i / m_num_keys); } + bool idx2bit(unsigned i) const { return 0 != (m_keys[idx2key(i)] & (1LL << idx2bitnum(i))); } + bool idx2sign(unsigned i) const { return m_sign[idx2key(i)]; } + + bool is_leaf(node_id n) const { return n <= 1; } + + }; +}; + +#endif diff --git a/src/muz_qe/heap_trie.h b/src/muz_qe/heap_trie.h index a99861359..c2a1c52d1 100644 --- a/src/muz_qe/heap_trie.h +++ b/src/muz_qe/heap_trie.h @@ -123,9 +123,9 @@ class heap_trie { } // push nodes whose keys are <= key into vector. - void find_le(Key key, ptr_vector& nodes) { + void find_le(KeyLE& le, Key key, ptr_vector& nodes) { for (unsigned i = 0; i < m_nodes.size(); ++i) { - if (KeyLE::le(m_nodes[i].first, key)) { + if (le.le(m_nodes[i].first, key)) { node* n = m_nodes[i].second; if (n->ref_count() > 0){ nodes.push_back(n); @@ -179,6 +179,7 @@ class heap_trie { }; small_object_allocator m_alloc; + KeyLE& m_le; unsigned m_num_keys; unsigned_vector m_keys; unsigned m_do_reshuffle; @@ -189,8 +190,9 @@ class heap_trie { public: - heap_trie(): + heap_trie(KeyLE& le): m_alloc("heap_trie"), + m_le(le), m_num_keys(0), m_do_reshuffle(4), m_root(0), @@ -255,7 +257,7 @@ public: for (unsigned i = 0; i < num_keys(); ++i) { for (unsigned j = 0; j < todo[index].size(); ++j) { ++m_stats.m_num_find_le_nodes; - to_trie(todo[index][j])->find_le(get_key(keys, i), todo[!index]); + to_trie(todo[index][j])->find_le(m_le, get_key(keys, i), todo[!index]); } todo[index].reset(); index = !index; @@ -577,7 +579,7 @@ private: verbose_stream() << " "; } verbose_stream() << nodes[i].first << " <=? " << key << " rc:" << m->ref_count() << "\n";); - if (m->ref_count() > 0 && KeyLE::le(nodes[i].first, key) && find_le(m, index+1, keys, check)) { + if (m->ref_count() > 0 && m_le.le(nodes[i].first, key) && find_le(m, index+1, keys, check)) { if (i > 0) { std::swap(nodes[i], nodes[0]); } diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 9fbd8cc2e..221e9a706 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -21,6 +21,7 @@ Revision History: #include "heap.h" #include "map.h" #include "heap_trie.h" +#include "fdd.h" #include "stopwatch.h" @@ -58,14 +59,13 @@ public: m_table.reset(); } - bool find(offset_t idx, values const& vs, offset_t& found_idx) { + bool find(offset_t idx, values const& vs) { // display_profile(idx, std::cout); int_table::iterator it = m_table.begin(), end = m_table.end(); for (; it != end; ++it) { offset_t offs(*it); ++m_stats.m_num_comparisons; if (*it != static_cast(idx.m_offset) && hb.is_subsumed(idx, offs)) { - found_idx = offs; ++m_stats.m_num_hit; return true; } @@ -163,20 +163,21 @@ private: class hilbert_basis::value_index2 { struct key_le { - static bool le(numeral const& n1, numeral const& n2) { - return hilbert_basis::is_abs_geq(n2, n1); + hilbert_basis& hb; + key_le(hilbert_basis& hb): hb(hb) {} + bool le(numeral const& n1, numeral const& n2) const { + return hb.is_abs_geq(n2, n1); } }; typedef heap_trie ht; + struct checker : public ht::check_value { hilbert_basis* hb; offset_t m_value; - offset_t* m_found; - checker(): hb(0), m_found(0) {} - virtual bool operator()(unsigned const& v) { - if (m_value.m_offset != v && hb->is_subsumed(m_value, offset_t(v))) { - *m_found = offset_t(v); + checker(): hb(0) {} + virtual bool operator()(unsigned const& v) { + if (m_value.m_offset != v) { // && hb->is_subsumed(m_value, offset_t(v))) { return true; } else { @@ -185,23 +186,25 @@ class hilbert_basis::value_index2 { } }; hilbert_basis& hb; + key_le m_le; ht m_trie; - vector m_found; - bool m_init; checker m_checker; - vector m_keys; + unsigned m_offset; numeral const* get_keys(values const& vs) { - return vs()-1; + return vs()-m_offset; } public: - value_index2(hilbert_basis& hb): hb(hb), m_init(false) { + value_index2(hilbert_basis& hb): + hb(hb), + m_le(hb), + m_trie(m_le), + m_offset(1) { m_checker.hb = &hb; } void insert(offset_t idx, values const& vs) { - init(); m_trie.insert(get_keys(vs), idx.m_offset); } @@ -209,15 +212,13 @@ public: m_trie.remove(get_keys(vs)); } - void reset() { - m_trie.reset(hb.get_num_vars()+1); - m_keys.resize(hb.get_num_vars()+1); + void reset(unsigned offset) { + m_offset = offset; + m_trie.reset(hb.get_num_vars()+m_offset); } - bool find(offset_t idx, values const& vs, offset_t& found_idx) { - init(); + bool find(offset_t idx, values const& vs) { m_checker.m_value = idx; - m_checker.m_found = &found_idx; return m_trie.find_le(get_keys(vs), m_checker); } @@ -237,15 +238,63 @@ public: // m_trie.display(out); } -private: - void init() { - if (!m_init) { - reset(); - m_init = true; - } - } + }; +class hilbert_basis::value_index3 { + hilbert_basis& hb; + fdd::manager m_fdd; + unsigned m_offset; + svector m_keys; + + int64 const* get_keys(values const& vs) { + numeral const* nums = vs()-m_offset; + for (unsigned i = 0; i < m_keys.size(); ++i) { + m_keys[i] = nums[i].get_int64(); + } + return m_keys.c_ptr(); + } + +public: + + value_index3(hilbert_basis & hb): hb(hb), m_offset(1) {} + + void insert(offset_t, values const& vs) { + m_fdd.insert(get_keys(vs)); + } + + bool find(offset_t, values const& vs) { + return m_fdd.find_le(get_keys(vs)); + } + + void reset(unsigned offset) { + m_offset = offset; + m_fdd.reset(hb.get_num_vars()+m_offset); + m_keys.resize(hb.get_num_vars()+m_offset); + } + + void collect_statistics(statistics& st) const { + m_fdd.collect_statistics(st); + } + + void reset_statistics() { + m_fdd.reset_statistics(); + } + + unsigned size() const { + return m_fdd.size(); + } + + void remove(offset_t idx, values const& vs) { + UNREACHABLE(); + } + + void display(std::ostream& out) const { + // m_fdd.display(out); + } + + +}; class hilbert_basis::index { @@ -253,7 +302,8 @@ class hilbert_basis::index { // for positive weights a shared value index. // typedef value_index1 value_index; - typedef value_index2 value_index; + // typedef value_index2 value_index; + typedef value_index3 value_index; struct stats { unsigned m_num_find; @@ -271,9 +321,10 @@ class hilbert_basis::index { value_index m_pos; value_index m_zero; stats m_stats; + unsigned m_num_ineqs; public: - index(hilbert_basis& hb): hb(hb), m_pos(hb), m_zero(hb) {} + index(hilbert_basis& hb): hb(hb), m_pos(hb), m_zero(hb), m_num_ineqs(0) {} void insert(offset_t idx, values const& vs) { ++m_stats.m_num_insert; @@ -287,6 +338,7 @@ public: value_index* map = 0; if (!m_neg.find(vs.weight(), map)) { map = alloc(value_index, hb); + map->reset(m_num_ineqs); m_neg.insert(vs.weight(), map); } map->insert(idx, vs); @@ -305,29 +357,30 @@ public: } } - bool find(offset_t idx, values const& vs, offset_t& found_idx) { + bool find(offset_t idx, values const& vs) { ++m_stats.m_num_find; if (vs.weight().is_pos()) { - return m_pos.find(idx, vs, found_idx); + return m_pos.find(idx, vs); } else if (vs.weight().is_zero()) { - return m_zero.find(idx, vs, found_idx); + return m_zero.find(idx, vs); } else { value_index* map; return m_neg.find(vs.weight(), map) && - map->find(idx, vs, found_idx); + map->find(idx, vs); } } - void reset() { + void reset(unsigned num_ineqs) { value_map::iterator it = m_neg.begin(), end = m_neg.end(); for (; it != end; ++it) { - it->m_value->reset(); + dealloc(it->m_value); } - m_pos.reset(); - m_zero.reset(); + m_pos.reset(num_ineqs); + m_zero.reset(num_ineqs); + m_num_ineqs = num_ineqs; m_neg.reset(); } @@ -685,7 +738,7 @@ void hilbert_basis::reset() { m_passive->reset(); m_passive2->reset(); m_zero.reset(); - m_index->reset(); + m_index->reset(1); m_ints.reset(); m_cancel = false; } @@ -703,42 +756,46 @@ void hilbert_basis::reset_statistics() { m_index->reset_statistics(); } -void hilbert_basis::add_ge(num_vector const& v, numeral const& b) { +void hilbert_basis::add_ge(rational_vector const& v, rational const& b) { SASSERT(m_ineqs.empty() || v.size() + 1 == m_ineqs.back().size()); num_vector w; - w.push_back(-b); - w.append(v); + w.push_back(to_numeral(-b)); + for (unsigned i = 0; i < v.size(); ++i) { + w.push_back(to_numeral(v[i])); + } m_ineqs.push_back(w); m_iseq.push_back(false); } -void hilbert_basis::add_le(num_vector const& v, numeral const& b) { - num_vector w(v); +void hilbert_basis::add_le(rational_vector const& v, rational const& b) { + rational_vector w(v); for (unsigned i = 0; i < w.size(); ++i) { w[i].neg(); } add_ge(w, -b); } -void hilbert_basis::add_eq(num_vector const& v, numeral const& b) { +void hilbert_basis::add_eq(rational_vector const& v, rational const& b) { SASSERT(m_ineqs.empty() || v.size() + 1 == m_ineqs.back().size()); num_vector w; - w.push_back(-b); - w.append(v); + w.push_back(to_numeral(-b)); + for (unsigned i = 0; i < v.size(); ++i) { + w.push_back(to_numeral(v[i])); + } m_ineqs.push_back(w); m_iseq.push_back(true); } -void hilbert_basis::add_ge(num_vector const& v) { - add_ge(v, numeral(0)); +void hilbert_basis::add_ge(rational_vector const& v) { + add_ge(v, rational(0)); } -void hilbert_basis::add_le(num_vector const& v) { - add_le(v, numeral(0)); +void hilbert_basis::add_le(rational_vector const& v) { + add_le(v, rational(0)); } -void hilbert_basis::add_eq(num_vector const& v) { - add_eq(v, numeral(0)); +void hilbert_basis::add_eq(rational_vector const& v) { + add_eq(v, rational(0)); } void hilbert_basis::set_is_int(unsigned var_index) { @@ -824,7 +881,7 @@ lbool hilbert_basis::saturate_orig(num_vector const& ineq, bool is_eq) { m_active.reset(); m_passive->reset(); m_zero.reset(); - m_index->reset(); + m_index->reset(m_current_ineq+1); int_table support; TRACE("hilbert_basis", display_ineq(tout, ineq, is_eq);); iterator it = begin(); @@ -896,7 +953,7 @@ bool hilbert_basis::vector_lt(offset_t idx1, offset_t idx2) const { lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { m_zero.reset(); - m_index->reset(); + m_index->reset(m_current_ineq+1); m_passive2->reset(); m_sos.reset(); TRACE("hilbert_basis", display_ineq(tout, ineq, is_eq);); @@ -975,19 +1032,21 @@ lbool hilbert_basis::saturate(num_vector const& ineq, bool is_eq) { return m_basis.empty()?l_false:l_true; } -void hilbert_basis::get_basis_solution(unsigned i, num_vector& v, bool& is_initial) { +void hilbert_basis::get_basis_solution(unsigned i, rational_vector& v, bool& is_initial) { offset_t offs = m_basis[i]; v.reset(); for (unsigned i = 1; i < get_num_vars(); ++i) { - v.push_back(vec(offs)[i]); + v.push_back(to_rational(vec(offs)[i])); } is_initial = !vec(offs)[0].is_zero(); } -void hilbert_basis::get_ge(unsigned i, num_vector& v, numeral& b, bool& is_eq) { +void hilbert_basis::get_ge(unsigned i, rational_vector& v, rational& b, bool& is_eq) { v.reset(); - v.append(m_ineqs[i].size() - 1, m_ineqs[i].c_ptr() + 1); - b = -m_ineqs[i][0]; + for (unsigned j = 1; j < m_ineqs[i].size(); ++j) { + v.push_back(to_rational(m_ineqs[i][j])); + } + b = to_rational(-m_ineqs[i][0]); is_eq = m_iseq[i]; } @@ -1122,8 +1181,7 @@ bool hilbert_basis::add_goal(offset_t idx) { bool hilbert_basis::is_subsumed(offset_t idx) { - offset_t found_idx; - if (m_index->find(idx, vec(idx), found_idx)) { + if (m_index->find(idx, vec(idx))) { ++m_stats.m_num_subsumptions; return true; } @@ -1317,7 +1375,7 @@ bool hilbert_basis::is_geq(values const& v, values const& w) const { return true; } -bool hilbert_basis::is_abs_geq(numeral const& v, numeral const& w) { +bool hilbert_basis::is_abs_geq(numeral const& v, numeral const& w) const { if (w.is_neg()) { return v <= w; } diff --git a/src/muz_qe/hilbert_basis.h b/src/muz_qe/hilbert_basis.h index bad4b1fbd..abb59be2d 100644 --- a/src/muz_qe/hilbert_basis.h +++ b/src/muz_qe/hilbert_basis.h @@ -18,6 +18,11 @@ Author: Revision History: + Hilbert basis can be templatized + based on traits that define numeral: + as rational, mpz, checked_int64 + (checked or unchecked). + --*/ #ifndef _HILBERT_BASIS_H_ @@ -26,14 +31,25 @@ Revision History: #include "rational.h" #include "lbool.h" #include "statistics.h" +#include "checked_int64.h" + +typedef vector rational_vector; class hilbert_basis { -public: - typedef rational numeral; + + static const bool check = false; + typedef checked_int64 numeral; typedef vector num_vector; -private: + static checked_int64 to_numeral(rational const& r) { + return checked_int64(r.get_int64()); + } + static rational to_rational(checked_int64 const& i) { + return rational(i.get_int64(), rational::i64()); + } + class value_index1; class value_index2; + class value_index3; class index; class passive; class passive2; @@ -112,7 +128,7 @@ private: unsigned get_num_vars() const; numeral get_weight(values const & val, num_vector const& ineq) const; bool is_geq(values const& v, values const& w) const; - static bool is_abs_geq(numeral const& v, numeral const& w); + bool is_abs_geq(numeral const& v, numeral const& w) const; bool is_subsumed(offset_t idx); bool is_subsumed(offset_t i, offset_t j) const; void recycle(offset_t idx); @@ -147,16 +163,16 @@ public: // add inequality v*x >= 0 // add inequality v*x <= 0 // add equality v*x = 0 - void add_ge(num_vector const& v); - void add_le(num_vector const& v); - void add_eq(num_vector const& v); + void add_ge(rational_vector const& v); + void add_le(rational_vector const& v); + void add_eq(rational_vector const& v); // add inequality v*x >= b // add inequality v*x <= b // add equality v*x = b - void add_ge(num_vector const& v, numeral const& b); - void add_le(num_vector const& v, numeral const& b); - void add_eq(num_vector const& v, numeral const& b); + void add_ge(rational_vector const& v, rational const& b); + void add_le(rational_vector const& v, rational const& b); + void add_eq(rational_vector const& v, rational const& b); void set_is_int(unsigned var_index); bool get_is_int(unsigned var_index) const; @@ -164,10 +180,10 @@ public: lbool saturate(); unsigned get_basis_size() const { return m_basis.size(); } - void get_basis_solution(unsigned i, num_vector& v, bool& is_initial); + void get_basis_solution(unsigned i, rational_vector& v, bool& is_initial); unsigned get_num_ineqs() const { return m_ineqs.size(); } - void get_ge(unsigned i, num_vector& v, numeral& b, bool& is_eq); + void get_ge(unsigned i, rational_vector& v, rational& b, bool& is_eq); void set_cancel(bool f) { m_cancel = f; } diff --git a/src/test/fdd.cpp b/src/test/fdd.cpp new file mode 100644 index 000000000..2a0079456 --- /dev/null +++ b/src/test/fdd.cpp @@ -0,0 +1,87 @@ +#include "fdd.h" + +static void test1() { + fdd::manager m; + + m.reset(2); + int64 keys1[2] = { 1, 2 }; + m.insert(keys1); + m.display(std::cout << "test1\n"); +} + +static void test2() { + fdd::manager m; + + m.reset(2); + int64 keys2[2] = { 2, 1 }; + m.insert(keys2); + m.display(std::cout << "test2\n"); + +} + +static void test3() { + fdd::manager m; + + m.reset(2); + int64 keys1[2] = { 1, 2 }; + int64 keys2[2] = { 2, 1 }; + m.insert(keys1); + m.insert(keys2); + m.display(std::cout << "test3\n"); +} + +static void test4() { + fdd::manager m; + + std::cout << "test4\n"; + + m.reset(2); + int64 keys1[2] = { 1, 2 }; + int64 keys2[2] = { 2, 1 }; + int64 keys3[2] = { 1, 1 }; + int64 keys4[2] = { 2, 2 }; + int64 keys5[2] = { 2, 3 }; + int64 keys6[2] = { 3, 1 }; + int64 keys7[2] = { 3, 4 }; + m.insert(keys1); + m.insert(keys2); + std::cout << m.find_le(keys1) << "\n"; + std::cout << m.find_le(keys2) << "\n"; + std::cout << m.find_le(keys3) << "\n"; + std::cout << m.find_le(keys4) << "\n"; + std::cout << m.find_le(keys5) << "\n"; + std::cout << m.find_le(keys6) << "\n"; + std::cout << m.find_le(keys7) << "\n"; + + SASSERT(m.find_le(keys1)); + SASSERT(m.find_le(keys2)); + SASSERT(!m.find_le(keys3)); + SASSERT(m.find_le(keys4)); + SASSERT(m.find_le(keys5)); + SASSERT(m.find_le(keys6)); + SASSERT(m.find_le(keys7)); +} + +static void test5() { + fdd::manager m; + + std::cout << "test5\n"; + + m.reset(2); + int64 keys1[2] = { 1, 2 }; + int64 keys2[2] = { 2, 1 }; + m.insert(keys1); + m.insert(keys2); + m.insert(keys2); + + m.display(std::cout); + +} + +void tst_fdd() { + test1(); + test2(); + test3(); + test4(); + test5(); +} diff --git a/src/test/heap_trie.cpp b/src/test/heap_trie.cpp index dd04f7b98..92ef97f72 100644 --- a/src/test/heap_trie.cpp +++ b/src/test/heap_trie.cpp @@ -27,7 +27,8 @@ static void find_le(heap_trie_t& ht, unsigned num_keys, unsigned const* keys) { void tst_heap_trie() { - heap_trie_t ht; + unsigned_le le; + heap_trie_t ht(le); ht.reset(3); unsigned keys1[3] = { 1, 2, 3}; diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index bd5d20f8d..a5f554e5e 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -508,6 +508,12 @@ static void tst15() { saturate_basis(hb); } +static void tst16() { + hilbert_basis hb; + hb.add_le(vec(1, 0), R(100)); + saturate_basis(hb); +} + void tst_hilbert_basis() { std::cout << "hilbert basis test\n"; @@ -537,6 +543,7 @@ void tst_hilbert_basis() { tst13(); tst14(); tst15(); + tst16(); gorrila_test(0, 4, 3, 20, 5); gorrila_test(1, 4, 3, 20, 5); //gorrila_test(2, 4, 3, 20, 5); diff --git a/src/test/main.cpp b/src/test/main.cpp index c48f4529e..6ecfd6d4f 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -210,6 +210,7 @@ int main(int argc, char ** argv) { TST(hilbert_basis); TST(heap_trie); TST(karr); + TST(fdd); } void initialize_mam() {} diff --git a/src/util/checked_int64.h b/src/util/checked_int64.h new file mode 100644 index 000000000..3772e5ab0 --- /dev/null +++ b/src/util/checked_int64.h @@ -0,0 +1,231 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + checked_int64.h + +Abstract: + + A class for wrapping checked (and unchecked) int64 operations. + Note: the mpfx class defines a more general class of fixed-point operations. + A tradeoff is that it relies on a manager. + This class several of the most common operations from rational, so + it can be swapped for rational. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-25. + +Revision History: + +--*/ + +#ifndef __CHECKED_INT64_H_ +#define __CHECKED_INT64_H_ + +#include"z3_exception.h" +#include"rational.h" + +template +class checked_int64 { + int64 m_value; + typedef checked_int64 ci; + + rational r64(int64 i) { return rational(i, rational::i64()); } + +public: + + checked_int64(): m_value(0) {} + checked_int64(int64 v): m_value(v) {} + checked_int64(checked_int64 const& other) { m_value = other.m_value; } + + class overflow_exception : public z3_exception { + virtual char const * msg() const { return "checked_int64 overflow/underflow";} + }; + + bool is_zero() const { return m_value == 0; } + bool is_pos() const { return m_value > 0; } + bool is_neg() const { return m_value < 0; } + bool is_one() const { return m_value == 1; } + bool is_minus_one() const { return m_value == -1; } + bool is_nonneg() const { return m_value >= 0; } + bool is_nonpos() const { return m_value <= 0; } + bool is_even() const { return 0 == (m_value ^ 0x1); } + + static checked_int64 zero() { return ci(0); } + static checked_int64 one() { return ci(1); } + static checked_int64 minus_one() { return ci(-1);} + + int64 get_int64() const { return m_value; } + + checked_int64 abs() const { + if (m_value >= 0) { + return *this; + } + if (CHECK && m_value == INT64_MIN) { + throw overflow_exception(); + } + return ci(-m_value); + } + + checked_int64& neg() { + if (CHECK && m_value == INT64_MIN) { + throw overflow_exception(); + } + m_value = -m_value; + return *this; + } + + unsigned hash() const { return static_cast(m_value); } + + struct hash_proc { unsigned operator()(checked_int64 const& r) const { return r.hash(); } }; + + struct eq_proc { bool operator()(checked_int64 const& r1, checked_int64 const& r2) const { return r1 == r2; } }; + + friend inline std::ostream& operator<<(std::ostream& out, checked_int64 const& i) { + return out << i.m_value; + } + + friend inline bool operator==(checked_int64 const& a, checked_int64 const& b) { + return a.m_value == b.m_value; + } + + friend inline bool operator<(checked_int64 const& a, checked_int64 const& b) { + return a.m_value < b.m_value; + } + + checked_int64 & operator++() { + if (CHECK && INT64_MAX == m_value) { + throw overflow_exception(); + } + ++m_value; + return *this; + } + + const checked_int64 operator++(int) { checked_int64 tmp(*this); ++(*this); return tmp; } + + checked_int64 & operator--() { + if (CHECK && m_value == INT64_MIN) { + throw overflow_exception(); + } + --m_value; + return *this; + } + + const checked_int64 operator--(int) { checked_int64 tmp(*this); --(*this); return tmp; } + + checked_int64& operator+=(checked_int64 const& other) { + if (CHECK && m_value > 0 && other.m_value > 0 && + (m_value > INT_MAX || other.m_value > INT_MAX)) { + rational r(r64(m_value) + r64(other.m_value)); + if (!r.is_int64()) { + throw overflow_exception(); + } + m_value = r.get_int64(); + return *this; + } + if (CHECK && m_value < 0 && other.m_value < 0 && + (m_value < INT_MIN || other.m_value < INT_MIN)) { + rational r(r64(m_value) + r64(other.m_value)); + if (!r.is_int64()) { + throw overflow_exception(); + } + m_value = r.get_int64(); + return *this; + } + m_value += other.m_value; + return *this; + } + + checked_int64& operator-=(checked_int64 const& other) { + if (CHECK && m_value > 0 && other.m_value < 0 && + (m_value > INT_MAX || other.m_value < INT_MIN)) { + rational r(r64(m_value) - r64(other.m_value)); + if (!r.is_int64()) { + throw overflow_exception(); + } + m_value = r.get_int64(); + return *this; + } + if (CHECK && m_value < 0 && other.m_value > 0 && + (m_value < INT_MIN || other.m_value > INT_MAX)) { + rational r(r64(m_value) - r64(other.m_value)); + if (!r.is_int64()) { + throw overflow_exception(); + } + m_value = r.get_int64(); + return *this; + } + m_value -= other.m_value; + return *this; + } + + checked_int64& operator*=(checked_int64 const& other) { + if (CHECK) { + rational r(r64(m_value) * r64(other.m_value)); + if (!r.is_int64()) { + throw overflow_exception(); + } + m_value = r.get_int64(); + } + else { + m_value *= other.m_value; + } + return *this; + } + + friend inline checked_int64 abs(checked_int64 const& i) { + return i.abs(); + } + +}; + +template +inline bool operator!=(checked_int64 const & i1, checked_int64 const & i2) { + return !operator==(i1, i2); +} + +template +inline bool operator>(checked_int64 const & i1, checked_int64 const & i2) { + return operator<(i2, i1); +} + +template +inline bool operator<=(checked_int64 const & i1, checked_int64 const & i2) { + return !operator>(i1, i2); +} + +template +inline bool operator>=(checked_int64 const & i1, checked_int64 const & i2) { + return !operator<(i1, i2); +} + +template +inline checked_int64 operator-(checked_int64 const& i) { + checked_int64 result(i); + return result.neg(); +} + +template +inline checked_int64 operator+(checked_int64 const& a, checked_int64 const& b) { + checked_int64 result(a); + result += b; + return result; +} + +template +inline checked_int64 operator-(checked_int64 const& a, checked_int64 const& b) { + checked_int64 result(a); + result -= b; + return result; +} + +template +inline checked_int64 operator*(checked_int64 const& a, checked_int64 const& b) { + checked_int64 result(a); + result *= b; + return result; +} + +#endif From 5c4003b4e5a9a69e35015458ed9889239836a070 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 26 Mar 2013 17:31:59 -0700 Subject: [PATCH 042/281] test hilbert-basis with fdds and checked integers Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_bit_blast.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index ccba0d69f..b3bd3f124 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -212,7 +212,6 @@ namespace datalog { ast_manager & m; params_ref m_params; rule_ref_vector m_rules; - th_rewriter m_theory_rewriter; bit_blaster_rewriter m_blaster; expand_mkbv m_rewriter; @@ -220,7 +219,6 @@ namespace datalog { bool blast(expr_ref& fml) { proof_ref pr(m); expr_ref fml1(m), fml2(m); - m_theory_rewriter(fml); m_blaster(fml, fml1, pr); m_rewriter(fml1, fml2); TRACE("dl", tout << mk_pp(fml, m) << " -> " << mk_pp(fml1, m) << " -> " << mk_pp(fml2, m) << "\n";); @@ -243,7 +241,6 @@ namespace datalog { m(ctx.get_manager()), m_params(ctx.get_params().p), m_rules(ctx.get_rule_manager()), - m_theory_rewriter(m, m_params), m_blaster(m, m_params), m_rewriter(m, ctx, m_rules) { m_params.set_bool("blast_full", true); From 1cece1c1fbec5d67699bcd34ab8f38869973f2e2 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 27 Mar 2013 10:38:50 -0700 Subject: [PATCH 043/281] Datalog improvements: - add cancel status - display statistics on cancel (by me & Nikolaj) Signed-off-by: Nuno Lopes --- src/muz_qe/dl_cmds.cpp | 11 ++++-- src/muz_qe/dl_context.cpp | 25 ++++++++++++-- src/muz_qe/dl_context.h | 8 ++++- src/muz_qe/dl_instruction.cpp | 59 ++++++++++++++++++-------------- src/muz_qe/dl_instruction.h | 38 +++++++++++--------- src/muz_qe/dl_mk_array_blast.cpp | 2 +- src/muz_qe/dl_mk_bit_blast.cpp | 2 +- src/muz_qe/rel_context.cpp | 59 +++++++++++++++++++++----------- src/muz_qe/rel_context.h | 14 ++++---- src/shell/datalog_frontend.cpp | 1 - 10 files changed, 142 insertions(+), 77 deletions(-) diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp index d49a8a671..aef14e051 100644 --- a/src/muz_qe/dl_cmds.cpp +++ b/src/muz_qe/dl_cmds.cpp @@ -234,7 +234,6 @@ public: catch (z3_exception& ex) { ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl; } - dlctx.cleanup(); } switch (status) { case l_false: @@ -250,6 +249,7 @@ public: ctx.regular_stream() << "unknown\n"; switch(dlctx.get_status()) { case datalog::INPUT_ERROR: + ctx.regular_stream() << "input error\n"; break; case datalog::MEMOUT: @@ -261,14 +261,21 @@ public: break; case datalog::OK: + UNREACHABLE(); + break; + + case datalog::CANCELED: + ctx.regular_stream() << "canceled\n"; + dlctx.display_profile(ctx.regular_stream()); break; default: - // exception was raised. + UNREACHABLE(); break; } break; } + dlctx.cleanup(); print_statistics(ctx); m_target = 0; } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 89f2fcf4a..592cfaccd 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -229,11 +229,13 @@ namespace datalog { m_pinned(m), m_vars(m), m_rule_set(*this), + m_transformed_rule_set(*this), m_rule_fmls(m), m_background(m), m_mc(0), m_closed(false), m_saturation_was_run(false), + m_last_status(OK), m_last_answer(m), m_engine(LAST_ENGINE), m_cancel(false) { @@ -873,6 +875,11 @@ namespace datalog { m_rule_set.add_rules(rs); } + void context::record_transformed_rules() { + m_transformed_rule_set.reset(); + m_transformed_rule_set.add_rules(m_rule_set); + } + void context::apply_default_transformation() { ensure_closed(); m_transf.reset(); @@ -942,18 +949,18 @@ namespace datalog { void context::cancel() { m_cancel = true; + m_last_status = CANCELED; m_transf.cancel(); if (m_pdr.get()) m_pdr->cancel(); if (m_bmc.get()) m_bmc->cancel(); - if (m_rel.get()) m_rel->cancel(); if (m_tab.get()) m_tab->cancel(); } void context::cleanup() { m_cancel = false; + m_last_status = OK; if (m_pdr.get()) m_pdr->cleanup(); if (m_bmc.get()) m_bmc->cleanup(); - if (m_rel.get()) m_rel->cleanup(); if (m_tab.get()) m_tab->cleanup(); } @@ -1178,6 +1185,20 @@ namespace datalog { } } + void context::display_profile(std::ostream& out) const { + out << "\n---------------\n"; + out << "Original rules\n"; + display_rules(out); + + out << "\n---------------\n"; + out << "Transformed rules\n"; + m_transformed_rule_set.display(out); + + if (m_rel) { + m_rel->display_profile(out); + } + } + void context::reset_statistics() { if (m_pdr) { m_pdr->reset_statistics(); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index d278d3abc..ddf200b70 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -52,7 +52,8 @@ namespace datalog { OK, TIMEOUT, MEMOUT, - INPUT_ERROR + INPUT_ERROR, + CANCELED }; class context { @@ -92,6 +93,7 @@ namespace datalog { sym2decl m_preds_by_name; pred2syms m_argument_var_names; rule_set m_rule_set; + rule_set m_transformed_rule_set; expr_ref_vector m_rule_fmls; svector m_rule_names; expr_ref_vector m_background; @@ -323,6 +325,7 @@ namespace datalog { void transform_rules(); void transform_rules(rule_transformer& transf); void replace_rules(rule_set & rs); + void record_transformed_rules(); void apply_default_transformation(); @@ -349,6 +352,8 @@ namespace datalog { void display_smt2(unsigned num_queries, expr* const* queries, std::ostream& out); + void display_profile(std::ostream& out) const; + // ----------------------------------- // // basic usage methods @@ -356,6 +361,7 @@ namespace datalog { // ----------------------------------- void cancel(); + bool canceled() const { return m_cancel; } void cleanup(); void reset_cancel() { cleanup(); } diff --git a/src/muz_qe/dl_instruction.cpp b/src/muz_qe/dl_instruction.cpp index 503ffec3b..401a42e98 100644 --- a/src/muz_qe/dl_instruction.cpp +++ b/src/muz_qe/dl_instruction.cpp @@ -58,14 +58,18 @@ namespace datalog { reset_timelimit(); } + rel_context& execution_context::get_rel_context() { + return m_context.get_rel_context(); + } + struct compare_size_proc { typedef std::pair pr; bool operator()(pr const& a, pr const& b) const { return a.second > b.second; } - }; - void execution_context::report_big_relations(unsigned threshold, std::ostream & out) { + + void execution_context::report_big_relations(unsigned threshold, std::ostream & out) const { unsigned n = register_count(); svector > sizes; size_t total_bytes = 0; @@ -110,6 +114,7 @@ namespace datalog { bool execution_context::should_terminate() { return + m_context.canceled() || memory::above_high_watermark() || (m_stopwatch && m_timelimit_ms != 0 && @@ -135,7 +140,7 @@ namespace datalog { process_costs(); } - void instruction::display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const { + void instruction::display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const { out << indentation; display_head_impl(ctx, out); if (ctx.output_profile()) { @@ -182,7 +187,7 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) { ctx.set_register_annotation(m_reg, m_pred->get_name().bare_str()); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { const char * rel_name = m_pred->get_name().bare_str(); if (m_store) { out << "store " << m_reg << " into " << rel_name; @@ -213,7 +218,7 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) { ctx.set_register_annotation(m_reg, "alloc"); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "dealloc " << m_reg; } }; @@ -248,7 +253,7 @@ namespace datalog { ctx.set_register_annotation(m_src, str); } } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << (m_clone ? "clone " : "move ") << m_src << " into " << m_tgt; } }; @@ -304,11 +309,11 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) { m_body->make_annotations(ctx); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const { out << "while"; print_container(m_controls, out); } - virtual void display_body_impl(rel_context & ctx, std::ostream & out, std::string indentation) const { + virtual void display_body_impl(rel_context const & ctx, std::ostream & out, std::string indentation) const { m_body->display_indented(ctx, out, indentation+" "); } }; @@ -385,7 +390,7 @@ namespace datalog { ctx.get_register_annotation(m_rel1, a1); ctx.set_register_annotation(m_res, "join " + a1 + " " + a2); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const { out << "join " << m_rel1; print_container(m_cols1, out); out << " and " << m_rel2; @@ -434,7 +439,7 @@ namespace datalog { a << "filter_equal " << m_col << " val: " << ctx.get_rel_context().get_rmanager().to_nice_string(m_value); ctx.set_register_annotation(m_reg, a.str()); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "filter_equal " << m_reg << " col: " << m_col << " val: " << ctx.get_rmanager().to_nice_string(m_value); } @@ -476,7 +481,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "filter_identical " << m_reg << " "; print_container(m_cols, out); } @@ -519,7 +524,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "filter_interpreted " << m_reg << " using " << mk_pp(m_cond, m_cond.get_manager()); } @@ -619,12 +624,16 @@ namespace datalog { return true; } virtual void make_annotations(execution_context & ctx) { - std::string str; - if (ctx.get_register_annotation(m_tgt, str) && m_delta!=execution_context::void_register) { - ctx.set_register_annotation(m_delta, "delta of "+str); + std::string str = "union"; + if (!ctx.get_register_annotation(m_tgt, str)) { + ctx.set_register_annotation(m_tgt, "union"); } + if (m_delta != execution_context::void_register) { + str = "delta of " + str; + } + ctx.set_register_annotation(m_delta, str); } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << (m_widen ? "widen " : "union ") << m_src << " into " << m_tgt; if (m_delta!=execution_context::void_register) { out << " with delta " << m_delta; @@ -678,7 +687,7 @@ namespace datalog { return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << (m_projection ? "project " : "rename ") << m_src << " into " << m_tgt; out << (m_projection ? " deleting columns " : " with cycle "); print_container(m_cols, out); @@ -739,7 +748,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "join_project " << m_rel1; print_container(m_cols1, out); out << " and " << m_rel2; @@ -800,7 +809,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "select_equal_and_project " << m_src <<" into " << m_result << " col: " << m_col << " val: " << ctx.get_rmanager().to_nice_string(m_value); } @@ -854,7 +863,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "filter_by_negation on " << m_tgt; print_container(m_cols1, out); out << " with " << m_neg_rel; @@ -892,7 +901,7 @@ namespace datalog { ctx.set_reg(m_tgt, rel); return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "mk_unary_singleton into " << m_tgt << " sort:" << ctx.get_rmanager().to_nice_string(m_sig[0]) << " val:" << ctx.get_rmanager().to_nice_string(m_sig[0], m_fact[0]); @@ -922,7 +931,7 @@ namespace datalog { ctx.set_reg(m_tgt, ctx.get_rel_context().get_rmanager().mk_full_relation(m_sig, m_pred)); return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "mk_total into " << m_tgt << " sort:" << ctx.get_rmanager().to_nice_string(m_sig); } @@ -947,7 +956,7 @@ namespace datalog { ctx.get_rel_context().get_rmanager().mark_saturated(m_pred); return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "mark_saturated " << m_pred->get_name().bare_str(); } virtual void make_annotations(execution_context & ctx) { @@ -970,7 +979,7 @@ namespace datalog { } return true; } - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { out << "instr_assert_signature of " << m_tgt << " signature:"; print_container(m_sig, out); } @@ -1042,7 +1051,7 @@ namespace datalog { } } - void instruction_block::display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const { + void instruction_block::display_indented(rel_context const& ctx, std::ostream & out, std::string indentation) const { instr_seq_type::const_iterator it = m_data.begin(); instr_seq_type::const_iterator end = m_data.end(); for(; it!=end; ++it) { diff --git a/src/muz_qe/dl_instruction.h b/src/muz_qe/dl_instruction.h index 89f95c860..ae6310ba6 100644 --- a/src/muz_qe/dl_instruction.h +++ b/src/muz_qe/dl_instruction.h @@ -31,6 +31,7 @@ namespace datalog { class execution_context; class instruction_block; + class rel_context; inline void check_overflow(unsigned i) { if (i == UINT_MAX) { @@ -78,7 +79,7 @@ namespace datalog { void reset(); - rel_context & get_rel_context() { return m_context.get_rel_context(); }; + rel_context & get_rel_context(); void set_timelimit(unsigned time_in_ms); void reset_timelimit(); @@ -91,10 +92,9 @@ namespace datalog { If register contains zero, it should be treated as if it contains an empty relation. */ - reg_type reg(reg_idx i) { - if (i>=m_registers.size()) { - check_overflow(i); - m_registers.resize(i+1,0); + reg_type reg(reg_idx i) const { + if (i >= m_registers.size()) { + return 0; } return m_registers[i]; } @@ -102,27 +102,29 @@ namespace datalog { \brief Return value of the register and assign zero into it place. */ reg_type release_reg(reg_idx i) { - SASSERT(i=m_registers.size()) { + if (i >= m_registers.size()) { check_overflow(i); m_registers.resize(i+1,0); } - if(m_registers[i]) { + if (m_registers[i]) { m_registers[i]->deallocate(); } - m_registers[i]=val; + m_registers[i] = val; } + void make_empty(reg_idx i) { - if(reg(i)) { + if (reg(i)) { set_reg(i, 0); } } @@ -130,14 +132,16 @@ namespace datalog { unsigned register_count() const { return m_registers.size(); } + bool get_register_annotation(reg_idx reg, std::string & res) const { return m_reg_annotation.find(reg, res); } + void set_register_annotation(reg_idx reg, std::string str) { m_reg_annotation.insert(reg, str); } - void report_big_relations(unsigned threshold, std::ostream & out); + void report_big_relations(unsigned threshold, std::ostream & out) const; }; @@ -208,7 +212,7 @@ namespace datalog { The newline character at the end should not be printed. */ - virtual void display_head_impl(rel_context & ctx, std::ostream & out) const { + virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const { out << ""; } /** @@ -216,7 +220,7 @@ namespace datalog { Each line must be prepended by \c indentation and ended by a newline character. */ - virtual void display_body_impl(rel_context & ctx, std::ostream & out, std::string indentation) const {} + virtual void display_body_impl(rel_context const & ctx, std::ostream & out, std::string indentation) const {} public: typedef execution_context::reg_type reg_type; typedef execution_context::reg_idx reg_idx; @@ -227,10 +231,10 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) = 0; - void display(rel_context & ctx, std::ostream & out) const { + void display(rel_context const& ctx, std::ostream & out) const { display_indented(ctx, out, ""); } - void display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const; + void display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const; static instruction * mk_load(ast_manager & m, func_decl * pred, reg_idx tgt); /** @@ -329,10 +333,10 @@ namespace datalog { void make_annotations(execution_context & ctx); - void display(rel_context & ctx, std::ostream & out) const { + void display(rel_context const & ctx, std::ostream & out) const { display_indented(ctx, out, ""); } - void display_indented(rel_context & ctx, std::ostream & out, std::string indentation) const; + void display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const; }; diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp index 537b0b5ac..048269c5a 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz_qe/dl_mk_array_blast.cpp @@ -213,7 +213,7 @@ namespace datalog { rule_set* rules = alloc(rule_set, m_ctx); rule_set::iterator it = source.begin(), end = source.end(); bool change = false; - for (; it != end; ++it) { + for (; !m_ctx.canceled() && it != end; ++it) { change = blast(**it, *rules) || change; } if (!change) { diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index e6612022f..338eed0b4 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -265,7 +265,7 @@ namespace datalog { expr_ref fml(m); reset(); rule_set * result = alloc(rule_set, m_context); - for (unsigned i = 0; i < sz; ++i) { + for (unsigned i = 0; !m_context.canceled() && i < sz; ++i) { rule * r = source.get_rule(i); r->to_formula(fml); if (blast(r, fml)) { diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 8e22a704c..c79acf67f 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -39,8 +39,8 @@ namespace datalog { m(ctx.get_manager()), m_rmanager(ctx), m_answer(m), - m_cancel(false), - m_last_result_relation(0) { + m_last_result_relation(0), + m_ectx(ctx) { // register plugins for builtin tables @@ -94,9 +94,9 @@ namespace datalog { decl_set original_predicates; m_context.collect_predicates(original_predicates); - instruction_block rules_code; + m_code.reset(); instruction_block termination_code; - execution_context ex_ctx(m_context); + m_ectx.reset(); lbool result; @@ -104,9 +104,13 @@ namespace datalog { while (true) { m_context.transform_rules(); - compiler::compile(m_context, m_context.get_rules(), rules_code, termination_code); + if (m_context.canceled()) { + result = l_undef; + break; + } + compiler::compile(m_context, m_context.get_rules(), m_code, termination_code); - TRACE("dl", rules_code.display(*this, tout); ); + TRACE("dl", m_code.display(*this, tout); ); bool timeout_after_this_round = time_limit && (restart_time==0 || remaining_time_limit<=restart_time); @@ -114,29 +118,32 @@ namespace datalog { unsigned timeout = time_limit ? (restart_time!=0) ? std::min(remaining_time_limit, restart_time) : remaining_time_limit : restart_time; - ex_ctx.set_timelimit(timeout); + m_ectx.set_timelimit(timeout); } - bool early_termination = !rules_code.perform(ex_ctx); - ex_ctx.reset_timelimit(); - VERIFY( termination_code.perform(ex_ctx) ); + bool early_termination = !m_code.perform(m_ectx); + m_ectx.reset_timelimit(); + VERIFY( termination_code.perform(m_ectx) || m_context.canceled()); - rules_code.process_all_costs(); + m_code.process_all_costs(); - IF_VERBOSE(10, ex_ctx.report_big_relations(1000, verbose_stream());); - + IF_VERBOSE(10, m_ectx.report_big_relations(1000, verbose_stream());); + + if (m_context.canceled()) { + result = l_undef; + break; + } if (!early_termination) { m_context.set_status(OK); result = l_true; break; } - if (memory::above_high_watermark()) { m_context.set_status(MEMOUT); result = l_undef; break; } - if (timeout_after_this_round || m_cancel) { + if (timeout_after_this_round) { m_context.set_status(TIMEOUT); result = l_undef; break; @@ -154,9 +161,7 @@ namespace datalog { restart_time = static_cast(new_restart_time); } - rules_code.reset(); - termination_code.reset(); - ex_ctx.reset(); + termination_code.reset(); m_context.reopen(); restrict_predicates(original_predicates); m_context.replace_rules(original_rules); @@ -164,10 +169,12 @@ namespace datalog { } m_context.reopen(); restrict_predicates(original_predicates); + m_context.record_transformed_rules(); m_context.replace_rules(original_rules); m_context.close(); - TRACE("dl", ex_ctx.report_big_relations(100, tout);); - m_cancel = false; + TRACE("dl", m_ectx.report_big_relations(100, tout);); + m_code.process_all_costs(); + m_code.make_annotations(m_ectx); return result; } @@ -504,5 +511,17 @@ namespace datalog { get_rmanager().display(out); } + void rel_context::display_profile(std::ostream& out) const { + out << "\n--------------\n"; + out << "Instructions\n"; + m_code.display(*this, out); + + out << "\n--------------\n"; + out << "Big relations\n"; + m_ectx.report_big_relations(1000, out); + + get_rmanager().display_relation_sizes(out); + } + }; diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index b05532d14..2e2b5cd9d 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -22,6 +22,7 @@ Revision History: #define _REL_CONTEXT_H_ #include "ast.h" #include "dl_relation_manager.h" +#include "dl_instruction.h" #include "lbool.h" namespace datalog { @@ -35,10 +36,11 @@ namespace datalog { ast_manager& m; relation_manager m_rmanager; expr_ref m_answer; - volatile bool m_cancel; relation_base * m_last_result_relation; decl_set m_output_preds; fact_vector m_table_facts; + execution_context m_ectx; + instruction_block m_code; void reset_negated_tables(); @@ -53,8 +55,8 @@ namespace datalog { relation_manager & get_rmanager(); const relation_manager & get_rmanager() const; - ast_manager& get_manager() { return m; } - context& get_context() { return m_context; } + ast_manager& get_manager() const { return m; } + context& get_context() const { return m_context; } relation_base & get_relation(func_decl * pred); relation_base * try_get_relation(func_decl * pred) const; expr_ref get_last_answer() { return m_answer; } @@ -70,10 +72,6 @@ namespace datalog { void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred); - void cancel() { m_cancel = true; } - - void cleanup() { m_cancel = false; } - /** \brief Restrict the set of used predicates to \c res. @@ -107,6 +105,8 @@ namespace datalog { void display_output_facts(std::ostream & out) const; void display_facts(std::ostream & out) const; + void display_profile(std::ostream& out) const; + lbool saturate(); }; diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 07052609e..fe2699504 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -209,7 +209,6 @@ unsigned read_datalog(char const * file) { rules_code.make_annotations(ex_ctx); ex_ctx.set_timelimit(timeout); - SASSERT(!ex_ctx.should_terminate()); early_termination = !rules_code.perform(ex_ctx); if(early_termination) { From 06e3b6cfb87c7ce86be13b4cc5464411d814ee82 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Mar 2013 08:13:07 -0700 Subject: [PATCH 044/281] remove model converter from transformer operators. Rely on reference in context Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_context.cpp | 2 +- src/muz_qe/dl_context.h | 1 + src/muz_qe/dl_mk_array_blast.cpp | 2 +- src/muz_qe/dl_mk_array_blast.h | 2 +- src/muz_qe/dl_mk_bit_blast.cpp | 10 +++++----- src/muz_qe/dl_mk_bit_blast.h | 2 +- src/muz_qe/dl_mk_coalesce.cpp | 2 +- src/muz_qe/dl_mk_coalesce.h | 2 +- src/muz_qe/dl_mk_coi_filter.cpp | 10 ++++------ src/muz_qe/dl_mk_coi_filter.h | 4 +--- src/muz_qe/dl_mk_explanations.cpp | 8 ++------ src/muz_qe/dl_mk_explanations.h | 2 +- src/muz_qe/dl_mk_extract_quantifiers.cpp | 2 +- src/muz_qe/dl_mk_extract_quantifiers.h | 2 +- src/muz_qe/dl_mk_filter_rules.cpp | 2 +- src/muz_qe/dl_mk_filter_rules.h | 2 +- src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 2 +- src/muz_qe/dl_mk_interp_tail_simplifier.h | 2 +- src/muz_qe/dl_mk_karr_invariants.cpp | 6 +++--- src/muz_qe/dl_mk_karr_invariants.h | 2 +- src/muz_qe/dl_mk_magic_sets.cpp | 4 ++-- src/muz_qe/dl_mk_magic_sets.h | 2 +- src/muz_qe/dl_mk_partial_equiv.cpp | 2 +- src/muz_qe/dl_mk_partial_equiv.h | 2 +- src/muz_qe/dl_mk_rule_inliner.cpp | 14 +++++++------- src/muz_qe/dl_mk_rule_inliner.h | 2 +- src/muz_qe/dl_mk_similarity_compressor.cpp | 2 +- src/muz_qe/dl_mk_similarity_compressor.h | 2 +- src/muz_qe/dl_mk_simple_joins.cpp | 3 +-- src/muz_qe/dl_mk_simple_joins.h | 2 +- src/muz_qe/dl_mk_slice.cpp | 6 +++--- src/muz_qe/dl_mk_slice.h | 2 +- src/muz_qe/dl_mk_subsumption_checker.cpp | 2 +- src/muz_qe/dl_mk_subsumption_checker.h | 2 +- src/muz_qe/dl_mk_unbound_compressor.cpp | 2 +- src/muz_qe/dl_mk_unbound_compressor.h | 2 +- src/muz_qe/dl_mk_unfold.cpp | 2 +- src/muz_qe/dl_mk_unfold.h | 2 +- src/muz_qe/dl_rule_transformer.cpp | 4 ++-- src/muz_qe/dl_rule_transformer.h | 6 ++---- src/muz_qe/hilbert_basis.cpp | 3 --- 41 files changed, 61 insertions(+), 74 deletions(-) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 592cfaccd..71ef7ad20 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -860,7 +860,7 @@ namespace datalog { void context::transform_rules(rule_transformer& transf) { SASSERT(m_closed); //we must finish adding rules before we start transforming them TRACE("dl", display_rules(tout);); - if (transf(m_rule_set, m_mc)) { + if (transf(m_rule_set)) { //we have already ensured the negation is stratified and transformations //should not break the stratification m_rule_set.ensure_closed(); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index ddf200b70..0c4558a28 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -319,6 +319,7 @@ namespace datalog { void ensure_opened(); model_converter_ref& get_model_converter() { return m_mc; } + void add_model_converter(model_converter* mc) { m_mc = concat(m_mc.get(), mc); } proof_converter_ref& get_proof_converter() { return m_pc; } void add_proof_converter(proof_converter* pc) { m_pc = concat(m_pc.get(), pc); } diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp index 048269c5a..1182a2756 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz_qe/dl_mk_array_blast.cpp @@ -208,7 +208,7 @@ namespace datalog { return true; } - rule_set * mk_array_blast::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_array_blast::operator()(rule_set const & source) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::iterator it = source.begin(), end = source.end(); diff --git a/src/muz_qe/dl_mk_array_blast.h b/src/muz_qe/dl_mk_array_blast.h index 94eb64601..c27bb32b3 100644 --- a/src/muz_qe/dl_mk_array_blast.h +++ b/src/muz_qe/dl_mk_array_blast.h @@ -54,7 +54,7 @@ namespace datalog { virtual ~mk_array_blast(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 338eed0b4..d14080498 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -255,7 +255,7 @@ namespace datalog { m_blaster.updt_params(m_params); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * operator()(rule_set const & source) { // TODO pc if (!m_context.get_params().bit_blast()) { return 0; @@ -284,7 +284,7 @@ namespace datalog { result->add_rule(m_rules.get(i)); } - if (mc) { + if (m_context.get_model_converter()) { filter_model_converter* fmc = alloc(filter_model_converter, m); bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m); func_decl_ref_vector const& old_funcs = m_rewriter.m_cfg.old_funcs(); @@ -293,7 +293,7 @@ namespace datalog { fmc->insert(new_funcs[i]); bvmc->insert(old_funcs[i], new_funcs[i]); } - mc = concat(mc.get(), concat(bvmc, fmc)); + m_context.add_model_converter(concat(bvmc, fmc)); } return result; @@ -308,8 +308,8 @@ namespace datalog { dealloc(m_impl); } - rule_set * mk_bit_blast::operator()(rule_set const & source, model_converter_ref& mc) { - return (*m_impl)(source, mc); + rule_set * mk_bit_blast::operator()(rule_set const & source) { + return (*m_impl)(source); } }; diff --git a/src/muz_qe/dl_mk_bit_blast.h b/src/muz_qe/dl_mk_bit_blast.h index 3a6de75e3..60c83f6cb 100644 --- a/src/muz_qe/dl_mk_bit_blast.h +++ b/src/muz_qe/dl_mk_bit_blast.h @@ -44,7 +44,7 @@ namespace datalog { mk_bit_blast(context & ctx, unsigned priority = 35000); ~mk_bit_blast(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_coalesce.cpp b/src/muz_qe/dl_mk_coalesce.cpp index de5388312..94c42e33b 100644 --- a/src/muz_qe/dl_mk_coalesce.cpp +++ b/src/muz_qe/dl_mk_coalesce.cpp @@ -171,7 +171,7 @@ namespace datalog { return true; } - rule_set * mk_coalesce::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_coalesce::operator()(rule_set const & source) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::decl2rules::iterator it = source.begin_grouped_rules(), end = source.end_grouped_rules(); for (; it != end; ++it) { diff --git a/src/muz_qe/dl_mk_coalesce.h b/src/muz_qe/dl_mk_coalesce.h index ab0b74479..4a4065174 100644 --- a/src/muz_qe/dl_mk_coalesce.h +++ b/src/muz_qe/dl_mk_coalesce.h @@ -52,7 +52,7 @@ namespace datalog { */ mk_coalesce(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_coi_filter.cpp b/src/muz_qe/dl_mk_coi_filter.cpp index 915dd4306..6aa688a3c 100644 --- a/src/muz_qe/dl_mk_coi_filter.cpp +++ b/src/muz_qe/dl_mk_coi_filter.cpp @@ -33,9 +33,7 @@ namespace datalog { // ----------------------------------- - rule_set * mk_coi_filter::operator()( - rule_set const & source, - model_converter_ref& mc) + rule_set * mk_coi_filter::operator()(rule_set const & source) { if (source.get_num_rules()==0) { return 0; @@ -80,7 +78,7 @@ namespace datalog { if (interesting_preds.contains(pred)) { res->add_rule(r); } - else if (mc.get()) { + else if (m_context.get_model_converter()) { pruned_preds.insert(pred); } } @@ -89,14 +87,14 @@ namespace datalog { res = 0; } - if (res && mc) { + if (res && m_context.get_model_converter()) { decl_set::iterator end = pruned_preds.end(); decl_set::iterator it = pruned_preds.begin(); extension_model_converter* mc0 = alloc(extension_model_converter, m); for (; it != end; ++it) { mc0->insert(*it, m.mk_true()); } - mc = concat(mc.get(), mc0); + m_context.add_model_converter(mc0); } return res.detach(); diff --git a/src/muz_qe/dl_mk_coi_filter.h b/src/muz_qe/dl_mk_coi_filter.h index 2191048d3..b02bed9ec 100644 --- a/src/muz_qe/dl_mk_coi_filter.h +++ b/src/muz_qe/dl_mk_coi_filter.h @@ -38,9 +38,7 @@ namespace datalog { m(ctx.get_manager()), m_context(ctx) {} - - rule_set * operator()(rule_set const & source, - model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_explanations.cpp b/src/muz_qe/dl_mk_explanations.cpp index af5b1d97a..646a0bcbe 100644 --- a/src/muz_qe/dl_mk_explanations.cpp +++ b/src/muz_qe/dl_mk_explanations.cpp @@ -174,11 +174,9 @@ namespace datalog { } } -#if 1 virtual void deallocate() { get_plugin().recycle(this); } -#endif public: @@ -875,14 +873,12 @@ namespace datalog { } } - rule_set * mk_explanations::operator()(rule_set const & source, model_converter_ref& mc) { - SASSERT(!mc); + rule_set * mk_explanations::operator()(rule_set const & source) { + if(source.get_num_rules()==0) { return 0; } - m_context.collect_predicates(m_original_preds); - rule_set * res = alloc(rule_set, m_context); transform_facts(m_context.get_rel_context().get_rmanager()); transform_rules(source, *res); diff --git a/src/muz_qe/dl_mk_explanations.h b/src/muz_qe/dl_mk_explanations.h index 40606f8df..4e7e23e98 100644 --- a/src/muz_qe/dl_mk_explanations.h +++ b/src/muz_qe/dl_mk_explanations.h @@ -82,7 +82,7 @@ namespace datalog { return get_union_decl(m_context); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); static expr* get_explanation(relation_base const& r); }; diff --git a/src/muz_qe/dl_mk_extract_quantifiers.cpp b/src/muz_qe/dl_mk_extract_quantifiers.cpp index a3d5cc2ab..76e329d79 100644 --- a/src/muz_qe/dl_mk_extract_quantifiers.cpp +++ b/src/muz_qe/dl_mk_extract_quantifiers.cpp @@ -355,7 +355,7 @@ namespace datalog { m_quantifiers.reset(); } - rule_set * mk_extract_quantifiers::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_extract_quantifiers::operator()(rule_set const & source) { reset(); rule_set::iterator it = source.begin(), end = source.end(); for (; !m_has_quantifiers && it != end; ++it) { diff --git a/src/muz_qe/dl_mk_extract_quantifiers.h b/src/muz_qe/dl_mk_extract_quantifiers.h index 7d2f7b149..27b13cd71 100644 --- a/src/muz_qe/dl_mk_extract_quantifiers.h +++ b/src/muz_qe/dl_mk_extract_quantifiers.h @@ -77,7 +77,7 @@ namespace datalog { void set_query(func_decl* q); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); bool has_quantifiers() { return m_has_quantifiers; } diff --git a/src/muz_qe/dl_mk_filter_rules.cpp b/src/muz_qe/dl_mk_filter_rules.cpp index 46fde4bc2..62abd78c4 100644 --- a/src/muz_qe/dl_mk_filter_rules.cpp +++ b/src/muz_qe/dl_mk_filter_rules.cpp @@ -150,7 +150,7 @@ namespace datalog { } } - rule_set * mk_filter_rules::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_filter_rules::operator()(rule_set const & source) { // TODO mc, pc m_tail2filter.reset(); m_result = alloc(rule_set, m_context); diff --git a/src/muz_qe/dl_mk_filter_rules.h b/src/muz_qe/dl_mk_filter_rules.h index daa72e36f..4a247fdb5 100644 --- a/src/muz_qe/dl_mk_filter_rules.h +++ b/src/muz_qe/dl_mk_filter_rules.h @@ -72,7 +72,7 @@ namespace datalog { /** \brief Return a new rule set where only filter rules contain atoms with repeated variables and/or values. */ - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index a48b7b32f..27b99cf98 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -572,7 +572,7 @@ namespace datalog { return modified; } - rule_set * mk_interp_tail_simplifier::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_interp_tail_simplifier::operator()(rule_set const & source) { if (source.get_num_rules() == 0) { return 0; } diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.h b/src/muz_qe/dl_mk_interp_tail_simplifier.h index 4cb14914a..247b20755 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.h +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.h @@ -93,7 +93,7 @@ namespace datalog { */ bool transform_rule(rule * r, rule_ref& res); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index d44b31979..982bdfd74 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -520,7 +520,7 @@ namespace datalog { m_hb.set_cancel(true); } - rule_set * mk_karr_invariants::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_karr_invariants::operator()(rule_set const & source) { if (!m_ctx.get_params().karr()) { return 0; } @@ -590,7 +590,7 @@ namespace datalog { for (; it != end; ++it) { update_body(*rules, **it); } - if (mc) { + if (m_ctx.get_model_converter()) { add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m); rule_set::decl2rules::iterator git = source.begin_grouped_rules(); rule_set::decl2rules::iterator gend = source.end_grouped_rules(); @@ -601,7 +601,7 @@ namespace datalog { kmc->add(p, *M); } } - mc = concat(mc.get(), kmc); + m_ctx.add_model_converter(kmc); } TRACE("dl", rules->display(tout);); return rules; diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index 7cd26d495..8abab9d7e 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -69,7 +69,7 @@ namespace datalog { virtual void cancel(); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; diff --git a/src/muz_qe/dl_mk_magic_sets.cpp b/src/muz_qe/dl_mk_magic_sets.cpp index 990040ab8..6885edc4e 100644 --- a/src/muz_qe/dl_mk_magic_sets.cpp +++ b/src/muz_qe/dl_mk_magic_sets.cpp @@ -317,8 +317,8 @@ namespace datalog { m_rules.push_back(r); } - rule_set * mk_magic_sets::operator()(rule_set const & source, model_converter_ref& mc) { - SASSERT(!mc); + rule_set * mk_magic_sets::operator()(rule_set const & source) { + SASSERT(!m_context.get_model_converter()); unsigned init_rule_cnt = source.get_num_rules(); { func_decl_set intentional; diff --git a/src/muz_qe/dl_mk_magic_sets.h b/src/muz_qe/dl_mk_magic_sets.h index 3f50e6713..2dc91c7e8 100644 --- a/src/muz_qe/dl_mk_magic_sets.h +++ b/src/muz_qe/dl_mk_magic_sets.h @@ -121,7 +121,7 @@ namespace datalog { */ mk_magic_sets(context & ctx, rule * goal_rule); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_partial_equiv.cpp b/src/muz_qe/dl_mk_partial_equiv.cpp index b55f5294e..35f8ff8df 100644 --- a/src/muz_qe/dl_mk_partial_equiv.cpp +++ b/src/muz_qe/dl_mk_partial_equiv.cpp @@ -86,7 +86,7 @@ namespace datalog { } - rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source) { // TODO mc if (source.get_num_rules() == 0) { diff --git a/src/muz_qe/dl_mk_partial_equiv.h b/src/muz_qe/dl_mk_partial_equiv.h index c44d59e8c..54a70b3c0 100644 --- a/src/muz_qe/dl_mk_partial_equiv.h +++ b/src/muz_qe/dl_mk_partial_equiv.h @@ -35,7 +35,7 @@ namespace datalog { m(ctx.get_manager()), m_context(ctx) {} - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); private: diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp index 047ed768f..91cfbe3fc 100644 --- a/src/muz_qe/dl_mk_rule_inliner.cpp +++ b/src/muz_qe/dl_mk_rule_inliner.cpp @@ -241,8 +241,10 @@ namespace datalog { return false; } - //these conditions are optional, they avoid possible exponential increase - //in the size of the problem + // + // these conditions are optional, they avoid possible exponential increase + // in the size of the problem + // return //m_head_pred_non_empty_tails_ctr.get(pred)<=1 @@ -837,7 +839,7 @@ namespace datalog { return done_something; } - rule_set * mk_rule_inliner::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_rule_inliner::operator()(rule_set const & source) { bool something_done = false; ref hsmc; @@ -854,7 +856,7 @@ namespace datalog { } - if (mc) { + if (m_context.get_model_converter()) { hsmc = alloc(horn_subsume_model_converter, m); } m_mc = hsmc.get(); @@ -881,9 +883,7 @@ namespace datalog { res = 0; } else { - if (mc) { - mc = concat(mc.get(), hsmc.get()); - } + m_context.add_model_converter(hsmc.get()); } return res.detach(); diff --git a/src/muz_qe/dl_mk_rule_inliner.h b/src/muz_qe/dl_mk_rule_inliner.h index a58b3b473..5ef8db7eb 100644 --- a/src/muz_qe/dl_mk_rule_inliner.h +++ b/src/muz_qe/dl_mk_rule_inliner.h @@ -196,7 +196,7 @@ namespace datalog { {} virtual ~mk_rule_inliner() { } - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index dfd0a4d81..9868c82f6 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -500,7 +500,7 @@ namespace datalog { } } - rule_set * mk_similarity_compressor::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_similarity_compressor::operator()(rule_set const & source) { // TODO mc m_modified = false; unsigned init_rule_cnt = source.get_num_rules(); diff --git a/src/muz_qe/dl_mk_similarity_compressor.h b/src/muz_qe/dl_mk_similarity_compressor.h index d1ded01e7..6e0ca9db5 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.h +++ b/src/muz_qe/dl_mk_similarity_compressor.h @@ -69,7 +69,7 @@ namespace datalog { public: mk_similarity_compressor(context & ctx, unsigned threshold_count); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_simple_joins.cpp b/src/muz_qe/dl_mk_simple_joins.cpp index f19e34fec..3a3f96acf 100644 --- a/src/muz_qe/dl_mk_simple_joins.cpp +++ b/src/muz_qe/dl_mk_simple_joins.cpp @@ -718,8 +718,7 @@ namespace datalog { } }; - rule_set * mk_simple_joins::operator()(rule_set const & source, model_converter_ref& mc) { - // TODO mc + rule_set * mk_simple_joins::operator()(rule_set const & source) { rule_set rs_aux_copy(m_context); rs_aux_copy.add_rules(source); if(!rs_aux_copy.is_closed()) { diff --git a/src/muz_qe/dl_mk_simple_joins.h b/src/muz_qe/dl_mk_simple_joins.h index df8d3f55c..89832626f 100644 --- a/src/muz_qe/dl_mk_simple_joins.h +++ b/src/muz_qe/dl_mk_simple_joins.h @@ -53,7 +53,7 @@ namespace datalog { public: mk_simple_joins(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_slice.cpp b/src/muz_qe/dl_mk_slice.cpp index 0adab78ce..c98d6503e 100644 --- a/src/muz_qe/dl_mk_slice.cpp +++ b/src/muz_qe/dl_mk_slice.cpp @@ -802,7 +802,7 @@ namespace datalog { } } - rule_set * mk_slice::operator()(rule_set const & src, model_converter_ref& mc) { + rule_set * mk_slice::operator()(rule_set const & src) { for (unsigned i = 0; i < src.get_num_rules(); ++i) { if (src.get_rule(i)->has_quantifiers()) { return 0; @@ -813,7 +813,7 @@ namespace datalog { if (m_ctx.generate_proof_trace()) { spc = alloc(slice_proof_converter, m_ctx); } - if (mc) { + if (m_ctx.get_model_converter()) { smc = alloc(slice_model_converter, *this, m); } m_pc = spc.get(); @@ -836,7 +836,7 @@ namespace datalog { } } m_ctx.add_proof_converter(spc.get()); - mc = concat(mc.get(), smc.get()); + m_ctx.add_model_converter(smc.get()); return result; } diff --git a/src/muz_qe/dl_mk_slice.h b/src/muz_qe/dl_mk_slice.h index 4290ee4b9..1b4312e77 100644 --- a/src/muz_qe/dl_mk_slice.h +++ b/src/muz_qe/dl_mk_slice.h @@ -102,7 +102,7 @@ namespace datalog { virtual ~mk_slice() { } - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); func_decl* get_predicate(func_decl* p) { func_decl* q = p; m_predicates.find(p, q); return q; } diff --git a/src/muz_qe/dl_mk_subsumption_checker.cpp b/src/muz_qe/dl_mk_subsumption_checker.cpp index 2f0d56475..fb55a377c 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.cpp +++ b/src/muz_qe/dl_mk_subsumption_checker.cpp @@ -332,7 +332,7 @@ namespace datalog { } } - rule_set * mk_subsumption_checker::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_subsumption_checker::operator()(rule_set const & source) { // TODO mc m_have_new_total_rule = false; diff --git a/src/muz_qe/dl_mk_subsumption_checker.h b/src/muz_qe/dl_mk_subsumption_checker.h index a95f08c5d..59904b3ef 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.h +++ b/src/muz_qe/dl_mk_subsumption_checker.h @@ -84,7 +84,7 @@ namespace datalog { reset_dealloc_values(m_ground_unconditional_rule_heads); } - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_unbound_compressor.cpp b/src/muz_qe/dl_mk_unbound_compressor.cpp index 54b6f4ebe..40926c2a8 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.cpp +++ b/src/muz_qe/dl_mk_unbound_compressor.cpp @@ -334,7 +334,7 @@ namespace datalog { } } - rule_set * mk_unbound_compressor::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_unbound_compressor::operator()(rule_set const & source) { // TODO mc m_modified = false; diff --git a/src/muz_qe/dl_mk_unbound_compressor.h b/src/muz_qe/dl_mk_unbound_compressor.h index 256be180d..cad953783 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.h +++ b/src/muz_qe/dl_mk_unbound_compressor.h @@ -82,7 +82,7 @@ namespace datalog { public: mk_unbound_compressor(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_mk_unfold.cpp b/src/muz_qe/dl_mk_unfold.cpp index 7af82110a..dfbd87122 100644 --- a/src/muz_qe/dl_mk_unfold.cpp +++ b/src/muz_qe/dl_mk_unfold.cpp @@ -50,7 +50,7 @@ namespace datalog { } } - rule_set * mk_unfold::operator()(rule_set const & source, model_converter_ref& mc) { + rule_set * mk_unfold::operator()(rule_set const & source) { rule_set* rules = alloc(rule_set, m_ctx); rule_set::iterator it = source.begin(), end = source.end(); for (; it != end; ++it) { diff --git a/src/muz_qe/dl_mk_unfold.h b/src/muz_qe/dl_mk_unfold.h index 90aefa86e..26f64926d 100644 --- a/src/muz_qe/dl_mk_unfold.h +++ b/src/muz_qe/dl_mk_unfold.h @@ -44,7 +44,7 @@ namespace datalog { */ mk_unfold(context & ctx); - rule_set * operator()(rule_set const & source, model_converter_ref& mc); + rule_set * operator()(rule_set const & source); }; }; diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index 5ecbf2b45..50a3f3310 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -73,7 +73,7 @@ namespace datalog { m_dirty=true; } - bool rule_transformer::operator()(rule_set & rules, model_converter_ref& mc) { + bool rule_transformer::operator()(rule_set & rules) { ensure_ordered(); bool modified = false; @@ -87,7 +87,7 @@ namespace datalog { for(; it!=end && !m_cancel; ++it) { plugin & p = **it; - rule_set * new_rules = p(rules, mc); + rule_set * new_rules = p(rules); if (!new_rules) { continue; } diff --git a/src/muz_qe/dl_rule_transformer.h b/src/muz_qe/dl_rule_transformer.h index 3b2140caf..2dbf25118 100644 --- a/src/muz_qe/dl_rule_transformer.h +++ b/src/muz_qe/dl_rule_transformer.h @@ -23,7 +23,6 @@ Revision History: #include"vector.h" #include"dl_rule.h" #include"dl_rule_set.h" -#include"model_converter.h" namespace datalog { @@ -68,7 +67,7 @@ namespace datalog { \brief Transform the rule set using the registered transformation plugins. If the rule set has changed, return true; otherwise return false. */ - bool operator()(rule_set & rules, model_converter_ref& mc); + bool operator()(rule_set & rules); }; class rule_transformer::plugin { @@ -104,8 +103,7 @@ namespace datalog { The caller takes ownership of the returned \c rule_set object. */ - virtual rule_set * operator()(rule_set const & source, - model_converter_ref& mc) = 0; + virtual rule_set * operator()(rule_set const & source) = 0; virtual void cancel() { m_cancel = true; } diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 9fbd8cc2e..0b6b664ec 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -997,11 +997,9 @@ void hilbert_basis::select_inequality() { unsigned best = m_current_ineq; unsigned non_zeros = get_num_nonzeros(m_ineqs[best]); unsigned prod = get_ineq_product(m_ineqs[best]); - //numeral diff = get_ineq_diff(m_ineqs[best]); for (unsigned j = best+1; prod != 0 && j < m_ineqs.size(); ++j) { unsigned non_zeros2 = get_num_nonzeros(m_ineqs[j]); unsigned prod2 = get_ineq_product(m_ineqs[j]); - //numeral diff2 = get_ineq_diff(m_ineqs[j]); if (prod2 == 0) { prod = prod2; non_zeros = non_zeros2; @@ -1010,7 +1008,6 @@ void hilbert_basis::select_inequality() { } if (non_zeros2 < non_zeros || (non_zeros2 == non_zeros && prod2 < prod)) { prod = prod2; - // diff = diff2; non_zeros = non_zeros2; best = j; } From 6ed266e4dee0cc0526a6f28340e779b620e4785b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Mar 2013 08:53:46 -0700 Subject: [PATCH 045/281] debugging karr invariants Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_array_blast.cpp | 11 +-- src/muz_qe/dl_mk_array_blast.h | 2 + src/muz_qe/dl_mk_bit_blast.cpp | 4 +- src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 43 +++++------ src/muz_qe/dl_mk_karr_invariants.cpp | 67 ++++++++++++----- src/muz_qe/dl_mk_karr_invariants.h | 6 +- src/muz_qe/dl_rule_set.h | 2 +- src/muz_qe/dl_rule_transformer.cpp | 6 +- src/muz_qe/dl_rule_transformer.h | 8 +-- src/muz_qe/fdd.cpp | 17 ++--- src/muz_qe/hilbert_basis.cpp | 6 +- src/test/hilbert_basis.cpp | 12 ++++ src/test/karr.cpp | 80 +++++++++++++++++++++ 13 files changed, 196 insertions(+), 68 deletions(-) diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp index 048269c5a..adf08662a 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz_qe/dl_mk_array_blast.cpp @@ -30,7 +30,8 @@ namespace datalog { m(ctx.get_manager()), a(m), rm(ctx.get_rule_manager()), - m_rewriter(m, m_params){ + m_rewriter(m, m_params), + m_simplifier(ctx) { m_params.set_bool("expand_select_store",true); m_rewriter.updt_params(m_params); } @@ -202,9 +203,11 @@ namespace datalog { SASSERT(new_rules.size() == 1); TRACE("dl", new_rules[0]->display(m_ctx, tout << "new rule\n");); - - rules.add_rule(new_rules[0].get()); - rm.mk_rule_rewrite_proof(r, *new_rules[0].get()); + rule_ref new_rule(rm); + if (m_simplifier.transform_rule(new_rules[0].get(), new_rule)) { + rules.add_rule(new_rule.get()); + rm.mk_rule_rewrite_proof(r, *new_rule.get()); + } return true; } diff --git a/src/muz_qe/dl_mk_array_blast.h b/src/muz_qe/dl_mk_array_blast.h index 94eb64601..4680821a2 100644 --- a/src/muz_qe/dl_mk_array_blast.h +++ b/src/muz_qe/dl_mk_array_blast.h @@ -22,6 +22,7 @@ Revision History: #include"dl_context.h" #include"dl_rule_set.h" #include"dl_rule_transformer.h" +#include"dl_mk_interp_tail_simplifier.h" #include "equiv_proof_converter.h" #include "array_decl_plugin.h" @@ -37,6 +38,7 @@ namespace datalog { rule_manager& rm; params_ref m_params; th_rewriter m_rewriter; + mk_interp_tail_simplifier m_simplifier; typedef obj_map defs_t; diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 338eed0b4..9dfd9deba 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -223,7 +223,9 @@ namespace datalog { expr_ref fml1(m), fml2(m), fml3(m); rule_ref r2(m_context.get_rule_manager()); // We need to simplify rule before bit-blasting. - m_simplifier.transform_rule(r, r2); + if (!m_simplifier.transform_rule(r, r2)) { + r2 = r; + } r2->to_formula(fml1); m_blaster(fml1, fml2, pr); m_rewriter(fml2, fml3); diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index a48b7b32f..35fd630f9 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -469,7 +469,7 @@ namespace datalog { start: unsigned u_len = r->get_uninterpreted_tail_size(); unsigned len = r->get_tail_size(); - if (u_len==len) { + if (u_len == len) { res = r; return true; } @@ -504,34 +504,29 @@ namespace datalog { expr_ref simp_res(m); simplify_expr(itail.get(), simp_res); - modified |= itail.get()!=simp_res.get(); - - if (is_app(simp_res.get())) { - itail = to_app(simp_res.get()); - } - else if (m.is_bool(simp_res)) { - itail = m.mk_eq(simp_res, m.mk_true()); - } - else { - throw default_exception("simplification resulted in non-boolean non-function"); - } - - if (m.is_false(itail.get())) { - //the tail member is never true, so we may delete the rule + modified |= itail.get() != simp_res.get(); + + if (m.is_false(simp_res)) { TRACE("dl", r->display(m_context, tout << "rule is infeasible\n");); return false; } - if (!m.is_true(itail.get())) { - //if the simplified tail is not a tautology, we add it to the rule - tail.push_back(itail); - tail_neg.push_back(false); - } - else { - modified = true; - } + SASSERT(m.is_bool(simp_res)); - SASSERT(tail.size() == tail_neg.size()); if (modified) { + expr_ref_vector conjs(m); + flatten_and(simp_res, conjs); + for (unsigned i = 0; i < conjs.size(); ++i) { + expr* e = conjs[i].get(); + if (is_app(e)) { + tail.push_back(to_app(e)); + } + else { + tail.push_back(m.mk_eq(e, m.mk_true())); + } + tail_neg.push_back(false); + } + + SASSERT(tail.size() == tail_neg.size()); res = m_context.get_rule_manager().mk(head, tail.size(), tail.c_ptr(), tail_neg.c_ptr()); res->set_accounting_parent_object(m_context, r); } diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index d44b31979..013923045 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -62,12 +62,38 @@ namespace datalog { return *this; } + void mk_karr_invariants::matrix::display_row( + std::ostream& out, vector const& row, rational const& b, bool is_eq) { + for (unsigned j = 0; j < row.size(); ++j) { + out << row[j] << " "; + } + out << (is_eq?" = ":" >= ") << -b << "\n"; + } + + void mk_karr_invariants::matrix::display_ineq( + std::ostream& out, vector const& row, rational const& b, bool is_eq) { + bool first = true; + for (unsigned j = 0; j < row.size(); ++j) { + if (!row[j].is_zero()) { + if (!first && row[j].is_pos()) { + out << "+ "; + } + if (row[j].is_minus_one()) { + out << "- "; + } + if (row[j] > rational(1) || row[j] < rational(-1)) { + out << row[j] << "*"; + } + out << "x" << j << " "; + first = false; + } + } + out << (is_eq?"= ":">= ") << -b << "\n"; + } + void mk_karr_invariants::matrix::display(std::ostream& out) const { for (unsigned i = 0; i < A.size(); ++i) { - for (unsigned j = 0; j < A[i].size(); ++j) { - out << A[i][j] << " "; - } - out << (eq[i]?" = ":" >= ") << -b[i] << "\n"; + display_row(out, A[i], b[i], eq[i]); } } @@ -182,24 +208,28 @@ namespace datalog { M.b.push_back(b); M.eq.push_back(true); } - else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { M.A.push_back(row); M.b.push_back(b); M.eq.push_back(false); } - else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { M.A.push_back(row); - M.b.push_back(b + rational(1)); + M.b.push_back(b - rational(1)); M.eq.push_back(false); } - else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { M.A.push_back(row); M.b.push_back(b); M.eq.push_back(false); } - else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { M.A.push_back(row); - M.b.push_back(b + rational(1)); + M.b.push_back(b - rational(1)); M.eq.push_back(false); } else if (m.is_or(e, e1, e2) && is_eq(e1, v, n1) && is_eq(e2, w, n2) && v == w) { @@ -221,7 +251,9 @@ namespace datalog { else { processed = false; } - TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n";); + TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n"; + if (processed) matrix::display_ineq(tout, row, M.b.back(), M.eq.back()); + ); } // intersect with the head predicate. app* head = r.get_head(); @@ -270,6 +302,7 @@ namespace datalog { M.b.push_back(MD.b[i]); M.eq.push_back(true); } + TRACE("dl", M.display(tout << r.get_decl()->get_name() << "\n");); return true; } @@ -322,7 +355,7 @@ namespace datalog { m_hb.set_is_int(i); } lbool is_sat = m_hb.saturate(); - TRACE("dl", m_hb.display(tout);); + TRACE("dl_verbose", m_hb.display(tout);); SASSERT(is_sat == l_true); unsigned basis_size = m_hb.get_basis_size(); for (unsigned i = 0; i < basis_size; ++i) { @@ -353,7 +386,7 @@ namespace datalog { m_hb.set_is_int(i); } lbool is_sat = m_hb.saturate(); - TRACE("dl", m_hb.display(tout);); + TRACE("dl_verbose", m_hb.display(tout);); SASSERT(is_sat == l_true); dst.reset(); unsigned basis_size = m_hb.get_basis_size(); @@ -532,7 +565,7 @@ namespace datalog { } } bool change = true, non_empty = false; - while (!m_cancel && change) { + while (!m_ctx.canceled() && change) { change = false; it = source.begin(); for (; it != end; ++it) { @@ -550,8 +583,8 @@ namespace datalog { dualizeH(P, ND); TRACE("dl", - MD.display(tout << "MD\n"); - P.display(tout << "P\n");); + ND.display(tout << "ND\n"); + P.display(tout << "P\n");); if (!N) { change = true; @@ -569,7 +602,7 @@ namespace datalog { return 0; } - if (m_cancel) { + if (m_ctx.canceled()) { return 0; } diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index 7cd26d495..d70fb374b 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -41,6 +41,10 @@ namespace datalog { matrix& operator=(matrix const& other); void append(matrix const& other) { A.append(other.A); b.append(other.b); eq.append(other.eq); } void display(std::ostream& out) const; + static void display_row( + std::ostream& out, vector const& row, rational const& b, bool is_eq); + static void display_ineq( + std::ostream& out, vector const& row, rational const& b, bool is_eq); }; class add_invariant_model_converter; @@ -67,7 +71,7 @@ namespace datalog { virtual ~mk_karr_invariants(); - virtual void cancel(); + virtual void cancel(); rule_set * operator()(rule_set const & source, model_converter_ref& mc); diff --git a/src/muz_qe/dl_rule_set.h b/src/muz_qe/dl_rule_set.h index fdbbf7626..3079c6072 100644 --- a/src/muz_qe/dl_rule_set.h +++ b/src/muz_qe/dl_rule_set.h @@ -46,7 +46,7 @@ namespace datalog { ast_mark m_visited; - //we need to take care with removing to aviod memory leaks + //we need to take care with removing to avoid memory leaks void remove_m_data_entry(func_decl * key); //sometimes we need to return reference to an empty set, diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index 5ecbf2b45..7e0e951e1 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -26,7 +26,7 @@ Revision History: namespace datalog { rule_transformer::rule_transformer(context & ctx) - : m_context(ctx), m_rule_manager(m_context.get_rule_manager()), m_dirty(false), m_cancel(false) { + : m_context(ctx), m_rule_manager(m_context.get_rule_manager()), m_dirty(false) { } @@ -42,11 +42,9 @@ namespace datalog { } m_plugins.reset(); m_dirty = false; - m_cancel = false; } void rule_transformer::cancel() { - m_cancel = true; plugin_vector::iterator it = m_plugins.begin(); plugin_vector::iterator end = m_plugins.end(); for(; it!=end; ++it) { @@ -84,7 +82,7 @@ namespace datalog { ); plugin_vector::iterator it = m_plugins.begin(); plugin_vector::iterator end = m_plugins.end(); - for(; it!=end && !m_cancel; ++it) { + for(; it!=end && !m_context.canceled(); ++it) { plugin & p = **it; rule_set * new_rules = p(rules, mc); diff --git a/src/muz_qe/dl_rule_transformer.h b/src/muz_qe/dl_rule_transformer.h index 3b2140caf..87ff10fb0 100644 --- a/src/muz_qe/dl_rule_transformer.h +++ b/src/muz_qe/dl_rule_transformer.h @@ -41,7 +41,6 @@ namespace datalog { context & m_context; rule_manager & m_rule_manager; bool m_dirty; - volatile bool m_cancel; svector m_plugins; void ensure_ordered(); @@ -81,7 +80,6 @@ namespace datalog { void attach(rule_transformer & transformer) { m_transformer = &transformer; } protected: - volatile bool m_cancel; /** \brief Create a plugin object for rule_transformer. @@ -90,7 +88,7 @@ namespace datalog { (higher priority plugins will be applied first). */ plugin(unsigned priority, bool can_destratify_negation = false) : m_priority(priority), - m_can_destratify_negation(can_destratify_negation), m_transformer(0), m_cancel(false) {} + m_can_destratify_negation(can_destratify_negation), m_transformer(0) {} public: virtual ~plugin() {} @@ -98,6 +96,8 @@ namespace datalog { unsigned get_priority() { return m_priority; } bool can_destratify_negation() const { return m_can_destratify_negation; } + virtual void cancel() {} + /** \brief Return \c rule_set object with containing transformed rules or 0 if no transformation was done. @@ -107,8 +107,6 @@ namespace datalog { virtual rule_set * operator()(rule_set const & source, model_converter_ref& mc) = 0; - virtual void cancel() { m_cancel = true; } - /** Removes duplicate tails. */ diff --git a/src/muz_qe/fdd.cpp b/src/muz_qe/fdd.cpp index afb5206cc..6c3bc0974 100644 --- a/src/muz_qe/fdd.cpp +++ b/src/muz_qe/fdd.cpp @@ -97,14 +97,14 @@ node_id manager::mk_node(unsigned var, node_id lo, node_id hi) { inc_ref(hi); } - TRACE("mtdd", tout << "mk_node: " << var << " " << lo << " " << hi << " -> " << result << "\n";); + TRACE("fdd", tout << "mk_node: " << var << " " << lo << " " << hi << " -> " << result << "\n";); return result; } void manager::inc_ref(node_id n) { - TRACE("mtdd", tout << "incref: " << n << "\n";); + TRACE("fdd", tout << "incref: " << n << "\n";); if (!is_leaf(n)) { m_nodes[n].inc_ref(); } @@ -126,6 +126,7 @@ void manager::setup_keys(Key const* keys) { void manager::insert(Key const* keys) { setup_keys(keys); + m_insert_cache.reset(); node_id result = insert_sign(m_num_idx + m_num_keys, m_root); inc_ref(result); dec_ref(m_root); @@ -161,7 +162,7 @@ node_id manager::insert_sign(unsigned idx, node_id n) { node_id manager::insert(unsigned idx, node_id n) { node_id result; SASSERT(0 <= idx && idx <= m_num_idx); - TRACE("mtdd", tout << "insert: " << idx << " " << n << "\n";); + TRACE("fdd", tout << "insert: " << idx << " " << n << "\n";); if (is_leaf(n)) { while (idx > 0) { --idx; @@ -176,9 +177,8 @@ node_id manager::insert(unsigned idx, node_id n) { --idx; config c(m_dont_cares, idx, n); - insert_cache::key_data & kd = m_insert_cache.insert_if_not_there2(c, 0)->get_data(); - if (kd.m_value != 0) { - return kd.m_value; + if (m_insert_cache.find(c, result)) { + return result; } node nd = m_nodes[n]; @@ -209,7 +209,7 @@ node_id manager::insert(unsigned idx, node_id n) { } result = mk_node(idx, lo, hi); } - kd.m_value = result; + m_insert_cache.insert(c, result); return result; } @@ -263,11 +263,12 @@ bool manager::find_le(Key const* keys) { SASSERT(idx > 0); --idx; while (nc.var() < idx) { - if (idx2bit(idx)) { + if (idx2bit(idx) && is_dont_care(idx2key(idx))) { set_dont_care(idx2key(idx)); } --idx; } + SASSERT(nc.var() == idx); if (is_dont_care(idx2key(idx)) || idx2bit(idx)) { n = nc.hi(); } diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 221e9a706..69b8765a7 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -290,7 +290,7 @@ public: } void display(std::ostream& out) const { - // m_fdd.display(out); + m_fdd.display(out); } @@ -302,8 +302,8 @@ class hilbert_basis::index { // for positive weights a shared value index. // typedef value_index1 value_index; - // typedef value_index2 value_index; - typedef value_index3 value_index; + typedef value_index2 value_index; + // typedef value_index3 value_index; struct stats { unsigned m_num_find; diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index a5f554e5e..2f58cc3c8 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -514,6 +514,15 @@ static void tst16() { saturate_basis(hb); } +static void tst17() { + hilbert_basis hb; + hb.add_eq(vec(1, 0), R(0)); + hb.add_eq(vec(-1, 0), R(0)); + hb.add_eq(vec(0, 2), R(0)); + hb.add_eq(vec(0, -2), R(0)); + saturate_basis(hb); + +} void tst_hilbert_basis() { std::cout << "hilbert basis test\n"; @@ -522,6 +531,9 @@ void tst_hilbert_basis() { g_use_ordered_support = true; + tst17(); + return; + if (true) { tst1(); tst2(); diff --git a/src/test/karr.cpp b/src/test/karr.cpp index 3ac427a88..8770eac94 100644 --- a/src/test/karr.cpp +++ b/src/test/karr.cpp @@ -165,6 +165,28 @@ namespace karr { return v; } + static vector V(int i, int j, int k, int l, int m) { + vector v; + v.push_back(rational(i)); + v.push_back(rational(j)); + v.push_back(rational(k)); + v.push_back(rational(l)); + v.push_back(rational(m)); + return v; + } + + static vector V(int i, int j, int k, int l, int x, int y, int z) { + vector v; + v.push_back(rational(i)); + v.push_back(rational(j)); + v.push_back(rational(k)); + v.push_back(rational(l)); + v.push_back(rational(x)); + v.push_back(rational(y)); + v.push_back(rational(z)); + return v; + } + #define R(_x_) rational(_x_) @@ -206,8 +228,66 @@ namespace karr { e2.display(std::cout << "e2\n"); } + void tst2() { + /** + 0 0 0 0 0 0 0 = 0 + 0 0 0 0 0 0 0 = 0 + 0 0 0 0 0 0 0 = 0 + 0 0 0 0 0 0 0 = 0 + 0 0 0 0 1 0 0 = 0 + 0 0 0 0 -1 0 0 = 0 + 0 1 0 0 0 0 0 = 0 + 0 -1 0 0 0 0 0 = 0 + 0 0 0 2 0 0 0 = 0 + 0 0 0 -2 0 0 0 = 0 + */ + + matrix ND; + ND.A.push_back(V(0,0,0,0,1,0,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,0,0,0,-1,0,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,1,0,0,0,0,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,-1,0,0,0,0,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,0,0,2,0,0,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,0,0,-2,0,0,0)); ND.b.push_back(R(0)); + + ND.display(std::cout << "ND\n"); + + matrix N; + dualizeH(N, ND); + + N.display(std::cout << "N\n"); + + + } + + void tst3() { + /** + 0 0 0 0 1 0 0 = 0 + 0 0 0 0 -1 0 0 = 0 + 0 1 0 0 0 0 0 = 0 + 0 -1 0 0 0 0 0 = 0 + 0 0 0 2 0 0 0 = 0 + 0 0 0 -2 0 0 0 = 0 + */ + + matrix ND; + ND.A.push_back(V(1,0)); ND.b.push_back(R(0)); + ND.A.push_back(V(0,2)); ND.b.push_back(R(0)); + + ND.display(std::cout << "ND\n"); + + matrix N; + dualizeH(N, ND); + + N.display(std::cout << "N\n"); + + + } + }; void tst_karr() { + karr::tst3(); + return; karr::tst1(); } From 435c6dd365362737f70b3730b5d084bc111b90e2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Mar 2013 09:05:36 -0700 Subject: [PATCH 046/281] convert mega-bytes to bytes in env_params Signed-off-by: Nikolaj Bjorner --- src/util/env_params.cpp | 2 +- src/util/util.h | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/util/env_params.cpp b/src/util/env_params.cpp index 28d80d92d..b01a1c250 100644 --- a/src/util/env_params.cpp +++ b/src/util/env_params.cpp @@ -26,7 +26,7 @@ void env_params::updt_params() { params_ref p = gparams::get(); set_verbosity_level(p.get_uint("verbose", get_verbosity_level())); enable_warning_messages(p.get_bool("warning", true)); - memory::set_max_size(p.get_uint("memory_max_size", 0)); + memory::set_max_size(megabytes_to_bytes(p.get_uint("memory_max_size", 0))); memory::set_high_watermark(p.get_uint("memory_high_watermark", 0)); } diff --git a/src/util/util.h b/src/util/util.h index 3360c2282..8bcbce4a3 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -394,11 +394,14 @@ public: inline std::ostream & operator<<(std::ostream & out, escaped const & s) { s.display(out); return out; } -inline unsigned long long megabytes_to_bytes(unsigned b) { - if (b == UINT_MAX) - return UINT64_MAX; - else - return static_cast(b) * 1024ull * 1024ull; +inline size_t megabytes_to_bytes(unsigned mb) { + if (mb == UINT_MAX) + return SIZE_MAX; + unsigned long long b = static_cast(mb) * 1024ull * 1024ull; + size_t r = static_cast(b); + if (r != b) // overflow + r = SIZE_MAX; + return r; } void z3_bound_num_procs(); From cd48a5164e8009271fed347d8599ddf2f39f3c46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 29 Mar 2013 17:05:17 -0700 Subject: [PATCH 047/281] fix bug in hilbert_basis reset method. Missing reset of m_iseq Signed-off-by: Nikolaj Bjorner --- src/muz_qe/hilbert_basis.cpp | 22 ++++++++++++++++------ src/test/hilbert_basis.cpp | 20 +++++++++++++++++++- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 7aed98487..7b3e67487 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -731,16 +731,26 @@ bool hilbert_basis::is_invalid_offset(offset_t offs) { void hilbert_basis::reset() { m_ineqs.reset(); - m_basis.reset(); + m_iseq.reset(); m_store.reset(); + m_basis.reset(); m_free_list.reset(); - m_active.reset(); - m_passive->reset(); - m_passive2->reset(); + m_sos.reset(); m_zero.reset(); - m_index->reset(1); - m_ints.reset(); + m_active.reset(); + if (m_passive) { + m_passive->reset(); + } + if (m_passive2) { + m_passive2->reset(); + } m_cancel = false; + if (m_index) { + m_index->reset(1); + } + m_ints.reset(); + m_current_ineq = 0; + } void hilbert_basis::collect_statistics(statistics& st) const { diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index 2f58cc3c8..e0a4a8370 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -524,6 +524,20 @@ static void tst17() { } +static void tst18() { + hilbert_basis hb; + hb.add_eq(vec(0, 1), R(0)); + hb.add_eq(vec(1, -1), R(2)); + saturate_basis(hb); +} + +static void tst19() { + hilbert_basis hb; + hb.add_eq(vec(0, 1, 0), R(0)); + hb.add_eq(vec(1, -1, 0), R(2)); + saturate_basis(hb); +} + void tst_hilbert_basis() { std::cout << "hilbert basis test\n"; // tst3(); @@ -531,9 +545,13 @@ void tst_hilbert_basis() { g_use_ordered_support = true; - tst17(); + tst18(); return; + tst19(); + return; + tst17(); + if (true) { tst1(); tst2(); From 4138e17b3f49d2aad4505128bed9260851cee49e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 31 Mar 2013 16:40:10 -0700 Subject: [PATCH 048/281] extract karr invariants as a Datalog relation Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_base.h | 1 + src/muz_qe/dl_compiler.cpp | 12 +- src/muz_qe/dl_context.cpp | 4 +- src/muz_qe/dl_interval_relation.cpp | 8 +- src/muz_qe/dl_interval_relation.h | 1 - src/muz_qe/dl_mk_karr_invariants.cpp | 1311 +++++++++++++++++--------- src/muz_qe/dl_mk_karr_invariants.h | 109 ++- src/muz_qe/dl_relation_manager.cpp | 6 + src/muz_qe/dl_relation_manager.h | 1 + src/muz_qe/dl_rule_set.cpp | 160 ++-- src/muz_qe/dl_rule_set.h | 2 + src/muz_qe/hilbert_basis.cpp | 3 +- src/muz_qe/hilbert_basis.h | 5 +- src/muz_qe/rel_context.cpp | 31 +- src/muz_qe/rel_context.h | 2 +- 15 files changed, 1082 insertions(+), 574 deletions(-) diff --git a/src/muz_qe/dl_base.h b/src/muz_qe/dl_base.h index 872bf7565..6c53a4b27 100644 --- a/src/muz_qe/dl_base.h +++ b/src/muz_qe/dl_base.h @@ -233,6 +233,7 @@ namespace datalog { symbol const& get_name() const { return m_name; } + virtual void set_cancel(bool f) {} relation_manager & get_manager() const { return m_manager; } ast_manager& get_ast_manager() const { return datalog::get_ast_manager_from_rel_manager(m_manager); } diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index cc56df4b7..c898f7964 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -1028,21 +1028,23 @@ namespace datalog { func_decl * head_pred = *preds.begin(); const rule_vector & rules = m_rule_set.get_predicate_rules(head_pred); + + reg_idx output_delta; - if(!output_deltas.find(head_pred, output_delta)) { + if (!output_deltas.find(head_pred, output_delta)) { output_delta = execution_context::void_register; } rule_vector::const_iterator it = rules.begin(); rule_vector::const_iterator end = rules.end(); - for(; it!=end; ++it) { + for (; it != end; ++it) { rule * r = *it; SASSERT(r->get_head()->get_decl()==head_pred); compile_rule_evaluation(r, input_deltas, output_delta, false, acc); } - if(add_saturation_marks) { + if (add_saturation_marks) { //now the predicate is saturated, so we may mark it as such acc.push_back(instruction::mk_mark_saturated(m_context.get_manager(), head_pred)); } @@ -1068,7 +1070,7 @@ namespace datalog { for(; sit!=send; ++sit) { func_decl_set & strat_preds = **sit; - if(all_saturated(strat_preds)) { + if (all_saturated(strat_preds)) { //all predicates in stratum are saturated, so no need to compile rules for them continue; } @@ -1084,7 +1086,7 @@ namespace datalog { tout << "\n"; ); - if(is_nonrecursive_stratum(strat_preds)) { + if (is_nonrecursive_stratum(strat_preds)) { //this stratum contains just a single non-recursive rule compile_nonrecursive_stratum(strat_preds, input_deltas, output_deltas, add_saturation_marks, acc); } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 71ef7ad20..c667c7775 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -954,6 +954,7 @@ namespace datalog { if (m_pdr.get()) m_pdr->cancel(); if (m_bmc.get()) m_bmc->cancel(); if (m_tab.get()) m_tab->cancel(); + if (m_rel.get()) m_rel->set_cancel(true); } void context::cleanup() { @@ -962,6 +963,7 @@ namespace datalog { if (m_pdr.get()) m_pdr->cleanup(); if (m_bmc.get()) m_bmc->cleanup(); if (m_tab.get()) m_tab->cleanup(); + if (m_rel.get()) m_rel->set_cancel(false); } class context::engine_type_proc { @@ -1231,7 +1233,7 @@ namespace datalog { return m_rel->result_contains_fact(f); } - // TBD: algebraic data-types declarations will not be printed. + // NB: algebraic data-types declarations will not be printed. class free_func_visitor { ast_manager& m; func_decl_set m_funcs; diff --git a/src/muz_qe/dl_interval_relation.cpp b/src/muz_qe/dl_interval_relation.cpp index 150ba1c78..3397f2db0 100644 --- a/src/muz_qe/dl_interval_relation.cpp +++ b/src/muz_qe/dl_interval_relation.cpp @@ -21,6 +21,7 @@ Revision History: #include "optional.h" #include "ast_pp.h" #include "dl_interval_relation.h" +#include "bool_rewriter.h" namespace datalog { @@ -30,8 +31,7 @@ namespace datalog { interval_relation_plugin::interval_relation_plugin(relation_manager& m): relation_plugin(interval_relation_plugin::get_name(), m), m_empty(m_dep), - m_arith(get_ast_manager()), - m_bsimp(get_ast_manager()) { + m_arith(get_ast_manager()) { } bool interval_relation_plugin::can_handle_signature(const relation_signature & sig) { @@ -374,7 +374,6 @@ namespace datalog { void interval_relation::to_formula(expr_ref& fml) const { ast_manager& m = get_plugin().get_ast_manager(); arith_util& arith = get_plugin().m_arith; - basic_simplifier_plugin& bsimp = get_plugin().m_bsimp; expr_ref_vector conjs(m); relation_signature const& sig = get_signature(); for (unsigned i = 0; i < sig.size(); ++i) { @@ -405,7 +404,8 @@ namespace datalog { } } } - bsimp.mk_and(conjs.size(), conjs.c_ptr(), fml); + bool_rewriter br(m); + br.mk_and(conjs.size(), conjs.c_ptr(), fml); } diff --git a/src/muz_qe/dl_interval_relation.h b/src/muz_qe/dl_interval_relation.h index 0ff05719e..1a25f430f 100644 --- a/src/muz_qe/dl_interval_relation.h +++ b/src/muz_qe/dl_interval_relation.h @@ -34,7 +34,6 @@ namespace datalog { v_dependency_manager m_dep; interval m_empty; arith_util m_arith; - basic_simplifier_plugin m_bsimp; class join_fn; class project_fn; diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 77b52f2b9..6dca35cdf 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -33,36 +33,35 @@ Revision History: --*/ #include"dl_mk_karr_invariants.h" +#include"expr_safe_replace.h" +#include"bool_rewriter.h" namespace datalog { + mk_karr_invariants::mk_karr_invariants(context & ctx, unsigned priority): rule_transformer::plugin(priority, false), m_ctx(ctx), m(ctx.get_manager()), rm(ctx.get_rule_manager()), + m_inner_ctx(m, ctx.get_fparams()), a(m) { + params_ref params; + params.set_sym("default_relation", symbol("karr_relation")); + params.set_sym("engine", symbol("datalog")); + params.set_bool("karr", false); + m_inner_ctx.updt_params(params); } - mk_karr_invariants::~mk_karr_invariants() { - obj_map::iterator it = m_constraints.begin(), end = m_constraints.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } - it = m_dual_constraints.begin(); - end = m_dual_constraints.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } - } + mk_karr_invariants::~mk_karr_invariants() { } - mk_karr_invariants::matrix& mk_karr_invariants::matrix::operator=(matrix const& other) { + matrix& matrix::operator=(matrix const& other) { reset(); append(other); return *this; } - void mk_karr_invariants::matrix::display_row( + void matrix::display_row( std::ostream& out, vector const& row, rational const& b, bool is_eq) { for (unsigned j = 0; j < row.size(); ++j) { out << row[j] << " "; @@ -70,7 +69,7 @@ namespace datalog { out << (is_eq?" = ":" >= ") << -b << "\n"; } - void mk_karr_invariants::matrix::display_ineq( + void matrix::display_ineq( std::ostream& out, vector const& row, rational const& b, bool is_eq) { bool first = true; for (unsigned j = 0; j < row.size(); ++j) { @@ -91,391 +90,31 @@ namespace datalog { out << (is_eq?"= ":">= ") << -b << "\n"; } - void mk_karr_invariants::matrix::display(std::ostream& out) const { + void matrix::display(std::ostream& out) const { for (unsigned i = 0; i < A.size(); ++i) { display_row(out, A[i], b[i], eq[i]); } } - - bool mk_karr_invariants::is_linear(expr* e, vector& row, rational& b, rational const& mul) { - if (!a.is_int(e)) { - return false; - } - if (is_var(e)) { - row[to_var(e)->get_idx()] += mul; - return true; - } - if (!is_app(e)) { - return false; - } - rational n; - if (a.is_numeral(e, n)) { - b += mul*n; - return true; - } - if (a.is_add(e)) { - for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { - if (!is_linear(to_app(e)->get_arg(i), row, b, mul)) { - return false; - } - } - return true; - } - expr* e1, *e2; - if (a.is_sub(e, e1, e2)) { - return is_linear(e1, row, b, mul) && is_linear(e2, row, b, -mul); - } - if (a.is_mul(e, e1, e2) && a.is_numeral(e1, n)) { - return is_linear(e2, row, b, mul*n); - } - if (a.is_mul(e, e1, e2) && a.is_numeral(e2, n)) { - return is_linear(e1, row, b, mul*n); - } - if (a.is_uminus(e, e1)) { - return is_linear(e1, row, b, -mul); - } - return false; - } - - mk_karr_invariants::matrix* mk_karr_invariants::get_constraints(func_decl* p) { - matrix* result = 0; - m_constraints.find(p, result); - return result; - } - - mk_karr_invariants::matrix& mk_karr_invariants::get_dual_constraints(func_decl* p) { - matrix* result = 0; - if (!m_dual_constraints.find(p, result)) { - result = alloc(matrix); - m_dual_constraints.insert(p, result); - } - return *result; - } - - bool mk_karr_invariants::is_eq(expr* e, var*& v, rational& n) { - expr* e1, *e2; - if (!m.is_eq(e, e1, e2)) { - return false; - } - if (!is_var(e1)) { - std::swap(e1, e2); - } - if (!is_var(e1)) { - return false; - } - v = to_var(e1); - if (!a.is_numeral(e2, n)) { - return false; - } - return true; - } - bool mk_karr_invariants::get_transition_relation(rule const& r, matrix& M) { - unsigned num_vars = rm.get_counter().get_max_rule_var(r)+1; - unsigned arity = r.get_decl()->get_arity(); - unsigned num_columns = arity + num_vars; - unsigned utsz = r.get_uninterpreted_tail_size(); - unsigned tsz = r.get_tail_size(); - M.reset(); - - for (unsigned i = 0; i < utsz; ++i) { - matrix const* Mp = get_constraints(r.get_decl(i)); - if (!Mp) { - return false; - } - TRACE("dl", Mp->display(tout << "Intersect\n");); - intersect_matrix(r.get_tail(i), *Mp, num_columns, M); - } - - rational one(1), mone(-1); - expr* e1, *e2, *en; - var* v, *w; - rational n1, n2; - expr_ref_vector conjs(m); - for (unsigned i = utsz; i < tsz; ++i) { - conjs.push_back(r.get_tail(i)); - } - datalog::flatten_and(conjs); - - for (unsigned i = 0; i < conjs.size(); ++i) { - expr* e = conjs[i].get(); - rational b(0); - vector row; - row.resize(num_columns, rational(0)); - bool processed = true; - if (m.is_eq(e, e1, e2) && is_linear(e1, row, b, one) && is_linear(e2, row, b, mone)) { - M.A.push_back(row); - M.b.push_back(b); - M.eq.push_back(true); - } - else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b); - M.eq.push_back(false); - } - else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b - rational(1)); - M.eq.push_back(false); - } - else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b); - M.eq.push_back(false); - } - else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b - rational(1)); - M.eq.push_back(false); - } - else if (m.is_or(e, e1, e2) && is_eq(e1, v, n1) && is_eq(e2, w, n2) && v == w) { - if (n1 > n2) { - std::swap(n1, n2); - } - SASSERT(n1 <= n2); - row[v->get_idx()] = rational(1); - // v - n1 >= 0 - M.A.push_back(row); - M.b.push_back(-n1); - M.eq.push_back(false); - // -v + n2 >= 0 - row[v->get_idx()] = rational(-1); - M.A.push_back(row); - M.b.push_back(n2); - M.eq.push_back(false); - } - else { - processed = false; - } - TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n"; - if (processed) matrix::display_ineq(tout, row, M.b.back(), M.eq.back()); - ); - } - // intersect with the head predicate. - app* head = r.get_head(); - unsigned sz0 = M.A.size(); - for (unsigned i = 0; i < arity; ++i) { - rational n; - expr* arg = head->get_arg(i); - if (!a.is_int(arg)) { - // no-op - } - else if (is_var(arg)) { - vector row; - row.resize(num_columns, rational(0)); - unsigned idx = to_var(arg)->get_idx(); - row[idx] = rational(-1); - row[num_vars + i] = rational(1); - M.A.push_back(row); - M.b.push_back(rational(0)); - M.eq.push_back(true); - } - else if (a.is_numeral(arg, n)) { - vector row; - row.resize(num_columns, rational(0)); - row[num_vars + i] = rational(1); - M.A.push_back(row); - M.b.push_back(-n); - M.eq.push_back(true); - } - else { - UNREACHABLE(); - } - } - if (M.A.size() == sz0) { - return false; - } - - TRACE("dl", M.display(tout << r.get_decl()->get_name() << "\n");); - matrix MD; - dualizeI(MD, M); - M.reset(); - // project for variables in head. - for (unsigned i = 0; i < MD.size(); ++i) { - vector row; - row.append(arity, MD.A[i].c_ptr() + num_vars); - M.A.push_back(row); - M.b.push_back(MD.b[i]); - M.eq.push_back(true); - } - TRACE("dl", M.display(tout << r.get_decl()->get_name() << "\n");); - - return true; - } - - void mk_karr_invariants::intersect_matrix(app* p, matrix const& Mp, unsigned num_columns, matrix& M) { - for (unsigned j = 0; j < Mp.size(); ++j) { - rational b = Mp.b[j], n; - vector row; - row.resize(num_columns, rational(0)); - for (unsigned i = 0; i < p->get_num_args(); ++i) { - expr* arg = p->get_arg(i); - if (!a.is_int(arg)) { - // no-op - } - else if (is_var(arg)) { - unsigned idx = to_var(arg)->get_idx(); - row[idx] += Mp.A[j][i]; - } - else if (a.is_numeral(arg, n)) { - b += Mp.A[j][i]*n; - } - else { - UNREACHABLE(); - } - } - M.A.push_back(row); - M.b.push_back(b); - M.eq.push_back(Mp.eq[j]); - } - } - - // treat src as a homogeneous matrix. - void mk_karr_invariants::dualizeH(matrix& dst, matrix const& src) { - dst.reset(); - if (src.size() == 0) { - return; - } - m_hb.reset(); - for (unsigned i = 0; i < src.size(); ++i) { - vector v(src.A[i]); - v.push_back(src.b[i]); - if (src.eq[i]) { - m_hb.add_eq(v, rational(0)); - } - else { - m_hb.add_ge(v, rational(0)); - } - } - for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) { - m_hb.set_is_int(i); - } - lbool is_sat = m_hb.saturate(); - TRACE("dl_verbose", m_hb.display(tout);); - SASSERT(is_sat == l_true); - unsigned basis_size = m_hb.get_basis_size(); - for (unsigned i = 0; i < basis_size; ++i) { - bool is_initial; - vector soln; - m_hb.get_basis_solution(i, soln, is_initial); - if (!is_initial) { - dst.b.push_back(soln.back()); - dst.eq.push_back(true); - soln.pop_back(); - dst.A.push_back(soln); - } - } - } - - // treat src as an inhomegeneous matrix. - void mk_karr_invariants::dualizeI(matrix& dst, matrix const& src) { - m_hb.reset(); - for (unsigned i = 0; i < src.size(); ++i) { - if (src.eq[i]) { - m_hb.add_eq(src.A[i], -src.b[i]); - } - else { - m_hb.add_ge(src.A[i], -src.b[i]); - } - } - for (unsigned i = 0; !src.A.empty() && i < src.A[0].size(); ++i) { - m_hb.set_is_int(i); - } - lbool is_sat = m_hb.saturate(); - TRACE("dl_verbose", m_hb.display(tout);); - SASSERT(is_sat == l_true); - dst.reset(); - unsigned basis_size = m_hb.get_basis_size(); - bool first_initial = true; - for (unsigned i = 0; i < basis_size; ++i) { - bool is_initial; - vector soln; - m_hb.get_basis_solution(i, soln, is_initial); - if (is_initial && first_initial) { - dst.A.push_back(soln); - dst.b.push_back(rational(1)); - dst.eq.push_back(true); - first_initial = false; - } - else if (!is_initial) { - dst.A.push_back(soln); - dst.b.push_back(rational(0)); - dst.eq.push_back(true); - } - } - } - - void mk_karr_invariants::update_body(rule_set& rules, rule& r){ - unsigned utsz = r.get_uninterpreted_tail_size(); - unsigned tsz = r.get_tail_size(); - app_ref_vector tail(m); - for (unsigned i = 0; i < tsz; ++i) { - tail.push_back(r.get_tail(i)); - } - for (unsigned i = 0; i < utsz; ++i) { - func_decl* q = r.get_decl(i); - matrix* N = get_constraints(q); - if (!N) { - continue; - } - expr_ref zero(m), lhs(m); - zero = a.mk_numeral(rational(0), true); - for (unsigned j = 0; j < N->size(); ++j) { - rational n; - SASSERT(N->A[j].size() == q->get_arity()); - expr_ref_vector sum(m); - for (unsigned k = 0; k < N->A[j].size(); ++k) { - n = N->A[j][k]; - if (!n.is_zero()) { - expr* arg = r.get_tail(i)->get_arg(k); - sum.push_back(a.mk_mul(a.mk_numeral(n, true), arg)); - } - } - n = N->b[j]; - if (!n.is_zero()) { - sum.push_back(a.mk_numeral(n, true)); - } - lhs = a.mk_add(sum.size(), sum.c_ptr()); - if (N->eq[j]) { - tail.push_back(m.mk_eq(lhs, zero)); - } - else { - tail.push_back(a.mk_ge(lhs, zero)); - } - } - } - rule* new_rule = &r; - if (tail.size() != tsz) { - new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name()); - } - rules.add_rule(new_rule); - rm.mk_rule_rewrite_proof(r, *new_rule); // should be weakening rule. - } class mk_karr_invariants::add_invariant_model_converter : public model_converter { ast_manager& m; arith_util a; func_decl_ref_vector m_funcs; - ptr_vector m_invs; + expr_ref_vector m_invs; public: - add_invariant_model_converter(ast_manager& m): m(m), a(m), m_funcs(m) {} + add_invariant_model_converter(ast_manager& m): m(m), a(m), m_funcs(m), m_invs(m) {} - virtual ~add_invariant_model_converter() { - for (unsigned i = 0; i < m_invs.size(); ++i) { - dealloc(m_invs[i]); + virtual ~add_invariant_model_converter() { } + + void add(func_decl* p, expr* inv) { + if (!m.is_true(inv)) { + m_funcs.push_back(p); + m_invs.push_back(inv); } } - void add(func_decl* p, matrix& M) { - m_funcs.push_back(p); - m_invs.push_back(alloc(matrix, M)); - } - virtual void operator()(model_ref & mr) { for (unsigned i = 0; i < m_funcs.size(); ++i) { func_decl* p = m_funcs[i].get(); @@ -484,11 +123,9 @@ namespace datalog { unsigned arity = p->get_arity(); SASSERT(0 < arity); if (f) { - matrix const& M = *m_invs[i]; - mk_body(M, body); SASSERT(f->num_entries() == 0); if (!f->is_partial()) { - body = m.mk_and(f->get_else(), body); + bool_rewriter(m).mk_and(f->get_else(), m_invs[i].get(), body); } } else { @@ -503,7 +140,7 @@ namespace datalog { virtual model_converter * translate(ast_translation & translator) { add_invariant_model_converter* mc = alloc(add_invariant_model_converter, m); for (unsigned i = 0; i < m_funcs.size(); ++i) { - mc->add(translator(m_funcs[i].get()), *m_invs[i]); + mc->add(translator(m_funcs[i].get()), m_invs[i].get()); } return mc; } @@ -514,7 +151,7 @@ namespace datalog { for (unsigned i = 0; i < M.size(); ++i) { mk_body(M.A[i], M.b[i], M.eq[i], conj); } - body = m.mk_and(conj.size(), conj.c_ptr()); + bool_rewriter(m).mk_and(conj.size(), conj.c_ptr(), body); } void mk_body(vector const& row, rational const& b, bool is_eq, expr_ref_vector& conj) { @@ -545,12 +182,10 @@ namespace datalog { conj.push_back(a.mk_ge(lhs, zero)); } } - }; void mk_karr_invariants::cancel() { - rule_transformer::plugin::cancel(); - m_hb.set_cancel(true); + m_inner_ctx.cancel(); } rule_set * mk_karr_invariants::operator()(rule_set const & source) { @@ -564,64 +199,27 @@ namespace datalog { return 0; } } - bool change = true, non_empty = false; - while (!m_ctx.canceled() && change) { - change = false; - it = source.begin(); - for (; it != end; ++it) { - rule const& r = **it; - TRACE("dl", r.display(m_ctx, tout);); - matrix MD, P; - if (!get_transition_relation(r, MD)) { - continue; - } - non_empty = true; - func_decl* p = r.get_decl(); - matrix& ND = get_dual_constraints(p); - matrix* N = get_constraints(p); - ND.append(MD); - dualizeH(P, ND); - - TRACE("dl", - ND.display(tout << "ND\n"); - P.display(tout << "P\n");); - - if (!N) { - change = true; - N = alloc(matrix, P); - m_constraints.insert(p, N); - } - else if (P.size() != N->size()) { - change = true; - *N = P; - } - } + rel_context& rctx = m_inner_ctx.get_rel_context(); + ptr_vector heads; + m_inner_ctx.ensure_opened(); + it = source.begin(); + for (; it != end; ++it) { + rule_ref r(*it, m_ctx.get_rule_manager()); + m_inner_ctx.add_rule(r); + m_inner_ctx.register_predicate(r->get_decl()); } - - if (!non_empty) { - return 0; + m_inner_ctx.close(); + rule_set::decl2rules::iterator dit = source.begin_grouped_rules(); + rule_set::decl2rules::iterator dend = source.end_grouped_rules(); + for (; dit != dend; ++dit) { + heads.push_back(dit->m_key); } - - if (m_ctx.canceled()) { - return 0; - } - - TRACE("dl", - rule_set::decl2rules::iterator git = source.begin_grouped_rules(); - rule_set::decl2rules::iterator gend = source.end_grouped_rules(); - for (; git != gend; ++git) { - func_decl* p = git->m_key; - matrix* M = get_constraints(p); - tout << p->get_name() << "\n"; - if (M) { - M->display(tout); - } - }); + m_inner_ctx.rel_query(heads.size(), heads.c_ptr()); rule_set* rules = alloc(rule_set, m_ctx); it = source.begin(); for (; it != end; ++it) { - update_body(*rules, **it); + update_body(rctx, *rules, **it); } if (m_ctx.get_model_converter()) { add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m); @@ -629,9 +227,11 @@ namespace datalog { rule_set::decl2rules::iterator gend = source.end_grouped_rules(); for (; git != gend; ++git) { func_decl* p = git->m_key; - matrix* M = get_constraints(p); - if (M) { - kmc->add(p, *M); + expr_ref fml(m); + relation_base* rb = rctx.try_get_relation(p); + if (rb) { + rb->to_formula(fml); + kmc->add(p, fml); } } m_ctx.add_model_converter(kmc); @@ -640,5 +240,824 @@ namespace datalog { return rules; } + void mk_karr_invariants::update_body(rel_context& rctx, rule_set& rules, rule& r) { + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + app_ref_vector tail(m); + expr_ref fml(m); + for (unsigned i = 0; i < tsz; ++i) { + tail.push_back(r.get_tail(i)); + } + for (unsigned i = 0; i < utsz; ++i) { + func_decl* q = r.get_decl(i); + relation_base* rb = rctx.try_get_relation(r.get_decl(i)); + if (rb) { + rb->to_formula(fml); + expr_safe_replace rep(m); + for (unsigned j = 0; j < q->get_arity(); ++j) { + rep.insert(m.mk_var(j, q->get_domain(j)), + r.get_tail(i)->get_arg(j)); + } + rep(fml); + tail.push_back(to_app(fml)); + } + } + rule* new_rule = &r; + if (tail.size() != tsz) { + new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name()); + } + rules.add_rule(new_rule); + rm.mk_rule_rewrite_proof(r, *new_rule); // should be weakening rule. + } + + + + class karr_relation : public relation_base { + friend class karr_relation_plugin; + friend class karr_relation_plugin::filter_equal_fn; + + karr_relation_plugin& m_plugin; + ast_manager& m; + mutable arith_util a; + func_decl_ref m_fn; + mutable bool m_empty; + mutable matrix m_ineqs; + mutable bool m_ineqs_valid; + mutable matrix m_basis; + mutable bool m_basis_valid; + + public: + karr_relation(karr_relation_plugin& p, func_decl* f, relation_signature const& s, bool is_empty): + relation_base(p, s), + m_plugin(p), + m(p.get_ast_manager()), + a(m), + m_fn(f, m), + m_empty(is_empty), + m_ineqs_valid(!is_empty), + m_basis_valid(false) + { + } + + virtual bool empty() const { + return m_empty; + } + + virtual void add_fact(const relation_fact & f) { + SASSERT(m_empty); + SASSERT(!m_basis_valid); + m_empty = false; + m_ineqs_valid = true; + for (unsigned i = 0; i < f.size(); ++i) { + rational n; + if (a.is_numeral(f[i], n) && n.is_int()) { + vector row; + row.resize(f.size()); + row[i] = rational(1); + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(-n); + m_ineqs.eq.push_back(true); + } + } + } + + virtual bool contains_fact(const relation_fact & f) const { + UNREACHABLE(); + return false; + } + + virtual void display(std::ostream & out) const { + if (m_fn) { + out << m_fn->get_name() << "\n"; + } + if (empty()) { + out << "empty\n"; + } + else { + if (m_ineqs_valid) { + m_ineqs.display(out << "ineqs:\n"); + } + if (m_basis_valid) { + m_basis.display(out << "basis:\n"); + } + } + } + + virtual karr_relation * clone() const { + karr_relation* result = alloc(karr_relation, m_plugin, m_fn, get_signature(), m_empty); + result->copy(*this); + return result; + } + + virtual karr_relation * complement(func_decl*) const { + UNREACHABLE(); + return 0; + } + + virtual void to_formula(expr_ref& fml) const { + if (empty()) { + fml = m.mk_false(); + } + else { + matrix const& M = get_ineqs(); + expr_ref_vector conj(m); + for (unsigned i = 0; i < M.size(); ++i) { + to_formula(M.A[i], M.b[i], M.eq[i], conj); + } + bool_rewriter(m).mk_and(conj.size(), conj.c_ptr(), fml); + } + } + + karr_relation_plugin& get_plugin() const { return m_plugin; } + + void filter_interpreted(app* cond) { + rational one(1), mone(-1); + expr* e1, *e2, *en; + var* v, *w; + rational n1, n2; + expr_ref_vector conjs(m); + datalog::flatten_and(cond, conjs); + matrix& M = get_ineqs(); + unsigned num_columns = get_signature().size(); + + for (unsigned i = 0; i < conjs.size(); ++i) { + expr* e = conjs[i].get(); + rational b(0); + vector row; + row.resize(num_columns, rational(0)); + bool processed = true; + if (m.is_eq(e, e1, e2) && is_linear(e1, row, b, one) && is_linear(e2, row, b, mone)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(true); + } + else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(false); + } + else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b - rational(1)); + M.eq.push_back(false); + } + else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(false); + } + else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b - rational(1)); + M.eq.push_back(false); + } + else if (m.is_or(e, e1, e2) && is_eq(e1, v, n1) && is_eq(e2, w, n2) && v == w) { + if (n1 > n2) { + std::swap(n1, n2); + } + SASSERT(n1 <= n2); + row[v->get_idx()] = rational(1); + // v - n1 >= 0 + M.A.push_back(row); + M.b.push_back(-n1); + M.eq.push_back(false); + // -v + n2 >= 0 + row[v->get_idx()] = rational(-1); + M.A.push_back(row); + M.b.push_back(n2); + M.eq.push_back(false); + } + else { + processed = false; + } + TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n"; + if (processed) matrix::display_ineq(tout, row, M.b.back(), M.eq.back()); + ); + } + TRACE("dl", display(tout);); + } + + void mk_join(karr_relation const& r1, karr_relation const& r2, + unsigned col_cnt, unsigned const* cols1, unsigned const* cols2) { + if (r1.empty() || r2.empty()) { + m_empty = true; + return; + } + matrix const& M1 = r1.get_ineqs(); + matrix const& M2 = r2.get_ineqs(); + unsigned sig1_size = r1.get_signature().size(); + unsigned sig_size = get_signature().size(); + m_ineqs.reset(); + for (unsigned i = 0; i < M1.size(); ++i) { + vector row; + row.append(M1.A[i]); + row.resize(sig_size); + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(M1.b[i]); + m_ineqs.eq.push_back(M1.eq[i]); + } + for (unsigned i = 0; i < M2.size(); ++i) { + vector row; + row.resize(sig_size); + for (unsigned j = 0; j < M2.A[i].size(); ++j) { + row[sig1_size + j] = M2.A[i][j]; + } + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(M2.b[i]); + m_ineqs.eq.push_back(M2.eq[i]); + } + for (unsigned i = 0; i < col_cnt; ++i) { + vector row; + row.resize(sig_size); + row[cols1[i]] = rational(1); + row[sig1_size + cols2[i]] = rational(-1); + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(rational(0)); + m_ineqs.eq.push_back(true); + } + m_ineqs_valid = true; + m_basis_valid = false; + m_empty = false; + if (r1.m_fn) { + m_fn = r1.m_fn; + } + if (r2.m_fn) { + m_fn = r2.m_fn; + } + } + + void mk_project(karr_relation const& r, unsigned cnt, unsigned const* cols) { + if (r.m_empty) { + m_empty = true; + return; + } + matrix const& M = r.get_basis(); + m_basis.reset(); + for (unsigned i = 0; i < M.size(); ++i) { + vector row; + unsigned k = 0; + for (unsigned j = 0; j < M.A[i].size(); ++j) { + if (k < cnt && j == cols[k]) { + ++k; + } + else { + row.push_back(M.A[i][j]); + } + } + SASSERT(row.size() + cnt == M.A[i].size()); + SASSERT(M.eq[i]); + m_basis.A.push_back(row); + m_basis.b.push_back(M.b[i]); + m_basis.eq.push_back(true); + } + m_basis_valid = true; + m_ineqs_valid = false; + m_empty = false; + m_fn = r.m_fn; + + TRACE("dl", + for (unsigned i = 0; i < cnt; ++i) { + tout << cols[i] << " "; + } + tout << "\n"; + r.display(tout); + display(tout);); + } + + void mk_rename(const karr_relation & r, unsigned col_cnt, const unsigned * cols) { + if (r.empty()) { + m_empty = true; + return; + } + m_ineqs.reset(); + m_basis.reset(); + m_ineqs_valid = r.m_ineqs_valid; + m_basis_valid = r.m_basis_valid; + if (m_ineqs_valid) { + m_ineqs.append(r.m_ineqs); + mk_rename(m_ineqs, col_cnt, cols); + } + if (m_basis_valid) { + m_basis.append(r.m_basis); + mk_rename(m_basis, col_cnt, cols); + } + m_fn = r.m_fn; + TRACE("dl", r.display(tout); display(tout);); + } + + void mk_union(karr_relation const& src, karr_relation* delta) { + if (src.empty()) { + if (delta) { + delta->m_empty = true; + } + return; + } + matrix const& M = src.get_basis(); + if (empty()) { + m_basis = M; + m_basis_valid = true; + m_empty = false; + m_ineqs_valid = false; + if (delta) { + delta->copy(*this); + } + return; + } + matrix& N = get_basis(); + unsigned N_size = N.size(); + for (unsigned i = 0; i < M.size(); ++i) { + bool found = false; + for (unsigned j = 0; !found && j < N_size; ++j) { + found = + same_row(M.A[i], N.A[j]) && + M.b[i] == N.b[j] && + M.eq[i] == N.eq[j]; + } + if (!found) { + N.A.push_back(M.A[i]); + N.b.push_back(M.b[i]); + N.eq.push_back(M.eq[i]); + } + } + m_ineqs_valid = false; + if (N_size != N.size()) { + if (delta) { + delta->copy(*this); + } + } + } + + matrix const& get_basis() const { + init_basis(); + return m_basis; + } + + matrix& get_basis() { + init_basis(); + return m_basis; + } + + matrix const& get_ineqs() const { + init_ineqs(); + return m_ineqs; + } + + matrix & get_ineqs() { + init_ineqs(); + return m_ineqs; + } + + private: + + void copy(karr_relation const& other) { + m_ineqs = other.m_ineqs; + m_basis = other.m_basis; + m_basis_valid = other.m_basis_valid; + m_ineqs_valid = other.m_ineqs_valid; + m_empty = other.m_empty; + } + + bool same_row(vector const& r1, vector const& r2) const { + SASSERT(r1.size() == r2.size()); + for (unsigned i = 0; i < r1.size(); ++i) { + if (r1[i] != r2[i]) { + return false; + } + } + return true; + } + + void mk_rename(matrix& M, unsigned col_cnt, unsigned const* cols) { + for (unsigned j = 0; j < M.size(); ++j) { + vector & row = M.A[j]; + rational tmp = row[cols[0]]; + for (unsigned i = 0; i + 1 < col_cnt; ++i) { + row[cols[i]] = row[cols[i+1]]; + } + row[cols[col_cnt-1]] = tmp; + } + } + + bool is_eq(expr* e, var*& v, rational& n) { + expr* e1, *e2; + if (!m.is_eq(e, e1, e2)) { + return false; + } + if (!is_var(e1)) { + std::swap(e1, e2); + } + if (!is_var(e1)) { + return false; + } + v = to_var(e1); + if (!a.is_numeral(e2, n)) { + return false; + } + return true; + } + + bool is_linear(expr* e, vector& row, rational& b, rational const& mul) { + if (!a.is_int(e)) { + return false; + } + if (is_var(e)) { + row[to_var(e)->get_idx()] += mul; + return true; + } + if (!is_app(e)) { + return false; + } + rational n; + if (a.is_numeral(e, n)) { + b += mul*n; + return true; + } + if (a.is_add(e)) { + for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { + if (!is_linear(to_app(e)->get_arg(i), row, b, mul)) { + return false; + } + } + return true; + } + expr* e1, *e2; + if (a.is_sub(e, e1, e2)) { + return is_linear(e1, row, b, mul) && is_linear(e2, row, b, -mul); + } + if (a.is_mul(e, e1, e2) && a.is_numeral(e1, n)) { + return is_linear(e2, row, b, mul*n); + } + if (a.is_mul(e, e1, e2) && a.is_numeral(e2, n)) { + return is_linear(e1, row, b, mul*n); + } + if (a.is_uminus(e, e1)) { + return is_linear(e1, row, b, -mul); + } + return false; + } + + void init_ineqs() const { + if (!m_ineqs_valid) { + SASSERT(m_basis_valid); + m_plugin.dualizeH(m_ineqs, m_basis); + m_ineqs_valid = true; + } + } + + void init_basis() const { + if (!m_basis_valid) { + SASSERT(m_ineqs_valid); + if (m_plugin.dualizeI(m_basis, m_ineqs)) { + m_basis_valid = true; + } + else { + m_empty = true; + } + } + } + + void to_formula(vector const& row, rational const& b, bool is_eq, expr_ref_vector& conj) const { + expr_ref_vector sum(m); + expr_ref zero(m), lhs(m); + zero = a.mk_numeral(rational(0), true); + + for (unsigned i = 0; i < row.size(); ++i) { + if (row[i].is_zero()) { + continue; + } + var* var = m.mk_var(i, a.mk_int()); + if (row[i].is_one()) { + sum.push_back(var); + } + else { + sum.push_back(a.mk_mul(a.mk_numeral(row[i], true), var)); + } + } + if (!b.is_zero()) { + sum.push_back(a.mk_numeral(b, true)); + } + lhs = a.mk_add(sum.size(), sum.c_ptr()); + if (is_eq) { + conj.push_back(m.mk_eq(lhs, zero)); + } + else { + conj.push_back(a.mk_ge(lhs, zero)); + } + } + }; + + + karr_relation& karr_relation_plugin::get(relation_base& r) { + return dynamic_cast(r); + } + + karr_relation const & karr_relation_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + + void karr_relation_plugin::set_cancel(bool f) { + m_hb.set_cancel(f); + } + + relation_base * karr_relation_plugin::mk_empty(const relation_signature & s) { + return alloc(karr_relation, *this, 0, s, true); + } + + relation_base * karr_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { + return alloc(karr_relation, *this, p, s, false); + } + + class karr_relation_plugin::join_fn : public convenient_relation_join_fn { + public: + join_fn(const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2){ + } + + virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + karr_relation const& r1 = get(_r1); + karr_relation const& r2 = get(_r2); + karr_relation_plugin& p = r1.get_plugin(); + karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_join(r1, r2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); + return result; + } + }; + + relation_join_fn * karr_relation_plugin::mk_join_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (!check_kind(t1) || !check_kind(t2)) { + return 0; + } + return alloc(join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); + } + + + class karr_relation_plugin::project_fn : public convenient_relation_project_fn { + public: + project_fn(const relation_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) + : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { + } + + virtual relation_base * operator()(const relation_base & _r) { + karr_relation const& r = get(_r); + karr_relation_plugin& p = r.get_plugin(); + karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_project(r, m_removed_cols.size(), m_removed_cols.c_ptr()); + return result; + } + }; + + relation_transformer_fn * karr_relation_plugin::mk_project_fn(const relation_base & r, + unsigned col_cnt, const unsigned * removed_cols) { + return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); + } + + class karr_relation_plugin::rename_fn : public convenient_relation_rename_fn { + public: + rename_fn(karr_relation_plugin& p, const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) {} + + virtual relation_base * operator()(const relation_base & _r) { + karr_relation const& r = get(_r); + karr_relation_plugin& p = r.get_plugin(); + karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_rename(r, m_cycle.size(), m_cycle.c_ptr()); + return result; + } + }; + + relation_transformer_fn * karr_relation_plugin::mk_rename_fn(const relation_base & r, + unsigned cycle_len, const unsigned * permutation_cycle) { + if (!check_kind(r)) { + return 0; + } + return alloc(rename_fn, *this, r.get_signature(), cycle_len, permutation_cycle); + } + + bool karr_relation_plugin::dualizeI(matrix& dst, matrix const& src) { + dst.reset(); + m_hb.reset(); + for (unsigned i = 0; i < src.size(); ++i) { + if (src.eq[i]) { + m_hb.add_eq(src.A[i], -src.b[i]); + } + else { + m_hb.add_ge(src.A[i], -src.b[i]); + } + } + for (unsigned i = 0; !src.A.empty() && i < src.A[0].size(); ++i) { + m_hb.set_is_int(i); + } + lbool is_sat = l_undef; + + try { + is_sat = m_hb.saturate(); + } + catch (...) { + is_sat = l_undef; + } + TRACE("dl_verbose", m_hb.display(tout);); + if (is_sat == l_false) { + return false; + } + if (is_sat == l_undef) { + return true; + } + unsigned basis_size = m_hb.get_basis_size(); + bool first_initial = true; + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + m_hb.get_basis_solution(i, soln, is_initial); + if (is_initial && first_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(1)); + dst.eq.push_back(true); + first_initial = false; + } + else if (!is_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(0)); + dst.eq.push_back(true); + } + } + return true; + } + + void karr_relation_plugin::dualizeH(matrix& dst, matrix const& src) { + dst.reset(); + if (src.size() == 0) { + return; + } + m_hb.reset(); + for (unsigned i = 0; i < src.size(); ++i) { + vector v(src.A[i]); + v.push_back(src.b[i]); + if (src.eq[i]) { + m_hb.add_eq(v, rational(0)); + } + else { + m_hb.add_ge(v, rational(0)); + } + } + for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) { + m_hb.set_is_int(i); + } + lbool is_sat = l_undef; + try { + is_sat = m_hb.saturate(); + } + catch (...) { + is_sat = l_undef; + } + if (is_sat != l_true) { + return; + } + TRACE("dl_verbose", m_hb.display(tout);); + SASSERT(is_sat == l_true); + unsigned basis_size = m_hb.get_basis_size(); + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + m_hb.get_basis_solution(i, soln, is_initial); + if (!is_initial) { + dst.b.push_back(soln.back()); + dst.eq.push_back(true); + soln.pop_back(); + dst.A.push_back(soln); + } + } + } + + + class karr_relation_plugin::union_fn : public relation_union_fn { + karr_relation_plugin& m_plugin; + public: + union_fn(karr_relation_plugin& p) : + m_plugin(p) { + } + + virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + + karr_relation& r = get(_r); + karr_relation const& src = get(_src); + TRACE("dl", r.display(tout << "dst:\n"); src.display(tout << "src:\n");); + + if (_delta) { + karr_relation& d = get(*_delta); + r.mk_union(src, &d); + } + else { + r.mk_union(src, 0); + } + TRACE("dl", r.display(tout << "result:\n");); + } + }; + + relation_union_fn * karr_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { + return 0; + } + return alloc(union_fn, *this); + } + + class karr_relation_plugin::filter_identical_fn : public relation_mutator_fn { + unsigned_vector m_identical_cols; + public: + filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) + : m_identical_cols(col_cnt, identical_cols) {} + + virtual void operator()(relation_base & _r) { + karr_relation & r = get(_r); + TRACE("dl", r.display(tout << "src:\n");); + r.get_ineqs(); + for (unsigned i = 1; i < m_identical_cols.size(); ++i) { + unsigned c1 = m_identical_cols[0]; + unsigned c2 = m_identical_cols[i]; + vector row; + row.resize(r.get_signature().size()); + row[c1] = rational(1); + row[c2] = rational(-1); + r.m_ineqs.A.push_back(row); + r.m_ineqs.b.push_back(rational(0)); + r.m_ineqs.eq.push_back(true); + r.m_basis_valid = false; + } + TRACE("dl", r.display(tout << "result:\n");); + } + }; + + relation_mutator_fn * karr_relation_plugin::mk_filter_identical_fn( + const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { + if(!check_kind(t)) { + return 0; + } + return alloc(filter_identical_fn, col_cnt, identical_cols); + } + + + class karr_relation_plugin::filter_equal_fn : public relation_mutator_fn { + unsigned m_col; + rational m_value; + public: + filter_equal_fn(relation_manager & m, const relation_element & value, unsigned col) + : m_col(col) { + arith_util arith(m.get_context().get_manager()); + VERIFY(arith.is_numeral(value, m_value)); + } + + virtual void operator()(relation_base & _r) { + karr_relation & r = get(_r); + karr_relation_plugin & p = r.get_plugin(); + if (m_value.is_int()) { + r.get_ineqs(); + vector row; + row.resize(r.get_signature().size()); + row[m_col] = rational(1); + r.m_ineqs.A.push_back(row); + r.m_ineqs.b.push_back(rational(-1)); + r.m_ineqs.eq.push_back(true); + r.m_basis_valid = false; + } + TRACE("dl", tout << m_value << "\n"; r.display(tout);); + } + }; + + relation_mutator_fn * karr_relation_plugin::mk_filter_equal_fn(const relation_base & r, + const relation_element & value, unsigned col) { + if(check_kind(r)) { + return alloc(filter_equal_fn, get_manager(), value, col); + } + return 0; + } + + + class karr_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { + app_ref m_cond; + public: + filter_interpreted_fn(karr_relation const& t, app* cond): + m_cond(cond, t.get_plugin().get_ast_manager()) { + } + + void operator()(relation_base& t) { + get(t).filter_interpreted(m_cond); + TRACE("dl", tout << mk_pp(m_cond, m_cond.get_manager()) << "\n"; t.display(tout);); + } + }; + + relation_mutator_fn * karr_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { + if (check_kind(t)) { + return alloc(filter_interpreted_fn, get(t), condition); + } + return 0; + } + }; diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index 9d611e365..414953e4f 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -30,41 +30,32 @@ namespace datalog { /** \brief Rule transformer that strengthens bodies with invariants. */ + + struct matrix { + vector > A; + vector b; + svector eq; + unsigned size() const { return A.size(); } + void reset() { A.reset(); b.reset(); eq.reset(); } + matrix& operator=(matrix const& other); + void append(matrix const& other) { A.append(other.A); b.append(other.b); eq.append(other.eq); } + void display(std::ostream& out) const; + static void display_row( + std::ostream& out, vector const& row, rational const& b, bool is_eq); + static void display_ineq( + std::ostream& out, vector const& row, rational const& b, bool is_eq); + }; + class mk_karr_invariants : public rule_transformer::plugin { - struct matrix { - vector > A; - vector b; - svector eq; - unsigned size() const { return A.size(); } - void reset() { A.reset(); b.reset(); eq.reset(); } - matrix& operator=(matrix const& other); - void append(matrix const& other) { A.append(other.A); b.append(other.b); eq.append(other.eq); } - void display(std::ostream& out) const; - static void display_row( - std::ostream& out, vector const& row, rational const& b, bool is_eq); - static void display_ineq( - std::ostream& out, vector const& row, rational const& b, bool is_eq); - }; class add_invariant_model_converter; - + context& m_ctx; ast_manager& m; rule_manager& rm; + context m_inner_ctx; arith_util a; - obj_map m_constraints; - obj_map m_dual_constraints; - hilbert_basis m_hb; - - bool is_linear(expr* e, vector& row, rational& b, rational const& mul); - bool is_eq(expr* e, var*& v, rational& n); - bool get_transition_relation(rule const& r, matrix& M); - void intersect_matrix(app* p, matrix const& Mp, unsigned num_columns, matrix& M); - matrix* get_constraints(func_decl* p); - matrix& get_dual_constraints(func_decl* p); - void dualizeH(matrix& dst, matrix const& src); - void dualizeI(matrix& dst, matrix const& src); - void update_body(rule_set& rules, rule& r); + void update_body(rel_context& rctx, rule_set& result, rule& r); public: mk_karr_invariants(context & ctx, unsigned priority); @@ -77,6 +68,68 @@ namespace datalog { }; + class karr_relation; + + class karr_relation_plugin : public relation_plugin { + arith_util a; + hilbert_basis m_hb; + + class join_fn; + class project_fn; + class rename_fn; + class union_fn; + class filter_equal_fn; + class filter_identical_fn; + class filter_interpreted_fn; + friend class karr_relation; + public: + karr_relation_plugin(relation_manager& rm): + relation_plugin(karr_relation_plugin::get_name(), rm), + a(get_ast_manager()) + {} + + virtual bool can_handle_signature(const relation_signature & sig) { + for (unsigned i = 0; i < sig.size(); ++i) { + if (a.is_int(sig[i])) { + return true; + } + } + return false; + } + + static symbol get_name() { return symbol("karr_relation"); } + + virtual void set_cancel(bool f); + + virtual relation_base * mk_empty(const relation_signature & s); + + virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + + static karr_relation& get(relation_base& r); + static karr_relation const & get(relation_base const& r); + + virtual relation_join_fn * mk_join_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + private: + bool dualizeI(matrix& dst, matrix const& src); + void dualizeH(matrix& dst, matrix const& src); + + + }; + + }; #endif /* _DL_MK_KARR_INVARIANTS_H_ */ diff --git a/src/muz_qe/dl_relation_manager.cpp b/src/muz_qe/dl_relation_manager.cpp index 3407f8fbe..e001dd1a4 100644 --- a/src/muz_qe/dl_relation_manager.cpp +++ b/src/muz_qe/dl_relation_manager.cpp @@ -468,6 +468,12 @@ namespace datalog { } } + void relation_manager::set_cancel(bool f) { + for (unsigned i = 0; i < m_relation_plugins.size(); ++i) { + m_relation_plugins[i]->set_cancel(f); + } + } + std::string relation_manager::to_nice_string(const relation_element & el) const { uint64 val; std::stringstream stm; diff --git a/src/muz_qe/dl_relation_manager.h b/src/muz_qe/dl_relation_manager.h index ecba3d598..6b350642e 100644 --- a/src/muz_qe/dl_relation_manager.h +++ b/src/muz_qe/dl_relation_manager.h @@ -223,6 +223,7 @@ namespace datalog { relation_fact & to); + void set_cancel(bool f); // ----------------------------------- diff --git a/src/muz_qe/dl_rule_set.cpp b/src/muz_qe/dl_rule_set.cpp index caecc76ef..f9ae3620d 100644 --- a/src/muz_qe/dl_rule_set.cpp +++ b/src/muz_qe/dl_rule_set.cpp @@ -30,17 +30,17 @@ namespace datalog { rule_dependencies::rule_dependencies(const rule_dependencies & o, bool reversed): m_context(o.m_context) { - if(reversed) { + if (reversed) { iterator oit = o.begin(); iterator oend = o.end(); - for(; oit!=oend; ++oit) { + for (; oit!=oend; ++oit) { func_decl * pred = oit->m_key; item_set & orig_items = *oit->get_value(); ensure_key(pred); item_set::iterator dit = orig_items.begin(); item_set::iterator dend = orig_items.end(); - for(; dit!=dend; ++dit) { + for (; dit!=dend; ++dit) { func_decl * master_pred = *dit; insert(master_pred, pred); } @@ -49,7 +49,7 @@ namespace datalog { else { iterator oit = o.begin(); iterator oend = o.end(); - for(; oit!=oend; ++oit) { + for (; oit!=oend; ++oit) { func_decl * pred = oit->m_key; item_set & orig_items = *oit->get_value(); m_data.insert(pred, alloc(item_set, orig_items)); @@ -73,7 +73,7 @@ namespace datalog { rule_dependencies::item_set & rule_dependencies::ensure_key(func_decl * pred) { deps_type::obj_map_entry * e = m_data.insert_if_not_there2(pred, 0); - if(!e->get_data().m_value) { + if (!e->get_data().m_value) { e->get_data().m_value = alloc(item_set); } return *e->get_data().m_value; @@ -101,12 +101,13 @@ namespace datalog { void rule_dependencies::populate(unsigned n, rule * const * rules) { SASSERT(m_data.empty()); - for(unsigned i=0; iget_decl()->get_name() << "\n";); m_visited.reset(); func_decl * d = r->get_head()->get_decl(); func_decl_set & s = ensure_key(d); @@ -141,7 +142,7 @@ namespace datalog { const rule_dependencies::item_set & rule_dependencies::get_deps(func_decl * f) const { deps_type::obj_map_entry * e = m_data.find_core(f); - if(!e) { + if (!e) { return m_empty_item_set; } SASSERT(e->get_data().get_value()); @@ -152,9 +153,9 @@ namespace datalog { ptr_vector to_remove; iterator pit = begin(); iterator pend = end(); - for(; pit!=pend; ++pit) { + for (; pit!=pend; ++pit) { func_decl * pred = pit->m_key; - if(!allowed.contains(pred)) { + if (!allowed.contains(pred)) { to_remove.insert(pred); continue; } @@ -163,7 +164,7 @@ namespace datalog { } ptr_vector::iterator rit = to_remove.begin(); ptr_vector::iterator rend = to_remove.end(); - for(; rit!=rend; ++rit) { + for (; rit!=rend; ++rit) { remove_m_data_entry(*rit); } } @@ -172,7 +173,7 @@ namespace datalog { remove_m_data_entry(itm); iterator pit = begin(); iterator pend = end(); - for(; pit!=pend; ++pit) { + for (; pit!=pend; ++pit) { item_set & itms = *pit->get_value(); itms.remove(itm); } @@ -181,12 +182,12 @@ namespace datalog { void rule_dependencies::remove(const item_set & to_remove) { item_set::iterator rit = to_remove.begin(); item_set::iterator rend = to_remove.end(); - for(; rit!=rend; ++rit) { + for (; rit!=rend; ++rit) { remove_m_data_entry(*rit); } iterator pit = begin(); iterator pend = end(); - for(; pit!=pend; ++pit) { + for (; pit!=pend; ++pit) { item_set * itms = pit->get_value(); set_difference(*itms, to_remove); } @@ -196,9 +197,9 @@ namespace datalog { unsigned res = 0; iterator pit = begin(); iterator pend = end(); - for(; pit!=pend; ++pit) { + for (; pit!=pend; ++pit) { item_set & itms = *pit->get_value(); - if(itms.contains(f)) { + if (itms.contains(f)) { res++; } } @@ -214,10 +215,10 @@ namespace datalog { iterator pit = begin(); iterator pend = end(); - for(; pit!=pend; ++pit) { + for (; pit!=pend; ++pit) { func_decl * pred = pit->m_key; unsigned deg = in_degree(pred); - if(deg==0) { + if (deg==0) { res.push_back(pred); } else { @@ -225,25 +226,25 @@ namespace datalog { } } - while(curr_indexget_data().m_value; SASSERT(child_deg>0); child_deg--; - if(child_deg==0) { + if (child_deg==0) { res.push_back(child); } } curr_index++; } - if(res.size()m_key; const item_set & deps = *pit->m_value; item_set::iterator dit=deps.begin(); item_set::iterator dend=deps.end(); - if(dit==dend) { + if (dit == dend) { out<get_name()<<" - \n"; } - for(; dit!=dend; ++dit) { + for (; dit != dend; ++dit) { func_decl * dep = *dit; - out<get_name()<<" -> "<get_name()<<"\n"; + out << pred->get_name() << " -> " << dep->get_name() << "\n"; } } } @@ -292,8 +293,8 @@ namespace datalog { m_deps(rs.m_context), m_stratifier(0) { add_rules(rs); - if(rs.m_stratifier) { - TRUSTME(close()); + if (rs.m_stratifier) { + VERIFY(close()); } } @@ -302,7 +303,7 @@ namespace datalog { } void rule_set::reset() { - if(m_stratifier) { + if (m_stratifier) { m_stratifier = 0; } reset_dealloc_values(m_head2rules); @@ -346,18 +347,19 @@ namespace datalog { void rule_set::ensure_closed() { - if(!is_closed()) { - TRUSTME(close()); + if (!is_closed()) { + VERIFY(close()); } } bool rule_set::close() { SASSERT(!is_closed()); //the rule_set is not already closed + m_deps.populate(*this); m_stratifier = alloc(rule_stratifier, m_deps); - if(!stratified_negation()) { + if (!stratified_negation()) { m_stratifier = 0; m_deps.reset(); return false; @@ -391,7 +393,7 @@ namespace datalog { unsigned head_strat = get_predicate_strat(head_decl); SASSERT(head_strat>=neg_strat); //head strat can never be lower than that of a tail - if(head_strat==neg_strat) { + if (head_strat == neg_strat) { return false; } } @@ -415,7 +417,7 @@ namespace datalog { const rule_vector & rule_set::get_predicate_rules(func_decl * pred) const { decl2rules::obj_map_entry * e = m_head2rules.find_core(pred); - if(!e) { + if (!e) { return m_empty_rule_vector; } return *e->get_data().m_value; @@ -443,7 +445,7 @@ namespace datalog { ptr_vector::iterator end2 = rules->end(); for (; it2 != end2; ++it2) { rule * r = *it2; - if(!r->passes_output_thresholds(m_context)) { + if (!r->passes_output_thresholds(m_context)) { continue; } r->display(m_context, out); @@ -468,23 +470,23 @@ namespace datalog { const pred_set_vector & strats = get_strats(); pred_set_vector::const_iterator sit = strats.begin(); pred_set_vector::const_iterator send = strats.end(); - for(; sit!=send; ++sit) { + for (; sit!=send; ++sit) { func_decl_set & strat = **sit; func_decl_set::iterator fit=strat.begin(); func_decl_set::iterator fend=strat.end(); bool non_empty = false; - for(; fit!=fend; ++fit) { + for (; fit!=fend; ++fit) { func_decl * first = *fit; const func_decl_set & deps = m_deps.get_deps(first); func_decl_set::iterator dit=deps.begin(); func_decl_set::iterator dend=deps.end(); - for(; dit!=dend; ++dit) { + for (; dit!=dend; ++dit) { non_empty = true; func_decl * dep = *dit; out<get_name()<<" -> "<get_name()<<"\n"; } } - if(non_empty && sit!=send) { + if (non_empty && sit!=send) { out << "\n"; } } @@ -499,7 +501,7 @@ namespace datalog { rule_stratifier::~rule_stratifier() { comp_vector::iterator it = m_strats.begin(); comp_vector::iterator end = m_strats.end(); - for(; it!=end; ++it) { + for (; it!=end; ++it) { SASSERT(*it); dealloc(*it); } @@ -507,7 +509,7 @@ namespace datalog { unsigned rule_stratifier::get_predicate_strat(func_decl * pred) const { unsigned num; - if(!m_pred_strat_nums.find(pred, num)) { + if (!m_pred_strat_nums.find(pred, num)) { //the number of the predicate is not stored, therefore it did not appear //in the algorithm and therefore it does not depend on anything and nothing //depends on it. So it is safe to assign zero strate to it, although it is @@ -520,19 +522,19 @@ namespace datalog { void rule_stratifier::traverse(T* el) { unsigned p_num; - if(m_preorder_nums.find(el, p_num)) { - if(p_numinsert(s_el); m_component_nums.insert(s_el, comp_num); - } while(s_el!=el); + } while (s_el!=el); m_stack_P.pop_back(); } } } void rule_stratifier::process() { - if(m_deps.empty()) { + if (m_deps.empty()) { return; } //detect strong components rule_dependencies::iterator it = m_deps.begin(); rule_dependencies::iterator end = m_deps.end(); - for(; it!=end; ++it) { + for (; it!=end; ++it) { T * el = it->m_key; //we take a note of the preorder number with which this sweep started m_first_preorder = m_next_preorder; @@ -593,32 +595,32 @@ namespace datalog { //init in_degrees it = m_deps.begin(); end = m_deps.end(); - for(; it!=end; ++it) { + for (; it != end; ++it) { T * el = it->m_key; item_set * out_edges = it->m_value; unsigned el_comp; - TRUSTME( m_component_nums.find(el, el_comp) ); + VERIFY( m_component_nums.find(el, el_comp) ); - item_set::iterator eit=out_edges->begin(); - item_set::iterator eend=out_edges->end(); - for(; eit!=eend; ++eit) { + item_set::iterator eit = out_edges->begin(); + item_set::iterator eend = out_edges->end(); + for (; eit!=eend; ++eit) { T * tgt = *eit; unsigned tgt_comp = m_component_nums.find(tgt); - if(el_comp!=tgt_comp) { + if (el_comp != tgt_comp) { in_degrees[tgt_comp]++; } } } - //We put components whose indegree is zero to m_strats and assign its - //m_components entry to zero. + // We put components whose indegree is zero to m_strats and assign its + // m_components entry to zero. unsigned comp_cnt = m_components.size(); - for(unsigned i=0; ibegin(); item_set::iterator cend=comp->end(); - for(; cit!=cend; ++cit) { + for (; cit!=cend; ++cit) { T * el = *cit; const item_set & deps = m_deps.get_deps(el); item_set::iterator eit=deps.begin(); item_set::iterator eend=deps.end(); - for(; eit!=eend; ++eit) { + for (; eit!=eend; ++eit) { T * tgt = *eit; unsigned tgt_comp; - TRUSTME( m_component_nums.find(tgt, tgt_comp) ); + VERIFY( m_component_nums.find(tgt, tgt_comp) ); //m_components[tgt_comp]==0 means the edge is intra-component. //Otherwise it would go to another component, but it is not possible, since //as m_components[tgt_comp]==0, its indegree has already reached zero. - if(m_components[tgt_comp]) { + if (m_components[tgt_comp]) { SASSERT(in_degrees[tgt_comp]>0); in_degrees[tgt_comp]--; - if(in_degrees[tgt_comp]==0) { + if (in_degrees[tgt_comp]==0) { m_strats.push_back(m_components[tgt_comp]); m_components[tgt_comp] = 0; } } - - traverse(*cit); } } @@ -669,13 +669,12 @@ namespace datalog { SASSERT(m_pred_strat_nums.empty()); unsigned strat_cnt = m_strats.size(); - for(unsigned strat_index=0; strat_indexbegin(); item_set::iterator cend=comp->end(); - for(; cit!=cend; ++cit) { + for (; cit != cend; ++cit) { T * el = *cit; - m_pred_strat_nums.insert(el, strat_index); } } @@ -686,6 +685,21 @@ namespace datalog { m_stack_P.finalize(); m_component_nums.finalize(); m_components.finalize(); + + } + + void rule_stratifier::display(std::ostream& out) const { + m_deps.display(out << "dependencies\n"); + out << "strata\n"; + for (unsigned i = 0; i < m_strats.size(); ++i) { + item_set::iterator it = m_strats[i]->begin(); + item_set::iterator end = m_strats[i]->end(); + for (; it != end; ++it) { + out << (*it)->get_name() << " "; + } + out << "\n"; + } + } }; diff --git a/src/muz_qe/dl_rule_set.h b/src/muz_qe/dl_rule_set.h index 3079c6072..9aa64425c 100644 --- a/src/muz_qe/dl_rule_set.h +++ b/src/muz_qe/dl_rule_set.h @@ -146,6 +146,8 @@ namespace datalog { const comp_vector & get_strats() const { return m_strats; } unsigned get_predicate_strat(func_decl * pred) const; + + void display( std::ostream & out ) const; }; /** diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz_qe/hilbert_basis.cpp index 7b3e67487..62f091dbc 100644 --- a/src/muz_qe/hilbert_basis.cpp +++ b/src/muz_qe/hilbert_basis.cpp @@ -744,7 +744,6 @@ void hilbert_basis::reset() { if (m_passive2) { m_passive2->reset(); } - m_cancel = false; if (m_index) { m_index->reset(1); } @@ -867,7 +866,7 @@ lbool hilbert_basis::saturate() { stopwatch sw; sw.start(); lbool r = saturate(m_ineqs[m_current_ineq], m_iseq[m_current_ineq]); - IF_VERBOSE(1, + IF_VERBOSE(3, { statistics st; collect_statistics(st); st.display(verbose_stream()); diff --git a/src/muz_qe/hilbert_basis.h b/src/muz_qe/hilbert_basis.h index abb59be2d..733b3a2f0 100644 --- a/src/muz_qe/hilbert_basis.h +++ b/src/muz_qe/hilbert_basis.h @@ -37,10 +37,13 @@ typedef vector rational_vector; class hilbert_basis { - static const bool check = false; + static const bool check = true; typedef checked_int64 numeral; typedef vector num_vector; static checked_int64 to_numeral(rational const& r) { + if (!r.is_int64()) { + throw checked_int64::overflow_exception(); + } return checked_int64(r.get_int64()); } static rational to_rational(checked_int64 const& i) { diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index c79acf67f..12045047b 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -27,6 +27,7 @@ Revision History: #include"dl_product_relation.h" #include"dl_bound_relation.h" #include"dl_interval_relation.h" +#include"dl_mk_karr_invariants.h" #include"dl_finite_product_relation.h" #include"dl_sparse_table.h" #include"dl_table.h" @@ -54,6 +55,8 @@ namespace datalog { get_rmanager().register_plugin(alloc(bound_relation_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(interval_relation_plugin, get_rmanager())); + get_rmanager().register_plugin(alloc(karr_relation_plugin, get_rmanager())); + } @@ -178,23 +181,23 @@ namespace datalog { return result; } -#define BEGIN_QUERY() \ +#define BEGIN_QUERY() \ rule_set original_rules(m_context.get_rules()); \ - decl_set original_preds; \ - m_context.collect_predicates(original_preds); \ - bool was_closed = m_context.is_closed(); \ - if (was_closed) { \ + decl_set original_preds; \ + m_context.collect_predicates(original_preds); \ + bool was_closed = m_context.is_closed(); \ + if (was_closed) { \ m_context.reopen(); \ - } \ - -#define END_QUERY() \ + } \ + +#define END_QUERY() \ m_context.reopen(); \ m_context.replace_rules(original_rules); \ - restrict_predicates(original_preds); \ - \ - if (was_closed) { \ + restrict_predicates(original_preds); \ + \ + if (was_closed) { \ m_context.close(); \ - } \ + } \ lbool rel_context::query(unsigned num_rels, func_decl * const* rels) { get_rmanager().reset_saturated_marks(); @@ -427,6 +430,10 @@ namespace datalog { get_rmanager().set_predicate_kind(pred, target_kind); } + void rel_context::set_cancel(bool f) { + get_rmanager().set_cancel(f); + } + relation_plugin & rel_context::get_ordinary_relation_plugin(symbol relation_name) { relation_plugin * plugin = get_rmanager().get_relation_plugin(relation_name); if (!plugin) { diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index 2e2b5cd9d..08ee868c0 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -63,7 +63,6 @@ namespace datalog { bool output_profile() const; - lbool query(expr* q); lbool query(unsigned num_rels, func_decl * const* rels); @@ -72,6 +71,7 @@ namespace datalog { void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred); + void set_cancel(bool f); /** \brief Restrict the set of used predicates to \c res. From a2207bc35cbbdb86d4d8b864eb3213b227f584d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Apr 2013 07:52:55 -0700 Subject: [PATCH 049/281] stash --- src/muz_qe/dl_mk_karr_invariants.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 77b52f2b9..458f46628 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -387,6 +387,8 @@ namespace datalog { } lbool is_sat = m_hb.saturate(); TRACE("dl_verbose", m_hb.display(tout);); + // TBD: actually transition function can be unsat. + // in this case the rule can be removed. SASSERT(is_sat == l_true); dst.reset(); unsigned basis_size = m_hb.get_basis_size(); From fbb59453c3bf1f8d1041de9f055f93061a1129b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Apr 2013 09:10:34 -0700 Subject: [PATCH 050/281] add loop counter v1 Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_bit_blast.h | 21 +----- src/muz_qe/dl_mk_karr_invariants.cpp | 2 +- src/muz_qe/dl_mk_loop_counter.cpp | 104 +++++++++++++++++++++++++++ src/muz_qe/dl_mk_loop_counter.h | 38 ++++++++++ 4 files changed, 146 insertions(+), 19 deletions(-) create mode 100644 src/muz_qe/dl_mk_loop_counter.cpp create mode 100644 src/muz_qe/dl_mk_loop_counter.h diff --git a/src/muz_qe/dl_mk_bit_blast.h b/src/muz_qe/dl_mk_bit_blast.h index 60c83f6cb..da91c5804 100644 --- a/src/muz_qe/dl_mk_bit_blast.h +++ b/src/muz_qe/dl_mk_bit_blast.h @@ -7,7 +7,7 @@ Module Name: Abstract: - + Functor for bit-blasting a rule set Author: @@ -19,31 +19,16 @@ Revision History: #ifndef _DL_MK_BIT_BLAST_H_ #define _DL_MK_BIT_BLAST_H_ -#include - -#include"map.h" -#include"obj_pair_hashtable.h" -#include"dl_context.h" -#include"dl_rule_set.h" #include"dl_rule_transformer.h" namespace datalog { - /** - \brief Functor for bit-blasting a rule set. - */ - class mk_bit_blast : public rule_transformer::plugin { class impl; - - impl* m_impl; - void blast(expr_ref& b); - void reset(); - + impl* m_impl; public: mk_bit_blast(context & ctx, unsigned priority = 35000); - ~mk_bit_blast(); - + ~mk_bit_blast(); rule_set * operator()(rule_set const & source); }; diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 6dca35cdf..2596a7337 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -204,7 +204,7 @@ namespace datalog { m_inner_ctx.ensure_opened(); it = source.begin(); for (; it != end; ++it) { - rule_ref r(*it, m_ctx.get_rule_manager()); + rule_ref r(*it, m_inner_ctx.get_rule_manager()); m_inner_ctx.add_rule(r); m_inner_ctx.register_predicate(r->get_decl()); } diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp new file mode 100644 index 000000000..8c9ad7f52 --- /dev/null +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -0,0 +1,104 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_loop_counter.cpp + +Abstract: + + Add loop counter argument to relations. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-31 + +Revision History: + +--*/ + +#include"dl_mk_loop_counter.h" +#include"dl_context.h" + +namespace datalog { + + mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority): + plugin(priority) { + } + + mk_loop_counter::~mk_loop_counter() { } + + app_ref mk_loop_counter::add_arg(ast_manager& m, app* fn, unsigned idx) { + arith_util a(m); + ptr_vector domain; + expr_ref_vector args(m); + domain.append(fn->get_num_args(), fn->get_decl()->get_domain()); + domain.push_back(a.mk_int()); + args.append(fn->get_num_args(), fn->get_args()); + args.push_back(m.mk_var(idx, a.mk_int())); + func_decl_ref new_fn(m); + new_fn = m.mk_func_decl(fn->get_decl()->get_name(), domain.size(), domain.c_ptr(), m.mk_bool_sort()); + return app_ref(m.mk_app(new_fn, args.size(), args.c_ptr()), m); + } + + rule_set * mk_loop_counter::operator()(rule_set const & source) { + context& ctx = source.get_context(); + ast_manager& m = source.get_manager(); + rule_manager& rm = source.get_rule_manager(); + arith_util a(m); + rule_set * result = alloc(rule_set, ctx); + unsigned sz = source.get_num_rules(); + rule_ref new_rule(rm); + app_ref_vector tail(m); + app_ref head(m); + svector neg; + rule_counter& vc = rm.get_counter(); + for (unsigned i = 0; i < sz; ++i) { + tail.reset(); + neg.reset(); + rule & r = *source.get_rule(i); + unsigned cnt = vc.get_max_rule_var(r)+1; + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + for (unsigned j = 0; j < utsz; ++j, ++cnt) { + tail.push_back(add_arg(m, r.get_tail(j), cnt)); + neg.push_back(r.is_neg_tail(j)); + ctx.register_predicate(tail.back()->get_decl()); + } + for (unsigned j = utsz; j < tsz; ++j) { + tail.push_back(r.get_tail(j)); + neg.push_back(false); + } + head = add_arg(m, r.get_head(), cnt); + ctx.register_predicate(head->get_decl()); + // set the loop counter to be an increment of the previous + bool found = false; + unsigned last = head->get_num_args()-1; + for (unsigned j = 0; !found && j < utsz; ++j) { + if (head->get_decl() == tail[j]->get_decl()) { + tail.push_back(m.mk_eq(head->get_arg(last), + a.mk_add(tail[j]->get_arg(last), + a.mk_numeral(rational(1), true)))); + neg.push_back(false); + found = true; + } + } + // initialize loop counter to 0 if none was found. + if (!found) { + expr_ref_vector args(m); + args.append(head->get_num_args(), head->get_args()); + args[last] = a.mk_numeral(rational(0), true); + head = m.mk_app(head->get_decl(), args.size(), args.c_ptr()); + } + + new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + result->add_rule(new_rule); + } + + // model converter: remove references to extra argument. + // proof converter: etc. + + return result; + } + +}; diff --git a/src/muz_qe/dl_mk_loop_counter.h b/src/muz_qe/dl_mk_loop_counter.h new file mode 100644 index 000000000..ad2c837a9 --- /dev/null +++ b/src/muz_qe/dl_mk_loop_counter.h @@ -0,0 +1,38 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_loop_counter.h + +Abstract: + + Add loop counter argument to relations. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-31 + +Revision History: + +--*/ +#ifndef _DL_MK_LOOP_COUNTER_H_ +#define _DL_MK_LOOP_COUNTER_H_ + +#include"dl_rule_transformer.h" + +namespace datalog { + + class mk_loop_counter : public rule_transformer::plugin { + app_ref add_arg(ast_manager& m, app* fn, unsigned idx); + public: + mk_loop_counter(context & ctx, unsigned priority = 33000); + ~mk_loop_counter(); + + rule_set * operator()(rule_set const & source); + }; + +}; + +#endif /* _DL_MK_LOOP_COUNTER_H_ */ + From 2e0c5f5042df30adf85fada14c94607096ca1028 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Apr 2013 09:15:23 -0700 Subject: [PATCH 051/281] loop counting Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_loop_counter.cpp | 13 ++++++------- src/muz_qe/dl_mk_loop_counter.h | 5 ++++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp index 8c9ad7f52..1e7d0c3fa 100644 --- a/src/muz_qe/dl_mk_loop_counter.cpp +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -23,13 +23,14 @@ Revision History: namespace datalog { mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority): - plugin(priority) { + plugin(priority), + m(ctx.get_manager()), + a(m) { } mk_loop_counter::~mk_loop_counter() { } - app_ref mk_loop_counter::add_arg(ast_manager& m, app* fn, unsigned idx) { - arith_util a(m); + app_ref mk_loop_counter::add_arg(app* fn, unsigned idx) { ptr_vector domain; expr_ref_vector args(m); domain.append(fn->get_num_args(), fn->get_decl()->get_domain()); @@ -43,9 +44,7 @@ namespace datalog { rule_set * mk_loop_counter::operator()(rule_set const & source) { context& ctx = source.get_context(); - ast_manager& m = source.get_manager(); rule_manager& rm = source.get_rule_manager(); - arith_util a(m); rule_set * result = alloc(rule_set, ctx); unsigned sz = source.get_num_rules(); rule_ref new_rule(rm); @@ -61,7 +60,7 @@ namespace datalog { unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); for (unsigned j = 0; j < utsz; ++j, ++cnt) { - tail.push_back(add_arg(m, r.get_tail(j), cnt)); + tail.push_back(add_arg(r.get_tail(j), cnt)); neg.push_back(r.is_neg_tail(j)); ctx.register_predicate(tail.back()->get_decl()); } @@ -69,7 +68,7 @@ namespace datalog { tail.push_back(r.get_tail(j)); neg.push_back(false); } - head = add_arg(m, r.get_head(), cnt); + head = add_arg(r.get_head(), cnt); ctx.register_predicate(head->get_decl()); // set the loop counter to be an increment of the previous bool found = false; diff --git a/src/muz_qe/dl_mk_loop_counter.h b/src/muz_qe/dl_mk_loop_counter.h index ad2c837a9..c16159b1c 100644 --- a/src/muz_qe/dl_mk_loop_counter.h +++ b/src/muz_qe/dl_mk_loop_counter.h @@ -20,11 +20,14 @@ Revision History: #define _DL_MK_LOOP_COUNTER_H_ #include"dl_rule_transformer.h" +#include"arith_decl_plugin.h" namespace datalog { class mk_loop_counter : public rule_transformer::plugin { - app_ref add_arg(ast_manager& m, app* fn, unsigned idx); + ast_manager& m; + arith_util a; + app_ref add_arg(app* fn, unsigned idx); public: mk_loop_counter(context & ctx, unsigned priority = 33000); ~mk_loop_counter(); From 65e64d100669c3f0fde64d5b0cd154a0317a2c50 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Apr 2013 09:54:32 -0700 Subject: [PATCH 052/281] loop counting Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_loop_counter.cpp | 24 +++++++++++++++++------- src/muz_qe/dl_mk_loop_counter.h | 6 ++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp index 1e7d0c3fa..172198746 100644 --- a/src/muz_qe/dl_mk_loop_counter.cpp +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -25,24 +25,34 @@ namespace datalog { mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority): plugin(priority), m(ctx.get_manager()), - a(m) { + a(m), + m_refs(m) { } mk_loop_counter::~mk_loop_counter() { } app_ref mk_loop_counter::add_arg(app* fn, unsigned idx) { - ptr_vector domain; expr_ref_vector args(m); - domain.append(fn->get_num_args(), fn->get_decl()->get_domain()); - domain.push_back(a.mk_int()); + func_decl* new_fn, *old_fn = fn->get_decl(); args.append(fn->get_num_args(), fn->get_args()); args.push_back(m.mk_var(idx, a.mk_int())); - func_decl_ref new_fn(m); - new_fn = m.mk_func_decl(fn->get_decl()->get_name(), domain.size(), domain.c_ptr(), m.mk_bool_sort()); + + if (!m_old2new.find(old_fn, new_fn)) { + ptr_vector domain; + domain.append(fn->get_num_args(), old_fn->get_domain()); + domain.push_back(a.mk_int()); + new_fn = m.mk_func_decl(old_fn->get_name(), domain.size(), domain.c_ptr(), old_fn->get_range()); + m_old2new.insert(old_fn, new_fn); + m_new2old.insert(new_fn, old_fn); + m_refs.push_back(new_fn); + } return app_ref(m.mk_app(new_fn, args.size(), args.c_ptr()), m); } rule_set * mk_loop_counter::operator()(rule_set const & source) { + m_refs.reset(); + m_old2new.reset(); + m_new2old.reset(); context& ctx = source.get_context(); rule_manager& rm = source.get_rule_manager(); rule_set * result = alloc(rule_set, ctx); @@ -95,7 +105,7 @@ namespace datalog { } // model converter: remove references to extra argument. - // proof converter: etc. + // proof converter: remove references to extra argument as well. return result; } diff --git a/src/muz_qe/dl_mk_loop_counter.h b/src/muz_qe/dl_mk_loop_counter.h index c16159b1c..6601f837f 100644 --- a/src/muz_qe/dl_mk_loop_counter.h +++ b/src/muz_qe/dl_mk_loop_counter.h @@ -27,12 +27,18 @@ namespace datalog { class mk_loop_counter : public rule_transformer::plugin { ast_manager& m; arith_util a; + func_decl_ref_vector m_refs; + obj_map m_new2old; + obj_map m_old2new; + app_ref add_arg(app* fn, unsigned idx); public: mk_loop_counter(context & ctx, unsigned priority = 33000); ~mk_loop_counter(); rule_set * operator()(rule_set const & source); + + func_decl* get_old(func_decl* f) const { return m_new2old.find(f); } }; }; From 4c353ec7204a6a16f9b87eb1bbae694db40076cb Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Apr 2013 13:45:42 +0100 Subject: [PATCH 053/281] FPA: bugfix for model completion. Thanks to Levent Erkok. Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 9 +++++++++ src/ast/float_decl_plugin.h | 1 + src/tactic/fpa/fpa2bv_converter.cpp | 19 ++++++++++++------- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 62ec3a4cf..26131bc28 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -491,6 +491,15 @@ void float_decl_plugin::get_sort_names(svector & sort_names, symbo sort_names.push_back(builtin_name("RoundingMode", ROUNDING_MODE_SORT)); } +expr * float_decl_plugin::get_some_value(sort * s) { + SASSERT(s->is_sort_of(m_family_id, FLOAT_SORT)); + mpf tmp; + m_fm.mk_nan(s->get_parameter(0).get_int(), s->get_parameter(1).get_int(), tmp); + expr * res = this->mk_value(tmp); + m_fm.del(tmp); + return res; +} + bool float_decl_plugin::is_value(app * e) const { if (e->get_family_id() != m_family_id) return false; diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 6f1ef5ec2..4ec17addf 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -140,6 +140,7 @@ public: unsigned arity, sort * const * domain, sort * range); virtual void get_op_names(svector & op_names, symbol const & logic); virtual void get_sort_names(svector & sort_names, symbol const & logic); + virtual expr * get_some_value(sort * s); virtual bool is_value(app* e) const; virtual bool is_unique_value(app* e) const { return is_value(e); } diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 79f86ac46..838090045 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1263,6 +1263,9 @@ void fpa2bv_converter::mk_float_eq(func_decl * f, unsigned num, expr * const * a expr * x = args[0], * y = args[1]; + TRACE("fpa2bv_float_eq", tout << "X = " << mk_ismt2_pp(x, m) << std::endl; + tout << "Y = " << mk_ismt2_pp(y, m) << std::endl;); + expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m); mk_is_nan(x, x_is_nan); mk_is_nan(y, y_is_nan); @@ -1290,6 +1293,8 @@ void fpa2bv_converter::mk_float_eq(func_decl * f, unsigned num, expr * const * a m_simp.mk_ite(c2, m.mk_true(), c3t4, c2else); m_simp.mk_ite(c1, m.mk_false(), c2else, result); + + TRACE("fpa2bv_float_eq", tout << "FLOAT_EQ = " << mk_ismt2_pp(result, m) << std::endl; ); } void fpa2bv_converter::mk_float_lt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -2314,9 +2319,10 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { unsigned ebits = fu.get_ebits(var->get_range()); unsigned sbits = fu.get_sbits(var->get_range()); - expr * sgn = bv_mdl->get_const_interp(to_app(a->get_arg(0))->get_decl()); - expr * sig = bv_mdl->get_const_interp(to_app(a->get_arg(1))->get_decl()); - expr * exp = bv_mdl->get_const_interp(to_app(a->get_arg(2))->get_decl()); + expr_ref sgn(m), sig(m), exp(m); + sgn = bv_mdl->get_const_interp(to_app(a->get_arg(0))->get_decl()); + sig = bv_mdl->get_const_interp(to_app(a->get_arg(1))->get_decl()); + exp = bv_mdl->get_const_interp(to_app(a->get_arg(2))->get_decl()); seen.insert(to_app(a->get_arg(0))->get_decl()); seen.insert(to_app(a->get_arg(1))->get_decl()); @@ -2385,12 +2391,11 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { for (unsigned i = 0; i < sz; i++) { func_decl * c = bv_mdl->get_constant(i); - if (seen.contains(c)) - continue; - float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); + if (!seen.contains(c)) + float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); } -// And keep everything else + // And keep everything else sz = bv_mdl->get_num_functions(); for (unsigned i = 0; i < sz; i++) { From 3d486c4c98b2a6d07ca397f4fd2d2d5257d19e95 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Apr 2013 15:28:45 -0700 Subject: [PATCH 054/281] add abstraction and instantiation Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/expr_safe_replace.cpp | 6 + src/ast/rewriter/expr_safe_replace.h | 2 + src/muz_qe/dl_context.cpp | 4 + src/muz_qe/dl_mk_quantifier_abstraction.cpp | 206 ++++++++++++ src/muz_qe/dl_mk_quantifier_abstraction.h | 61 ++++ src/muz_qe/dl_mk_quantifier_instantiation.cpp | 295 ++++++++++++++++++ src/muz_qe/dl_mk_quantifier_instantiation.h | 120 +++++++ src/muz_qe/fixedpoint_params.pyg | 2 + 8 files changed, 696 insertions(+) create mode 100644 src/muz_qe/dl_mk_quantifier_abstraction.cpp create mode 100644 src/muz_qe/dl_mk_quantifier_abstraction.h create mode 100644 src/muz_qe/dl_mk_quantifier_instantiation.cpp create mode 100644 src/muz_qe/dl_mk_quantifier_instantiation.h diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index b3b4d5138..1ec810414 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -100,3 +100,9 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { } res = cache.find(e); } + +void expr_safe_replace::reset() { + m_src.reset(); + m_dst.reset(); + m_subst.reset(); +} diff --git a/src/ast/rewriter/expr_safe_replace.h b/src/ast/rewriter/expr_safe_replace.h index 6af819596..b6131906a 100644 --- a/src/ast/rewriter/expr_safe_replace.h +++ b/src/ast/rewriter/expr_safe_replace.h @@ -38,6 +38,8 @@ public: void operator()(expr_ref& e) { (*this)(e.get(), e); } void operator()(expr* src, expr_ref& e); + + void reset(); }; #endif /* __EXPR_SAFE_REPLACE_H__ */ diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index c667c7775..9207fbe61 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -46,6 +46,7 @@ Revision History: #include"dl_mk_bit_blast.h" #include"dl_mk_array_blast.h" #include"dl_mk_karr_invariants.h" +#include"dl_mk_quantifier_abstraction.h" #include"datatype_decl_plugin.h" #include"expr_abstract.h" @@ -905,6 +906,9 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890)); m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); + + m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000)); + m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.cpp b/src/muz_qe/dl_mk_quantifier_abstraction.cpp new file mode 100644 index 000000000..511ab7b9a --- /dev/null +++ b/src/muz_qe/dl_mk_quantifier_abstraction.cpp @@ -0,0 +1,206 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_quantifier_abstraction.cpp + +Abstract: + + Create quantified Horn clauses from benchmarks with arrays. + +Author: + + Ken McMillan + Andrey Rybalchenko + Nikolaj Bjorner (nbjorner) 2013-04-02 + +Revision History: + +--*/ + +#include "dl_mk_quantifier_abstraction.h" +#include "dl_context.h" + +namespace datalog { + + mk_quantifier_abstraction::mk_quantifier_abstraction( + context & ctx, unsigned priority): + plugin(priority), + m(ctx.get_manager()), + m_ctx(ctx), + a(m), + m_refs(m) { + } + + mk_quantifier_abstraction::~mk_quantifier_abstraction() { + + } + + func_decl* mk_quantifier_abstraction::declare_pred(func_decl* old_p) { + + unsigned sz = old_p->get_arity(); + unsigned num_arrays = 0; + for (unsigned i = 0; i < sz; ++i) { + if (a.is_array(old_p->get_domain(i))) { + num_arrays++; + } + } + if (num_arrays == 0) { + return 0; + } + + func_decl* new_p = 0; + if (!m_old2new.find(old_p, new_p)) { + sort_ref_vector domain(m); + for (unsigned i = 0; i < sz; ++i) { + sort* s = old_p->get_domain(i); + while (a.is_array(s)) { + unsigned arity = get_array_arity(s); + for (unsigned j = 0; j < arity; ++j) { + domain.push_back(get_array_domain(s, j)); + } + s = get_array_range(s); + } + domain.push_back(s); + } + SASSERT(old_p->get_range() == m.mk_bool_sort()); + new_p = m.mk_func_decl(old_p->get_name(), domain.size(), domain.c_ptr(), old_p->get_range()); + m_refs.push_back(new_p); + m_ctx.register_predicate(new_p); + } + return new_p; + } + + app_ref mk_quantifier_abstraction::mk_head(app* p, unsigned idx) { + func_decl* new_p = declare_pred(p->get_decl()); + if (!new_p) { + return app_ref(p, m); + } + expr_ref_vector args(m); + expr_ref arg(m); + unsigned sz = p->get_num_args(); + for (unsigned i = 0; i < sz; ++i) { + arg = p->get_arg(i); + sort* s = m.get_sort(arg); + while (a.is_array(s)) { + unsigned arity = get_array_arity(s); + for (unsigned j = 0; j < arity; ++j) { + args.push_back(m.mk_var(idx++, get_array_domain(s, j))); + } + ptr_vector args2; + args2.push_back(arg); + args2.append(arity, args.c_ptr()-arity); + arg = a.mk_select(args2.size(), args2.c_ptr()); + s = get_array_range(s); + } + args.push_back(arg); + } + return app_ref(m.mk_app(new_p, args.size(), args.c_ptr()), m); + } + + app_ref mk_quantifier_abstraction::mk_tail(app* p) { + func_decl* old_p = p->get_decl(); + func_decl* new_p = declare_pred(old_p); + if (!new_p) { + return app_ref(p, m); + } + SASSERT(new_p->get_arity() > old_p->get_arity()); + unsigned num_extra_args = new_p->get_arity() - old_p->get_arity(); + var_shifter shift(m); + expr_ref p_shifted(m); + shift(p, num_extra_args, p_shifted); + app* ps = to_app(p_shifted); + expr_ref_vector args(m); + app_ref_vector pats(m); + sort_ref_vector vars(m); + svector names; + expr_ref arg(m); + unsigned idx = 0; + unsigned sz = p->get_num_args(); + for (unsigned i = 0; i < sz; ++i) { + arg = ps->get_arg(i); + sort* s = m.get_sort(arg); + bool is_pattern = false; + while (a.is_array(s)) { + is_pattern = true; + unsigned arity = get_array_arity(s); + for (unsigned j = 0; j < arity; ++j) { + vars.push_back(get_array_domain(s, j)); + names.push_back(symbol(idx)); + args.push_back(m.mk_var(idx++, vars.back())); + } + ptr_vector args2; + args2.push_back(arg); + args2.append(arity, args.c_ptr()-arity); + arg = a.mk_select(args2.size(), args2.c_ptr()); + s = get_array_range(s); + } + if (is_pattern) { + pats.push_back(to_app(arg)); + } + args.push_back(arg); + } + expr* pat = 0; + expr_ref pattern(m); + pattern = m.mk_pattern(pats.size(), pats.c_ptr()); + pat = pattern.get(); + app_ref result(m); + symbol qid, skid; + result = m.mk_app(new_p, args.size(), args.c_ptr()); + result = m.mk_eq(m.mk_forall(vars.size(), vars.c_ptr(), names.c_ptr(), result, 1, qid, skid, 1, &pat), m.mk_true()); + return result; + } + + rule_set * mk_quantifier_abstraction::operator()(rule_set const & source) { + if (!m_ctx.get_params().quantify_arrays()) { + return 0; + } + m_refs.reset(); + m_old2new.reset(); + m_new2old.reset(); + rule_manager& rm = source.get_rule_manager(); + rule_set * result = alloc(rule_set, m_ctx); + unsigned sz = source.get_num_rules(); + rule_ref new_rule(rm); + app_ref_vector tail(m); + app_ref head(m); + svector neg; + rule_counter& vc = rm.get_counter(); + + for (unsigned i = 0; i < sz; ++i) { + tail.reset(); + neg.reset(); + rule & r = *source.get_rule(i); + unsigned cnt = vc.get_max_rule_var(r)+1; + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + for (unsigned j = 0; j < utsz; ++j) { + tail.push_back(mk_tail(r.get_tail(j))); + neg.push_back(r.is_neg_tail(j)); + } + for (unsigned j = utsz; j < tsz; ++j) { + tail.push_back(r.get_tail(j)); + neg.push_back(false); + } + head = mk_head(r.get_head(), cnt); + + new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + result->add_rule(new_rule); + + } + + // model converter: TBD. + // proof converter: TBD. + + if (m_old2new.empty()) { + dealloc(result); + result = 0; + } + return result; + } + + +}; + + diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.h b/src/muz_qe/dl_mk_quantifier_abstraction.h new file mode 100644 index 000000000..8c26e277a --- /dev/null +++ b/src/muz_qe/dl_mk_quantifier_abstraction.h @@ -0,0 +1,61 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_quantifier_abstraction.h + +Abstract: + + Convert clauses with array arguments to predicates + into Quantified Horn clauses. + +Author: + + Ken McMillan + Andrey Rybalchenko + Nikolaj Bjorner (nbjorner) 2013-04-02 + +Revision History: + + Based on approach suggested in SAS 2013 paper + "On Solving Universally Quantified Horn Clauses" + +--*/ +#ifndef _DL_MK_QUANTIFIER_ABSTRACTION_H_ +#define _DL_MK_QUANTIFIER_ABSTRACTION_H_ + + +#include"dl_rule_transformer.h" +#include"array_decl_plugin.h" + +namespace datalog { + + class context; + + class mk_quantifier_abstraction : public rule_transformer::plugin { + ast_manager& m; + context& m_ctx; + array_util a; + func_decl_ref_vector m_refs; + obj_map m_new2old; + obj_map m_old2new; + + func_decl* declare_pred(func_decl* old_p); + app_ref mk_head(app* p, unsigned idx); + app_ref mk_tail(app* p); + + public: + mk_quantifier_abstraction(context & ctx, unsigned priority); + + virtual ~mk_quantifier_abstraction(); + + rule_set * operator()(rule_set const & source); + }; + + + +}; + +#endif /* _DL_MK_QUANTIFIER_ABSTRACTION_H_ */ + diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.cpp b/src/muz_qe/dl_mk_quantifier_instantiation.cpp new file mode 100644 index 000000000..a5b80af4f --- /dev/null +++ b/src/muz_qe/dl_mk_quantifier_instantiation.cpp @@ -0,0 +1,295 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_quantifier_instantiation.cpp + +Abstract: + + Convert Quantified Horn clauses into non-quantified clauses using + instantiation. + +Author: + + Ken McMillan + Andrey Rybalchenko + Nikolaj Bjorner (nbjorner) 2013-04-02 + +Revision History: + + Based on approach suggested in SAS 2013 paper + "On Solving Universally Quantified Horn Clauses" + +--*/ + +#include "dl_mk_quantifier_instantiation.h" +#include "dl_context.h" + +namespace datalog { + + mk_quantifier_instantiation::mk_quantifier_instantiation( + context & ctx, unsigned priority): + plugin(priority), + m(ctx.get_manager()), + m_ctx(ctx), + m_var2cnst(m), + m_cnst2var(m), + a(m) { + } + + mk_quantifier_instantiation::~mk_quantifier_instantiation() { + + } + + void mk_quantifier_instantiation::extract_quantifiers(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs) { + conjs.reset(); + qs.reset(); + unsigned tsz = r.get_tail_size(); + for (unsigned j = 0; j < tsz; ++j) { + conjs.push_back(r.get_tail(j)); + + } + datalog::flatten_and(conjs); + for (unsigned j = 0; j < conjs.size(); ++j) { + expr* e = conjs[j].get(); + quantifier* q; + if (rule_manager::is_forall(m, e, q)) { + qs.push_back(q); + conjs[j] = conjs.back(); + conjs.pop_back(); + --j; + } + } + } + + void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, expr_ref_vector & conjs) { + expr_ref qe(m); + qe = q; + m_var2cnst(qe); + q = to_quantifier(qe); + unsigned num_patterns = q->get_num_patterns(); + for (unsigned i = 0; i < num_patterns; ++i) { + expr * pat = q->get_pattern(i); + SASSERT(m.is_pattern(pat)); + instantiate_quantifier(q, to_app(pat), conjs); + } + } + + + void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs) { + unsigned sz = pat->get_num_args(); + m_binding.reset(); + m_binding.resize(q->get_num_decls()); + term_pairs todo; + match(0, pat, 0, todo, q, conjs); + } + + void mk_quantifier_instantiation::match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs) { + while (j < todo.size()) { + expr* p = todo[j].first; + expr* t = todo[j].second; + if (is_var(p)) { + unsigned idx = to_var(p)->get_idx(); + expr* t2 = m_binding[idx]; + if (!t2) { + m_binding[idx] = t; + match(i, pat, j + 1, todo, q, conjs); + m_binding[idx] = 0; + return; + } + else if (m_uf.find(t2->get_id()) != m_uf.find(t->get_id())) { + // matching failed. + return; + } + j += 1; + continue; + } + if (!is_app(p)) { + return; + } + app* a1 = to_app(p); + unsigned id = t->get_id(); + unsigned next_id = id; + unsigned sz = todo.size(); + do { + expr* t2 = m_terms[next_id]; + if (is_app(t2)) { + app* a2 = to_app(t2); + if (a1->get_decl() == a2->get_decl() && + a1->get_num_args() == a2->get_num_args()) { + for (unsigned k = 0; k < a1->get_num_args(); ++k) { + todo.push_back(std::make_pair(a1->get_arg(k), a2->get_arg(k))); + } + match(i, pat, j + 1, todo, q, conjs); + todo.resize(sz); + } + } + next_id = m_uf.next(id); + } + while (next_id != id); + return; + } + + if (i == pat->get_num_args()) { + yield_binding(q, conjs); + return; + } + expr* arg = pat->get_arg(i); + ptr_vector* terms = 0; + + if (m_funs.find(to_app(arg)->get_decl(), terms)) { + for (unsigned k = 0; k < terms->size(); ++k) { + todo.push_back(std::make_pair(arg, (*terms)[k])); + match(i + 1, pat, j, todo, q, conjs); + todo.pop_back(); + } + } + } + + void mk_quantifier_instantiation::yield_binding(quantifier* q, expr_ref_vector& conjs) { + DEBUG_CODE( + for (unsigned i = 0; i < m_binding.size(); ++i) { + SASSERT(m_binding[i]); + }); + m_binding.reverse(); + expr_ref res(m); + instantiate(m, q, m_binding.c_ptr(), res); + m_binding.reverse(); + conjs.push_back(res); + } + + void mk_quantifier_instantiation::merge(expr* e1, expr* e2) { + unsigned i1 = e1->get_id(); + unsigned i2 = e2->get_id(); + unsigned n = std::max(i1, i2); + while (n >= m_uf.get_num_vars()) { + m_uf.mk_var(); + } + m_uf.merge(i1, i2); + } + + void mk_quantifier_instantiation::collect_egraph(expr* e) { + expr* e1, *e2; + m_todo.push_back(e); + expr_fast_mark1 visited; + while (!m_todo.empty()) { + e = m_todo.back(); + m_todo.pop_back(); + if (visited.is_marked(e)) { + continue; + } + if (e->get_id() >= m_terms.size()) { + m_terms.resize(e->get_id()+1); + } + m_terms[e->get_id()] = e; + visited.mark(e); + if (m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) { + merge(e1, e2); + } + if (is_app(e)) { + app* ap = to_app(e); + ptr_vector* terms = 0; + if (m_funs.find(ap->get_decl(), terms)) { + terms = alloc(ptr_vector); + m_funs.insert(ap->get_decl(), terms); + } + terms->push_back(e); + m_todo.append(ap->get_num_args(), ap->get_args()); + } + } + } + + void mk_quantifier_instantiation::instantiate_rule(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs, rule_set& rules) { + rule_manager& rm = m_ctx.get_rule_manager(); + expr_ref fml(m), cnst(m); + var_ref var(m); + ptr_vector sorts; + r.get_vars(sorts); + m_uf.reset(); + m_terms.reset(); + m_var2cnst.reset(); + m_cnst2var.reset(); + fml = m.mk_and(conjs.size(), conjs.c_ptr()); + + for (unsigned i = 0; i < sorts.size(); ++i) { + if (!sorts[i]) { + sorts[i] = m.mk_bool_sort(); + } + var = m.mk_var(i, sorts[i]); + cnst = m.mk_fresh_const("C", sorts[i]); + m_var2cnst.insert(var, cnst); + m_cnst2var.insert(cnst, var); + } + + fml = m.mk_and(conjs.size(), conjs.c_ptr()); + m_var2cnst(fml); + collect_egraph(fml); + + for (unsigned i = 0; i < qs.size(); ++i) { + instantiate_quantifier(qs[i].get(), conjs); + } + obj_map*>::iterator it = m_funs.begin(), end = m_funs.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + m_funs.reset(); + + fml = m.mk_and(conjs.size(), conjs.c_ptr()); + fml = m.mk_implies(fml, r.get_head()); + + rule_ref_vector added_rules(rm); + proof_ref pr(m); // proofs are TBD. + rm.mk_rule(fml, pr, added_rules); + rules.add_rules(added_rules.size(), added_rules.c_ptr()); + } + + rule_set * mk_quantifier_instantiation::operator()(rule_set const & source) { + if (!m_ctx.get_params().instantiate_quantifiers()) { + return 0; + } + bool has_quantifiers = false; + unsigned sz = source.get_num_rules(); + for (unsigned i = 0; !has_quantifiers && i < sz; ++i) { + rule& r = *source.get_rule(i); + has_quantifiers = has_quantifiers || r.has_quantifiers(); + if (r.has_negation()) { + return 0; + } + } + if (!has_quantifiers) { + return 0; + } + + expr_ref_vector conjs(m); + quantifier_ref_vector qs(m); + rule_set * result = alloc(rule_set, m_ctx); + + bool instantiated = false; + + for (unsigned i = 0; i < sz; ++i) { + rule * r = source.get_rule(i); + extract_quantifiers(*r, conjs, qs); + if (qs.empty()) { + result->add_rule(r); + } + else { + instantiate_rule(*r, conjs, qs, *result); + instantiated = true; + } + } + + // model converter: TBD. + // proof converter: TBD. + + if (!instantiated) { + dealloc(result); + result = 0; + } + return result; + } + + +}; + + diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.h b/src/muz_qe/dl_mk_quantifier_instantiation.h new file mode 100644 index 000000000..81a77e86a --- /dev/null +++ b/src/muz_qe/dl_mk_quantifier_instantiation.h @@ -0,0 +1,120 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_quantifier_instantiation.h + +Abstract: + + Convert Quantified Horn clauses into non-quantified clauses using + instantiation. + +Author: + + Ken McMillan + Andrey Rybalchenko + Nikolaj Bjorner (nbjorner) 2013-04-02 + +Revision History: + + Based on approach suggested in SAS 2013 paper + "On Solving Universally Quantified Horn Clauses" + +--*/ +#ifndef _DL_MK_QUANTIFIER_INSTANTIATION_H_ +#define _DL_MK_QUANTIFIER_INSTANTIATION_H_ + + +#include"dl_rule_transformer.h" +#include"array_decl_plugin.h" +#include"expr_safe_replace.h" + + +namespace datalog { + + class context; + + class mk_quantifier_instantiation : public rule_transformer::plugin { + typedef svector > term_pairs; + + class union_find { + unsigned_vector m_find; + unsigned_vector m_size; + unsigned_vector m_next; + public: + unsigned mk_var() { + unsigned r = m_find.size(); + m_find.push_back(r); + m_size.push_back(1); + m_next.push_back(r); + return r; + } + unsigned get_num_vars() const { return m_find.size(); } + + unsigned find(unsigned v) const { + while (true) { + unsigned new_v = m_find[v]; + if (new_v == v) + return v; + v = new_v; + } + } + + unsigned next(unsigned v) const { return m_next[v]; } + + bool is_root(unsigned v) const { return m_find[v] == v; } + + void merge(unsigned v1, unsigned v2) { + unsigned r1 = find(v1); + unsigned r2 = find(v2); + if (r1 == r2) + return; + if (m_size[r1] > m_size[r2]) + std::swap(r1, r2); + m_find[r1] = r2; + m_size[r2] += m_size[r1]; + std::swap(m_next[r1], m_next[r2]); + } + + void reset() { + m_find.reset(); + m_next.reset(); + m_size.reset(); + } + }; + ast_manager& m; + context& m_ctx; + expr_safe_replace m_var2cnst; + expr_safe_replace m_cnst2var; + array_util a; + union_find m_uf; + ptr_vector m_todo; + ptr_vector m_terms; + ptr_vector m_binding; + obj_map*> m_funs; + + + void merge(expr* e1, expr* e2); + void extract_quantifiers(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs); + void collect_egraph(expr* e); + void instantiate_rule(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs, rule_set& rules); + void instantiate_quantifier(quantifier* q, expr_ref_vector & conjs); + void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs); + void mk_quantifier_instantiation::match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs); + void mk_quantifier_instantiation::yield_binding(quantifier* q, expr_ref_vector& conjs); + + public: + mk_quantifier_instantiation(context & ctx, unsigned priority); + + virtual ~mk_quantifier_instantiation(); + + rule_set * operator()(rule_set const & source); + }; + + + +}; + +#endif /* _DL_MK_QUANTIFIER_INSTANTIATION_H_ */ + diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index 7a3316c56..774559cdb 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -42,6 +42,8 @@ def_module_params('fixedpoint', ('simplify_formulas_post', BOOL, False, "PDR: simplify derived formulas after inductive propagation"), ('slice', BOOL, True, "PDR: simplify clause set using slicing"), ('karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), + ('quantify_arrays', BOOL, False, "create quantified Horn clauses from clauses with arrays"), + ('instantiate_quantifiers', BOOL, False, "instantiate quantified Horn clauses using E-matching heuristic"), ('coalesce_rules', BOOL, False, "BMC: coalesce rules"), ('use_multicore_generalizer', BOOL, False, "PDR: extract multiple cores for blocking states"), ('use_inductive_generalizer', BOOL, True, "PDR: generalize lemmas using induction strengthening"), From cda29bc03b8e0e64099a4f7b95792fc181471a46 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Apr 2013 15:29:52 -0700 Subject: [PATCH 055/281] add abstraction and instantiation Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_context.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 9207fbe61..44852a52f 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -47,6 +47,7 @@ Revision History: #include"dl_mk_array_blast.h" #include"dl_mk_karr_invariants.h" #include"dl_mk_quantifier_abstraction.h" +#include"dl_mk_quantifier_instantiation.h" #include"datatype_decl_plugin.h" #include"expr_abstract.h" @@ -908,6 +909,7 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000)); + m_transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, *this, 32000)); m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); From 477e8cc46a10c61a211aba23acbdcd77b337dcf1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Apr 2013 20:33:22 -0700 Subject: [PATCH 056/281] debugging quantifier instantiation Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_quantifier_instantiation.cpp | 35 +++++++++------ src/muz_qe/dl_mk_quantifier_instantiation.h | 45 +++++++++++++------ 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.cpp b/src/muz_qe/dl_mk_quantifier_instantiation.cpp index a5b80af4f..11c039bf8 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.cpp +++ b/src/muz_qe/dl_mk_quantifier_instantiation.cpp @@ -18,13 +18,14 @@ Author: Revision History: - Based on approach suggested in SAS 2013 paper + Based on approach suggested in the SAS 2013 paper "On Solving Universally Quantified Horn Clauses" --*/ #include "dl_mk_quantifier_instantiation.h" #include "dl_context.h" +#include "pattern_inference.h" namespace datalog { @@ -34,12 +35,10 @@ namespace datalog { m(ctx.get_manager()), m_ctx(ctx), m_var2cnst(m), - m_cnst2var(m), - a(m) { + m_cnst2var(m) { } - mk_quantifier_instantiation::~mk_quantifier_instantiation() { - + mk_quantifier_instantiation::~mk_quantifier_instantiation() { } void mk_quantifier_instantiation::extract_quantifiers(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs) { @@ -66,8 +65,15 @@ namespace datalog { void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, expr_ref_vector & conjs) { expr_ref qe(m); qe = q; - m_var2cnst(qe); + m_var2cnst(qe); q = to_quantifier(qe); + if (q->get_num_patterns() == 0) { + proof_ref new_pr(m); + pattern_inference_params params; + pattern_inference infer(m, params); + infer(q, qe, new_pr); + q = to_quantifier(qe); + } unsigned num_patterns = q->get_num_patterns(); for (unsigned i = 0; i < num_patterns; ++i) { expr * pat = q->get_pattern(i); @@ -86,6 +92,7 @@ namespace datalog { } void mk_quantifier_instantiation::match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs) { + TRACE("dl", tout << "match" << mk_pp(pat, m) << "\n";); while (j < todo.size()) { expr* p = todo[j].first; expr* t = todo[j].second; @@ -102,7 +109,7 @@ namespace datalog { // matching failed. return; } - j += 1; + ++j; continue; } if (!is_app(p)) { @@ -125,7 +132,7 @@ namespace datalog { todo.resize(sz); } } - next_id = m_uf.next(id); + next_id = m_uf.next(next_id); } while (next_id != id); return; @@ -156,16 +163,14 @@ namespace datalog { expr_ref res(m); instantiate(m, q, m_binding.c_ptr(), res); m_binding.reverse(); + m_cnst2var(res); conjs.push_back(res); + TRACE("dl", tout << mk_pp(q, m) << "\n==>\n" << mk_pp(res, m) << "\n";); } void mk_quantifier_instantiation::merge(expr* e1, expr* e2) { unsigned i1 = e1->get_id(); unsigned i2 = e2->get_id(); - unsigned n = std::max(i1, i2); - while (n >= m_uf.get_num_vars()) { - m_uf.mk_var(); - } m_uf.merge(i1, i2); } @@ -179,7 +184,8 @@ namespace datalog { if (visited.is_marked(e)) { continue; } - if (e->get_id() >= m_terms.size()) { + unsigned n = e->get_id(); + if (n >= m_terms.size()) { m_terms.resize(e->get_id()+1); } m_terms[e->get_id()] = e; @@ -190,7 +196,7 @@ namespace datalog { if (is_app(e)) { app* ap = to_app(e); ptr_vector* terms = 0; - if (m_funs.find(ap->get_decl(), terms)) { + if (!m_funs.find(ap->get_decl(), terms)) { terms = alloc(ptr_vector); m_funs.insert(ap->get_decl(), terms); } @@ -237,6 +243,7 @@ namespace datalog { fml = m.mk_and(conjs.size(), conjs.c_ptr()); fml = m.mk_implies(fml, r.get_head()); + TRACE("dl", r.display(m_ctx, tout); tout << mk_pp(fml, m) << "\n";); rule_ref_vector added_rules(rm); proof_ref pr(m); // proofs are TBD. diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.h b/src/muz_qe/dl_mk_quantifier_instantiation.h index 81a77e86a..969a0bf23 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.h +++ b/src/muz_qe/dl_mk_quantifier_instantiation.h @@ -18,7 +18,7 @@ Author: Revision History: - Based on approach suggested in SAS 2013 paper + Based on approach suggested in the SAS 2013 paper "On Solving Universally Quantified Horn Clauses" --*/ @@ -27,7 +27,6 @@ Revision History: #include"dl_rule_transformer.h" -#include"array_decl_plugin.h" #include"expr_safe_replace.h" @@ -42,6 +41,12 @@ namespace datalog { unsigned_vector m_find; unsigned_vector m_size; unsigned_vector m_next; + + void ensure_size(unsigned v) { + while (v >= get_num_vars()) { + mk_var(); + } + } public: unsigned mk_var() { unsigned r = m_find.size(); @@ -53,6 +58,9 @@ namespace datalog { unsigned get_num_vars() const { return m_find.size(); } unsigned find(unsigned v) const { + if (v >= get_num_vars()) { + return v; + } while (true) { unsigned new_v = m_find[v]; if (new_v == v) @@ -61,15 +69,24 @@ namespace datalog { } } - unsigned next(unsigned v) const { return m_next[v]; } + unsigned next(unsigned v) const { + if (v >= get_num_vars()) { + return v; + } + return m_next[v]; + } - bool is_root(unsigned v) const { return m_find[v] == v; } + bool is_root(unsigned v) const { + return v >= get_num_vars() || m_find[v] == v; + } void merge(unsigned v1, unsigned v2) { unsigned r1 = find(v1); unsigned r2 = find(v2); if (r1 == r2) return; + ensure_size(v1); + ensure_size(v2); if (m_size[r1] > m_size[r2]) std::swap(r1, r2); m_find[r1] = r2; @@ -83,15 +100,15 @@ namespace datalog { m_size.reset(); } }; - ast_manager& m; - context& m_ctx; + + ast_manager& m; + context& m_ctx; expr_safe_replace m_var2cnst; expr_safe_replace m_cnst2var; - array_util a; - union_find m_uf; - ptr_vector m_todo; - ptr_vector m_terms; - ptr_vector m_binding; + union_find m_uf; + ptr_vector m_todo; + ptr_vector m_terms; + ptr_vector m_binding; obj_map*> m_funs; @@ -100,9 +117,9 @@ namespace datalog { void collect_egraph(expr* e); void instantiate_rule(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs, rule_set& rules); void instantiate_quantifier(quantifier* q, expr_ref_vector & conjs); - void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs); - void mk_quantifier_instantiation::match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs); - void mk_quantifier_instantiation::yield_binding(quantifier* q, expr_ref_vector& conjs); + void instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs); + void match(unsigned i, app* pat, unsigned j, term_pairs& todo, quantifier* q, expr_ref_vector& conjs); + void yield_binding(quantifier* q, expr_ref_vector& conjs); public: mk_quantifier_instantiation(context & ctx, unsigned priority); From 67e9d746533b1fe81a8de567b1d9644c7c5be688 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 3 Apr 2013 09:44:31 -0700 Subject: [PATCH 057/281] constify a few functions Signed-off-by: Nuno Lopes --- src/ast/bv_decl_plugin.cpp | 4 ++-- src/ast/bv_decl_plugin.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 0ef3b60d6..8b77244f9 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -766,7 +766,7 @@ bool bv_recognizers::is_zero(expr const * n) const { return decl->get_parameter(0).get_rational().is_zero(); } -bool bv_recognizers::is_extract(expr const* e, unsigned& low, unsigned& high, expr*& b) { +bool bv_recognizers::is_extract(expr const* e, unsigned& low, unsigned& high, expr*& b) const { if (!is_extract(e)) return false; low = get_extract_low(e); high = get_extract_high(e); @@ -774,7 +774,7 @@ bool bv_recognizers::is_extract(expr const* e, unsigned& low, unsigned& high, ex return true; } -bool bv_recognizers::is_bv2int(expr const* e, expr*& r) { +bool bv_recognizers::is_bv2int(expr const* e, expr*& r) const { if (!is_bv2int(e)) return false; r = to_app(e)->get_arg(0); return true; diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 8ea90f844..c5ebfb2d9 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -288,10 +288,10 @@ public: bool is_extract(expr const * e) const { return is_app_of(e, get_fid(), OP_EXTRACT); } unsigned get_extract_high(func_decl const * f) const { return f->get_parameter(0).get_int(); } unsigned get_extract_low(func_decl const * f) const { return f->get_parameter(1).get_int(); } - unsigned get_extract_high(expr const * n) { SASSERT(is_extract(n)); return get_extract_high(to_app(n)->get_decl()); } - unsigned get_extract_low(expr const * n) { SASSERT(is_extract(n)); return get_extract_low(to_app(n)->get_decl()); } - bool is_extract(expr const * e, unsigned & low, unsigned & high, expr * & b); - bool is_bv2int(expr const * e, expr * & r); + unsigned get_extract_high(expr const * n) const { SASSERT(is_extract(n)); return get_extract_high(to_app(n)->get_decl()); } + unsigned get_extract_low(expr const * n) const { SASSERT(is_extract(n)); return get_extract_low(to_app(n)->get_decl()); } + bool is_extract(expr const * e, unsigned & low, unsigned & high, expr * & b) const; + bool is_bv2int(expr const * e, expr * & r) const; bool is_bv_add(expr const * e) const { return is_app_of(e, get_fid(), OP_BADD); } bool is_bv_sub(expr const * e) const { return is_app_of(e, get_fid(), OP_BSUB); } bool is_bv_mul(expr const * e) const { return is_app_of(e, get_fid(), OP_BMUL); } From 2a745d5224c416ce81bcf8f5d586cdc24a879d1e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Apr 2013 14:46:58 -0700 Subject: [PATCH 058/281] adding model convertion to quantifier transformation Signed-off-by: Nikolaj Bjorner --- src/api/api_datalog.cpp | 4 +- src/muz_qe/datalog_parser.cpp | 4 +- src/muz_qe/dl_cmds.cpp | 1 + src/muz_qe/dl_context.cpp | 11 +- src/muz_qe/dl_context.h | 14 +- src/muz_qe/dl_mk_karr_invariants.cpp | 2 +- src/muz_qe/dl_mk_loop_counter.cpp | 4 +- src/muz_qe/dl_mk_quantifier_abstraction.cpp | 160 ++++++++++++++++-- src/muz_qe/dl_mk_quantifier_abstraction.h | 5 +- src/muz_qe/dl_mk_quantifier_instantiation.cpp | 38 ++--- src/muz_qe/dl_mk_quantifier_instantiation.h | 1 - src/muz_qe/dl_rule.cpp | 2 +- src/muz_qe/horn_tactic.cpp | 2 +- 13 files changed, 188 insertions(+), 60 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 0f100e747..f6eadfea0 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -358,7 +358,7 @@ extern "C" { v->m_ast_vector.push_back(coll.m_queries[i].get()); } for (unsigned i = 0; i < coll.m_rels.size(); ++i) { - to_fixedpoint_ref(d)->ctx().register_predicate(coll.m_rels[i].get()); + to_fixedpoint_ref(d)->ctx().register_predicate(coll.m_rels[i].get(), true); } for (unsigned i = 0; i < coll.m_rules.size(); ++i) { to_fixedpoint_ref(d)->add_rule(coll.m_rules[i].get(), coll.m_names[i]); @@ -415,7 +415,7 @@ extern "C" { void Z3_API Z3_fixedpoint_register_relation(Z3_context c,Z3_fixedpoint d, Z3_func_decl f) { Z3_TRY; LOG_Z3_fixedpoint_register_relation(c, d, f); - to_fixedpoint_ref(d)->ctx().register_predicate(to_func_decl(f)); + to_fixedpoint_ref(d)->ctx().register_predicate(to_func_decl(f), true); Z3_CATCH; } diff --git a/src/muz_qe/datalog_parser.cpp b/src/muz_qe/datalog_parser.cpp index cfe283410..545f3e14a 100644 --- a/src/muz_qe/datalog_parser.cpp +++ b/src/muz_qe/datalog_parser.cpp @@ -441,6 +441,7 @@ protected: unsigned m_sym_idx; std::string m_path; str2sort m_sort_dict; + // true if an error occured during the current call to the parse_stream // function @@ -812,7 +813,8 @@ protected: } f = m_manager.mk_func_decl(s, domain.size(), domain.c_ptr(), m_manager.mk_bool_sort()); - m_context.register_predicate(f); + m_context.register_predicate(f, true); + while (tok == TK_ID) { char const* pred_pragma = m_lexer->get_token_data(); if(strcmp(pred_pragma, "printtuples")==0 || strcmp(pred_pragma, "outputtuples")==0) { diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp index aef14e051..c1e3f85f9 100644 --- a/src/muz_qe/dl_cmds.cpp +++ b/src/muz_qe/dl_cmds.cpp @@ -229,6 +229,7 @@ public: status = dlctx.query(m_target); } catch (z3_error & ex) { + ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl; throw ex; } catch (z3_exception& ex) { diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 44852a52f..a928d7ba7 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -302,14 +302,6 @@ namespace datalog { return m_preds.contains(pred); } - func_decl * context::try_get_predicate_decl(symbol pred_name) const { - func_decl * res; - if (!m_preds_by_name.find(pred_name, res)) { - return 0; - } - return res; - } - void context::register_variable(func_decl* var) { m_vars.push_back(m.mk_const(var)); } @@ -361,7 +353,6 @@ namespace datalog { m_pinned.push_back(decl); m_preds.insert(decl); if (named) { - SASSERT(!m_preds_by_name.contains(decl->get_name())); m_preds_by_name.insert(decl->get_name(), decl); } } @@ -448,7 +439,7 @@ namespace datalog { func_decl* new_pred = m.mk_fresh_func_decl(prefix, suffix, arity, domain, m.mk_bool_sort()); - register_predicate(new_pred); + register_predicate(new_pred, true); if (m_rel.get()) { m_rel->inherit_predicate_kind(new_pred, orig_pred); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index 0c4558a28..cb432d4e9 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -183,18 +183,22 @@ namespace datalog { retrieved by the try_get_predicate_decl() function. Auxiliary predicates introduced e.g. by rule transformations do not need to be named. */ - void register_predicate(func_decl * pred, bool named = true); + void register_predicate(func_decl * pred, bool named); bool is_predicate(func_decl * pred) const; - + /** \brief If a predicate name has a \c func_decl object assigned, return pointer to it; otherwise return 0. - + Not all \c func_decl object used as relation identifiers need to be assigned to their names. Generally, the names coming from the parses are registered here. - */ - func_decl * try_get_predicate_decl(symbol pred_name) const; + */ + func_decl * try_get_predicate_decl(symbol const& pred_name) const { + func_decl * res = 0; + m_preds_by_name.find(pred_name, res); + return res; + } /** \brief Create a fresh head predicate declaration. diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 2596a7337..7932735fe 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -206,7 +206,7 @@ namespace datalog { for (; it != end; ++it) { rule_ref r(*it, m_inner_ctx.get_rule_manager()); m_inner_ctx.add_rule(r); - m_inner_ctx.register_predicate(r->get_decl()); + m_inner_ctx.register_predicate(r->get_decl(), false); } m_inner_ctx.close(); rule_set::decl2rules::iterator dit = source.begin_grouped_rules(); diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp index 172198746..6b95671f2 100644 --- a/src/muz_qe/dl_mk_loop_counter.cpp +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -72,14 +72,14 @@ namespace datalog { for (unsigned j = 0; j < utsz; ++j, ++cnt) { tail.push_back(add_arg(r.get_tail(j), cnt)); neg.push_back(r.is_neg_tail(j)); - ctx.register_predicate(tail.back()->get_decl()); + ctx.register_predicate(tail.back()->get_decl(), false); } for (unsigned j = utsz; j < tsz; ++j) { tail.push_back(r.get_tail(j)); neg.push_back(false); } head = add_arg(r.get_head(), cnt); - ctx.register_predicate(head->get_decl()); + ctx.register_predicate(head->get_decl(), false); // set the loop counter to be an increment of the previous bool found = false; unsigned last = head->get_num_args()-1; diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.cpp b/src/muz_qe/dl_mk_quantifier_abstraction.cpp index 511ab7b9a..0dd48ef53 100644 --- a/src/muz_qe/dl_mk_quantifier_abstraction.cpp +++ b/src/muz_qe/dl_mk_quantifier_abstraction.cpp @@ -21,9 +21,110 @@ Revision History: #include "dl_mk_quantifier_abstraction.h" #include "dl_context.h" +#include "expr_safe_replace.h" +#include "expr_abstract.h" namespace datalog { + + // model converter: + // Given model for P^(x, y, i, a[i]) + // create model: P(x,y,a) == forall i . P^(x,y,i,a[i]) + // requires substitution and list of bound variables. + + class mk_quantifier_abstraction::qa_model_converter : public model_converter { + ast_manager& m; + func_decl_ref_vector m_old_funcs; + func_decl_ref_vector m_new_funcs; + vector m_subst; + vector > m_bound; + + public: + + qa_model_converter(ast_manager& m): + m(m), m_old_funcs(m), m_new_funcs(m) {} + + virtual ~qa_model_converter() {} + + virtual model_converter * translate(ast_translation & translator) { + return alloc(qa_model_converter, m); + } + + void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, svector const& bound) { + m_old_funcs.push_back(old_p); + m_new_funcs.push_back(new_p); + m_subst.push_back(sub); + m_bound.push_back(bound); + } + + virtual void operator()(model_ref & model) { + for (unsigned i = 0; i < m_new_funcs.size(); ++i) { + func_decl* p = m_new_funcs[i].get(); + func_decl* q = m_old_funcs[i].get(); + expr_ref_vector const& s = m_subst[i]; + svector const& is_bound = m_bound[i]; + func_interp* f = 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); + model->register_decl(p, f); + func_interp* g = alloc(func_interp, m, arity_q); + + if (f) { + body = f->get_interp(); + SASSERT(!f->is_partial()); + SASSERT(body); + } + else { + body = m.mk_false(); + } + // TBD. create quantifier wrapper around body. + + // 1. replace variables by the compound terms from + // the original predicate. + expr_safe_replace sub(m); + for (unsigned i = 0; i < s.size(); ++i) { + sub.insert(m.mk_var(i, m.get_sort(s[i])), s[i]); + } + sub(body); + sub.reset(); + + // 2. replace bound variables by constants. + expr_ref_vector consts(m), bound(m), free(m); + ptr_vector sorts; + svector names; + for (unsigned i = 0; i < q->get_arity(); ++i) { + sort* s = q->get_domain(i); + consts.push_back(m.mk_fresh_const("C", s)); + sub.insert(m.mk_var(i, s), consts.back()); + if (is_bound[i]) { + bound.push_back(consts.back()); + names.push_back(symbol(i)); + sorts.push_back(s); + } + else { + free.push_back(consts.back()); + } + } + sub(body); + sub.reset(); + + // 3. abstract and quantify those variables that should be bound. + expr_abstract(m, 0, bound.size(), bound.c_ptr(), body, body); + body = m.mk_forall(names.size(), sorts.c_ptr(), names.c_ptr(), body); + + // 4. replace remaining constants by variables. + for (unsigned i = 0; i < free.size(); ++i) { + sub.insert(free[i].get(), m.mk_var(i, m.get_sort(free[i].get()))); + } + sub(body); + g->set_else(body); + model->register_decl(q, g); + } + } + }; + mk_quantifier_abstraction::mk_quantifier_abstraction( context & ctx, unsigned priority): plugin(priority), @@ -33,8 +134,7 @@ namespace datalog { m_refs(m) { } - mk_quantifier_abstraction::~mk_quantifier_abstraction() { - + mk_quantifier_abstraction::~mk_quantifier_abstraction() { } func_decl* mk_quantifier_abstraction::declare_pred(func_decl* old_p) { @@ -52,22 +152,41 @@ namespace datalog { func_decl* new_p = 0; if (!m_old2new.find(old_p, new_p)) { + expr_ref_vector sub(m); + svector bound; sort_ref_vector domain(m); + expr_ref arg(m); for (unsigned i = 0; i < sz; ++i) { sort* s = old_p->get_domain(i); + unsigned lookahead = 0; + sort* s0 = s; + while (a.is_array(s0)) { + lookahead += get_array_arity(s0); + s0 = get_array_range(s0); + } + arg = m.mk_var(bound.size() + lookahead, s); while (a.is_array(s)) { unsigned arity = get_array_arity(s); + expr_ref_vector args(m); for (unsigned j = 0; j < arity; ++j) { domain.push_back(get_array_domain(s, j)); + args.push_back(m.mk_var(bound.size(), domain.back())); + bound.push_back(true); } + arg = mk_select(arg, args.size(), args.c_ptr()); s = get_array_range(s); } domain.push_back(s); + bound.push_back(false); + sub.push_back(arg); } SASSERT(old_p->get_range() == m.mk_bool_sort()); new_p = m.mk_func_decl(old_p->get_name(), domain.size(), domain.c_ptr(), old_p->get_range()); m_refs.push_back(new_p); - m_ctx.register_predicate(new_p); + m_ctx.register_predicate(new_p, false); + if (m_mc) { + m_mc->insert(old_p, new_p, sub, bound); + } } return new_p; } @@ -88,10 +207,7 @@ namespace datalog { for (unsigned j = 0; j < arity; ++j) { args.push_back(m.mk_var(idx++, get_array_domain(s, j))); } - ptr_vector args2; - args2.push_back(arg); - args2.append(arity, args.c_ptr()-arity); - arg = a.mk_select(args2.size(), args2.c_ptr()); + arg = mk_select(arg, arity, args.c_ptr()+args.size()-arity); s = get_array_range(s); } args.push_back(arg); @@ -130,10 +246,7 @@ namespace datalog { names.push_back(symbol(idx)); args.push_back(m.mk_var(idx++, vars.back())); } - ptr_vector args2; - args2.push_back(arg); - args2.append(arity, args.c_ptr()-arity); - arg = a.mk_select(args2.size(), args2.c_ptr()); + arg = mk_select(arg, arity, args.c_ptr()+args.size()-arity); s = get_array_range(s); } if (is_pattern) { @@ -151,8 +264,16 @@ namespace datalog { result = m.mk_eq(m.mk_forall(vars.size(), vars.c_ptr(), names.c_ptr(), result, 1, qid, skid, 1, &pat), m.mk_true()); return result; } + + expr * mk_quantifier_abstraction::mk_select(expr* arg, unsigned num_args, expr* const* args) { + ptr_vector args2; + args2.push_back(arg); + args2.append(num_args, args); + return a.mk_select(args2.size(), args2.c_ptr()); + } rule_set * mk_quantifier_abstraction::operator()(rule_set const & source) { + TRACE("dl", tout << "quantify " << source.get_num_rules() << " " << m_ctx.get_params().quantify_arrays() << "\n";); if (!m_ctx.get_params().quantify_arrays()) { return 0; } @@ -168,6 +289,10 @@ namespace datalog { svector neg; rule_counter& vc = rm.get_counter(); + if (m_ctx.get_model_converter()) { + m_mc = alloc(qa_model_converter, m); + } + for (unsigned i = 0; i < sz; ++i) { tail.reset(); neg.reset(); @@ -186,17 +311,22 @@ namespace datalog { head = mk_head(r.get_head(), cnt); new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + TRACE("dl", r.display(m_ctx, tout); new_rule->display(m_ctx, tout);); result->add_rule(new_rule); - } - - // model converter: TBD. - // proof converter: TBD. + + // proof converter: proofs are not necessarily preserved using this transformation. if (m_old2new.empty()) { dealloc(result); + dealloc(m_mc); result = 0; } + else { + m_ctx.add_model_converter(m_mc); + } + m_mc = 0; + return result; } diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.h b/src/muz_qe/dl_mk_quantifier_abstraction.h index 8c26e277a..c7e6c6bb4 100644 --- a/src/muz_qe/dl_mk_quantifier_abstraction.h +++ b/src/muz_qe/dl_mk_quantifier_abstraction.h @@ -34,16 +34,19 @@ namespace datalog { class context; class mk_quantifier_abstraction : public rule_transformer::plugin { + class qa_model_converter; ast_manager& m; context& m_ctx; array_util a; - func_decl_ref_vector m_refs; + func_decl_ref_vector m_refs; obj_map m_new2old; obj_map m_old2new; + qa_model_converter* m_mc; func_decl* declare_pred(func_decl* old_p); app_ref mk_head(app* p, unsigned idx); app_ref mk_tail(app* p); + expr* mk_select(expr* a, unsigned num_args, expr* const* args); public: mk_quantifier_abstraction(context & ctx, unsigned priority); diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.cpp b/src/muz_qe/dl_mk_quantifier_instantiation.cpp index 11c039bf8..993e5ada5 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.cpp +++ b/src/muz_qe/dl_mk_quantifier_instantiation.cpp @@ -46,8 +46,7 @@ namespace datalog { qs.reset(); unsigned tsz = r.get_tail_size(); for (unsigned j = 0; j < tsz; ++j) { - conjs.push_back(r.get_tail(j)); - + conjs.push_back(r.get_tail(j)); } datalog::flatten_and(conjs); for (unsigned j = 0; j < conjs.size(); ++j) { @@ -98,17 +97,12 @@ namespace datalog { expr* t = todo[j].second; if (is_var(p)) { unsigned idx = to_var(p)->get_idx(); - expr* t2 = m_binding[idx]; - if (!t2) { + if (!m_binding[idx]) { m_binding[idx] = t; match(i, pat, j + 1, todo, q, conjs); m_binding[idx] = 0; return; } - else if (m_uf.find(t2->get_id()) != m_uf.find(t->get_id())) { - // matching failed. - return; - } ++j; continue; } @@ -168,12 +162,6 @@ namespace datalog { TRACE("dl", tout << mk_pp(q, m) << "\n==>\n" << mk_pp(res, m) << "\n";); } - void mk_quantifier_instantiation::merge(expr* e1, expr* e2) { - unsigned i1 = e1->get_id(); - unsigned i2 = e2->get_id(); - m_uf.merge(i1, i2); - } - void mk_quantifier_instantiation::collect_egraph(expr* e) { expr* e1, *e2; m_todo.push_back(e); @@ -186,12 +174,12 @@ namespace datalog { } unsigned n = e->get_id(); if (n >= m_terms.size()) { - m_terms.resize(e->get_id()+1); + m_terms.resize(n+1); } - m_terms[e->get_id()] = e; + m_terms[n] = e; visited.mark(e); if (m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) { - merge(e1, e2); + m_uf.merge(e1->get_id(), e2->get_id()); } if (is_app(e)) { app* ap = to_app(e); @@ -246,12 +234,23 @@ namespace datalog { TRACE("dl", r.display(m_ctx, tout); tout << mk_pp(fml, m) << "\n";); rule_ref_vector added_rules(rm); - proof_ref pr(m); // proofs are TBD. + proof_ref pr(m); rm.mk_rule(fml, pr, added_rules); + if (r.get_proof()) { + // use def-axiom to encode that new rule is a weakening of the original. + proof* p1 = r.get_proof(); + for (unsigned i = 0; i < added_rules.size(); ++i) { + rule* r2 = added_rules[i].get(); + r2->to_formula(fml); + pr = m.mk_modus_ponens(m.mk_def_axiom(m.mk_implies(m.get_fact(p1), fml)), p1); + r2->set_proof(m, pr); + } + } rules.add_rules(added_rules.size(), added_rules.c_ptr()); } rule_set * mk_quantifier_instantiation::operator()(rule_set const & source) { + TRACE("dl", tout << m_ctx.get_params().instantiate_quantifiers() << "\n";); if (!m_ctx.get_params().instantiate_quantifiers()) { return 0; } @@ -286,8 +285,7 @@ namespace datalog { } } - // model converter: TBD. - // proof converter: TBD. + // model convertion: identity function. if (!instantiated) { dealloc(result); diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.h b/src/muz_qe/dl_mk_quantifier_instantiation.h index 969a0bf23..138d5abee 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.h +++ b/src/muz_qe/dl_mk_quantifier_instantiation.h @@ -112,7 +112,6 @@ namespace datalog { obj_map*> m_funs; - void merge(expr* e1, expr* e2); void extract_quantifiers(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs); void collect_egraph(expr* e); void instantiate_rule(rule& r, expr_ref_vector& conjs, quantifier_ref_vector& qs, rule_set& rules); diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 14a316e48..b7d6d9fae 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -135,7 +135,7 @@ namespace datalog { h.set_name(name); h(fml, p, fmls, prs); for (unsigned i = 0; i < h.get_fresh_predicates().size(); ++i) { - m_ctx.register_predicate(h.get_fresh_predicates()[i]); + m_ctx.register_predicate(h.get_fresh_predicates()[i], false); } for (unsigned i = 0; i < fmls.size(); ++i) { mk_rule_core2(fmls[i].get(), prs[i].get(), rules, name); diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 02c41c091..1a8f562d9 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -92,7 +92,7 @@ class horn_tactic : public tactic { void register_predicate(expr* a) { SASSERT(is_predicate(a)); - m_ctx.register_predicate(to_app(a)->get_decl(), true); + m_ctx.register_predicate(to_app(a)->get_decl(), false); } void check_predicate(ast_mark& mark, expr* a) { From 1c96a7d52f48b42891e5f40fa47e0b38c77a0b2e Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 3 Apr 2013 15:51:09 -0700 Subject: [PATCH 059/281] Add option smt.bv.enable_int2bv in the new parameter setting framework. This is the new name for the old parameter :bv-enable-int2bv-propagation. This modification addresses an issue reported at http://stackoverflow.com/questions/15798984/bv-enable-int2bv-propagation-option. Signed-off-by: Leonardo de Moura --- src/smt/params/smt_params_helper.pyg | 1 + src/smt/params/theory_bv_params.cpp | 1 + src/util/gparams.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 43dd1b586..21b5c6281 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -29,6 +29,7 @@ def_module_params(module_name='smt', ('qi.cost', STRING, '(+ weight generation)', 'expression specifying what is the cost of a given quantifier instantiation'), ('qi.max_multi_patterns', UINT, 0, 'specify the number of extra multi patterns'), ('bv.reflect', BOOL, True, 'create enode for every bit-vector term'), + ('bv.enable_int2bv', BOOL, False, 'enable support for int2bv and bv2int operators'), ('arith.random_initial_value', BOOL, False, 'use random initial values in the simplex-based procedure for linear arithmetic'), ('arith.solver', UINT, 2, 'arithmetic solver: 0 - no solver, 1 - bellman-ford based solver (diff. logic only), 2 - simplex based solver, 3 - floyd-warshall based solver (diff. logic only) and no theory combination'), ('arith.nl', BOOL, True, '(incomplete) nonlinear arithmetic support based on Groebner basis and interval propagation'), diff --git a/src/smt/params/theory_bv_params.cpp b/src/smt/params/theory_bv_params.cpp index c2a31c59d..d3f386ab4 100644 --- a/src/smt/params/theory_bv_params.cpp +++ b/src/smt/params/theory_bv_params.cpp @@ -22,4 +22,5 @@ Revision History: void theory_bv_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); m_bv_reflect = p.bv_reflect(); + m_bv_enable_int2bv2int = p.bv_enable_int2bv(); } diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 8b1fbe40e..3b2e8edc1 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -49,6 +49,7 @@ char const * g_params_renames[] = { "restart_factor", "smt.restart_factor", "arith_random_initial_value", "smt.arith.random_initial_value", "bv_reflect", "smt.bv.reflect", + "bv_enable_int2bv_propagation", "smt.bv.enable_int2bv", "qi_cost", "smt.qi.cost", "qi_eager_threshold", "smt.qi.eager_threshold", "nl_arith", "smt.arith.nl", From 0b7a270883dc8b66070b88ed2ca132aa5a6d5b48 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Apr 2013 16:53:09 -0700 Subject: [PATCH 060/281] debug quantifier transforms Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_context.cpp | 5 +- src/muz_qe/dl_mk_quantifier_abstraction.cpp | 125 ++++++++++++-------- src/muz_qe/dl_rule_set.h | 1 - 3 files changed, 82 insertions(+), 49 deletions(-) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index a928d7ba7..852d8f847 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -899,7 +899,10 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); - m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000)); + if (get_params().quantify_arrays()) { + m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000)); + m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 32500)); + } m_transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, *this, 32000)); m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.cpp b/src/muz_qe/dl_mk_quantifier_abstraction.cpp index 0dd48ef53..d4abb1ffc 100644 --- a/src/muz_qe/dl_mk_quantifier_abstraction.cpp +++ b/src/muz_qe/dl_mk_quantifier_abstraction.cpp @@ -37,6 +37,7 @@ namespace datalog { func_decl_ref_vector m_old_funcs; func_decl_ref_vector m_new_funcs; vector m_subst; + vector m_sorts; vector > m_bound; public: @@ -50,25 +51,27 @@ namespace datalog { return alloc(qa_model_converter, m); } - void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, svector const& bound) { + void insert(func_decl* old_p, func_decl* new_p, expr_ref_vector& sub, sort_ref_vector& sorts, svector const& bound) { m_old_funcs.push_back(old_p); m_new_funcs.push_back(new_p); m_subst.push_back(sub); m_bound.push_back(bound); + m_sorts.push_back(sorts); } - virtual void operator()(model_ref & model) { + virtual void operator()(model_ref & old_model) { + model_ref new_model = alloc(model, m); for (unsigned i = 0; i < m_new_funcs.size(); ++i) { func_decl* p = m_new_funcs[i].get(); func_decl* q = m_old_funcs[i].get(); - expr_ref_vector const& s = m_subst[i]; + expr_ref_vector const& sub = m_subst[i]; + sort_ref_vector const& sorts = m_sorts[i]; svector const& is_bound = m_bound[i]; - func_interp* f = model->get_func_interp(p); + 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); - model->register_decl(p, f); func_interp* g = alloc(func_interp, m, arity_q); if (f) { @@ -79,49 +82,56 @@ namespace datalog { else { body = m.mk_false(); } - // TBD. create quantifier wrapper around body. + // Create quantifier wrapper around body. + TRACE("dl", tout << mk_pp(body, m) << "\n";); // 1. replace variables by the compound terms from // the original predicate. - expr_safe_replace sub(m); - for (unsigned i = 0; i < s.size(); ++i) { - sub.insert(m.mk_var(i, m.get_sort(s[i])), s[i]); + expr_safe_replace rep(m); + for (unsigned i = 0; i < sub.size(); ++i) { + rep.insert(m.mk_var(i, m.get_sort(sub[i])), sub[i]); } - sub(body); - sub.reset(); + rep(body); + rep.reset(); + TRACE("dl", tout << mk_pp(body, m) << "\n";); // 2. replace bound variables by constants. expr_ref_vector consts(m), bound(m), free(m); - ptr_vector sorts; svector names; - for (unsigned i = 0; i < q->get_arity(); ++i) { - sort* s = q->get_domain(i); + ptr_vector bound_sorts; + for (unsigned i = 0; i < sorts.size(); ++i) { + sort* s = sorts[i]; consts.push_back(m.mk_fresh_const("C", s)); - sub.insert(m.mk_var(i, s), consts.back()); + rep.insert(m.mk_var(i, s), consts.back()); if (is_bound[i]) { bound.push_back(consts.back()); names.push_back(symbol(i)); - sorts.push_back(s); + bound_sorts.push_back(s); } else { free.push_back(consts.back()); } } - sub(body); - sub.reset(); + rep(body); + rep.reset(); + TRACE("dl", tout << mk_pp(body, m) << "\n";); // 3. abstract and quantify those variables that should be bound. expr_abstract(m, 0, bound.size(), bound.c_ptr(), body, body); - body = m.mk_forall(names.size(), sorts.c_ptr(), names.c_ptr(), body); + body = m.mk_forall(names.size(), bound_sorts.c_ptr(), names.c_ptr(), body); + TRACE("dl", tout << mk_pp(body, m) << "\n";); // 4. replace remaining constants by variables. for (unsigned i = 0; i < free.size(); ++i) { - sub.insert(free[i].get(), m.mk_var(i, m.get_sort(free[i].get()))); + rep.insert(free[i].get(), m.mk_var(i, m.get_sort(free[i].get()))); } - sub(body); + rep(body); g->set_else(body); - model->register_decl(q, g); + TRACE("dl", tout << mk_pp(body, m) << "\n";); + + new_model->register_decl(q, g); } + old_model = new_model; } }; @@ -139,6 +149,10 @@ namespace datalog { func_decl* mk_quantifier_abstraction::declare_pred(func_decl* old_p) { + if (m_ctx.is_output_predicate(old_p)) { + return 0; + } + unsigned sz = old_p->get_arity(); unsigned num_arrays = 0; for (unsigned i = 0; i < sz; ++i) { @@ -152,26 +166,29 @@ namespace datalog { func_decl* new_p = 0; if (!m_old2new.find(old_p, new_p)) { - expr_ref_vector sub(m); - svector bound; - sort_ref_vector domain(m); + expr_ref_vector sub(m), vars(m); + svector bound; + sort_ref_vector domain(m), sorts(m); expr_ref arg(m); for (unsigned i = 0; i < sz; ++i) { - sort* s = old_p->get_domain(i); + sort* s0 = old_p->get_domain(i); unsigned lookahead = 0; - sort* s0 = s; - while (a.is_array(s0)) { - lookahead += get_array_arity(s0); - s0 = get_array_range(s0); + sort* s = s0; + while (a.is_array(s)) { + lookahead += get_array_arity(s); + s = get_array_range(s); } - arg = m.mk_var(bound.size() + lookahead, s); + arg = m.mk_var(bound.size() + lookahead, s0); + s = s0; while (a.is_array(s)) { unsigned arity = get_array_arity(s); expr_ref_vector args(m); for (unsigned j = 0; j < arity; ++j) { - domain.push_back(get_array_domain(s, j)); - args.push_back(m.mk_var(bound.size(), domain.back())); + sort* s1 = get_array_domain(s, j); + domain.push_back(s1); + args.push_back(m.mk_var(bound.size(), s1)); bound.push_back(true); + sorts.push_back(s1); } arg = mk_select(arg, args.size(), args.c_ptr()); s = get_array_range(s); @@ -179,14 +196,16 @@ namespace datalog { domain.push_back(s); bound.push_back(false); sub.push_back(arg); + sorts.push_back(s0); } SASSERT(old_p->get_range() == m.mk_bool_sort()); new_p = m.mk_func_decl(old_p->get_name(), domain.size(), domain.c_ptr(), old_p->get_range()); m_refs.push_back(new_p); m_ctx.register_predicate(new_p, false); if (m_mc) { - m_mc->insert(old_p, new_p, sub, bound); + m_mc->insert(old_p, new_p, sub, sorts, bound); } + m_old2new.insert(old_p, new_p); } return new_p; } @@ -212,6 +231,11 @@ namespace datalog { } args.push_back(arg); } + TRACE("dl", + tout << mk_pp(new_p, m) << "\n"; + for (unsigned i = 0; i < args.size(); ++i) { + tout << mk_pp(args[i].get(), m) << "\n"; + }); return app_ref(m.mk_app(new_p, args.size(), args.c_ptr()), m); } @@ -237,7 +261,7 @@ namespace datalog { for (unsigned i = 0; i < sz; ++i) { arg = ps->get_arg(i); sort* s = m.get_sort(arg); - bool is_pattern = false; + bool is_pattern = false; while (a.is_array(s)) { is_pattern = true; unsigned arity = get_array_arity(s); @@ -277,42 +301,49 @@ namespace datalog { if (!m_ctx.get_params().quantify_arrays()) { return 0; } + unsigned sz = source.get_num_rules(); + for (unsigned i = 0; i < sz; ++i) { + rule& r = *source.get_rule(i); + if (r.has_negation()) { + return 0; + } + } + m_refs.reset(); m_old2new.reset(); m_new2old.reset(); rule_manager& rm = source.get_rule_manager(); - rule_set * result = alloc(rule_set, m_ctx); - unsigned sz = source.get_num_rules(); rule_ref new_rule(rm); - app_ref_vector tail(m); + expr_ref_vector tail(m); app_ref head(m); - svector neg; + expr_ref fml(m); rule_counter& vc = rm.get_counter(); if (m_ctx.get_model_converter()) { m_mc = alloc(qa_model_converter, m); } + rule_set * result = alloc(rule_set, m_ctx); - for (unsigned i = 0; i < sz; ++i) { + for (unsigned i = 0; i < sz; ++i) { tail.reset(); - neg.reset(); rule & r = *source.get_rule(i); + TRACE("dl", r.display(m_ctx, tout); ); unsigned cnt = vc.get_max_rule_var(r)+1; unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); for (unsigned j = 0; j < utsz; ++j) { tail.push_back(mk_tail(r.get_tail(j))); - neg.push_back(r.is_neg_tail(j)); } for (unsigned j = utsz; j < tsz; ++j) { tail.push_back(r.get_tail(j)); - neg.push_back(false); } head = mk_head(r.get_head(), cnt); - - new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); - TRACE("dl", r.display(m_ctx, tout); new_rule->display(m_ctx, tout);); - result->add_rule(new_rule); + fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), head); + rule_ref_vector added_rules(rm); + proof_ref pr(m); + rm.mk_rule(fml, pr, added_rules); + result->add_rules(added_rules.size(), added_rules.c_ptr()); + TRACE("dl", added_rules.back()->display(m_ctx, tout);); } // proof converter: proofs are not necessarily preserved using this transformation. diff --git a/src/muz_qe/dl_rule_set.h b/src/muz_qe/dl_rule_set.h index 9aa64425c..58427ca87 100644 --- a/src/muz_qe/dl_rule_set.h +++ b/src/muz_qe/dl_rule_set.h @@ -20,7 +20,6 @@ Revision History: #define _DL_RULE_SET_H_ #include"obj_hashtable.h" - #include"dl_rule.h" namespace datalog { From afd83f41b800e7aef366f154e976dc59adf893d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Apr 2013 17:03:07 -0700 Subject: [PATCH 061/281] fix compiler warnings and errors Signed-off-by: Nikolaj Bjorner --- src/muz_qe/fdd.h | 10 +++++++--- src/test/hilbert_basis.cpp | 2 ++ src/test/karr.cpp | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/muz_qe/fdd.h b/src/muz_qe/fdd.h index e6808375c..59d5a78f5 100644 --- a/src/muz_qe/fdd.h +++ b/src/muz_qe/fdd.h @@ -39,7 +39,7 @@ namespace fdd { unsigned m_ref_count; void reset(); public: - node() : m_var(0), m_hi(0), m_lo(0), m_ref_count(0) {} + node() : m_var(0), m_lo(0), m_hi(0), m_ref_count(0) {} node(unsigned var, node_id l, node_id h): m_var(var), m_lo(l), m_hi(h), m_ref_count(0) {} unsigned get_hash() const; @@ -93,9 +93,13 @@ namespace fdd { class manager { public: typedef int64 Key; + typedef node::hash node_hash; + typedef node::eq node_eq; + typedef config::hash config_hash; + typedef config::eq config_eq; private: - typedef map node_table; - typedef map insert_cache; + typedef map node_table; + typedef map insert_cache; node_table m_table; insert_cache m_insert_cache; svector m_nodes; diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index e0a4a8370..4752dd78d 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -220,6 +220,7 @@ static void on_ctrl_c(int) { raise(SIGINT); } +#if 0 static void validate_sat(hilbert_basis& hb) { ast_manager m; reg_decl_plugins(m); @@ -239,6 +240,7 @@ static void validate_sat(hilbert_basis& hb) { lbool r = sol->check_sat(0,0); std::cout << r << "\n"; } +#endif static void saturate_basis(hilbert_basis& hb) { signal(SIGINT, on_ctrl_c); diff --git a/src/test/karr.cpp b/src/test/karr.cpp index 8770eac94..87debf662 100644 --- a/src/test/karr.cpp +++ b/src/test/karr.cpp @@ -54,7 +54,6 @@ namespace karr { SASSERT(is_sat == l_true); dst.reset(); unsigned basis_size = hb.get_basis_size(); - bool first_initial = true; for (unsigned i = 0; i < basis_size; ++i) { bool is_initial; vector soln; @@ -165,6 +164,7 @@ namespace karr { return v; } +#if 0 static vector V(int i, int j, int k, int l, int m) { vector v; v.push_back(rational(i)); @@ -174,6 +174,7 @@ namespace karr { v.push_back(rational(m)); return v; } +#endif static vector V(int i, int j, int k, int l, int x, int y, int z) { vector v; From 359d2326f8a10f2f870b8e78d5d78d63db3be94b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Apr 2013 17:06:45 -0700 Subject: [PATCH 062/281] stash Signed-off-by: Nikolaj Bjorner --- src/api/api_datalog.cpp | 4 ++-- src/ast/rewriter/expr_safe_replace.cpp | 6 ++++++ src/ast/rewriter/expr_safe_replace.h | 2 ++ src/muz_qe/dl_cmds.cpp | 1 + src/muz_qe/dl_context.cpp | 20 ++++++++++---------- src/muz_qe/dl_context.h | 14 +++++++++----- src/muz_qe/dl_mk_karr_invariants.cpp | 2 +- src/muz_qe/dl_mk_loop_counter.cpp | 4 ++-- src/muz_qe/dl_rule.cpp | 2 +- src/muz_qe/dl_rule_set.h | 1 - src/muz_qe/fixedpoint_params.pyg | 2 ++ src/muz_qe/horn_tactic.cpp | 2 +- 12 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 0f100e747..f6eadfea0 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -358,7 +358,7 @@ extern "C" { v->m_ast_vector.push_back(coll.m_queries[i].get()); } for (unsigned i = 0; i < coll.m_rels.size(); ++i) { - to_fixedpoint_ref(d)->ctx().register_predicate(coll.m_rels[i].get()); + to_fixedpoint_ref(d)->ctx().register_predicate(coll.m_rels[i].get(), true); } for (unsigned i = 0; i < coll.m_rules.size(); ++i) { to_fixedpoint_ref(d)->add_rule(coll.m_rules[i].get(), coll.m_names[i]); @@ -415,7 +415,7 @@ extern "C" { void Z3_API Z3_fixedpoint_register_relation(Z3_context c,Z3_fixedpoint d, Z3_func_decl f) { Z3_TRY; LOG_Z3_fixedpoint_register_relation(c, d, f); - to_fixedpoint_ref(d)->ctx().register_predicate(to_func_decl(f)); + to_fixedpoint_ref(d)->ctx().register_predicate(to_func_decl(f), true); Z3_CATCH; } diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index b3b4d5138..1ec810414 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -100,3 +100,9 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { } res = cache.find(e); } + +void expr_safe_replace::reset() { + m_src.reset(); + m_dst.reset(); + m_subst.reset(); +} diff --git a/src/ast/rewriter/expr_safe_replace.h b/src/ast/rewriter/expr_safe_replace.h index 6af819596..b6131906a 100644 --- a/src/ast/rewriter/expr_safe_replace.h +++ b/src/ast/rewriter/expr_safe_replace.h @@ -38,6 +38,8 @@ public: void operator()(expr_ref& e) { (*this)(e.get(), e); } void operator()(expr* src, expr_ref& e); + + void reset(); }; #endif /* __EXPR_SAFE_REPLACE_H__ */ diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp index aef14e051..c1e3f85f9 100644 --- a/src/muz_qe/dl_cmds.cpp +++ b/src/muz_qe/dl_cmds.cpp @@ -229,6 +229,7 @@ public: status = dlctx.query(m_target); } catch (z3_error & ex) { + ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl; throw ex; } catch (z3_exception& ex) { diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index c667c7775..852d8f847 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -46,6 +46,8 @@ Revision History: #include"dl_mk_bit_blast.h" #include"dl_mk_array_blast.h" #include"dl_mk_karr_invariants.h" +#include"dl_mk_quantifier_abstraction.h" +#include"dl_mk_quantifier_instantiation.h" #include"datatype_decl_plugin.h" #include"expr_abstract.h" @@ -300,14 +302,6 @@ namespace datalog { return m_preds.contains(pred); } - func_decl * context::try_get_predicate_decl(symbol pred_name) const { - func_decl * res; - if (!m_preds_by_name.find(pred_name, res)) { - return 0; - } - return res; - } - void context::register_variable(func_decl* var) { m_vars.push_back(m.mk_const(var)); } @@ -359,7 +353,6 @@ namespace datalog { m_pinned.push_back(decl); m_preds.insert(decl); if (named) { - SASSERT(!m_preds_by_name.contains(decl->get_name())); m_preds_by_name.insert(decl->get_name(), decl); } } @@ -446,7 +439,7 @@ namespace datalog { func_decl* new_pred = m.mk_fresh_func_decl(prefix, suffix, arity, domain, m.mk_bool_sort()); - register_predicate(new_pred); + register_predicate(new_pred, true); if (m_rel.get()) { m_rel->inherit_predicate_kind(new_pred, orig_pred); @@ -905,6 +898,13 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890)); m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); + + if (get_params().quantify_arrays()) { + m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000)); + m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 32500)); + } + m_transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, *this, 32000)); + m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index 0c4558a28..cb432d4e9 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -183,18 +183,22 @@ namespace datalog { retrieved by the try_get_predicate_decl() function. Auxiliary predicates introduced e.g. by rule transformations do not need to be named. */ - void register_predicate(func_decl * pred, bool named = true); + void register_predicate(func_decl * pred, bool named); bool is_predicate(func_decl * pred) const; - + /** \brief If a predicate name has a \c func_decl object assigned, return pointer to it; otherwise return 0. - + Not all \c func_decl object used as relation identifiers need to be assigned to their names. Generally, the names coming from the parses are registered here. - */ - func_decl * try_get_predicate_decl(symbol pred_name) const; + */ + func_decl * try_get_predicate_decl(symbol const& pred_name) const { + func_decl * res = 0; + m_preds_by_name.find(pred_name, res); + return res; + } /** \brief Create a fresh head predicate declaration. diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 2596a7337..7932735fe 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -206,7 +206,7 @@ namespace datalog { for (; it != end; ++it) { rule_ref r(*it, m_inner_ctx.get_rule_manager()); m_inner_ctx.add_rule(r); - m_inner_ctx.register_predicate(r->get_decl()); + m_inner_ctx.register_predicate(r->get_decl(), false); } m_inner_ctx.close(); rule_set::decl2rules::iterator dit = source.begin_grouped_rules(); diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp index 172198746..6b95671f2 100644 --- a/src/muz_qe/dl_mk_loop_counter.cpp +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -72,14 +72,14 @@ namespace datalog { for (unsigned j = 0; j < utsz; ++j, ++cnt) { tail.push_back(add_arg(r.get_tail(j), cnt)); neg.push_back(r.is_neg_tail(j)); - ctx.register_predicate(tail.back()->get_decl()); + ctx.register_predicate(tail.back()->get_decl(), false); } for (unsigned j = utsz; j < tsz; ++j) { tail.push_back(r.get_tail(j)); neg.push_back(false); } head = add_arg(r.get_head(), cnt); - ctx.register_predicate(head->get_decl()); + ctx.register_predicate(head->get_decl(), false); // set the loop counter to be an increment of the previous bool found = false; unsigned last = head->get_num_args()-1; diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 14a316e48..b7d6d9fae 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -135,7 +135,7 @@ namespace datalog { h.set_name(name); h(fml, p, fmls, prs); for (unsigned i = 0; i < h.get_fresh_predicates().size(); ++i) { - m_ctx.register_predicate(h.get_fresh_predicates()[i]); + m_ctx.register_predicate(h.get_fresh_predicates()[i], false); } for (unsigned i = 0; i < fmls.size(); ++i) { mk_rule_core2(fmls[i].get(), prs[i].get(), rules, name); diff --git a/src/muz_qe/dl_rule_set.h b/src/muz_qe/dl_rule_set.h index 9aa64425c..58427ca87 100644 --- a/src/muz_qe/dl_rule_set.h +++ b/src/muz_qe/dl_rule_set.h @@ -20,7 +20,6 @@ Revision History: #define _DL_RULE_SET_H_ #include"obj_hashtable.h" - #include"dl_rule.h" namespace datalog { diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index 7a3316c56..774559cdb 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -42,6 +42,8 @@ def_module_params('fixedpoint', ('simplify_formulas_post', BOOL, False, "PDR: simplify derived formulas after inductive propagation"), ('slice', BOOL, True, "PDR: simplify clause set using slicing"), ('karr', BOOL, False, "Add linear invariants to clauses using Karr's method"), + ('quantify_arrays', BOOL, False, "create quantified Horn clauses from clauses with arrays"), + ('instantiate_quantifiers', BOOL, False, "instantiate quantified Horn clauses using E-matching heuristic"), ('coalesce_rules', BOOL, False, "BMC: coalesce rules"), ('use_multicore_generalizer', BOOL, False, "PDR: extract multiple cores for blocking states"), ('use_inductive_generalizer', BOOL, True, "PDR: generalize lemmas using induction strengthening"), diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 02c41c091..1a8f562d9 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -92,7 +92,7 @@ class horn_tactic : public tactic { void register_predicate(expr* a) { SASSERT(is_predicate(a)); - m_ctx.register_predicate(to_app(a)->get_decl(), true); + m_ctx.register_predicate(to_app(a)->get_decl(), false); } void check_predicate(ast_mark& mark, expr* a) { From 65dff93e935f3b76537645f0afa1825ebc3f6f68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Apr 2013 17:11:33 -0700 Subject: [PATCH 063/281] fix more compiler warnings Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_karr_invariants.cpp | 1 - src/muz_qe/fdd.cpp | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 7932735fe..c4a6a3cdb 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -1015,7 +1015,6 @@ namespace datalog { virtual void operator()(relation_base & _r) { karr_relation & r = get(_r); - karr_relation_plugin & p = r.get_plugin(); if (m_value.is_int()) { r.get_ineqs(); vector row; diff --git a/src/muz_qe/fdd.cpp b/src/muz_qe/fdd.cpp index 6c3bc0974..6b23f3a3f 100644 --- a/src/muz_qe/fdd.cpp +++ b/src/muz_qe/fdd.cpp @@ -42,11 +42,11 @@ bool node::operator==(node const& other) const { // ------------------------------------------ // manager -manager::manager() : +manager::manager() : + m_alloc_node(2), m_false(0), m_true(1), - m_root(m_false), - m_alloc_node(2) + m_root(m_false) { m_nodes.push_back(node()); // false m_nodes.push_back(node()); // true @@ -183,7 +183,6 @@ node_id manager::insert(unsigned idx, node_id n) { node nd = m_nodes[n]; SASSERT(idx >= nd.var()); - unsigned idx0 = idx; while (idx > nd.var()) { if (idx2bit(idx) && !is_dont_care(idx2key(idx))) { return mk_node(idx, n, insert(idx, n)); From 5ef0fdc9c86eafed39c518525387703ccc96e374 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 4 Apr 2013 21:39:20 -0700 Subject: [PATCH 064/281] dealing with build warnings Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_quantifier_instantiation.cpp | 1 - src/muz_qe/fdd.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.cpp b/src/muz_qe/dl_mk_quantifier_instantiation.cpp index 993e5ada5..1d80d9b77 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.cpp +++ b/src/muz_qe/dl_mk_quantifier_instantiation.cpp @@ -83,7 +83,6 @@ namespace datalog { void mk_quantifier_instantiation::instantiate_quantifier(quantifier* q, app* pat, expr_ref_vector & conjs) { - unsigned sz = pat->get_num_args(); m_binding.reset(); m_binding.resize(q->get_num_decls()); term_pairs todo; diff --git a/src/muz_qe/fdd.cpp b/src/muz_qe/fdd.cpp index 6b23f3a3f..9ca5f758a 100644 --- a/src/muz_qe/fdd.cpp +++ b/src/muz_qe/fdd.cpp @@ -23,12 +23,12 @@ Revision History: #include "bit_vector.h" #include "trace.h" -#define OFFSET_OF(ty, field) (unsigned char*)(&((ty*)(0))->field) - (unsigned char*)(ty*)(0) +#define OFFSET_OF(th, ty, field) (unsigned char*)(&((ty*)(th))->field) - (unsigned char*)(ty*)(th) using namespace fdd; unsigned node::get_hash() const { - return string_hash((char*)this, OFFSET_OF(node, m_ref_count), 11); + return string_hash((char*)this, static_cast(OFFSET_OF(this, node, m_ref_count)), 11); } bool node::operator==(node const& other) const { From 26efb3c7f1c0812dcd141d5bb4da0a8af351b1c2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 5 Apr 2013 12:45:28 +0100 Subject: [PATCH 065/281] FPA bugfixes for denormal numbers. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 139 +++++++++++++++++----------- src/tactic/fpa/fpa2bv_converter.h | 2 +- 2 files changed, 85 insertions(+), 56 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 838090045..6d39dbfc4 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -423,9 +423,9 @@ void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args, unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); - expr_ref a_sgn(m), a_sig(m), a_exp(m), b_sgn(m), b_sig(m), b_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); - unpack(y, b_sgn, b_sig, b_exp, false); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, false); + unpack(y, b_sgn, b_sig, b_exp, b_lz, false); dbg_decouple("fpa2bv_add_unpack_a_sgn", a_sgn); dbg_decouple("fpa2bv_add_unpack_a_sig", a_sig); @@ -511,7 +511,7 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, mk_nzero(f, nzero); mk_pzero(f, pzero); mk_minus_inf(f, ninf); - mk_plus_inf(f, pinf); + mk_plus_inf(f, pinf); expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m); expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m); @@ -575,13 +575,21 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, unsigned sbits = m_util.get_sbits(f->get_range()); SASSERT(ebits <= sbits); - expr_ref a_sgn(m), a_sig(m), a_exp(m), b_sgn(m), b_sig(m), b_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); - unpack(y, b_sgn, b_sig, b_exp, true); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); - expr_ref lz_a(m), lz_b(m); - mk_leading_zeros(a_sig, ebits+2, lz_a); - mk_leading_zeros(b_sig, ebits+2, lz_b); + dbg_decouple("fpa2bv_mul_a_sig", a_sig); + dbg_decouple("fpa2bv_mul_a_exp", a_exp); + dbg_decouple("fpa2bv_mul_b_sig", b_sig); + dbg_decouple("fpa2bv_mul_b_exp", b_exp); + + expr_ref a_lz_ext(m), b_lz_ext(m); + a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); + b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz); + + dbg_decouple("fpa2bv_mul_lz_a", a_lz); + dbg_decouple("fpa2bv_mul_lz_b", b_lz); expr_ref a_sig_ext(m), b_sig_ext(m); a_sig_ext = m_bv_util.mk_zero_extend(sbits, a_sig); @@ -597,9 +605,9 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, dbg_decouple("fpa2bv_mul_res_sgn", res_sgn); - res_exp = m_bv_util.mk_bv_sub( - m_bv_util.mk_bv_add(a_exp_ext, b_exp_ext), - m_bv_util.mk_bv_add(lz_a, lz_b)); + res_exp = m_bv_util.mk_bv_add( + m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext), + m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext)); expr_ref product(m); product = m_bv_util.mk_bv_mul(a_sig_ext, b_sig_ext); @@ -614,11 +622,11 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, if (sbits >= 4) { expr_ref sticky(m); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits-4, 0, l_p)); - rbits = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-3, l_p), sticky); + sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits-4, 0, product)); + rbits = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits-1, sbits-3, product), sticky); } else - rbits = m_bv_util.mk_concat(l_p, m_bv_util.mk_numeral(0, 4 - m_bv_util.get_bv_size(l_p))); + rbits = m_bv_util.mk_concat(l_p, m_bv_util.mk_numeral(0, 4 - sbits)); SASSERT(m_bv_util.get_bv_size(rbits) == 4); res_sig = m_bv_util.mk_concat(h_p, rbits); @@ -719,9 +727,9 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, unsigned sbits = m_util.get_sbits(f->get_range()); SASSERT(ebits <= sbits); - expr_ref a_sgn(m), a_sig(m), a_exp(m), b_sgn(m), b_sig(m), b_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); - unpack(y, b_sgn, b_sig, b_exp, true); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); unsigned extra_bits = sbits+2; expr_ref a_sig_ext(m), b_sig_ext(m); @@ -736,7 +744,13 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, expr * signs[2] = { a_sgn, b_sgn }; res_sgn = m_bv_util.mk_bv_xor(2, signs); - res_exp = m_bv_util.mk_bv_sub(a_exp_ext, b_exp_ext); + expr_ref a_lz_ext(m), b_lz_ext(m); + a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); + b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz); + + res_exp = m_bv_util.mk_bv_sub( + m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext), + m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext)); expr_ref quotient(m); quotient = m.mk_app(m_bv_util.get_fid(), OP_BUDIV, a_sig_ext, b_sig_ext); @@ -829,10 +843,10 @@ void fpa2bv_converter::mk_remainder(func_decl * f, unsigned num, expr * const * unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); - expr_ref a_sgn(m), a_sig(m), a_exp(m); - expr_ref b_sgn(m), b_sig(m), b_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); - unpack(y, b_sgn, b_sig, b_exp, true); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); + expr_ref b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); BVSLT(a_exp, b_exp, c6); v6 = x; @@ -1062,16 +1076,16 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar expr_ref rm_is_to_neg(m); mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg); - expr_ref a_sgn(m), a_sig(m), a_exp(m); - expr_ref b_sgn(m), b_sig(m), b_exp(m); - expr_ref c_sgn(m), c_sig(m), c_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); - unpack(y, b_sgn, b_sig, b_exp, true); - unpack(z, c_sgn, c_sig, c_exp, false); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); + expr_ref b_sgn(m), b_sig(m), b_exp(m), b_lz(m); + expr_ref c_sgn(m), c_sig(m), c_exp(m), c_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + unpack(y, b_sgn, b_sig, b_exp, b_lz, true); + unpack(z, c_sgn, c_sig, c_exp, c_lz, false); - expr_ref lz_a(m), lz_b(m); - mk_leading_zeros(a_sig, ebits+2, lz_a); - mk_leading_zeros(b_sig, ebits+2, lz_b); + expr_ref a_lz_ext(m), b_lz_ext(m); + a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); + b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz); expr_ref a_sig_ext(m), b_sig_ext(m); a_sig_ext = m_bv_util.mk_zero_extend(sbits, a_sig); @@ -1089,7 +1103,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar mul_exp = m_bv_util.mk_bv_sub( m_bv_util.mk_bv_add(a_exp_ext, b_exp_ext), - m_bv_util.mk_bv_add(lz_a, lz_b)); + m_bv_util.mk_bv_add(a_lz_ext, b_lz_ext)); mul_sig = m_bv_util.mk_bv_mul(a_sig_ext, b_sig_ext); @@ -1209,8 +1223,11 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * unsigned sbits = m_util.get_sbits(f->get_range()); SASSERT(ebits < sbits); - expr_ref a_sgn(m), a_sig(m), a_exp(m); - unpack(x, a_sgn, a_sig, a_exp, true); + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + + dbg_decouple("fpa2bv_r2i_unpacked_sig", a_sig); + dbg_decouple("fpa2bv_r2i_unpacked_exp", a_exp); expr_ref exp_is_small(m), exp_h(m), one_1(m); exp_h = m_bv_util.mk_extract(ebits-1, ebits-1, a_exp); @@ -1456,8 +1473,8 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a // otherwise: the actual conversion with rounding. sort * s = f->get_range(); - expr_ref sgn(m), sig(m), exp(m); - unpack(x, sgn, sig, exp, true); + expr_ref sgn(m), sig(m), exp(m), lz(m); + unpack(x, sgn, sig, exp, lz, true); expr_ref res_sgn(m), res_sig(m), res_exp(m); @@ -1818,7 +1835,7 @@ void fpa2bv_converter::mk_unbias(expr * e, expr_ref & result) { result = m_bv_util.mk_concat(n_leading, rest); } -void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, bool normalize) { +void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & lz, bool normalize) { SASSERT(is_app_of(e, m_plugin->get_family_id(), OP_TO_FLOAT)); SASSERT(to_app(e)->get_num_args() == 3); @@ -1837,23 +1854,29 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref expr_ref normal_sig(m), normal_exp(m); normal_sig = m_bv_util.mk_concat(m_bv_util.mk_numeral(1, 1), sig); mk_unbias(exp, normal_exp); + dbg_decouple("fpa2bv_unpack_normal_exp", normal_exp); expr_ref denormal_sig(m), denormal_exp(m); - denormal_sig = m_bv_util.mk_concat(m_bv_util.mk_numeral(0, 1), sig); + denormal_sig = m_bv_util.mk_zero_extend(1, sig); denormal_exp = m_bv_util.mk_numeral(1, ebits); mk_unbias(denormal_exp, denormal_exp); + dbg_decouple("fpa2bv_unpack_denormal_exp", denormal_exp); - dbg_decouple("fpa2bv_unpack_denormal_exp", denormal_exp); + expr_ref zero_e(m); + zero_e = m_bv_util.mk_numeral(0, ebits); if (normalize) { - expr_ref is_sig_zero(m), shift(m), lz(m), zero_s(m), zero_e(m); - zero_s = m_bv_util.mk_numeral(0, sbits-1); - zero_e = m_bv_util.mk_numeral(0, ebits); - m_simp.mk_eq(zero_s, sig, is_sig_zero); - mk_leading_zeros(sig, ebits, lz); - m_simp.mk_ite(is_sig_zero, zero_e, lz, shift); - SASSERT(is_well_sorted(m, is_sig_zero)); - SASSERT(is_well_sorted(m, lz)); + expr_ref lz_d(m); + mk_leading_zeros(denormal_sig, ebits, lz_d); + m_simp.mk_ite(is_normal, zero_e, lz_d, lz); + dbg_decouple("fpa2bv_unpack_lz", lz); + + expr_ref is_sig_zero(m), shift(m), zero_s(m); + zero_s = m_bv_util.mk_numeral(0, sbits); + m_simp.mk_eq(zero_s, denormal_sig, is_sig_zero); + m_simp.mk_ite(is_sig_zero, zero_e, lz, shift); + dbg_decouple("fpa2bv_unpack_shift", shift); + SASSERT(is_well_sorted(m, is_sig_zero)); SASSERT(is_well_sorted(m, shift)); SASSERT(m_bv_util.get_bv_size(shift) == ebits); if (ebits <= sbits) { @@ -1872,10 +1895,11 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref m_simp.mk_eq(zero_s, sh, is_sh_zero); short_shift = m_bv_util.mk_extract(sbits-1, 0, shift); m_simp.mk_ite(is_sh_zero, short_shift, sbits_s, sl); - denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, sl); - } - denormal_exp = m_bv_util.mk_bv_sub(denormal_exp, shift); + denormal_sig = m_bv_util.mk_bv_shl(denormal_sig, sl); + } } + else + lz = zero_e; SASSERT(is_well_sorted(m, normal_sig)); SASSERT(is_well_sorted(m, denormal_sig)); @@ -2020,8 +2044,12 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & dbg_decouple("fpa2bv_rnd_beta", beta); - expr_ref sigma(m), sigma_add(m); - sigma_add = m_bv_util.mk_bv_add(exp, m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1), ebits+2)); + dbg_decouple("fpa2bv_rnd_e_min", e_min); + dbg_decouple("fpa2bv_rnd_e_max", e_max); + + expr_ref sigma(m), sigma_add(m), e_min_p2(m); + sigma_add = m_bv_util.mk_bv_sub(exp, m_bv_util.mk_sign_extend(2, e_min)); + sigma_add = m_bv_util.mk_bv_add(sigma_add, m_bv_util.mk_numeral(1, ebits+2)); m_simp.mk_ite(TINY, sigma_add, lz, sigma); dbg_decouple("fpa2bv_rnd_sigma", sigma); @@ -2034,7 +2062,8 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & unsigned sig_size = m_bv_util.get_bv_size(sig); SASSERT(sig_size == sbits+4); - unsigned sigma_size = m_bv_util.get_bv_size(sigma); + SASSERT(m_bv_util.get_bv_size(sigma) == ebits+2); + unsigned sigma_size = ebits+2; expr_ref sigma_neg(m), sigma_cap(m), sigma_neg_capped(m), sigma_lt_zero(m), sig_ext(m), rs_sig(m), ls_sig(m), big_sh_sig(m), sigma_le_cap(m); diff --git a/src/tactic/fpa/fpa2bv_converter.h b/src/tactic/fpa/fpa2bv_converter.h index 6ac1d2b8b..e5d546763 100644 --- a/src/tactic/fpa/fpa2bv_converter.h +++ b/src/tactic/fpa/fpa2bv_converter.h @@ -135,7 +135,7 @@ protected: void mk_bias(expr * e, expr_ref & result); void mk_unbias(expr * e, expr_ref & result); - void unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, bool normalize); + void unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & lz, bool normalize); void round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & result); void add_core(unsigned sbits, unsigned ebits, expr_ref & rm, From 5915533170b069e1b74a1e7fe5e14b263a48e299 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 5 Apr 2013 15:27:05 +0100 Subject: [PATCH 066/281] FPA: bugfix for corner-case sign of division Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 6d39dbfc4..84a1efaff 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -711,11 +711,11 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, mk_is_ninf(y, c5); mk_ite(x_is_inf, nan, xy_zero, v5); - // (y is 0) -> if (x is 0) then NaN else inf with x's sign. + // (y is 0) -> if (x is 0) then NaN else inf with xor sign. c6 = y_is_zero; - expr_ref x_sgn_inf(m); - mk_ite(x_is_pos, pinf, ninf, x_sgn_inf); - mk_ite(x_is_zero, nan, x_sgn_inf, v6); + expr_ref sgn_inf(m); + mk_ite(signs_xor, ninf, pinf, sgn_inf); + mk_ite(x_is_zero, nan, sgn_inf, v6); // (x is 0) -> result is zero with sgn = x.sgn^y.sgn // This is a special case to avoid problems with the unpacking of zero. From 5f298b69659a9955b50e96100f541989e2ce58b8 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 5 Apr 2013 18:02:41 -0700 Subject: [PATCH 067/281] spread some static love Signed-off-by: Nuno Lopes --- src/muz_qe/dl_mk_similarity_compressor.cpp | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index 9868c82f6..9855196c9 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -42,7 +42,7 @@ namespace datalog { /** Allows to traverse head and positive tails in a single for loop starting from -1 */ - app * get_by_tail_index(rule * r, int idx) { + static app * get_by_tail_index(rule * r, int idx) { if(idx==-1) { return r->get_head(); } @@ -51,11 +51,11 @@ namespace datalog { } template - int aux_compare(T a, T b) { + static int aux_compare(T a, T b) { return (a>b) ? 1 : ( (a==b) ? 0 : -1); } - int compare_var_args(app* t1, app* t2) { + static int compare_var_args(app* t1, app* t2) { SASSERT(t1->get_num_args()==t2->get_num_args()); int res; unsigned n = t1->get_num_args(); @@ -73,7 +73,7 @@ namespace datalog { return 0; } - int compare_args(app* t1, app* t2, int & skip_countdown) { + static int compare_args(app* t1, app* t2, int & skip_countdown) { SASSERT(t1->get_num_args()==t2->get_num_args()); int res; unsigned n = t1->get_num_args(); @@ -98,7 +98,7 @@ namespace datalog { Two rules are in the same rough similarity class if they differ only in constant arguments of positive uninterpreted predicates. */ - int rough_compare(rule * r1, rule * r2) { + static int rough_compare(rule * r1, rule * r2) { int res = aux_compare(r1->get_tail_size(), r2->get_tail_size()); if(res!=0) { return res; } res = aux_compare(r1->get_uninterpreted_tail_size(), r2->get_uninterpreted_tail_size()); @@ -129,7 +129,7 @@ namespace datalog { \c r1 and \c r2 must be equal according to the \c rough_compare function for this function to be called. */ - int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) { + static int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) { SASSERT(rough_compare(r1, r2)==0); int pos_tail_sz = r1->get_positive_tail_size(); for(int i=-1; i info_vector; - void collect_const_indexes(app * t, int tail_index, info_vector & res) { + static void collect_const_indexes(app * t, int tail_index, info_vector & res) { unsigned n = t->get_num_args(); for(unsigned i=0; iget_arg(i))) { @@ -175,7 +175,7 @@ namespace datalog { } } - void collect_const_indexes(rule * r, info_vector & res) { + static void collect_const_indexes(rule * r, info_vector & res) { collect_const_indexes(r->get_head(), -1, res); unsigned pos_tail_sz = r->get_positive_tail_size(); for(unsigned i=0; i - void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) { + static void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) { unsigned const_cnt = const_infos.size(); tgt.reset(); for(unsigned i=0; i - void collect_orphan_sorts(rule * r, const info_vector & const_infos, T & tgt) { + static void collect_orphan_sorts(rule * r, const info_vector & const_infos, T & tgt) { unsigned const_cnt = const_infos.size(); tgt.reset(); for(unsigned i=0; i1); unsigned const_cnt = const_infos.size(); @@ -252,7 +252,7 @@ namespace datalog { first constant that is equal to it in all the rules. If there is no such, it will contain its own index. */ - void detect_equal_constants(rule_vector::iterator first, rule_vector::iterator after_last, + static void detect_equal_constants(rule_vector::iterator first, rule_vector::iterator after_last, info_vector & const_infos) { SASSERT(first!=after_last); unsigned const_cnt = const_infos.size(); @@ -302,7 +302,7 @@ namespace datalog { } } - unsigned get_constant_count(rule * r) { + static unsigned get_constant_count(rule * r) { unsigned res = r->get_head()->get_num_args() - count_variable_arguments(r->get_head()); unsigned pos_tail_sz = r->get_positive_tail_size(); for(unsigned i=0; i0; } return total_compare(r1, r2)>0; From 1ef17cbe679884c434a95c2039959f2c0cd61034 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 5 Apr 2013 18:12:58 -0700 Subject: [PATCH 068/281] add dl_context::has_facts(pred) Signed-off-by: Nuno Lopes --- src/muz_qe/dl_context.cpp | 4 ++++ src/muz_qe/dl_context.h | 1 + src/muz_qe/rel_context.cpp | 5 +++++ src/muz_qe/rel_context.h | 7 ++++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 852d8f847..7a1e3b8fc 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -780,6 +780,10 @@ namespace datalog { add_fact(head->get_decl(), fact); } + bool context::has_facts(func_decl * pred) const { + return m_rel && m_rel->has_facts(pred); + } + void context::add_table_fact(func_decl * pred, const table_fact & fact) { if (get_engine() == DATALOG_ENGINE) { ensure_rel(); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index cb432d4e9..d23cf2c0c 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -249,6 +249,7 @@ namespace datalog { void add_fact(app * head); void add_fact(func_decl * pred, const relation_fact & fact); + bool has_facts(func_decl * pred) const; void add_rule(rule_ref& r); void add_rules(rule_ref_vector& rs); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 12045047b..58263b9d0 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -497,6 +497,11 @@ namespace datalog { } } + bool rel_context::has_facts(func_decl * pred) const { + relation_base* r = try_get_relation(pred); + return r && !r->empty(); + } + void rel_context::store_relation(func_decl * pred, relation_base * rel) { get_rmanager().store_relation(pred, rel); } diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index 08ee868c0..d2f6973da 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -92,9 +92,14 @@ namespace datalog { */ bool result_contains_fact(relation_fact const& f); + /** \brief add facts to relation + */ void add_fact(func_decl* pred, relation_fact const& fact); - void add_fact(func_decl* pred, table_fact const& fact); + + /** \brief check if facts were added to relation + */ + bool has_facts(func_decl * pred) const; /** \brief Store the relation \c rel under the predicate \c pred. The \c context object From 8f46179deffa7f671d5f9ec5cd92496c8bfc72f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 8 Apr 2013 13:50:56 -0700 Subject: [PATCH 069/281] reorganization of rule_set structure Signed-off-by: Nikolaj Bjorner --- src/ast/dl_decl_plugin.cpp | 6 +- src/muz_qe/dl_base.h | 2 + src/muz_qe/dl_bmc_engine.cpp | 19 +- src/muz_qe/dl_cmds.cpp | 36 - src/muz_qe/dl_compiler.cpp | 8 +- src/muz_qe/dl_context.cpp | 121 +- src/muz_qe/dl_context.h | 30 +- src/muz_qe/dl_finite_product_relation.cpp | 4 +- src/muz_qe/dl_mk_array_blast.cpp | 8 +- src/muz_qe/dl_mk_bit_blast.cpp | 49 +- src/muz_qe/dl_mk_coalesce.cpp | 1 + src/muz_qe/dl_mk_coi_filter.cpp | 5 +- src/muz_qe/dl_mk_explanations.cpp | 200 +- src/muz_qe/dl_mk_explanations.h | 20 +- src/muz_qe/dl_mk_extract_quantifiers.cpp | 379 -- src/muz_qe/dl_mk_extract_quantifiers.h | 99 - src/muz_qe/dl_mk_filter_rules.cpp | 7 +- src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 1 + src/muz_qe/dl_mk_karr_invariants.cpp | 13 +- src/muz_qe/dl_mk_loop_counter.cpp | 7 +- src/muz_qe/dl_mk_loop_counter.h | 1 + src/muz_qe/dl_mk_magic_sets.cpp | 177 +- src/muz_qe/dl_mk_magic_sets.h | 25 +- src/muz_qe/dl_mk_partial_equiv.cpp | 5 +- src/muz_qe/dl_mk_quantifier_abstraction.cpp | 22 +- src/muz_qe/dl_mk_quantifier_abstraction.h | 6 +- src/muz_qe/dl_mk_quantifier_instantiation.cpp | 13 +- src/muz_qe/dl_mk_rule_inliner.cpp | 27 +- src/muz_qe/dl_mk_rule_inliner.h | 4 +- src/muz_qe/dl_mk_similarity_compressor.cpp | 150 +- src/muz_qe/dl_mk_simple_joins.cpp | 7 +- src/muz_qe/dl_mk_slice.cpp | 8 +- src/muz_qe/dl_mk_slice.h | 2 +- src/muz_qe/dl_mk_subsumption_checker.cpp | 29 +- src/muz_qe/dl_mk_subsumption_checker.h | 4 +- src/muz_qe/dl_mk_unbound_compressor.cpp | 59 +- src/muz_qe/dl_mk_unbound_compressor.h | 14 +- src/muz_qe/dl_mk_unfold.cpp | 1 + src/muz_qe/dl_relation_manager.cpp | 12 +- src/muz_qe/dl_relation_manager.h | 6 +- src/muz_qe/dl_rule.cpp | 47 +- src/muz_qe/dl_rule.h | 16 +- src/muz_qe/dl_rule_set.cpp | 161 +- src/muz_qe/dl_rule_set.h | 31 +- src/muz_qe/dl_rule_transformer.cpp | 32 +- src/muz_qe/dl_skip_table.cpp | 622 --- src/muz_qe/dl_skip_table.h | 161 - src/muz_qe/dl_sparse_table.cpp | 3 + src/muz_qe/imdd.cpp | 3688 ----------------- src/muz_qe/imdd.h | 849 ---- src/muz_qe/interval_skip_list.h | 1876 --------- src/muz_qe/pdr_dl_interface.cpp | 52 +- src/muz_qe/pdr_manager.cpp | 2 +- src/muz_qe/pdr_quantifiers.cpp | 660 --- src/muz_qe/pdr_quantifiers.h | 117 - src/muz_qe/rel_context.cpp | 145 +- src/muz_qe/rel_context.h | 13 +- src/muz_qe/tab_context.cpp | 14 +- src/shell/datalog_frontend.cpp | 5 +- src/test/dl_query.cpp | 2 +- src/test/dl_table.cpp | 12 - src/test/imdd.cpp | 617 --- src/test/interval_skip_list.cpp | 716 ---- src/test/main.cpp | 13 +- src/util/mpz.cpp | 5 +- 65 files changed, 778 insertions(+), 10668 deletions(-) delete mode 100644 src/muz_qe/dl_mk_extract_quantifiers.cpp delete mode 100644 src/muz_qe/dl_mk_extract_quantifiers.h delete mode 100644 src/muz_qe/dl_skip_table.cpp delete mode 100644 src/muz_qe/dl_skip_table.h delete mode 100644 src/muz_qe/imdd.cpp delete mode 100644 src/muz_qe/imdd.h delete mode 100644 src/muz_qe/interval_skip_list.h delete mode 100644 src/muz_qe/pdr_quantifiers.cpp delete mode 100644 src/muz_qe/pdr_quantifiers.h delete mode 100644 src/test/imdd.cpp delete mode 100644 src/test/interval_skip_list.cpp diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index 8ac19c11c..1524760e5 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -636,9 +636,13 @@ namespace datalog { app* dl_decl_util::mk_numeral(uint64 value, sort* s) { if (is_finite_sort(s)) { + uint64 sz = 0; + if (try_get_size(s, sz) && sz <= value) { + m.raise_exception("value is out of bounds"); + } parameter params[2] = { parameter(rational(value, rational::ui64())), parameter(s) }; return m.mk_const(m.mk_func_decl(m_fid, OP_DL_CONSTANT, 2, params, 0, (sort*const*)0)); - } + } if (m_arith.is_int(s) || m_arith.is_real(s)) { return m_arith.mk_numeral(rational(value, rational::ui64()), s); } diff --git a/src/muz_qe/dl_base.h b/src/muz_qe/dl_base.h index 6c53a4b27..e7243cb70 100644 --- a/src/muz_qe/dl_base.h +++ b/src/muz_qe/dl_base.h @@ -37,6 +37,8 @@ namespace datalog { ast_manager & get_ast_manager_from_rel_manager(const relation_manager & rm); context & get_context_from_rel_manager(const relation_manager & rm); + typedef func_decl_set decl_set; + #if DL_LEAK_HUNTING void leak_guard_check(const symbol & s); #endif diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp index 959a11605..15876b631 100644 --- a/src/muz_qe/dl_bmc_engine.cpp +++ b/src/muz_qe/dl_bmc_engine.cpp @@ -44,7 +44,6 @@ namespace datalog { public: qlinear(bmc& b): b(b), m(b.m), m_bv(m), m_bit_width(1) {} - lbool check() { setup(); m_bit_width = 4; @@ -1416,19 +1415,12 @@ namespace datalog { lbool bmc::query(expr* query) { m_solver.reset(); m_answer = 0; - m_ctx.ensure_opened(); m_rules.reset(); - datalog::rule_manager& rule_manager = m_ctx.get_rule_manager(); - datalog::rule_set old_rules(m_ctx.get_rules()); - datalog::rule_ref_vector query_rules(rule_manager); - datalog::rule_ref query_rule(rule_manager); - rule_manager.mk_query(query, m_query_pred, query_rules, query_rule); - m_ctx.add_rules(query_rules); - expr_ref bg_assertion = m_ctx.get_background_assertion(); - - m_ctx.set_output_predicate(m_query_pred); + datalog::rule_set old_rules(m_ctx.get_rules()); + rule_manager.mk_query(query, m_ctx.get_rules()); + expr_ref bg_assertion = m_ctx.get_background_assertion(); m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { @@ -1436,10 +1428,9 @@ namespace datalog { datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); m_ctx.transform_rules(transformer); - m_query_pred = slice->get_predicate(m_query_pred.get()); - m_ctx.set_output_predicate(m_query_pred); } - m_rules.add_rules(m_ctx.get_rules()); + m_query_pred = m_ctx.get_rules().get_output_predicate(); + m_rules.replace_rules(m_ctx.get_rules()); m_rules.close(); m_ctx.reopen(); m_ctx.replace_rules(old_rules); diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp index c1e3f85f9..b82225785 100644 --- a/src/muz_qe/dl_cmds.cpp +++ b/src/muz_qe/dl_cmds.cpp @@ -445,40 +445,8 @@ public: ctx.insert(var); m_dl_ctx->dlctx().register_variable(var); } - }; -class dl_push_cmd : public cmd { - ref m_ctx; -public: - dl_push_cmd(dl_context* ctx): - cmd("fixedpoint-push"), - m_ctx(ctx) - {} - - virtual char const * get_usage() const { return ""; } - virtual char const * get_descr(cmd_context & ctx) const { return "push context on the fixedpoint engine"; } - - virtual void execute(cmd_context& ctx) { - m_ctx->push(); - } -}; - -class dl_pop_cmd : public cmd { - ref m_ctx; -public: - dl_pop_cmd(dl_context* ctx): - cmd("fixedpoint-pop"), - m_ctx(ctx) - {} - - virtual char const * get_usage() const { return ""; } - virtual char const * get_descr(cmd_context & ctx) const { return "pop context on the fixedpoint engine"; } - - virtual void execute(cmd_context& ctx) { - m_ctx->pop(); - } -}; static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_cmds) { dl_context * dl_ctx = alloc(dl_context, ctx, collected_cmds); @@ -486,10 +454,6 @@ static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_c ctx.insert(alloc(dl_query_cmd, dl_ctx)); ctx.insert(alloc(dl_declare_rel_cmd, dl_ctx)); ctx.insert(alloc(dl_declare_var_cmd, dl_ctx)); -#ifndef _EXTERNAL_RELEASE - ctx.insert(alloc(dl_push_cmd, dl_ctx)); // not exposed to keep command-extensions simple. - ctx.insert(alloc(dl_pop_cmd, dl_ctx)); -#endif } void install_dl_cmds(cmd_context & ctx) { diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index c898f7964..681dc696a 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -760,7 +760,7 @@ namespace datalog { typedef svector tail_delta_infos; unsigned rule_len = r->get_uninterpreted_tail_size(); - reg_idx head_reg = m_pred_regs.find(r->get_head()->get_decl()); + reg_idx head_reg = m_pred_regs.find(r->get_decl()); svector tail_regs; tail_delta_infos tail_deltas; @@ -884,7 +884,7 @@ namespace datalog { rule_vector::const_iterator rend = pred_rules.end(); for(; rit!=rend; ++rit) { rule * r = *rit; - SASSERT(head_pred==r->get_head()->get_decl()); + SASSERT(head_pred==r->get_decl()); compile_rule_evaluation(r, input_deltas, d_head_reg, widen_predicate_in_loop, acc); } @@ -1039,7 +1039,7 @@ namespace datalog { rule_vector::const_iterator end = rules.end(); for (; it != end; ++it) { rule * r = *it; - SASSERT(r->get_head()->get_decl()==head_pred); + SASSERT(r->get_decl()==head_pred); compile_rule_evaluation(r, input_deltas, output_delta, false, acc); } @@ -1112,7 +1112,7 @@ namespace datalog { //load predicate data for(unsigned i=0;iget_head()->get_decl(), acc); + ensure_predicate_loaded(r->get_decl(), acc); unsigned rule_len = r->get_uninterpreted_tail_size(); for(unsigned j=0;jget_name(), decl); + } } - m_pinned.push_back(decl); - m_preds.insert(decl); - if (named) { - m_preds_by_name.insert(decl->get_name(), decl); + } + + void context::restrict_predicates(func_decl_set const& preds) { + m_preds.reset(); + func_decl_set::iterator it = preds.begin(), end = preds.end(); + for (; it != end; ++it) { + m_preds.insert(*it); } } @@ -447,21 +446,6 @@ namespace datalog { return new_pred; } - void context::set_output_predicate(func_decl * pred) { - ensure_rel(); - m_rel->set_output_predicate(pred); - } - - bool context::is_output_predicate(func_decl * pred) { - ensure_rel(); - return m_rel->is_output_predicate(pred); - } - - const decl_set & context::get_output_predicates() { - ensure_rel(); - return m_rel->get_output_predicates(); - } - void context::add_rule(expr* rl, symbol const& name) { m_rule_fmls.push_back(rl); m_rule_names.push_back(name); @@ -469,14 +453,12 @@ namespace datalog { void context::flush_add_rules() { datalog::rule_manager& rm = get_rule_manager(); - datalog::rule_ref_vector rules(rm); scoped_proof_mode _scp(m, generate_proof_trace()?PGM_FINE:PGM_DISABLED); for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { expr* fml = m_rule_fmls[i].get(); proof* p = generate_proof_trace()?m.mk_asserted(fml):0; - rm.mk_rule(fml, p, rules, m_rule_names[i]); + rm.mk_rule(fml, p, m_rule_set, m_rule_names[i]); } - add_rules(rules); m_rule_fmls.reset(); m_rule_names.reset(); } @@ -487,25 +469,28 @@ namespace datalog { // void context::update_rule(expr* rl, symbol const& name) { datalog::rule_manager& rm = get_rule_manager(); - datalog::rule_ref_vector rules(rm); proof* p = 0; if (generate_proof_trace()) { p = m.mk_asserted(rl); } - rm.mk_rule(rl, p, rules, name); - if (rules.size() != 1) { + unsigned size_before = m_rule_set.get_num_rules(); + rm.mk_rule(rl, p, m_rule_set, name); + unsigned size_after = m_rule_set.get_num_rules(); + if (size_before + 1 != size_after) { std::stringstream strm; strm << "Rule " << name << " has a non-trivial body. It cannot be modified"; throw default_exception(strm.str()); } - rule_ref r(rules[0].get(), rm); + // The new rule is inserted last: + rule_ref r(m_rule_set.get_rule(size_before), rm); rule_ref_vector const& rls = m_rule_set.get_rules(); rule* old_rule = 0; - for (unsigned i = 0; i < rls.size(); ++i) { + for (unsigned i = 0; i < size_before; ++i) { if (rls[i]->name() == name) { if (old_rule) { std::stringstream strm; strm << "Rule " << name << " occurs twice. It cannot be modified"; + m_rule_set.del_rule(r); throw default_exception(strm.str()); } old_rule = rls[i]; @@ -518,11 +503,11 @@ namespace datalog { old_rule->display(*this, strm); strm << "does not subsume new rule "; r->display(*this, strm); + m_rule_set.del_rule(r); throw default_exception(strm.str()); } m_rule_set.del_rule(old_rule); } - m_rule_set.add_rule(r); } bool context::check_subsumes(rule const& stronger_rule, rule const& weaker_rule) { @@ -623,20 +608,20 @@ namespace datalog { } class context::contains_pred : public i_expr_pred { - rule_manager const& m; + context const& ctx; public: - contains_pred(rule_manager const& m): m(m) {} + contains_pred(context& ctx): ctx(ctx) {} virtual ~contains_pred() {} virtual bool operator()(expr* e) { - return is_app(e) && m.is_predicate(to_app(e)); + return ctx.is_predicate(e); } }; void context::check_existential_tail(rule_ref& r) { unsigned ut_size = r->get_uninterpreted_tail_size(); unsigned t_size = r->get_tail_size(); - contains_pred contains_p(get_rule_manager()); + contains_pred contains_p(*this); check_pred check_pred(contains_p, get_manager()); TRACE("dl", r->display_smt2(get_manager(), tout); tout << "\n";); @@ -663,7 +648,7 @@ namespace datalog { } ast_manager& m = get_manager(); datalog::rule_manager& rm = get_rule_manager(); - contains_pred contains_p(rm); + contains_pred contains_p(*this); check_pred check_pred(contains_p, get_manager()); for (unsigned i = ut_size; i < t_size; ++i) { @@ -676,7 +661,7 @@ namespace datalog { continue; } visited.mark(e, true); - if (rm.is_predicate(e)) { + if (is_predicate(e)) { } else if (m.is_and(e) || m.is_or(e)) { todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); @@ -749,14 +734,6 @@ namespace datalog { m_rule_set.add_rule(r); } - void context::add_rules(rule_ref_vector& rules) { - for (unsigned i = 0; i < rules.size(); ++i) { - rule_ref rule(rules[i].get(), rules.get_manager()); - add_rule(rule); - } - } - - void context::add_fact(func_decl * pred, const relation_fact & fact) { if (get_engine() == DATALOG_ENGINE) { ensure_rel(); @@ -771,10 +748,9 @@ namespace datalog { void context::add_fact(app * head) { SASSERT(is_fact(head)); - relation_fact fact(get_manager()); - unsigned n=head->get_num_args(); - for (unsigned i=0; iget_num_args(); + for (unsigned i = 0; i < n; i++) { fact.push_back(to_app(head->get_arg(i))); } add_fact(head->get_decl(), fact); @@ -849,6 +825,12 @@ namespace datalog { transform_rules(m_transf); } + + void context::transform_rules(rule_transformer::plugin* plugin) { + rule_transformer transformer(*this); + transformer.register_plugin(plugin); + transform_rules(transformer); + } void context::transform_rules(rule_transformer& transf) { SASSERT(m_closed); //we must finish adding rules before we start transforming them @@ -862,15 +844,16 @@ namespace datalog { } } - void context::replace_rules(rule_set & rs) { + void context::replace_rules(rule_set const & rs) { SASSERT(!m_closed); - m_rule_set.reset(); - m_rule_set.add_rules(rs); + m_rule_set.replace_rules(rs); + if (m_rel) { + m_rel->restrict_predicates(get_predicates()); + } } void context::record_transformed_rules() { - m_transformed_rule_set.reset(); - m_transformed_rule_set.add_rules(m_rule_set); + m_transformed_rule_set.replace_rules(m_rule_set); } void context::apply_default_transformation() { @@ -921,16 +904,6 @@ namespace datalog { if (m_pdr.get()) m_pdr->updt_params(); } - void context::collect_predicates(decl_set& res) { - ensure_rel(); - m_rel->collect_predicates(res); - } - - void context::restrict_predicates(decl_set const& res) { - ensure_rel(); - m_rel->restrict_predicates(res); - } - expr_ref context::get_background_assertion() { expr_ref result(m); switch (m_background.size()) { @@ -1269,14 +1242,13 @@ namespace datalog { void context::get_rules_as_formulas(expr_ref_vector& rules, svector& names) { expr_ref fml(m); datalog::rule_manager& rm = get_rule_manager(); - datalog::rule_ref_vector rule_refs(rm); // ensure that rules are all using bound variables. for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { ptr_vector sorts; get_free_vars(m_rule_fmls[i].get(), sorts); if (!sorts.empty()) { - rm.mk_rule(m_rule_fmls[i].get(), 0, rule_refs, m_rule_names[i]); + rm.mk_rule(m_rule_fmls[i].get(), 0, m_rule_set, m_rule_names[i]); m_rule_fmls[i] = m_rule_fmls.back(); m_rule_names[i] = m_rule_names.back(); m_rule_fmls.pop_back(); @@ -1284,7 +1256,6 @@ namespace datalog { --i; } } - add_rules(rule_refs); rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); for (; it != end; ++it) { (*it)->to_formula(fml); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index cb432d4e9..62f1b83e1 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -185,7 +185,17 @@ namespace datalog { */ void register_predicate(func_decl * pred, bool named); - bool is_predicate(func_decl * pred) const; + /** + Restrict reltaions to set of predicates. + */ + void restrict_predicates(func_decl_set const& preds); + + /** + \brief Retrieve predicates + */ + func_decl_set const& get_predicates() const { return m_preds; } + bool is_predicate(func_decl* pred) const { return m_preds.contains(pred); } + bool is_predicate(expr * e) const { return is_app(e) && is_predicate(to_app(e)->get_decl()); } /** \brief If a predicate name has a \c func_decl object assigned, return pointer to it; @@ -238,11 +248,9 @@ namespace datalog { void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, symbol const * relation_names); - void set_output_predicate(func_decl * pred); - bool is_output_predicate(func_decl * pred); - const decl_set & get_output_predicates(); + void set_output_predicate(func_decl * pred) { m_rule_set.set_output_predicate(pred); } - rule_set const & get_rules() { flush_add_rules(); return m_rule_set; } + rule_set & get_rules() { flush_add_rules(); return m_rule_set; } void get_rules_as_formulas(expr_ref_vector& fmls, svector& names); @@ -251,7 +259,6 @@ namespace datalog { void add_rule(rule_ref& r); - void add_rules(rule_ref_vector& rs); void assert_expr(expr* e); expr_ref get_background_assertion(); @@ -329,7 +336,8 @@ namespace datalog { void transform_rules(); void transform_rules(rule_transformer& transf); - void replace_rules(rule_set & rs); + void transform_rules(rule_transformer::plugin* plugin); + void replace_rules(rule_set const& rs); void record_transformed_rules(); void apply_default_transformation(); @@ -338,14 +346,6 @@ namespace datalog { void updt_params(params_ref const& p); - void collect_predicates(decl_set & res); - /** - \brief Restrict the set of used predicates to \c res. - - The function deallocates unsused relations, it does not deal with rules. - */ - void restrict_predicates(const decl_set & res); - void display_rules(std::ostream & out) const { m_rule_set.display(out); } diff --git a/src/muz_qe/dl_finite_product_relation.cpp b/src/muz_qe/dl_finite_product_relation.cpp index 3070475ac..4880e6068 100644 --- a/src/muz_qe/dl_finite_product_relation.cpp +++ b/src/muz_qe/dl_finite_product_relation.cpp @@ -129,7 +129,7 @@ namespace datalog { for(unsigned i=0; idisplay(m_ctx, tout << "new rule\n");); + TRACE("dl", new_rules.last()->display(m_ctx, tout << "new rule\n");); rule_ref new_rule(rm); - if (m_simplifier.transform_rule(new_rules[0].get(), new_rule)) { + if (m_simplifier.transform_rule(new_rules.last(), new_rule)) { rules.add_rule(new_rule.get()); rm.mk_rule_rewrite_proof(r, *new_rule.get()); } @@ -214,6 +213,7 @@ namespace datalog { rule_set * mk_array_blast::operator()(rule_set const & source) { rule_set* rules = alloc(rule_set, m_ctx); + rules->inherit_predicates(source); rule_set::iterator it = source.begin(), end = source.end(); bool change = false; for (; !m_ctx.canceled() && it != end; ++it) { diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 3d6c35bb3..3f92bbce8 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -108,31 +108,35 @@ namespace datalog { class expand_mkbv_cfg : public default_rewriter_cfg { context& m_context; - rule_ref_vector& m_rules; ast_manager& m; bv_util m_util; expr_ref_vector m_args, m_f_vars, m_g_vars; func_decl_ref_vector m_old_funcs; func_decl_ref_vector m_new_funcs; + rule_set const* m_src; + rule_set* m_dst; obj_map m_pred2blast; public: - expand_mkbv_cfg(context& ctx, rule_ref_vector& rules): + expand_mkbv_cfg(context& ctx): m_context(ctx), - m_rules(rules), m(ctx.get_manager()), m_util(m), m_args(m), m_f_vars(m), m_g_vars(m), m_old_funcs(m), - m_new_funcs(m) + m_new_funcs(m), + m_src(0), + m_dst(0) {} ~expand_mkbv_cfg() {} + void set_src(rule_set const* src) { m_src = src; } + void set_dst(rule_set* dst) { m_dst = dst; } func_decl_ref_vector const& old_funcs() const { return m_old_funcs; } func_decl_ref_vector const& new_funcs() const { return m_new_funcs; } @@ -183,14 +187,7 @@ namespace datalog { m_new_funcs.push_back(g); m_pred2blast.insert(f, g); - // Create rule f(mk_mkbv(args)) :- g(args) - - fml = m.mk_implies(m.mk_app(g, m_g_vars.size(), m_g_vars.c_ptr()), m.mk_app(f, m_f_vars.size(), m_f_vars.c_ptr())); - proof_ref pr(m); - if (m_context.generate_proof_trace()) { - pr = m.mk_asserted(fml); // or a def? - } - rm.mk_rule(fml, pr, m_rules, g->get_name()); + m_dst->inherit_predicate(*m_src, f, g); } result = m.mk_app(g, m_args.size(), m_args.c_ptr()); result_pr = 0; @@ -200,9 +197,9 @@ namespace datalog { struct expand_mkbv : public rewriter_tpl { expand_mkbv_cfg m_cfg; - expand_mkbv(ast_manager& m, context& ctx, rule_ref_vector& rules): + expand_mkbv(ast_manager& m, context& ctx): rewriter_tpl(m, m.proofs_enabled(), m_cfg), - m_cfg(ctx, rules) { + m_cfg(ctx) { } }; @@ -212,7 +209,6 @@ namespace datalog { context & m_context; ast_manager & m; params_ref m_params; - rule_ref_vector m_rules; mk_interp_tail_simplifier m_simplifier; bit_blaster_rewriter m_blaster; expand_mkbv m_rewriter; @@ -239,19 +235,14 @@ namespace datalog { } } - void reset() { - m_rules.reset(); - } - public: impl(context& ctx): m_context(ctx), m(ctx.get_manager()), m_params(ctx.get_params().p), - m_rules(ctx.get_rule_manager()), m_simplifier(ctx), m_blaster(ctx.get_manager(), m_params), - m_rewriter(ctx.get_manager(), ctx, m_rules) { + m_rewriter(ctx.get_manager(), ctx) { m_params.set_bool("blast_full", true); m_params.set_bool("blast_quant", true); m_blaster.updt_params(m_params); @@ -265,8 +256,9 @@ namespace datalog { rule_manager& rm = m_context.get_rule_manager(); unsigned sz = source.get_num_rules(); expr_ref fml(m); - reset(); - rule_set * result = alloc(rule_set, m_context); + rule_set * result = alloc(rule_set, m_context); + m_rewriter.m_cfg.set_src(&source); + m_rewriter.m_cfg.set_dst(result); for (unsigned i = 0; !m_context.canceled() && i < sz; ++i) { rule * r = source.get_rule(i); r->to_formula(fml); @@ -275,17 +267,16 @@ namespace datalog { if (m_context.generate_proof_trace()) { pr = m.mk_asserted(fml); // loses original proof of r. } - rm.mk_rule(fml, pr, m_rules, r->name()); + // TODO add logic for pc: + // 1. replace fresh predicates by non-bit-blasted predicates + // 2. replace pr by the proof of r. + rm.mk_rule(fml, pr, *result, r->name()); } else { - m_rules.push_back(r); + result->add_rule(r); } } - for (unsigned i = 0; i < m_rules.size(); ++i) { - result->add_rule(m_rules.get(i)); - } - if (m_context.get_model_converter()) { filter_model_converter* fmc = alloc(filter_model_converter, m); bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m); diff --git a/src/muz_qe/dl_mk_coalesce.cpp b/src/muz_qe/dl_mk_coalesce.cpp index 94c42e33b..8c7f1d5b4 100644 --- a/src/muz_qe/dl_mk_coalesce.cpp +++ b/src/muz_qe/dl_mk_coalesce.cpp @@ -173,6 +173,7 @@ namespace datalog { rule_set * mk_coalesce::operator()(rule_set const & source) { rule_set* rules = alloc(rule_set, m_ctx); + rules->inherit_predicates(source); rule_set::decl2rules::iterator it = source.begin_grouped_rules(), end = source.end_grouped_rules(); for (; it != end; ++it) { rule_ref_vector d_rules(rm); diff --git a/src/muz_qe/dl_mk_coi_filter.cpp b/src/muz_qe/dl_mk_coi_filter.cpp index 6aa688a3c..b253a0e20 100644 --- a/src/muz_qe/dl_mk_coi_filter.cpp +++ b/src/muz_qe/dl_mk_coi_filter.cpp @@ -35,7 +35,7 @@ namespace datalog { rule_set * mk_coi_filter::operator()(rule_set const & source) { - if (source.get_num_rules()==0) { + if (source.empty()) { return 0; } @@ -43,7 +43,7 @@ namespace datalog { decl_set pruned_preds; ptr_vector todo; { - const decl_set& output_preds = m_context.get_output_predicates(); + const decl_set& output_preds = source.get_output_predicates(); decl_set::iterator oend = output_preds.end(); for (decl_set::iterator it = output_preds.begin(); it!=oend; ++it) { todo.push_back(*it); @@ -70,6 +70,7 @@ namespace datalog { } scoped_ptr res = alloc(rule_set, m_context); + res->inherit_predicates(source); rule_set::iterator rend = source.end(); for (rule_set::iterator rit = source.begin(); rit!=rend; ++rit) { diff --git a/src/muz_qe/dl_mk_explanations.cpp b/src/muz_qe/dl_mk_explanations.cpp index 646a0bcbe..bf3548a7a 100644 --- a/src/muz_qe/dl_mk_explanations.cpp +++ b/src/muz_qe/dl_mk_explanations.cpp @@ -80,8 +80,8 @@ namespace datalog { virtual bool can_handle_signature(const relation_signature & s) { unsigned n=s.size(); - for(unsigned i=0; i(get_plugin().mk_empty(get_signature())); - if(empty()) { + if (empty()) { res->set_undefined(); } return res; } void display_explanation(app * expl, std::ostream & out) const { - if(expl) { + if (expl) { //TODO: some nice explanation output ast_smt_pp pp(get_plugin().get_ast_manager()); pp.display_expr_smt2(out, expl); @@ -249,13 +249,13 @@ namespace datalog { } virtual void display(std::ostream & out) const { - if(empty()) { + if (empty()) { out << "\n"; return; } unsigned sz = get_signature().size(); - for(unsigned i=0; i(plugin.mk_empty(get_result_signature())); - if(!r1.empty() && !r2.empty()) { + if (!r1.empty() && !r2.empty()) { res->m_empty = false; SASSERT(res->m_data.empty()); res->m_data.append(r1.m_data); @@ -317,10 +317,10 @@ namespace datalog { relation_join_fn * explanation_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if(&r1.get_plugin()!=this || &r2.get_plugin()!=this) { + if (&r1.get_plugin()!=this || &r2.get_plugin()!=this) { return 0; } - if(col_cnt!=0) { + if (col_cnt!=0) { return 0; } return alloc(join_fn, r1.get_signature(), r2.get_signature()); @@ -337,7 +337,7 @@ namespace datalog { explanation_relation_plugin & plugin = r.get_plugin(); explanation_relation * res = static_cast(plugin.mk_empty(get_result_signature())); - if(!r.empty()) { + if (!r.empty()) { relation_fact proj_data = r.m_data; project_out_vector_columns(proj_data, m_removed_cols); res->assign_data(proj_data); @@ -348,7 +348,7 @@ namespace datalog { relation_transformer_fn * explanation_relation_plugin::mk_project_fn(const relation_base & r, unsigned col_cnt, const unsigned * removed_cols) { - if(&r.get_plugin()!=this) { + if (&r.get_plugin()!=this) { return 0; } return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); @@ -365,7 +365,7 @@ namespace datalog { explanation_relation_plugin & plugin = r.get_plugin(); explanation_relation * res = static_cast(plugin.mk_empty(get_result_signature())); - if(!r.empty()) { + if (!r.empty()) { relation_fact permutated_data = r.m_data; permutate_by_cycle(permutated_data, m_cycle); res->assign_data(permutated_data); @@ -389,16 +389,16 @@ namespace datalog { explanation_relation * delta = delta0 ? static_cast(delta0) : 0; explanation_relation_plugin & plugin = tgt.get_plugin(); - if(!src.no_undefined() || !tgt.no_undefined() || (delta && !delta->no_undefined())) { + if (!src.no_undefined() || !tgt.no_undefined() || (delta && !delta->no_undefined())) { UNREACHABLE(); } - if(src.empty()) { + if (src.empty()) { return; } - if(plugin.m_relation_level_explanations) { + if (plugin.m_relation_level_explanations) { tgt.unite_with_data(src.m_data); - if(delta) { - if(!m_delta_union_fun) { + if (delta) { + if (!m_delta_union_fun) { m_delta_union_fun = plugin.get_manager().mk_union_fn(*delta, src); SASSERT(m_delta_union_fun); } @@ -406,9 +406,9 @@ namespace datalog { } } else { - if(tgt.empty()) { + if (tgt.empty()) { tgt.assign_data(src.m_data); - if(delta && delta->empty()) { + if (delta && delta->empty()) { delta->assign_data(src.m_data); } } @@ -423,11 +423,11 @@ namespace datalog { explanation_relation & tgt = static_cast(tgt0); explanation_relation * delta = delta0 ? static_cast(delta0) : 0; - if(src.empty()) { + if (src.empty()) { return; } tgt.set_undefined(); - if(delta) { + if (delta) { delta->set_undefined(); } } @@ -435,10 +435,10 @@ namespace datalog { relation_union_fn * explanation_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, const relation_base * delta) { - if(!check_kind(tgt) || (delta && !check_kind(*delta))) { + if (!check_kind(tgt) || (delta && !check_kind(*delta))) { return 0; } - if(!check_kind(src)) { + if (!check_kind(src)) { //this is to handle the product relation return alloc(foreign_union_fn); } @@ -460,7 +460,7 @@ namespace datalog { virtual void operator()(relation_base & r0) { explanation_relation & r = static_cast(r0); - if(!r.is_undefined(m_col_idx)) { + if (!r.is_undefined(m_col_idx)) { UNREACHABLE(); } @@ -468,7 +468,7 @@ namespace datalog { ptr_vector subst_arg; subst_arg.resize(sz, 0); unsigned ofs = sz-1; - for(unsigned i=0; iget_arg(0); expr * arg2 = cond->get_arg(1); - if(is_var(arg2)) { + if (is_var(arg2)) { std::swap(arg1, arg2); } - if(!is_var(arg1) || !is_app(arg2)) { + if (!is_var(arg1) || !is_app(arg2)) { return 0; } var * col_var = to_var(arg1); app * new_rule = to_app(arg2); - if(!get_context().get_decl_util().is_rule_sort(col_var->get_sort())) { + if (!get_context().get_decl_util().is_rule_sort(col_var->get_sort())) { return 0; } unsigned col_idx = col_var->get_idx(); @@ -511,7 +511,7 @@ namespace datalog { class explanation_relation_plugin::negation_filter_fn : public relation_intersection_filter_fn { public: virtual void operator()(relation_base & r, const relation_base & neg) { - if(!neg.empty()) { + if (!neg.empty()) { r.reset(); } } @@ -520,7 +520,7 @@ namespace datalog { relation_intersection_filter_fn * explanation_relation_plugin::mk_filter_by_negation_fn(const relation_base & r, const relation_base & neg, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) { - if(&r.get_plugin()!=this || &neg.get_plugin()!=this) { + if (&r.get_plugin()!=this || &neg.get_plugin()!=this) { return 0; } return alloc(negation_filter_fn); @@ -537,26 +537,26 @@ namespace datalog { explanation_relation & tgt = static_cast(tgt0); const explanation_relation & src = static_cast(src0); - if(src.empty()) { + if (src.empty()) { tgt.reset(); return; } - if(tgt.empty()) { + if (tgt.empty()) { return; } unsigned sz = tgt.get_signature().size(); - for(unsigned i=0; iget_decl()==m_union_decl.get()) { - if(curr_tgt->get_arg(0)==curr_src || curr_tgt->get_arg(1)==curr_src) { + if (curr_tgt->get_decl()==m_union_decl.get()) { + if (curr_tgt->get_arg(0)==curr_src || curr_tgt->get_arg(1)==curr_src) { tgt.m_data.set(i, curr_src); continue; } @@ -570,18 +570,18 @@ namespace datalog { relation_intersection_filter_fn * explanation_relation_plugin::mk_filter_by_intersection_fn( const relation_base & tgt, const relation_base & src, unsigned joined_col_cnt, const unsigned * tgt_cols, const unsigned * src_cols) { - if(&tgt.get_plugin()!=this || &src.get_plugin()!=this) { + if (&tgt.get_plugin()!=this || &src.get_plugin()!=this) { return 0; } //this checks the join is one to one on all columns - if(tgt.get_signature()!=src.get_signature() + if (tgt.get_signature()!=src.get_signature() || joined_col_cnt!=tgt.get_signature().size() || !containers_equal(tgt_cols, tgt_cols+joined_col_cnt, src_cols, src_cols+joined_col_cnt)) { return 0; } counter ctr; ctr.count(joined_col_cnt, tgt_cols); - if(ctr.get_max_counter_value()>1 || (joined_col_cnt && ctr.get_max_positive()!=joined_col_cnt-1)) { + if (ctr.get_max_counter_value()>1 || (joined_col_cnt && ctr.get_max_positive()!=joined_col_cnt-1)) { return 0; } return alloc(intersection_filter_fn, *this); @@ -595,23 +595,23 @@ namespace datalog { // ----------------------------------- - mk_explanations::mk_explanations(context & ctx, bool relation_level) - : plugin(50000), - m_manager(ctx.get_manager()), - m_context(ctx), - m_decl_util(ctx.get_decl_util()), - m_relation_level(relation_level), - m_pinned(m_manager) { + mk_explanations::mk_explanations(context & ctx) + : plugin(50000), + m_manager(ctx.get_manager()), + m_context(ctx), + m_decl_util(ctx.get_decl_util()), + m_relation_level(ctx.explanations_on_relation_level()), + m_pinned(m_manager) { m_e_sort = m_decl_util.mk_rule_sort(); m_pinned.push_back(m_e_sort); relation_manager & rmgr = ctx.get_rel_context().get_rmanager(); - symbol er_symbol = explanation_relation_plugin::get_name(relation_level); + symbol er_symbol = explanation_relation_plugin::get_name(m_relation_level); m_er_plugin = static_cast(rmgr.get_relation_plugin(er_symbol)); - if(!m_er_plugin) { - m_er_plugin = alloc(explanation_relation_plugin, relation_level, rmgr); + if (!m_er_plugin) { + m_er_plugin = alloc(explanation_relation_plugin, m_relation_level, rmgr); rmgr.register_plugin(m_er_plugin); - if(!m_relation_level) { + if (!m_relation_level) { DEBUG_CODE( finite_product_relation_plugin * dummy; SASSERT(!rmgr.try_get_finite_product_relation_plugin(*m_er_plugin, dummy)); @@ -620,7 +620,7 @@ namespace datalog { } } DEBUG_CODE( - if(!m_relation_level) { + if (!m_relation_level) { finite_product_relation_plugin * dummy; SASSERT(rmgr.try_get_finite_product_relation_plugin(*m_er_plugin, dummy)); } @@ -668,7 +668,7 @@ namespace datalog { func_decl * mk_explanations::get_e_decl(func_decl * orig_decl) { decl_map::obj_map_entry * e = m_e_decl_map.insert_if_not_there2(orig_decl, 0); - if(e->get_data().m_value==0) { + if (e->get_data().m_value==0) { relation_signature e_domain; e_domain.append(orig_decl->get_arity(), orig_decl->get_domain()); e_domain.push_back(m_e_sort); @@ -677,7 +677,7 @@ namespace datalog { m_pinned.push_back(new_decl); e->get_data().m_value = new_decl; - if(m_relation_level) { + if (m_relation_level) { assign_rel_level_kind(new_decl, orig_decl); } } @@ -716,13 +716,13 @@ namespace datalog { app_ref_vector e_tail(m_manager); svector neg_flags; unsigned pos_tail_sz = r->get_positive_tail_size(); - for(unsigned i=0; iget_tail(i), e_var)); neg_flags.push_back(false); } unsigned tail_sz = r->get_tail_size(); - for(unsigned i=pos_tail_sz; iget_tail(i)); neg_flags.push_back(r->is_neg_tail(i)); } @@ -730,9 +730,9 @@ namespace datalog { symbol rule_repr = get_rule_symbol(r); expr_ref_vector rule_expr_args(m_manager); - for(unsigned tail_idx=0; tail_idxget_arg(tail->get_num_args()-1)); } @@ -754,37 +754,32 @@ namespace datalog { return m_context.get_rule_manager().mk(e_head, e_tail.size(), e_tail.c_ptr(), neg_flags.c_ptr()); } - void mk_explanations::transform_rules(const rule_set & orig, rule_set & tgt) { - rule_set::iterator rit = orig.begin(); - rule_set::iterator rend = orig.end(); - for(; rit!=rend; ++rit) { + void mk_explanations::transform_rules(const rule_set & src, rule_set & dst) { + rule_set::iterator rit = src.begin(); + rule_set::iterator rend = src.end(); + for (; rit!=rend; ++rit) { rule * e_rule = get_e_rule(*rit); - tgt.add_rule(e_rule); + dst.add_rule(e_rule); } //add rules that will (for output predicates) copy facts from explained relations back to //the original ones expr_ref_vector lit_args(m_manager); - decl_set::iterator pit = m_original_preds.begin(); - decl_set::iterator pend = m_original_preds.end(); - for(; pit!=pend; ++pit) { + decl_set::iterator pit = src.get_output_predicates().begin(); + decl_set::iterator pend = src.get_output_predicates().end(); + for (; pit != pend; ++pit) { func_decl * orig_decl = *pit; - if(!m_context.is_output_predicate(orig_decl)) { - continue; - } - lit_args.reset(); unsigned arity = orig_decl->get_arity(); - for(unsigned i=0; iget_domain(i))); } app_ref orig_lit(m_manager.mk_app(orig_decl, lit_args.c_ptr()), m_manager); app_ref e_lit(get_e_lit(orig_lit, arity), m_manager); app * tail[] = { e_lit.get() }; - tgt.add_rule(m_context.get_rule_manager().mk(orig_lit, 1, tail, 0)); + dst.add_rule(m_context.get_rule_manager().mk(orig_lit, 1, tail, 0)); } - } void mk_explanations::translate_rel_level_relation(relation_manager & rmgr, relation_base & orig, @@ -799,7 +794,7 @@ namespace datalog { sieve_relation * srels[] = { static_cast(&prod_rel[0]), static_cast(&prod_rel[1]) }; - if(&srels[0]->get_inner().get_plugin()==m_er_plugin) { + if (&srels[0]->get_inner().get_plugin()==m_er_plugin) { std::swap(srels[0], srels[1]); } SASSERT(&srels[0]->get_inner().get_plugin()==&orig.get_plugin()); @@ -821,10 +816,9 @@ namespace datalog { } } - void mk_explanations::transform_facts(relation_manager & rmgr) { + void mk_explanations::transform_facts(relation_manager & rmgr, rule_set const& src, rule_set& dst) { - - if(!m_e_fact_relation) { + if (!m_e_fact_relation) { relation_signature expl_singleton_sig; expl_singleton_sig.push_back(m_e_sort); @@ -836,29 +830,26 @@ namespace datalog { SASSERT(&expl_singleton->get_plugin()==m_er_plugin); m_e_fact_relation = static_cast(expl_singleton); } - - - - decl_set::iterator it = m_original_preds.begin(); - decl_set::iterator end = m_original_preds.end(); - for(; it!=end; ++it) { + func_decl_set const& predicates = m_context.get_predicates(); + decl_set::iterator it = predicates.begin(); + decl_set::iterator end = predicates.end(); + for (; it!=end; ++it) { func_decl * orig_decl = *it; func_decl * e_decl = get_e_decl(orig_decl); - if(m_context.is_output_predicate(orig_decl)) { - m_context.set_output_predicate(e_decl); - } - - if(!rmgr.try_get_relation(orig_decl)) { - //there are no facts for this predicate + if (!rmgr.try_get_relation(orig_decl) && + !src.contains(orig_decl)) { + // there are no facts or rules for this predicate continue; } + dst.inherit_predicate(src, orig_decl, e_decl); + relation_base & orig_rel = rmgr.get_relation(orig_decl); relation_base & e_rel = rmgr.get_relation(e_decl); SASSERT(e_rel.empty()); //the e_rel should be a new relation - - if(m_relation_level) { + + if (m_relation_level) { translate_rel_level_relation(rmgr, orig_rel, e_rel); } else { @@ -869,18 +860,19 @@ namespace datalog { SASSERT(union_fun); (*union_fun)(e_rel, *aux_extended_rel); } - } } rule_set * mk_explanations::operator()(rule_set const & source) { - if(source.get_num_rules()==0) { + if (source.empty()) { + return 0; + } + if (!m_context.generate_explanations()) { return 0; } - m_context.collect_predicates(m_original_preds); rule_set * res = alloc(rule_set, m_context); - transform_facts(m_context.get_rel_context().get_rmanager()); + transform_facts(m_context.get_rel_context().get_rmanager(), source, *res); transform_rules(source, *res); return res; } diff --git a/src/muz_qe/dl_mk_explanations.h b/src/muz_qe/dl_mk_explanations.h index 4e7e23e98..9e4d705c3 100644 --- a/src/muz_qe/dl_mk_explanations.h +++ b/src/muz_qe/dl_mk_explanations.h @@ -32,19 +32,13 @@ namespace datalog { typedef obj_map decl_map; - ast_manager & m_manager; - context & m_context; + ast_manager & m_manager; + context & m_context; dl_decl_util & m_decl_util; - - bool m_relation_level; - - decl_set m_original_preds; - + bool m_relation_level; ast_ref_vector m_pinned; - explanation_relation_plugin * m_er_plugin; - - sort * m_e_sort; + sort * m_e_sort; scoped_rel m_e_fact_relation; decl_map m_e_decl_map; @@ -62,15 +56,15 @@ namespace datalog { void assign_rel_level_kind(func_decl * e_decl, func_decl * orig); void translate_rel_level_relation(relation_manager & rmgr, relation_base & orig, relation_base & e_rel); - void transform_rules(const rule_set & orig, rule_set & tgt); + void transform_rules(const rule_set & src, rule_set & dst); - void transform_facts(relation_manager & rmgr); + void transform_facts(relation_manager & rmgr, rule_set const& src, rule_set& dst); public: /** If relation_level is true, the explanation will not be stored for each fact, but we will rather store history of the whole relation. */ - mk_explanations(context & ctx, bool relation_level); + mk_explanations(context & ctx); /** \brief Return explanation predicate that corresponds to \c orig_decl. diff --git a/src/muz_qe/dl_mk_extract_quantifiers.cpp b/src/muz_qe/dl_mk_extract_quantifiers.cpp deleted file mode 100644 index 76e329d79..000000000 --- a/src/muz_qe/dl_mk_extract_quantifiers.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - dl_mk_extract_quantifiers.cpp - -Abstract: - - Remove universal quantifiers over interpreted predicates in the body. - -Author: - - Nikolaj Bjorner (nbjorner) 2012-11-21 - -Revision History: - ---*/ - -#include"dl_mk_extract_quantifiers.h" -#include"ast_pp.h" -#include"dl_bmc_engine.h" -#include"smt_quantifier.h" -#include"smt_context.h" -#include"for_each_expr.h" -#include "expr_abstract.h" - - -namespace datalog { - - - mk_extract_quantifiers::mk_extract_quantifiers(context & ctx) : - rule_transformer::plugin(101, false), - m_ctx(ctx), - m(ctx.get_manager()), - rm(ctx.get_rule_manager()), - m_query_pred(m) - {} - - mk_extract_quantifiers::~mk_extract_quantifiers() { - reset(); - } - - void mk_extract_quantifiers::set_query(func_decl* q) { - m_query_pred = q; - } - - void mk_extract_quantifiers::ensure_predicate(expr* e, unsigned& max_var, app_ref_vector& tail) { - SASSERT(is_app(e)); - SASSERT(to_app(e)->get_decl()->get_family_id() == null_family_id); - app* a = to_app(e); - expr_ref_vector args(m); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr* arg = a->get_arg(i); - if (is_var(arg) || m.is_value(arg)) { - args.push_back(arg); - } - else { - expr_ref new_var(m); - new_var = m.mk_var(++max_var, m.get_sort(arg)); - args.push_back(new_var); - tail.push_back(m.mk_eq(new_var, arg)); - } - } - tail.push_back(m.mk_app(a->get_decl(), args.size(), args.c_ptr())); - } - - class mk_extract_quantifiers::collect_insts { - ast_manager& m; - ptr_vector m_binding; - vector m_bindings; - ptr_vector m_quantifiers; - public: - collect_insts(ast_manager& m): m(m) { } - - void operator()(expr* n) { - expr* not_q_or_i, *e1, *e2, *e3; - if (m.is_quant_inst(n, not_q_or_i, m_binding)) { - VERIFY(m.is_or(not_q_or_i, e1, e2)); - VERIFY(m.is_not(e1, e3)); - SASSERT(is_quantifier(e3)); - m_quantifiers.push_back(to_quantifier(e3)); - m_bindings.push_back(expr_ref_vector(m,m_binding.size(), m_binding.c_ptr())); - m_binding.reset(); - } - else if ((m.is_rewrite(n, e1, e2) || - (m.is_rewrite_star(n) && - (e3 = to_app(n)->get_arg(to_app(n)->get_num_args()-1), - e1 = to_app(e3)->get_arg(0), - e2 = to_app(e3)->get_arg(1), - true))) && - is_quantifier(e1) && m.is_false(e2)) { - quantifier* q = to_quantifier(e1); - m_quantifiers.push_back(q); - m_bindings.push_back(expr_ref_vector(m)); - expr_ref_vector& b = m_bindings.back(); - for (unsigned i = 0; i < q->get_num_decls(); ++i) { - b.push_back(m.mk_fresh_const("V", q->get_decl_sort(i))); - } - } - } - - void reset() { - m_quantifiers.reset(); - m_bindings.reset(); - } - - unsigned size() const { return m_quantifiers.size(); } - ptr_vector const& quantifiers() const { return m_quantifiers; } - vector const& bindings() const { return m_bindings; } - }; - - - /* - * forall y . P1(x,y) & - * forall y . P2(x,y) & - * Body[x] & - * ~H[x] - * forall y . y != binding1 => ~ P1(x,y) - * forall y . y != binding2 => ~ P2(x,y) - */ - void mk_extract_quantifiers::extract(rule& r, rule_set& new_rules) { - unsigned utsz = r.get_uninterpreted_tail_size(); - expr_ref_vector conjs(m); - quantifier_ref_vector qs(m); - for (unsigned i = utsz; i < r.get_tail_size(); ++i) { - conjs.push_back(r.get_tail(i)); - } - datalog::flatten_and(conjs); - for (unsigned j = 0; j < conjs.size(); ++j) { - expr* e = conjs[j].get(); - quantifier* q; - if (rule_manager::is_forall(m, e, q)) { - qs.push_back(q); - conjs[j] = conjs.back(); - conjs.pop_back(); - --j; - } - } - if (qs.empty()) { - new_rules.add_rule(&r); - } - else { - expr_ref fml(m); - expr_ref_vector bindings(m); - obj_map insts; - for (unsigned i = 0; i < qs.size(); ++i) { - insts.insert(qs[i].get(), alloc(expr_ref_vector, m)); - } - - unsigned max_inst = 10; // TODO configuration. - - for (unsigned i = 0; i < max_inst; ++i) { - app_ref_vector sub(m); - rule2formula(r, insts, fml, sub); - bool new_binding = find_instantiations_proof_based(fml, sub, insts, bindings); - if (!new_binding) { - break; - } - } - - expr_ref_vector fmls(m); - for (unsigned i = 0; i < utsz; ++i) { - fmls.push_back(r.get_tail(i)); - } - fmls.append(bindings); - fmls.append(conjs); - fml = m.mk_implies(m.mk_and(fmls.size(), fmls.c_ptr()), r.get_head()); - TRACE("dl", tout << "new rule\n" << mk_pp(fml, m) << "\n";); - rule_ref_vector rules(rm); - proof_ref pr(m); - if (m_ctx.generate_proof_trace()) { - scoped_proof _scp(m); - expr_ref fml1(m); - r.to_formula(fml1); - pr = m.mk_rewrite(fml1, fml); - pr = m.mk_modus_ponens(r.get_proof(), pr); - } - rm.mk_rule(fml, pr, rules, r.name()); - for (unsigned i = 0; i < rules.size(); ++i) { - new_rules.add_rule(rules[i].get()); - m_quantifiers.insert(rules[i].get(), alloc(quantifier_ref_vector, qs)); - } - obj_map::iterator it = insts.begin(), end = insts.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } - } - } - - void mk_extract_quantifiers::rule2formula( - rule& r, - obj_map const& insts, - expr_ref& fml, - app_ref_vector& sub) - { - expr_ref body(m); - expr_ref_vector fmls(m); - ptr_vector sorts; - var_subst vs(m, false); - obj_map::iterator it = insts.begin(), end = insts.end(); - for (; it != end; ++it) { - quantifier* q = it->m_key; - expr_ref_vector& eqs = *it->m_value; - expr_ref_vector disj(m); - disj.append(eqs); - disj.push_back(m.mk_not(q->get_expr())); - body = m.mk_or(disj.size(), disj.c_ptr()); - fml = m.update_quantifier(q, body); - fmls.push_back(fml); - } - fml = m.mk_or(fmls.size(), fmls.c_ptr()); - fmls.reset(); - fmls.push_back(fml); - for (unsigned i = 0; i < r.get_tail_size(); ++i) { - SASSERT(!r.is_neg_tail(i)); - fmls.push_back(r.get_tail(i)); - } - fmls.push_back(m.mk_not(r.get_head())); - fml = m.mk_and(fmls.size(), fmls.c_ptr()); - - get_free_vars(fml, sorts); - for (unsigned i = 0; i < sorts.size(); ++i) { - if (!sorts[i]) { - sorts[i] = m.mk_bool_sort(); - } - sub.push_back(m.mk_const(symbol(i), sorts[i])); - } - vs(fml, sub.size(), (expr*const*)sub.c_ptr(), fml); - } - - bool mk_extract_quantifiers::find_instantiations_proof_based( - expr* fml, - app_ref_vector const& var_inst, - obj_map& insts, - expr_ref_vector& bindings) - { - datalog::scoped_proof _scp(m); - smt_params fparams; - fparams.m_mbqi = true; // false - fparams.m_soft_timeout = 1000; - smt::kernel solver(m, fparams); - solver.assert_expr(fml); - IF_VERBOSE(1, verbose_stream() << "check\n";); - lbool result = solver.check(); - IF_VERBOSE(1, verbose_stream() << "checked\n";); - TRACE("dl", tout << result << "\n";); - if (result != l_false) { - return false; - } - - map qid_map; - quantifier* q; - - obj_map::iterator it = insts.begin(), end = insts.end(); - for (; it != end; ++it) { - q = it->m_key; - qid_map.insert(q->get_qid(), q); - } - - proof* p = solver.get_proof(); - TRACE("dl", tout << mk_pp(p, m) << "\n";); - collect_insts collector(m); - for_each_expr(collector, p); - ptr_vector const& quants = collector.quantifiers(); - - for (unsigned i = 0; i < collector.size(); ++i) { - symbol qid = quants[i]->get_qid(); - if (!qid_map.find(qid, q)) { - TRACE("dl", tout << "Could not find quantifier " << mk_pp(quants[i], m) << "\n";); - continue; - } - expr_ref_vector const& binding = collector.bindings()[i]; - - TRACE("dl", tout << "Instantiating:\n" << mk_pp(quants[i], m) << "\n"; - for (unsigned j = 0; j < binding.size(); ++j) { - tout << mk_pp(binding[j], m) << " "; - } - tout << "\n";); - - expr_ref_vector instantiation(m); - for (unsigned j = 0; j < binding.size(); ++j) { - instantiation.push_back(binding[j]); - } - add_binding(var_inst, bindings, q, instantiation, insts); - } - - return collector.size() > 0; - } - - void mk_extract_quantifiers::add_binding( - app_ref_vector const& var_inst, - expr_ref_vector& bindings, - quantifier* q, - expr_ref_vector const& instantiation, - obj_map& insts) - { - if (instantiation.size() == q->get_num_decls()) { - // Full binding. - apply_binding(var_inst, bindings, q, instantiation, insts); - } - } - - void mk_extract_quantifiers::apply_binding( - app_ref_vector const& var_inst, - expr_ref_vector& bindings, - quantifier* q, - expr_ref_vector const& instantiation, - obj_map& insts) - { - datalog::scoped_no_proof _scp(m); - expr_ref e(m); - expr_ref_vector eqs(m); - var_subst vs(m, false); - inv_var_shifter invsh(m); - vs(q->get_expr(), instantiation.size(), instantiation.c_ptr(), e); - invsh(e, q->get_num_decls(), e); - expr_ref_vector inst(m); - inst.append(var_inst.size(), (expr*const*)var_inst.c_ptr()); - inst.reverse(); - expr_abstract(m, 0, inst.size(), inst.c_ptr(), e, e); - bindings.push_back(e); - for (unsigned i = 0; i < instantiation.size(); ++i) { - e = instantiation[i]; - e = m.mk_eq(m.mk_var(i, q->get_decl_sort(i)), e); - eqs.push_back(e); - } - e = m.mk_and(eqs.size(), eqs.c_ptr()); - insts.find(q)->push_back(e); - - TRACE("dl", tout << mk_pp(q, m) << "\n"; - tout << "instantiation: "; - for (unsigned i = 0; i < instantiation.size(); ++i) { - tout << mk_pp(instantiation[i], m) << " "; - } - tout << "\n"; - tout << "inst: "; - for (unsigned i = 0; i < var_inst.size(); ++i) { - tout << mk_pp(var_inst[i], m) << " "; - } - tout << "\n"; - tout << mk_pp(bindings.back(), m) << "\n"; - tout << "eqs: " << mk_pp(e, m) << "\n"; - ); - } - - - void mk_extract_quantifiers::reset() { - obj_map::iterator it = m_quantifiers.begin(), - end = m_quantifiers.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } - m_has_quantifiers = false; - m_quantifiers.reset(); - } - - rule_set * mk_extract_quantifiers::operator()(rule_set const & source) { - reset(); - rule_set::iterator it = source.begin(), end = source.end(); - for (; !m_has_quantifiers && it != end; ++it) { - m_has_quantifiers = (*it)->has_quantifiers(); - } - if (!m_has_quantifiers) { - return 0; - } - - rule_set* rules = alloc(rule_set, m_ctx); - it = source.begin(); - for (; it != end; ++it) { - extract(**it, *rules); - } - - return rules; - } - -}; - - diff --git a/src/muz_qe/dl_mk_extract_quantifiers.h b/src/muz_qe/dl_mk_extract_quantifiers.h deleted file mode 100644 index 27b13cd71..000000000 --- a/src/muz_qe/dl_mk_extract_quantifiers.h +++ /dev/null @@ -1,99 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - dl_mk_extract_quantifiers.h - -Abstract: - - Replace universal quantifiers over interpreted predicates in the body - by instantiations mined using bounded model checking search. - -Author: - - Nikolaj Bjorner (nbjorner) 2012-11-21 - -Revision History: - ---*/ -#ifndef _DL_MK_EXTRACT_QUANTIFIERS_H_ -#define _DL_MK_EXTRACT_QUANTIFIERS_H_ - -#include"dl_context.h" -#include"dl_rule_set.h" -#include"dl_rule_transformer.h" -#include"obj_pair_hashtable.h" - -namespace datalog { - - /** - \brief Extract universal quantifiers from rules. - */ - class mk_extract_quantifiers : public rule_transformer::plugin { - - class collect_insts; - - context& m_ctx; - ast_manager& m; - rule_manager& rm; - func_decl_ref m_query_pred; - bool m_has_quantifiers; - obj_map m_quantifiers; - - void reset(); - - void extract(rule& r, rule_set& new_rules); - - void rule2formula( - rule& r, - obj_map const& insts, - expr_ref& fml, - app_ref_vector& sub); - - - void add_binding( - app_ref_vector const& var_inst, - expr_ref_vector& bindings, - quantifier* q, - expr_ref_vector const& instantiation, - obj_map& insts); - - void apply_binding( - app_ref_vector const& var_inst, - expr_ref_vector& bindings, - quantifier* q, - expr_ref_vector const& instantiation, - obj_map& insts); - - - public: - /** - \brief Create rule transformer that extracts universal quantifiers (over recursive predicates). - */ - mk_extract_quantifiers(context & ctx); - - virtual ~mk_extract_quantifiers(); - - void set_query(func_decl* q); - - rule_set * operator()(rule_set const & source); - - bool has_quantifiers() { return m_has_quantifiers; } - - obj_map& quantifiers() { return m_quantifiers; } - - void ensure_predicate(expr* e, unsigned& max_var, app_ref_vector& tail); - - bool find_instantiations_proof_based( - expr* fml, - app_ref_vector const& var_inst, - obj_map& insts, - expr_ref_vector& bindings); - - }; - -}; - -#endif /* _DL_MK_EXTRACT_QUANTIFIERS_H_ */ - diff --git a/src/muz_qe/dl_mk_filter_rules.cpp b/src/muz_qe/dl_mk_filter_rules.cpp index 62abd78c4..3f5ee0394 100644 --- a/src/muz_qe/dl_mk_filter_rules.cpp +++ b/src/muz_qe/dl_mk_filter_rules.cpp @@ -31,6 +31,7 @@ namespace datalog { m_result(0), m_pinned(m_manager) { } + mk_filter_rules::~mk_filter_rules() { ptr_vector to_dealloc; filter_cache::iterator it = m_tail2filter.begin(); @@ -50,7 +51,7 @@ namespace datalog { \brief Return true if \c pred is a cadidate for a "filter" rule. */ bool mk_filter_rules::is_candidate(app * pred) { - if (!m_context.get_rule_manager().is_predicate(pred)) { + if (!m_context.is_predicate(pred)) { TRACE("mk_filter_rules", tout << mk_pp(pred, m_manager) << "\nis not a candidate because it is interpreted.\n";); return false; } @@ -157,13 +158,13 @@ namespace datalog { m_modified = false; unsigned num_rules = source.get_num_rules(); for (unsigned i = 0; i < num_rules; i++) { - rule * r = source.get_rule(i); - process(r); + process(source.get_rule(i)); } if(!m_modified) { dealloc(m_result); return static_cast(0); } + m_result->inherit_predicates(source); return m_result; } diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index 0d468f9ef..51bbd52df 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -587,6 +587,7 @@ namespace datalog { dealloc(res); res = 0; } + res->inherit_predicates(source); return res; } diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index c4a6a3cdb..c8e350eeb 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -199,15 +199,15 @@ namespace datalog { return 0; } } + m_inner_ctx.reset(); rel_context& rctx = m_inner_ctx.get_rel_context(); ptr_vector heads; - m_inner_ctx.ensure_opened(); - it = source.begin(); - for (; it != end; ++it) { - rule_ref r(*it, m_inner_ctx.get_rule_manager()); - m_inner_ctx.add_rule(r); - m_inner_ctx.register_predicate(r->get_decl(), false); + func_decl_set const& predicates = m_ctx.get_predicates(); + for (func_decl_set::iterator fit = predicates.begin(); fit != predicates.end(); ++fit) { + m_inner_ctx.register_predicate(*fit, false); } + m_inner_ctx.ensure_opened(); + m_inner_ctx.replace_rules(source); m_inner_ctx.close(); rule_set::decl2rules::iterator dit = source.begin_grouped_rules(); rule_set::decl2rules::iterator dend = source.end_grouped_rules(); @@ -237,6 +237,7 @@ namespace datalog { m_ctx.add_model_converter(kmc); } TRACE("dl", rules->display(tout);); + rules->inherit_predicates(source); return rules; } diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp index 6b95671f2..144826639 100644 --- a/src/muz_qe/dl_mk_loop_counter.cpp +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -25,6 +25,7 @@ namespace datalog { mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority): plugin(priority), m(ctx.get_manager()), + m_ctx(ctx), a(m), m_refs(m) { } @@ -72,14 +73,14 @@ namespace datalog { for (unsigned j = 0; j < utsz; ++j, ++cnt) { tail.push_back(add_arg(r.get_tail(j), cnt)); neg.push_back(r.is_neg_tail(j)); - ctx.register_predicate(tail.back()->get_decl(), false); + m_ctx.register_predicate(tail.back()->get_decl(), false); } for (unsigned j = utsz; j < tsz; ++j) { tail.push_back(r.get_tail(j)); neg.push_back(false); } head = add_arg(r.get_head(), cnt); - ctx.register_predicate(head->get_decl(), false); + m_ctx.register_predicate(head->get_decl(), false); // set the loop counter to be an increment of the previous bool found = false; unsigned last = head->get_num_args()-1; @@ -107,6 +108,8 @@ namespace datalog { // model converter: remove references to extra argument. // proof converter: remove references to extra argument as well. + result->inherit_predicates(source); + return result; } diff --git a/src/muz_qe/dl_mk_loop_counter.h b/src/muz_qe/dl_mk_loop_counter.h index 6601f837f..fc4d7e32f 100644 --- a/src/muz_qe/dl_mk_loop_counter.h +++ b/src/muz_qe/dl_mk_loop_counter.h @@ -26,6 +26,7 @@ namespace datalog { class mk_loop_counter : public rule_transformer::plugin { ast_manager& m; + context& m_ctx; arith_util a; func_decl_ref_vector m_refs; obj_map m_new2old; diff --git a/src/muz_qe/dl_mk_magic_sets.cpp b/src/muz_qe/dl_mk_magic_sets.cpp index 6885edc4e..27846410c 100644 --- a/src/muz_qe/dl_mk_magic_sets.cpp +++ b/src/muz_qe/dl_mk_magic_sets.cpp @@ -24,13 +24,12 @@ Revision History: namespace datalog { - mk_magic_sets::mk_magic_sets(context & ctx, rule * goal_rule) : + mk_magic_sets::mk_magic_sets(context & ctx, func_decl* goal) : plugin(10000, true), m_context(ctx), - m_manager(ctx.get_manager()), - m_rules(ctx.get_rule_manager()), - m_pinned(m_manager), - m_goal_rule(goal_rule, ctx.get_rule_manager()) { + m(ctx.get_manager()), + m_pinned(m), + m_goal(goal, m) { } void mk_magic_sets::reset() { @@ -39,14 +38,13 @@ namespace datalog { m_adorned_preds.reset(); m_adornments.reset(); m_magic_preds.reset(); - m_rules.reset(); m_pinned.reset(); } void mk_magic_sets::adornment::populate(app * lit, const var_idx_set & bound_vars) { SASSERT(empty()); unsigned arity = lit->get_num_args(); - for(unsigned i=0; iget_arg(i); bool bound = !is_var(arg) || bound_vars.contains(to_var(arg)->get_idx()); push_back(bound ? AD_BOUND : AD_FREE); @@ -57,17 +55,8 @@ namespace datalog { std::string res; const_iterator eit = begin(); const_iterator eend = end(); - for(; eit!=eend; ++eit) { - switch(*eit) { - case AD_BOUND: - res+='b'; - break; - case AD_FREE: - res+='f'; - break; - default: - UNREACHABLE(); - } + for (; eit != eend; ++eit) { + res += (*eit == AD_BOUND)?'b':'f'; } return res; } @@ -75,14 +64,13 @@ namespace datalog { unsigned get_bound_arg_count(app * lit, const var_idx_set & bound_vars) { unsigned res = 0; unsigned n = lit->get_num_args(); - for(unsigned i=0; iget_arg(i); - if(is_var(arg) && !bound_vars.contains(to_var(arg)->get_idx())) { - continue; + if (!is_var(arg) || bound_vars.contains(to_var(arg)->get_idx())) { + SASSERT(is_var(arg) || is_app(arg)); + SASSERT(!is_app(arg) || to_app(arg)->get_num_args()==0); + res++; } - SASSERT(is_var(arg) || is_app(arg)); - SASSERT(!is_app(arg) || to_app(arg)->get_num_args()==0); - res++; } return res; } @@ -91,10 +79,10 @@ namespace datalog { func_decl * pred = lit->get_decl(); float res = 1; unsigned n = lit->get_num_args(); - for(unsigned i=0; iget_arg(i); - if(is_var(arg) && !bound_vars.contains(to_var(arg)->get_idx())) { - res*=m_context.get_sort_size_estimate(pred->get_domain(i)); + if (is_var(arg) && !bound_vars.contains(to_var(arg)->get_idx())) { + res *= m_context.get_sort_size_estimate(pred->get_domain(i)); } //res-=1; } @@ -111,22 +99,22 @@ namespace datalog { float best_cost; int candidate_index = -1; unsigned n = cont.size(); - for(unsigned i=0; iget_tail(cont[i]); unsigned bound_cnt = get_bound_arg_count(lit, bound_vars); - if(bound_cnt==0) { + if (bound_cnt==0) { continue; } float cost = get_unbound_cost(lit, bound_vars); - if(candidate_index==-1 || cost(n-1)) { + if (candidate_index != static_cast(n-1)) { std::swap(cont[candidate_index], cont[n-1]); } unsigned res = cont.back(); @@ -137,12 +125,12 @@ namespace datalog { app * mk_magic_sets::adorn_literal(app * lit, const var_idx_set & bound_vars) { SASSERT(!m_extentional.contains(lit->get_decl())); func_decl * old_pred = lit->get_decl(); - SASSERT(m_manager.is_bool(old_pred->get_range())); + SASSERT(m.is_bool(old_pred->get_range())); adornment_desc adn(old_pred); adn.m_adornment.populate(lit, bound_vars); adornment_map::entry * e = m_adorned_preds.insert_if_not_there2(adn, 0); func_decl * new_pred = e->get_data().m_value; - if(new_pred==0) { + if (new_pred==0) { std::string suffix = "ad_"+adn.m_adornment.to_string(); new_pred = m_context.mk_fresh_head_predicate( old_pred->get_name(), symbol(suffix.c_str()), @@ -152,34 +140,34 @@ namespace datalog { m_todo.push_back(adn); m_adornments.insert(new_pred, adn.m_adornment); } - app * res = m_manager.mk_app(new_pred, lit->get_args()); + app * res = m.mk_app(new_pred, lit->get_args()); m_pinned.push_back(res); return res; } app * mk_magic_sets::create_magic_literal(app * l) { func_decl * l_pred = l->get_decl(); - SASSERT(m_manager.is_bool(l_pred->get_range())); + SASSERT(m.is_bool(l_pred->get_range())); pred_adornment_map::obj_map_entry * ae = m_adornments.find_core(l_pred); SASSERT(ae); const adornment & adn = ae->get_data().m_value; unsigned l_arity = l->get_num_args(); ptr_vector bound_args; - for(unsigned i=0; iget_arg(i)); } } pred2pred::obj_map_entry * e = m_magic_preds.insert_if_not_there2(l_pred, 0); func_decl * mag_pred = e->get_data().m_value; - if(mag_pred==0) { + if (mag_pred==0) { unsigned mag_arity = bound_args.size(); ptr_vector mag_domain; - for(unsigned i=0; iget_domain(i)); } } @@ -190,12 +178,12 @@ namespace datalog { e->get_data().m_value = mag_pred; } - app * res = m_manager.mk_app(mag_pred, bound_args.c_ptr()); + app * res = m.mk_app(mag_pred, bound_args.c_ptr()); m_pinned.push_back(res); return res; } - void mk_magic_sets::create_magic_rules(app * head, unsigned tail_cnt, app * const * tail, bool const* negated) { + void mk_magic_sets::create_magic_rules(app * head, unsigned tail_cnt, app * const * tail, bool const* negated, rule_set& result) { //TODO: maybe include relevant interpreted predicates from the original rule ptr_vector new_tail; svector negations; @@ -204,26 +192,26 @@ namespace datalog { negations.push_back(false); negations.append(tail_cnt, negated); - for(unsigned i=0; iget_decl())) { + for (unsigned i=0; iget_decl())) { continue; } app * mag_head = create_magic_literal(tail[i]); rule * r = m_context.get_rule_manager().mk(mag_head, i+1, new_tail.c_ptr(), negations.c_ptr()); TRACE("dl", r->display(m_context,tout); ); - m_rules.push_back(r); + result.add_rule(r); } } - void mk_magic_sets::transform_rule(const adornment & head_adornment, rule * r) { + void mk_magic_sets::transform_rule(const adornment & head_adornment, rule * r, rule_set& result) { app * head = r->get_head(); unsigned head_len = head->get_num_args(); SASSERT(head_len==head_adornment.size()); var_idx_set bound_vars; - for(unsigned i=0; iget_arg(i); - if(head_adornment[i]==AD_BOUND && is_var(arg)) { + if (head_adornment[i]==AD_BOUND && is_var(arg)) { bound_vars.insert(to_var(arg)->get_idx()); } } @@ -231,9 +219,9 @@ namespace datalog { unsigned processed_tail_len = r->get_uninterpreted_tail_size(); unsigned_vector exten_tails; unsigned_vector inten_tails; - for(unsigned i=0; iget_tail(i); - if(m_extentional.contains(t->get_decl())) { + if (m_extentional.contains(t->get_decl())) { exten_tails.push_back(i); } else { @@ -243,17 +231,17 @@ namespace datalog { ptr_vector new_tail; svector negations; - while(new_tail.size()!=processed_tail_len) { + while (new_tail.size()!=processed_tail_len) { bool intentional = false; int curr_index = pop_bound(exten_tails, r, bound_vars); - if(curr_index==-1) { + if (curr_index==-1) { curr_index = pop_bound(inten_tails, r,bound_vars); - if(curr_index!=-1) { + if (curr_index!=-1) { intentional = true; } } - if(curr_index==-1) { - if(!exten_tails.empty()) { + if (curr_index==-1) { + if (!exten_tails.empty()) { curr_index = exten_tails.back(); exten_tails.pop_back(); } @@ -266,24 +254,24 @@ namespace datalog { } SASSERT(curr_index!=-1); app * curr = r->get_tail(curr_index); - if(intentional) { + if (intentional) { curr = adorn_literal(curr, bound_vars); } new_tail.push_back(curr); negations.push_back(r->is_neg_tail(curr_index)); - collect_vars(m_manager, curr, bound_vars); + collect_vars(m, curr, bound_vars); } func_decl * new_head_pred; VERIFY( m_adorned_preds.find(adornment_desc(head->get_decl(), head_adornment), new_head_pred) ); - app * new_head = m_manager.mk_app(new_head_pred, head->get_args()); + app * new_head = m.mk_app(new_head_pred, head->get_args()); SASSERT(new_tail.size()==r->get_uninterpreted_tail_size()); - create_magic_rules(new_head, new_tail.size(), new_tail.c_ptr(), negations.c_ptr()); + create_magic_rules(new_head, new_tail.size(), new_tail.c_ptr(), negations.c_ptr(), result); unsigned tail_len = r->get_tail_size(); - for(unsigned i=processed_tail_len; iget_tail(i)); negations.push_back(r->is_neg_tail(i)); } @@ -292,43 +280,49 @@ namespace datalog { negations.push_back(false); rule * nr = m_context.get_rule_manager().mk(new_head, new_tail.size(), new_tail.c_ptr(), negations.c_ptr()); - m_rules.push_back(nr); + result.add_rule(nr); nr->set_accounting_parent_object(m_context, r); } - void mk_magic_sets::create_transfer_rule(const adornment_desc & d) { - func_decl * adn_pred; - TRUSTME( m_adorned_preds.find(d, adn_pred) ); + void mk_magic_sets::create_transfer_rule(const adornment_desc & d, rule_set& result) { + func_decl * adn_pred = m_adorned_preds.find(d); unsigned arity = adn_pred->get_arity(); - SASSERT(arity==d.m_pred->get_arity()); + SASSERT(arity == d.m_pred->get_arity()); ptr_vector args; - for(unsigned i=0; iget_domain(i))); + for (unsigned i=0; iget_domain(i))); } - app * lit = m_manager.mk_app(d.m_pred, args.c_ptr()); - app * adn_lit = m_manager.mk_app(adn_pred, args.c_ptr()); + app * lit = m.mk_app(d.m_pred, args.c_ptr()); + app * adn_lit = m.mk_app(adn_pred, args.c_ptr()); app * mag_lit = create_magic_literal(adn_lit); app * tail[] = {lit, mag_lit}; rule * r = m_context.get_rule_manager().mk(adn_lit, 2, tail, 0); - m_rules.push_back(r); + result.add_rule(r); } rule_set * mk_magic_sets::operator()(rule_set const & source) { - SASSERT(!m_context.get_model_converter()); + + if (!m_context.magic_sets_for_queries()) { + return 0; + } + + app * goal_head = source.get_predicate_rules(m_goal)[0]->get_head(); + unsigned init_rule_cnt = source.get_num_rules(); { func_decl_set intentional; - for(unsigned i=0; iget_head()->get_decl()); + for (unsigned i=0; iget_decl(); + intentional.insert(pred); } //now we iterate through all predicates and collect the set of extentional ones const rule_dependencies * deps; rule_dependencies computed_deps(m_context); - if(source.is_closed()) { + if (source.is_closed()) { deps = &source.get_dependencies(); } else { @@ -337,9 +331,9 @@ namespace datalog { } rule_dependencies::iterator it = deps->begin(); rule_dependencies::iterator end = deps->end(); - for(; it!=end; ++it) { + for (; it!=end; ++it) { func_decl * pred = it->m_key; - if(intentional.contains(pred)) { + if (intentional.contains(pred)) { continue; } SASSERT(it->m_value->empty());//extentional predicates have no dependency @@ -347,48 +341,39 @@ namespace datalog { } } - SASSERT(m_rules.empty()); - - app * goal_head = m_goal_rule->get_head(); //adornment goal_adn; //goal_adn.populate(goal_head, ); var_idx_set empty_var_idx_set; adorn_literal(goal_head, empty_var_idx_set); - while(!m_todo.empty()) { + rule_set * result = alloc(rule_set, m_context); + result->inherit_predicates(source); + + while (!m_todo.empty()) { adornment_desc task = m_todo.back(); m_todo.pop_back(); const rule_vector & pred_rules = source.get_predicate_rules(task.m_pred); rule_vector::const_iterator it = pred_rules.begin(); rule_vector::const_iterator end = pred_rules.end(); - for(; it!=end; ++it) { + for (; it != end; ++it) { rule * r = *it; - transform_rule(task.m_adornment, r); + transform_rule(task.m_adornment, r, *result); } - if(!m_context.get_rel_context().get_relation(task.m_pred).empty()) { + if (!m_context.get_rel_context().get_relation(task.m_pred).empty()) { //we need a rule to copy facts that are already in a relation into the adorned //relation (since out intentional predicates can have facts, not only rules) - create_transfer_rule(task); + create_transfer_rule(task, *result); } } app * adn_goal_head = adorn_literal(goal_head, empty_var_idx_set); app * mag_goal_head = create_magic_literal(adn_goal_head); SASSERT(mag_goal_head->is_ground()); - //SASSERT(is_fact(m_manager, mag_goal_head)); - //m_context.add_fact(mag_goal_head); rule * mag_goal_rule = m_context.get_rule_manager().mk(mag_goal_head, 0, 0, 0); - m_rules.push_back(mag_goal_rule); + result->add_rule(mag_goal_rule); rule * back_to_goal_rule = m_context.get_rule_manager().mk(goal_head, 1, &adn_goal_head, 0); - m_rules.push_back(back_to_goal_rule); - - rule_set * result = static_cast(0); - result = alloc(rule_set, m_context); - unsigned fin_rule_cnt = m_rules.size(); - for(unsigned i=0; iadd_rule(m_rules.get(i)); - } + result->add_rule(back_to_goal_rule); return result; } }; diff --git a/src/muz_qe/dl_mk_magic_sets.h b/src/muz_qe/dl_mk_magic_sets.h index 2dc91c7e8..507f6c2bf 100644 --- a/src/muz_qe/dl_mk_magic_sets.h +++ b/src/muz_qe/dl_mk_magic_sets.h @@ -88,21 +88,20 @@ namespace datalog { typedef obj_map pred_adornment_map; typedef obj_map pred2pred; - context & m_context; - ast_manager & m_manager; - rule_ref_vector m_rules; - ast_ref_vector m_pinned; - rule_ref m_goal_rule; + context & m_context; + ast_manager & m; + ast_ref_vector m_pinned; /** \brief Predicates from the original set that appear in a head of a rule */ - func_decl_set m_extentional; + func_decl_set m_extentional; //adornment_set m_processed; vector m_todo; - adornment_map m_adorned_preds; - pred_adornment_map m_adornments; - pred2pred m_magic_preds; + adornment_map m_adorned_preds; + pred_adornment_map m_adornments; + pred2pred m_magic_preds; + func_decl_ref m_goal; void reset(); @@ -110,16 +109,16 @@ namespace datalog { int pop_bound(unsigned_vector & cont, rule * r, const var_idx_set & bound_vars); app * create_magic_literal(app * l); - void create_magic_rules(app * head, unsigned tail_cnt, app * const * tail, bool const* negated); + void create_magic_rules(app * head, unsigned tail_cnt, app * const * tail, bool const* negated, rule_set& result); app * adorn_literal(app * lit, const var_idx_set & bound_vars); - void transform_rule(const adornment & head_adornment, rule * r); - void create_transfer_rule(const adornment_desc & d); + void transform_rule(const adornment & head_adornment, rule * r, rule_set& result); + void create_transfer_rule(const adornment_desc & d, rule_set& result); public: /** \brief Create magic sets rule transformer for \c goal_rule. When applying the transformer, the \c goal_rule must be present in the \c rule_set that is being transformed. */ - mk_magic_sets(context & ctx, rule * goal_rule); + mk_magic_sets(context & ctx, func_decl* goal); rule_set * operator()(rule_set const & source); }; diff --git a/src/muz_qe/dl_mk_partial_equiv.cpp b/src/muz_qe/dl_mk_partial_equiv.cpp index 35f8ff8df..5ba1e71dd 100644 --- a/src/muz_qe/dl_mk_partial_equiv.cpp +++ b/src/muz_qe/dl_mk_partial_equiv.cpp @@ -23,7 +23,7 @@ Revision History: namespace datalog { bool mk_partial_equivalence_transformer::is_symmetry(rule const* r) { - func_decl* p = r->get_head()->get_decl(); + func_decl* p = r->get_decl(); return p->get_arity() == 2 && p->get_domain(0) == p->get_domain(1) && @@ -38,7 +38,7 @@ namespace datalog { bool mk_partial_equivalence_transformer::is_transitivity(rule const* r) { - func_decl* p = r->get_head()->get_decl(); + func_decl* p = r->get_decl(); if (p->get_arity() != 2 || p->get_domain(0) != p->get_domain(1) || r->get_tail_size() != 2 || @@ -144,6 +144,7 @@ namespace datalog { dealloc(res); return 0; } + res->inherit_predicates(source); return res; } diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.cpp b/src/muz_qe/dl_mk_quantifier_abstraction.cpp index d4abb1ffc..68f5bc3a3 100644 --- a/src/muz_qe/dl_mk_quantifier_abstraction.cpp +++ b/src/muz_qe/dl_mk_quantifier_abstraction.cpp @@ -147,9 +147,10 @@ namespace datalog { mk_quantifier_abstraction::~mk_quantifier_abstraction() { } - func_decl* mk_quantifier_abstraction::declare_pred(func_decl* old_p) { + func_decl* mk_quantifier_abstraction::declare_pred(rule_set const& rules, rule_set& dst, func_decl* old_p) { - if (m_ctx.is_output_predicate(old_p)) { + if (rules.is_output_predicate(old_p)) { + dst.inherit_predicate(rules, old_p, old_p); return 0; } @@ -210,8 +211,8 @@ namespace datalog { return new_p; } - app_ref mk_quantifier_abstraction::mk_head(app* p, unsigned idx) { - func_decl* new_p = declare_pred(p->get_decl()); + app_ref mk_quantifier_abstraction::mk_head(rule_set const& rules, rule_set& dst, app* p, unsigned idx) { + func_decl* new_p = declare_pred(rules, dst, p->get_decl()); if (!new_p) { return app_ref(p, m); } @@ -239,9 +240,9 @@ namespace datalog { return app_ref(m.mk_app(new_p, args.size(), args.c_ptr()), m); } - app_ref mk_quantifier_abstraction::mk_tail(app* p) { + app_ref mk_quantifier_abstraction::mk_tail(rule_set const& rules, rule_set& dst, app* p) { func_decl* old_p = p->get_decl(); - func_decl* new_p = declare_pred(old_p); + func_decl* new_p = declare_pred(rules, dst, old_p); if (!new_p) { return app_ref(p, m); } @@ -332,18 +333,17 @@ namespace datalog { unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); for (unsigned j = 0; j < utsz; ++j) { - tail.push_back(mk_tail(r.get_tail(j))); + tail.push_back(mk_tail(source, *result, r.get_tail(j))); } for (unsigned j = utsz; j < tsz; ++j) { tail.push_back(r.get_tail(j)); } - head = mk_head(r.get_head(), cnt); + head = mk_head(source, *result, r.get_head(), cnt); fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), head); rule_ref_vector added_rules(rm); proof_ref pr(m); - rm.mk_rule(fml, pr, added_rules); - result->add_rules(added_rules.size(), added_rules.c_ptr()); - TRACE("dl", added_rules.back()->display(m_ctx, tout);); + rm.mk_rule(fml, pr, *result); + TRACE("dl", result->last()->display(m_ctx, tout);); } // proof converter: proofs are not necessarily preserved using this transformation. diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.h b/src/muz_qe/dl_mk_quantifier_abstraction.h index c7e6c6bb4..0e65c54f7 100644 --- a/src/muz_qe/dl_mk_quantifier_abstraction.h +++ b/src/muz_qe/dl_mk_quantifier_abstraction.h @@ -43,9 +43,9 @@ namespace datalog { obj_map m_old2new; qa_model_converter* m_mc; - func_decl* declare_pred(func_decl* old_p); - app_ref mk_head(app* p, unsigned idx); - app_ref mk_tail(app* p); + func_decl* declare_pred(rule_set const& rules, rule_set& dst, func_decl* old_p); + app_ref mk_head(rule_set const& rules, rule_set& dst, app* p, unsigned idx); + app_ref mk_tail(rule_set const& rules, rule_set& dst, app* p); expr* mk_select(expr* a, unsigned num_args, expr* const* args); public: diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.cpp b/src/muz_qe/dl_mk_quantifier_instantiation.cpp index 1d80d9b77..ddbddca01 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.cpp +++ b/src/muz_qe/dl_mk_quantifier_instantiation.cpp @@ -232,20 +232,20 @@ namespace datalog { fml = m.mk_implies(fml, r.get_head()); TRACE("dl", r.display(m_ctx, tout); tout << mk_pp(fml, m) << "\n";); - rule_ref_vector added_rules(rm); + rule_set added_rules(m_ctx); proof_ref pr(m); rm.mk_rule(fml, pr, added_rules); if (r.get_proof()) { // use def-axiom to encode that new rule is a weakening of the original. proof* p1 = r.get_proof(); - for (unsigned i = 0; i < added_rules.size(); ++i) { - rule* r2 = added_rules[i].get(); + for (unsigned i = 0; i < added_rules.get_num_rules(); ++i) { + rule* r2 = added_rules.get_rule(i); r2->to_formula(fml); pr = m.mk_modus_ponens(m.mk_def_axiom(m.mk_implies(m.get_fact(p1), fml)), p1); r2->set_proof(m, pr); } } - rules.add_rules(added_rules.size(), added_rules.c_ptr()); + rules.add_rules(added_rules); } rule_set * mk_quantifier_instantiation::operator()(rule_set const & source) { @@ -286,7 +286,10 @@ namespace datalog { // model convertion: identity function. - if (!instantiated) { + if (instantiated) { + result->inherit_predicates(source); + } + else { dealloc(result); result = 0; } diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp index 91cfbe3fc..c6ffa1378 100644 --- a/src/muz_qe/dl_mk_rule_inliner.cpp +++ b/src/muz_qe/dl_mk_rule_inliner.cpp @@ -230,10 +230,10 @@ namespace datalog { } } - bool mk_rule_inliner::inlining_allowed(func_decl * pred) + bool mk_rule_inliner::inlining_allowed(rule_set const& source, func_decl * pred) { if (//these three conditions are important for soundness - m_context.is_output_predicate(pred) || + source.is_output_predicate(pred) || m_preds_with_facts.contains(pred) || m_preds_with_neg_occurrence.contains(pred) || //this condition is used for breaking of cycles among inlined rules @@ -260,7 +260,7 @@ namespace datalog { unsigned rcnt = orig.get_num_rules(); for (unsigned i=0; iget_decl())) { + if (inlining_allowed(orig, r->get_decl())) { res->add_rule(r); } } @@ -324,7 +324,7 @@ namespace datalog { unsigned pt_len = r->get_positive_tail_size(); for (unsigned ti = 0; tiget_decl(ti); - if (!inlining_allowed(tail_pred)) { + if (!inlining_allowed(orig, tail_pred)) { continue; } unsigned tail_pred_head_cnt = m_head_pred_ctr.get(tail_pred); @@ -359,7 +359,7 @@ namespace datalog { func_decl * head_pred = r->get_decl(); - if (inlining_allowed(head_pred)) { + if (inlining_allowed(orig, head_pred)) { //we have already processed inlined rules continue; } @@ -368,7 +368,7 @@ namespace datalog { unsigned pt_len = r->get_positive_tail_size(); for (unsigned ti = 0; tiget_decl(ti); - if (!inlining_allowed(pred)) { + if (!inlining_allowed(orig, pred)) { continue; } if (m_head_pred_ctr.get(pred)<=1) { @@ -417,14 +417,14 @@ namespace datalog { const rule_vector& pred_rules = candidate_inlined_set->get_predicate_rules(pred); rule_vector::const_iterator iend = pred_rules.end(); for (rule_vector::const_iterator iit = pred_rules.begin(); iit!=iend; ++iit) { - transform_rule(*iit, m_inlined_rules); + transform_rule(orig, *iit, m_inlined_rules); } } TRACE("dl", tout << "inlined rules after mutual inlining:\n" << m_inlined_rules; ); } - bool mk_rule_inliner::transform_rule(rule * r0, rule_set& tgt) { + bool mk_rule_inliner::transform_rule(rule_set const& orig, rule * r0, rule_set& tgt) { bool modified = false; rule_ref_vector todo(m_rm); todo.push_back(r0); @@ -436,7 +436,7 @@ namespace datalog { unsigned i = 0; - for (; i < pt_len && !inlining_allowed(r->get_decl(i)); ++i) {}; + for (; i < pt_len && !inlining_allowed(orig, r->get_decl(i)); ++i) {}; SASSERT(!has_quantifier(*r.get())); @@ -478,12 +478,12 @@ namespace datalog { // this relation through inlining, // so we don't add its rules to the result - something_done |= !inlining_allowed(pred) && transform_rule(r, tgt); + something_done |= !inlining_allowed(orig, pred) && transform_rule(orig, r, tgt); } if (something_done && m_mc) { for (rule_set::iterator rit = orig.begin(); rit!=rend; ++rit) { - if (inlining_allowed((*rit)->get_decl())) { + if (inlining_allowed(orig, (*rit)->get_decl())) { datalog::del_rule(m_mc, **rit); } } @@ -676,7 +676,7 @@ namespace datalog { m_head_index.insert(head); m_pinned.push_back(r); - if (m_context.is_output_predicate(headd) || + if (m_context.get_rules().is_output_predicate(headd) || m_preds_with_facts.contains(headd)) { can_remove.set(i, false); TRACE("dl", output_predicate(m_context, head, tout << "cannot remove: " << i << " "); tout << "\n";); @@ -692,7 +692,7 @@ namespace datalog { tl_sz == 1 && r->get_positive_tail_size() == 1 && !m_preds_with_facts.contains(r->get_decl(0)) - && !m_context.is_output_predicate(r->get_decl(0)); + && !m_context.get_rules().is_output_predicate(r->get_decl(0)); can_expand.set(i, can_exp); } @@ -883,6 +883,7 @@ namespace datalog { res = 0; } else { + res->inherit_predicates(source); m_context.add_model_converter(hsmc.get()); } diff --git a/src/muz_qe/dl_mk_rule_inliner.h b/src/muz_qe/dl_mk_rule_inliner.h index 5ef8db7eb..bec788ffe 100644 --- a/src/muz_qe/dl_mk_rule_inliner.h +++ b/src/muz_qe/dl_mk_rule_inliner.h @@ -129,7 +129,7 @@ namespace datalog { bool try_to_inline_rule(rule& tgt, rule& src, unsigned tail_index, rule_ref& res); - bool inlining_allowed(func_decl * pred); + bool inlining_allowed(rule_set const& orig, func_decl * pred); void count_pred_occurrences(rule_set const & orig); @@ -143,7 +143,7 @@ namespace datalog { bool forbid_multiple_multipliers(const rule_set & orig, rule_set const & proposed_inlined_rules); /** Return true if the rule was modified */ - bool transform_rule(rule * r, rule_set& tgt); + bool transform_rule(rule_set const& orig, rule * r, rule_set& tgt); /** Return true if some transformation was performed */ bool transform_rules(const rule_set & orig, rule_set & tgt); diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index 9868c82f6..0e101eb68 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -24,15 +24,15 @@ Revision History: namespace datalog { mk_similarity_compressor::mk_similarity_compressor(context & ctx, unsigned threshold_count) : - plugin(5000), - m_context(ctx), - m_manager(ctx.get_manager()), - m_threshold_count(threshold_count), - m_result_rules(ctx.get_rule_manager()), - m_pinned(m_manager) { + plugin(5000), + m_context(ctx), + m_manager(ctx.get_manager()), + m_threshold_count(threshold_count), + m_result_rules(ctx.get_rule_manager()), + m_pinned(m_manager) { SASSERT(threshold_count>1); } - + void mk_similarity_compressor::reset() { m_rules.reset(); m_result_rules.reset(); @@ -43,7 +43,7 @@ namespace datalog { Allows to traverse head and positive tails in a single for loop starting from -1 */ app * get_by_tail_index(rule * r, int idx) { - if(idx==-1) { + if (idx == -1) { return r->get_head(); } SASSERT(idx(r->get_positive_tail_size())); @@ -59,15 +59,18 @@ namespace datalog { SASSERT(t1->get_num_args()==t2->get_num_args()); int res; unsigned n = t1->get_num_args(); - for(unsigned i=0; iget_arg(i); expr * a2 = t2->get_arg(i); - res = aux_compare(is_var(a1), is_var(a2)); - if(res!=0) { return res; } - if(is_var(a1)) { + if (res != 0) { + return res; + } + if (is_var(a1)) { res = aux_compare(to_var(a1)->get_idx(), to_var(a2)->get_idx()); - if(res!=0) { return res; } + if (res != 0) { + return res; + } } } return 0; @@ -77,16 +80,16 @@ namespace datalog { SASSERT(t1->get_num_args()==t2->get_num_args()); int res; unsigned n = t1->get_num_args(); - for(unsigned i=0; iget_arg(i))) { - SASSERT(t1->get_arg(i)==t2->get_arg(i)); + for (unsigned i=0; iget_arg(i))) { + SASSERT(t1->get_arg(i) == t2->get_arg(i)); continue; } - if((skip_countdown--)==0) { + if ((skip_countdown--) == 0) { continue; } res = aux_compare(t1->get_arg(i), t2->get_arg(i)); - if(res!=0) { return res; } + if (res!=0) { return res; } } return 0; } @@ -100,26 +103,26 @@ namespace datalog { */ int rough_compare(rule * r1, rule * r2) { int res = aux_compare(r1->get_tail_size(), r2->get_tail_size()); - if(res!=0) { return res; } + if (res!=0) { return res; } res = aux_compare(r1->get_uninterpreted_tail_size(), r2->get_uninterpreted_tail_size()); - if(res!=0) { return res; } + if (res!=0) { return res; } res = aux_compare(r1->get_positive_tail_size(), r2->get_positive_tail_size()); - if(res!=0) { return res; } + if (res!=0) { return res; } int pos_tail_sz = r1->get_positive_tail_size(); - for(int i=-1; iget_decl(), t2->get_decl()); - if(res!=0) { return res; } + if (res!=0) { return res; } res = compare_var_args(t1, t2); - if(res!=0) { return res; } + if (res!=0) { return res; } } unsigned tail_sz = r1->get_tail_size(); - for(unsigned i=pos_tail_sz; iget_tail(i), r2->get_tail(i)); - if(res!=0) { return res; } + if (res!=0) { return res; } } return 0; @@ -132,9 +135,9 @@ namespace datalog { int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) { SASSERT(rough_compare(r1, r2)==0); int pos_tail_sz = r1->get_positive_tail_size(); - for(int i=-1; iget_num_args(); - for(unsigned i=0; iget_arg(i))) { + for (unsigned i=0; iget_arg(i))) { continue; } res.push_back(const_info(tail_index, i)); @@ -178,7 +181,7 @@ namespace datalog { void collect_const_indexes(rule * r, info_vector & res) { collect_const_indexes(r->get_head(), -1, res); unsigned pos_tail_sz = r->get_positive_tail_size(); - for(unsigned i=0; iget_tail(i), i, res); } } @@ -187,9 +190,9 @@ namespace datalog { void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) { unsigned const_cnt = const_infos.size(); tgt.reset(); - for(unsigned i=0; iget_arg(const_infos[i].arg_index())); - if(vals[i]!=val) { + if (vals[i]!=val) { vals[i] = 0; } } } unsigned removed_cnt = 0; - for(unsigned i=0; i possible_parents(const_cnt); - for(unsigned i=1; iget_head()->get_num_args() - count_variable_arguments(r->get_head()); unsigned pos_tail_sz = r->get_positive_tail_size(); - for(unsigned i=0; iget_tail(i)->get_num_args() - count_variable_arguments(r->get_tail(i)); } return res; @@ -313,7 +316,7 @@ namespace datalog { bool initial_comparator(rule * r1, rule * r2) { int res = rough_compare(r1, r2); - if(res!=0) { return res>0; } + if (res!=0) { return res>0; } return total_compare(r1, r2)>0; } @@ -348,7 +351,7 @@ namespace datalog { ptr_vector aux_domain; collect_orphan_sorts(r, const_infos, aux_domain); - func_decl* head_pred = r->get_head()->get_decl(); + func_decl* head_pred = r->get_decl(); symbol const& name_prefix = head_pred->get_name(); std::string name_suffix = "sc_" + to_string(const_cnt); func_decl * aux_pred = m_context.mk_fresh_head_predicate(name_prefix, symbol(name_suffix.c_str()), @@ -357,7 +360,7 @@ namespace datalog { relation_fact val_fact(m_manager, const_cnt); rule_vector::iterator it = first; - for(; it!=after_last; ++it) { + for (; it!=after_last; ++it) { collect_orphan_consts(*it, const_infos, val_fact); m_context.add_fact(aux_pred, val_fact); } @@ -367,7 +370,7 @@ namespace datalog { ptr_vector new_tail; svector new_negs; unsigned tail_sz = r->get_tail_size(); - for(unsigned i=0; iget_tail(i)); new_negs.push_back(r->is_neg_tail(i)); } @@ -375,7 +378,7 @@ namespace datalog { rule_counter ctr; ctr.count_rule_vars(m_manager, r); unsigned max_var_idx, new_var_idx_base; - if(ctr.get_max_positive(max_var_idx)) { + if (ctr.get_max_positive(max_var_idx)) { new_var_idx_base = max_var_idx+1; } else { @@ -387,15 +390,15 @@ namespace datalog { unsigned aux_column_index = 0; - for(unsigned i=0; i mod_args(mod_tail->get_num_args(), mod_tail->get_args()); - for(; im_threshold_count) { + if (it==after_last || !comparator.eq(*prev, *it)) { + if (grp_size>m_threshold_count) { merge_class(grp_begin, it); //group was processed, so we remove it from the class - if(it==after_last) { + if (it==after_last) { after_last=grp_begin; it=after_last; } @@ -484,9 +487,9 @@ namespace datalog { //TODO: compress also rules with pairs (or tuples) of equal constants #if 1 - if(const_cnt>0) { + if (const_cnt>0) { unsigned rule_cnt = static_cast(after_last-first); - if(rule_cnt>m_threshold_count) { + if (rule_cnt>m_threshold_count) { merge_class(first, after_last); return; } @@ -495,7 +498,7 @@ namespace datalog { //put rules which weren't merged into result rule_vector::iterator it = first; - for(; it!=after_last; ++it) { + for (; it!=after_last; ++it) { m_result_rules.push_back(*it); } } @@ -505,7 +508,7 @@ namespace datalog { m_modified = false; unsigned init_rule_cnt = source.get_num_rules(); SASSERT(m_rules.empty()); - for(unsigned i=0; i(0); - if(m_modified) { + if (m_modified) { result = alloc(rule_set, m_context); unsigned fin_rule_cnt = m_result_rules.size(); - for(unsigned i=0; iadd_rule(m_result_rules.get(i)); } + result->inherit_predicates(source); } reset(); return result; diff --git a/src/muz_qe/dl_mk_simple_joins.cpp b/src/muz_qe/dl_mk_simple_joins.cpp index 3a3f96acf..2fec78066 100644 --- a/src/muz_qe/dl_mk_simple_joins.cpp +++ b/src/muz_qe/dl_mk_simple_joins.cpp @@ -89,7 +89,7 @@ namespace datalog { m_consumers++; } if(m_stratified) { - unsigned head_stratum = pl.get_stratum(r->get_head()->get_decl()); + unsigned head_stratum = pl.get_stratum(r->get_decl()); SASSERT(head_stratum>=m_src_stratum); if(head_stratum==m_src_stratum) { m_stratified = false; @@ -383,7 +383,7 @@ namespace datalog { rule * one_parent = inf.m_rules.back(); - func_decl* parent_head = one_parent->get_head()->get_decl(); + func_decl* parent_head = one_parent->get_decl(); const char * one_parent_name = parent_head->get_name().bare_str(); std::string parent_name; if(inf.m_rules.size()>1) { @@ -714,13 +714,14 @@ namespace datalog { m_context.get_rule_manager().mk_rule_asserted_proof(*m_introduced_rules.back()); m_introduced_rules.pop_back(); } + result->inherit_predicates(source); return result; } }; rule_set * mk_simple_joins::operator()(rule_set const & source) { rule_set rs_aux_copy(m_context); - rs_aux_copy.add_rules(source); + rs_aux_copy.replace_rules(source); if(!rs_aux_copy.is_closed()) { rs_aux_copy.close(); } diff --git a/src/muz_qe/dl_mk_slice.cpp b/src/muz_qe/dl_mk_slice.cpp index c98d6503e..21c3486b3 100644 --- a/src/muz_qe/dl_mk_slice.cpp +++ b/src/muz_qe/dl_mk_slice.cpp @@ -703,7 +703,7 @@ namespace datalog { m_pinned.reset(); } - void mk_slice::declare_predicates() { + void mk_slice::declare_predicates(rule_set const& src, rule_set& dst) { obj_map::iterator it = m_sliceable.begin(), end = m_sliceable.end(); ptr_vector domain; func_decl* f; @@ -720,6 +720,7 @@ namespace datalog { f = m_ctx.mk_fresh_head_predicate(p->get_name(), symbol("slice"), domain.size(), domain.c_ptr(), p); m_pinned.push_back(f); m_predicates.insert(p, f); + dst.inherit_predicate(src, p, f); if (m_mc) { m_mc->add_predicate(p, f); } @@ -820,13 +821,14 @@ namespace datalog { m_mc = smc.get(); reset(); saturate(src); - declare_predicates(); + rule_set* result = alloc(rule_set, m_ctx); + declare_predicates(src, *result); if (m_predicates.empty()) { // nothing could be sliced. + dealloc(result); return 0; } TRACE("dl", display(tout);); - rule_set* result = alloc(rule_set, m_ctx); update_rules(src, *result); TRACE("dl", result->display(tout);); if (m_mc) { diff --git a/src/muz_qe/dl_mk_slice.h b/src/muz_qe/dl_mk_slice.h index 1b4312e77..aedc1feb0 100644 --- a/src/muz_qe/dl_mk_slice.h +++ b/src/muz_qe/dl_mk_slice.h @@ -83,7 +83,7 @@ namespace datalog { expr_ref_vector get_tail_conjs(rule const& r); - void declare_predicates(); + void declare_predicates(rule_set const& src, rule_set& dst); bool rule_updated(rule const& r); diff --git a/src/muz_qe/dl_mk_subsumption_checker.cpp b/src/muz_qe/dl_mk_subsumption_checker.cpp index fb55a377c..f50bd104c 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.cpp +++ b/src/muz_qe/dl_mk_subsumption_checker.cpp @@ -21,11 +21,8 @@ Revision History: #include #include"ast_pp.h" - #include "rewriter.h" #include "rewriter_def.h" - - #include"dl_mk_subsumption_checker.h" #include"dl_table_relation.h" @@ -82,7 +79,7 @@ namespace datalog { void mk_subsumption_checker::on_discovered_total_relation(func_decl * pred, rule * r) { //this should be rule marking a new relation as total SASSERT(!m_total_relations.contains(pred)); - SASSERT(!r || pred==r->get_head()->get_decl()); + SASSERT(!r || pred==r->get_decl()); SASSERT(!r || is_total_rule(r)); m_total_relations.insert(pred); @@ -102,7 +99,7 @@ namespace datalog { rule_set::iterator rend = rules.end(); for(rule_set::iterator rit = rules.begin(); rit!=rend; ++rit) { rule * r = *rit; - func_decl * head_pred = r->get_head()->get_decl(); + func_decl * head_pred = r->get_decl(); if(is_total_rule(r) && !m_total_relations.contains(head_pred)) { on_discovered_total_relation(head_pred, r); new_discovered = true; @@ -196,10 +193,10 @@ namespace datalog { for(rule_set::iterator rit = rbegin; rit!=rend; ++rit) { rule * r = *rit; - func_decl * head_pred = r->get_head()->get_decl(); + func_decl * head_pred = r->get_decl(); if(m_total_relations.contains(head_pred)) { - if(!m_context.is_output_predicate(head_pred) || + if(!orig.is_output_predicate(head_pred) || total_relations_with_included_rules.contains(head_pred)) { //We just skip definitions of total non-output relations as //we'll eliminate them from the problem. @@ -217,7 +214,7 @@ namespace datalog { modified = true; } tgt.add_rule(totality_rule); - SASSERT(totality_rule->get_head()->get_decl()==head_pred); + SASSERT(totality_rule->get_decl()==head_pred); } else { modified = true; @@ -250,24 +247,23 @@ namespace datalog { return modified; } - void mk_subsumption_checker::scan_for_relations_total_due_to_facts() { + void mk_subsumption_checker::scan_for_relations_total_due_to_facts(rule_set const& source) { relation_manager& rm = m_context.get_rel_context().get_rmanager(); - decl_set candidate_preds; - m_context.collect_predicates(candidate_preds); + decl_set const& candidate_preds = m_context.get_predicates(); decl_set::iterator end = candidate_preds.end(); for(decl_set::iterator it = candidate_preds.begin(); it!=end; ++it) { func_decl * pred = *it; - if(m_total_relations.contains(pred)) { continue; } //already total + if (m_total_relations.contains(pred)) { continue; } //already total relation_base * rel = rm.try_get_relation(pred); - if(!rel || !rel->knows_exact_size()) { continue; } + if (!rel || !rel->knows_exact_size()) { continue; } unsigned arity = pred->get_arity(); - if(arity>30) { continue; } + if (arity > 30) { continue; } //for now we only check booleans domains for(unsigned i=0; iget_head()->get_decl(); + func_decl * pred = r->get_decl(); if(r->get_tail_size()!=0) { continue; } @@ -337,7 +333,7 @@ namespace datalog { m_have_new_total_rule = false; collect_ground_unconditional_rule_heads(source); - scan_for_relations_total_due_to_facts(); + scan_for_relations_total_due_to_facts(source); scan_for_total_rules(source); m_have_new_total_rule = false; @@ -361,6 +357,7 @@ namespace datalog { transform_rules(*old, *res); dealloc(old); } + res->inherit_predicates(source); return res; } diff --git a/src/muz_qe/dl_mk_subsumption_checker.h b/src/muz_qe/dl_mk_subsumption_checker.h index 59904b3ef..da42e4202 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.h +++ b/src/muz_qe/dl_mk_subsumption_checker.h @@ -64,8 +64,8 @@ namespace datalog { /** Function to be called when a new total relation is discovered */ void on_discovered_total_relation(func_decl * pred, rule * r); - void scan_for_total_rules(const rule_set & rules); - void scan_for_relations_total_due_to_facts(); + void scan_for_total_rules(rule_set const& rules); + void scan_for_relations_total_due_to_facts(rule_set const& rules); void collect_ground_unconditional_rule_heads(const rule_set & rules); diff --git a/src/muz_qe/dl_mk_unbound_compressor.cpp b/src/muz_qe/dl_mk_unbound_compressor.cpp index 40926c2a8..eec0b991d 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.cpp +++ b/src/muz_qe/dl_mk_unbound_compressor.cpp @@ -26,9 +26,9 @@ namespace datalog { mk_unbound_compressor::mk_unbound_compressor(context & ctx) : plugin(500), m_context(ctx), - m_manager(ctx.get_manager()), + m(ctx.get_manager()), m_rules(ctx.get_rule_manager()), - m_pinned(m_manager) { + m_pinned(m) { } void mk_unbound_compressor::reset() { @@ -48,7 +48,7 @@ namespace datalog { unsigned var_idx = to_var(head_arg)->get_idx(); var_idx_set tail_vars; - collect_tail_vars(m_manager, r, tail_vars); + collect_tail_vars(m, r, tail_vars); return tail_vars.contains(var_idx); } @@ -81,14 +81,14 @@ namespace datalog { m_map.insert(ci, cpred); } - void mk_unbound_compressor::detect_tasks(unsigned rule_index) { + void mk_unbound_compressor::detect_tasks(rule_set const& source, unsigned rule_index) { rule * r = m_rules.get(rule_index); var_idx_set tail_vars; - collect_tail_vars(m_manager, r, tail_vars); + collect_tail_vars(m, r, tail_vars); app * head = r->get_head(); func_decl * head_pred = head->get_decl(); - if (m_context.is_output_predicate(head_pred)) { + if (source.is_output_predicate(head_pred)) { //we don't compress output predicates return; } @@ -96,7 +96,7 @@ namespace datalog { unsigned n = head_pred->get_arity(); var_counter head_var_counter; - head_var_counter.count_vars(m_manager, head, 1); + head_var_counter.count_vars(m, head, 1); for (unsigned i=0; iget_arg(i); @@ -118,18 +118,18 @@ namespace datalog { } } - void mk_unbound_compressor::try_compress(unsigned rule_index) { + void mk_unbound_compressor::try_compress(rule_set const& source, unsigned rule_index) { start: rule * r = m_rules.get(rule_index); var_idx_set tail_vars; - collect_tail_vars(m_manager, r, tail_vars); + collect_tail_vars(m, r, tail_vars); app * head = r->get_head(); func_decl * head_pred = head->get_decl(); unsigned head_arity = head_pred->get_arity(); var_counter head_var_counter; - head_var_counter.count_vars(m_manager, head); + head_var_counter.count_vars(m, head); unsigned arg_index; for (arg_index = 0; arg_index < head_arity; arg_index++) { @@ -163,13 +163,13 @@ namespace datalog { } } - app_ref chead(m_manager.mk_app(cpred, head_arity-1, cargs.c_ptr()), m_manager); + app_ref chead(m.mk_app(cpred, head_arity-1, cargs.c_ptr()), m); if (r->get_tail_size()==0 && m_context.get_rule_manager().is_fact(chead)) { m_non_empty_rels.insert(cpred); m_context.add_fact(chead); //remove the rule that became fact by placing the last rule on its place - m_head_occurrence_ctr.dec(m_rules.get(rule_index)->get_head()->get_decl()); + m_head_occurrence_ctr.dec(m_rules.get(rule_index)->get_decl()); m_rules.set(rule_index, m_rules.get(m_rules.size()-1)); m_rules.shrink(m_rules.size()-1); //since we moved the last rule to rule_index, we have to try to compress it as well @@ -181,10 +181,10 @@ namespace datalog { rule_ref new_rule(m_context.get_rule_manager().mk(r, chead), m_context.get_rule_manager()); new_rule->set_accounting_parent_object(m_context, r); - m_head_occurrence_ctr.dec(m_rules.get(rule_index)->get_head()->get_decl()); + m_head_occurrence_ctr.dec(m_rules.get(rule_index)->get_decl()); m_rules.set(rule_index, new_rule); - m_head_occurrence_ctr.inc(m_rules.get(rule_index)->get_head()->get_decl()); - detect_tasks(rule_index); + m_head_occurrence_ctr.inc(m_rules.get(rule_index)->get_decl()); + detect_tasks(source, rule_index); } m_modified = true; @@ -205,10 +205,10 @@ namespace datalog { } } SASSERT(dtail_args.size()==dtail_pred->get_arity()); - app_ref dtail(m_manager.mk_app(dtail_pred, dtail_args.size(), dtail_args.c_ptr()), m_manager); + app_ref dtail(m.mk_app(dtail_pred, dtail_args.size(), dtail_args.c_ptr()), m); svector tails_negated; - app_ref_vector tails(m_manager); + app_ref_vector tails(m); unsigned tail_len = r->get_tail_size(); for (unsigned i=0; iis_neg_tail(i)); @@ -232,17 +232,17 @@ namespace datalog { m_context.get_rule_manager().fix_unbound_vars(res, true); } - void mk_unbound_compressor::add_decompression_rule(rule * r, unsigned tail_index, unsigned arg_index) { + void mk_unbound_compressor::add_decompression_rule(rule_set const& source, rule * r, unsigned tail_index, unsigned arg_index) { rule_ref new_rule(m_context.get_rule_manager()); mk_decompression_rule(r, tail_index, arg_index, new_rule); unsigned new_rule_index = m_rules.size(); m_rules.push_back(new_rule); m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *new_rule.get()); - m_head_occurrence_ctr.inc(new_rule->get_head()->get_decl()); + m_head_occurrence_ctr.inc(new_rule->get_decl()); - detect_tasks(new_rule_index); + detect_tasks(source, new_rule_index); m_modified = true; @@ -258,7 +258,7 @@ namespace datalog { //P:- R1(x), S1(x) } - void mk_unbound_compressor::replace_by_decompression_rule(unsigned rule_index, unsigned tail_index, unsigned arg_index) + void mk_unbound_compressor::replace_by_decompression_rule(rule_set const& source, unsigned rule_index, unsigned tail_index, unsigned arg_index) { rule * r = m_rules.get(rule_index); @@ -269,12 +269,12 @@ namespace datalog { //we don't update the m_head_occurrence_ctr because the head predicate doesn't change - detect_tasks(rule_index); + detect_tasks(source, rule_index); m_modified = true; } - void mk_unbound_compressor::add_decompression_rules(unsigned rule_index) { + void mk_unbound_compressor::add_decompression_rules(rule_set const& source, unsigned rule_index) { unsigned_vector compressed_tail_pred_arg_indexes; @@ -306,11 +306,11 @@ namespace datalog { m_head_occurrence_ctr.get(t_pred)==0; if (can_remove_orig_rule || is_negated_predicate) { - replace_by_decompression_rule(rule_index, tail_index, arg_index); + replace_by_decompression_rule(source, rule_index, tail_index, arg_index); orig_rule_replaced = true; } else { - add_decompression_rule(r, tail_index, arg_index); + add_decompression_rule(source, r, tail_index, arg_index); } } if (orig_rule_replaced) { @@ -345,11 +345,11 @@ namespace datalog { for (unsigned i=0; iget_head()->get_decl()); + m_head_occurrence_ctr.inc(r->get_decl()); } for (unsigned i=0; iadd_rule(m_rules.get(i)); } + result->inherit_predicates(source); } reset(); return result; diff --git a/src/muz_qe/dl_mk_unbound_compressor.h b/src/muz_qe/dl_mk_unbound_compressor.h index cad953783..4e56a74fc 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.h +++ b/src/muz_qe/dl_mk_unbound_compressor.h @@ -50,8 +50,8 @@ namespace datalog { typedef hashtable > in_progress_table; typedef svector todo_stack; - context & m_context; - ast_manager & m_manager; + context & m_context; + ast_manager & m; rule_ref_vector m_rules; bool m_modified; todo_stack m_todo; @@ -71,13 +71,13 @@ namespace datalog { bool is_unbound_argument(rule * r, unsigned head_index); bool has_unbound_head_var(rule * r); - void detect_tasks(unsigned rule_index); + void detect_tasks(rule_set const& source, unsigned rule_index); void add_task(func_decl * pred, unsigned arg_index); - void try_compress(unsigned rule_index); - void add_decompression_rules(unsigned rule_index); + void try_compress(rule_set const& source, unsigned rule_index); + void add_decompression_rules(rule_set const& source, unsigned rule_index); void mk_decompression_rule(rule * r, unsigned tail_index, unsigned arg_index, rule_ref& res); - void add_decompression_rule(rule * r, unsigned tail_index, unsigned arg_index); - void replace_by_decompression_rule(unsigned rule_index, unsigned tail_index, unsigned arg_index); + void add_decompression_rule(rule_set const& source, rule * r, unsigned tail_index, unsigned arg_index); + void replace_by_decompression_rule(rule_set const& source, unsigned rule_index, unsigned tail_index, unsigned arg_index); void reset(); public: mk_unbound_compressor(context & ctx); diff --git a/src/muz_qe/dl_mk_unfold.cpp b/src/muz_qe/dl_mk_unfold.cpp index dfbd87122..a9357f88a 100644 --- a/src/muz_qe/dl_mk_unfold.cpp +++ b/src/muz_qe/dl_mk_unfold.cpp @@ -56,6 +56,7 @@ namespace datalog { for (; it != end; ++it) { expand_tail(**it, 0, source, *rules); } + rules->inherit_predicates(source); return rules; } diff --git a/src/muz_qe/dl_relation_manager.cpp b/src/muz_qe/dl_relation_manager.cpp index e001dd1a4..d92ae7dcc 100644 --- a/src/muz_qe/dl_relation_manager.cpp +++ b/src/muz_qe/dl_relation_manager.cpp @@ -124,14 +124,6 @@ namespace datalog { e->get_data().m_value = rel; } - void relation_manager::collect_predicates(decl_set & res) const { - relation_map::iterator it = m_relations.begin(); - relation_map::iterator end = m_relations.end(); - for(; it!=end; ++it) { - res.insert(it->m_key); - } - } - void relation_manager::collect_non_empty_predicates(decl_set & res) const { relation_map::iterator it = m_relations.begin(); relation_map::iterator end = m_relations.end(); @@ -539,8 +531,8 @@ namespace datalog { } } - void relation_manager::display_output_tables(std::ostream & out) const { - const decl_set & output_preds = get_context().get_output_predicates(); + void relation_manager::display_output_tables(rule_set const& rules, std::ostream & out) const { + const decl_set & output_preds = rules.get_output_predicates(); decl_set::iterator it=output_preds.begin(); decl_set::iterator end=output_preds.end(); for(; it!=end; ++it) { diff --git a/src/muz_qe/dl_relation_manager.h b/src/muz_qe/dl_relation_manager.h index 6b350642e..8715e5cff 100644 --- a/src/muz_qe/dl_relation_manager.h +++ b/src/muz_qe/dl_relation_manager.h @@ -22,7 +22,6 @@ Revision History: #include"map.h" #include"vector.h" - #include"dl_base.h" namespace datalog { @@ -35,8 +34,8 @@ namespace datalog { class finite_product_relation_plugin; class sieve_relation; class sieve_relation_plugin; + class rule_set; - typedef hashtable, ptr_eq > decl_set; class relation_manager { class empty_signature_relation_join_fn; @@ -153,7 +152,6 @@ namespace datalog { } } - void collect_predicates(decl_set & res) const; void collect_non_empty_predicates(decl_set & res) const; void restrict_predicates(const decl_set & preds); @@ -595,7 +593,7 @@ namespace datalog { void display(std::ostream & out) const; void display_relation_sizes(std::ostream & out) const; - void display_output_tables(std::ostream & out) const; + void display_output_tables(rule_set const& rules, std::ostream & out) const; private: relation_intersection_filter_fn * try_mk_default_filter_by_intersection_fn(const relation_base & t, diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index b7d6d9fae..92f504bcc 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -50,10 +50,6 @@ namespace datalog { : m(ctx.get_manager()), m_ctx(ctx) {} - bool rule_manager::is_predicate(func_decl * f) const { - return m_ctx.is_predicate(f); - } - void rule_manager::inc_ref(rule * r) { if (r) { SASSERT(r->m_ref_cnt != UINT_MAX); @@ -102,7 +98,7 @@ namespace datalog { } - void rule_manager::mk_rule(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name) { + void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) { scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); proof_ref pr(p, m); expr_ref fml1(m); @@ -111,13 +107,13 @@ namespace datalog { pr = m.mk_asserted(fml1); } remove_labels(fml1, pr); - mk_rule_core_new(fml1, pr, rules, name); + mk_rule_core(fml1, pr, rules, name); } void rule_manager::mk_negations(app_ref_vector& body, svector& is_negated) { for (unsigned i = 0; i < body.size(); ++i) { expr* e = body[i].get(), *e1; - if (m.is_not(e, e1) && is_predicate(e1)) { + if (m.is_not(e, e1) && m_ctx.is_predicate(e1)) { check_app(e1); body[i] = to_app(e1); is_negated.push_back(true); @@ -128,7 +124,7 @@ namespace datalog { } } - void rule_manager::mk_rule_core_new(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name) { + void rule_manager::mk_rule_core(expr* fml, proof* p, rule_set& rules, symbol const& name) { hnf h(m); expr_ref_vector fmls(m); proof_ref_vector prs(m); @@ -138,11 +134,11 @@ namespace datalog { m_ctx.register_predicate(h.get_fresh_predicates()[i], false); } for (unsigned i = 0; i < fmls.size(); ++i) { - mk_rule_core2(fmls[i].get(), prs[i].get(), rules, name); + mk_horn_rule(fmls[i].get(), prs[i].get(), rules, name); } } - void rule_manager::mk_rule_core2(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name) { + void rule_manager::mk_horn_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) { app_ref_vector body(m); app_ref head(m); @@ -189,7 +185,7 @@ namespace datalog { } r->set_proof(m, p); } - rules.push_back(r); + rules.add_rule(r); } unsigned rule_manager::extract_horn(expr* fml, app_ref_vector& body, app_ref& head) { @@ -224,7 +220,7 @@ namespace datalog { } - void rule_manager::mk_query(expr* query, func_decl_ref& qpred, rule_ref_vector& query_rules, rule_ref& query_rule) { + func_decl* rule_manager::mk_query(expr* query, rule_set& rules) { ptr_vector vars; svector names; app_ref_vector body(m); @@ -279,7 +275,9 @@ namespace datalog { } vars.reverse(); names.reverse(); - qpred = m_ctx.mk_fresh_head_predicate(symbol("query"), symbol(), vars.size(), vars.c_ptr(), body_pred); + func_decl* qpred = m_ctx.mk_fresh_head_predicate(symbol("query"), symbol(), vars.size(), vars.c_ptr(), body_pred); + m_ctx.register_predicate(qpred, false); + rules.set_output_predicate(qpred); expr_ref_vector qhead_args(m); for (unsigned i = 0; i < vars.size(); i++) { @@ -297,9 +295,8 @@ namespace datalog { if (m_ctx.generate_proof_trace()) { pr = m.mk_asserted(rule_expr); } - mk_rule(rule_expr, pr, query_rules); - SASSERT(query_rules.size() >= 1); - query_rule = query_rules.back(); + mk_rule(rule_expr, pr, rules); + return qpred; } void rule_manager::bind_variables(expr* fml, bool is_forall, expr_ref& result) { @@ -330,7 +327,7 @@ namespace datalog { return; } expr_ref_vector args(m); - if (!is_predicate(fml)) { + if (!m_ctx.is_predicate(fml)) { return; } for (unsigned i = 0; i < fml->get_num_args(); ++i) { @@ -355,19 +352,19 @@ namespace datalog { } class contains_predicate_proc { - rule_manager const& m; + context const& ctx; public: struct found {}; - contains_predicate_proc(rule_manager const& m): m(m) {} + contains_predicate_proc(context const& ctx): ctx(ctx) {} void operator()(var * n) {} void operator()(quantifier * n) {} void operator()(app* n) { - if (m.is_predicate(n)) throw found(); + if (ctx.is_predicate(n)) throw found(); } }; bool rule_manager::contains_predicate(expr* fml) const { - contains_predicate_proc proc(*this); + contains_predicate_proc proc(m_ctx); try { quick_for_each_expr(proc, fml); } @@ -434,7 +431,7 @@ namespace datalog { bool is_neg = (is_negated != 0 && is_negated[i]); app * curr = tail[i]; - if (is_neg && !is_predicate(curr)) { + if (is_neg && !m_ctx.is_predicate(curr)) { curr = m.mk_not(curr); is_neg = false; } @@ -442,7 +439,7 @@ namespace datalog { has_neg = true; } app * tail_entry = TAG(app *, curr, is_neg); - if (is_predicate(curr)) { + if (m_ctx.is_predicate(curr)) { *uninterp_tail=tail_entry; uninterp_tail++; } @@ -755,7 +752,7 @@ namespace datalog { void rule_manager::check_valid_head(expr * head) const { SASSERT(head); - if (!is_predicate(head)) { + if (!m_ctx.is_predicate(head)) { std::ostringstream out; out << "Illegal head. The head predicate needs to be uninterpreted and registered (as recursive) " << mk_pp(head, m); throw default_exception(out.str()); @@ -966,7 +963,7 @@ namespace datalog { if (is_neg_tail(i)) out << "not "; app * t = get_tail(i); - if (ctx.get_rule_manager().is_predicate(t)) { + if (ctx.is_predicate(t)) { output_predicate(ctx, t, out); } else { diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index 3f535125f..666ddbd50 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -32,6 +32,7 @@ namespace datalog { class rule; class rule_manager; + class rule_set; class table; class context; @@ -74,13 +75,11 @@ namespace datalog { void bind_variables(expr* fml, bool is_forall, expr_ref& result); - void mk_rule_core(expr* fml, rule_ref_vector& rules, symbol const& name); - void mk_negations(app_ref_vector& body, svector& is_negated); - void mk_rule_core_new(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name); + void mk_rule_core(expr* fml, proof* p, rule_set& rules, symbol const& name); - void mk_rule_core2(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name); + void mk_horn_rule(expr* fml, proof* p, rule_set& rules, symbol const& name); static expr_ref mk_implies(app_ref_vector const& body, expr* head); @@ -104,13 +103,13 @@ namespace datalog { The formula is of the form (forall (...) (forall (...) (=> (and ...) head))) */ - void mk_rule(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name = symbol::null); + void mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name = symbol::null); /** \brief Create a Datalog query from an expression. The formula is of the form (exists (...) (exists (...) (and ...)) */ - void mk_query(expr* query, func_decl_ref& query_pred, rule_ref_vector& query_rules, rule_ref& query_rule); + func_decl* mk_query(expr* query, rule_set& rules); /** \brief Create a Datalog rule head :- tail[0], ..., tail[n-1]. @@ -166,11 +165,6 @@ namespace datalog { bool is_fact(app * head) const; - bool is_predicate(func_decl * f) const; - bool is_predicate(expr * e) const { - return is_app(e) && is_predicate(to_app(e)->get_decl()); - } - static bool is_forall(ast_manager& m, expr* e, quantifier*& q); rule_counter& get_counter() { return m_counter; } diff --git a/src/muz_qe/dl_rule_set.cpp b/src/muz_qe/dl_rule_set.cpp index f9ae3620d..b0bcdec89 100644 --- a/src/muz_qe/dl_rule_set.cpp +++ b/src/muz_qe/dl_rule_set.cpp @@ -64,8 +64,7 @@ namespace datalog { reset_dealloc_values(m_data); } - void rule_dependencies::remove_m_data_entry(func_decl * key) - { + void rule_dependencies::remove_m_data_entry(func_decl * key) { item_set * itm_set = m_data.find(key); dealloc(itm_set); m_data.remove(key); @@ -109,7 +108,7 @@ namespace datalog { void rule_dependencies::populate(rule const* r) { TRACE("dl_verbose", tout << r->get_decl()->get_name() << "\n";); m_visited.reset(); - func_decl * d = r->get_head()->get_decl(); + func_decl * d = r->get_decl(); func_decl_set & s = ensure_key(d); for (unsigned i = 0; i < r->get_tail_size(); ++i) { @@ -164,7 +163,7 @@ namespace datalog { } ptr_vector::iterator rit = to_remove.begin(); ptr_vector::iterator rend = to_remove.end(); - for (; rit!=rend; ++rit) { + for (; rit != rend; ++rit) { remove_m_data_entry(*rit); } } @@ -173,7 +172,7 @@ namespace datalog { remove_m_data_entry(itm); iterator pit = begin(); iterator pend = end(); - for (; pit!=pend; ++pit) { + for (; pit != pend; ++pit) { item_set & itms = *pit->get_value(); itms.remove(itm); } @@ -244,7 +243,7 @@ namespace datalog { } curr_index++; } - if (res.size()::iterator it = other.m_orig2pred.begin(); + obj_map::iterator end = other.m_orig2pred.end(); + for (; it != end; ++it) { + m_orig2pred.insert(it->m_key, it->m_value); + m_refs.push_back(it->m_key); + m_refs.push_back(it->m_value); + } + } + { + obj_map::iterator it = other.m_pred2orig.begin(); + obj_map::iterator end = other.m_pred2orig.end(); + for (; it != end; ++it) { + m_pred2orig.insert(it->m_key, it->m_value); + m_refs.push_back(it->m_key); + m_refs.push_back(it->m_value); + } + } + } + + void rule_set::inherit_predicate(rule_set const& other, func_decl* orig, func_decl* pred) { + if (other.is_output_predicate(orig)) { + set_output_predicate(pred); + } + orig = other.get_orig(orig); + m_refs.push_back(pred); + m_refs.push_back(orig); + m_orig2pred.insert(orig, pred); + m_pred2orig.insert(pred, orig); + } + void rule_set::add_rule(rule * r) { TRACE("dl_verbose", r->display(m_context, tout << "add:");); SASSERT(!is_closed()); @@ -329,7 +379,7 @@ namespace datalog { void rule_set::del_rule(rule * r) { TRACE("dl", r->display(m_context, tout << "del:");); - func_decl* d = r->get_head()->get_decl(); + func_decl* d = r->get_decl(); rule_vector* rules = m_head2rules.find(d); #define DEL_VECTOR(_v) \ for (unsigned i = (_v).size(); i > 0; ) { \ @@ -345,32 +395,26 @@ namespace datalog { DEL_VECTOR(m_rules); } - void rule_set::ensure_closed() - { + void rule_set::ensure_closed() { if (!is_closed()) { VERIFY(close()); } } bool rule_set::close() { - SASSERT(!is_closed()); //the rule_set is not already closed - - + SASSERT(!is_closed()); //the rule_set is not already closed m_deps.populate(*this); m_stratifier = alloc(rule_stratifier, m_deps); - if (!stratified_negation()) { m_stratifier = 0; m_deps.reset(); return false; } - return true; } void rule_set::reopen() { SASSERT(is_closed()); - m_stratifier = 0; m_deps.reset(); } @@ -401,18 +445,20 @@ namespace datalog { return true; } - void rule_set::add_rules(const rule_set & src) { - SASSERT(!is_closed()); - unsigned n = src.get_num_rules(); - for (unsigned i=0; iget_predicate_strat(pred); } + void rule_set::split_founded_rules(func_decl_set& founded, func_decl_set& non_founded) { + founded.reset(); + non_founded.reset(); + { + decl2rules::iterator it = begin_grouped_rules(), end = end_grouped_rules(); + for (; it != end; ++it) { + non_founded.insert(it->m_key); + } + } + bool change = true; + while (change) { + change = false; + func_decl_set::iterator it = non_founded.begin(), end = non_founded.end(); + for (; it != end; ++it) { + rule_vector const& rv = get_predicate_rules(*it); + bool found = false; + for (unsigned i = 0; !found && i < rv.size(); ++i) { + rule const& r = *rv[i]; + bool is_founded = true; + for (unsigned j = 0; is_founded && j < r.get_uninterpreted_tail_size(); ++j) { + is_founded = founded.contains(r.get_decl(j)); + } + if (is_founded) { + founded.insert(*it); + non_founded.remove(*it); + change = true; + found = true; + } + } + } + } + } void rule_set::display(std::ostream & out) const { out << "; rule count: " << get_num_rules() << "\n"; @@ -451,17 +529,6 @@ namespace datalog { r->display(m_context, out); } } - -#if 0 //print dependencies - out<<"##\n"; - out< m_stratifier; //!< contains stratifier object iff the rule_set is closed + rule_ref_vector m_rules; //!< all rules + decl2rules m_head2rules; //!< mapping from head symbol to rules. + rule_dependencies m_deps; //!< dependencies + scoped_ptr m_stratifier; //!< contains stratifier object iff the rule_set is closed + func_decl_set m_output_preds; //!< output predicates + obj_map m_orig2pred; + obj_map m_pred2orig; + func_decl_ref_vector m_refs; //sometimes we need to return reference to an empty rule_vector, @@ -184,6 +188,12 @@ namespace datalog { rule_manager & get_rule_manager() const { return const_cast(m_rule_manager); } context& get_context() const { return m_context; } + + void inherit_predicates(rule_set const& other); + void inherit_predicate(rule_set const& other, func_decl* orig, func_decl* pred); + func_decl* get_orig(func_decl* pred) const; + func_decl* get_pred(func_decl* orig) const; + /** \brief Add rule \c r to the rule set. */ @@ -198,7 +208,7 @@ namespace datalog { \brief Add all rules from a different rule_set. */ void add_rules(const rule_set& src); - void add_rules(unsigned sz, rule * const * rules); + void replace_rules(const rule_set& other); /** \brief This method should be invoked after all rules are added to the rule set. @@ -216,11 +226,14 @@ namespace datalog { bool is_closed() const { return m_stratifier != 0; } unsigned get_num_rules() const { return m_rules.size(); } + bool empty() const { return m_rules.size() == 0; } rule * get_rule(unsigned i) const { return m_rules[i]; } + rule * last() const { return m_rules[m_rules.size()-1]; } rule_ref_vector const& get_rules() const { return m_rules; } const rule_vector & get_predicate_rules(func_decl * pred) const; + bool contains(func_decl* pred) const { return m_head2rules.contains(pred); } const rule_stratifier & get_stratifier() const { SASSERT(m_stratifier); @@ -230,9 +243,17 @@ namespace datalog { unsigned get_predicate_strat(func_decl * pred) const; const rule_dependencies & get_dependencies() const { SASSERT(is_closed()); return m_deps; } + // split predicats into founded and non-founded. + void split_founded_rules(func_decl_set& founded, func_decl_set& non_founded); void reset(); + void set_output_predicate(func_decl * pred) { m_refs.push_back(pred); m_output_preds.insert(pred); } + bool is_output_predicate(func_decl * pred) const { return m_output_preds.contains(pred); } + const func_decl_set & get_output_predicates() const { return m_output_preds; } + func_decl* get_output_predicate() const { SASSERT(m_output_preds.size() == 1); return *m_output_preds.begin(); } + + void display(std::ostream & out) const; /** diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index 5cc686052..0cad08cb4 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -80,36 +80,38 @@ namespace datalog { tout<<"init:\n"; rules.display(tout); ); + rule_set* new_rules = alloc(rule_set, rules); plugin_vector::iterator it = m_plugins.begin(); plugin_vector::iterator end = m_plugins.end(); for(; it!=end && !m_context.canceled(); ++it) { plugin & p = **it; - rule_set * new_rules = p(rules); - if (!new_rules) { + rule_set * new_rules1 = p(*new_rules); + if (!new_rules1) { continue; } - if (p.can_destratify_negation()) { - if (!new_rules->is_closed()) { - if (!new_rules->close()) { - warning_msg("a rule transformation skipped because it destratified negation"); - dealloc(new_rules); - continue; - } - } + if (p.can_destratify_negation() && + !new_rules1->is_closed() && + !new_rules1->close()) { + warning_msg("a rule transformation skipped " + "because it destratified negation"); + dealloc(new_rules1); + continue; } modified = true; - rules.reset(); - rules.add_rules(*new_rules); dealloc(new_rules); - rules.ensure_closed(); + new_rules = new_rules1; + new_rules->ensure_closed(); TRACE("dl_rule_transf", tout << typeid(p).name()<<":\n"; - rules.display(tout); + new_rules->display(tout); ); - } + if (modified) { + rules.replace_rules(*new_rules); + } + dealloc(new_rules); return modified; } diff --git a/src/muz_qe/dl_skip_table.cpp b/src/muz_qe/dl_skip_table.cpp deleted file mode 100644 index 28efaabee..000000000 --- a/src/muz_qe/dl_skip_table.cpp +++ /dev/null @@ -1,622 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_skip_table.h - -Abstract: - - - -Author: - - Nikolaj Bjorner (nbjorner) - Leonardo de Moura (leonardo) 2010-10-14 - - -Revision History: - ---*/ - -#ifndef _EXTERNAL_RELEASE - -#include "dl_skip_table.h" -#include "dl_table.h" -#include "dl_context.h" - - -namespace datalog { - - skip_table & skip_table_plugin::get(table_base& r) { - return static_cast(r); - } - - skip_table const & skip_table_plugin::get(table_base const& r) { - return static_cast(r); - } - - table_base * skip_table_plugin::mk_empty(const table_signature & s) { - return alloc(skip_table, *this, s); - } - - skip_table* skip_table_plugin::mk_join( - table_base const& t1, table_base const& t2, table_signature const& result_sig, - unsigned_vector const& cols1, unsigned_vector const& cols2) { - skip_table const& s1 = get(t1); - skip_table const& s2 = get(t2); - imdd_manager& m = s1.get_imdd_manager(); - imdd_ref pr(m); - m.mk_join(s1.get_imdd(), s2.get_imdd(), pr, cols1, cols2); - return alloc(skip_table, s1.get_plugin(), result_sig, pr); - } - - skip_table* skip_table_plugin::mk_join_project( - table_base const& t1, table_base const& t2, table_signature const& result_sig, - unsigned_vector const& cols1, unsigned_vector const& cols2, - unsigned_vector const& proj_cols) { - - skip_table const& s1 = get(t1); - skip_table const& s2 = get(t2); - imdd_manager& m = s1.get_imdd_manager(); - imdd_ref pr(m); - m.mk_join_project(s1.get_imdd(), s2.get_imdd(), pr, cols1, cols2, proj_cols); - return alloc(skip_table, s1.get_plugin(), result_sig, pr); - } - - class skip_table_plugin::join_fn : public convenient_table_join_fn { - public: - join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2): - convenient_table_join_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2) { - } - - virtual table_base* operator()(const table_base & t1, const table_base & t2) { - return skip_table_plugin::mk_join(t1, t2, get_result_signature(), m_cols1, m_cols2); - } - }; - - table_join_fn * skip_table_plugin::mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (check_kind(t1) && check_kind(t2)) { - return alloc(join_fn, t1, t2, col_cnt, cols1, cols2); - } - TRACE("dl", tout << "could not handle operation\n";); - return 0; - } - - class skip_table_plugin::join_project_fn : public convenient_table_join_project_fn { - public: - join_project_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols): - convenient_table_join_project_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, - removed_col_cnt, removed_cols) { - } - - virtual table_base* operator()(const table_base & t1, const table_base & t2) { - return skip_table_plugin::mk_join_project(t1, t2, get_result_signature(), m_cols1, m_cols2, m_removed_cols); - } - }; - - - - table_join_fn * skip_table_plugin::mk_join_project_fn( - const table_base & t1, const table_base & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols) { - if (check_kind(t1) && check_kind(t2)) { - return alloc(join_project_fn, t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt, removed_cols); - } - TRACE("dl", tout << "could not handle operation\n";); - return 0; - } - - class skip_table_plugin::union_fn : public table_union_fn { - public: - virtual void operator()(table_base& tgt, const table_base& src, table_base* delta) { - skip_table& s1 = get(tgt); - skip_table const& s2 = get(src); - imdd_manager& m = s1.get_imdd_manager(); - imdd_ref r(m); - m.mk_union(s1.get_imdd(), s2.get_imdd(), r); - if (delta) { - skip_table& d = get(*delta); - if (m.is_subset(r, s1.get_imdd())) { - d.update(m.mk_empty(s1.get_signature().size())); - } - else { - d.update(r); - } - } - s1.update(r); - } - }; - - table_union_fn * skip_table_plugin::mk_union_fn(const table_base & tgt, const table_base & src, const table_base * delta) { - if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) { - return alloc(union_fn); - } - TRACE("dl", tout << "could not handle operation\n";); - return 0; - } - - skip_table* skip_table_plugin::mk_project(table_base const& src, table_signature const& result_sig, unsigned_vector const& cols) { - skip_table const& s = get(src); - imdd_manager& m = s.get_imdd_manager(); - imdd_ref pr(m); - m.mk_project(s.get_imdd(), pr, cols.size(), cols.c_ptr()); - return alloc(skip_table, s.get_plugin(), result_sig, pr); - } - - - class skip_table_plugin::project_fn : public convenient_table_project_fn { - public: - project_fn(table_signature const& orig_sig, unsigned col_cnt, unsigned const* removed_cols): - convenient_table_project_fn(orig_sig, col_cnt, removed_cols) {} - - table_base* operator()(table_base const& src) { - return mk_project(src, get_result_signature(), m_removed_cols); - } - }; - - table_transformer_fn * skip_table_plugin::mk_project_fn(const table_base & t, unsigned col_cnt, const unsigned * removed_cols) { - if (check_kind(t)) { - return alloc(project_fn, t.get_signature(), col_cnt, removed_cols); - } - TRACE("dl", tout << "could not handle operation\n";); - return 0; - } - - class skip_table_plugin::rename_fn : public convenient_table_rename_fn { - - void swap2(imdd_ref& n, unsigned col1, unsigned col2) { - imdd_manager& m = n.get_manager(); - imdd_ref tmp(m); - if (col1 == col2) { - return; - } - if (col1 > col2) { - std::swap(col1, col2); - } - for (unsigned i = col1; i < col2; ++i) { - m.mk_swap(n, tmp, i); - n = tmp; - } - for (unsigned i = col2 - 1; i > col1; ) { - --i; - m.mk_swap(n, tmp, i); - n = tmp; - } - } - public: - rename_fn(table_signature const& sig, unsigned cycle_len, unsigned const* cycle): - convenient_rename_fn(sig, cycle_len, cycle) {} - - table_base* operator()(table_base const& src) { - TRACE("skip", - for (unsigned i = 0; i < m_cycle.size(); ++i) { - tout << m_cycle[i] << " "; - } - tout << "\n"; - src.display(tout);); - skip_table const& s = get(src); - imdd_ref n(s.m_imdd, s.get_imdd_manager()); - unsigned cycle_len = m_cycle.size(); - unsigned col1, col2; - // TBD: review this for proper direction - for (unsigned i = 0; i + 1 < cycle_len; ++i) { - col1 = m_cycle[i]; - col2 = m_cycle[i+1]; - swap2(n, col1, col2); - } - if (cycle_len > 2) { - col1 = m_cycle[cycle_len-1]; - col2 = m_cycle[0]; - swap2(n, col1, col2); - } - skip_table* res = alloc(skip_table, s.get_plugin(), get_result_signature(), n); - TRACE("skip",res->display(tout);); - return res; - } - }; - - table_transformer_fn * skip_table_plugin::mk_rename_fn(const table_base & t, unsigned len, const unsigned * cycle) { - if (check_kind(t)) { - return alloc(rename_fn, t.get_signature(), len, cycle); - } - TRACE("dl", tout << "could not handle operation\n";); - return 0; - } - - class skip_table_plugin::filter_identical_fn : public table_mutator_fn { - unsigned_vector m_cols; - - public: - filter_identical_fn(unsigned cnt, unsigned const* cols): - m_cols(cnt, cols) - {} - - void operator()(table_base & t) { - skip_table& s = get(t); - imdd_manager& m = s.get_imdd_manager(); - m.mk_filter_identical(s.get_imdd(), s.m_imdd, m_cols.size(), m_cols.c_ptr(), true); - } - }; - - table_mutator_fn * skip_table_plugin::mk_filter_identical_fn(const table_base & t, unsigned col_cnt, - const unsigned * identical_cols) { - if (check_kind(t)) { - return alloc(filter_identical_fn, col_cnt, identical_cols); - } - TRACE("dl", tout << "could not handle operation\n";); - return 0; - } - - class skip_table_plugin::filter_equal_fn : public table_mutator_fn { - unsigned m_col; - unsigned m_value; - public: - filter_equal_fn(const table_base & t, const table_element & v, unsigned col): - m_col(col), - m_value(static_cast(v)) - { - SASSERT(v <= UINT_MAX); - } - - virtual void operator()(table_base& src) { - skip_table& s = get(src); - imdd_manager& m = s.get_imdd_manager(); - m.mk_filter_equal(s.get_imdd(), s.m_imdd, m_col, m_value); - } - }; - - table_mutator_fn * skip_table_plugin::mk_filter_equal_fn(const table_base & t, const table_element & value, - unsigned col) { - if (check_kind(t)) { - return alloc(filter_equal_fn, t, value, col); - } - TRACE("dl", tout << "could not handle operation\n";); - return 0; - } - - class skip_table_plugin::filter_not_equal_fn : public table_mutator_fn { - unsigned m_col; - unsigned m_value; - public: - filter_not_equal_fn(const table_base & t, const table_element & v, unsigned col): - m_col(col), - m_value(static_cast(v)) - { - SASSERT(v <= UINT_MAX); - } - - virtual void operator()(table_base& src) { - skip_table& s = get(src); - imdd_manager& m = s.get_imdd_manager(); - m.mk_filter_disequal(s.get_imdd(), s.m_imdd, m_col, m_value); - } - }; - - table_mutator_fn * skip_table_plugin::mk_filter_not_equal_fn(const table_base & t, const table_element & value, - unsigned col) { - if (check_kind(t)) { - return alloc(filter_not_equal_fn, t, value, col); - } - TRACE("dl", tout << "could not handle operation\n";); - return 0; - } - - class skip_table_plugin::filter_distinct_fn : public table_mutator_fn { - unsigned m_col1; - unsigned m_col2; - public: - filter_distinct_fn(const table_base & t, unsigned col1, unsigned col2): - m_col1(col1), - m_col2(col2) { - } - - virtual void operator()(table_base& src) { - skip_table& s = get(src); - imdd_manager& m = s.get_imdd_manager(); - m.mk_filter_distinct(s.get_imdd(), s.m_imdd, m_col1, m_col2); - } - }; - - table_mutator_fn * skip_table_plugin::mk_filter_distinct_fn(const table_base & t, unsigned col1, unsigned col2) { - if (check_kind(t)) { - return alloc(filter_distinct_fn, t, col1, col2); - } - TRACE("dl", tout << "could not handle operation\n";); - return 0; - } - - // - // The default implementation uses an iterator - // if the condition is a comparison <, <=, then interval table native will be an advantage. - // - table_mutator_fn * skip_table_plugin::mk_filter_interpreted_fn(const table_base & t, app * condition) { - ast_manager& m = get_ast_manager(); - dl_decl_util& util = get_context().get_decl_util(); - uint64 value; - - if (m.is_eq(condition)) { - expr* x = condition->get_arg(0); - expr* y = condition->get_arg(1); - if (is_var(y)) { - std::swap(x,y); - } - if (is_var(x) && is_var(y)) { - unsigned cols[2] = { to_var(x)->get_idx(), to_var(y)->get_idx() }; - return mk_filter_identical_fn(t, 2, cols); - } - if (is_var(x) && util.is_numeral_ext(y, value)) { - return mk_filter_equal_fn(t, value, to_var(x)->get_idx()); - } - } - - if (m.is_not(condition) && is_app(condition->get_arg(0))) { - condition = to_app(condition->get_arg(0)); - if (m.is_eq(condition)) { - expr* x = condition->get_arg(0); - expr* y = condition->get_arg(1); - if (is_var(y)) { - std::swap(x,y); - } - if (is_var(x) && is_var(y)) { - return mk_filter_distinct_fn(t, to_var(x)->get_idx(), to_var(y)->get_idx()); - } - if (is_var(x) && util.is_numeral_ext(y, value)) { - return mk_filter_not_equal_fn(t, value, to_var(x)->get_idx()); - } - } - } - - TRACE("dl", tout << "could not handle operation\n";); - return 0; - } - - class skip_table_plugin::filter_by_negation_fn : public convenient_table_negation_filter_fn { - public: - filter_by_negation_fn( - const table_base & tgt, const table_base & neg, - unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) - : convenient_table_negation_filter_fn(tgt, neg, joined_col_cnt, t_cols, negated_cols) { - - } - - // - // Compute - // { (x,y) | t(x,y) & ! exists z . negated_obj(x,z) } - // - // 1. Project z - // 2. Join with result. - // - - virtual void operator()(table_base & tgt0, const table_base & neg0) { - skip_table & tgt = get(tgt0); - const skip_table & neg = get(neg0); - unsigned_vector cols2(m_cols2); - unsigned_vector proj_cols; - table_base* t1 = 0; - if (!m_all_neg_bound) { - unsigned_vector proj_cols, remap; - table_signature sig2; - table_signature const& neg_sig = neg.get_signature(); - for (unsigned i = 0, j = 0; i < m_bound.size(); ++i) { - if (m_bound[i]) { - remap.push_back(j++); - sig2.push_back(neg_sig[i]); - } - else { - proj_cols.push_back(i); - remap.push_back(0); - } - } - for (unsigned i = 0; i < cols2.size(); ++i) { - cols2[i] = remap[cols2[i]]; - } - skip_table* t0 = skip_table_plugin::mk_project(neg, sig2, proj_cols); - t1 = t0->complement(); - t0->deallocate(); - proj_cols.reset(); - } - else { - t1 = neg.complement(); - } - for (unsigned i = 0; i < t1->get_signature().size(); ++i) { - proj_cols.push_back(tgt0.get_signature().size()+i); - } - skip_table* t2 = skip_table_plugin::mk_join_project(tgt0, *t1, tgt0.get_signature(), m_cols1, cols2, proj_cols); - t1->deallocate(); - tgt.update(*t2); - t2->deallocate(); - } - }; - - table_intersection_filter_fn * skip_table_plugin::mk_filter_by_negation_fn( - const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols) { - - if (check_kind(t) && check_kind(negated_obj)) { - return alloc(filter_by_negation_fn, t, negated_obj, joined_col_cnt, t_cols, negated_cols); - } - TRACE("dl", tout << "could not handle operation\n";); - return 0; - } - - bool skip_table_plugin::can_handle_signature(table_signature const& sig) { - for (unsigned i = 0; i < sig.size(); ++i) { - if (sig[i] >= UINT_MAX) { - return false; - } - } - return true; - } - - // ------------------ - // skip_table - - - skip_table::skip_table(skip_table_plugin & p, const table_signature & sig): - table_base(p, sig), - m_imdd(p.get_imdd_manager().mk_empty(sig.size()), p.get_imdd_manager()) { - SASSERT(well_formed()); - } - - skip_table::skip_table(skip_table_plugin & p, const table_signature & sig, imdd* m): - table_base(p, sig), - m_imdd(m, p.get_imdd_manager()) { - SASSERT(well_formed()); - } - - skip_table::~skip_table() { - } - - - bool skip_table::well_formed() const { - table_signature const& sig = get_signature(); - return - get_plugin().can_handle_signature(sig) && - (get_imdd()->get_arity() == sig.size()); - } - - bool skip_table::empty() const { - return get_imdd()->empty(); - } - - void skip_table::update(imdd* n) { - m_imdd = n; - SASSERT(well_formed()); - } - - void skip_table::add_fact(const table_fact & f) { - imdd_manager& m = get_plugin().get_imdd_manager(); - unsigned const* fact = get_fact(f.c_ptr()); - m.add_fact(get_imdd(), m_imdd, f.size(), fact); - SASSERT(well_formed()); - } - - void skip_table::remove_fact(const table_element* f) { - imdd_manager& m = get_imdd_manager(); - unsigned const* fact = get_fact(f); - m.remove_facts(get_imdd(), m_imdd, get_signature().size(), fact, fact); - } - - bool skip_table::contains_fact(const table_fact & f) const { - imdd_manager& m = get_imdd_manager(); - unsigned const* fact = get_fact(f.c_ptr()); - return m.contains(get_imdd(), f.size(), fact); - } - - table_base * skip_table::clone() const { - return alloc(skip_table, get_plugin(), get_signature(), get_imdd()); - } - - table_base * skip_table::complement() const { - imdd_manager& m = get_plugin().get_imdd_manager(); - table_signature const& sig = get_signature(); - unsigned_vector mins, maxs; - for (unsigned i = 0; i < sig.size(); ++i) { - SASSERT(sig[i] < UINT_MAX); - mins.push_back(0); - maxs.push_back(static_cast(sig[i])); - } - imdd_ref cmpl(m); - m.mk_complement(get_imdd(), cmpl, sig.size(), mins.c_ptr(), maxs.c_ptr()); - return alloc(skip_table, get_plugin(), get_signature(), cmpl); - } - - unsigned const* skip_table::get_fact(table_element const* f) const { - table_signature const& sig = get_signature(); - const_cast(m_fact).reset(); - for (unsigned i = 0; i < sig.size(); ++i) { - const_cast(m_fact).push_back(static_cast(f[i])); - SASSERT(f[i] < UINT_MAX); - } - return m_fact.c_ptr(); - } - - - - class skip_table::our_iterator_core : public table_base::iterator_core { - skip_table const& m_table; - imdd_manager::iterator m_iterator; - - class our_row : public row_interface { - const our_iterator_core & m_parent; - public: - our_row(const our_iterator_core & parent) : row_interface(parent.m_table), m_parent(parent) {} - - virtual void get_fact(table_fact & result) const { - result.reset(); - unsigned arity = m_parent.m_iterator.get_arity(); - unsigned const* values = *(m_parent.m_iterator); - for (unsigned i = 0; i < arity; ++i) { - result.push_back(values[i]); - } - } - virtual table_element operator[](unsigned col) const { - SASSERT(col < m_parent.m_iterator.get_arity()); - unsigned const* values = *(m_parent.m_iterator); - return values[col]; - } - }; - - our_row m_row_obj; - - public: - struct b {}; - struct e {}; - - our_iterator_core(skip_table const& t, b): - m_table(t), - m_iterator(t.m_imdd.get_manager(), t.get_imdd()), - m_row_obj(*this) {} - - our_iterator_core(skip_table const& t, e): - m_table(t), - m_iterator(), - m_row_obj(*this) {} - - virtual bool is_finished() const { - return m_iterator == imdd_manager::iterator(); - } - - virtual row_interface & operator*() { - SASSERT(!is_finished()); - return m_row_obj; - } - - virtual void operator++() { - SASSERT(!is_finished()); - ++m_iterator; - } - }; - - - table_base::iterator skip_table::begin() const { - return mk_iterator(alloc(our_iterator_core, *this, our_iterator_core::b())); - } - - table_base::iterator skip_table::end() const { - return mk_iterator(alloc(our_iterator_core, *this, our_iterator_core::e())); - } - - unsigned skip_table::get_size_estimate_rows() const { - imdd_manager& m = get_plugin().get_imdd_manager(); - size_t sz = m.get_num_rows(get_imdd()); - unsigned sz0 = static_cast(sz); - SASSERT (sz == sz0 && "we need to use size_t or big-ints for row count"); - return sz0; - } - - unsigned skip_table::get_size_estimate_bytes() const { - imdd_manager& m = get_plugin().get_imdd_manager(); - return m.memory(get_imdd()); - } - -}; - -#endif diff --git a/src/muz_qe/dl_skip_table.h b/src/muz_qe/dl_skip_table.h deleted file mode 100644 index 6a9af9636..000000000 --- a/src/muz_qe/dl_skip_table.h +++ /dev/null @@ -1,161 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_skip_table.h - -Abstract: - - - -Author: - - Nikolaj Bjorner (nbjorner) - Leonardo de Moura (leonardo) 2010-10-14 - - -Revision History: - ---*/ - -#ifndef _DL_SKIP_TABLE_H_ -#define _DL_SKIP_TABLE_H_ - -#include "dl_base.h" -#include "imdd.h" - -namespace datalog { - class skip_table; - - class skip_table_plugin : public table_plugin { - friend class skip_table; - imdd_manager m_manager; - protected: - class join_fn; - class join_project_fn; - class union_fn; - class transformer_fn; - class rename_fn; - class project_fn; - class filter_equal_fn; - class filter_not_equal_fn; - class filter_identical_fn; - class filter_distinct_fn; - class filter_by_negation_fn; - - imdd_manager& get_imdd_manager() const { return const_cast(m_manager); } - - public: - typedef skip_table table; - - skip_table_plugin(relation_manager & manager) - : table_plugin(symbol("skip"), manager) {} - - virtual table_base * mk_empty(const table_signature & s); - - virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual table_join_fn * mk_join_project_fn( - const table_base & t1, const table_base & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols); - virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, - const table_base * delta); - virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual table_mutator_fn * mk_filter_identical_fn(const table_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value, - unsigned col); - virtual table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition); - virtual table_intersection_filter_fn * mk_filter_by_negation_fn( - const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); - - virtual bool can_handle_signature(table_signature const& s); - - private: - static skip_table& get(table_base& r); - - static skip_table const & get(table_base const& r); - - static skip_table* mk_join(table_base const& t1, table_base const& t2, table_signature const& s, - unsigned_vector const& cols_t1, unsigned_vector const& cols_t2); - - static skip_table* mk_join_project(table_base const& t1, table_base const& t2, table_signature const& s, - unsigned_vector const& cols_t1, unsigned_vector const& cols_t2, unsigned_vector const& proj_cols); - - static skip_table* mk_project(table_base const& src, table_signature const& result_sig, - unsigned_vector const& cols); - - virtual table_mutator_fn * mk_filter_distinct_fn(const table_base & t, unsigned col1, unsigned col2); - - virtual table_mutator_fn * mk_filter_not_equal_fn(const table_base & t, const table_element & value, - unsigned col); - - }; - - class skip_table : public table_base { - friend class skip_table_plugin; - friend class skip_table_plugin::join_fn; - friend class skip_table_plugin::union_fn; - friend class skip_table_plugin::transformer_fn; - friend class skip_table_plugin::rename_fn; - friend class skip_table_plugin::project_fn; - friend class skip_table_plugin::filter_equal_fn; - friend class skip_table_plugin::filter_not_equal_fn; - friend class skip_table_plugin::filter_identical_fn; - friend class skip_table_plugin::filter_distinct_fn; - - class our_iterator_core; - - imdd_ref m_imdd; - unsigned_vector m_fact; - - imdd* get_imdd() const { return m_imdd.get(); } - - imdd_manager& get_imdd_manager() const { return get_plugin().get_imdd_manager(); } - - unsigned const* get_fact(table_element const* f) const; - - bool well_formed() const; - - void update(imdd* n); - - void update(skip_table& t) { update(t.m_imdd); } - - skip_table(skip_table_plugin & p, const table_signature & sig); - - skip_table(skip_table_plugin & p, const table_signature & sig, imdd*); - - skip_table(const skip_table & t); - - virtual ~skip_table(); - - public: - - skip_table_plugin & get_plugin() const { - return static_cast(table_base::get_plugin()); - } - - virtual bool empty() const; - virtual void add_fact(const table_fact & f); - virtual void remove_fact(const table_element * fact); - virtual bool contains_fact(const table_fact & f) const; - virtual table_base * complement() const; - virtual table_base * clone() const; - - virtual iterator begin() const; - virtual iterator end() const; - - virtual unsigned get_size_estimate_rows() const; - virtual unsigned get_size_estimate_bytes() const; - }; - - }; - - #endif /* _DL_SKIP_TABLE_H_ */ diff --git a/src/muz_qe/dl_sparse_table.cpp b/src/muz_qe/dl_sparse_table.cpp index 1449b7d3d..b912ef136 100644 --- a/src/muz_qe/dl_sparse_table.cpp +++ b/src/muz_qe/dl_sparse_table.cpp @@ -500,6 +500,9 @@ namespace datalog { char * reserve = m_data.get_reserve_ptr(); unsigned col_cnt = m_column_layout.size(); for(unsigned i=0; i= get_signature()[i]) { + std::cout << f[i] << " " << get_signature()[i] << "\n"; + } SASSERT(f[i]is_shared()) { - if (cache.find(d, r) && (r == 0 || !r->is_dead())) - return true; - } - return false; -} - -inline void cache_result(imdd2imdd_cache & cache, imdd * d, imdd * r) { - if (d->is_shared()) - cache.insert(d, r); -} - -inline bool is_cached(imdd_pair2imdd_cache & cache, imdd * d1, imdd * d2, imdd * & r) { - if (d1->is_shared() && d2->is_shared()) { - if (cache.find(d1, d2, r) && (r == 0 || !r->is_dead())) - return true; - } - return false; -} - -inline void cache_result(imdd_pair2imdd_cache & cache, imdd * d1, imdd * d2, imdd * r) { - if (d1->is_shared() && d2->is_shared()) - cache.insert(d1, d2, r); -} - -inline bool destructive_update_at(bool destructive, imdd * d) { - return destructive && !d->is_memoized() && !d->is_shared(); -} - -void sl_imdd_manager::inc_ref_eh(imdd * v) { - m_manager->inc_ref(v); -} - -void sl_imdd_manager::dec_ref_eh(imdd * v) { - m_manager->dec_ref(v); -} - -unsigned imdd::hc_hash() const { - unsigned r = 0; - r = get_arity(); - imdd_children::iterator it = begin_children(); - imdd_children::iterator end = end_children(); - for (; it != end; ++it) { - unsigned b = it->begin_key(); - unsigned e = it->end_key(); - imdd const * child = it->val(); - mix(b, e, r); - if (child) { - SASSERT(child->is_memoized()); - unsigned v = child->get_id(); - mix(v, v, r); - } - } - return r; -} - -bool imdd::hc_equal(imdd const * other) const { - if (m_arity != other->m_arity) - return false; - return m_children.is_equal(other->m_children); -} - -imdd_manager::delay_dealloc::~delay_dealloc() { - SASSERT(m_manager.m_to_delete.size() >= m_to_delete_size); - ptr_vector::iterator it = m_manager.m_to_delete.begin() + m_to_delete_size; - ptr_vector::iterator end = m_manager.m_to_delete.end(); - for (; it != end; ++it) { - SASSERT((*it)->is_dead()); - m_manager.deallocate_imdd(*it); - } - m_manager.m_to_delete.shrink(m_to_delete_size); - m_manager.m_delay_dealloc = m_delay_dealloc_value; -} - -imdd_manager::imdd_manager(): - m_sl_manager(m_alloc), - m_simple_max_entries(DEFAULT_SIMPLE_MAX_ENTRIES), - m_delay_dealloc(false) { - m_sl_manager.m_manager = this; - m_swap_new_child = 0; -} - -imdd * imdd_manager::_mk_empty(unsigned arity) { - SASSERT(arity > 0); - void * mem = m_alloc.allocate(sizeof(imdd)); - return new (mem) imdd(m_sl_manager, m_id_gen.mk(), arity); -} - -imdd * imdd_manager::defrag_core(imdd * d) { - if (d->is_memoized()) - return d; - unsigned h = d->get_arity(); - if (h == 1 && !is_simple_node(d)) - return d; - imdd * new_d = 0; - if (is_cached(m_defrag_cache, d, new_d)) - return new_d; - - if (h == 1) { - SASSERT(is_simple_node(d)); - imdd * new_can_d = memoize(d); - cache_result(m_defrag_cache, d, new_can_d); - return new_can_d; - } - - SASSERT(h > 1); - new_d = _mk_empty(h); - imdd_children::push_back_proc push_back(m_sl_manager, new_d->m_children); - bool has_new = false; - bool children_memoized = true; - - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd * child = it->val(); - imdd * new_child = defrag_core(child); - if (child != new_child) - has_new = true; - if (!new_child->is_memoized()) - children_memoized = false; - push_back(it->begin_key(), it->end_key(), new_child); - } - - if (has_new) { - if (children_memoized && is_simple_node(new_d)) { - imdd * new_can_d = memoize(new_d); - if (new_can_d != new_d) { - SASSERT(new_d->get_ref_count() == 0); - delete_imdd(new_d); - } - new_d = new_can_d; - } - } - else { - SASSERT(!has_new); - delete_imdd(new_d); - new_d = d; - if (children_memoized && is_simple_node(new_d)) { - new_d = memoize(new_d); - } - } - - cache_result(m_defrag_cache, d, new_d); - return new_d; -} - -/** - \brief Compress the given IMDD by using hash-consing. -*/ -void imdd_manager::defrag(imdd_ref & d) { - delay_dealloc delay(*this); - m_defrag_cache.reset(); - d = defrag_core(d); -} - -/** - \brief Memoize the given IMDD. - Return an IMDD structurally equivalent to d. - This method assumes the children of d are memoized. - If that is not the case, the user should invoke defrag instead. -*/ -imdd * imdd_manager::memoize(imdd * d) { - if (d->is_memoized()) - return d; - unsigned h = d->get_arity(); - m_tables.reserve(h); - DEBUG_CODE({ - if (h > 1) { - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - SASSERT(it->val()->is_memoized()); - } - } - }); - imdd * r = m_tables[h-1].insert_if_not_there(d); - if (r == d) { - r->mark_as_memoized(); - } - SASSERT(r->is_memoized()); - return r; -} - -/** - \brief Remove the given IMDD from the hash-consing table -*/ -void imdd_manager::unmemoize(imdd * d) { - SASSERT(d->is_memoized()); - m_tables[d->get_arity()-1].erase(d); - d->mark_as_memoized(false); -} - - -/** - \brief Remove the given IMDD (and its children) from the hash-consing tables. -*/ -void imdd_manager::unmemoize_rec(imdd * d) { - SASSERT(m_worklist.empty()); - m_worklist.push_back(d); - while (!m_worklist.empty()) { - d = m_worklist.back(); - if (d->is_memoized()) { - unmemoize(d); - SASSERT(!d->is_memoized()); - if (d->get_arity() > 1) { - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) - m_worklist.push_back(it->val()); - } - } - } -} - -bool imdd_manager::is_simple_node(imdd * d) const { - return !d->m_children.has_more_than_k_entries(m_simple_max_entries); -} - -void imdd_manager::mark_as_dead(imdd * d) { - // The references to the children were decremented by delete_imdd. - SASSERT(!d->is_dead()); - d->m_children.deallocate_no_decref(m_sl_manager); - d->mark_as_dead(); - if (m_delay_dealloc) - m_to_delete.push_back(d); - else - deallocate_imdd(d); -} - -void imdd_manager::deallocate_imdd(imdd * d) { - SASSERT(d->is_dead()); - memset(d, 0, sizeof(*d)); - m_alloc.deallocate(sizeof(imdd), d); -} - -void imdd_manager::delete_imdd(imdd * d) { - SASSERT(m_worklist.empty()); - m_worklist.push_back(d); - - while (!m_worklist.empty()) { - d = m_worklist.back(); - m_worklist.pop_back(); - - m_id_gen.recycle(d->get_id()); - - SASSERT(d->get_ref_count() == 0); - if (d->is_memoized()) { - unsigned arity = d->get_arity(); - SASSERT(m_tables[arity-1].contains(d)); - m_tables[arity-1].erase(d); - } - - if (d->get_arity() > 1) { - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd * child = it->val(); - SASSERT(child); - child->dec_ref(); - if (child->get_ref_count() == 0) - m_worklist.push_back(child); - } - } - - mark_as_dead(d); - } -} - -/** - \brief Return a (non-memoized) shallow copy of d. -*/ -imdd * imdd_manager::copy_main(imdd * d) { - imdd * d_copy = _mk_empty(d->get_arity()); - d_copy->m_children.copy(m_sl_manager, d->m_children); - SASSERT(!d_copy->is_memoized()); - SASSERT(d_copy->get_ref_count() == 0); - return d_copy; -} - -/** - \brief Insert the values [b, e] into a IMDD of arity 1. - - If destructive == true, d is not memoized and is not shared, then a - destructive update is performed, and d is returned. - - Otherwise, a fresh IMDD is returned. -*/ -imdd * imdd_manager::insert_main(imdd * d, unsigned b, unsigned e, bool destructive, bool memoize_res) { - SASSERT(d->get_arity() == 1); - if (destructive_update_at(destructive, d)) { - add_child(d, b, e, 0); - return d; - } - else { - imdd * new_d = copy_main(d); - add_child(new_d, b, e, 0); - return memoize_new_imdd_if(memoize_res, new_d); - } -} - - -/** - \brief Remove the values [b, e] from an IMDD of arity 1. - - If destructive == true, d is not memoized and is not shared, then a - destructive update is performed, and d is returned. - - Otherwise, a fresh IMDD is returned. -*/ -imdd * imdd_manager::remove_main(imdd * d, unsigned b, unsigned e, bool destructive, bool memoize_res) { - SASSERT(d->get_arity() == 1); - if (destructive_update_at(destructive, d)) { - remove_child(d, b, e); - return d; - } - else { - imdd * new_d = copy_main(d); - remove_child(new_d, b, e); - return memoize_new_imdd_if(memoize_res, new_d); - } -} - -/** - \brief Auxiliary functor used to implement destructive version of mk_product. -*/ -struct imdd_manager::null2imdd_proc { - imdd * m_d2; - null2imdd_proc(imdd * d2):m_d2(d2) {} - imdd * operator()(imdd * d) { SASSERT(d == 0); return m_d2; } -}; - -/** - \brief Auxiliary functor used to implement destructive version of mk_product. -*/ -struct imdd_manager::mk_product_proc { - imdd_manager & m_manager; - imdd * m_d2; - bool m_memoize; - mk_product_proc(imdd_manager & m, imdd * d2, bool memoize): - m_manager(m), - m_d2(d2), - m_memoize(memoize) { - } - imdd * operator()(imdd * d1) { return m_manager.mk_product_core(d1, m_d2, true, m_memoize); } -}; - -imdd * imdd_manager::mk_product_core(imdd * d1, imdd * d2, bool destructive, bool memoize_res) { - SASSERT(!d1->empty()); - SASSERT(!d2->empty()); - if (destructive && !d1->is_shared()) { - if (d1->is_memoized()) - unmemoize(d1); - - if (d1->get_arity() == 1) { - null2imdd_proc f(d2); - d1->m_children.update_values(m_sl_manager, f); - d1->m_arity += d2->m_arity; - } - else { - mk_product_proc f(*this, d2, memoize_res); - d1->m_children.update_values(m_sl_manager, f); - d1->m_arity += d2->m_arity; - } - return d1; - } - else { - imdd * new_d1 = 0; - if (is_cached(m_mk_product_cache, d1, new_d1)) - return new_d1; - unsigned arity1 = d1->get_arity(); - unsigned arity2 = d2->get_arity(); - new_d1 = _mk_empty(arity1 + arity2); - imdd_children::push_back_proc push_back(m_sl_manager, new_d1->m_children); - imdd_children::iterator it = d1->begin_children(); - imdd_children::iterator end = d1->end_children(); - bool children_memoized = true; - for (; it != end; ++it) { - imdd * new_child; - if (arity1 == 1) - new_child = d2; - else - new_child = mk_product_core(it->val(), d2, false, memoize_res); - if (!new_child->is_memoized()) - children_memoized = false; - push_back(it->begin_key(), it->end_key(), new_child); - } - new_d1 = memoize_new_imdd_if(memoize_res && children_memoized, new_d1); - cache_result(m_mk_product_cache, d1, new_d1); - return new_d1; - } -} - -imdd * imdd_manager::mk_product_main(imdd * d1, imdd * d2, bool destructive, bool memoize_res) { - if (d1->empty() || d2->empty()) { - unsigned a1 = d1->get_arity(); - unsigned a2 = d2->get_arity(); - return _mk_empty(a1 + a2); - } - delay_dealloc delay(*this); - if (d1 == d2) - destructive = false; - m_mk_product_cache.reset(); - return mk_product_core(d1, d2, destructive, memoize_res); -} - -void imdd_manager::init_add_facts_new_children(unsigned num, unsigned const * lowers, unsigned const * uppers, bool memoize_res) { - if (m_add_facts_new_children[num] != 0) { - DEBUG_CODE({ - for (unsigned i = 1; i <= num; i++) { - SASSERT(m_add_facts_new_children[i] != 0); - }}); - return; - } - for (unsigned i = 1; i <= num; i++) { - if (m_add_facts_new_children[i] == 0) { - imdd * new_child = _mk_empty(i); - unsigned b = lowers[num - i]; - unsigned e = uppers[num - i]; - bool prev_memoized = true; - if (i == 1) { - add_child(new_child, b, e, 0); - } - else { - SASSERT(m_add_facts_new_children[i-1] != 0); - prev_memoized = m_add_facts_new_children[i-1]->is_memoized(); - add_child(new_child, b, e, m_add_facts_new_children[i-1]); - } - new_child = memoize_new_imdd_if(memoize_res && prev_memoized, new_child); - m_add_facts_new_children[i] = new_child; - } - } - DEBUG_CODE({ - for (unsigned i = 1; i <= num; i++) { - SASSERT(m_add_facts_new_children[i] != 0); - }}); -} - -imdd * imdd_manager::add_facts_core(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res) { - SASSERT(d->get_arity() == num); - imdd_ref new_child(*this); - bool new_children_memoized = true; -#define INIT_NEW_CHILD() { \ - if (new_child == 0) { \ - init_add_facts_new_children(num - 1, lowers + 1, uppers + 1, memoize_res); \ - new_child = m_add_facts_new_children[num-1]; \ - if (!new_child->is_memoized()) new_children_memoized = false; \ - }} - - if (destructive_update_at(destructive, d)) { - if (num == 1) - return insert_main(d, *lowers, *uppers, destructive, memoize_res); - SASSERT(num > 1); - sbuffer to_insert; - new_child = m_add_facts_new_children[num-1]; - - unsigned b = *lowers; - unsigned e = *uppers; - imdd_children::iterator it = d->m_children.find_geq(b); - imdd_children::iterator end = d->end_children(); - for (; it != end && b <= e; ++it) { - imdd_children::entry const & curr_entry = *it; - if (e < curr_entry.begin_key()) - break; - if (b < curr_entry.begin_key()) { - INIT_NEW_CHILD(); - SASSERT(b <= curr_entry.begin_key() - 1); - to_insert.push_back(entry(b, curr_entry.begin_key() - 1, new_child)); - b = curr_entry.begin_key(); - } - imdd * curr_child = curr_entry.val(); - SASSERT(b >= curr_entry.begin_key()); - bool cover = b == curr_entry.begin_key() && e >= curr_entry.end_key(); - // If cover == true, then the curr_child is completely covered by the new facts, and it is not needed anymore. - // So, we can perform a destructive update. - imdd * new_curr_child = add_facts_core(curr_child, num - 1, lowers + 1, uppers + 1, cover, memoize_res); - - if (e >= curr_entry.end_key()) { - SASSERT(b <= curr_entry.end_key()); - to_insert.push_back(entry(b, curr_entry.end_key(), new_curr_child)); - } - else { - SASSERT(e < curr_entry.end_key()); - SASSERT(b <= e); - to_insert.push_back(entry(b, e, new_curr_child)); - } - b = curr_entry.end_key() + 1; - } - // Re-insert entries in m_add_facts_to_insert into d->m_children, - // and if b <= e also insert [b, e] -> new_child - if (b <= e) { - INIT_NEW_CHILD(); - add_child(d, b, e, new_child); - } - - svector::iterator it2 = to_insert.begin(); - svector::iterator end2 = to_insert.end(); - for (; it2 != end2; ++it2) { - imdd_children::entry const & curr_entry = *it2; - add_child(d, curr_entry.begin_key(), curr_entry.end_key(), curr_entry.val()); - } - - return d; - } - else { - imdd * new_d = 0; - if (is_cached(m_add_facts_cache, d, new_d)) - return new_d; - - if (num == 1) { - new_d = insert_main(d, *lowers, *uppers, destructive, memoize_res); - } - else { - new_d = copy_main(d); - new_child = m_add_facts_new_children[num-1]; - TRACE("add_facts_bug", tout << "after copying: " << new_d << "\n" << mk_ll_pp(new_d, *this) << "\n";); - - unsigned b = *lowers; - unsigned e = *uppers; - imdd_children::iterator it = d->m_children.find_geq(b); - imdd_children::iterator end = d->end_children(); - for (; it != end && b <= e; ++it) { - imdd_children::entry const & curr_entry = *it; - if (e < curr_entry.begin_key()) - break; - if (b < curr_entry.begin_key()) { - INIT_NEW_CHILD(); - SASSERT(b <= curr_entry.begin_key() - 1); - add_child(new_d, b, curr_entry.begin_key() - 1, new_child); - TRACE("add_facts_bug", tout << "after inserting new child: " << new_d << "\n" << mk_ll_pp(new_d, *this) << "\n";); - b = curr_entry.begin_key(); - } - imdd * curr_child = curr_entry.val(); - imdd * new_curr_child = add_facts_core(curr_child, num - 1, lowers + 1, uppers + 1, false, memoize_res); - if (!new_curr_child->is_memoized()) - new_children_memoized = false; - if (e >= curr_entry.end_key()) { - SASSERT(b <= curr_entry.end_key()); - add_child(new_d, b, curr_entry.end_key(), new_curr_child); - TRACE("add_facts_bug", tout << "1) after inserting new curr child: " << new_d << "\n" << mk_ll_pp(new_d, *this) << "\n"; - tout << "new_curr_child: " << mk_ll_pp(new_curr_child, *this) << "\n";); - } - else { - SASSERT(e < curr_entry.end_key()); - SASSERT(b <= e); - add_child(new_d, b, e, new_curr_child); - TRACE("add_facts_bug", tout << "2) after inserting new curr child: " << new_d << "\n" << mk_ll_pp(new_d, *this) << "\n"; - tout << "new_curr_child: " << mk_ll_pp(new_curr_child, *this) << "\n";); - } - b = curr_entry.end_key() + 1; - } - if (b <= e) { - INIT_NEW_CHILD(); - add_child(new_d, b, e, new_child); - } - - new_d = memoize_new_imdd_if(memoize_res && d->is_memoized() && new_children_memoized, new_d); - } - - cache_result(m_add_facts_cache, d, new_d); - return new_d; - } -} - -imdd * imdd_manager::add_facts_main(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res) { - SASSERT(d->get_arity() == num); - delay_dealloc delay(*this); - m_add_facts_cache.reset(); - m_add_facts_new_children.reset(); - m_add_facts_new_children.resize(num, 0); - return add_facts_core(d, num, lowers, uppers, destructive, memoize_res); -} - -inline void update_memoized_flag(imdd * d, bool & memoized_flag) { - if (d && !d->is_memoized()) - memoized_flag = false; -} - -void imdd_manager::push_back_entries(unsigned head, imdd_children::iterator & it, imdd_children::iterator & end, - imdd_children::push_back_proc & push_back, bool & children_memoized) { - if (it != end) { - push_back(head, it->end_key(), it->val()); - update_memoized_flag(it->val(), children_memoized); - ++it; - for (; it != end; ++it) { - update_memoized_flag(it->val(), children_memoized); - push_back(it->begin_key(), it->end_key(), it->val()); - } - } -} - -/** - \brief Push the entries starting at head upto the given limit (no included). - That is, we are copying the entries in the interval [head, limit). -*/ -void imdd_manager::push_back_upto(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, - unsigned limit, imdd_children::push_back_proc & push_back, bool & children_memoized) { - SASSERT(it != end); - SASSERT(head <= it->end_key()); - SASSERT(head >= it->begin_key()); - SASSERT(head < limit); - while (head < limit && it != end) { - if (it->end_key() < limit) { - update_memoized_flag(it->val(), children_memoized); - push_back(head, it->end_key(), it->val()); - ++it; - if (it != end) - head = it->begin_key(); - } - else { - SASSERT(it->end_key() >= limit); - update_memoized_flag(it->val(), children_memoized); - push_back(head, limit-1, it->val()); - head = limit; - } - } - SASSERT(head == limit || it == end || head == it->begin_key()); -} - -void imdd_manager::move_head(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, unsigned new_head) { - SASSERT(new_head >= head); - SASSERT(head >= it->begin_key()); - SASSERT(head <= it->end_key()); - SASSERT(new_head <= it->end_key()); - if (new_head < it->end_key()) { - head = new_head+1; - SASSERT(head <= it->end_key()); - } - else { - SASSERT(new_head == it->end_key()); - ++it; - if (it != end) - head = it->begin_key(); - } -} - -/** - \brief Copy the entries starting at head upto the given limit (no included). - That is, we are copying the entries in the interval [head, limit). -*/ -void imdd_manager::copy_upto(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, - unsigned limit, sbuffer & result) { - SASSERT(it != end); - SASSERT(head <= it->end_key()); - SASSERT(head >= it->begin_key()); - SASSERT(head < limit); - while (head < limit && it != end) { - if (it->end_key() < limit) { - result.push_back(entry(head, it->end_key(), it->val())); - ++it; - if (it != end) - head = it->begin_key(); - } - else { - SASSERT(it->end_key() >= limit); - result.push_back(entry(head, limit-1, it->val())); - head = limit; - } - } - SASSERT(head == limit || it == end || head == it->begin_key()); -} - -imdd * imdd_manager::mk_union_core(imdd * d1, imdd * d2, bool destructive, bool memoize_res) { - if (d1 == d2) - return d1; - if (destructive_update_at(destructive, d1)) { - if (d1->get_arity() == 1) { - imdd_children::iterator it = d2->begin_children(); - imdd_children::iterator end = d2->end_children(); - for (; it != end; ++it) - add_child(d1, it->begin_key(), it->end_key(), 0); - return d1; - } - else { - imdd_children::iterator it2 = d2->begin_children(); - imdd_children::iterator end2 = d2->end_children(); - imdd_children::iterator it1 = d1->m_children.find_geq(it2->begin_key()); - imdd_children::iterator end1 = d1->end_children(); - sbuffer to_insert; - unsigned head1 = it1 != end1 ? it1->begin_key() : UINT_MAX; - SASSERT(it2 != end2); - unsigned head2 = it2->begin_key(); - while (true) { - if (it1 == end1) { - // copy it2 to d1 - // Remark: we don't need to copy to to_insert, since we will not be using it1 anymore. - // That is, we can directly insert into d1->m_children. - if (it2 != end2) { - add_child(d1, head2, it2->end_key(), it2->val()); - ++it2; - for (; it2 != end2; ++it2) - add_child(d1, it2->begin_key(), it2->end_key(), it2->val()); - } - break; - } - - if (it2 == end2) { - break; - } - - if (head1 < head2) { - it1.move_to(head2); - head1 = it1 != end1 ? (it1->begin_key() < head2?head2:it1->begin_key()): UINT_MAX; - } - else if (head1 > head2) { - copy_upto(head2, it2, end2, head1, to_insert); - } - else { - SASSERT(head1 == head2); - unsigned tail = std::min(it1->end_key(), it2->end_key()); - imdd * new_child = 0; - SASSERT(d1->get_arity() > 1); - bool cover = head1 == it1->begin_key() && tail == it1->end_key(); - // If cover == true, then the it1->val() (curr_child) is completely covered by - // the new_child, and it is not needed anymore. - // So, we can perform a destructive update. - new_child = mk_union_core(it1->val(), it2->val(), cover, memoize_res); - if (new_child != it1->val()) - to_insert.push_back(entry(head1, tail, new_child)); - move_head(head1, it1, end1, tail); - move_head(head2, it2, end2, tail); - } - } - sbuffer::const_iterator it3 = to_insert.begin(); - sbuffer::const_iterator end3 = to_insert.end(); - for (; it3 != end3; ++it3) - add_child(d1, it3->begin_key(), it3->end_key(), it3->val()); - return d1; - } - } - else { - imdd * r = 0; - if (is_cached(m_union_cache, d1, d2, r)) - return r; - - unsigned arity = d1->get_arity(); - r = _mk_empty(arity); - imdd_children::push_back_proc push_back(m_sl_manager, r->m_children); - imdd_children::iterator it1 = d1->begin_children(); - imdd_children::iterator end1 = d1->end_children(); - imdd_children::iterator it2 = d2->begin_children(); - imdd_children::iterator end2 = d2->end_children(); - SASSERT(it1 != end1); - SASSERT(it2 != end2); - unsigned head1 = it1->begin_key(); - unsigned head2 = it2->begin_key(); - bool children_memoized = true; - while (true) { - if (it1 == end1) { - // copy it2 to result - push_back_entries(head2, it2, end2, push_back, children_memoized); - break; - } - if (it2 == end2) { - // copy it1 to result - push_back_entries(head1, it1, end1, push_back, children_memoized); - break; - } - - if (head1 < head2) { - push_back_upto(head1, it1, end1, head2, push_back, children_memoized); - } - else if (head1 > head2) { - push_back_upto(head2, it2, end2, head1, push_back, children_memoized); - } - else { - SASSERT(head1 == head2); - unsigned tail = std::min(it1->end_key(), it2->end_key()); - imdd * new_child = 0; - if (arity > 1) { - new_child = mk_union_core(it1->val(), it2->val(), false, memoize_res); - update_memoized_flag(new_child, children_memoized); - } - push_back(head1, tail, new_child); - move_head(head1, it1, end1, tail); - move_head(head2, it2, end2, tail); - } - } - r = memoize_new_imdd_if(memoize_res && children_memoized, r); - cache_result(m_union_cache, d1, d2, r); - return r; - } -} - -void imdd_manager::reset_union_cache() { - m_union_cache.reset(); -} - -imdd * imdd_manager::mk_union_main(imdd * d1, imdd * d2, bool destructive, bool memoize_res) { - SASSERT(d1->get_arity() == d2->get_arity()); - if (d1 == d2) - return d1; - if (d1->empty()) - return d2; - if (d2->empty()) - return d1; - delay_dealloc delay(*this); - reset_union_cache(); - return mk_union_core(d1, d2, destructive, memoize_res); -} - -void imdd_manager::mk_union_core_dupdt(imdd_ref & d1, imdd * d2, bool memoize_res) { - SASSERT(d1->get_arity() == d2->get_arity()); - if (d1 == d2 || d2->empty()) - return; - if (d1->empty()) { - d1 = d2; - return; - } - d1 = mk_union_core(d1, d2, true, memoize_res); -} - -void imdd_manager::mk_union_core(imdd * d1, imdd * d2, imdd_ref & r, bool memoize_res) { - SASSERT(d1->get_arity() == d2->get_arity()); - if (d1 == d2 || d2->empty()) { - r = d1; - return; - } - if (d1->empty()) { - r = d2; - return; - } - TRACE("mk_union_core", - tout << "d1:\n"; - display_ll(tout, d1); - tout << "d2:\n"; - display_ll(tout, d2);); - r = mk_union_core(d1, d2, false, memoize_res); -} - -imdd * imdd_manager::mk_complement_core(imdd * d, unsigned num, unsigned const * mins, unsigned const * maxs, bool destructive, bool memoize_res) { - SASSERT(d->get_arity() == num); - SASSERT(!d->empty()); - SASSERT(*mins <= *maxs); - unsigned arity = d->get_arity(); - imdd_ref new_child(*this); - bool new_children_memoized = true; -#undef INIT_NEW_CHILD -#define INIT_NEW_CHILD() { \ - if (arity > 1 && new_child == 0) { \ - init_add_facts_new_children(num - 1, mins + 1, maxs + 1, memoize_res); \ - new_child = m_add_facts_new_children[num-1]; \ - SASSERT(new_child != 0); \ - if (!new_child->is_memoized()) new_children_memoized = false; \ - }} - - if (false && destructive_update_at(destructive, d)) { - // TODO - NOT_IMPLEMENTED_YET(); - return 0; - } - else { - destructive = false; - imdd * r = 0; - if (is_cached(m_complement_cache, d, r)) - return r; - - r = _mk_empty(arity); - imdd_children::push_back_proc push_back(m_sl_manager, r->m_children); - - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - unsigned prev_key = *mins; - for (; it != end; ++it) { - SASSERT(it->begin_key() >= *mins); - SASSERT(it->end_key() <= *maxs); - if (prev_key < it->begin_key()) { - INIT_NEW_CHILD(); - push_back(prev_key, it->begin_key() - 1, new_child); - } - if (arity > 1) { - imdd * new_curr = mk_complement_core(it->val(), num - 1, mins + 1, maxs + 1, false, memoize_res); - if (new_curr != 0) { - push_back(it->begin_key(), it->end_key(), new_curr); - if (!new_curr->is_memoized()) - new_children_memoized = false; - } - } - prev_key = it->end_key() + 1; - } - - if (prev_key <= *maxs) { - INIT_NEW_CHILD(); - push_back(prev_key, *maxs, new_child); - } - - if (r->empty()) { - delete_imdd(r); - r = 0; - } - - r = memoize_new_imdd_if(r && memoize_res && new_children_memoized, r); - cache_result(m_complement_cache, d, r); - return r; - } -} - -imdd * imdd_manager::mk_complement_main(imdd * d, unsigned num, unsigned const * mins, unsigned const * maxs, bool destructive, bool memoize_res) { - unsigned arity = d->get_arity(); - SASSERT(arity == num); - // reuse m_add_facts_new_children for creating the universe-set IMDDs - m_add_facts_new_children.reset(); - m_add_facts_new_children.resize(num+1, 0); - - if (d->empty()) { - // return the universe-set - init_add_facts_new_children(num, mins, maxs, memoize_res); - return m_add_facts_new_children[num]; - } - - delay_dealloc delay(*this); - m_complement_cache.reset(); - imdd * r = mk_complement_core(d, num, mins, maxs, destructive, memoize_res); - if (r == 0) - return _mk_empty(arity); - else - return r; -} - -/** - \brief Replace the IMDD children with new_children. - The function will also decrement the ref-counter of every IMDD in new_children, since - it assumes the counter was incremented when the IMDD was inserted into the buffer. -*/ -void imdd::replace_children(sl_imdd_manager & m, sbuffer & new_children) { - m_children.reset(m); - imdd_children::push_back_proc push_back(m, m_children); - svector::iterator it = new_children.begin(); - svector::iterator end = new_children.end(); - for (; it != end; ++it) { - SASSERT(it->val() == 0 || it->val()->get_ref_count() > 0); - push_back(it->begin_key(), it->end_key(), it->val()); - SASSERT(it->val() == 0 || it->val()->get_ref_count() > 1); - if (it->val() != 0) - it->val()->dec_ref(); - } -} - -imdd * imdd_manager::mk_filter_equal_core(imdd * d, unsigned vidx, unsigned value, bool destructive, bool memoize_res) { - SASSERT(!d->empty()); - SASSERT(vidx >= 0 && vidx < d->get_arity()); - unsigned arity = d->get_arity(); - if (destructive_update_at(destructive, d)) { - if (vidx == 0) { - imdd * child = 0; - if (d->m_children.find(value, child)) { - imdd_ref ref(*this); - ref = child; // protect child, we don't want the following reset to delete it. - d->m_children.reset(m_sl_manager); - add_child(d, value, child); - return d; - } - else { - return 0; - } - } - SASSERT(arity > 1); - sbuffer to_insert; - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - imdd * new_child = mk_filter_equal_core(curr_child, vidx-1, value, true, memoize_res); - if (new_child != 0) { - new_child->inc_ref(); // protect new child, we will be resetting d->m_children later. - to_insert.push_back(entry(it->begin_key(), it->end_key(), new_child)); - } - } - if (to_insert.empty()) { - return 0; - } - d->replace_children(m_sl_manager, to_insert); - return d; - } - - imdd * r = 0; - if (is_cached(m_filter_equal_cache, d, r)) - return r; - bool new_children_memoized = true; - - if (vidx == 0) { - // found filter variable - imdd * child = 0; - if (d->m_children.find(value, child)) { - r = _mk_empty(arity); - add_child(r, value, child); - if (child && !child->is_memoized()) - new_children_memoized = false; - } - else { - r = 0; - } - } - else { - SASSERT(arity > 1); - r = _mk_empty(arity); - imdd_children::push_back_proc push_back(m_sl_manager, r->m_children); - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - imdd * new_child = mk_filter_equal_core(curr_child, vidx-1, value, false, memoize_res); - if (new_child != 0) { - push_back(it->begin_key(), it->end_key(), new_child); - if (!new_child->is_memoized()) - new_children_memoized = false; - } - } - if (r->empty()) { - delete_imdd(r); - r = 0; - } - } - - r = memoize_new_imdd_if(r && memoize_res && new_children_memoized, r); - cache_result(m_filter_equal_cache, d, r); - return r; -} - -imdd * imdd_manager::mk_filter_equal_main(imdd * d, unsigned vidx, unsigned value, bool destructive, bool memoize_res) { - unsigned arity = d->get_arity(); - SASSERT(vidx >= 0 && vidx < arity); - if (d->empty()) - return d; - delay_dealloc delay(*this); - m_filter_equal_cache.reset(); - imdd * r = mk_filter_equal_core(d, vidx, value, destructive, memoize_res); - if (r == 0) - return _mk_empty(arity); - else - return r; -} - - -/** - \brief create map from imdd nodes to the interval of variables that are covered by variable. - -*/ - -static void mk_interval_set_intersect(sl_manager_base &m, sl_interval_set const& src, unsigned b, unsigned e, sl_interval_set& dst) { - sl_interval_set::iterator it = src.find_geq(b); - sl_interval_set::iterator end = src.end(); - for (; it != end; ++it) { - unsigned b1 = it->begin_key(); - unsigned e1 = it->end_key(); - if (e < b1) { - break; - } - if (b1 < b) { - b1 = b; - } - if (e < e1) { - e1 = e; - } - SASSERT(b <= b1 && b1 <= e1 && e1 <= e); - dst.insert(m, b1, e1); - } -} - -static void mk_interval_set_union(sl_manager_base &m, sl_interval_set& dst, sl_interval_set const& src) { - sl_interval_set::iterator it = src.begin(), end = src.end(); - for (; it != end; ++it) { - dst.insert(m, it->begin_key(), it->end_key()); - } -} - -void imdd_manager::reset_fi_intervals(sl_imanager& m) { - for (unsigned i = 0; i < m_alloc_is.size(); ++i) { - m_alloc_is[i]->deallocate(m); - dealloc(m_alloc_is[i]); - } - m_alloc_is.reset(); - m_imdd2interval_set.reset(); -} - -sl_interval_set const* imdd_manager::init_fi_intervals(sl_imanager& m, imdd* d, unsigned var, unsigned num_found) { - sl_interval_set* result = 0; -#define ALLOC_RESULT() if (!result) { result = alloc(sl_interval_set, m); m_alloc_is.push_back(result); } - if (m_imdd2interval_set.find(d, result)) { - return result; - } - bool _is_fi_var = is_fi_var(var); - unsigned new_num_found = _is_fi_var?num_found+1:num_found; - bool last_fi_var = (new_num_found == m_fi_num_vars); - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd_children::entry const & curr_entry = *it; - unsigned b = curr_entry.begin_key(); - unsigned e = curr_entry.end_key(); - - if (last_fi_var) { - ALLOC_RESULT(); - result->insert(m, b, e, 1); - } - else { - SASSERT(d->get_arity() > 1); - imdd* curr_child = curr_entry.val(); - sl_interval_set const* is2 = init_fi_intervals(m, curr_child, var+1, new_num_found); - if (!is2) { - continue; - } - if (_is_fi_var) { - sl_interval_set is3(m); - mk_interval_set_intersect(m, *is2, b, e, is3); - if (!is3.empty()) { - ALLOC_RESULT(); - mk_interval_set_union(m, *result, is3); - } - is3.deallocate(m); - } - else { - if (is2 && result != is2) { - ALLOC_RESULT(); - mk_interval_set_union(m, *result, *is2); - } - } - } - } - m_imdd2interval_set.insert(d, result); - return result; -} - -inline mk_fi_result mk(imdd * d) { - mk_fi_result r; - r.m_d = d; - return r; -} - -inline mk_fi_result mk(fi_cache_entry * e) { - mk_fi_result r; - r.m_entry = e; - return r; -} - -fi_cache_entry * imdd_manager::mk_fi_cache_entry(imdd * d, unsigned lower, unsigned upper, unsigned num_pairs, imdd_value_pair pairs[]) { - void * mem = m_fi_entries.allocate(sizeof(fi_cache_entry) + sizeof(imdd_value_pair) * num_pairs); - DEBUG_CODE({ - for (unsigned i = 0; i < num_pairs; i++) { - SASSERT(pairs[i].first != 0); - } - }); - return new (mem) fi_cache_entry(d, lower, upper, num_pairs, pairs); -} - -struct imdd_value_pair_lt_value { - bool operator()(imdd_value_pair const & p1, imdd_value_pair const & p2) const { - return p1.second < p2.second; - } -}; - -// Review note: identical nodes should be unit intervals? -// 1 -> 1 -> x - -mk_fi_result imdd_manager::mk_filter_identical_core(imdd * d, unsigned var, unsigned num_found, unsigned lower, unsigned upper, - bool destructive, bool memoize_res) { - TRACE("imdd", tout << "#" << d->get_id() << " var: " << var << " num_found: " << num_found << - " lower: " << lower << " upper: " << upper << "\n";); - - unsigned arity = d->get_arity(); -#define MK_EMPTY_ENTRY (num_found == 0 && destructive_update_at(destructive, d))?mk(static_cast(0)):mk(static_cast(0)) - sl_interval_set* node_ranges = m_imdd2interval_set.find(d); - if (!node_ranges) { - return MK_EMPTY_ENTRY; - } - sl_interval_set::iterator sl_it = node_ranges->find_geq(lower); - if (sl_it == node_ranges->end() || upper < sl_it->begin_key()) { - return MK_EMPTY_ENTRY; - } - - bool new_children_memoized = true; - bool _is_fi_var = is_fi_var(var); - if (num_found == 0) { - SASSERT(arity > 1); - if (destructive_update_at(destructive, d)) { - sbuffer to_insert; - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - if (_is_fi_var) { - fi_cache_entry * child_entry = (mk_filter_identical_core(curr_child, - var+1, - 1, - it->begin_key(), - it->end_key(), - false, - memoize_res)).m_entry; - for (unsigned i = 0; child_entry && i < child_entry->m_num_result; i++) { - imdd * new_child = child_entry->m_result[i].first; - unsigned value = child_entry->m_result[i].second; - to_insert.push_back(entry(value, value, new_child)); - } - } - else { - imdd * new_child = (mk_filter_identical_core(curr_child, var+1, 0, 0, UINT_MAX, false, memoize_res)).m_d; - if (new_child != 0) { - new_child->inc_ref(); - to_insert.push_back(entry(it->begin_key(), it->end_key(), new_child)); - } - } - } - if (to_insert.empty()) { - return mk(static_cast(0)); - } - d->replace_children(m_sl_manager, to_insert); - return mk(d); - } - else { - // num_found == 0 && variable is not part of the filter && no destructive update. - imdd * r = 0; - if (is_cached(m_fi_top_cache, d, r)) - return mk(r); - r = _mk_empty(arity); - imdd_children::push_back_proc push_back(m_sl_manager, r->m_children); - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - if (_is_fi_var) { - fi_cache_entry * entry = (mk_filter_identical_core(curr_child, - var+1, - 1, - it->begin_key(), - it->end_key(), - false, - memoize_res)).m_entry; - for (unsigned i = 0; entry && i < entry->m_num_result; i++) { - imdd * new_child = entry->m_result[i].first; - unsigned value = entry->m_result[i].second; - push_back(value, value, new_child); - if (!new_child->is_memoized()) - new_children_memoized = false; - } - } - else { - imdd * new_child = (mk_filter_identical_core(curr_child, var+1, 0, 0, UINT_MAX, false, memoize_res)).m_d; - if (new_child != 0) { - push_back(it->begin_key(), it->end_key(), new_child); - if (!new_child->is_memoized()) - new_children_memoized = false; - } - } - } - if (r->empty()) { - delete_imdd(r); - r = 0; - } - r = memoize_new_imdd_if(r && memoize_res && new_children_memoized, r); - cache_result(m_fi_top_cache, d, r); - return mk(r); - } - } - else { - SASSERT(num_found > 0); - fi_cache_entry d_entry(d, lower, upper); - fi_cache_entry * r_entry; - if (d->is_shared() && m_fi_bottom_cache.find(&d_entry, r_entry)) - return mk(r_entry); - sbuffer result; - if (_is_fi_var) { - unsigned new_num_found = num_found + 1; - bool last_fi_var = (new_num_found == m_fi_num_vars); - imdd_children::iterator it = d->m_children.find_geq(lower); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - unsigned curr_lower = it->begin_key(); - unsigned curr_upper = it->end_key(); - if (curr_lower < lower) - curr_lower = lower; - if (curr_upper > upper) - curr_upper = upper; - if (curr_lower <= curr_upper) { - if (last_fi_var) { - for (unsigned i = curr_lower; i <= curr_upper; i++) { - imdd * new_d = _mk_empty(arity); - add_child(new_d, i, curr_child); - new_d = memoize_new_imdd_if(memoize_res && (curr_child == 0 || curr_child->is_memoized()), new_d); - result.push_back(imdd_value_pair(new_d, i)); - } - } - else { - fi_cache_entry * new_entry = (mk_filter_identical_core(curr_child, - var+1, - new_num_found, - curr_lower, - curr_upper, - false, - memoize_res)).m_entry; - for (unsigned i = 0; new_entry && i < new_entry->m_num_result; i++) { - SASSERT(new_entry->m_result[i].first != 0); - imdd * curr_child = new_entry->m_result[i].first; - unsigned value = new_entry->m_result[i].second; - imdd * new_d = _mk_empty(arity); - add_child(new_d, value, curr_child); - SASSERT(curr_child != 0); - new_d = memoize_new_imdd_if(memoize_res && curr_child->is_memoized(), new_d); - result.push_back(imdd_value_pair(new_d, value)); - } - } - } - if (curr_upper == upper) - break; - } - } - else { - SASSERT(arity > 1); - u_map value2imdd; - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - SASSERT(curr_child != 0); - fi_cache_entry * new_entry = (mk_filter_identical_core(curr_child, - var+1, - num_found, - lower, - upper, - false, - memoize_res)).m_entry; - for (unsigned i = 0; new_entry && i < new_entry->m_num_result; i++) { - unsigned value = new_entry->m_result[i].second; - imdd * new_child = new_entry->m_result[i].first; - imdd * new_d = 0; - if (!value2imdd.find(value, new_d)) { - new_d = _mk_empty(arity); - value2imdd.insert(value, new_d); - result.push_back(imdd_value_pair(new_d, value)); - } - SASSERT(new_d != 0); - add_child(new_d, it->begin_key(), it->end_key(), new_child); - } - } - std::sort(result.begin(), result.end(), imdd_value_pair_lt_value()); - } - r_entry = mk_fi_cache_entry(d, lower, upper, result.size(), result.c_ptr()); - if (d->is_shared()) - m_fi_bottom_cache.insert(r_entry); - return mk(r_entry); - } -} - -imdd * imdd_manager::mk_filter_identical_main(imdd * d, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res) { - if (d->empty() || num_vars < 2) - return d; - TRACE("imdd", - tout << "vars: "; - for (unsigned i = 0; i < num_vars; ++i) { - tout << vars[i] << " "; - } - tout << "\n"; - tout << "rows: " << get_num_rows(d) << "\n"; - display_ll(tout, d); ); - unsigned arity = d->get_arity(); - DEBUG_CODE(for (unsigned i = 0; i < num_vars; ++i) SASSERT(vars[i] < arity);); - m_fi_num_vars = num_vars; - m_fi_begin_vars = vars; - m_fi_end_vars = vars + num_vars; - delay_dealloc delay(*this); - m_fi_bottom_cache.reset(); - m_fi_top_cache.reset(); - m_fi_entries.reset(); - - sl_imanager imgr; - init_fi_intervals(imgr, d, 0, 0); - - TRACE("imdd_verbose", - ptr_addr_hashtable ht; - imdd2intervals::iterator it = m_imdd2interval_set.begin(); - imdd2intervals::iterator end = m_imdd2interval_set.end(); - for (; it != end; ++it) { - tout << it->m_key->get_id() << " "; - if (it->m_value) { - if (ht.contains(it->m_value)) { - tout << "dup\n"; - continue; - } - ht.insert(it->m_value); - sl_interval_set::iterator sit = it->m_value->begin(); - sl_interval_set::iterator send = it->m_value->end(); - for (; sit != send; ++sit) { - tout << "[" << sit->begin_key() << ":" << sit->end_key() << "] "; - } - } - else { - tout << "{}"; - } - tout << "\n"; - }); - mk_fi_result r = mk_filter_identical_core(d, 0, 0, 0, UINT_MAX, destructive, memoize_res); - reset_fi_intervals(imgr); - - TRACE("imdd", if (r.m_d) display_ll(tout << "result\n", r.m_d);); - if (r.m_d == 0) - return _mk_empty(arity); - else - return r.m_d; -} - -void imdd_manager::swap_in(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars) { - // variables are sorted. - DEBUG_CODE(for (unsigned i = 0; i + 1 < num_vars; ++i) SASSERT(vars[i] < vars[i+1]);); - imdd_ref tmp1(*this), tmp2(*this); - tmp1 = d; - SASSERT(num_vars > 1); - unsigned v1 = vars[0]+1; // next position to swap to. - for (unsigned i = 1; i < num_vars; ++i) { - unsigned v2 = vars[i]; - SASSERT(v1 <= v2); - for (unsigned j = v2-1; j >= v1; --j) { - mk_swap(tmp1, tmp2, j); - tmp1 = tmp2; - } - ++v1; - } - TRACE("imdd", - for (unsigned i = 0; i < num_vars; ++i) tout << vars[i] << " "; - tout << "\n"; - display_ll(tout << "in\n", d); - display_ll(tout << "out\n", tmp1); - tout << "\n";); - r = tmp1; -} - -void imdd_manager::swap_out(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars) { - // variables are sorted. - DEBUG_CODE(for (unsigned i = 0; i + 1 < num_vars; ++i) SASSERT(vars[i] < vars[i+1]);); - imdd_ref tmp1(*this), tmp2(*this); - tmp1 = d; - SASSERT(num_vars > 1); - unsigned v1 = vars[0]+num_vars-1; // position of next variable to be swapped. - for (unsigned i = num_vars; i > 1; ) { - --i; - unsigned v2 = vars[i]; - for (unsigned j = v1; j < v2; ++j) { - mk_swap(tmp1, tmp2, j); - tmp1 = tmp2; - } - --v1; - } - TRACE("imdd", - for (unsigned i = 0; i < num_vars; ++i) tout << vars[i] << " "; - tout << "\n"; - display_ll(tout << "out\n", d); - display_ll(tout << "in\n", tmp1); - tout << "\n";); - r = tmp1; -} - -void imdd_manager::filter_identical_core2(imdd* d, unsigned num_vars, unsigned b, unsigned e, ptr_vector& ch) { - SASSERT(num_vars > 0); - imdd* r = 0; - - imdd_children::iterator it = d->m_children.find_geq(b); - imdd_children::iterator end = d->m_children.end(); - - for (; it != end; ++it) { - unsigned b1 = it->begin_key(); - unsigned e1 = it->end_key(); - if (e < b1) { - break; - } - if (b1 < b) { - b1 = b; - } - if (e <= e1) { - e1 = e; - } - SASSERT(b <= b1 && b1 <= e1 && e1 <= e); - imdd* curr_child = it->val(); - if (num_vars == 1) { - for (unsigned i = b1; i <= e1; ++i) { - r = _mk_empty(d->get_arity()); - add_child(r, i, i, it->val()); - r = memoize_new_imdd_if(!it->val() || it->val()->is_memoized(), r); - ch.push_back(r); - } - continue; - } - ptr_vector ch2; - filter_identical_core2(curr_child, num_vars-1, b1, e1, ch2); - for (unsigned i = 0; i < ch2.size(); ++i) { - r = _mk_empty(d->get_arity()); - unsigned key = ch2[i]->begin_children()->begin_key(); - SASSERT(ch2[i]->begin_children()->end_key() == key); - add_child(r, key, key, ch2[i]); - r = memoize_new_imdd_if(ch2[i]->is_memoized(), r); - ch.push_back(r); - } - } -} - -imdd* imdd_manager::filter_identical_core2(imdd* d, unsigned var, unsigned num_vars, bool memoize_res) { - imdd* r = 0; - if (m_filter_identical_cache.find(d, r)) { - return r; - } - - bool children_memoized = true; - - r = _mk_empty(d->get_arity()); - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - imdd_children::push_back_proc push_back(m_sl_manager, r->m_children); - - if (var > 0) { - for (; it != end; ++it) { - imdd* curr_child = it->val(); - imdd* new_child = filter_identical_core2(curr_child, var-1, num_vars, memoize_res); - if (new_child) { - push_back(it->begin_key(), it->end_key(), new_child); - if (!new_child->is_memoized()) { - children_memoized = false; - } - } - } - } - else { - ptr_vector ch; - - for (; it != end; ++it) { - imdd* curr_child = it->val(); - filter_identical_core2(curr_child, num_vars-1, it->begin_key(), it->end_key(), ch); - } - for (unsigned i = 0; i < ch.size(); ++i) { - unsigned key = ch[i]->begin_children()->begin_key(); - SASSERT(ch[i]->begin_children()->end_key() == key); - push_back(key, key, ch[i]); - if (!ch[i]->is_memoized()) { - children_memoized = false; - } - } - } - if (r->empty()) { - delete_imdd(r); - r = 0; - } - m_filter_identical_cache.insert(d, r); - r = memoize_new_imdd_if(r && memoize_res && children_memoized, r); - return r; -} - -void imdd_manager::filter_identical_main2(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res) { - m_filter_identical_cache.reset(); - imdd_ref tmp1(*this), tmp2(*this); - swap_in(d, tmp1, num_vars, vars); - tmp2 = filter_identical_core2(tmp1, vars[0], num_vars, memoize_res); - if (!tmp2) { - r = _mk_empty(d->get_arity()); - } - else { - swap_out(tmp2, r, num_vars, vars); - } - m_filter_identical_cache.reset(); -} - -void imdd_manager::filter_identical_main3(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res) { - for (unsigned i = 0; i+1 < num_vars; ++i) { - imdd_ref tmp(*this); - tmp = r; - filter_identical_main3(tmp, r, vars[i], false, vars[i+1], false, memoize_res); - } -} - -void imdd_manager::filter_identical_main3(imdd * d, imdd_ref& r, unsigned v1, bool del1, unsigned v2, bool del2, bool memoize_res) { - r = filter_identical_loop3(d, v1, del1, v2, del2, memoize_res); - if (r == 0) { - r = _mk_empty(d->get_arity()-del1-del2); - } - m_filter_identical_cache.reset(); -} - -imdd* imdd_manager::filter_identical_loop3(imdd * d, unsigned v1, bool del1, unsigned v2, bool del2, bool memoize_res) { - imdd* r; - if (m_filter_identical_cache.find(d, r)) { - return r; - } - if (v1 == 0) { - return filter_identical_mk_nodes(d, v2, del1, del2, memoize_res); - } - - r = _mk_empty(d->get_arity()-del1-del2); - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - imdd_children::push_back_proc push_back(m_sl_manager, r->m_children); - bool children_memoized = true; - - for (; it != end; ++it) { - imdd* curr_child = it->val(); - imdd* new_child = filter_identical_loop3(curr_child, v1-1, del1, v2-1, del2, memoize_res); - if (!new_child) { - continue; - } - if (new_child->empty()) { - delete_imdd(new_child); - continue; - } - if (!new_child->is_memoized()) { - children_memoized = false; - } - push_back(it->begin_key(), it->end_key(), new_child); - } - if (r->empty()) { - delete_imdd(r); - r = 0; - } - m_filter_identical_cache.insert(d, r); - r = memoize_new_imdd_if(r && memoize_res && children_memoized, r); - return r; -} - -void imdd_manager::merge_intervals(svector& dst, svector const& src) { - svector& tmp = m_i_nodes_tmp; - tmp.reset(); - // invariant: intervals are sorted. - for (unsigned i = 0, j = 0; i < src.size() || j < dst.size();) { - SASSERT(!(i + 1 < src.size()) || src[i].m_hi < src[i+1].m_lo); - SASSERT(!(i + 1 < dst.size()) || dst[i].m_hi < dst[i+1].m_lo); - SASSERT(!(i < src.size()) || src[i].m_lo <= src[i].m_hi); - SASSERT(!(i < dst.size()) || dst[i].m_lo <= dst[i].m_hi); - if (i < src.size() && j < dst.size()) { - if (src[i].m_lo == dst[j].m_lo) { - tmp.push_back(src[i]); - ++i; - ++j; - } - else if (src[i].m_lo < dst[j].m_lo) { - tmp.push_back(src[i]); - ++i; - } - else { - tmp.push_back(dst[j]); - ++j; - } - } - else if (i < src.size()) { - tmp.push_back(src[i]); - ++i; - } - else { - tmp.push_back(dst[j]); - ++j; - } - } - dst.reset(); - dst.append(tmp); -} - -/** - * Propagate intervals down: what intervals can reach which nodes. - */ -imdd* imdd_manager::filter_identical_mk_nodes(imdd* d, unsigned v, bool del1, bool del2, bool memoize_res) { - SASSERT(v > 0); - - TRACE("imdd", display_ll(tout << "v: " << v << "\n", d);); - - // - // (0) - // Create map d |-> [I] from nodes to ordered set of disjoint intervals that visit the node. - // - // For each level up to 'v' create a list of nodes visited - // insert to a map the set of intervals that visit the node. - // - m_nodes.reset(); - filter_id_map& nodes = m_nodes; - imdd* d1, *d2, *d3; - vector > levels; - levels.push_back(ptr_vector()); - - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - imdd* curr_child; - for (; it != end; ++it) { - curr_child = it->val(); - svector& iv = nodes.init(curr_child); - if (iv.empty()) { - levels.back().push_back(curr_child); - } - iv.push_back(interval(it->begin_key(), it->end_key())); - } - - for (unsigned j = 0; j+1 < v; ++j) { - levels.push_back(ptr_vector()); - for (unsigned i = 0; i < levels[j].size(); ++i) { - d1 = levels[j][i]; - svector& i_nodes = nodes.init(d1); - it = d1->begin_children(); - end = d1->end_children(); - for(; it != end; ++it) { - imdd* curr_child = it->val(); - svector& i_nodes2 = nodes.init(curr_child); - if (i_nodes2.empty()) { - levels[j+1].push_back(curr_child); - i_nodes2.append(i_nodes); - } - else { - merge_intervals(i_nodes2, i_nodes); - } - } - } - } - - TRACE("imdd", - for (unsigned i = 0; i < levels.size(); ++i) { - tout << "Level: " << i << "\n"; - for (unsigned j = 0; j < levels[i].size(); ++j) { - tout << levels[i][j]->get_id() << " "; - svector const& i_nodes = nodes.init(levels[i][j]); - for (unsigned k = 0; k < i_nodes.size(); ++k) { - tout << i_nodes[k].m_lo << ":" << i_nodes[k].m_hi << " "; - } - tout << "\n"; - } - } - ); - - - // - // (1) - // Intersect with children: - // - d [l1:h1:ch1][l2:h2:ch2][...] - // => produce_units: d |-> [uI1 |-> d'[uI1:ch1], uI2 |-> d''[uI2:ch1], ...] // unit intervals - // => del2: d |-> [I |-> union of ch1, ch2, .. under intersection] - // => del1 & !del2: d |-> [I |-> d'[I:ch]] // intersections of intervals. - // - - m_nodes_dd.reset(); - filter_idd_map& nodes_dd = m_nodes_dd; - SASSERT(levels.size() == v); - for (unsigned i = 0; i < levels[v-1].size(); ++i) { - d1 = levels[v-1][i]; - svector const & i_nodes = nodes.init(d1); - it = d1->begin_children(); - end = d1->end_children(); - unsigned j = 0; - svector& i_nodes_dd = nodes_dd.init(d1); - while (it != end && j < i_nodes.size()) { - unsigned lo1 = it->begin_key(); - unsigned hi1 = it->end_key(); - unsigned lo2 = i_nodes[j].m_lo; - unsigned hi2 = i_nodes[j].m_hi; - if (hi2 < lo1) { - ++j; - } - else if (hi1 < lo2) { - ++it; - } - // lo1 <= hi2 && lo2 <= hi1 - else { - curr_child = it->val(); - unsigned lo = std::max(lo1, lo2); - unsigned hi = std::min(hi1, hi2); - SASSERT(lo <= hi); - - if (!del1 && !del2) { - for (unsigned k = lo; k <= hi; ++k) { - imdd* d2 = _mk_empty(d1->get_arity()); - add_child(d2, k, k, curr_child); - i_nodes_dd.push_back(interval_dd(k, k, d2)); - } - } - else if (del2) { - i_nodes_dd.push_back(interval_dd(lo, hi, curr_child)); // retrofill after loop. - } - else { - imdd* d2 = _mk_empty(d1->get_arity()); - add_child(d2, lo, hi, curr_child); - i_nodes_dd.push_back(interval_dd(lo, hi, d2)); - } - if (hi2 <= hi) { - ++j; - } - if (hi1 <= hi) { - ++it; - } - } - } - // take union of accumulated children. - // retrofill union inside list. - if (del2) { - d2 = 0; - for (unsigned k = 0; k < i_nodes_dd.size(); ++k) { - d3 = i_nodes_dd[k].m_dd; - if (!d2) { - d2 = d3; - } - else { - d2 = mk_union_core(d2, d3, true, memoize_res); - } - } - for (unsigned k = 0; k < i_nodes_dd.size(); ++k) { - i_nodes_dd[k].m_dd = d2; - } - } - } - - TRACE("imdd", print_filter_idd(tout, nodes_dd);); - - // - // (2) - // Move up: - // d1 |-> [I1] // intervals visiting d1 - // d1 |-> [lo:hi:child] // children of d1 - // child |-> [I2 |-> child'] // current decomposition - // result: - // d3 = d1' |-> [lo:hi:child'] - // d1 |-> [I3 |-> d3] for I3 in merge of [I1] and [I2] - // - // The merge is defined as the intersection of intervals that reside in I1 and - // the fractions in I2. They are decomposed so that all intervals are covered. - // By construction I2 are contained in I1, - // but they may be overlapping among different I2. - // - - for (unsigned i = v-1; i > 0; ) { - --i; - for (unsigned j = 0; j < levels[i].size(); ++j) { - d1 = levels[i][j]; - m_i_nodes_dd.reset(); - svector i_nodes = nodes.init(d1); - svector& i_nodes_dd = nodes_dd.init(d1); - it = d1->begin_children(); - end = d1->end_children(); - unsigned num_children = 0; - for( ; it != end; ++it, ++num_children); - - m_offsets.reset(); - unsigned_vector& offsets = m_offsets; - offsets.resize(num_children); - it = d1->begin_children(); - for( ; it != end; ++it) { - curr_child = it->val(); - refine_intervals(i_nodes, nodes_dd.init(curr_child)); - } - - for (unsigned k = 0; k < i_nodes.size(); ++k) { - interval const& intv = i_nodes[k]; - d3 = _mk_empty(d1->get_arity()-del2); - it = d1->begin_children(); - for(unsigned child_id = 0; it != end; ++it, ++child_id) { - curr_child = it->val(); - svector const& ch_nodes_dd = nodes_dd.init(curr_child); - unsigned offset = offsets[child_id]; - TRACE("imdd_verbose", tout << intv.m_lo << ":" << intv.m_hi << "\n"; - for (unsigned l = offset; l < ch_nodes_dd.size(); ++l) { - tout << ch_nodes_dd[l].m_lo << ":" << ch_nodes_dd[l].m_hi << " " << ch_nodes_dd[l].m_dd->get_id() << " "; - } - tout << "\n"; - ); - - unsigned hi, lo; - d2 = 0; - while (offset < ch_nodes_dd.size() && !d2) { - lo = ch_nodes_dd[offset].m_lo; - hi = ch_nodes_dd[offset].m_hi; - if (intv.m_hi < lo) { - break; - } - if (hi < intv.m_lo) { - ++offset; - continue; - } - SASSERT(lo <= intv.m_lo); - SASSERT(intv.m_hi <= hi); - d2 = ch_nodes_dd[offset].m_dd; - if (intv.m_hi == hi) { - ++offset; - } - } - offsets[child_id] = offset; - if (d2) { - add_child(d3, it->begin_key(), it->end_key(), d2); - } - } - if (d3->empty()) { - delete_imdd(d3); - } - else { - i_nodes_dd.push_back(interval_dd(intv.m_lo, intv.m_hi, d3)); - } - } - TRACE("imdd", tout << d1->get_id() << ": "; print_interval_dd(tout, i_nodes_dd);); - - } - } - - TRACE("imdd", print_filter_idd(tout, nodes_dd);); - - // - // (3) - // Finalize: - // d |-> [I1:child] // children of d - // child |-> [I2 |-> child'] // current decomposition - // result: - // d' = union of child' // if del1 - // d' |-> [I2:child'] // if !del1 - // - - - it = d->begin_children(); - end = d->end_children(); - d1 = _mk_empty(d->get_arity()-del1-del2); - m_i_nodes_dd.reset(); - m_i_nodes_tmp.reset(); - svector& i_nodes_dd = m_i_nodes_dd; - svector& i_nodes_tmp = m_i_nodes_dd_tmp; - for (; it != end; ++it) { - curr_child = it->val(); - i_nodes_tmp.reset(); - svector const& i_nodes_dd1 = nodes_dd.init(curr_child); - for (unsigned i = 0, j = 0; i < i_nodes_dd.size() || j < i_nodes_dd1.size(); ) { - if (i < i_nodes_dd.size() && j < i_nodes_dd1.size()) { - interval_dd const& iv1 = i_nodes_dd[i]; - interval_dd const& iv2 = i_nodes_dd1[j]; - if (iv1.m_lo == iv2.m_lo) { - SASSERT(iv1.m_hi == iv2.m_hi); - SASSERT(iv1.m_dd == iv2.m_dd); - i_nodes_tmp.push_back(iv1); - ++i; - ++j; - } - else if (iv1.m_lo < iv2.m_lo) { - SASSERT(iv1.m_hi < iv2.m_lo); - i_nodes_tmp.push_back(iv1); - ++i; - } - else { - SASSERT(iv2.m_hi < iv1.m_lo); - i_nodes_tmp.push_back(iv2); - ++j; - } - } - else if (i < i_nodes_dd.size()) { - i_nodes_tmp.push_back(i_nodes_dd[i]); - ++i; - } - else if (j < i_nodes_dd1.size()) { - i_nodes_tmp.push_back(i_nodes_dd1[j]); - ++j; - } - } - i_nodes_dd.reset(); - i_nodes_dd.append(i_nodes_tmp); - } - - for (unsigned i = 0; i < i_nodes_dd.size(); ++i) { - imdd* ch = i_nodes_dd[i].m_dd; - unsigned lo = i_nodes_dd[i].m_lo; - unsigned hi = i_nodes_dd[i].m_hi; - if (del1) { - d1 = mk_union_core(d1, ch, true, memoize_res); - } - else { - add_child(d1, lo, hi, ch); - } - } - - TRACE("imdd", display_ll(tout, d1);); - - return d1; -} - - -void imdd_manager::print_interval_dd(std::ostream& out, svector const& m) { - for (unsigned i = 0; i < m.size(); ++i) { - out << m[i].m_lo << ":" << m[i].m_hi << " " << m[i].m_dd->get_id() << " "; - } - out << "\n"; -} - -void imdd_manager::print_filter_idd(std::ostream& out, filter_idd_map const& m) { - filter_idd_map::iterator it = m.begin(), end = m.end(); - for (unsigned i = 0; it != end; ++it, ++i) { - out << i << ": "; - print_interval_dd(out, *it); - } -} - -/** - \brief partition intervals of i_nodes by sub-intervals that are used in i_nodes_dd. - Assumption: - - All values covered in i_nodes_dd are present in i_nodes. -*/ - -void imdd_manager::refine_intervals(svector& i_nodes, svector const& i_nodes_dd) { - m_i_nodes.reset(); - svector& result = m_i_nodes; - unsigned sz1 = i_nodes.size(); - unsigned sz2 = i_nodes_dd.size(); - for (unsigned i = 0, j = 0; i < sz1; ++i) { - interval& iv = i_nodes[i]; - result.push_back(iv); - unsigned lo = iv.m_lo; - unsigned hi = iv.m_hi; - for (; j < sz2; ++j) { - unsigned lo1 = i_nodes_dd[j].m_lo; - unsigned hi1 = i_nodes_dd[j].m_hi; - SASSERT(lo <= hi); - SASSERT(lo1 <= hi1); - if (hi < lo1) { - break; - } - if (lo < lo1) { - result.back().m_hi = lo1-1; - result.push_back(interval(lo1, hi)); - lo = lo1; - } - SASSERT(lo1 <= lo); - if (lo > hi1) { - continue; - } - if (hi1 < hi) { - result.back().m_hi = hi1; - result.push_back(interval(hi1+1, hi)); - lo = hi1+1; - } - } - } - i_nodes.reset(); - i_nodes.append(result); -} - - - -void imdd_manager::mk_project_core(imdd * d, imdd_ref & r, unsigned var, unsigned num_found, bool memoize_res) { - unsigned arity = d->get_arity(); - bool _is_proj_var = is_proj_var(var); - - if (_is_proj_var && arity == (m_proj_num_vars - num_found)) { - r = 0; // 0 here means the unit element (aka the 0-tuple). - return; - } - - imdd * _r = 0; - if (is_cached(m_proj_cache, d, _r)) { - r = _r; - return; - } - - bool new_children_memoized = true; - if (_is_proj_var) { - SASSERT(d != 0); - SASSERT(d->get_arity() > 1); - unsigned new_var = var + 1; - unsigned new_num_found = num_found + 1; - bool found_all = new_num_found == m_proj_num_vars; - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - imdd_ref tmp_r(*this); - CTRACE("imdd", it == end, display_ll(tout, d);); - SASSERT(it != end); - for (; it != end; ++it) { - imdd_ref new_child(*this); - if (found_all) - new_child = it->val(); - else - mk_project_core(it->val(), new_child, new_var, new_num_found, memoize_res); - - if (tmp_r == 0) - tmp_r = new_child; - else - mk_union_core(tmp_r, new_child, tmp_r, memoize_res); - SASSERT(tmp_r != 0); - } - SASSERT(tmp_r != 0); - SASSERT(tmp_r->get_arity() == d->get_arity() - (m_proj_num_vars - num_found)); - r = tmp_r; - } - else { - SASSERT(num_found < m_proj_num_vars); - unsigned new_var = var+1; - _r = _mk_empty(arity - (m_proj_num_vars - num_found)); - imdd_children::push_back_proc push_back(m_sl_manager, _r->m_children); - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - SASSERT(it != end); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - imdd_ref new_child(*this); - mk_project_core(curr_child, new_child, new_var, num_found, memoize_res); - push_back(it->begin_key(), it->end_key(), new_child); - if (new_child != 0 && !new_child->is_memoized()) - new_children_memoized = false; - } - SASSERT(!_r->empty()); - _r = memoize_new_imdd_if(memoize_res && new_children_memoized, _r); - r = _r; - } - cache_result(m_proj_cache, d, r); -} - -void imdd_manager::mk_project_dupdt_core(imdd_ref & d, unsigned var, unsigned num_found, bool memoize_res) { - unsigned arity = d->get_arity(); - bool _is_proj_var = is_proj_var(var); - - if (_is_proj_var && arity == (m_proj_num_vars - num_found)) { - d = 0; // 0 here means the unit element (aka the 0-tuple). - return; - } - - if (!destructive_update_at(true, d)) { - mk_project_core(d, d, var, num_found, memoize_res); - return; - } - - if (_is_proj_var) { - SASSERT(d != 0); - SASSERT(d->get_arity() > 1); - unsigned new_var = var + 1; - unsigned new_num_found = num_found + 1; - bool found_all = new_num_found == m_proj_num_vars; - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - imdd_ref r(*this); - for (; it != end; ++it) { - imdd_ref new_child(*this); - it.take_curr_ownership(m_sl_manager, new_child); - if (!found_all) { - mk_project_dupdt_core(new_child, new_var, new_num_found, memoize_res); - } - if (r == 0) - r = new_child; - else - mk_union_core_dupdt(r, new_child, memoize_res); - } - // we traverse the children of d, and decrement the reference counter of each one of them. - d->m_children.reset_no_decref(m_sl_manager); - d = r; - SASSERT(r != 0); - SASSERT(r->get_arity() == d->get_arity() - (m_proj_num_vars - num_found)); - } - else { - SASSERT(!_is_proj_var); - sbuffer to_insert; - unsigned new_var = var+1; - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd_ref new_child(*this); - it.take_curr_ownership(m_sl_manager, new_child); - mk_project_dupdt_core(new_child, new_var, num_found, memoize_res); - if (new_child) - new_child->inc_ref(); // protect new child, since we will insert it into to_insert - to_insert.push_back(entry(it->begin_key(), it->end_key(), new_child)); - } - SASSERT(!to_insert.empty()); - d->replace_children(m_sl_manager, to_insert); - } -} - -void imdd_manager::mk_project_init(unsigned num_vars, unsigned * vars) { - m_proj_num_vars = num_vars; - m_proj_begin_vars = vars; - m_proj_end_vars = vars + num_vars; - m_proj_cache.reset(); - reset_union_cache(); -} - -void imdd_manager::mk_project_dupdt(imdd_ref & d, unsigned num_vars, unsigned * vars, bool memoize_res) { - if (num_vars == 0) { - return; - } - unsigned arity = d->get_arity(); - SASSERT(num_vars < arity); - if (d->empty()) { - d = _mk_empty(arity - num_vars); - return; - } - delay_dealloc delay(*this); - mk_project_init(num_vars, vars); - mk_project_dupdt_core(d, 0, 0, memoize_res); -} - -void imdd_manager::mk_project(imdd * d, imdd_ref & r, unsigned num_vars, unsigned * vars, bool memoize_res) { - if (num_vars == 0) { - r = d; - return; - } - unsigned arity = d->get_arity(); - SASSERT(num_vars < arity); - if (d->empty()) { - r = _mk_empty(arity - num_vars); - return; - } - delay_dealloc delay(*this); - mk_project_init(num_vars, vars); - mk_project_core(d, r, 0, 0, memoize_res); - - STRACE("imdd_trace", tout << "mk_project(0x" << d << ", 0x" << r.get() << ", "; - for (unsigned i = 0; i < num_vars; i++) tout << vars[i] << ", "; - tout << memoize_res << ");\n";); -} - -void imdd_manager::mk_join( - imdd * d1, imdd * d2, imdd_ref & r, - unsigned_vector const& vars1, unsigned_vector const& vars2, - bool memoize_res) { - SASSERT(vars1.size() == vars2.size()); - imdd_ref tmp(*this); - unsigned d1_arity = d1->get_arity(); - mk_product(d1, d2, tmp); - for (unsigned i = 0; i < vars1.size(); ++i) { - unsigned vars[2] = { vars1[i], vars2[i] + d1_arity }; - mk_filter_identical_dupdt(tmp, 2, vars); - } - r = tmp; // memoize_new_imdd_if(memoize_res, tmp); -} - -#if 0 -void imdd_manager::mk_join_project( - imdd * d1, imdd * d2, imdd_ref & r, - unsigned_vector const& vars1, unsigned_vector const& vars2, - unsigned_vector const& proj_vars, bool memoize_res) { - SASSERT(vars1.size() == vars2.size()); - imdd_ref tmp(*this); - unsigned d1_arity = d1->get_arity(); - mk_product(d1, d2, tmp); - for (unsigned i = 0; i < vars1.size(); ++i) { - unsigned vars[2] = { vars1[i], vars2[i] + d1_arity }; - mk_filter_identical(tmp, tmp, 2, vars); - } - mk_project(tmp, tmp, proj_vars.size(), proj_vars.c_ptr()); - TRACE("dl", - tout << "vars: "; - for (unsigned i = 0; i < vars1.size(); ++i) tout << vars1[i] << ":" << vars2[i] << " "; - tout << "\n"; - tout << "proj: "; - for (unsigned i = 0; i < proj_vars.size(); ++i) tout << proj_vars[i] << " "; - tout << "\n"; - tout << "arity: " << d1->get_arity() << " + " << d2->get_arity() << "\n"; - display_ll(tout << "d1\n", d1); - display_ll(tout << "d2\n", d2); - display_ll(tout << "result\n", tmp); - tout << "\n"; - ); - - r = tmp; // memoize_new_imdd_if(memoize_res, tmp); -} -#endif - - -void imdd_manager::mk_join_project( - imdd * d1, imdd * d2, imdd_ref & r, - unsigned_vector const& vars1, unsigned_vector const& vars2, - unsigned_vector const& proj_vars, bool memoize_res) { - SASSERT(vars1.size() == vars2.size()); - imdd_ref tmp(*this); - mk_product(d1, d2, tmp); - unsigned d1_arity = d1->get_arity(); - unsigned sz = tmp->get_arity(); - - // set up schedule for join-project. - unsigned_vector remap; - svector projected; - unsigned_vector ref_count; - for (unsigned i = 0; i < sz; ++i) { - remap.push_back(i); - } - projected.resize(sz, false); - ref_count.resize(sz, 0); - for (unsigned i = 0; i < proj_vars.size(); ++i) { - projected[proj_vars[i]] = true; - } - for (unsigned i = 0; i < vars1.size(); ++i) { - ref_count[vars1[i]]++; - ref_count[vars2[i]+d1_arity]++; - } - -#define UPDATE_REMAP() \ - for (unsigned i = 0, j = 0; i < sz; ++i) { \ - remap[i] = j; \ - if (!projected[i] || ref_count[i] > 0) { \ - ++j; \ - } \ - } \ - - - UPDATE_REMAP(); - // project unused variables: - unsigned_vector proj2; - for (unsigned i = 0; i < sz; ++i) { - if (projected[i] && ref_count[i] == 0) { - proj2.push_back(i); - } - } - mk_project(tmp, tmp, proj2.size(), proj2.c_ptr()); - - for (unsigned i = 0; i < vars1.size(); ++i) { - unsigned idx1 = vars1[i]; - unsigned idx2 = vars2[i]+d1_arity; - ref_count[idx1]--; - ref_count[idx2]--; - bool del1 = ref_count[idx1] == 0 && projected[idx1]; - bool del2 = ref_count[idx2] == 0 && projected[idx2]; - - filter_identical_main3(tmp, tmp, remap[idx1], del1, remap[idx2], del2, memoize_res); - if (del1 || del2) { - UPDATE_REMAP(); - } - } - TRACE("imdd", - tout << "vars: "; - for (unsigned i = 0; i < vars1.size(); ++i) tout << vars1[i] << ":" << vars2[i] << " "; - tout << "\n"; - tout << "proj: "; - for (unsigned i = 0; i < proj_vars.size(); ++i) tout << proj_vars[i] << " "; - tout << "\n"; - tout << "arity: " << d1->get_arity() << " + " << d2->get_arity() << "\n"; - display_ll(tout << "d1\n", d1); - display_ll(tout << "d2\n", d2); - display_ll(tout << "result\n", tmp); - tout << "\n"; - ); - - r = tmp; // memoize_new_imdd_if(memoize_res, tmp); -} - - - -imdd * imdd_manager::mk_swap_new_child(unsigned lower, unsigned upper, imdd * grandchild) { - if (m_swap_new_child == 0) { - m_swap_new_child = _mk_empty(grandchild == 0 ? 1 : grandchild->get_arity() + 1); - add_child(m_swap_new_child, lower, upper, grandchild); - if (grandchild && !grandchild->is_memoized()) - m_swap_granchildren_memoized = false; - inc_ref(m_swap_new_child); - } - SASSERT(m_swap_new_child != 0); - return m_swap_new_child; -} - -void imdd_manager::mk_swap_acc1_dupdt(imdd_ref & d, unsigned lower, unsigned upper, imdd * grandchild, bool memoize_res) { - SASSERT(d->get_ref_count() == 1); - sbuffer to_insert; - imdd_children::ext_iterator it; - imdd_children::ext_iterator end; - d->m_children.move_geq(it, lower); - while (it != end && lower <= upper) { - imdd_children::entry const & curr_entry = *it; - unsigned curr_entry_begin_key = curr_entry.begin_key(); - unsigned curr_entry_end_key = curr_entry.end_key(); - imdd * curr_entry_val = curr_entry.val(); - bool move_head = true; - if (upper < curr_entry_begin_key) - break; - if (lower < curr_entry_begin_key) { - to_insert.push_back(entry(lower, curr_entry_begin_key - 1, grandchild)); - lower = curr_entry_begin_key; - } - SASSERT(lower >= curr_entry_begin_key); - imdd * curr_grandchild = curr_entry_val; - imdd_ref new_grandchild(*this); - SASSERT((curr_grandchild == 0) == (grandchild == 0)); - if (curr_grandchild != 0) { - bool cover = lower == curr_entry_begin_key && upper >= curr_entry_end_key; - // If cover == true, then the curr_child is completely covered, and it is not needed anymore. - // So, we can perform a destructive update. - if (cover) { - new_grandchild = curr_grandchild; // take over the ownership of curr_grandchild - it.erase(m_sl_manager); - move_head = false; // it.erase is effectively moving the head. - mk_union_core_dupdt(new_grandchild, grandchild, memoize_res); - } - else { - mk_union_core(curr_grandchild, grandchild, new_grandchild, memoize_res); - } - if (!new_grandchild->is_memoized()) - m_swap_granchildren_memoized = false; - // protect new_grandchild, since it will be stored in to_insert. - new_grandchild->inc_ref(); - } - if (upper >= curr_entry_end_key) { - to_insert.push_back(entry(lower, curr_entry_end_key, new_grandchild)); - } - else { - to_insert.push_back(entry(lower, upper, new_grandchild)); - } - lower = curr_entry_end_key + 1; - if (move_head) - ++it; - } - svector::iterator it2 = to_insert.begin(); - svector::iterator end2 = to_insert.end(); - for (; it2 != end2; ++it2) { - imdd_children::entry const & curr_entry = *it2; - add_child(d, curr_entry.begin_key(), curr_entry.end_key(), curr_entry.val()); - if (curr_entry.val()) - curr_entry.val()->dec_ref(); // to_insert will be destroyed, so decrement ref. - } - if (lower <= upper) { - add_child(d, lower, upper, grandchild); - } - TRACE("mk_swap_bug", tout << "after mk_swap_acc1_dupt\n" << mk_ll_pp(d, *this) << "\n";); -} - -void imdd_manager::mk_swap_acc1(imdd * d, imdd_ref & r, unsigned lower, unsigned upper, imdd * grandchild, bool memoize_res) { - copy(d, r); - imdd_children::iterator it = d->m_children.find_geq(lower); - imdd_children::iterator end = d->end_children(); - for (; it != end && lower <= upper; ++it) { - imdd_children::entry const & curr_entry = *it; - if (upper < curr_entry.begin_key()) - break; - if (lower < curr_entry.begin_key()) { - SASSERT(lower <= curr_entry.begin_key() - 1); - add_child(r, lower, curr_entry.begin_key() - 1, grandchild); - lower = curr_entry.begin_key(); - } - SASSERT(lower >= curr_entry.begin_key()); - imdd * curr_grandchild = curr_entry.val(); - SASSERT((curr_grandchild == 0) == (grandchild == 0)); - imdd_ref new_curr_grandchild(*this); - mk_union_core(curr_grandchild, grandchild, new_curr_grandchild, memoize_res); - if (new_curr_grandchild && !new_curr_grandchild->is_memoized()) - m_swap_granchildren_memoized = false; - if (upper >= curr_entry.end_key()) { - add_child(r, lower, curr_entry.end_key(), new_curr_grandchild); - } - else { - SASSERT(upper < curr_entry.end_key()); - SASSERT(lower <= upper); - add_child(r, lower, upper, new_curr_grandchild); - } - lower = curr_entry.end_key() + 1; - } - if (lower <= upper) { - add_child(r, lower, upper, grandchild); - } - TRACE("mk_swap_bug", tout << "after mk_swap_acc1\n" << mk_ll_pp(r, *this) << "\n";); -} - -/** - \brief Auxiliary function for mk_swap_core -*/ -void imdd_manager::mk_swap_acc2(imdd_ref & r, unsigned lower1, unsigned upper1, unsigned lower2, unsigned upper2, imdd * grandchild, bool memoize_res) { - SASSERT((r->get_arity() == 2 && grandchild == 0) || - (r->get_arity() == grandchild->get_arity() + 2)); - SASSERT(r->get_ref_count() <= 1); // we perform destructive updates on r. - SASSERT(!r->is_memoized()); - TRACE("mk_swap_bug", - tout << mk_ll_pp(r, *this) << "\n"; - tout << "adding\n[" << lower1 << ", " << upper1 << "] -> [" << lower2 << ", " << upper2 << "] ->\n"; - tout << mk_ll_pp(grandchild, *this) << "\n";); - - sbuffer to_insert; - imdd_children::ext_iterator it; - imdd_children::ext_iterator end; - r->m_children.move_geq(it, lower1); - SASSERT(m_swap_new_child == 0); - - while(it != end && lower1 <= upper1) { - imdd_children::entry const & curr_entry = *it; - unsigned curr_entry_begin_key = curr_entry.begin_key(); - unsigned curr_entry_end_key = curr_entry.end_key(); - imdd * curr_entry_val = curr_entry.val(); - bool move_head = true; - TRACE("mk_swap_bug", tout << lower1 << " " << upper1 << " " << curr_entry_begin_key << "\n";); - if (upper1 < curr_entry_begin_key) - break; - if (lower1 < curr_entry_begin_key) { - imdd * new_child = mk_swap_new_child(lower2, upper2, grandchild); - SASSERT(lower1 <= curr_entry_begin_key - 1); - add_child(r, lower1, curr_entry_begin_key - 1, new_child); - lower1 = curr_entry_begin_key; - } - SASSERT(lower1 >= curr_entry_begin_key); - imdd * curr_child = curr_entry_val; - SASSERT(curr_child != 0); - SASSERT(!curr_child->is_memoized()); - imdd_ref new_curr_child(*this); - bool destructive = curr_child->get_ref_count() == 1 && lower1 == curr_entry_begin_key && upper1 >= curr_entry_end_key; - if (destructive) { - new_curr_child = curr_child; // take over curr_child. - it.erase(m_sl_manager); - move_head = false; // it.erase is effectively moving the head. - mk_swap_acc1_dupdt(new_curr_child, lower2, upper2, grandchild, memoize_res); - } - else { - mk_swap_acc1(curr_child, new_curr_child, lower2, upper2, grandchild, memoize_res); - } - new_curr_child->inc_ref(); // it will be stored in to_insert - if (upper1 >= curr_entry_end_key) { - to_insert.push_back(entry(lower1, curr_entry_end_key, new_curr_child)); - } - else { - to_insert.push_back(entry(lower1, upper1, new_curr_child)); - } - lower1 = curr_entry_end_key + 1; - if (move_head) - ++it; - } - svector::iterator it2 = to_insert.begin(); - svector::iterator end2 = to_insert.end(); - for (; it2 != end2; ++it2) { - imdd_children::entry const & curr_entry = *it2; - add_child(r, curr_entry.begin_key(), curr_entry.end_key(), curr_entry.val()); - SASSERT(curr_entry.val()); - curr_entry.val()->dec_ref(); // to_insert will be destroyed, so decrement ref. - } - if (lower1 <= upper1) { - imdd * new_child = mk_swap_new_child(lower2, upper2, grandchild); - add_child(r, lower1, upper1, new_child); - } - if (m_swap_new_child != 0) { - dec_ref(m_swap_new_child); - m_swap_new_child = 0; - } - TRACE("mk_swap_bug", tout << "after mk_swap_acc2\n" << mk_ll_pp(r, *this) << "\n";); -} - -/** - \brief Memoize the given IMDD assuming all grandchildren of d are memoized. -*/ -imdd * imdd_manager::mk_swap_memoize(imdd * d) { - if (d->is_memoized()) - return d; - bool children_memoized = true; - imdd * new_d = _mk_empty(d->get_arity()); - imdd_children::push_back_proc push_back(m_sl_manager, new_d->m_children); - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd * child = it->val(); - imdd * new_child = memoize(child); - if (!new_child->is_memoized()) - children_memoized = false; - push_back(it->begin_key(), it->end_key(), new_child); - } - - if (children_memoized && is_simple_node(new_d)) { - imdd * new_can_d = memoize(new_d); - if (new_can_d != new_d) { - SASSERT(new_d->get_ref_count() == 0); - delete_imdd(new_d); - } - new_d = new_can_d; - } - return new_d; -} - -/** - \brief Swap the two top vars. -*/ -void imdd_manager::mk_swap_top_vars(imdd * d, imdd_ref & r, bool memoize_res) { - SASSERT(d->get_arity() >= 2); - r = _mk_empty(d->get_arity()); - m_swap_granchildren_memoized = true; - m_swap_new_child = 0; - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - SASSERT(curr_child != 0); - SASSERT(m_swap_new_child == 0); - imdd_children::iterator it2 = curr_child->begin_children(); - imdd_children::iterator end2 = curr_child->end_children(); - for (; it2 != end2; ++it2) { - imdd * grandchild = it2->val(); - mk_swap_acc2(r, it2->begin_key(), it2->end_key(), it->begin_key(), it->end_key(), grandchild, memoize_res); - } - SASSERT(m_swap_new_child == 0); - } - - if (memoize_res && m_swap_granchildren_memoized) { - r = mk_swap_memoize(r); - } - TRACE("mk_swap_bug", tout << "result:\n" << mk_ll_pp(r, *this) << "\n";); -} - -void imdd_manager::mk_swap_core(imdd * d, imdd_ref & r, unsigned vidx, bool memoize_res) { - SASSERT(d); - unsigned arity = d->get_arity(); - SASSERT(arity > 1); - - imdd * _r = 0; - if (is_cached(m_swap_cache, d, _r)) { - r = _r; - return; - } - - if (vidx == 0) { - mk_swap_top_vars(d, r, memoize_res); - } - else { - SASSERT(vidx > 0); - bool new_children_memoized = true; - unsigned new_vidx = vidx - 1; - _r = _mk_empty(arity); - imdd_children::push_back_proc push_back(m_sl_manager, _r->m_children); - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - SASSERT(it != end); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - imdd_ref new_child(*this); - mk_swap_core(curr_child, new_child, new_vidx, memoize_res); - push_back(it->begin_key(), it->end_key(), new_child); - if (new_child != 0 && !new_child->is_memoized()) - new_children_memoized = false; - } - SASSERT(!_r->empty()); - _r = memoize_new_imdd_if(memoize_res && new_children_memoized, _r); - r = _r; - } - cache_result(m_swap_cache, d, r); -} - -void imdd_manager::mk_swap_dupdt_core(imdd_ref & d, unsigned vidx, bool memoize_res) { - SASSERT(d); - unsigned arity = d->get_arity(); - SASSERT(arity > 1); - - if (!destructive_update_at(true, d)) { - mk_swap_core(d, d, vidx, memoize_res); - return; - } - - if (vidx == 0) { - mk_swap_top_vars(d, d, memoize_res); - return; - } - - SASSERT(vidx > 0); - sbuffer to_insert; - unsigned new_vidx = vidx-1; - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd_ref new_child(*this); - it.take_curr_ownership(m_sl_manager, new_child); - mk_swap_dupdt_core(new_child, new_vidx, memoize_res); - new_child->inc_ref(); // protect new child, since we insert into to_insert - to_insert.push_back(entry(it->begin_key(), it->end_key(), new_child)); - } - SASSERT(!to_insert.empty()); - d->replace_children(m_sl_manager, to_insert); -} - -void imdd_manager::mk_swap_dupdt(imdd_ref & d, unsigned vidx, bool memoize_res) { - SASSERT(d); - unsigned arity = d->get_arity(); - SASSERT(arity > 1); - SASSERT(vidx < arity - 1); - if (d->empty()) { - return; - } - m_swap_cache.reset(); - reset_union_cache(); - delay_dealloc delay(*this); - mk_swap_dupdt_core(d, vidx, memoize_res); -} - -void imdd_manager::mk_swap(imdd * d, imdd_ref & r, unsigned vidx, bool memoize_res) { - SASSERT(d); - unsigned arity = d->get_arity(); - SASSERT(arity > 1); - SASSERT(vidx < arity - 1); - if (d->empty()) { - r = d; - return; - } - TRACE("mk_swap_bug", tout << "mk_swap: " << vidx << "\n"; display_ll(tout, d); ); - TRACE("mk_swap_bug2", tout << "mk_swap: " << vidx << "\n"; display_ll(tout, d); ); - m_swap_cache.reset(); - reset_union_cache(); - delay_dealloc delay(*this); - mk_swap_core(d, r, vidx, memoize_res); - TRACE("mk_swap_bug2", tout << "mk_swap result\n"; display_ll(tout, r); ); - STRACE("imdd_trace", tout << "mk_swap(0x" << d << ", 0x" << r.get() << ", " << vidx << ", " << memoize_res << ");\n";); -} - -imdd_manager::iterator::iterator(imdd_manager const & m, imdd const * d) { - if (d->empty()) { - m_done = true; - return; - } - m_done = false; - unsigned arity = d->get_arity(); - m_iterators.resize(arity); - m_element.resize(arity); - begin_iterators(d, 0); -} - -void imdd_manager::iterator::begin_iterators(imdd const * curr, unsigned start_idx) { - for (unsigned i = start_idx; i < get_arity(); i++) { - m_iterators[i] = curr->begin_children(); - imdd_children::iterator & it = m_iterators[i]; - SASSERT(!it.at_end()); - m_element[i] = it->begin_key(); - curr = it->val(); - } -} - -imdd_manager::iterator & imdd_manager::iterator::operator++() { - unsigned i = get_arity(); - while (i > 0) { - --i; - imdd_children::iterator & it = m_iterators[i]; - if (m_element[i] < it->end_key()) { - m_element[i]++; - begin_iterators(it->val(), i+1); - return *this; - } - else { - ++it; - if (!it.at_end()) { - m_element[i] = it->begin_key(); - begin_iterators(it->val(), i+1); - return *this; - } - } - } - m_done = true; // at end... - return *this; -} - -bool imdd_manager::iterator::operator==(iterator const & it) const { - if (m_done && it.m_done) - return true; - if (m_done || it.m_done) - return false; - if (m_element.size() != it.m_element.size()) - return false; - unsigned sz = m_element.size(); - for (unsigned i = 0; i < sz; i++) - if (m_element[i] != it.m_element[i]) - return false; - return true; -} - -bool imdd_manager::is_equal_core(imdd * d1, imdd * d2) { - if (d1 == d2) - return true; - if (d1->is_memoized() && d2->is_memoized()) - return false; - SASSERT(d1->get_arity() == d2->get_arity()); - SASSERT(!d1->empty()); - SASSERT(!d2->empty()); - bool shared = d1->is_shared() && d2->is_shared(); - bool r; - if (shared && m_is_equal_cache.find(d1, d2, r)) - return r; - - if (d1->get_arity() == 1) { - r = d1->m_children.is_equal(d2->m_children); - } - else { - imdd_children::iterator it1 = d1->begin_children(); - imdd_children::iterator end1 = d1->end_children(); - imdd_children::iterator it2 = d2->begin_children(); - imdd_children::iterator end2 = d2->end_children(); - SASSERT(it1 != end1); - SASSERT(it2 != end2); - if (it1->begin_key() != it2->begin_key()) { - r = false; - } - else { - while (true) { - if (it1 == end1) { - r = (it2 == end2); - break; - } - if (it2 == end2) { - r = (it1 == end1); - break; - } - SASSERT(it1->val() != 0 && it2->val() != 0); - if (!is_equal_core(it1->val(), it2->val())) { - r = false; - break; - } - if (it1->end_key() < it2->end_key()) { - unsigned prev_end_key = it1->end_key(); - ++it1; - if (it1 == end1 || it1->begin_key() != prev_end_key + 1) { - r = false; - break; - } - } - else if (it1->end_key() > it2->end_key()) { - unsigned prev_end_key = it2->end_key(); - ++it2; - if (it2 == end2 || it2->begin_key() != prev_end_key + 1) { - r = false; - break; - } - } - else { - SASSERT(it1->end_key() == it2->end_key()); - ++it1; - ++it2; - } - } - } - } - if (shared) - m_is_equal_cache.insert(d1, d2, r); - return r; -} - -bool imdd_manager::is_equal(imdd * d1, imdd * d2) { - if (d1 == d2) - return true; - if (d1->is_memoized() && d2->is_memoized()) - return false; - if (d1->get_arity() != d2->get_arity()) - return false; - if (d1->empty() && d2->empty()) - return true; - if (d1->empty() || d2->empty()) - return false; - SASSERT(!d1->empty()); - SASSERT(!d2->empty()); - m_is_equal_cache.reset(); - return is_equal_core(d1, d2); -} - -/** - \brief Return true if the given imdd contains the tuple (values[0], ..., values[num-1]) -*/ -bool imdd_manager::contains(imdd * d, unsigned num, unsigned const * values) const { - SASSERT(d->get_arity() == num); - imdd * curr = d; - for (unsigned i = 0; i < num; i++) { - imdd * child; - if (!curr->m_children.find(values[i], child)) - return false; - curr = child; - } - return true; -} - -inline bool overlap(unsigned b1, unsigned e1, unsigned b2, unsigned e2) { - // [b1, e1] [b2, e2] - if (e1 < b2) - return false; - // [b2, e2] [b1, e1] - if (e2 < b1) - return false; - return true; -} - -bool imdd_manager::subsumes_core(imdd * d1, imdd * d2) { - if (d1 == d2) - return true; - SASSERT(d1->get_arity() == d2->get_arity()); - SASSERT(!d1->empty()); - SASSERT(!d2->empty()); - bool shared = d1->is_shared() && d2->is_shared(); - bool r; - if (shared && m_subsumes_cache.find(d1, d2, r)) - return r; - - imdd_children::iterator it1 = d1->begin_children(); - imdd_children::iterator end1 = d1->end_children(); - imdd_children::iterator it2 = d2->begin_children(); - imdd_children::iterator end2 = d2->end_children(); - SASSERT(it1 != end1); - SASSERT(it2 != end2); - if (it1->begin_key() > it2->begin_key()) { - r = false; - goto subsumes_end; - } - - if (d1->get_arity() == 1) { - // leaf case - while(true) { - SASSERT(it1 != end1); - SASSERT(it2 != end2); - it1.move_to(it2->begin_key()); - if (it1 == end1 || - it1->begin_key() > it2->begin_key() || // missed beginning of it2 curr entry - it1->end_key() < it2->end_key() // missed end of it2 curr entry - ) { - r = false; - goto subsumes_end; - } - SASSERT(it1->end_key() >= it2->end_key()); - ++it2; - if (it2 == end2) { - r = true; - goto subsumes_end; - } - } - } - else { - // non-leaf case - while (true) { - SASSERT(it1 != end1); - SASSERT(it2 != end2); - SASSERT(it1->val() != 0); - SASSERT(it2->val() != 0); - it1.move_to(it2->begin_key()); - if (it1 == end1 || - it1->begin_key() > it2->begin_key() // missed beginning of it2 curr entry - ) { - r = false; - goto subsumes_end; - } - // the beginning of it2 is inside it1 - SASSERT(it2->begin_key() >= it1->begin_key() && it2->begin_key() <= it1->end_key()); - // it1: [ ][ ][ ] - // it2 [ ] - while (true) { - SASSERT(it1 != end1); - SASSERT(it2 != end2); - // there is a overlap between the current entry in it1 and the current entry in it2 - SASSERT(overlap(it1->begin_key(), it1->end_key(), - it2->begin_key(), it2->end_key())); - if (!subsumes_core(it1->val(), it2->val())) { - r = false; - goto subsumes_end; - } - if (it1->end_key() >= it2->end_key()) { - ++it2; // processed the whole entry in it2 - break; - } - SASSERT(it1->end_key() < it2->end_key()); - unsigned prev_end_key = it1->end_key(); - ++it1; - if (it1 == end1 || it1->begin_key() != prev_end_key + 1) { - r = false; - goto subsumes_end; - } - } - if (it2 == end2) { - r = true; - goto subsumes_end; - } - } - } - subsumes_end: - if (shared) - m_subsumes_cache.insert(d1, d2, r); - return r; -} - -/** - \brief Return true is d1 is a superset of d2, or equal to d2. -*/ -bool imdd_manager::subsumes(imdd * d1, imdd * d2) { - SASSERT(d1->get_arity() == d2->get_arity()); - if (d1 == d2) - return true; - if (d2->empty()) - return true; - if (d1->empty()) { - SASSERT(!d2->empty()); - return false; - } - SASSERT(!d1->empty()); - SASSERT(!d2->empty()); - m_subsumes_cache.reset(); - return subsumes_core(d1, d2); -} - -void imdd_manager::remove_facts_dupdt(imdd_ref & d, unsigned num, unsigned const * lowers, unsigned const * uppers) { - SASSERT(d->get_arity() == num); - d = remove_facts_main(d, num, lowers, uppers, true, true); -} - -void imdd_manager::remove_facts(imdd * d, imdd_ref & r, unsigned num, unsigned const * lowers, unsigned const * uppers) { - SASSERT(d->get_arity() == num); - r = remove_facts_main(d, num, lowers, uppers, false, true); -} - -imdd * imdd_manager::remove_facts_main(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res) { - SASSERT(d->get_arity() == num); - delay_dealloc delay(*this); - m_remove_facts_cache.reset(); - return remove_facts_core(d, num, lowers, uppers, destructive, memoize_res); -} - -imdd * imdd_manager::remove_facts_core(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res) { - SASSERT(d->get_arity() == num && num > 0); - - imdd * new_d = 0; - unsigned b = *lowers; - unsigned e = *uppers; - sbuffer to_insert, to_remove; - imdd_children::iterator it = d->m_children.find_geq(b); - imdd_children::iterator end = d->end_children(); - bool is_destructive = destructive_update_at(destructive, d); - - if (!is_destructive && is_cached(m_remove_facts_cache, d, new_d)) { - return new_d; - } - - if (num == 1) { - new_d = remove_main(d, *lowers, *uppers, destructive, memoize_res); - if (!is_destructive) { - cache_result(m_remove_facts_cache, d, new_d); - } - return new_d; - } - - if (it == end || e < it->begin_key()) { - if (!is_destructive) { - cache_result(m_remove_facts_cache, d, d); - } - return d; - } - - if (!is_destructive) { - new_d = copy_main(d); - } - else { - new_d = d; - } - for (; it != end && b <= e; ++it) { - // - // remove ([b:e]::rest), [b_key:e_key] * ch) = - // { [b_key:e_key] * ch } if e < b_key - // { [b_key:e_key] * ch' } if b <= b_key <= e_key <= e - // { [b_key:e]*ch' [e+1:e_key]*ch } if b <= b_key <= e < e_key - // { [b_key:b-1]*ch [b:e]*ch', [e+1:e_key]*ch } if b_key < b <= e < e_key - // { [b_key:b-1]*ch [b:e_key]*ch' } if b_key < b <= e_key <= e - // where - // ch' = remove(rest, ch) - // assumption: remove_child retains the cases where ch is in the tree. - // - - imdd_children::entry const & curr_entry = *it; - unsigned b_key = curr_entry.begin_key(); - unsigned e_key = curr_entry.end_key(); - imdd* curr_child = curr_entry.val(); - imdd* new_curr_child = 0; - - if (e < b_key) { - break; - } - - new_curr_child = remove_facts_core(curr_child, num-1, lowers+1, uppers+1, destructive, memoize_res); - - if (new_curr_child == curr_child) { - continue; - } - - if (new_curr_child != 0) { - if (b <= b_key && e_key <= e) { - to_insert.push_back(entry(b_key, e_key, new_curr_child)); - } - if (b <= b_key && e < e_key) { - to_insert.push_back(entry(b_key, e, new_curr_child)); - } - if (b_key < b && e < e_key) { - to_insert.push_back(entry(b, e, new_curr_child)); - } - if (b_key < b && e_key <= e) { - to_insert.push_back(entry(b, e_key, new_curr_child)); - } - } - if (is_destructive) { - to_remove.push_back(entry(b, e, 0)); - } - else { - remove_child(new_d, b, e); - } - b = e_key + 1; - } - for (unsigned i = 0; i < to_remove.size(); ++i) { - remove_child(new_d, to_remove[i].begin_key(), to_remove[i].end_key()); - } - for (unsigned i = 0; i < to_insert.size(); ++i) { - add_child(new_d, to_insert[i].begin_key(), to_insert[i].end_key(), to_insert[i].val()); - } - if (!is_destructive) { - cache_result(m_remove_facts_cache, d, new_d); - } - return new_d; -} - -void imdd_manager::display(std::ostream & out, imdd const * d, unsigned_vector & intervals, bool & first) const { - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - if (d->get_arity() == 1) { - for (; it != end; ++it) { - SASSERT(it->val() == 0); - if (first) { - first = false; - } - else { - out << ",\n "; - } - out << "("; - unsigned sz = intervals.size(); - for (unsigned i = 0; i < sz; i+=2) { - out << "[" << intervals[i] << ", " << intervals[i+1] << "]"; - out << ", "; - } - out << "[" << it->begin_key() << ", " << it->end_key() << "])"; - } - } - else { - for (; it != end; ++it) { - intervals.push_back(it->begin_key()); - intervals.push_back(it->end_key()); - display(out, it->val(), intervals, first); - intervals.pop_back(); - intervals.pop_back(); - } - } -} - -void imdd_manager::display(std::ostream & out, imdd const * d) const { - unsigned_vector intervals; - bool first = true; - out << "{"; - display(out, d, intervals, first); - out << "}"; -} - -struct display_ll_context { - typedef map, default_eq > imdd2uint; - std::ostream & m_out; - unsigned m_next_id; - imdd2uint m_map; - display_ll_context(std::ostream & out):m_out(out), m_next_id(1) {} - - void display_tabs(unsigned num_tabs) { - for (unsigned i = 0; i < num_tabs; i++) - m_out << " "; - } - - void display_node(unsigned num_tabs, imdd const * d) { - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - if (it == end) { - m_out << "{}"; - return; - } - if (d->get_arity() == 1) { - // leaf - m_out << "{"; - for (bool first = true; it != end; ++it) { - if (first) - first = false; - else - m_out << ", "; - m_out << "[" << it->begin_key() << ", " << it->end_key() << "]"; - } - m_out << "}"; - } - else { - m_out << "{\n"; - display_tabs(num_tabs); - while (it != end) { - m_out << " [" << it->begin_key() << ", " << it->end_key() << "] -> "; - display(num_tabs+1, it->val()); - ++it; - if (it != end) { - m_out << "\n"; - display_tabs(num_tabs); - } - else { - m_out << "}"; - } - } - } - m_out << (d->is_memoized() ? "*" : "") << "$" << d->memory(); - } - - void display(unsigned num_tabs, imdd const * d) { - if (d == 0) { - m_out << ""; - return; - } - unsigned id; - if (m_map.find(const_cast(d), id)) { - m_out << "#" << id; - } - else if (d->is_shared()) { - id = m_next_id; - m_next_id++; - m_map.insert(const_cast(d), id); - m_out << "#" << id << ":"; - display_node(num_tabs, d); - } - else { - display_node(num_tabs, d); - } - } -}; - -void imdd_manager::display_ll(std::ostream & out, imdd const * d) const { - display_ll_context ctx(out); - ctx.display(0, d); - out << "\n"; -} - -struct addone_proc { - unsigned m_r; - addone_proc():m_r(0) {} - void operator()(imdd * d) { m_r++; } -}; - -/** - \brief Return the number of nodes in an IMDD. - This is *not* a constant time operation. - It is linear on the size of the IMDD -*/ -unsigned imdd_manager::get_num_nodes(imdd const * d) const { - addone_proc p; - for_each(const_cast(d), p); - return p.m_r; -} - -struct addmem_proc { - unsigned m_r; - addmem_proc():m_r(0) {} - void operator()(imdd * d) { m_r += d->memory(); } -}; - -/** - \brief Return the amount of memory consumed by the given IMDD. -*/ -unsigned imdd_manager::memory(imdd const * d) const { - addmem_proc p; - for_each(const_cast(d), p); - return p.m_r; -} - -/** - \brief Return number of rows the given IMDD represents. -*/ -size_t imdd_manager::get_num_rows(imdd const* root) const { - obj_map counts; - ptr_vector todo; - todo.push_back(root); - while (!todo.empty()) { - imdd const* d = todo.back(); - if (counts.contains(d)) { - todo.pop_back(); - continue; - } - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - bool all_valid = true; - size_t count = 0, c; - for (; it != end; ++it) { - imdd const* ch = it->val(); - if (!ch) { - count += (it->end_key()-it->begin_key()+1); - } - else if (counts.find(ch, c)) { - count += c*(it->end_key()-it->begin_key()+1); - } - else { - all_valid = false; - todo.push_back(ch); - } - } - if (all_valid) { - todo.pop_back(); - counts.insert(d, count); - } - } - return counts.find(root); -} - -imdd * imdd_manager::add_bounded_var_core(imdd * d, unsigned before_vidx, unsigned lower, unsigned upper, bool destructive, bool memoize_res) { - if (d == 0) { - SASSERT(before_vidx == 0); - imdd * r = _mk_empty(1); - add_child(r, lower, upper, 0); - r = memoize_new_imdd_if(memoize_res, r); - return r; - } - imdd * r = 0; - if (is_cached(m_add_bounded_var_cache, d, r)) - return r; - if (before_vidx == 0) { - imdd * r = _mk_empty(d->get_arity() + 1); - add_child(r, lower, upper, d); - r = memoize_new_imdd_if(d->is_memoized() && memoize_res, r); - return r; - } - - if (destructive_update_at(destructive, d)) { - sbuffer to_insert; - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - imdd * new_child = add_bounded_var_core(curr_child, before_vidx-1, lower, upper, true, memoize_res); - new_child->inc_ref(); // we will be resetting d->m_children later. - to_insert.push_back(entry(it->begin_key(), it->end_key(), new_child)); - } - SASSERT(!to_insert.empty()); - d->replace_children(m_sl_manager, to_insert); - return d; - } - - bool new_children_memoized = true; - r = _mk_empty(d->get_arity() + 1); - imdd_children::push_back_proc push_back(m_sl_manager, r->m_children); - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - SASSERT(it != end); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - imdd * new_child = add_bounded_var_core(curr_child, before_vidx-1, lower, upper, false, memoize_res); - push_back(it->begin_key(), it->end_key(), new_child); - if (!new_child->is_memoized()) - new_children_memoized = false; - } - r = memoize_new_imdd_if(r && memoize_res && new_children_memoized, r); - cache_result(m_add_bounded_var_cache, d, r); - return r; -} - -/** - \brief Add a variable (bounded by lower and upper) before the variable before_var. - - That is, for each tuple (v_1, ..., v_n) in the IMDD \c d, the resultant IMDD contains the - tuples - - (v_1, ..., v_{after_vidx}, lower, ..., v_n) - (v_1, ..., v_{after_vidx}, lower+1, ..., v_n) - ... - (v_1, ..., v_{after_vidx}, upper, ..., v_n) - - This function is mainly used to implement mk_filter. - - \pre after_vidx < d->get_arity() -*/ -imdd * imdd_manager::add_bounded_var_main(imdd * d, unsigned before_vidx, unsigned lower, unsigned upper, bool destructive, bool memoize_res) { - SASSERT(before_vidx <= d->get_arity()); - if (d->empty()) - return d; - m_add_bounded_var_cache.reset(); - delay_dealloc delay(*this); - imdd * r = add_bounded_var_core(d, before_vidx, lower, upper, destructive, memoize_res); - return r; -} - -filter_cache_entry * imdd_manager::mk_filter_cache_entry(imdd * d, unsigned ctx_sz, unsigned * ctx, imdd * r) { - void * mem = m_filter_entries.allocate(filter_cache_entry::get_obj_size(ctx_sz)); - return new (mem) filter_cache_entry(d, r, ctx_sz, ctx); -} - -imdd * imdd_manager::is_mk_filter_cached(imdd * d, unsigned ctx_sz, unsigned * ctx) { - if (!d->is_shared()) - return 0; - m_filter_entries.push_scope(); - filter_cache_entry * tmp_entry = mk_filter_cache_entry(d, ctx_sz, ctx, 0); - filter_cache_entry * e = 0; - bool r = m_filter_cache.find(tmp_entry, e); - m_filter_entries.pop_scope(); - if (!r || e->m_r->is_dead()) - return 0; - return e->m_r; -} - -void imdd_manager::cache_mk_filter(imdd * d, unsigned ctx_sz, unsigned * ctx, imdd * r) { - if (d->is_shared()) { - filter_cache_entry * new_entry = mk_filter_cache_entry(d, ctx_sz, ctx, r); - m_filter_cache.insert(new_entry); - } -} - -void imdd_manager::init_mk_filter(unsigned arity, unsigned num_vars, unsigned * vars) { - m_filter_cache.reset(); - m_filter_entries.reset(); - m_filter_context.reset(); - m_filter_num_vars = num_vars; - m_filter_begin_vars = vars; - m_filter_end_vars = vars + num_vars; - DEBUG_CODE({ - for (unsigned i = 0; i < num_vars; i++) { - SASSERT(vars[i] < arity); - } - }); -} - -template -void imdd_manager::mk_filter_dupdt_core(imdd_ref & d, unsigned vidx, unsigned num_found, FilterProc & proc, bool memoize_res) { - SASSERT(!d->empty()); - - if (!destructive_update_at(true, d)) { - mk_filter_core(d, d, vidx, num_found, proc, memoize_res); - return; - } - - bool _is_filter_var = is_filter_var(vidx); - if (_is_filter_var) - num_found++; - unsigned new_vidx = vidx+1; - imdd_ref new_r(*this); - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - SASSERT(it != end); - for (; it != end; ++it) { - imdd_ref new_child(*this); - it.take_curr_ownership(m_sl_manager, new_child); // take ownership of the current child. - if (!_is_filter_var) { - mk_filter_dupdt_core(new_child, new_vidx, num_found, proc, memoize_res); - add_bounded_var_dupdt(new_child, num_found, it->begin_key(), it->end_key(), memoize_res); - if (new_r == 0) - new_r = new_child; - else - mk_union_core_dupdt(new_r, new_child, memoize_res); - } - else { - m_filter_context.push_back(it->begin_key()); - m_filter_context.push_back(it->end_key()); - if (num_found < m_filter_num_vars) { - mk_filter_dupdt_core(new_child, new_vidx, num_found, proc, memoize_res); - } - else { - proc(m_filter_context.c_ptr(), new_child, new_child, memoize_res); - } - m_filter_context.pop_back(); - m_filter_context.pop_back(); - if (new_r == 0) - new_r = new_child; - else - mk_union_core_dupdt(new_r, new_child, memoize_res); - } - } - d->m_children.reset(m_sl_manager); - d = new_r; -} - -template -void imdd_manager::mk_filter_core(imdd * d, imdd_ref & r, unsigned vidx, unsigned num_found, FilterProc & proc, bool memoize_res) { - SASSERT(!d->empty()); - - imdd * _r = is_mk_filter_cached(d, m_filter_context.size(), m_filter_context.c_ptr()); - if (_r) { - r = _r; - return; - } - - bool _is_filter_var = is_filter_var(vidx); - if (_is_filter_var) - num_found++; - unsigned new_vidx = vidx+1; - imdd_ref new_r(*this); - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - SASSERT(it != end); - for (; it != end; ++it) { - imdd * curr_child = it->val(); - imdd_ref new_child(*this); - if (!_is_filter_var) { - mk_filter_core(curr_child, new_child, new_vidx, num_found, proc, memoize_res); - imdd_ref tmp(*this); - add_bounded_var(new_child, tmp, num_found, it->begin_key(), it->end_key(), memoize_res); - if (new_r == 0) - new_r = tmp; - else - mk_union_core(new_r, tmp, new_r, memoize_res); - } - else { - m_filter_context.push_back(it->begin_key()); - m_filter_context.push_back(it->end_key()); - if (num_found < m_filter_num_vars) { - mk_filter_core(curr_child, new_child, new_vidx, num_found, proc, memoize_res); - } - else { - proc(m_filter_context.c_ptr(), curr_child, new_child, memoize_res); - } - m_filter_context.pop_back(); - m_filter_context.pop_back(); - if (new_r == 0) - new_r = new_child; - else - mk_union_core(new_r, new_child, new_r, memoize_res); - } - } - r = new_r; - cache_mk_filter(d, m_filter_context.size(), m_filter_context.c_ptr(), r); -} - -template -void imdd_manager::mk_filter_dupdt(imdd_ref & d, unsigned num_vars, unsigned * vars, FilterProc & proc, bool memoize_res) { - if (d->empty()) - return; - unsigned arity = d->get_arity(); - init_mk_filter(arity, num_vars, vars); - mk_filter_dupdt_core(d, 0, 0, proc, memoize_res); - if (d == 0) - d = _mk_empty(arity); -} - -template -void imdd_manager::mk_filter(imdd * d, imdd_ref & r, unsigned num_vars, unsigned * vars, FilterProc & proc, bool memoize_res) { - if (d->empty()) { - r = d; - return; - } - unsigned arity = d->get_arity(); - init_mk_filter(arity, num_vars, vars); - mk_filter_core(d, r, 0, 0, proc, memoize_res); - if (r == 0) - r = _mk_empty(arity); -} - -imdd * imdd_manager::mk_distinct_imdd(unsigned l1, unsigned u1, unsigned l2, unsigned u2, imdd * d, bool memoize_res) { - unsigned d_arity; - if (d == 0) { - d_arity = 0; - } - else { - d_arity = d->get_arity(); - memoize_res = memoize_res && d->is_memoized(); - } - imdd * r = _mk_empty(d_arity + 2); - imdd_children::push_back_proc push_back(m_sl_manager, r->m_children); - - TRACE("mk_distinct_imdd", tout << "STARTING: " << l1 << " " << u1 << " " << l2 << " " << u2 << "\n";); - -#define ADD_ENTRY(L1, U1, L2, U2) { \ - TRACE("mk_distinct_imdd", tout << "[" << L1 << " " << U1 << " " << L2 << " " << U2 << "]\n";); \ - imdd * new_child = _mk_empty(d_arity + 1); \ - add_child(new_child, L2, U2, d); \ - new_child = memoize_new_imdd_if(memoize_res, new_child); \ - push_back(L1, U1, new_child);} - - if (u1 < l2 || u2 < l1) { - ADD_ENTRY(l1, u1, l2, u2); // the intervals are disjoint - } - else { - if (l1 < l2) { - SASSERT(u1 >= l2); - // [l1 ... - // [l2 ... - // --> - // [l1, l2-1] X [l2, u2] - ADD_ENTRY(l1, l2-1, l2, u2); - } - - unsigned l = std::max(l1, l2); - unsigned u = std::min(u1, u2); - // [l, l] X [l2, l-1] // if l-1 >= l2 (i.e., l > l2) - // [l, l] X [l+1, u2] - // [l+1, l+1] X [l2, l] - // [l+1, l+1] X [l+2, u2] - // [l+2, l+2] X [l2, l+1] - // [l+2, l+2] X [l+3, u2] - // ... - // [u, u] X [l2, u-1] - // [u, u] X [u+1, u2] // if u+1 <= u2 (i.e., u < u2) - for (unsigned i = l; i <= u; i++) { - if (i > l2 && i < u2) { - // ADD_ENTRY(i, i, l2, i-1); - // ADD_ENTRY(i, i, i+1, u2); - imdd * new_child = _mk_empty(d_arity + 1); - add_child(new_child, l2, i-1, d); - add_child(new_child, i+1, u2, d); - new_child = memoize_new_imdd_if(memoize_res, new_child); - push_back(i, i, new_child); - } - else if (i > l2) { - SASSERT(!(i < u2)); - ADD_ENTRY(i, i, l2, i-1); - } - else if (i < u2) { - SASSERT(!(i > l2)); - ADD_ENTRY(i, i, i+1, u2); - } - } - - if (u1 > u2) { - // ... u1] - // ... u2] - // --> - // [u2+1, u1] X [l2, u2] - SASSERT(u2 >= l1); - ADD_ENTRY(u2+1, u1, l2, u2); - } - } -#undef ADD_ENTRY - - r = memoize_new_imdd_if(memoize_res, r); - return r; -} - -/** - \brief Auxiliary functor used to implement mk_filter_distinct -*/ -struct distinct_proc { - imdd_manager & m_manager; - - distinct_proc(imdd_manager & m): - m_manager(m) { - } - - void operator()(unsigned * lowers_uppers, imdd * d, imdd_ref & r, bool memoize_res) { - r = m_manager.mk_distinct_imdd(lowers_uppers[0], lowers_uppers[1], lowers_uppers[2], lowers_uppers[3], d, memoize_res); - } -}; - -void imdd_manager::mk_filter_distinct_dupdt(imdd_ref & d, unsigned v1, unsigned v2, bool memoize_res) { - unsigned vars[2] = { v1, v2 }; - distinct_proc proc(*this); - mk_filter_dupdt(d, 2, vars, proc, memoize_res); -} - -void imdd_manager::mk_filter_distinct(imdd * d, imdd_ref & r, unsigned v1, unsigned v2, bool memoize_res) { - unsigned vars[2] = { v1, v2 }; - distinct_proc proc(*this); - mk_filter(d, r, 2, vars, proc, memoize_res); - - STRACE("imdd_trace", tout << "mk_filter_distinct(0x" << d << ", 0x" << r.get() << ", " << v1 << ", " << v2 << ", " << memoize_res << ");\n";); -} - -imdd * imdd_manager::mk_disequal_imdd(unsigned l1, unsigned u1, unsigned value, imdd * d, bool memoize_res) { - unsigned d_arity; - if (d == 0) { - d_arity = 0; - } - else { - d_arity = d->get_arity(); - memoize_res = memoize_res && d->is_memoized(); - } - imdd * r = _mk_empty(d_arity + 1); - if (value < l1 || value > u1) { - add_child(r, l1, u1, d); - } - else { - SASSERT(l1 <= value && value <= u1); - if (l1 < value) { - add_child(r, l1, value-1, d); - } - if (value < u1) { - add_child(r, value+1, u1, d); - } - } - r = memoize_new_imdd_if(memoize_res, r); - return r; -} - -struct disequal_proc { - imdd_manager & m_manager; - unsigned m_value; - - disequal_proc(imdd_manager & m, unsigned v): - m_manager(m), - m_value(v) { - } - - void operator()(unsigned * lowers_uppers, imdd * d, imdd_ref & r, bool memoize_res) { - r = m_manager.mk_disequal_imdd(lowers_uppers[0], lowers_uppers[1], m_value, d, memoize_res); - } -}; - -void imdd_manager::mk_filter_disequal_dupdt(imdd_ref & d, unsigned var, unsigned value, bool memoize_res) { - unsigned vars[1] = { var }; - disequal_proc proc(*this, value); - mk_filter_dupdt(d, 1, vars, proc, memoize_res); -} - -void imdd_manager::mk_filter_disequal(imdd * d, imdd_ref & r, unsigned var, unsigned value, bool memoize_res) { - unsigned vars[1] = { var }; - disequal_proc proc(*this, value); - mk_filter(d, r, 1, vars, proc, memoize_res); - - STRACE("imdd_trace", tout << "mk_filter_disequal(0x" << d << ", 0x" << r.get() << ", " << var << ", " << value << ", " << memoize_res << ");\n";); -} - - diff --git a/src/muz_qe/imdd.h b/src/muz_qe/imdd.h deleted file mode 100644 index b2da275bf..000000000 --- a/src/muz_qe/imdd.h +++ /dev/null @@ -1,849 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - imdd.h - -Abstract: - - Interval based Multiple-valued Decision Diagrams. - -Author: - - Leonardo de Moura (leonardo) 2010-10-13. - -Revision History: - ---*/ -#ifndef _IMDD_H_ -#define _IMDD_H_ - -#include"id_gen.h" -#include"hashtable.h" -#include"map.h" -#include"obj_hashtable.h" -#include"obj_pair_hashtable.h" -#include"buffer.h" -#include"interval_skip_list.h" -#include"region.h" -#include"obj_ref.h" - -class imdd; -class imdd_manager; - -/** - \brief Manager for skip-lists used to implement IMDD nodes. -*/ -class sl_imdd_manager : public random_level_manager { - imdd_manager * m_manager; // real manager - small_object_allocator & m_alloc; - friend class imdd_manager; -public: - sl_imdd_manager(small_object_allocator & alloc):m_alloc(alloc) {} - void * allocate(size_t size) { return m_alloc.allocate(size); } - void deallocate(size_t size, void* p) { m_alloc.deallocate(size, p); } - void inc_ref_eh(imdd * v); - void dec_ref_eh(imdd * v); -}; - -#define IMDD_BUCKET_CAPACITY 128 -#define IMDD_MAX_LEVEL 32 - -typedef interval_skip_list, - IMDD_BUCKET_CAPACITY, - IMDD_MAX_LEVEL, - true, /* support ref-counting */ - sl_imdd_manager> > imdd_children; - -typedef interval_skip_list, - IMDD_BUCKET_CAPACITY, - IMDD_MAX_LEVEL, - false, - sl_manager_base > > sl_interval_set; - -/* - Notes: - - - We use reference counting for garbage collecting IMDDs nodes. - - - Each IMDD node has a "memoized" flag. If the flag is true, the we use hash-consing for this node. - - - The children of a memoized node must be memoized. - - - The children of a non-memoized node may be memoized. - - - The "memoized" flag cannot be reset after it was set. - - - The result of some operations may be cached. We only use caching for - operations processing memoized nodes. - - - For non-memoized nodes, if m_ref_count <= 1, destructive updates may be performed by some operations. - - - IMPORTANT: "memoized" flag == false doesn't imply m_ref_count <= 1. -*/ - - -/** - \brief IMDDs -*/ -class imdd { - -protected: - friend class imdd_manager; - - unsigned m_id; //!< Unique ID - unsigned m_ref_count; - unsigned m_arity:30; - unsigned m_memoized:1; - unsigned m_dead:1; - imdd_children m_children; - - void inc_ref() { - m_ref_count ++; - } - - void dec_ref() { - SASSERT(m_ref_count > 0); - m_ref_count --; - } - - void mark_as_memoized(bool flag = true) { - SASSERT(is_memoized() != flag); - m_memoized = flag; - } - - void mark_as_dead() { SASSERT(!m_dead); m_dead = true; } - - void replace_children(sl_imdd_manager & m, sbuffer & new_children); - -public: - imdd(sl_imdd_manager & m, unsigned id, unsigned arity):m_id(id), m_ref_count(0), m_arity(arity), m_memoized(false), m_dead(false), m_children(m) {} - unsigned get_id() const { return m_id; } - unsigned get_ref_count() const { return m_ref_count; } - bool is_memoized() const { return m_memoized; } - bool is_shared() const { return m_ref_count > 1; } - bool is_dead() const { return m_dead; } - unsigned get_arity() const { return m_arity; } - imdd_children::iterator begin_children() const { return m_children.begin(); } - imdd_children::iterator end_children() const { return m_children.end(); } - unsigned hc_hash() const; // hash code for hash-consing. - bool hc_equal(imdd const * other) const; // eq function for hash-consing - bool empty() const { return m_children.empty(); } - unsigned hash() const { return m_id; } - unsigned memory() const { return sizeof(imdd) + m_children.memory() - sizeof(imdd_children); } -}; - -// ----------------------------------- -// -// IMDD hash-consing -// -// ----------------------------------- - -// this is the internal hashing functor for hash-consing IMDDs. -struct imdd_hash_proc { - unsigned operator()(imdd const * d) const { return d->hc_hash(); } -}; - -// This is the internal comparison functor for hash-consing IMDDs. -struct imdd_eq_proc { - bool operator()(imdd const * d1, imdd const * d2) const { return d1->hc_equal(d2); } -}; - -typedef ptr_hashtable imdd_table; -typedef obj_hashtable imdd_cache; -typedef obj_map imdd2imdd_cache; -typedef obj_pair_map imdd_pair2imdd_cache; -typedef obj_pair_map imdd_pair2bool_cache; -typedef obj_map imdd2intervals; - -typedef std::pair imdd_value_pair; - -struct fi_cache_entry { - imdd * m_d; - unsigned m_lower; - unsigned m_upper; - unsigned m_hash; - unsigned m_num_result; - imdd_value_pair m_result[0]; - - void mk_hash() { - m_hash = hash_u_u(m_d->get_id(), hash_u_u(m_lower, m_upper)); - } - - fi_cache_entry(imdd * d, unsigned l, unsigned u): - m_d(d), - m_lower(l), - m_upper(u) { - mk_hash(); - } - - fi_cache_entry(imdd * d, unsigned l, unsigned u, unsigned num, imdd_value_pair result[]): - m_d(d), - m_lower(l), - m_upper(u), - m_num_result(num) { - mk_hash(); - memcpy(m_result, result, sizeof(imdd_value_pair)*num); - } - - unsigned hash() const { - return m_hash; - } - - bool operator==(fi_cache_entry const & other) const { - return - m_d == other.m_d && - m_lower == other.m_lower && - m_upper == other.m_upper; - } -}; - -typedef obj_hashtable imdd_fi_cache; -typedef union { - imdd * m_d; - fi_cache_entry * m_entry; -} mk_fi_result; - -struct filter_cache_entry { - imdd * m_d; - imdd * m_r; - unsigned m_hash; - unsigned m_ctx_size; - unsigned m_ctx[0]; // lower and upper bounds that are part of the context. - - static unsigned get_obj_size(unsigned ctx_size) { - return sizeof(filter_cache_entry) + ctx_size * sizeof(unsigned); - } - - void mk_hash() { - if (m_ctx_size > 0) - m_hash = string_hash(reinterpret_cast(m_ctx), m_ctx_size * sizeof(unsigned), m_d->get_id()); - else - m_hash = m_d->get_id(); - } - - filter_cache_entry(imdd * d, imdd * r, unsigned ctx_size, unsigned * ctx): - m_d(d), - m_r(r), - m_ctx_size(ctx_size) { - memcpy(m_ctx, ctx, sizeof(unsigned)*m_ctx_size); - mk_hash(); - } - - unsigned hash() const { - return m_hash; - } - - bool operator==(filter_cache_entry const & other) const { - if (m_d != other.m_d) - return false; - if (m_ctx_size != other.m_ctx_size) - return false; - for (unsigned i = 0; i < m_ctx_size; i++) - if (m_ctx[i] != other.m_ctx[i]) - return false; - return true; - } -}; - -typedef obj_hashtable imdd_mk_filter_cache; - -typedef obj_ref imdd_ref; - -class imdd_manager { - typedef imdd_children::entry entry; - small_object_allocator m_alloc; - id_gen m_id_gen; - vector m_tables; // we keep a table for each height. - sl_imdd_manager m_sl_manager; - unsigned m_simple_max_entries; //!< maximum number of entries in a "simple" node. - bool m_delay_dealloc; - ptr_vector m_to_delete; //!< list of IMDDs marked as dead. These IMDDs may still be in cache tables. - - // generic cache and todo-lists - ptr_vector m_worklist; - imdd_cache m_visited; - - void mark_as_dead(imdd * d); - void deallocate_imdd(imdd * d); - void delete_imdd(imdd * d); - - class delay_dealloc; - friend class delay_dealloc; - - class delay_dealloc { - imdd_manager & m_manager; - bool m_delay_dealloc_value; - unsigned m_to_delete_size; - public: - delay_dealloc(imdd_manager & m): - m_manager(m), - m_delay_dealloc_value(m_manager.m_delay_dealloc), - m_to_delete_size(m_manager.m_to_delete.size()) { - m_manager.m_delay_dealloc = true; - } - ~delay_dealloc(); - }; - - bool is_simple_node(imdd * d) const; - - void add_child(imdd * d, unsigned lower, unsigned upper, imdd * child) { - d->m_children.insert(m_sl_manager, lower, upper, child); - } - - void add_child(imdd * d, unsigned value, imdd * child) { - add_child(d, value, value, child); - } - - void remove_child(imdd * d, unsigned lower, unsigned upper) { - d->m_children.remove(m_sl_manager, lower, upper); - } - - imdd * copy_main(imdd * d); - - imdd * insert_main(imdd * d, unsigned b, unsigned e, bool destructive, bool memoize_res); - - imdd * remove_main(imdd * d, unsigned b, unsigned e, bool destructive, bool memoize_res); - - imdd2imdd_cache m_mk_product_cache; - struct null2imdd_proc; - struct mk_product_proc; - friend struct mk_product_proc; - imdd * mk_product_core(imdd * d1, imdd * d2, bool destructive, bool memoize); - imdd * mk_product_main(imdd * d1, imdd * d2, bool destructive, bool memoize_res); - - imdd2imdd_cache m_add_facts_cache; - ptr_vector m_add_facts_new_children; - void init_add_facts_new_children(unsigned num, unsigned const * lowers, unsigned const * uppers, bool memoize_res); - imdd * add_facts_core(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res); - imdd * add_facts_main(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res); - - imdd2imdd_cache m_remove_facts_cache; - imdd * remove_facts_core(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res); - imdd * remove_facts_main(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res); - - - imdd2imdd_cache m_defrag_cache; - imdd * defrag_core(imdd * d); - - imdd_pair2imdd_cache m_union_cache; - void push_back_entries(unsigned head, imdd_children::iterator & it, imdd_children::iterator & end, - imdd_children::push_back_proc & push_back, bool & children_memoized); - void push_back_upto(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, unsigned limit, - imdd_children::push_back_proc & push_back, bool & children_memoized); - void move_head(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, unsigned new_head); - void copy_upto(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, unsigned limit, sbuffer & result); - void reset_union_cache(); - imdd * mk_union_core(imdd * d1, imdd * d2, bool destructive, bool memoize_res); - imdd * mk_union_main(imdd * d1, imdd * d2, bool destructive, bool memoize_res); - void mk_union_core_dupdt(imdd_ref & d1, imdd * d2, bool memoize_res); - void mk_union_core(imdd * d1, imdd * d2, imdd_ref & r, bool memoize_res); - - imdd_pair2bool_cache m_is_equal_cache; - bool is_equal_core(imdd * d1, imdd * d2); - - imdd_pair2bool_cache m_subsumes_cache; - bool subsumes_core(imdd * d1, imdd * d2); - - imdd2imdd_cache m_complement_cache; - imdd * mk_complement_core(imdd * d, unsigned num, unsigned const * mins, unsigned const * maxs, bool destructive, bool memoize_res); - imdd * mk_complement_main(imdd * d, unsigned num, unsigned const * mins, unsigned const * maxs, bool destructive, bool memoize_res); - - imdd2imdd_cache m_filter_equal_cache; - imdd * mk_filter_equal_core(imdd * d, unsigned vidx, unsigned value, bool destructive, bool memoize_res); - imdd * mk_filter_equal_main(imdd * d, unsigned vidx, unsigned value, bool destructive, bool memoize_res); - - - // original - imdd2intervals m_imdd2interval_set; - ptr_vector m_alloc_is; - typedef sl_manager_base sl_imanager; - void reset_fi_intervals(sl_imanager& m); - sl_interval_set const* init_fi_intervals(sl_imanager& m, imdd* d, unsigned var, unsigned num_found); - - imdd2imdd_cache m_fi_top_cache; - imdd_fi_cache m_fi_bottom_cache; - unsigned m_fi_num_vars; - unsigned * m_fi_begin_vars; - unsigned * m_fi_end_vars; - region m_fi_entries; - bool is_fi_var(unsigned v) const { return std::find(m_fi_begin_vars, m_fi_end_vars, v) != m_fi_end_vars; } - fi_cache_entry * mk_fi_cache_entry(imdd * d, unsigned lower, unsigned upper, unsigned num_pairs, imdd_value_pair pairs[]); - mk_fi_result mk_filter_identical_core(imdd * d, unsigned offset, unsigned num_found, unsigned lower, unsigned upper, - bool destructive, bool memoize_res); - imdd * mk_filter_identical_main(imdd * d, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res); - - // v2 - obj_map m_filter_identical_cache; - void filter_identical_core2(imdd* d, unsigned num_vars, unsigned b, unsigned e, ptr_vector& ch); - imdd* filter_identical_core2(imdd* d, unsigned var, unsigned num_vars, bool memoize_res); - void filter_identical_main2(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res); - void swap_in(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars); - void swap_out(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars); - - // v3 - struct interval { - unsigned m_lo; - unsigned m_hi; - interval(unsigned lo, unsigned hi): m_lo(lo), m_hi(hi) {} - }; - struct interval_dd : public interval { - imdd* m_dd; - interval_dd(unsigned lo, unsigned hi, imdd* d): interval(lo, hi), m_dd(d) {} - }; - template - class id_map { - unsigned m_T; - unsigned_vector m_Ts; - svector*> m_vecs; - unsigned_vector m_alloc; - unsigned m_first_free; - void hard_reset() { - std::for_each(m_vecs.begin(), m_vecs.end(), delete_proc >()); - m_alloc.reset(); - m_first_free = 0; - m_vecs.reset(); - m_Ts.reset(); - m_T = 0; - } - - void allocate_entry(unsigned id) { - if (m_vecs[id]) { - return; - } - while (m_first_free < m_alloc.size()) { - if (m_vecs[m_first_free] && m_Ts[m_first_free] < m_T) { - svector* v = m_vecs[m_first_free]; - m_vecs[m_first_free] = 0; - m_vecs[id] = v; - ++m_first_free; - return; - } - ++m_first_free; - } - m_vecs[id] = alloc(svector); - m_alloc.push_back(id); - } - public: - id_map():m_T(0) {} - ~id_map() { hard_reset(); } - void reset() { ++m_T; m_first_free = 0; if (m_T == UINT_MAX) hard_reset(); } - svector& init(imdd* d) { - unsigned id = d->get_id(); - if (id >= m_vecs.size()) { - m_vecs.resize(id+1); - m_Ts.resize(id+1); - } - if (m_Ts[id] < m_T) { - allocate_entry(id); - m_vecs[id]->reset(); - m_Ts[id] = m_T; - } - return *m_vecs[id]; - } - - typedef svector data; - struct iterator { - unsigned m_offset; - id_map const& m; - iterator(unsigned o, id_map const& m):m_offset(o),m(m) {} - data const & operator*() const { return *m.m_vecs[m_offset]; } - data const * operator->() const { return &(operator*()); } - data * operator->() { return &(operator*()); } - iterator & operator++() { ++m_offset; return move_to_used(); } - iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; } - bool operator==(iterator const & it) const { return m_offset == it.m_offset; } - bool operator!=(iterator const & it) const { return m_offset != it.m_offset; } - iterator & move_to_used() { - while (m_offset < m.m_vecs.size() && - m.m_Ts[m_offset] < m.m_T) { - ++m_offset; - } - return *this; - } - }; - iterator begin() const { return iterator(0, *this).move_to_used(); } - iterator end() const { return iterator(m_vecs.size(), *this); } - }; - typedef id_map filter_id_map; - typedef id_map filter_idd_map; - filter_id_map m_nodes; - filter_idd_map m_nodes_dd; - svector m_i_nodes_dd, m_i_nodes_dd_tmp; - svector m_i_nodes, m_i_nodes_tmp; - unsigned_vector m_offsets; - void filter_identical_main3(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res); - void filter_identical_main3(imdd * d, imdd_ref& r, unsigned v1, bool del1, unsigned v2, bool del2, bool memoize_res); - imdd* filter_identical_loop3(imdd * d, unsigned v1, bool del1, unsigned v2, bool del2, bool memoize_res); - void refine_intervals(svector& i_nodes, svector const& i_nodes_dd); - void merge_intervals(svector& dst, svector const& src); - imdd* filter_identical_mk_nodes(imdd* d, unsigned v, bool del1, bool del2, bool memoize_res); - void print_filter_idd(std::ostream& out, filter_idd_map const& m); - void print_interval_dd(std::ostream& out, svector const& m); - - - - unsigned m_proj_num_vars; - unsigned * m_proj_begin_vars; - unsigned * m_proj_end_vars; - imdd2imdd_cache m_proj_cache; - bool is_proj_var(unsigned v) const { return std::find(m_proj_begin_vars, m_proj_end_vars, v) != m_proj_end_vars; } - void mk_project_init(unsigned num_vars, unsigned * vars); - void mk_project_core(imdd * d, imdd_ref & r, unsigned var, unsigned num_found, bool memoize_res); - void mk_project_dupdt_core(imdd_ref & d, unsigned var, unsigned num_found, bool memoize_res); - - imdd2imdd_cache m_swap_cache; - imdd * m_swap_new_child; - bool m_swap_granchildren_memoized; - imdd * mk_swap_new_child(unsigned lower, unsigned upper, imdd * child); - void mk_swap_acc1_dupdt(imdd_ref & d, unsigned lower, unsigned upper, imdd * grandchild, bool memoize_res); - void mk_swap_acc1(imdd * d, imdd_ref & r, unsigned lower, unsigned upper, imdd * grandchild, bool memoize_res); - void mk_swap_acc2(imdd_ref & r, unsigned lower1, unsigned upper1, unsigned lower2, unsigned upper2, imdd * grandchild, bool memoize_res); - void mk_swap_top_vars(imdd * d, imdd_ref & r, bool memoize_res); - imdd * mk_swap_memoize(imdd * d); - void mk_swap_core(imdd * d, imdd_ref & r, unsigned vidx, bool memoize_res); - void mk_swap_dupdt_core(imdd_ref & d, unsigned vidx, bool memoize_res); - - imdd2imdd_cache m_add_bounded_var_cache; - imdd * add_bounded_var_core(imdd * d, unsigned before_vidx, unsigned lower, unsigned upper, bool destructive, bool memoize_res); - imdd * add_bounded_var_main(imdd * d, unsigned before_vidx, unsigned lower, unsigned upper, bool destructive, bool memoize_res); - - friend struct distinct_proc; - imdd * mk_distinct_imdd(unsigned l1, unsigned u1, unsigned l2, unsigned u2, imdd * d, bool memoize_res = true); - - imdd_mk_filter_cache m_filter_cache; - region m_filter_entries; - unsigned m_filter_num_vars; - unsigned * m_filter_begin_vars; - unsigned * m_filter_end_vars; - unsigned_vector m_filter_context; - bool is_filter_var(unsigned v) const { return std::find(m_filter_begin_vars, m_filter_end_vars, v) != m_filter_end_vars; } - filter_cache_entry * mk_filter_cache_entry(imdd * d, unsigned ctx_sz, unsigned * ctx, imdd * r); - imdd * is_mk_filter_cached(imdd * d, unsigned ctx_sz, unsigned * ctx); - void cache_mk_filter(imdd * d, unsigned ctx_sz, unsigned * ctx, imdd * r); - void init_mk_filter(unsigned arity, unsigned num_vars, unsigned * vars); - template - void mk_filter_dupdt_core(imdd_ref & d, unsigned vidx, unsigned num_found, FilterProc & proc, bool memoize_res); - template - void mk_filter_core(imdd * d, imdd_ref & r, unsigned vidx, unsigned num_found, FilterProc & proc, bool memoize_res); - /** - \brief Filter the elements of the given IMDD using the given filter. - - The FilterProc template parameter is a filter for computing subsets of sets of the form: - - [L_1, U_1] X [L_2, U_2] X ... X [L_n, U_n] X d (where d is an IMDD) - - where n == num_vars - - The subset of elements is returned as an IMDD. - - FilterProc must have a method of the form: - - void operator()(unsigned * lowers_uppers, imdd * d, imdd_ref & r, bool memoize_res); - - The size of the array lowers_uppers is 2*num_vars - - The arity of the resultant IMDD must be num_vars + d->get_arity(). - */ - template - void mk_filter_dupdt(imdd_ref & d, unsigned num_vars, unsigned * vars, FilterProc & proc, bool memoize_res = true); - template - void mk_filter(imdd * d, imdd_ref & r, unsigned num_vars, unsigned * vars, FilterProc & proc, bool memoize_res = true); - - imdd * mk_disequal_imdd(unsigned l1, unsigned u1, unsigned value, imdd * d, bool memoize_res); - friend struct disequal_proc; - -public: - imdd_manager(); - - void inc_ref(imdd * d) { - if (d) - d->inc_ref(); - } - - void dec_ref(imdd * d) { - if (d) { - d->dec_ref(); - if (d->get_ref_count() == 0) - delete_imdd(d); - } - } - - unsigned get_num_nodes(imdd const * d) const; - - // count number of keys (rows) in table as if table is uncompressed. - size_t get_num_rows(imdd const* d) const; - - unsigned memory(imdd const * d) const; - -private: - imdd * _mk_empty(unsigned arity); - -public: - imdd * mk_empty(unsigned arity) { - imdd * r = _mk_empty(arity); - STRACE("imdd_trace", tout << "mk_empty(" << arity << ", 0x" << r << ");\n";); - return r; - } - -private: - imdd * memoize(imdd * d); - -public: - void memoize(imdd_ref const & d, imdd_ref & r) { r = memoize(d.get()); } - - void memoize(imdd_ref & d) { d = memoize(d.get()); } - - imdd * memoize_new_imdd_if(bool cond, imdd * r) { - if (cond && is_simple_node(r)) { - SASSERT(!r->is_shared()); - imdd * can_r = memoize(r); - if (can_r != r) { - SASSERT(r->get_ref_count() == 0); - delete_imdd(r); - } - return can_r; - } - return r; - } - -public: - void defrag(imdd_ref & d); - - void unmemoize(imdd * d); - - void unmemoize_rec(imdd * d); - - void copy(imdd * d, imdd_ref & r) { r = copy_main(d); } - - void insert_dupdt(imdd_ref & d, unsigned b, unsigned e, bool memoize_res = true) { - d = insert_main(d, b, e, true, memoize_res); - } - - void insert(imdd * d, imdd_ref & r, unsigned b, unsigned e, bool memoize_res = true) { - r = insert_main(d, b, e, false, memoize_res); - } - - void mk_product_dupdt(imdd_ref & d1, imdd * d2, bool memoize_res = true) { - d1 = mk_product_main(d1.get(), d2, true, memoize_res); - } - - void mk_product(imdd * d1, imdd * d2, imdd_ref & r, bool memoize_res = true) { - r = mk_product_main(d1, d2, false, memoize_res); - STRACE("imdd_trace", tout << "mk_product(0x" << d1 << ", 0x" << d2 << ", 0x" << r.get() << ", " << memoize_res << ");\n";); - } - - void mk_union_dupdt(imdd_ref & d1, imdd * d2, bool memoize_res = true) { - d1 = mk_union_main(d1.get(), d2, true, memoize_res); - } - - void mk_union(imdd * d1, imdd * d2, imdd_ref & r, bool memoize_res = true) { - r = mk_union_main(d1, d2, false, memoize_res); - STRACE("imdd_trace", tout << "mk_union(0x" << d1 << ", 0x" << d2 << ", 0x" << r.get() << ", " << memoize_res << ");\n";); - } - - void mk_complement_dupdt(imdd_ref & d, unsigned num, unsigned const * mins, unsigned const * maxs, bool memoize_res = true) { - d = mk_complement_main(d, num, mins, maxs, true, memoize_res); - } - - void mk_complement(imdd * d, imdd_ref & r, unsigned num, unsigned const * mins, unsigned const * maxs, bool memoize_res = true) { - r = mk_complement_main(d, num, mins, maxs, false, memoize_res); - - STRACE("imdd_trace", tout << "mk_complement(0x" << d << ", 0x" << r.get() << ", "; - for (unsigned i = 0; i < num; i++) tout << mins[i] << ", " << maxs[i] << ", "; - tout << memoize_res << ");\n";); - } - - void mk_filter_equal_dupdt(imdd_ref & d, unsigned vidx, unsigned value, bool memoize_res = true) { - d = mk_filter_equal_main(d, vidx, value, true, memoize_res); - } - - void mk_filter_equal(imdd * d, imdd_ref & r, unsigned vidx, unsigned value, bool memoize_res = true) { - r = mk_filter_equal_main(d, vidx, value, false, memoize_res); - - STRACE("imdd_trace", tout << "mk_filter_equal(0x" << d << ", 0x" << r.get() << ", " << vidx << ", " << value << ", " << memoize_res << ");\n";); - } - - void mk_filter_identical_dupdt(imdd_ref & d, unsigned num_vars, unsigned * vars, bool memoize_res = true) { - // d = mk_filter_identical_main(d, num_vars, vars, true, memoize_res); - filter_identical_main3(d, d, num_vars, vars, true, memoize_res); - } - - void mk_filter_identical(imdd * d, imdd_ref & r, unsigned num_vars, unsigned * vars, bool memoize_res = true) { - filter_identical_main3(d, r, num_vars, vars, false, memoize_res); - - STRACE("imdd_trace", tout << "mk_filter_identical(0x" << d << ", 0x" << r.get() << ", "; - for (unsigned i = 0; i < num_vars; i++) tout << vars[i] << ", "; - tout << memoize_res << ");\n";); - } - - void mk_project_dupdt(imdd_ref & d, unsigned num_vars, unsigned * vars, bool memoize_res = true); - - void mk_project(imdd * d, imdd_ref & r, unsigned num_vars, unsigned * vars, bool memoize_res = true); - - // swap vidx and vidx+1 - void mk_swap_dupdt(imdd_ref & d, unsigned vidx, bool memoize_res = true); - - // swap vidx and vidx+1 - void mk_swap(imdd * d, imdd_ref & r, unsigned vidx, bool memoize_res = true); - - void add_facts_dupdt(imdd_ref & d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool memoize_res = true) { - d = add_facts_main(d, num, lowers, uppers, true, memoize_res); - } - - void add_facts(imdd * d, imdd_ref & r, unsigned num, unsigned const * lowers, unsigned const * uppers, bool memoize_res = true) { - r = add_facts_main(d, num, lowers, uppers, false, memoize_res); - - STRACE("imdd_trace", tout << "add_facts(0x" << d << ", 0x" << r.get() << ", "; - for (unsigned i = 0; i < num; i++) tout << lowers[i] << ", " << uppers[i] << ", "; - tout << memoize_res << ");\n";); - } - - void add_fact_dupdt(imdd_ref & d, unsigned num, unsigned const * values, bool memoize_res = true) { - add_facts_dupdt(d, num, values, values, memoize_res); - } - - void add_fact(imdd * d, imdd_ref & r, unsigned num, unsigned const * values, bool memoize_res = true) { - add_facts(d, r, num, values, values, memoize_res); - } - - void add_bounded_var_dupdt(imdd_ref & d, unsigned before_vidx, unsigned lower, unsigned upper, bool memoize_res = true) { - d = add_bounded_var_main(d, before_vidx, lower, upper, true, memoize_res); - } - - void add_bounded_var(imdd * d, imdd_ref & r, unsigned before_vidx, unsigned lower, unsigned upper, bool memoize_res = true) { - r = add_bounded_var_main(d, before_vidx, lower, upper, false, memoize_res); - } - - void mk_filter_distinct_dupdt(imdd_ref & d, unsigned v1, unsigned v2, bool memoize_res = true); - - void mk_filter_distinct(imdd * d, imdd_ref & r, unsigned v1, unsigned v2, bool memoize_res = true); - - void mk_filter_disequal_dupdt(imdd_ref & d, unsigned var, unsigned value, bool memoize_res = true); - - void mk_filter_disequal(imdd * d, imdd_ref & r, unsigned var, unsigned value, bool memoize_res = true); - - void mk_join(imdd * d1, imdd * d2, imdd_ref & r, unsigned_vector const& vars1, unsigned_vector const& vars2, bool memoize_res = true); - - void mk_join_project(imdd * d1, imdd * d2, imdd_ref & r, - unsigned_vector const& vars1, unsigned_vector const& vars2, - unsigned_vector const& proj_vars, bool memoize_res = true); - - void mk_join_dupdt(imdd_ref & d1, imdd * d2, unsigned num_vars, unsigned const * vars1, unsigned const * vars2, bool memoize_res = true); - - void remove_facts_dupdt(imdd_ref & d, unsigned num, unsigned const * lowers, unsigned const * uppers); - - void remove_facts(imdd * d, imdd_ref & r, unsigned num, unsigned const * lowers, unsigned const * uppers); - - bool is_equal(imdd * d1, imdd * d2); - - bool contains(imdd * d, unsigned num, unsigned const * values) const; - - bool contains(imdd * d, unsigned v) const { return contains(d, 1, &v); } - - bool contains(imdd * d, unsigned v1, unsigned v2) const { unsigned vs[2] = {v1, v2}; return contains(d, 2, vs); } - - bool contains(imdd * d, unsigned v1, unsigned v2, unsigned v3) const { unsigned vs[3] = {v1,v2,v3}; return contains(d, 3, vs); } - - bool subsumes(imdd * d1, imdd * d2); - - bool is_subset(imdd * d1, imdd * d2) { return subsumes(d2, d1); } - -private: - void display(std::ostream & out, imdd const * d, unsigned_vector & intervals, bool & first) const; - -public: - void display(std::ostream & out, imdd const * d) const; - - void display_ll(std::ostream & out, imdd const * d) const; - - /** - \brief Execute proc (once) in each node in the IMDD rooted by d. - */ - template - void for_each(imdd * d, Proc & proc) const { - // for_each is a generic procedure, we don't know what proc will actually do. - // So, it is not safe to reuse m_worklist and m_visited. - ptr_buffer worklist; - imdd_cache visited; - worklist.push_back(d); - while (!worklist.empty()) { - d = worklist.back(); - worklist.pop_back(); - if (d->is_shared() && visited.contains(d)) - continue; - if (d->is_shared()) - visited.insert(d); - proc(d); - if (d->get_arity() > 1) { - imdd_children::iterator it = d->begin_children(); - imdd_children::iterator end = d->end_children(); - for (; it != end; ++it) - worklist.push_back(it->val()); - } - } - } - - class iterator { - bool m_done; - svector m_iterators; - svector m_element; - - void begin_iterators(imdd const * curr, unsigned start_idx); - - public: - iterator():m_done(true) {} - iterator(imdd_manager const & m, imdd const * d); - - unsigned get_arity() const { return m_element.size(); } - unsigned * operator*() const { return m_element.c_ptr(); } - iterator & operator++(); - - bool operator==(iterator const & it) const; - bool operator!=(iterator const & it) const { return !operator==(it); } - }; - - friend class iterator; - - iterator begin(imdd const * d) const { return iterator(*this, d); } - iterator end(imdd const * d) const { return iterator(); } -}; - -inline std::ostream & operator<<(std::ostream & out, imdd_ref const & r) { - r.get_manager().display(out, r.get()); - return out; -} - -struct mk_imdd_pp { - imdd * m_d; - imdd_manager & m_manager; - mk_imdd_pp(imdd * d, imdd_manager & m):m_d(d), m_manager(m) {} -}; - -inline mk_imdd_pp mk_pp(imdd * d, imdd_manager & m) { - return mk_imdd_pp(d, m); -} - -inline std::ostream & operator<<(std::ostream & out, mk_imdd_pp const & pp) { - pp.m_manager.display(out, pp.m_d); - return out; -} - -struct mk_imdd_ll_pp : public mk_imdd_pp { - mk_imdd_ll_pp(imdd * d, imdd_manager & m):mk_imdd_pp(d, m) {} -}; - -inline mk_imdd_ll_pp mk_ll_pp(imdd * d, imdd_manager & m) { - return mk_imdd_ll_pp(d, m); -} - -inline std::ostream & operator<<(std::ostream & out, mk_imdd_ll_pp const & pp) { - pp.m_manager.display_ll(out, pp.m_d); - return out; -} - -#endif /* _IMDD_H_ */ - diff --git a/src/muz_qe/interval_skip_list.h b/src/muz_qe/interval_skip_list.h deleted file mode 100644 index 7865e6ca5..000000000 --- a/src/muz_qe/interval_skip_list.h +++ /dev/null @@ -1,1876 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - interval_skip_list.h - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2010-10-01. - -Revision History: - ---*/ -#ifndef _INTERVAL_SKIP_LIST_H_ -#define _INTERVAL_SKIP_LIST_H_ - -#include"skip_list_base.h" - -/* - Interval skip lists implement a mapping from keys to values. - The key must be a total order. - - It compress consecutive entries k->v and (k+1)->v by - using intervals. Internally, we have [k1, k2]->v to represent - the set of entries k1->v, (k1+1)->v, ..., k2->v. - - For improving cache behavior, the entries are packed in - buckets. As regular skip-lists, a node/bucket may have - several next/forward pointers. - - Interval skip lists can also encode sets. In this case, - there is no value type. We achieve that by allowing the template - to be instantiated with an arbitrary "entry" class for encoding - [k1, k2]->v. This class must provide the methods: - - key const & begin_key() const - key const & end_key() const - value const & val() const - void set_begin_key(key const & k) - void set_end_key(key const & k) - void set_val(value const & v) - void display(ostream & out) const - bool operator==(entry const & other) const; - - And a definition for the key and value types. -*/ - -/** - \brief Default interval_skip_list entry. - It is useful for implementing mappings. -*/ -template -class default_islist_entry { -public: - typedef Key key; - typedef Value value; -private: - key m_begin_key; - key m_end_key; - value m_value; -public: - default_islist_entry() {} - default_islist_entry(key const & b, key const & e, value const & v): - m_begin_key(b), - m_end_key(e), - m_value(v) { - } - key const & begin_key() const { return m_begin_key; } - key const & end_key() const { return m_end_key; } - value const & val() const { return m_value; } - void set_begin_key(key const & k) { m_begin_key = k; } - void set_end_key(key const & k) { m_end_key = k; } - void set_val(value const & v) { m_value = v; } - void display(std::ostream & out) const { - out << "[" << begin_key() << ", " << end_key() << "] -> " << val(); - } -}; - -/** - \brief Default interval_skip_list entry for encoding sets. -*/ -template -struct default_set_islist_entry { -public: - typedef Key key; - typedef unsigned value; // don't care type -private: - key m_begin_key; - key m_end_key; -public: - default_set_islist_entry() {} - default_set_islist_entry(key const & b, key const & e): - m_begin_key(b), - m_end_key(e) { - } - key const & begin_key() const { return m_begin_key; } - key const & end_key() const { return m_end_key; } - unsigned const & val() const { static unsigned v = 0; return v; } - void set_begin_key(key const & k) { m_begin_key = k; } - void set_end_key(key const & k) { m_end_key = k; } - void set_val(value const & v) { /* do nothing */ } - void display(std::ostream & out) const { - out << "[" << begin_key() << ", " << end_key() << "]"; - } -}; - - -/** - \brief An interval skip list. - - See comments at skip_list_base.h -*/ -template -class interval_skip_list : public skip_list_base { -protected: - typedef typename skip_list_base::bucket bucket; -public: - typedef typename Traits::manager manager; - typedef typename Traits::entry entry; - typedef typename entry::key key; - typedef typename entry::value value; - -protected: - bool lt(key const & k1, key const & k2) const { return skip_list_base::lt(k1, k2); } - - static key const & first_key(bucket const * bt) { return bt->first_entry().begin_key(); } - - static key const & last_key(bucket const * bt) { return bt->last_entry().end_key(); } - - static void set_entry(bucket * bt, unsigned idx, key const & b, key const & e, value const & v) { - entry & en = bt->get(idx); - en.set_begin_key(b); - en.set_end_key(e); - en.set_val(v); - } - - /** - \brief Add first entry to the list. - - \remark This method will invoke inc_ref_eh for v. - */ - void insert_first_entry(manager & m, key const & b, key const & e, value const & v) { - entry en; - en.set_begin_key(b); - en.set_end_key(e); - en.set_val(v); - skip_list_base::insert_first_entry(m, en); - } - - /** - \brief Return true if the given key \c k is in the entry \c e. That is, - k \in [e.begin_key(), e.end_key()]. - */ - bool contains(entry const & e, key const & k) const { return this->leq(e.begin_key(), k) && this->leq(k, e.end_key()); } - - /** - \brief Return true if the given key \c k is in the entry \c e. That is, - k \in [e.begin_key(), e.end_key()]. If that is the case, then store e.value() in v. - Otherwise, return false. - */ - bool contains(entry const & e, key const & k, value & v) const { - if (contains(e, k)) { - v = e.val(); - return true; - } - else { - return false; - } - } - - /** - \brief Search for a key in a bucket starting at position s_idx using binary search. - - Return true if k was found in the bucket and store the index of - the entry containing \c k in \c idx. - - Otherwise, return false and \c idx will contain the index - s.t. - (idx == s_idx || entry[idx-1].end_key() < k) && (idx == bt->size() || k < entry[idx].begin_key()) - */ - bool find_core(bucket const * bt, unsigned s_idx, key const & k, unsigned & idx) const { - if (s_idx >= bt->size()) { - idx = s_idx; - return false; - } - int low = s_idx; - int high = bt->size() - 1; - for (;;) { - int mid = low + ((high - low) / 2); - entry const & mid_entry = bt->get(mid); - if (this->gt(k, mid_entry.end_key())) { - low = mid + 1; - if (low > high) { - idx = static_cast(mid) + 1; - SASSERT(idx >= s_idx); - SASSERT(idx == s_idx || lt(bt->get(idx - 1).end_key(), k)); - SASSERT(idx == bt->size() || lt(k, bt->get(idx).begin_key())); - return false; - } - - } - else if (lt(k, mid_entry.begin_key())) { - high = mid - 1; - if (low > high) { - idx = static_cast(mid); - SASSERT(idx >= s_idx); - SASSERT(idx == s_idx || lt(bt->get(idx - 1).end_key(), k)); - SASSERT(idx == bt->size() || lt(k, bt->get(idx).begin_key())); - return false; - } - } - else { - SASSERT(contains(mid_entry, k)); - SASSERT(mid >= 0); - idx = static_cast(mid); - SASSERT(idx >= s_idx); - return true; - } - } - } - - /** - \brief Search for a key in a bucket using binary search. - - Return true if k was found in the bucket and store the index of - the entry containing \c k in \c idx. - - Otherwise, return false and \c idx will contain the index - s.t. - (idx == 0 || entry[idx-1].end_key() < k) && (idx == bt->size() || k < entry[idx].begin_key() - */ - bool find_core(bucket const * bt, key const & k, unsigned & idx) const { - bool r = find_core(bt, 0, k, idx); - SASSERT(!r || contains(bt->get(idx), k)); - SASSERT( r || idx == 0 || lt(bt->get(idx - 1).end_key(), k)); - SASSERT( r || idx == bt->size() || lt(k, bt->get(idx).begin_key())); - return r; - } - - /** - \brief Search for the given key in the interval skip list. - Return true if the key is stored in the list, and store the location of the entry that contains the k in the - pair (bt, idx). The location should be read as the key is in the entry idx of the bucket bt. - Otherwise, returns false and (bt, idx) contains: - Case 1: bt != 0 && 0 < idx < bt->size() && bt->get(idx-1).end_key() < k && k < bt->get(idx).begin_key() - Case 2: bt != 0 && idx == 0 && (pred_bucket(bt) == m_header || last_key(pred_bucket(bt)) < k) && k < first_key(bt) - Case 3: bt == 0 && idx == 0 && k is greater than all keys in the list. - bt != m_header - - Even when find_core returns false, the pair (bt, idx) can be used to create an iterator object - to traverse keys >= k. - */ - template - bool find_core(key const & k, bucket * & bt, unsigned & idx, bucket * pred_vect[]) const { - bucket * curr = this->m_header; - unsigned i = this->m_header->level(); - bucket * next; - while (i > 0) { - i--; - for (;;) { - next = curr->get_next(i); - if (next != 0 && lt(first_key(next), k)) - curr = next; - else - break; - } - if (UpdatePredVect) - pred_vect[i] = curr; - } - - SASSERT(next == curr->get_next(0)); - - // the search_key must be in the current bucket, or in the first entry of the next bucket (if the next bucket is not 0). - SASSERT(curr->empty() || lt(first_key(curr), k)); - SASSERT(next == 0 || this->geq(first_key(next), k)); - DEBUG_CODE({ - if (UpdatePredVect && next != 0) - for (unsigned i = 0; i < next->level(); i++) - SASSERT(pred_vect[i]->get_next(i) == next); - }); - - if (next != 0 && contains(next->first_entry(), k)) { - bt = next; - idx = 0; - return true; - } - - bool r = find_core(curr, k, idx); - if (idx == curr->size()) { - SASSERT(!r); - bt = next; - idx = 0; - } - else { - SASSERT(idx < curr->size()); - bt = curr; - } - SASSERT(bt != this->m_header); - SASSERT((bt == 0 && idx == 0) || (bt != 0 && idx < bt->size())); - SASSERT(!r || contains(bt->get(idx), k)); - SASSERT(r || - // Case 1 - (bt != 0 && 0 < idx && idx < bt->size() && lt(bt->get(idx-1).end_key(), k) && lt(k, bt->get(idx).begin_key())) || - // Case 2 - (bt != 0 && idx == 0 && (this->pred_bucket(bt) == this->m_header || lt(last_key(this->pred_bucket(bt)), k)) && lt(k, first_key(bt))) || - // Case 3 - (bt == 0 && idx == 0) // k is greater than all keys in the list. - ); - return r; - } - - /** - \brief Return true if the two entries (that satisfy lt(e1, e2)) can be merged. - */ - bool can_be_merged(entry const & e1, entry const & e2) const { - return this->val_eq(e1.val(), e2.val()) && this->eq(this->succ(e1.end_key()), e2.begin_key()); - } - - /** - \brief Try to merge the last entry with bt with the first entry of its successor. - - \remark pred_vect contains the predecessors of the successor of bt. - */ - void merge_first_of_succ_if_possible(manager & m, bucket * bt, bucket * pred_vect[]) { - SASSERT(this->check_pred_vect(bt->get_next(0), pred_vect)); - bucket * next_bucket = bt->get_next(0); - if (next_bucket != 0) { - entry & curr_entry = bt->last_entry(); - entry & next_entry = next_bucket->get(0); - if (can_be_merged(curr_entry, next_entry)) { - curr_entry.set_end_key(next_entry.end_key()); - this->del_entry(m, next_bucket, 0); // del_entry invokes dec_ref_eh - if (next_bucket->empty()) - this->del_bucket(m, next_bucket, pred_vect); - } - } - } - - /** - \brief Try to merge the entry at position idx with the next entry if possible. - */ - void merge_next_if_possible(manager & m, bucket * bt, unsigned idx, bucket * pred_vect[]) { - SASSERT(!bt->empty()); - if (idx + 1 == bt->size()) { - // it is the last element - merge_first_of_succ_if_possible(m, bt, pred_vect); - } - else { - entry & curr_entry = bt->get(idx); - entry & next_entry = bt->get(idx+1); - if (can_be_merged(curr_entry, next_entry)) { - curr_entry.set_end_key(next_entry.end_key()); - this->del_entry(m, bt, idx+1); // del_entry invokes dec_ref_eh - } - } - } - - /** - \brief Try to merge the entry at position idx with the previous entry if possible. - - \remark This method assumes that idx > 0. - */ - void merge_prev_if_possible(manager & m, bucket * bt, unsigned idx) { - SASSERT(idx > 0); - entry & curr_entry = bt->get(idx); - entry & prev_entry = bt->get(idx-1); - if (can_be_merged(prev_entry, curr_entry)) { - prev_entry.set_end_key(curr_entry.end_key()); - this->del_entry(m, bt, idx); // del_entry invokes dec_ref_eh - } - } - - /** - \brief Delete entries starting at indices [s_idx, e_idx), assuming e_idx < bt->size() - - \remark The pre-condition guarantees that the bucket will not be empty after the entries - are deleted. - - \remark If RECYCLE_ENTRY is true, then method will try to recycle position s_idx if it is deleted, and will return true. - Position s_idx will be an empty slot in this case. - */ - template - bool del_entries(manager & m, bucket * bt, unsigned s_idx, unsigned e_idx) { - bool result = false; - if (RECYCLE_ENTRY && s_idx + 1 < e_idx) { - // The position s_idx will be recycled, but the reference to the value stored there - // will be lost. - this->dec_ref(m, bt->get(s_idx).val()); - s_idx++; - result = true; - } - TRACE("del_entries_upto_bug", this->display(tout, bt); tout << "[" << s_idx << ", " << e_idx << ")\n";); - SASSERT(e_idx >= s_idx); - SASSERT(e_idx < bt->size()); - // move entries - unsigned num_removed = e_idx - s_idx; - entry * dest_it = bt->get_entries() + s_idx; - entry * source_it = bt->get_entries() + e_idx; - entry * source_end = bt->get_entries() + bt->size(); - if (Traits::ref_count) { - // invoke dec_ref_eh for entries between dest_it and source_it, since they are being removed - entry * it = dest_it; - for (; it < source_it; ++it) { - this->dec_ref(m, it->val()); - } - } - for (; source_it < source_end; ++dest_it, ++source_it) { - *dest_it = *source_it; - } - // update size - bt->shrink(num_removed); - SASSERT(!bt->empty()); - TRACE("del_entries_upto_bug", this->display(tout, bt);); - return result; - } - - /** - \brief Delete all keys (starting at position s_idx) in the given bucket that are <= k. - The method assumes that k < bt->last_key(). - This condition guarantees that the bucket will not be empty after removing the keys. - - - \remark If RECYCLE_ENTRY is true, then method will try to recycle position s_idx if it is deleted, and will return true. - Position s_idx will be an empty slot in this case. - */ - template - bool del_last_entries_upto(manager & m, bucket * bt, unsigned s_idx, key const & k) { - SASSERT(s_idx < bt->size()); - SASSERT(lt(k, last_key(bt))); - int low = s_idx; - int high = bt->size() - 1; - SASSERT(low <= high); - for (;;) { - int mid = low + ((high - low) / 2); - SASSERT(mid < static_cast(bt->size())); - entry & mid_entry = bt->get(mid); - if (this->gt(k, mid_entry.end_key())) { - low = mid + 1; - if (low > high) { - // mid entry must be deleted since k > mid_entry.end_key(). - TRACE("del_entries_upto_bug", tout << "exit 1) mid: " << mid << "\n"; this->display(tout, mid_entry); tout << "\n";); - SASSERT(mid + 1 < static_cast(bt->size())); // Reason: method pre-condition: lt(k, last_key(bt)) - return del_entries(m, bt, s_idx, mid + 1); - } - } - else if (lt(k, mid_entry.begin_key())) { - high = mid - 1; - if (low > high) { - // mid entry must not be deleted since k < mid_entry.begin_key(). - TRACE("del_entries_upto_bug", tout << "exit 2) mid: " << mid << "\n"; this->display(tout, mid_entry); tout << "\n";); - SASSERT(mid < static_cast(bt->size())); // Reason: loop invariant - return del_entries(m, bt, s_idx, mid); - } - } - else { - SASSERT(contains(mid_entry, k)); - if (lt(k, mid_entry.end_key())) { - TRACE("del_entries_upto_bug", tout << "exit 3) mid: " << mid << "\n"; this->display(tout, mid_entry); tout << "\n";); - mid_entry.set_begin_key(this->succ(k)); - SASSERT(mid < static_cast(bt->size())); // Reason: loop invariant - return del_entries(m, bt, s_idx, mid); - } - else { - // mid_entry should also be removed - TRACE("del_entries_upto_bug", tout << "exit 4) mid: " << mid << "\n"; this->display(tout, mid_entry); tout << "\n";); - SASSERT(mid + 1 < static_cast(bt->size())); // Reason: method pre-condition: lt(k, last_key(bt)) - return del_entries(m, bt, s_idx, mid + 1); - } - } - } - } - - /** - \brief Keep deleting keys <= k in bt and its successors. - */ - void del_entries_upto_loop(manager & m, bucket * bt, key const & k, bucket * pred_vect []) { - SASSERT(this->check_pred_vect(bt, pred_vect)); - while (bt != 0) { - key const & bt_last_key = last_key(bt); - if (lt(k, bt_last_key)) { - del_last_entries_upto(m, bt, 0, k); - return; - } - else if (this->eq(k, bt_last_key)) { - this->del_bucket(m, bt, pred_vect); - return; - } - else { - SASSERT(this->gt(k, bt_last_key)); - bucket * next = bt->get_next(0); - this->del_bucket(m, bt, pred_vect); - bt = next; - // continue deleting... - } - } - } - - /** - \brief Delete entries starting at position 0 such that keys are <= k. - - If INSERT == true, then try to save/recycle an entry. Return true, if - managed to recycle the entry. - - The bucket bt may be deleted when INSERT==false and k >= last_key(bt). - - - pred_vect must contain the predecessors of bt. - - - next_pred_vect is an uninitialized predecessor vector. It may be initialized - when INSERT == true. If needed it is initialized using - update_predecessor_vector(pred_vect, bt, next_pred_vect); - */ - template - bool del_entries_upto(manager & m, bucket * bt, key const & k, bucket * pred_vect[], bucket * next_pred_vect[]) { - SASSERT(this->check_pred_vect(bt, pred_vect)); // pred_vect contains the predecessors of bt. - if (lt(k, first_key(bt))) { - // nothing to be done... - return false; // didn't manage to recycle entry. - } - - key const & bt_last_key = last_key(bt); - TRACE("del_entries_upto_bug", tout << "bt_last_key: " << bt_last_key << "\n";); - if (this->lt(k, bt_last_key)) { - return del_last_entries_upto(m, bt, 0, k); - } - else { - if (INSERT) { - // Invoke DEC-REF for all entries in bt - this->dec_ref(m, bt); - // REMARK: the slot 0 will be reused, but the element there is gone. - bt->set_size(1); - if (this->gt(k, bt_last_key)) { - bucket * next = bt->get_next(0); - if (next != 0) { - this->update_predecessor_vector(pred_vect, bt, next_pred_vect); - del_entries_upto_loop(m, next, k, next_pred_vect); - } - } - return true; // recycled entry. - } - else { - bucket * next = bt->get_next(0); - this->del_bucket(m, bt, pred_vect); // it will invoke dec_ref_eh for all values in bt. - // pred_vect does not need to be updated since it contains the predecessors of - // bt, since bt was deleted they are now the predecessors of its successor. - if (next != 0) { - del_entries_upto_loop(m, next, k, pred_vect); - } - return false; // don't care in this case, since it is not an insertion. - } - } - } - - /** - \brief Delete entries starting at position s_idx (> 0) such that keys are <= k. - The bucket bt cannot be deleted since s_idx > 0. - - If INSERT == true, then try to save/recycle an entry. Return true, if - managed to recycle the entry. - - - pred_vect must contain the predecessors of bt->get_next(0). - */ - template - bool del_entries_upto(manager & m, bucket * bt, unsigned s_idx, key const & k, bucket * pred_vect[]) { - SASSERT(this->check_pred_vect(bt->get_next(0), pred_vect)); // pred_vect contains the predecessors of the successor of bt. - SASSERT(s_idx > 0); - TRACE("del_entries_upto_bug", - tout << "INSERT: " << INSERT << "\n"; - tout << "del_entries_upto, s_idx: " << s_idx << ", k: " << k << "\n"; - this->display(tout, bt); - tout << "\n"; - this->display_predecessor_vector(tout, pred_vect);); - - if (s_idx >= bt->size()) { - // nothing to do in bt, moving to successors... - del_entries_upto_loop(m, bt->get_next(0), k, pred_vect); - return false; // didn't manage to recycle an entry - } - - if (lt(k, bt->get(s_idx).begin_key())) { - // nothing to be done... - return false; // didn't manage to recycle an entry - } - - key const & bt_last_key = last_key(bt); - TRACE("del_entries_upto_bug", tout << "bt_last_key: " << bt_last_key << "\n";); - if (lt(k, bt_last_key)) { - return del_last_entries_upto(m, bt, s_idx, k); - } - else { - if (this->gt(k, bt_last_key)) { - del_entries_upto_loop(m, bt->get_next(0), k, pred_vect); - } - if (Traits::ref_count) { - // Invoke dec_ref_eh for all values in [s_idx, bt->size()) - unsigned sz = bt->size(); - for (unsigned i = s_idx; i < sz; i++) - this->dec_ref(m, bt->get(i).val()); - } - if (INSERT) { - SASSERT(s_idx < bt->size()); - bt->set_size(s_idx + 1); - return true; // recycled an entry - - } - else { - bt->set_size(s_idx); - return false; // don't care. it is not an insertion. - } - } - } - - /** - \brief Insert entry [b,e]->v in the beginning of the bucket bt. - */ - void insert_begin(manager & m, bucket * bt, key const & b, key const & e, value const & v, bucket * pred_vect[]) { - TRACE("interval_skip_list_bug", tout << "insert_begin: [" << b << ", " << e << "] -> " << v << "\n"; this->display(tout, bt);); - SASSERT(this->check_pred_vect(bt, pred_vect)); - SASSERT(!bt->empty()); - SASSERT(bt->size() <= bt->capacity()); - SASSERT(this->leq(b, first_key(bt))); - bucket * next_pred_vect[Traits::max_level]; - next_pred_vect[0] = 0; - - this->inc_ref(m, v); - - // Delete entries that will be overlapped by new entry. - // Try to reuse a slot that was deleted... - bool recycled = del_entries_upto(m, bt, e, pred_vect, next_pred_vect); - if (recycled) { - set_entry(bt, 0, b, e, v); // Reference to v was stored, and inc_ref_eh was invoked above. - TRACE("interval_skip_list_bug", this->display_physical(tout);); - if (next_pred_vect[0] != 0) { - // the vector next_pred_vect was initialized by del_entries_upto. - merge_next_if_possible(m, bt, 0, next_pred_vect); - } - else { - this->update_predecessor_vector(pred_vect, bt); - merge_next_if_possible(m, bt, 0, pred_vect); - } - return; - } - // check if can merge with first entry in the bucket. - entry & fe = bt->first_entry(); - if (this->val_eq(fe.val(), v) && this->eq(fe.begin_key(), this->succ(e))) { - // can merge - fe.set_begin_key(b); - // A new reference to v was not created. So, we must invoke dec_ref_eh since we increased the counter above. - this->dec_ref(m, v); - return; - } - // Is there space for the new entry? - if (bt->size() == bt->capacity()) { - if (bt->capacity() < Traits::max_capacity) { - SASSERT(this->first_bucket() == bt && this->first_bucket()->get_next(0) == 0); - this->expand_first_bucket(m); - bt = this->first_bucket(); - } - else { - // there is no space - this->splice(m, bt, pred_vect); - } - } - this->open_space(bt, 0); - set_entry(bt, 0, b, e, v); // Reference to v was stored, and inc_ref_eh was invoked above. - SASSERT(!can_be_merged(bt->get(0), bt->get(1))); - } - - /** - \brief Insert the entry [b, e]->v at position idx. - */ - void insert_at(manager & m, bucket * bt, unsigned idx, key const & b, key const & e, value const & v, bucket * pred_vect[]) { - SASSERT(idx > 0); - SASSERT(this->check_pred_vect(bt->get_next(0), pred_vect)); - - this->inc_ref(m, v); - TRACE("insert_at_bug", tout << "before del_entries_upto:\n"; this->display_physical(tout);); - - bool recycled = del_entries_upto(m, bt, idx, e, pred_vect); - - TRACE("insert_at_bug", tout << "after del_entries_upto:\n"; this->display_physical(tout);); - - if (recycled) { - set_entry(bt, idx, b, e, v); // Reference to v was stored, and inc_ref_eh was invoked above. - merge_next_if_possible(m, bt, idx, pred_vect); - merge_prev_if_possible(m, bt, idx); - TRACE("insert_at_bug", tout << "using recycled:\n"; this->display_physical(tout);); - return; - } - - // Is there space for the new entry? - if (bt->size() == bt->capacity()) { - // there is no space - if (bt->capacity() < Traits::max_capacity) { - SASSERT(this->first_bucket() == bt && this->first_bucket()->get_next(0) == 0); - this->expand_first_bucket(m); - bt = this->first_bucket(); - // there is no need to update pred_vect, since the list contains only one bucket. - } - else { - this->splice(m, bt, pred_vect); - bucket * new_next = bt->get_next(0); - SASSERT(bt->size() == bt->capacity()/2); - if (idx == bt->capacity()/2) { - entry & bt_last_entry = bt->last_entry(); - if (this->val_eq(bt_last_entry.val(), v) && this->eq(bt_last_entry.end_key(), this->pred(b))) { - // merged with the last key of bt - bt_last_entry.set_end_key(e); - // A new reference to v was not created. So, we must invoke dec_ref_eh since we increased the counter above. - this->dec_ref(m, v); - return; - } - entry & new_next_first_entry = new_next->first_entry(); - if (this->val_eq(new_next_first_entry.val(), v) && this->eq(new_next_first_entry.begin_key(), this->succ(e))) { - // merged with the first key of new_next - new_next_first_entry.set_begin_key(b); - // A new reference to v was not created. So, we must invoke dec_ref_eh since we increased the counter above. - this->dec_ref(m, v); - return; - } - // insert in the end of bt. - bt->set_size(bt->capacity()/2 + 1); - set_entry(bt, bt->capacity()/2, b, e, v); // Reference to v was stored, and inc_ref_eh was invoked above. - return; - } - else if (idx > bt->capacity()/2) { - idx -= bt->capacity()/2; - SASSERT(idx > 0); - bt = new_next; - this->update_predecessor_vector(pred_vect, bt); - } - } - } - SASSERT(idx > 0); - this->open_space(bt, idx); - set_entry(bt, idx, b, e, v); // Reference to v was stored, and inc_ref_eh was invoked above. - merge_next_if_possible(m, bt, idx, pred_vect); - merge_prev_if_possible(m, bt, idx); - TRACE("insert_at_bug", tout << "using open-space:\n"; this->display_physical(tout);); - } - - /** - \brief Insert the entry [b,e]->v into the bucket bt. - - pred_vect contains the predecessors of the successor of bt (i.e., bt->get_next(0)) - */ - void insert_inside(manager & m, bucket * bt, key const & b, key const & e, value const & v, bucket * pred_vect[]) { - TRACE("interval_skip_list_bug", tout << "insert_inside: [" << b << ", " << e << "] -> " << v << "\n";); - SASSERT(this->check_pred_vect(bt->get_next(0), pred_vect)); - SASSERT(!bt->empty()); - SASSERT(bt->size() <= bt->capacity()); - // perform binary search to find position to insert [b, e]->v - int low = 0; - int high = bt->size() - 1; - for (;;) { - int mid = low + ((high - low) / 2); - entry & mid_entry = bt->get(mid); - if (this->gt(b, mid_entry.end_key())) { - low = mid + 1; - if (low > high) { - // insert after mid_entry since b > mid_entry.end_key(). - insert_at(m, bt, mid+1, b, e, v, pred_vect); - return; - } - } - else if (lt(b, mid_entry.begin_key())) { - high = mid - 1; - if (low > high) { - // insert before mid_entry since b < mid_entry.begin_key(). - SASSERT(mid > 0); // Reason: insert_begin would have been called instead. - insert_at(m, bt, mid, b, e, v, pred_vect); - return; - } - } - else { - SASSERT(contains(mid_entry, b)); - TRACE("insert_inside_bug", tout << "insert_inside:\n"; this->display(tout, bt);); - if (this->val_eq(mid_entry.val(), v)) { - if (this->gt(e, mid_entry.end_key())) { - // No need to create space. - // We did not create a new reference to v. - mid_entry.set_end_key(e); - del_entries_upto(m, bt, mid+1, e, pred_vect); - merge_next_if_possible(m, bt, mid, pred_vect); - return; - } - } - else { - if (this->gt(b, mid_entry.begin_key())) { - if (this->lt(e, mid_entry.end_key())) { - // New interval is the middle of existing interval - - // We must INVOKE add_ref_eh for mid_entry.val() and v. - this->inc_ref(m, v); - this->inc_ref(m, mid_entry.val()); // mid_entry was split in two. - - // we need two new entries. - if (bt->size() >= bt->capacity() - 1) { - if (bt->capacity() < Traits::max_capacity) { - SASSERT(this->first_bucket() == bt && this->first_bucket()->get_next(0) == 0); - this->expand_first_bucket(m); - bt = this->first_bucket(); - } - else { - this->splice(m, bt, pred_vect); - int new_sz = bt->size(); - bucket * new_next = bt->get_next(0); - if (mid >= new_sz) { - mid -= new_sz; - SASSERT(mid >= 0); - bt = new_next; - } - } - } - this->open_2spaces(bt, mid); - entry & mid1_entry = bt->get(mid); - entry & new_entry = bt->get(mid+1); - entry & mid2_entry = bt->get(mid+2); - mid2_entry = mid1_entry; - mid1_entry.set_end_key(this->pred(b)); - new_entry.set_begin_key(b); - new_entry.set_end_key(e); - new_entry.set_val(v); - mid2_entry.set_begin_key(this->succ(e)); - } - else { - mid_entry.set_end_key(this->pred(b)); - insert_at(m, bt, mid+1, b, e, v, pred_vect); - } - } - else { - SASSERT(this->eq(b, mid_entry.begin_key())); - SASSERT(mid > 0); // Reason: insert_begin would have been called instead. - insert_at(m, bt, mid, b, e, v, pred_vect); - } - } - return; - } - } - } - - /** - \brief Remove [b,e]->v from the beginning of the bucket bt. - */ - void remove_begin(manager & m, bucket * bt, key const & b, key const & e, bucket * pred_vect[]) { - TRACE("interval_skip_list_bug", tout << "remove_begin: [" << b << ", " << e << "]\n";); - SASSERT(!bt->empty()); - SASSERT(pred_vect[0]->get_next(0) == bt); - del_entries_upto(m, bt, e, pred_vect, 0); - } - - /** - \brief Remove [b,e]->v from the bucket bt. - */ - void remove_inside(manager & m, bucket * bt, key const & b, key const & e, bucket * pred_vect[]) { - TRACE("interval_skip_list_bug", tout << "remove_inside: [" << b << ", " << e << "]\n";); - // perform binary search to find position to insert [b, e]->v - int low = 0; - int high = bt->size() - 1; - for (;;) { - int mid = low + ((high - low) / 2); - entry & mid_entry = bt->get(mid); - if (this->gt(b, mid_entry.end_key())) { - low = mid + 1; - if (low > high) { - // insert after mid_entry since b > mid_entry.end_key(). - del_entries_upto(m, bt, mid+1, e, pred_vect); - return; - } - } - else if (this->lt(b, mid_entry.begin_key())) { - high = mid - 1; - if (low > high) { - // insert before mid_entry since b < mid_entry.begin_key(). - SASSERT(mid > 0); // Reason: remove_begin would have been called instead. - del_entries_upto(m, bt, mid, e, pred_vect); - return; - } - } - else { - SASSERT(contains(mid_entry, b)); - if (this->gt(b, mid_entry.begin_key())) { - if (this->lt(e, mid_entry.end_key())) { - // The removed interval is inside of an existing interval. - - // mid_entry will be split in two. So, we must invoke add_ref_eh for mid_entry.val() - this->inc_ref(m, mid_entry.val()); - - // We need to break mid_entry in two parts. - if (bt->size() == bt->capacity()) { - if (bt->capacity() < Traits::max_capacity) { - SASSERT(this->first_bucket() == bt && this->first_bucket()->get_next(0) == 0); - this->expand_first_bucket(m); - bt = this->first_bucket(); - SASSERT(bt->size() < bt->capacity()); - } - else { - this->splice(m, bt, pred_vect); - if (mid >= static_cast(bt->size())) { - // mid_entry moved to new (successor) bucket - mid -= bt->size(); - bt = bt->get_next(0); - } - } - } - this->open_space(bt, mid); - entry & mid1_entry = bt->get(mid); - entry & mid2_entry = bt->get(mid+1); - mid1_entry.set_end_key(this->pred(b)); - mid2_entry.set_begin_key(this->succ(e)); - } - else { - mid_entry.set_end_key(this->pred(b)); - del_entries_upto(m, bt, mid+1, e, pred_vect); - } - } - else { - SASSERT(this->eq(b, mid_entry.begin_key())); - SASSERT(mid > 0); // Reason: remove_begin would have been called instead. - del_entries_upto(m, bt, mid, e, pred_vect); - } - return; - } - } - } - -public: - interval_skip_list() { - } - - interval_skip_list(manager & m):skip_list_base(m) { - } - - ~interval_skip_list() { - } - - /** - \brief Copy the elements of other. - This method assumes that the *this* skip-list is empty. - */ - void copy(manager & m, interval_skip_list const & other) { - SASSERT(this->empty()); - other.clone_core(m, this); - } - - /** - \brief Return the smallest key stored in the interval skip list. - */ - key const & smallest() const { - SASSERT(!this->empty()); - return this->first_bucket()->get(0).begin_key(); - } - - /** - \brief Search for the given key in the interval skip list. - Return true if the key is stored in the list, and store the associated value in \c v. - */ - bool contains(key const & k, value & v) const { - bucket * bt; - unsigned idx; - if (find_core(k, bt, idx, 0)) { - v = bt->get(idx).val(); - return true; - } - return false; - } - - /** - \brief Alias for #contains. - */ - bool find(key const & k, value & v) const { - return contains(k, v); - } - -private: - /** - \brief Search for a bucket based on the key \c k. - - curr, next and pred_vect are output arguments. - - pred_vect must be an array of size level(). - - Post-conditions: - - pred_vect contains the predecessors of next. - That is, pred_vect[i] is the predecessor of level i. - - next is the successor of curr. - - pred_vect[0] == curr. - - curr == m_header || first_key(curr) < k - - next == 0 || k <= first_key(next) - */ - void find_bucket(key const & k, bucket * & curr, bucket * & next, bucket * pred_vect[]) { - SASSERT(this->level() > 0); - curr = this->m_header; - unsigned i = curr->level(); - SASSERT(i > 0); - while (i > 0) { - i--; - for (;;) { - next = curr->get_next(i); - if (next != 0 && lt(first_key(next), k)) - curr = next; - else - break; - } - pred_vect[i] = curr; - } - - SASSERT(next == curr->get_next(0)); - SASSERT(pred_vect[0] == curr); - DEBUG_CODE({ - if (next != 0) - for (unsigned i = 0; i < next->level(); i++) - SASSERT(pred_vect[i]->get_next(i) == next); - }); - SASSERT(curr == this->m_header || lt(first_key(curr), k)); - SASSERT(next == 0 || this->leq(k, first_key(next))); - } - -public: - - /** - \brief Insert the entries [i -> v] for every i \in [b, e]. - */ - void insert(manager & m, key const & b, key const & e, value const & v) { - SASSERT(this->leq(b, e)); - if (this->empty()) { - insert_first_entry(m, b, e, v); - return; - } - - // find the bucket where the new entries should be stored. - - // pred_vect[i] contains a pointer to the rightmost bucket of - // level i or higher that is to the left of the location of - // the insertion. - bucket * pred_vect[Traits::max_level]; - bucket * curr, * next; - find_bucket(b, curr, next, pred_vect); - - if (curr == this->m_header) { - SASSERT(next != 0); - // entry must be inserted in the first bucket. - SASSERT(this->first_bucket() == next); - insert_begin(m, next, b, e, v, pred_vect); - } - else if (next == 0 || this->gt(first_key(next), b)) { - insert_inside(m, curr, b, e, v, pred_vect); - } - else { - SASSERT(!curr->empty()); - SASSERT(!next->empty()); - SASSERT(next != 0); - SASSERT(this->eq(first_key(next), b)); - // Bucket curr is the predecessor of next. - SASSERT(curr->get_next(0) == next); - - // check if we can merge with last entry of curr - entry & curr_last_entry = curr->last_entry(); - if (this->val_eq(curr_last_entry.val(), v) && this->eq(curr_last_entry.end_key(), this->pred(b))) { - // No new reference to v was create, we don't need to invok inc_ref_eh - curr_last_entry.set_end_key(e); - del_entries_upto(m, next, e, pred_vect, 0); - merge_first_of_succ_if_possible(m, curr, pred_vect); - return; - } - insert_begin(m, next, b, e, v, pred_vect); - } - } - - /** - \brief Insert key [k->v]. - */ - void insert(manager & m, key const & k, value const & v) { - insert(m, k, k, v); - } - - class push_back_proc; - friend class push_back_proc; - - /** - \brief Functor for efficiently inserting elements in the end of the skip list. - - \remark The context becomes invalid if the skip-list is updated by other methods. - */ - class push_back_proc { - friend class interval_skip_list; - manager & m_manager; - interval_skip_list & m_list; - bucket * m_pred_vect[Traits::max_level]; - - bucket * last_bucket() const { return m_pred_vect[0]; } - - public: - push_back_proc(manager & m, interval_skip_list & l): - m_manager(m), - m_list(l) { - // initialize m_pred_vect - unsigned lvl = m_list.level(); - bucket * curr = m_list.m_header; - bucket * next; - unsigned i = lvl; - while (i > 0) { - i--; - for (;;) { - next = curr->get_next(i); - if (next != 0) - curr = next; - else - break; - } - m_pred_vect[i] = curr; - } - SASSERT(next == 0); - } - - interval_skip_list & list() { - return m_list; - } - - bool empty() const { - return m_list.empty(); - } - - key const & last_key() const { - return last_bucket()->last_entry().end_key(); - } - - void operator()(key const & b, key const & e, value const & v) { - SASSERT(m_list.leq(b, e)); - if (m_list.empty()) { - m_list.insert_first_entry(m_manager, b, e, v); - bucket * new_bucket = m_list.first_bucket(); - skip_list_base::update_predecessor_vector(m_pred_vect, new_bucket); - } - else { - bucket * bt = last_bucket(); - entry & et = bt->last_entry(); - SASSERT(m_list.lt(et.end_key(), b)); - // first check if new entry can be merged with the last entry in the list - if (m_list.val_eq(et.val(), v) && m_list.eq(et.end_key(), m_list.pred(b))) { - // can merge - et.set_end_key(e); - return; - } - // insert in the last bucket - unsigned sz = bt->size(); - if (sz >= bt->capacity()) { - if (bt->capacity() < Traits::max_capacity) { - SASSERT(m_list.first_bucket() == bt && m_list.first_bucket()->get_next(0) == 0); - m_list.expand_first_bucket(m_manager); - bt = m_list.first_bucket(); - SASSERT(bt->size() < bt->capacity()); - skip_list_base::update_predecessor_vector(m_pred_vect, bt); - sz = bt->size(); - } - else { - // last bucket is full... creating new bucket... - unsigned new_bucket_lvl = m_manager.random_level(Traits::max_level); - bucket * new_bucket = interval_skip_list::mk_bucket(m_manager, new_bucket_lvl); - m_list.update_list_level(m_manager, new_bucket_lvl, m_pred_vect); - for (unsigned i = 0; i < new_bucket_lvl; i++) { - SASSERT(m_pred_vect[i]->get_next(i) == 0); - m_pred_vect[i]->set_next(i, new_bucket); - m_pred_vect[i] = new_bucket; - SASSERT(m_pred_vect[i]->get_next(i) == 0); - } - SASSERT(last_bucket() == new_bucket); - bt = new_bucket; - sz = 0; - } - } - SASSERT(sz < bt->capacity()); - m_list.inc_ref(m_manager, v); - bt->expand(1); - interval_skip_list::set_entry(bt, sz, b, e, v); - } - } - }; - - /** - \brief For each i \in [b, e] remove any entry [i->v] if it is in the list. - */ - void remove(manager & m, key const & b, key const & e) { - SASSERT(this->leq(b, e)); - if (this->empty()) - return; - bucket * pred_vect[Traits::max_level]; - bucket * curr, * next; - - find_bucket(b, curr, next, pred_vect); - - if (curr == this->m_header) { - SASSERT(next != 0); - remove_begin(m, next, b, e, pred_vect); - } - else if (next == 0 || this->gt(first_key(next), b)) { - remove_inside(m, curr, b, e, pred_vect); - } - else { - SASSERT(next != 0); - SASSERT(this->eq(first_key(next), b)); - remove_begin(m, next, b, e, pred_vect); - } - } - - /** - \brief Remove entry [k->v] for some v, if it is in the list. - */ - void remove(manager & m, key const & k) { - remove(m, k, k); - } - - /** - \brief Alias for #remove. - */ - void erase(manager & m, key const & b, key const & e) { - remove(m, b, e); - } - - /** - \brief Alias for #remove. - */ - void erase(manager & m, key const & k) { - remove(m, k, k); - } - - /** - \begin Traverse the list applying the functor f. - The functor must have a method - - bool operator()(key const & b, key const & e, value const & v) - - The method will invoke f(b, e, v) whenever the entries [i -> v] for i \in [b, e] are - in the list. - - If the functor returns false, then the traversal is interrupted. - */ - template - void for_each(Functor & f) const { - SASSERT(this->m_header->empty()); - bucket * curr = this->first_bucket(); - while (curr != 0) { - unsigned sz = curr->size(); - for (unsigned i = 0; i < sz; i++) { - entry const & e = curr->get(i); - if (!f(e.begin_key(), e.end_key(), e.val())) - return; - } - curr = curr->get_next(0); - } - } - - /** - \brief Return the next/successor buffer, but skipping buffers that do not contains keys greater than or equal to k. - */ - bucket * next_bucket(bucket const * bt, key const & k) const { - bucket * curr = bt->get_next(0); // move to successor - if (curr == 0) - return 0; - unsigned i = curr->level(); - unsigned max = i; - bucket * next = 0; - while (i > 0) { - --i; - for (;;) { - next = curr->get_next(i); - if (next != 0 && this->leq(first_key(next), k)) { - TRACE("interval_skip_list", tout << "next_bucket(" << k << "), i: " << i << " skipping #" << this->get_bucket_idx(curr); - tout << ", moving to: #" << this->get_bucket_idx(next) << "\n"; this->display(tout, next);); - curr = next; - if (curr->level() > max) { - max = curr->level(); - i = curr->level(); - TRACE("interval_skip_list", tout << "max: " << max << ", curr->level(): " << curr->level() << ", i: " << i << "\n";); - break; - } - } - else { - break; - } - } - } - SASSERT(i == 0); - SASSERT(curr->get_next(0) == next); - SASSERT(next == 0 || lt(k, first_key(next))); - return curr; - } - - class iterator; - friend class iterator; - - class iterator { - interval_skip_list const * m_list; - bucket const * m_curr; - unsigned m_idx; - public: - iterator():m_list(0), m_curr(0), m_idx(0) {} - iterator(interval_skip_list const * l, bucket const * b = 0, unsigned idx = 0):m_list(l), m_curr(b), m_idx(idx) {} - entry const & operator*() const { return m_curr->get(m_idx); } - entry const * operator->() const { return &(operator*()); } - iterator & operator++() { - SASSERT(m_curr); - m_idx++; - if (m_idx >= m_curr->size()) { - m_idx = 0; - m_curr = m_curr->get_next(0); - } - return *this; - } - iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; } - - bool at_end() const { - return m_curr == 0; - } - - /** - \brief Move the iterator to the next entry of the form ([b, e] -> v) s.t. - - 1) k in [b, e], or - 2) b > k and for every entry ([b',e']->v') between the old current entry and ([b,e]->v), we - have k > e' - - If such entry does not exist, then the iterator is moved to the end. - That is, at_end() returns true. - */ - void move_to(key const & k) { - SASSERT(m_curr); - SASSERT(m_idx < m_curr->size()); - entry const & curr_entry = m_curr->get(m_idx); - if (m_list->gt(k, curr_entry.end_key())) { - m_list->find_core(m_curr, m_idx+1, k, m_idx); - if (m_idx < m_curr->size()) - return; // found new position - SASSERT(m_idx == m_curr->size()); - m_curr = m_list->next_bucket(m_curr, k); - if (m_curr != 0) { - // search for k in the current buffer. - m_list->find_core(m_curr, k, m_idx); - if (m_idx == m_curr->size()) { - // k is greater than all keys in the list. - m_curr = 0; - m_idx = 0; - } - } - else { - SASSERT(m_curr == 0); - m_idx = 0; - } - } - } - - bool operator==(iterator const & it) const { - SASSERT(m_list == it.m_list); - return m_curr == it.m_curr && m_idx == it.m_idx; - } - - bool operator!=(iterator const & it) const { - SASSERT(m_list == it.m_list); - return m_curr != it.m_curr; - } - - /** - \brief Take the ownership of the current value and reset it to 0. - - \warning This method should be used with extreme care, since it puts the interval skip list - in an inconsistent state that must be restored. This method should be only used by developers - familiar with the interval skip-lists internal invariants. - For users not familiar with internal invariants, they should only use the reset method in the skip list class - after this method is invoked. - - Store in r the current value. - */ - template - void take_curr_ownership(manager & m, ObjRef & r) { - SASSERT(!at_end()); - entry & curr = const_cast(operator*()); // <<< HACK - r = curr.val(); - if (Traits::ref_count) - m.dec_ref_eh(curr.val()); - curr.set_val(0); - } - }; - - iterator begin() const { return iterator(this, this->first_bucket()); } - - iterator end() const { return iterator(this); } - - /** - \brief Return an iterator starting at the first entry that contains k. - If the skip-list does not contain k, then return the "end()" iterator. - */ - iterator find(key const & k) const { - bucket * bt; - unsigned idx; - if (find_core(k, bt, idx, 0)) { - return iterator(this, bt, idx); - } - else { - return end(); - } - } - - iterator find_geq(key const & k) const { - bucket * bt; - unsigned idx; - find_core(k, bt, idx, 0); - return iterator(this, bt, idx); - } - - /** - \brief Return true if the skip lists are equal. - */ - bool is_equal(interval_skip_list const & other) const { - iterator it1 = begin(); - iterator end1 = end(); - iterator it2 = other.begin(); - iterator end2 = other.end(); - for (; it1 != end1 && it2 != end2; it1++, it2++) { - entry const & e1 = *it1; - entry const & e2 = *it2; - if (!this->eq(e1.begin_key(), e2.begin_key())) - return false; - if (!this->eq(e1.end_key(), e2.end_key())) - return false; - if (!this->val_eq(e1.val(), e2.val())) - return false; - } - return true; - } - - /** - \brief Update the values stored in the skip-list by appling the given - functor to them. The functor must provide the operation: - - value operator()(value const & v); - - The functor must be injective. That is - - x != y implies f(x) != f(y) - - If a non-injective functor is used, then the resultant skip-list may - not be in a consistent state. - */ - template - void update_values(manager & m, InjectiveFunction & f) { - if (!this->empty()) { - iterator it = begin(); - iterator it_end = end(); - for (; it != it_end; ++it) { - entry & curr = const_cast(*it); - value const & old_val = curr.val(); - value new_val = f(old_val); - this->inc_ref(m, new_val); - this->dec_ref(m, old_val); - curr.set_val(new_val); - } - SASSERT(check_invariant()); - } - } - - class ext_iterator; - friend class ext_iterator; - - class ext_iterator { - friend class interval_skip_list; - - interval_skip_list * m_list; - bucket * m_curr; - unsigned m_idx; - bucket * m_pred_vect[Traits::max_level]; - - void move_next_bucket() { - m_list->update_predecessor_vector(m_pred_vect, m_curr); - m_idx = 0; - m_curr = m_curr->get_next(0); - } - - public: - ext_iterator():m_list(0), m_curr(0), m_idx(0) {} - - entry const & operator*() const { return m_curr->get(m_idx); } - - entry const * operator->() const { return &(operator*()); } - - ext_iterator & operator++() { - SASSERT(m_curr); - m_idx++; - if (m_idx >= m_curr->size()) - move_next_bucket(); - return *this; - } - - ext_iterator operator++(int) { ext_iterator tmp = *this; ++*this; return tmp; } - - bool at_end() const { - return m_curr == 0; - } - - bool operator==(ext_iterator const & it) const { - return m_curr == it.m_curr && m_idx == it.m_idx; - } - - bool operator!=(ext_iterator const & it) const { - return m_curr != it.m_curr; - } - - void erase(manager & m) { - SASSERT(!at_end()); - SASSERT(m_curr->size() > 0); - if (m_curr->size() > 1) { - m_list->del_entry(m, m_curr, m_idx); - if (m_idx >= m_curr->size()) - move_next_bucket(); - } - else { - SASSERT(m_curr->size() == 1); - bucket * old_curr = m_curr; - m_curr = m_curr->get_next(0); - m_list->del_bucket(m, old_curr, m_pred_vect); - } - } - }; - - void move_begin(ext_iterator & it) { - if (!this->empty()) { - it.m_list = this; - it.m_curr = this->first_bucket(); - it.m_idx = 0; - unsigned lvl = this->level(); - for (unsigned i = 0; i < lvl; i++) - it.m_pred_vect[i] = this->m_header; - } - else { - it.m_curr = 0; - it.m_idx = 0; - } - } - - void move_geq(ext_iterator & it, key const & k) { - it.m_list = this; - find_core(k, it.m_curr, it.m_idx, it.m_pred_vect); - } - -private: - /** - \brief Auxiliary data-structure used to implement the join of two interval_skip_lists. - To implement an efficient join, we want to be able to skip as many entries as possible. - */ - struct join_state { - bucket * m_bucket; - unsigned m_entry_idx; - key m_head; // it it a key in [m_bucket->m_entries[m_entry_idx].begin_key(), m_bucket->m_entries[m_entry_idx].end_key()] - public: - join_state(bucket * bt): - m_bucket(bt), - m_entry_idx(0), - m_head(bt->first_entry().begin_key()) { - } - - bool done() const { - return m_bucket == 0; - } - - key const & head() const { - SASSERT(!done()); - return m_head; - } - - key const & tail() const { - SASSERT(!done()); - SASSERT(m_entry_idx < m_bucket->size()); - return m_bucket->get(m_entry_idx).end_key(); - } - - value const & val() const { - SASSERT(!done()); - return m_bucket->get(m_entry_idx).val(); - } - }; - - /** - \brief Create a join_state auxiliary data-structure for performing a join starting at key k. - */ - join_state mk_join_state(key const & k) const { - return join_state(next_bucket(this->m_header, k)); - } - - /** - \brief Move the join_state towards k. - */ - void move_js(join_state & js, key const & k) const { - SASSERT(!js.done()); - if (this->leq(k, js.tail())) { - // We can't skip the current entry, because k in inside it. - // So, we just update the head. - js.m_head = k; - } - else { - // Moving to the next entry. - js.m_entry_idx++; - if (js.m_entry_idx < js.m_bucket->size()) { - // Update js.m_head with the beginning of the next entry. - js.m_head = js.m_bucket->get(js.m_entry_idx).begin_key(); - } - else { - // We processed all entries in the current bucket. So, set state to js.m_move_next. - js.m_bucket = next_bucket(js.m_bucket, k); - js.m_entry_idx = 0; - if (js.m_bucket != 0) - js.m_head = first_key(js.m_bucket); - } - } - } - -public: - - /** - \brief Join two interval_skip_lists and apply the given functor in the process. - - The functor must have a method - - bool operator()(key const & b, key const & e, value const & v1, value const & v2) - - The method will invoke f(b, e, v1, v2) whenever forall i \in [b, e] entries [i -> v1] are in the *this* list, and [i->v2] in the *other* list. - */ - template - void join(interval_skip_list const & other, Functor & f) { - if (this->empty() || other.empty()) - return; - key const & f1 = smallest(); - key const & f2 = other.smallest(); - key const & smallest_key = leq(f1, f2) ? f1 : f2; - join_state s1 = mk_join_state(smallest_key); - join_state s2 = other.mk_join_state(smallest_key); - while (!s1.done() && !s2.done()) { - key const & h1 = s1.head(); - key const & h2 = s2.head(); - if (eq(h1, h2)) { - key const & t1 = s1.tail(); - key const & t2 = s2.tail(); - key const & t = leq(t1, t2) ? t1 : t2; - f(h1, t, s1.val(), s2.val()); - key next_key = succ(t); - move_js(s1, next_key); - move_js(s2, next_key); - } - else if (lt(h1, h2)) { - move_js(s1, h2); - } - else { - SASSERT(lt(h2, h1)); - move_js(s2, h1); - } - } - } - -#ifdef Z3DEBUG -private: - bool check_invariant(entry const & e) const { - SASSERT(this->leq(e.begin_key(), e.end_key())); - return true; - } - - /** - \brief Return true if the last key of \c e1 is less than the first key of \c e2. - */ - bool lt(entry const & e1, entry const & e2) const { - return lt(e1.end_key(), e2.begin_key()); - } - - bool check_invariant(bucket const * bt) const { - SASSERT(bt->size() <= bt->capacity()); - SASSERT(bt == this->m_header || !bt->empty()); - for (unsigned i = 0; i < bt->size(); i++) { - entry const & curr = bt->get(i); - check_invariant(curr); - if (i > 0) { - entry const & prev = bt->get(i-1); - CTRACE("interval_skip_list", !lt(prev, curr), this->display_physical(tout);); - SASSERT(lt(prev, curr)); - CTRACE("interval_skip_list", can_be_merged(prev, curr), this->display_physical(tout);); - SASSERT(!can_be_merged(prev, curr)); - } - } - return true; - } - -public: - bool check_invariant() const { - SASSERT(this->m_header->empty()); - for (unsigned i = 0; i < this->m_header->level(); i++) { - // traverse buckets using get_next(i) pointers - bucket const * curr = this->m_header->get_next(i); - while (curr != 0) { - SASSERT(!curr->empty()); // only the header is empty. - bucket const * next = curr->get_next(i); - if (next != 0) { - SASSERT(next->level() >= i); - SASSERT(i == 0 || this->is_reachable_at_i(curr, next, i-1)); - SASSERT(!next->empty()); - entry const & last_of_curr = curr->last_entry(); - entry const & first_of_next = next->first_entry(); - CTRACE("interval_skip_list", !lt(last_of_curr, first_of_next), - this->display_physical(tout); - tout << "\ncurr:\n"; - this->display(tout, curr); - tout << "\nnext:\n"; - this->display(tout, next);); - SASSERT(lt(last_of_curr, first_of_next)); - CTRACE("interval_skip_list", can_be_merged(last_of_curr, first_of_next), - this->display_physical(tout); - tout << "\ncurr:\n"; - this->display(tout, curr); - tout << "\nnext:\n"; - this->display(tout, next);); - SASSERT(!can_be_merged(last_of_curr, first_of_next)); - } - curr = next; - } - } - bucket const * curr = this->m_header; - while (curr != 0) { - check_invariant(curr); - curr = curr->get_next(0); - } - return true; - } -#endif - - static void display_size_info(std::ostream & out) { - skip_list_base::display_size_info_core(out, sizeof(interval_skip_list)); - } - - /** - \brief Return the amount of memory consumed by the list. - */ - unsigned memory() const { - return this->memory_core(sizeof(interval_skip_list)); - } - -}; - -/** - \brief Traits for instantiating a mapping from unsigned to Value using the interval_skip_list template. -*/ -template, - unsigned MaxCapacity=32, - unsigned MaxLevel=32, - bool RefCount=false, - typename Manager=sl_manager_base > -struct unsigned_interval_skip_list_traits : private EqProc { - typedef default_islist_entry entry; - typedef Manager manager; - typedef typename entry::key key; - typedef typename entry::value value; - static const unsigned max_capacity = MaxCapacity; - static const unsigned initial_capacity = 2; - static const unsigned max_level = MaxLevel; - static const bool ref_count = RefCount; - - bool lt(key const & k1, key const & k2) const { return k1 < k2; } - bool eq(key const & k1, key const & k2) const { return k1 == k2; } - key succ(key const & k) const { return k + 1; } - key pred(key const & k) const { SASSERT(k > 0); return k - 1; } - bool val_eq(value const & v1, value const & v2) const { return EqProc::operator()(v1, v2); } -}; - -/** - \brief Traits for instantiating a set of unsigned values using the interval_skip_list template. -*/ -template > -struct unsigned_set_interval_skip_list_traits { - typedef default_set_islist_entry entry; - typedef Manager manager; - typedef typename entry::key key; - typedef typename entry::value value; - static const unsigned max_capacity = MaxCapacity; - static const unsigned initial_capacity = 2; - static const unsigned max_level = MaxLevel; - static const bool ref_count = false; - - bool lt(key const & k1, key const & k2) const { return k1 < k2; } - bool eq(key const & k1, key const & k2) const { return k1 == k2; } - key succ(key const & k) const { return k + 1; } - key pred(key const & k) const { SASSERT(k > 0); return k - 1; } - bool val_eq(value const & v1, value const & v2) const { return true; } -}; - -/** - \brief Generic adapater for generating a set-like API on top of the map API -*/ -template -class map2set_adapter : public Map { - typedef typename Map::manager manager; - typedef typename Map::key key; - typedef typename Map::value value; - - template - struct for_each_functor_adapter : public Functor { - for_each_functor_adapter(Functor const & f):Functor(f) { - } - bool operator()(key const & b, key const & e, value const & v) { - return Functor::operator()(b, e); - } - }; - -public: - map2set_adapter(manager & m): - Map(m) { - SASSERT(this->m_header != 0); - } - - void insert(manager & m, key const & b, key const & e) { - value _dummy; - Map::insert(m, b, e, _dummy); - } - - void insert(manager & m, key const & k) { - value _dummy; - Map::insert(m, k, k, _dummy); - } - - bool contains(key const & k) const { - value _dummy; - return Map::contains(k); - } - - bool find(key const & k) const { - return contains(k); - } - - /** - \begin Traverse the set applying the functor f. - The functor must have a method - - bool operator()(key const & b, key const & e) - - The method will invoke f(b, e) whenever the interval [b, e] are - in the set. - - If the functor returns false, then the traversal is interrupted. - */ - template - void for_each(Functor & f) const { - for_each_functor_adapter F(f); - Map::for_each(F); - } -}; - - -/** - \brief A set of unsigned values using interval_skip_list. -*/ -template > -class unsigned_isp_set : public map2set_adapter > > { -public: - unsigned_isp_set(Manager & m): - map2set_adapter > >(m) { - } -}; - -#endif /* _INTERVAL_SKIP_LIST_H_ */ - - diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index e2232dafe..63ac6cf4b 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -25,7 +25,6 @@ Revision History: #include "dl_mk_rule_inliner.h" #include "dl_rule.h" #include "dl_rule_transformer.h" -#include "dl_mk_extract_quantifiers.h" #include "smt2parser.h" #include "pdr_context.h" #include "pdr_dl_interface.h" @@ -33,7 +32,6 @@ Revision History: #include "dl_mk_slice.h" #include "dl_mk_unfold.h" #include "dl_mk_coalesce.h" -#include "pdr_quantifiers.h" using namespace pdr; @@ -57,41 +55,36 @@ dl_interface::~dl_interface() { // re-use existing context. // void dl_interface::check_reset() { - datalog::rule_ref_vector const& new_rules = m_ctx.get_rules().get_rules(); + datalog::rule_set const& new_rules = m_ctx.get_rules(); datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules(); bool is_subsumed = !old_rules.empty(); - for (unsigned i = 0; is_subsumed && i < new_rules.size(); ++i) { + for (unsigned i = 0; is_subsumed && i < new_rules.get_num_rules(); ++i) { is_subsumed = false; for (unsigned j = 0; !is_subsumed && j < old_rules.size(); ++j) { - if (m_ctx.check_subsumes(*old_rules[j], *new_rules[i])) { + if (m_ctx.check_subsumes(*old_rules[j], *new_rules.get_rule(i))) { is_subsumed = true; } } if (!is_subsumed) { - TRACE("pdr", new_rules[i]->display(m_ctx, tout << "Fresh rule ");); + TRACE("pdr", new_rules.get_rule(i)->display(m_ctx, tout << "Fresh rule ");); m_context->reset(); } } - m_old_rules.reset(); - m_old_rules.add_rules(new_rules.size(), new_rules.c_ptr()); + m_old_rules.replace_rules(new_rules); } lbool dl_interface::query(expr * query) { //we restore the initial state in the datalog context m_ctx.ensure_opened(); - m_pdr_rules.reset(); m_refs.reset(); m_pred2slice.reset(); ast_manager& m = m_ctx.get_manager(); - datalog::rule_manager& rule_manager = m_ctx.get_rule_manager(); + datalog::rule_manager& rm = m_ctx.get_rule_manager(); datalog::rule_set old_rules(m_ctx.get_rules()); func_decl_ref query_pred(m); - datalog::rule_ref_vector query_rules(rule_manager); - datalog::rule_ref query_rule(rule_manager); - rule_manager.mk_query(query, query_pred, query_rules, query_rule); - m_ctx.add_rules(query_rules); + rm.mk_query(query, m_ctx.get_rules()); expr_ref bg_assertion = m_ctx.get_background_assertion(); check_reset(); @@ -107,7 +100,6 @@ lbool dl_interface::query(expr * query) { ); - m_ctx.set_output_predicate(query_pred); m_ctx.apply_default_transformation(); if (m_ctx.get_params().slice()) { @@ -115,8 +107,6 @@ lbool dl_interface::query(expr * query) { datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); transformer.register_plugin(slice); m_ctx.transform_rules(transformer); - query_pred = slice->get_predicate(query_pred.get()); - m_ctx.set_output_predicate(query_pred); // track sliced predicates. obj_map const& preds = slice->get_predicates(); @@ -142,23 +132,14 @@ lbool dl_interface::query(expr * query) { --num_unfolds; } } - // remove universal quantifiers from body. + query_pred = m_ctx.get_rules().get_output_predicate(); - - datalog::mk_extract_quantifiers* extract_quantifiers = alloc(datalog::mk_extract_quantifiers, m_ctx); - datalog::rule_transformer extract_q_tr(m_ctx); - extract_q_tr.register_plugin(extract_quantifiers); - m_ctx.transform_rules(extract_q_tr); - - IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); - m_pdr_rules.add_rules(m_ctx.get_rules()); + m_pdr_rules.replace_rules(m_ctx.get_rules()); m_pdr_rules.close(); m_ctx.reopen(); m_ctx.replace_rules(old_rules); - - quantifier_model_checker quantifier_mc(*m_context, m, extract_quantifiers->quantifiers(), m_pdr_rules); datalog::scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode. @@ -173,20 +154,7 @@ lbool dl_interface::query(expr * query) { return l_false; } - lbool result; - while (true) { - result = m_context->solve(); - if (result == l_true && extract_quantifiers->has_quantifiers()) { - result = quantifier_mc.check(); - if (result != l_false) { - return result; - } - // else continue - } - else { - return result; - } - } + return m_context->solve(); } diff --git a/src/muz_qe/pdr_manager.cpp b/src/muz_qe/pdr_manager.cpp index 04facc776..3e79e4f00 100644 --- a/src/muz_qe/pdr_manager.cpp +++ b/src/muz_qe/pdr_manager.cpp @@ -132,7 +132,7 @@ namespace pdr { for_each_expr(collect_decls, m_relation_info[i].m_body); } for (unsigned i = 0; i < rules.size(); ++i) { - bound_decls.insert(rules[i]->get_head()->get_decl()); + bound_decls.insert(rules[i]->get_decl()); } for (unsigned i = 0; i < rules.size(); ++i) { unsigned u_sz = rules[i]->get_uninterpreted_tail_size(); diff --git a/src/muz_qe/pdr_quantifiers.cpp b/src/muz_qe/pdr_quantifiers.cpp deleted file mode 100644 index 4a7b4b995..000000000 --- a/src/muz_qe/pdr_quantifiers.cpp +++ /dev/null @@ -1,660 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - pdr_quantifiers.cpp - -Abstract: - - Module for handling quantifiers in rule bodies. - -Author: - - Nikolaj Bjorner (nbjorner) 2012-05-19. - -Revision History: - ---*/ - -#include "pdr_quantifiers.h" -#include "pdr_context.h" -#include "qe.h" -#include "var_subst.h" -#include "dl_rule_set.h" -#include "ast_smt2_pp.h" -#include "model_smt2_pp.h" -#include "ast_smt_pp.h" -#include "expr_abstract.h" -#include "dl_mk_extract_quantifiers.h" -#include "qe_lite.h" -#include "well_sorted.h" -#include "expr_safe_replace.h" - - -namespace pdr { - - /** - \brief model check a potential model against quantifiers in bodies of rules. - - \return true if the model rooted in 'root' is checks with the quantifiers, otherwise - 'false' and a set of instantiations that contradict the current model. - */ - - static void get_nodes(model_node& root, ptr_vector& nodes) { - ptr_vector todo; - todo.push_back(&root); - while (!todo.empty()) { - model_node* n = todo.back(); - todo.pop_back(); - nodes.push_back(n); - todo.append(n->children().size(), n->children().c_ptr()); - } - } - - quantifier_model_checker::~quantifier_model_checker() { - obj_map::iterator it = m_reachable.begin(), end = m_reachable.end(); - for (; it != end; ++it) { - m.dec_ref(it->m_value); - } - } - - void quantifier_model_checker::generalize_binding(expr_ref_vector const& binding, vector& bindings) { - expr_ref_vector new_binding(m); - generalize_binding(binding, 0, new_binding, bindings); - } - - void quantifier_model_checker::generalize_binding( - expr_ref_vector const& binding, unsigned idx, - expr_ref_vector& new_binding, vector& bindings) { - if (idx == binding.size()) { - bool non_zero = false; - for (unsigned i = 0; i < binding.size(); ++i) { - if (new_binding[i].get()) { - non_zero = true; - } - else { - new_binding[i] = binding[i]; - } - } - if (non_zero) { - TRACE("pdr", - for (unsigned i = 0; i < new_binding.size(); ++i) { - tout << mk_pp(new_binding[i].get(), m) << " "; - } - tout << "\n";); - bindings.push_back(new_binding); - } - return; - } - model_node& node = *m_current_node; - expr_ref_vector ands(m); - expr* e1, *e2; - datalog::flatten_and(node.state(), ands); - new_binding.push_back(0); - generalize_binding(binding, idx + 1, new_binding, bindings); - for (unsigned i = 0; i < ands.size(); ++i) { - if (m.is_eq(ands[i].get(), e1, e2)) { - if (e2 == binding[idx]) { - new_binding[new_binding.size()-1] = e1; - generalize_binding(binding, idx + 1, new_binding, bindings); - } - } - } - new_binding.pop_back(); - } - - - void quantifier_model_checker::add_binding(quantifier* q, expr_ref_vector& binding) { - if (binding.size() != q->get_num_decls()) { - // not a full binding. It may happen that the quantifier got simplified. - return; - } - apply_binding(q, binding); - vector bindings; - generalize_binding(binding, bindings); - for (unsigned i = 0; i < bindings.size(); ++i) { - apply_binding(q, bindings[i]); - } - } - - void quantifier_model_checker::apply_binding(quantifier* q, expr_ref_vector& binding) { - datalog::scoped_no_proof _scp(m); - app_ref_vector& var_inst = m_current_pt->get_inst(m_current_rule); - expr_ref e(m); - var_subst vs(m, false); - inv_var_shifter invsh(m); - vs(q->get_expr(), binding.size(), binding.c_ptr(), e); - invsh(e, q->get_num_decls(), e); - expr_ref_vector inst(m); - inst.append(var_inst.size(), (expr*const*)var_inst.c_ptr()); - inst.reverse(); - expr_abstract(m, 0, inst.size(), inst.c_ptr(), e, e); - if (m_instantiations.contains(to_app(e))) { - return; - } - m_instantiated_rules.push_back(m_current_rule); - m_instantiations.push_back(to_app(e)); - TRACE("pdr", tout << mk_pp(q, m) << "\n"; - tout << "binding: "; - for (unsigned i = 0; i < binding.size(); ++i) { - tout << mk_pp(binding[i].get(), m) << " "; - } - tout << "\n"; - tout << "inst: "; - for (unsigned i = 0; i < var_inst.size(); ++i) { - tout << mk_pp(var_inst[i].get(), m) << " "; - } - tout << "\n"; - tout << mk_pp(e, m) << "\n"; - ); - } - - - // As & not Body_i is satisfiable - // then instantiate with model for parameters to Body_i - - void quantifier_model_checker::find_instantiations(quantifier_ref_vector const& qs, unsigned level) { - find_instantiations_proof_based(qs, level); - } - - class collect_insts { - ast_manager& m; - ptr_vector m_binding; - vector m_bindings; - ptr_vector m_quantifiers; - public: - collect_insts(ast_manager& m): m(m) { } - - void operator()(expr* n) { - expr* not_q_or_i, *e1, *e2, *e3; - if (m.is_quant_inst(n, not_q_or_i, m_binding)) { - VERIFY(m.is_or(not_q_or_i, e1, e2)); - VERIFY(m.is_not(e1, e3)); - SASSERT(is_quantifier(e3)); - m_quantifiers.push_back(to_quantifier(e3)); - m_bindings.push_back(expr_ref_vector(m,m_binding.size(), m_binding.c_ptr())); - m_binding.reset(); - } - else if ((m.is_rewrite(n, e1, e2) || - (m.is_rewrite_star(n) && - (e3 = to_app(n)->get_arg(to_app(n)->get_num_args()-1), - e1 = to_app(e3)->get_arg(0), - e2 = to_app(e3)->get_arg(1), - true))) && - is_quantifier(e1) && m.is_false(e2)) { - quantifier* q = to_quantifier(e1); - m_quantifiers.push_back(q); - m_bindings.push_back(expr_ref_vector(m)); - expr_ref_vector& b = m_bindings.back(); - for (unsigned i = 0; i < q->get_num_decls(); ++i) { - b.push_back(m.mk_fresh_const("V", q->get_decl_sort(i))); - } - } - } - - void reset() { - m_quantifiers.reset(); - m_bindings.reset(); - } - - unsigned size() const { return m_quantifiers.size(); } - ptr_vector const& quantifiers() const { return m_quantifiers; } - vector const& bindings() const { return m_bindings; } - - }; - - void quantifier_model_checker::find_instantiations_proof_based(quantifier_ref_vector const& qs, unsigned level) { - bool found_instance = false; - - datalog::scoped_proof _scp(m); - - expr_ref_vector fmls(m); - smt_params fparams; - SASSERT(m.proofs_enabled()); - fparams.m_mbqi = true; - - fmls.push_back(m_A.get()); - fmls.append(m_Bs); - TRACE("pdr", - tout << "assert\n"; - for (unsigned i = 0; i < fmls.size(); ++i) { - tout << mk_pp(fmls[i].get(), m) << "\n"; - }); - - smt::kernel solver(m, fparams); - for (unsigned i = 0; i < fmls.size(); ++i) { - solver.assert_expr(fmls[i].get()); - } - lbool result = solver.check(); - - TRACE("pdr", tout << result << "\n";); - - if (m_rules_model_check != l_false) { - m_rules_model_check = result; - } - - if (result != l_false) { - return; - } - - map qid_map; - quantifier* q; - for (unsigned i = 0; i < qs.size(); ++i) { - q = qs[i]; - qid_map.insert(q->get_qid(), q); - } - - proof* p = solver.get_proof(); - TRACE("pdr", tout << mk_ismt2_pp(p, m) << "\n";); - collect_insts collector(m); - for_each_expr(collector, p); - ptr_vector const& quants = collector.quantifiers(); - - for (unsigned i = 0; i < collector.size(); ++i) { - symbol qid = quants[i]->get_qid(); - if (!qid_map.find(qid, q)) { - TRACE("pdr", tout << "Could not find quantifier " << mk_pp(quants[i], m) << "\n";); - continue; - } - expr_ref_vector const& binding = collector.bindings()[i]; - - TRACE("pdr", tout << "Instantiating:\n" << mk_pp(quants[i], m) << "\n"; - for (unsigned j = 0; j < binding.size(); ++j) { - tout << mk_pp(binding[j], m) << " "; - } - tout << "\n";); - - expr_ref_vector new_binding(m); - for (unsigned j = 0; j < binding.size(); ++j) { - new_binding.push_back(binding[j]); - } - add_binding(q, new_binding); - found_instance = true; - } - if (found_instance) { - m_rules_model_check = l_false; - } - else if (m_rules_model_check != l_false) { - m_rules_model_check = l_undef; - } - } - - - /** - For under-approximations: - - m_reachable: set of reachable states, per predicate - - rules: P(x) :- B[x,y] & Fa z . Q(y,z) - Q(y,z) :- C[y,z,u] & Fa w . R(u,w) - - qis: Fa z . Q(y,z) - - M: model satisfying P(x) & B[x,y] - - B'[x,y]: body with reachable states substituted for predicates. - - Q'[y,z]: reachable states substituted for Q. - - S'[x]: Ex y . B'[x,y] & Fa z . Q'[y, z] - - Method: - - 1. M |= Fa z . Q'[y, z] => done - - Weaker variant: - Check B[x,y] & Fa z . Q'[y, z] for consistency. - - 2. Otherwise, extract instantiations. - - 3. Update reachable (for next round): - - Q'[y,z] := Q'[y,z] \/ C'[y,z,u] & Fa w . R'(u,w) - - */ - - - /** - For over-approximations: - - - pt - predicate transformer for rule: - P(x) :- Body1(x,y) || Body2(x,z) & (Fa u . Q(u,x,z)). - - rule - P(x) :- Body2(x,z) - - - qis - Fa u . Q(u,x,z) - - - A := node.state(x) && Body2(x,y) - - - - Bs := array of Bs of the form: - . Fa u . Q(u, P_x, P_y) - instantiate quantifier to P variables. - . B := inv(Q_0,Q_1,Q_2) - . B := inv(u, P_x, P_y) := B[u/Q_0, P_x/Q_1, P_y/Q_2] - . B := Fa u . inv(u, P_x, P_y) - - */ - - void quantifier_model_checker::update_reachable(func_decl* f, expr* e) { - expr* e_old; - m.inc_ref(e); - if (m_reachable.find(f, e_old)) { - m.dec_ref(e_old); - } - m_reachable.insert(f, e); - } - - - expr_ref quantifier_model_checker::get_reachable(func_decl* p) { - expr* e = 0; - if (!m_reachable.find(p, e)) { - e = m_ctx.get_pred_transformer(p).initial_state(); - update_reachable(p, e); - } - return expr_ref(e, m); - } - - void quantifier_model_checker::add_over_approximations(quantifier_ref_vector& qis, model_node& n) { - add_approximations(qis, n, true); - } - - void quantifier_model_checker::add_under_approximations(quantifier_ref_vector& qis, model_node& n) { - add_approximations(qis, n, false); - } - - void quantifier_model_checker::add_approximations(quantifier_ref_vector& qis, model_node& n, bool is_over) { - pred_transformer& pt = n.pt(); - manager& pm = pt.get_pdr_manager(); - unsigned level = n.level(); - expr_ref_vector Bs(m); - expr_ref B(m), v(m); - quantifier_ref q(m); - datalog::scoped_no_proof _no_proof(m); - scoped_ptr rep = mk_default_expr_replacer(m); - for (unsigned j = 0; j < qis.size(); ++j) { - q = qis[j].get(); - SASSERT(is_forall(q)); - app_ref_vector& inst = pt.get_inst(m_current_rule); - TRACE("pdr", - tout << "q:\n" << mk_pp(q, m) << "\n"; - tout << "level: " << level << "\n"; - model_smt2_pp(tout, m, n.get_model(), 0); - m_current_rule->display(m_ctx.get_context(), tout << "rule:\n"); - ); - - var_subst vs(m, false); - vs(q, inst.size(), (expr*const*)inst.c_ptr(), B); - q = to_quantifier(B); - TRACE("pdr", tout << "q instantiated:\n" << mk_pp(q, m) << "\n";); - - app* a = to_app(q->get_expr()); - func_decl* f = a->get_decl(); - pred_transformer& pt2 = m_ctx.get_pred_transformer(f); - if (is_over) { - B = pt2.get_formulas(level - 1, false); - } - else { - B = get_reachable(f); - SASSERT(is_well_sorted(m, B)); - } - TRACE("pdr", tout << "B:\n" << mk_pp(B, m) << "\n";); - - expr_safe_replace sub(m); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - v = m.mk_const(pm.o2n(pt2.sig(i),0)); - sub.insert(v, a->get_arg(i)); - } - sub(B); - TRACE("pdr", tout << "B substituted:\n" << mk_pp(B, m) << "\n";); - datalog::flatten_and(B, Bs); - for (unsigned i = 0; i < Bs.size(); ++i) { - m_Bs.push_back(m.update_quantifier(q, Bs[i].get())); - } - } - } - - /** - \brief compute strongest post-conditions for each predicate transformer. - (or at least something sufficient to change the set of current counter-examples) - */ - void quantifier_model_checker::weaken_under_approximation() { - - datalog::rule_set::decl2rules::iterator it = m_rules.begin_grouped_rules(), end = m_rules.end_grouped_rules(); - - for (; it != end; ++it) { - func_decl* p = it->m_key; - datalog::rule_vector& rules = *it->m_value; - expr_ref_vector bodies(m); - for (unsigned i = 0; i < rules.size(); ++i) { - bodies.push_back(strongest_post_condition(*rules[i])); - } - update_reachable(p, m.mk_or(bodies.size(), bodies.c_ptr())); - } - } - - expr_ref quantifier_model_checker::strongest_post_condition(datalog::rule& r) { - pred_transformer& pt = m_ctx.get_pred_transformer(r.get_decl()); - manager& pm = pt.get_pdr_manager(); - quantifier_ref_vector* qis = 0; - m_quantifiers.find(&r, qis); - expr_ref_vector body(m), inst(m); - expr_ref fml(m), v(m); - app* a; - func_decl* p; - svector names; - unsigned ut_size = r.get_uninterpreted_tail_size(); - unsigned t_size = r.get_tail_size(); - var_subst vs(m, false); - ptr_vector vars; - uint_set empty_index_set; - qe_lite qe(m); - - r.get_vars(vars); - - if (qis) { - quantifier_ref_vector const& qi = *qis; - for (unsigned i = 0; i < qi.size(); ++i) { - quantifier* q = qi[i]; - fml = q->get_expr(); - a = to_app(fml); - p = a->get_decl(); - expr* p_reach = get_reachable(p); - pred_transformer& pt2 = m_ctx.get_pred_transformer(p); - expr_safe_replace sub(m); - for (unsigned j = 0; j < a->get_num_args(); ++j) { - v = m.mk_const(pm.o2n(pt2.sig(j),0)); - sub.insert(v, a->get_arg(j)); - } - sub(p_reach, fml); - uint_set is; - for (unsigned j = 0; j < q->get_num_decls(); ++j) { - is.insert(j); - } - fml = m.mk_not(fml); - qe(is, true, fml); - fml = m.mk_not(fml); - body.push_back(m.update_quantifier(q, fml)); - } - } - - a = r.get_head(); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - v = m.mk_var(vars.size()+i, m.get_sort(a->get_arg(i))); - body.push_back(m.mk_eq(v, a->get_arg(i))); - } - for (unsigned i = 0; i < ut_size; ++i) { - a = r.get_tail(i); - p = a->get_decl(); - pred_transformer& pt2 = m_ctx.get_pred_transformer(p); - expr* p_reach = get_reachable(p); - expr_safe_replace sub(m); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - v = m.mk_const(pm.o2n(pt2.sig(i),0)); - sub.insert(v, a->get_arg(i)); - } - sub(p_reach, fml); - body.push_back(fml); - } - for (unsigned i = ut_size; i < t_size; ++i) { - body.push_back(r.get_tail(i)); - } - fml = m.mk_and(body.size(), body.c_ptr()); - vars.reverse(); - for (unsigned i = 0; i < vars.size(); ++i) { - names.push_back(symbol(i)); - } - if (!vars.empty()) { - fml = m.mk_exists(vars.size(), vars.c_ptr(), names.c_ptr(), fml); - SASSERT(is_well_sorted(m, fml)); - } - - for (unsigned i = 0; i < r.get_head()->get_num_args(); ++i) { - inst.push_back(m.mk_const(pm.o2n(pt.sig(i),0))); - } - vs(fml, inst.size(), inst.c_ptr(), fml); - SASSERT(is_well_sorted(m, fml)); - if (!vars.empty()) { - fml = to_quantifier(fml)->get_expr(); - qe(empty_index_set, false, fml); - fml = m.mk_exists(vars.size(), vars.c_ptr(), names.c_ptr(), fml); - SASSERT(is_well_sorted(m, fml)); - m_ctx.get_context().get_rewriter()(fml); - } - SASSERT(is_well_sorted(m, fml)); - - IF_VERBOSE(0, verbose_stream() << "instantiate to:\n" << mk_pp(fml, m) << "\n";); - return fml; - } - - - void quantifier_model_checker::model_check_node(model_node& node) { - TRACE("pdr", node.display(tout, 0);); - pred_transformer& pt = node.pt(); - manager& pm = pt.get_pdr_manager(); - expr_ref A(m), C(m); - expr_ref_vector As(m); - m_Bs.reset(); - // - // nodes from leaves that are repeated - // inside the search tree don't have models. - // - if (!node.get_model_ptr()) { - return; - } - m_current_rule = node.get_rule(); - m_current_pt = &pt; - m_current_node = &node; - if (!m_current_rule) { - return; - } - - quantifier_ref_vector* qis = 0; - m_quantifiers.find(m_current_rule, qis); - if (!qis) { - return; - } - unsigned level = node.level(); - if (level == 0) { - return; - } - - As.push_back(pt.get_propagation_formula(m_ctx.get_pred_transformers(), level)); - As.push_back(node.state()); - As.push_back(pt.rule2tag(m_current_rule)); - m_A = pm.mk_and(As); - - // Add quantifiers: - // add_over_approximations(*qis, node); - add_under_approximations(*qis, node); - - TRACE("pdr", - tout << "A:\n" << mk_pp(m_A, m) << "\n"; - tout << "quantifier:\n"; - for (unsigned i = 0; i < qis->size(); ++i) { - tout << mk_pp((*qis)[i].get(), m) << " "; - } - tout << "\n"; - tout << "B:\n"; - for (unsigned i = 0; i < m_Bs.size(); ++i) { - tout << mk_pp(m_Bs[i].get(), m) << "\n"; - } - ast_smt_pp pp(m); - pp.add_assumption(m_A); - for (unsigned i = 0; i < m_Bs.size(); ++i) { - pp.add_assumption(m_Bs[i].get()); - } - pp.display_smt2(tout, m.mk_true()); - ); - - find_instantiations(*qis, level); - } - - lbool quantifier_model_checker::model_check(model_node& root) { - m_instantiations.reset(); - m_instantiated_rules.reset(); - m_rules_model_check = l_true; - ptr_vector nodes; - get_nodes(root, nodes); - for (unsigned i = nodes.size(); i > 0; ) { - --i; - model_check_node(*nodes[i]); - } - if (m_rules_model_check == l_false) { - weaken_under_approximation(); - } - return m_rules_model_check; - } - - void quantifier_model_checker::refine() { - datalog::mk_extract_quantifiers eq(m_ctx.get_context()); - datalog::rule_manager& rm = m_rules.get_rule_manager(); - datalog::rule_set new_rules(m_rules.get_context()); - datalog::rule_set::iterator it = m_rules.begin(), end = m_rules.end(); - for (; it != end; ++it) { - datalog::rule* r = *it; - datalog::rule_counter vc(true); - unsigned max_var = vc.get_max_rule_var(*r); - app_ref_vector body(m); - for (unsigned i = 0; i < m_instantiations.size(); ++i) { - if (r == m_instantiated_rules[i]) { - eq.ensure_predicate(m_instantiations[i].get(), max_var, body); - } - } - if (body.empty()) { - new_rules.add_rule(r); - } - else { - for (unsigned i = 0; i < r->get_tail_size(); ++i) { - body.push_back(r->get_tail(i)); - } - quantifier_ref_vector* qs = 0; - m_quantifiers.find(r, qs); - m_quantifiers.remove(r); - datalog::rule_ref new_rule(rm); - new_rule = rm.mk(r->get_head(), body.size(), body.c_ptr(), 0, r->name(), false); - new_rules.add_rule(new_rule); - m_quantifiers.insert(new_rule, qs); - IF_VERBOSE(1, - verbose_stream() << "instantiating quantifiers\n"; - r->display(m_ctx.get_context(), verbose_stream()); - verbose_stream() << "replaced by\n"; - new_rule->display(m_ctx.get_context(), verbose_stream());); - } - } - new_rules.close(); - m_rules.reset(); - m_rules.add_rules(new_rules); - m_rules.close(); - m_ctx.update_rules(m_rules); - TRACE("pdr", m_rules.display(tout);); - } - - lbool quantifier_model_checker::check() { - lbool result = model_check(m_ctx.get_root()); - if (result == l_false) { - refine(); - } - return result; - } -}; - diff --git a/src/muz_qe/pdr_quantifiers.h b/src/muz_qe/pdr_quantifiers.h deleted file mode 100644 index 941fab3d9..000000000 --- a/src/muz_qe/pdr_quantifiers.h +++ /dev/null @@ -1,117 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - pdr_quantifiers.h - -Abstract: - - Module for handling quantifiers in rule bodies. - -Author: - - Nikolaj Bjorner (nbjorner) 2012-05-19. - -Revision History: - ---*/ - -#ifndef _PDR_QUANTIFIERS_H_ -#define _PDR_QUANTIFIERS_H_ - -#include "ast.h" -#include "lbool.h" -#include "dl_rule.h" -#include "obj_pair_hashtable.h" - -namespace datalog { - class rule_set; -}; - -namespace pdr { - - class model_node; - class pred_transformer; - class context; - - class quantifier_model_checker { - context& m_ctx; - ast_manager& m; - obj_map& m_quantifiers; - datalog::rule_set& m_rules; - - obj_map m_reachable; // set of reachable states - expr_ref m_A; - expr_ref_vector m_Bs; - pred_transformer* m_current_pt; - datalog::rule const* m_current_rule; - model_node* m_current_node; - lbool m_rules_model_check; - app_ref_vector m_instantiations; - ptr_vector m_instantiated_rules; - - void model_check_node(model_node& node); - - void weaken_under_approximation(); - - void find_instantiations(quantifier_ref_vector const& qs, unsigned level); - - void find_instantiations_proof_based(quantifier_ref_vector const& qs, unsigned level); - - void add_binding(quantifier* q, expr_ref_vector& binding); - - void apply_binding(quantifier* q, expr_ref_vector& binding); - - void generalize_binding(expr_ref_vector const& binding, vector& bindings); - - void generalize_binding(expr_ref_vector const& binding, unsigned idx, expr_ref_vector& new_binding, vector& bindings); - - void refine(); - - - /** - \brief model check a potential model against quantifiers in bodies of rules. - - \return true if the model rooted in 'root' is checks with the quantifiers, otherwise - 'false' and a set of instantiations that contradict the current model. - */ - - lbool model_check(model_node& root); - - void add_over_approximations(quantifier_ref_vector& qis, model_node& n); - - void add_under_approximations(quantifier_ref_vector& qis, model_node& n); - - void add_approximations(quantifier_ref_vector& qis, model_node& n, bool is_over); - - expr_ref get_reachable(func_decl* f); - - void update_reachable(func_decl* f, expr* e); - - expr_ref strongest_post_condition(datalog::rule& r); - - public: - quantifier_model_checker( - context& ctx, - ast_manager& m, - obj_map& quantifiers, - datalog::rule_set& rules) : - m_ctx(ctx), - m(m), - m_quantifiers(quantifiers), - m_rules(rules), - m_A(m), - m_Bs(m), - m_current_pt(0), - m_current_rule(0), - m_current_node(0), - m_instantiations(m) {} - - ~quantifier_model_checker(); - - lbool check(); - }; - -}; -#endif diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 12045047b..08ac1fa14 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -34,7 +34,40 @@ Revision History: #include"dl_table_relation.h" namespace datalog { - + + class rel_context::scoped_query { + context& m_ctx; + rule_set m_rules; + decl_set m_preds; + bool m_was_closed; + public: + scoped_query(context& ctx): + m_ctx(ctx), + m_rules(ctx.get_rules()), + m_preds(ctx.get_predicates()), + m_was_closed(ctx.is_closed()) + { + if (m_was_closed) { + ctx.reopen(); + } + } + ~scoped_query() { + m_ctx.reopen(); + m_ctx.restrict_predicates(m_preds); + m_ctx.replace_rules(m_rules); + if (m_was_closed) { + m_ctx.close(); + } + } + + void reset() { + m_ctx.reopen(); + m_ctx.restrict_predicates(m_preds); + m_ctx.replace_rules(m_rules); + m_ctx.close(); + } + }; + rel_context::rel_context(context& ctx) : m_context(ctx), m(ctx.get_manager()), @@ -56,9 +89,7 @@ namespace datalog { get_rmanager().register_plugin(alloc(bound_relation_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(interval_relation_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(karr_relation_plugin, get_rmanager())); - - -} + } rel_context::~rel_context() { if (m_last_result_relation) { @@ -67,25 +98,6 @@ namespace datalog { } } - void rel_context::collect_predicates(decl_set & res) { - unsigned rule_cnt = m_context.get_rules().get_num_rules(); - for (unsigned rindex=0; rindexget_head()->get_decl()); - unsigned tail_len = r->get_uninterpreted_tail_size(); - for (unsigned tindex=0; tindexget_tail(tindex)->get_decl()); - } - } - decl_set::iterator oit = m_output_preds.begin(); - decl_set::iterator oend = m_output_preds.end(); - for (; oit!=oend; ++oit) { - res.insert(*oit); - } - get_rmanager().collect_predicates(res); - } - - lbool rel_context::saturate() { m_context.ensure_closed(); @@ -93,9 +105,7 @@ namespace datalog { unsigned remaining_time_limit = m_context.soft_timeout(); unsigned restart_time = m_context.initial_restart_timeout(); - rule_set original_rules(m_context.get_rules()); - decl_set original_predicates; - m_context.collect_predicates(original_predicates); + scoped_query scoped_query(m_context); m_code.reset(); instruction_block termination_code; @@ -106,6 +116,7 @@ namespace datalog { TRACE("dl", m_context.display(tout);); while (true) { + m_context.ensure_closed(); m_context.transform_rules(); if (m_context.canceled()) { result = l_undef; @@ -165,45 +176,20 @@ namespace datalog { } termination_code.reset(); - m_context.reopen(); - restrict_predicates(original_predicates); - m_context.replace_rules(original_rules); - m_context.close(); + scoped_query.reset(); } - m_context.reopen(); - restrict_predicates(original_predicates); m_context.record_transformed_rules(); - m_context.replace_rules(original_rules); - m_context.close(); TRACE("dl", m_ectx.report_big_relations(100, tout);); m_code.process_all_costs(); m_code.make_annotations(m_ectx); return result; } - -#define BEGIN_QUERY() \ - rule_set original_rules(m_context.get_rules()); \ - decl_set original_preds; \ - m_context.collect_predicates(original_preds); \ - bool was_closed = m_context.is_closed(); \ - if (was_closed) { \ - m_context.reopen(); \ - } \ - -#define END_QUERY() \ - m_context.reopen(); \ - m_context.replace_rules(original_rules); \ - restrict_predicates(original_preds); \ - \ - if (was_closed) { \ - m_context.close(); \ - } \ lbool rel_context::query(unsigned num_rels, func_decl * const* rels) { get_rmanager().reset_saturated_marks(); - BEGIN_QUERY(); + scoped_query _scoped_query(m_context); for (unsigned i = 0; i < num_rels; ++i) { - set_output_predicate(rels[i]); + m_context.set_output_predicate(rels[i]); } m_context.close(); reset_negated_tables(); @@ -238,27 +224,16 @@ namespace datalog { case l_undef: break; } - END_QUERY(); return res; } lbool rel_context::query(expr* query) { get_rmanager().reset_saturated_marks(); - BEGIN_QUERY(); + scoped_query _scoped_query(m_context); rule_manager& rm = m_context.get_rule_manager(); - rule_ref qrule(rm); - rule_ref_vector qrules(rm); func_decl_ref query_pred(m); try { - rm.mk_query(query, query_pred, qrules, qrule); - } - catch(default_exception& exn) { - m_context.close(); - m_context.set_status(INPUT_ERROR); - throw exn; - } - try { - m_context.add_rules(qrules); + query_pred = rm.mk_query(query, m_context.get_rules()); } catch (default_exception& exn) { m_context.close(); @@ -266,29 +241,17 @@ namespace datalog { throw exn; } - set_output_predicate(qrule->get_head()->get_decl()); m_context.close(); reset_negated_tables(); if (m_context.generate_explanations()) { - rule_transformer transformer(m_context); - //expl_plugin is deallocated when transformer goes out of scope - mk_explanations * expl_plugin = - alloc(mk_explanations, m_context, m_context.explanations_on_relation_level()); - transformer.register_plugin(expl_plugin); - m_context.transform_rules(transformer); - - //we will retrieve the predicate with explanations instead of the original query predicate - query_pred = expl_plugin->get_e_decl(query_pred); - const rule_vector & query_rules = m_context.get_rules().get_predicate_rules(query_pred); - SASSERT(query_rules.size()==1); - qrule = query_rules.back(); + m_context.transform_rules(alloc(mk_explanations, m_context)); } + query_pred = m_context.get_rules().get_pred(query_pred); + if (m_context.magic_sets_for_queries()) { - rule_transformer transformer(m_context); - transformer.register_plugin(alloc(mk_magic_sets, m_context, qrule.get())); - m_context.transform_rules(transformer); + m_context.transform_rules(alloc(mk_magic_sets, m_context, query_pred)); } lbool res = saturate(); @@ -304,7 +267,6 @@ namespace datalog { } } - END_QUERY(); return res; } @@ -372,15 +334,8 @@ namespace datalog { } } - void rel_context::set_output_predicate(func_decl * pred) { - if (!m_output_preds.contains(pred)) { - m_output_preds.insert(pred); - } - } - - void rel_context::restrict_predicates( const decl_set & res ) { - set_intersection(m_output_preds, res); - get_rmanager().restrict_predicates(res); + void rel_context::restrict_predicates(func_decl_set const& predicates) { + get_rmanager().restrict_predicates(predicates); } relation_base & rel_context::get_relation(func_decl * pred) { return get_rmanager().get_relation(pred); } @@ -510,8 +465,8 @@ namespace datalog { } } - void rel_context::display_output_facts(std::ostream & out) const { - get_rmanager().display_output_tables(out); + void rel_context::display_output_facts(rule_set const& rules, std::ostream & out) const { + get_rmanager().display_output_tables(rules, out); } void rel_context::display_facts(std::ostream& out) const { diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index 08ee868c0..3ee9f76da 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -37,11 +37,12 @@ namespace datalog { relation_manager m_rmanager; expr_ref m_answer; relation_base * m_last_result_relation; - decl_set m_output_preds; fact_vector m_table_facts; execution_context m_ectx; instruction_block m_code; + class scoped_query; + void reset_negated_tables(); relation_plugin & get_ordinary_relation_plugin(symbol relation_name); @@ -78,13 +79,7 @@ namespace datalog { The function deallocates unsused relations, it does not deal with rules. */ - void restrict_predicates(const decl_set & res); - - void collect_predicates(decl_set & res); - - void set_output_predicate(func_decl * pred); - bool is_output_predicate(func_decl * pred) { return m_output_preds.contains(pred); } - const decl_set & get_output_predicates() const { return m_output_preds; } + void restrict_predicates(func_decl_set const& predicates); /** @@ -102,7 +97,7 @@ namespace datalog { */ void store_relation(func_decl * pred, relation_base * rel); - void display_output_facts(std::ostream & out) const; + void display_output_facts(rule_set const& rules, std::ostream & out) const; void display_facts(std::ostream & out) const; void display_profile(std::ostream& out) const; diff --git a/src/muz_qe/tab_context.cpp b/src/muz_qe/tab_context.cpp index 9ee059f44..44d9d94e2 100644 --- a/src/muz_qe/tab_context.cpp +++ b/src/muz_qe/tab_context.cpp @@ -191,6 +191,7 @@ namespace tb { unsigned get_index() const { return m_index; } void set_index(unsigned index) { m_index = index; } app* get_head() const { return m_head; } + func_decl* get_decl() const { return m_head->get_decl(); } void set_head(app* h) { m_head = h; } unsigned get_parent_index() const { return m_parent_index; } unsigned get_parent_rule() const { return m_parent_rule; } @@ -447,7 +448,7 @@ namespace tb { void insert(ref& g) { unsigned idx = m_rules.size(); m_rules.push_back(g); - func_decl* f = g->get_head()->get_decl(); + func_decl* f = g->get_decl(); map::obj_map_entry* e = m_index.insert_if_not_there2(f, unsigned_vector()); SASSERT(e); e->get_data().m_value.push_back(idx); @@ -613,7 +614,7 @@ namespace tb { bool match_head(clause const& g) { return - m_head->get_decl() == g.get_head()->get_decl() && + m_head->get_decl() == g.get_decl() && m_matcher(m_head, g.get_head(), m_subst, m_sideconds) && match_predicates(0, g); } @@ -1080,7 +1081,7 @@ namespace tb { bool unify(clause const& tgt, unsigned idx, clause const& src, bool compute_subst, ref& result) { qe_lite qe(m); reset(); - SASSERT(tgt.get_predicate(idx)->get_decl() == src.get_head()->get_decl()); + SASSERT(tgt.get_predicate(idx)->get_decl() == src.get_decl()); unsigned var_cnt = std::max(tgt.get_num_vars(), src.get_num_vars()); m_S1.reserve(2, var_cnt); if (!m_unifier(tgt.get_predicate(idx), src.get_head(), m_S1)) { @@ -1380,11 +1381,10 @@ namespace datalog { m_displayed_rules.reset(); m_rules.init(m_ctx.get_rules()); m_selection.init(m_rules); - rule_ref_vector query_rules(rm); + rule_set query_rules(m_ctx); rule_ref clause(rm); - func_decl_ref query_pred(m); - rm.mk_query(query, query_pred, query_rules, clause); - + rm.mk_query(query, query_rules); + clause = query_rules.last(); ref g = alloc(tb::clause, m); g->init(clause); g->set_head(m.mk_false()); diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index fe2699504..6cdfe1623 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -175,8 +175,6 @@ unsigned read_datalog(char const * file) { TRACE("dl_compiler", ctx.display(tout);); datalog::rule_set original_rules(ctx.get_rules()); - datalog::decl_set original_predicates; - ctx.collect_predicates(original_predicates); datalog::instruction_block rules_code; datalog::instruction_block termination_code; @@ -237,7 +235,6 @@ unsigned read_datalog(char const * file) { termination_code.reset(); ex_ctx.reset(); ctx.reopen(); - ctx.restrict_predicates(original_predicates); ctx.replace_rules(original_rules); ctx.close(); } @@ -248,7 +245,7 @@ unsigned read_datalog(char const * file) { rules_code.display(ctx.get_rel_context(), tout);); if (ctx.get_params().output_tuples()) { - ctx.get_rel_context().display_output_facts(std::cout); + ctx.get_rel_context().display_output_facts(ctx.get_rules(), std::cout); } display_statistics( diff --git a/src/test/dl_query.cpp b/src/test/dl_query.cpp index 4dc770056..3fab95583 100644 --- a/src/test/dl_query.cpp +++ b/src/test/dl_query.cpp @@ -59,7 +59,7 @@ void dl_query_test(ast_manager & m, smt_params & fparams, params_ref& params, } relation_manager & rel_mgr_q = ctx_b.get_rel_context().get_rmanager(); - decl_set out_preds = ctx_b.get_output_predicates(); + decl_set out_preds = ctx_b.get_rules().get_output_predicates(); decl_set::iterator it = out_preds.begin(); decl_set::iterator end = out_preds.end(); for(; it!=end; ++it) { diff --git a/src/test/dl_table.cpp b/src/test/dl_table.cpp index 0c8afcdc2..32a6f65e3 100644 --- a/src/test/dl_table.cpp +++ b/src/test/dl_table.cpp @@ -1,7 +1,6 @@ #ifdef _WINDOWS #include "dl_context.h" #include "dl_table.h" -#include "dl_skip_table.h" typedef datalog::table_base* (*mk_table_fn)(datalog::relation_manager& m, datalog::table_signature& sig); @@ -11,13 +10,6 @@ static datalog::table_base* mk_bv_table(datalog::relation_manager& m, datalog::t return p->mk_empty(sig); } -static datalog::table_base* mk_skip_table(datalog::relation_manager& m, datalog::table_signature& sig) { - datalog::table_plugin * p = m.get_table_plugin(symbol("skip")); - SASSERT(p); - return p->mk_empty(sig); -} - - static void test_table(mk_table_fn mk_table) { datalog::table_signature sig; sig.push_back(2); @@ -96,13 +88,9 @@ void test_dl_bitvector_table() { test_table(mk_bv_table); } -void test_dl_skip_table() { - test_table(mk_skip_table); -} void tst_dl_table() { test_dl_bitvector_table(); - test_dl_skip_table(); } #else void tst_dl_table() { diff --git a/src/test/imdd.cpp b/src/test/imdd.cpp deleted file mode 100644 index bfaca274c..000000000 --- a/src/test/imdd.cpp +++ /dev/null @@ -1,617 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - imdd.cpp - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2010-10-14. - -Revision History: - ---*/ -#include"imdd.h" - -#if !defined(_AMD64_) && defined(Z3DEBUG) - -static void tst0() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m), d4(m); - d1 = m.mk_empty(1); - d2 = m.mk_empty(1); - m.insert_dupdt(d1, 10, 20); - m.insert_dupdt(d1, 31, 50); - m.insert_dupdt(d2, 1, 5); - m.insert_dupdt(d2, 11, 13); - m.mk_product(d1, d2, d4); - m.mk_product(d4, d2, d4); - m.mk_product_dupdt(d1, d2); - std::cout << "d1:\n" << mk_ll_pp(d1, m) << "\n-------\n"; - m.mk_product_dupdt(d1, d2); - std::cout << "d4:\n" << mk_ll_pp(d4, m) << "\nd1:\n" << mk_ll_pp(d1, m) << "\nd2:\n" << mk_ll_pp(d2, m) << "\n"; - std::cout << d1 << "\n" << d2 << "\n"; - m.mk_product_dupdt(d1, d1); - std::cout << "d1 X d1:\n" << mk_ll_pp(d1, m) << "\n"; -} - -static void add_triple(imdd_manager & m, imdd_ref & d, unsigned l1, unsigned u1, unsigned l2, unsigned u2, unsigned l3, unsigned u3, - bool destructive = false, bool memoize = true) { - unsigned lowers[3] = {l1, l2, l3}; - unsigned uppers[3] = {u1, u2, u3}; - if (destructive) - m.add_facts_dupdt(d, 3, lowers, uppers, memoize); - else - m.add_facts(d, d, 3, lowers, uppers, memoize); - // std::cout << mk_ll_pp(d, m) << "\n"; -} - -static void add_pair(imdd_manager & m, imdd_ref & d, unsigned l1, unsigned u1, unsigned l2, unsigned u2, bool destructive = false, bool memoize = true) { - unsigned lowers[2] = {l1, l2}; - unsigned uppers[2] = {u1, u2}; - if (destructive) - m.add_facts_dupdt(d, 2, lowers, uppers, memoize); - else - m.add_facts(d, d, 2, lowers, uppers, memoize); - // std::cout << mk_ll_pp(d, m) << "\n"; -} - -static void add_some_facts(imdd_manager & m, imdd_ref & d, bool destructive = false, bool memoize = true) { - std::cout << "destructive: " << destructive << ", memoize: " << memoize << std::endl; - add_triple(m, d, 1, 10, 3, 3, 0, 100, destructive, memoize); - std::cout << mk_ll_pp(d, m) << std::endl; - SASSERT(m.contains(d, 2, 3, 20)); - SASSERT(!m.contains(d, 2, 4, 20)); - SASSERT(!m.contains(d, 2, 3, 200)); - SASSERT(!m.contains(d, 0, 3, 200)); - SASSERT(m.contains(d,1,3,0)); - add_triple(m, d, 3, 6, 3, 4, 7, 101, destructive, memoize); - std::cout << mk_ll_pp(d, m) << std::endl; - add_triple(m, d, 3, 6, 2, 2, 7, 101, destructive, memoize); - std::cout << mk_ll_pp(d, m) << std::endl; - add_triple(m, d, 3, 6, 5, 6, 7, 101, destructive, memoize); - SASSERT(m.contains(d, 2, 3, 20)); - std::cout << mk_ll_pp(d, m) << std::endl; - SASSERT(!m.contains(d, 2, 4, 20)); - SASSERT(m.contains(d, 3, 4, 20)); - SASSERT(!m.contains(d, 2, 3, 200)); - SASSERT(!m.contains(d, 0, 3, 200)); - SASSERT(m.contains(d,1,3,0)); -} - -static void tst1() { - std::cout << "--------------------------------\n"; - imdd_manager m; - { - imdd_ref d(m); - d = m.mk_empty(3); - add_some_facts(m, d); - } - { - imdd_ref d(m); - d = m.mk_empty(3); - add_some_facts(m, d, true, false); - m.defrag(d); - std::cout << mk_ll_pp(d, m) << "\n"; - } -} - -static void tst2() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m); - d1 = m.mk_empty(3); - add_triple(m, d1, 10, 20, 11, 21, 12, 22); - add_triple(m, d1, 30, 40, 31, 41, 32, 42); - d2 = m.mk_empty(3); - add_triple(m, d2, 15, 22, 15, 23, 7, 18); - add_triple(m, d2, 28, 42, 29, 39, 34, 46); - add_triple(m, d2, 28, 42, 29, 39, 100, 200); - add_triple(m, d2, 28, 42, 50, 60, 100, 200); - std::cout << mk_ll_pp(d1, m) << "\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; - m.mk_union(d1, d2, d3); - SASSERT(m.subsumes(d3, d1)); - SASSERT(m.subsumes(d3, d2)); - SASSERT(!m.subsumes(d1, d3)); - SASSERT(!m.subsumes(d2, d3)); - std::cout << "d3: " << d3.get() << "\n" << mk_ll_pp(d3, m) << "\n"; - m.mk_union_dupdt(d1, d2, false); - std::cout << "d1: " << d1.get() << "\n" << mk_ll_pp(d1, m) << "\n"; - SASSERT(m.is_equal(d1, d3)); - SASSERT(!m.is_equal(d2, d3)); - SASSERT(!m.is_equal(d2, d1)); - std::cout << "memory(d1): " << m.memory(d1) << "\n"; -} - -static void tst3() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m); - d1 = m.mk_empty(3); - unsigned mins[3] = {0,0,0}; - unsigned maxs[3] = {127, 511, 255}; - - m.mk_complement(d1, d1, 3, mins, maxs); - std::cout << d1 << "\n"; - m.mk_complement(d1, d1, 3, mins, maxs); - std::cout << d1 << "\n"; - SASSERT(d1->empty()); - - d1 = m.mk_empty(3); - add_triple(m, d1, 10, 20, 11, 21, 12, 22); - add_triple(m, d1, 30, 40, 31, 41, 32, 42); - std::cout << d1 << "\n"; - m.mk_complement(d1, d1, 3, mins, maxs); - std::cout << mk_ll_pp(d1,m) << "\n"; - m.mk_filter_equal(d1, d1, 1, 15); - std::cout << "after selecting second column = 15\n" << mk_ll_pp(d1,m) << "\n"; -} - -static void tst4() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m); - d1 = m.mk_empty(3); - add_triple(m, d1, 1, 2, 2, 5, 4, 4); - add_triple(m, d1, 3, 4, 3, 4, 2, 5); - std::cout << "testing iterator:\n"; - imdd_manager::iterator it = m.begin(d1); - imdd_manager::iterator end = m.end(d1); - for (; it != end; ++it) { - unsigned * tuple = *it; - std::cout << "["; - for (unsigned i = 0; i < d1->get_arity(); i++) { - if (i > 0) - std::cout << ", "; - std::cout << tuple[i]; - } - std::cout << "]\n"; - } -} - -static void tst5() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m); - std::cout.flush(); - d1 = m.mk_empty(3); - add_triple(m, d1, 5, 100, 10, 20, 3, 10); - std::cout << mk_ll_pp(d1,m) << std::endl; - add_triple(m, d1, 5, 100, 34, 50, 98, 110); - std::cout << mk_ll_pp(d1,m) << std::endl; - unsigned vals[3] = {6, 8, 3}; - SASSERT(!m.contains(d1, 3, vals)); - add_triple(m, d1, 6, 25, 8, 30, 14, 50); - std::cout << mk_ll_pp(d1,m) << std::endl; - SASSERT(!m.contains(d1, 3, vals)); - unsigned vars[2] = {0, 2}; - d2 = d1; - d3 = d1; - m.mk_filter_identical(d1, d1, 2, vars); - vars[1] = 1; - std::cout << "d1:\n" << mk_ll_pp(d1,m) << "\n"; - m.mk_filter_identical(d2, d2, 2, vars); - std::cout << "d2:\n" << mk_ll_pp(d2,m) << "\n"; - vars[0] = 1; - vars[1] = 2; - m.mk_filter_identical(d3, d3, 2, vars); - std::cout << "d3:\n" << mk_ll_pp(d3,m) << "\n"; -} - -static void add_5tuple(imdd_manager & m, imdd_ref & d, unsigned l1, unsigned u1, unsigned l2, unsigned u2, unsigned l3, unsigned u3, - unsigned l4, unsigned u4, unsigned l5, unsigned u5, bool destructive = false, bool memoize = true) { - unsigned lowers[5] = {l1, l2, l3, l4, l5}; - unsigned uppers[5] = {u1, u2, u3, u4, u5}; - if (destructive) - m.add_facts_dupdt(d, 5, lowers, uppers, memoize); - else - m.add_facts(d, d, 5, lowers, uppers, memoize); - // std::cout << mk_ll_pp(d, m) << "\n"; -} - -static void tst6() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m); - std::cout.flush(); - d1 = m.mk_empty(5); - // TODO: make a more complicated mk_filter_identical example -} - -static void tst7() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d2(m), d3(m); - d2 = m.mk_empty(3); - add_triple(m, d2, 15, 22, 15, 23, 7, 18); - add_triple(m, d2, 28, 42, 29, 39, 34, 46); - add_triple(m, d2, 28, 42, 29, 39, 100, 200); - add_triple(m, d2, 28, 42, 50, 60, 100, 200); - std::cout << "mk_project\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; - unsigned vars[1] = {1}; - m.mk_project(d2, d3, 1, vars); - std::cout << mk_ll_pp(d3, m) << "\n"; -} - -static void tst8() { - std::cout << "--------------------------------\n"; - // enable_trace("mk_swap_bug"); - imdd_manager m; - imdd_ref d2(m), d3(m); - d2 = m.mk_empty(3); - add_triple(m, d2, 15, 22, 15, 23, 7, 18); - add_triple(m, d2, 28, 42, 29, 39, 34, 46); - add_triple(m, d2, 28, 42, 29, 39, 100, 200); - add_triple(m, d2, 28, 42, 50, 60, 100, 200); - std::cout << mk_ll_pp(d2, m) << "\n"; - m.mk_swap(d2, d3, 0); - std::cout << "after swap 0<->1\n"; - std::cout << mk_ll_pp(d3, m) << "\n"; - m.mk_swap(d2, d3, 1); - std::cout << "after swap 1<->2\n"; - std::cout << mk_ll_pp(d3, m) << "\n"; -} - -static void tst9() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d2(m), d3(m); - d2 = m.mk_empty(5); - add_5tuple(m, d2, 2,2, 3,3, 1, 1, 5, 10, 100, 200); - std::cout << mk_ll_pp(d2, m) << "\n"; - add_5tuple(m, d2, 2,2, 3,3, 1, 1, 15, 20, 100, 200); - std::cout << mk_ll_pp(d2, m) << "\n"; - add_5tuple(m, d2, 4,4, 5,5, 1, 1, 5, 10, 100, 200); - std::cout << mk_ll_pp(d2, m) << "\n"; - add_5tuple(m, d2, 4,4, 5,5, 1, 1, 15, 20, 100, 200); - std::cout << mk_ll_pp(d2, m) << "\n"; - m.mk_swap(d2, d3, 2); - std::cout << "after swap 2<->3\n"; - std::cout << mk_ll_pp(d3, m) << "\n"; -} - -static void tst10() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m); - d1 = m.mk_empty(3); - add_triple(m, d1, 5, 100, 10, 20, 3, 10); - add_triple(m, d1, 5, 100, 34, 50, 98, 110); - m.add_bounded_var(d1, d2, 0, 66, 72); - std::cout << mk_ll_pp(d1, m) << "\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; - m.add_bounded_var(d1, d3, 1, 64, 73); - std::cout << mk_ll_pp(d3, m) << "\n"; -} - -static void tst11() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m); - d1 = m.mk_empty(3); - add_triple(m, d1, 5, 100, 10, 20, 3, 10); - add_triple(m, d1, 5, 100, 34, 50, 98, 110); - add_triple(m, d1, 20, 30, 5, 25, 11, 13); - m.mk_filter_distinct(d1, d2, 1, 2); - std::cout << mk_ll_pp(d1, m) << "\n"; - std::cout << "filter_distinct(1,2):\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; -} - -static void tst12() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m); - d1 = m.mk_empty(3); - add_triple(m, d1, 1, 10, 5, 25, 10, 13); - m.mk_filter_distinct(d1, d2, 1, 2); - std::cout << mk_ll_pp(d1, m) << "\n"; - std::cout << "filter_distinct(1,2):\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; -} - -static void tst13() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m); - d1 = m.mk_empty(3); - add_triple(m, d1, 5, 25, 1, 10, 10, 13); - add_triple(m, d1, 5, 25, 20, 30, 10, 13); - m.mk_filter_distinct(d1, d2, 0, 2); - std::cout << mk_ll_pp(d1, m) << "\n"; - std::cout << "filter_distinct(0,2):\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; -} - -static void tst14() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m); - d1 = m.mk_empty(3); - add_triple(m, d1, 5, 25, 1, 10, 10, 13); - add_triple(m, d1, 5, 25, 20, 30, 15, 18); - std::cout << "destructive version\n"; - std::cout << mk_ll_pp(d1, m) << "\n"; - m.mk_filter_distinct_dupdt(d1, 0, 2); - std::cout << "filter_distinct(0,2):\n"; - std::cout << mk_ll_pp(d1, m) << "\n"; -} - -static void tst15() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m); - d1 = m.mk_empty(3); - add_triple(m, d1, 5, 5, 1, 10, 5, 5); - std::cout << mk_ll_pp(d1, m) << "\n"; - m.mk_filter_distinct(d1, d2, 0, 2); - std::cout << "filter_distinct(0,2):\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; -} - -static void tst16() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m); - d1 = m.mk_empty(3); - add_triple(m, d1, 5, 15, 1, 10, 50, 500); - std::cout << mk_ll_pp(d1, m) << "\n"; - m.mk_filter_disequal(d1, d2, 1, 4); - std::cout << "filter_disequal(var1,4):\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; -} - -static void tst17() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m); - d1 = m.mk_empty(3); - add_triple(m, d1, 5, 15, 10, 10, 50, 500); - std::cout << mk_ll_pp(d1, m) << "\n"; - m.mk_filter_disequal(d1, d2, 1, 10); - std::cout << "filter_disequal(var1,10):\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; -} - -static void tst18() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d1(m), d2(m), d3(m); - d1 = m.mk_empty(2); - add_pair(m, d1, 1112, 1290, 1302, 1302); - std::cout << mk_ll_pp(d1, m) << "\n"; - m.mk_swap(d1, d2, 0); - std::cout << "mk_swap 0:\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; -} - -static void tst19() { - std::cout << "--------------------------------\n"; - imdd_manager m; - imdd_ref d2(m), d3(m); - d2 = m.mk_empty(3); - add_triple(m, d2, 15, 22, 15, 23, 7, 18); - add_triple(m, d2, 28, 42, 29, 39, 34, 46); - add_triple(m, d2, 28, 42, 29, 39, 100, 200); - add_triple(m, d2, 28, 42, 50, 60, 100, 200); - std::cout << "mk_project_dupdt\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; - unsigned vars[1] = {1}; - m.mk_project_dupdt(d2, 1, vars); - std::cout << "new table\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; -} - -static void init(unsigned* v, unsigned a, unsigned b, unsigned c) { - v[0] = a; - v[1] = b; - v[2] = c; -} - -static void tst20() { - std::cout << "--------------------------------\n"; - std::cout << "remove_facts\n"; - imdd_manager m; - imdd_ref d2(m), d3(m); - d2 = m.mk_empty(3); - add_triple(m, d2, 15, 22, 15, 23, 7, 18); - add_triple(m, d2, 28, 42, 29, 39, 34, 46); - add_triple(m, d2, 28, 42, 29, 39, 100, 200); - add_triple(m, d2, 28, 42, 50, 60, 100, 200); - std::cout << mk_ll_pp(d2, m) << "\n"; - // - // [15, 22] -> #1:{ - // [15, 23] -> {[7, 18]}*$80}*$80 - // [28, 42] -> #2:{ - // [29, 39] -> {[34, 46], [100, 200]}*$160 - // [50, 60] -> {[100, 200]}*$80}*$80}$80 - // - unsigned lowers[3] = {23,1,1}; - unsigned uppers[3] = {24,1,1}; - - m.remove_facts(d2, d3, 3, lowers, uppers); - std::cout << "new table (no change)\n"; - std::cout << mk_ll_pp(d3, m) << "\n"; - - lowers[0] = 22; - m.remove_facts(d2, d3, 3, lowers, uppers); - std::cout << "new table (no change)\n"; - std::cout << mk_ll_pp(d3, m) << "\n"; - - init(lowers, 22, 15, 0); - init(uppers, 24, 23, 0); - m.remove_facts(d2, d3, 3, lowers, uppers); - std::cout << "new table (no change)\n"; - std::cout << mk_ll_pp(d3, m) << "\n"; - - init(lowers, 22, 15, 7); - init(uppers, 24, 23, 18); - m.remove_facts(d2, d3, 3, lowers, uppers); - std::cout << "new table (narrow first interval)\n"; - std::cout << mk_ll_pp(d3, m) << "\n"; - - init(lowers, 22, 15, 8); - init(uppers, 24, 23, 18); - m.remove_facts(d2, d3, 3, lowers, uppers); - std::cout << "new table (split first interval)\n"; - std::cout << mk_ll_pp(d3, m) << "\n"; - - init(lowers, 22, 15, 8); - init(uppers, 24, 23, 17); - m.remove_facts(d2, d3, 3, lowers, uppers); - std::cout << "new table (split first interval)\n"; - std::cout << mk_ll_pp(d3, m) << "\n"; - - init(lowers, 22, 15, 8); - init(uppers, 24, 23, 19); - m.remove_facts(d2, d3, 3, lowers, uppers); - std::cout << "new table (split first interval)\n"; - std::cout << mk_ll_pp(d3, m) << "\n"; - - init(lowers, 30, 20, 120); - init(uppers, 40, 60, 140); - m.remove_facts(d2, d3, 3, lowers, uppers); - std::cout << "new table (split second interval)\n"; - std::cout << mk_ll_pp(d3, m) << "\n"; -} - - -static void tst21() { - std::cout << "--------------------------------\n"; - std::cout << "remove_facts\n"; - imdd_manager m; - imdd_ref d2(m), d3(m); - d2 = m.mk_empty(3); - add_triple(m, d2, 15, 22, 15, 23, 7, 18); - add_triple(m, d2, 28, 42, 29, 39, 34, 46); - add_triple(m, d2, 28, 42, 29, 39, 100, 200); - add_triple(m, d2, 28, 42, 50, 60, 100, 200); - std::cout << mk_ll_pp(d2, m) << "\n"; - // - // [15, 22] -> #1:{ - // [15, 23] -> {[7, 18]}*$80}*$80 - // [28, 42] -> #2:{ - // [29, 39] -> {[34, 46], [100, 200]}*$160 - // [50, 60] -> {[100, 200]}*$80}*$80}$80 - // - unsigned lowers[3] = {23,1,1}; - unsigned uppers[3] = {24,1,1}; - - d3 = d2; - m.remove_facts_dupdt(d2, 3, lowers, uppers); - std::cout << "new table (no change)\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; - d2 = d3; - - lowers[0] = 22; - m.remove_facts_dupdt(d2, 3, lowers, uppers); - std::cout << "new table (no change)\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; - - init(lowers, 22, 15, 0); - init(uppers, 24, 23, 0); - m.remove_facts_dupdt(d2, 3, lowers, uppers); - std::cout << "new table (no change)\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; - - init(lowers, 22, 15, 7); - init(uppers, 24, 23, 18); - m.remove_facts_dupdt(d2, 3, lowers, uppers); - std::cout << "new table (narrow first interval)\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; - - init(lowers, 22, 15, 8); - init(uppers, 24, 23, 18); - m.remove_facts_dupdt(d2, 3, lowers, uppers); - std::cout << "new table (split first interval)\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; - - init(lowers, 22, 15, 8); - init(uppers, 24, 23, 17); - m.remove_facts_dupdt(d2, 3, lowers, uppers); - std::cout << "new table (split first interval)\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; - - init(lowers, 22, 15, 8); - init(uppers, 24, 23, 19); - m.remove_facts_dupdt(d2, 3, lowers, uppers); - std::cout << "new table (split first interval)\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; - - init(lowers, 30, 20, 120); - init(uppers, 40, 60, 140); - m.remove_facts_dupdt(d2, 3, lowers, uppers); - std::cout << "new table (split second interval)\n"; - std::cout << mk_ll_pp(d2, m) << "\n"; -} - -static void tst22() { - std::cout << "--------------------------------\n"; - std::cout << "swap\n"; - imdd_manager m; - imdd_ref d2(m), d3(m), d4(m); - - d2 = m.mk_empty(3); - random_gen rand; - for (unsigned i = 0; i < 130; ++i) { - unsigned a = rand(20); - unsigned b = rand(20); - unsigned c = rand(20); - add_triple(m, d2, a, a, b, b, c, c); - } - std::cout << mk_ll_pp(d2, m) << "\n"; - - m.mk_swap(d2, d3, 0, true); - std::cout << mk_ll_pp(d3, m) << "\n"; - - m.mk_swap(d3, d4, 0, true); - std::cout << mk_ll_pp(d4, m) << "\n"; - SASSERT(m.is_subset(d2, d4)); - SASSERT(m.is_subset(d4, d2)); -} - -void tst_imdd() { - // enable_trace("imdd_add_bug"); - // enable_trace("add_facts_bug"); - enable_trace("mk_distinct_imdd"); - enable_trace("mk_union_core"); - tst22(); - tst0(); - tst1(); - tst2(); - tst3(); - tst4(); - tst5(); - tst6(); - tst7(); - tst19(); - tst8(); - tst9(); - tst10(); - tst11(); - tst12(); - tst13(); - tst14(); - tst15(); - tst16(); - tst17(); - tst18(); - tst20(); - tst21(); - -} - -#else - -void tst_imdd() { -} - -#endif diff --git a/src/test/interval_skip_list.cpp b/src/test/interval_skip_list.cpp deleted file mode 100644 index bda85c86e..000000000 --- a/src/test/interval_skip_list.cpp +++ /dev/null @@ -1,716 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - interval_skip_list.cpp - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2010-10-05. - -Revision History: - ---*/ - -#include"interval_skip_list.h" -#include"map.h" -#include"vector.h" - -typedef sl_manager_base slist_manager; -template class interval_skip_list, 4, 4, false, slist_manager> >; -typedef interval_skip_list, 4, 4, false, slist_manager> > slist; -typedef u_map u2u_map; -typedef unsigned_isp_set<4, 4, slist_manager> uset; - -static void tst1() { - slist_manager m; - slist l(m); - SASSERT(l.check_invariant()); - SASSERT(l.empty()); - // l.display_physical(std::cout); - l.insert(m, 20, 30, 5); - l.insert(m, 31, 32, 5); - l.insert(m, 18, 19, 5); - // l.display_physical(std::cout); - SASSERT(l.check_invariant()); - l.insert(m, 10, 15, 8); - SASSERT(l.check_invariant()); - // l.display_physical(std::cout); - l.insert(m, 5, 25, 7); - SASSERT(l.check_invariant()); - // l.display_physical(std::cout); - l.insert(m, 23, 27, 5); - // l.display_physical(std::cout); - SASSERT(l.check_invariant()); - l.deallocate(m); -} - -static void tst2() { - slist_manager(m); - slist l(m); - for(unsigned i = 0; i < 50; i++) { - l.insert(m,i,i,i*10); - } - // l.display_physical(std::cout); - SASSERT(l.check_invariant()); - for (unsigned i = 0; i < 25; i++) { - l.insert(m,i*2,i*2+1,i*20+1); - } - // l.display_physical(std::cout); - SASSERT(l.check_invariant()); - for (unsigned i = 0; i < 15; i++) { - l.insert(m,i*3,i*3+2,i*30+1); - } - SASSERT(l.check_invariant()); - // l.display_physical(std::cout); - // l.compress(4); - // l.display_physical(std::cout); - SASSERT(l.check_invariant()); - l.deallocate(m); -} - -static bool check_interval(slist & l, unsigned k1, unsigned k2, unsigned val) { - for (unsigned i = k1; i <= k2; i++) { - DEBUG_CODE({ - unsigned _val; - SASSERT(l.contains(i, _val) && _val == val); - }); - } - return true; -} - -static bool check_no_interval(slist & l, unsigned k1, unsigned k2) { - for (unsigned i = k1; i <= k2; i++) { - DEBUG_CODE({ - unsigned _val; - SASSERT(!l.contains(i, _val)); - }); - } - return true; -} - -static void tst4() { - slist_manager m; - slist l(m); - l.insert(m, 1, 10, 0); - l.insert(m, 2, 5, 1); - SASSERT(check_no_interval(l,0,0)); - SASSERT(check_interval(l,1,1,0)); - SASSERT(check_interval(l,2,5,1)); - SASSERT(check_interval(l,6,10,0)); - SASSERT(check_no_interval(l,11,20)); - SASSERT(l.check_invariant()); - l.deallocate(m); -} - -static void tst5() { - slist_manager m; - slist l(m); - l.insert(m, 1, 5, 0); - l.insert(m, 8, 100, 1); - l.insert(m, 8, 20, 1); - SASSERT(check_no_interval(l,0,0)); - SASSERT(check_interval(l,1,5,0)); - SASSERT(check_no_interval(l,6,7)); - SASSERT(check_interval(l,8,100,1)); - SASSERT(check_no_interval(l,101,200)); - SASSERT(l.check_invariant()); - l.deallocate(m); -} - -static void tst6() { - slist_manager m; - slist l(m); - l.insert(m, 1, 5, 0); - l.insert(m, 8, 100, 1); - l.insert(m, 3, 20, 1); - SASSERT(check_no_interval(l,0,0)); - SASSERT(check_interval(l,1,2,0)); - SASSERT(check_interval(l,3,100,1)); - SASSERT(check_no_interval(l,101,200)); - SASSERT(l.check_invariant()); - l.deallocate(m); -} - -static void tst7() { - slist_manager m; - slist l(m); - l.insert(m, 1, 5, 0); - l.insert(m, 8, 100, 1); - l.insert(m, 2, 12, 0); - SASSERT(check_no_interval(l,0,0)); - SASSERT(check_interval(l,1,12,0)); - SASSERT(check_interval(l,13,100,1)); - SASSERT(check_no_interval(l,101,200)); - SASSERT(l.check_invariant()); - l.deallocate(m); -} - -static void tst8() { - slist_manager m; - slist l(m); - for (unsigned i = 0; i < 100; i++) { - l.insert(m, 10*i, 10*i+5, i); - } - SASSERT(!l.empty()); - l.insert(m, 0, 10000, 0); - SASSERT(!l.has_more_than_k_entries(1)); - // l.display_physical(std::cout); - l.deallocate(m); -} - -struct for_each_contains { - slist const & m_other; - - for_each_contains(slist const & other):m_other(other) {} - - bool operator()(unsigned b, unsigned e, unsigned v) { - for (unsigned i = b; i <= e; i++) { - DEBUG_CODE({ - unsigned _v; - SASSERT(m_other.contains(i, _v)); - SASSERT(v == _v); - }); - } - return true; - } -}; - -static void random_tsts(unsigned num_ops, unsigned max_key, unsigned max_val, unsigned max_interval_size) { - slist_manager m; - slist m1(m); - u2u_map m2; - for (unsigned i = 0; i < num_ops; i++) { - SASSERT(m1.check_invariant()); - TRACE("interval_skip_list", tout << "i: " << i << "\n"; m1.display_physical(tout);); - // std::cout << i << std::endl; - int op = rand()%8; - if (op < 3) { - unsigned bg = rand() % max_key; - unsigned sz = rand() % max_interval_size; - if (sz == 0) sz = 1; - unsigned val = rand() % max_val; - m1.insert(m, bg, bg+sz, val); - for (unsigned j = bg; j <= bg+sz; j++) { - DEBUG_CODE({ - unsigned _val; - SASSERT(m1.contains(j, _val)); - CTRACE("interval_skip_list", val != _val, tout << "i: " << i << ", j: " << j << ", val: " << val << ", _val: " << _val << "\n"; m1.display_physical(tout);); - SASSERT(val == _val); - TRACE("interval_skip_list", tout << "[insert]: " << j << " -> " << val << "\n";); - }); - m2.insert(j, val); - } - } - else if (op < 4) { - unsigned bg = rand() % max_key; - unsigned sz = rand() % max_interval_size; - if (sz == 0) sz = 1; - m1.erase(m, bg, bg+sz); - for (unsigned i = bg; i <= bg+sz; i++) { - m2.erase(i); - } - } - else if (op < 5) { - slist m1_copy(m); - m1_copy.copy(m, m1); - for_each_contains proc1(m1); - for_each_contains proc2(m1_copy); - m1.for_each(proc2); - m1_copy.for_each(proc1); - // m1.display_physical(std::cout); - // std::cout << "COPY===>\n"; - // m1_copy->display_physical(std::cout); - m1_copy.deallocate(m); - } - else if (op < 6) { - m1.compress(m, 3); - } - else { - SASSERT(m1.check_invariant()); - u2u_map::iterator it = m2.begin(); - u2u_map::iterator end = m2.end(); - for (; it != end; ++it) { - DEBUG_CODE({ - unsigned _val; - CTRACE("interval_skip_list", !m1.contains(it->m_key, _val), - tout << it->m_key << " -> " << it->m_value << "\n"; - m1.display_physical(tout);); - SASSERT(m1.contains(it->m_key, _val)); - SASSERT(it->m_value == _val); - }); - } - } - } - // m1.display_physical(std::cout); - // m1.compress(4); - // m1.display_physical(std::cout); - m1.deallocate(m); -} - -static void tst9() { - slist_manager m; - slist l(m); - l.insert(m,10,10,1); - l.insert(m,9,9,0); - l.insert(m,8,8,2); - l.insert(m,7,7,3); - l.insert(m,6,8,3); - SASSERT(!l.has_more_than_k_buckets(1)); - SASSERT(check_no_interval(l,0,5)); - SASSERT(check_interval(l,6,8,3)); - SASSERT(check_interval(l,9,9,0)); - SASSERT(check_interval(l,10,10,1)); - SASSERT(check_no_interval(l,11,20)); - l.deallocate(m); -} - -static void tst10() { - slist_manager m; - slist l(m); - l.insert(m,10,10,1); - l.insert(m,13,16,2); - l.insert(m,17,28,3); - l.remove(m,12,19); - SASSERT(l.check_invariant()); - SASSERT(check_no_interval(l,0,9)); - SASSERT(check_interval(l,10,10,1)); - SASSERT(check_no_interval(l,12,19)); - SASSERT(check_interval(l,20,28,3)); - SASSERT(check_no_interval(l,29,100)); - l.remove(m,10,11); - SASSERT(l.check_invariant()); - SASSERT(check_no_interval(l,0,19)); - SASSERT(check_interval(l,20,28,3)); - SASSERT(check_no_interval(l,29,100)); - l.remove(m,0,1000); - SASSERT(l.empty()); - SASSERT(l.check_invariant()); - l.deallocate(m); -} - -static void tst11() { - slist_manager m; - slist l(m); - l.insert(m,11,20,1); - l.insert(m,21,30,2); - l.insert(m,31,40,3); - l.insert(m,41,50,4); - l.insert(m,51,60,5); - l.compress(m,4); - SASSERT(check_no_interval(l,0,10)); - SASSERT(check_interval(l,11,20,1)); - SASSERT(check_interval(l,21,30,2)); - SASSERT(check_interval(l,31,40,3)); - SASSERT(check_interval(l,41,50,4)); - SASSERT(check_interval(l,51,60,5)); - SASSERT(check_no_interval(l,61,100)); - SASSERT(l.check_invariant()); - l.remove(m, 25, 26); - SASSERT(check_no_interval(l,0,10)); - SASSERT(check_interval(l,11,20,1)); - SASSERT(check_interval(l,21,24,2)); - SASSERT(check_no_interval(l,25,26)); - SASSERT(check_interval(l,27,30,2)); - SASSERT(check_interval(l,31,40,3)); - SASSERT(check_interval(l,41,50,4)); - SASSERT(check_interval(l,51,60,5)); - SASSERT(check_no_interval(l,61,100)); - SASSERT(l.check_invariant()); - l.remove(m, 44,48); - SASSERT(check_no_interval(l,0,10)); - SASSERT(check_interval(l,11,20,1)); - SASSERT(check_interval(l,21,24,2)); - SASSERT(check_no_interval(l,25,26)); - SASSERT(check_interval(l,27,30,2)); - SASSERT(check_interval(l,31,40,3)); - SASSERT(check_interval(l,41,43,4)); - SASSERT(check_no_interval(l,44,48)); - SASSERT(check_interval(l,49,50,4)); - SASSERT(check_interval(l,51,60,5)); - SASSERT(check_no_interval(l,61,100)); - SASSERT(l.check_invariant()); - l.remove(m, 22,24); - SASSERT(check_no_interval(l,0,10)); - SASSERT(check_interval(l,11,20,1)); - SASSERT(check_interval(l,21,21,2)); - SASSERT(check_no_interval(l,22,26)); - SASSERT(check_interval(l,27,30,2)); - SASSERT(check_interval(l,31,40,3)); - SASSERT(check_interval(l,41,43,4)); - SASSERT(check_no_interval(l,44,48)); - SASSERT(check_interval(l,49,50,4)); - SASSERT(check_interval(l,51,60,5)); - SASSERT(check_no_interval(l,61,100)); - SASSERT(l.check_invariant()); - l.remove(m, 42,49); - SASSERT(check_no_interval(l,0,10)); - SASSERT(check_interval(l,11,20,1)); - SASSERT(check_interval(l,21,21,2)); - SASSERT(check_no_interval(l,22,26)); - SASSERT(check_interval(l,27,30,2)); - SASSERT(check_interval(l,31,40,3)); - SASSERT(check_interval(l,41,41,4)); - SASSERT(check_no_interval(l,42,49)); - SASSERT(check_interval(l,50,50,4)); - SASSERT(check_interval(l,51,60,5)); - SASSERT(check_no_interval(l,61,100)); - SASSERT(l.check_invariant()); - // l.display_physical(std::cout); - l.deallocate(m); -} - -static void tst12() { - slist_manager m; - slist l(m); - l.insert(m,10,10,0); - l.insert(m,9,9,0); - SASSERT(l.check_invariant()); - l.insert(m,8,9,1); - SASSERT(l.check_invariant()); - l.insert(m,7,7,2); - SASSERT(l.check_invariant()); - l.insert(m,6,6,3); - SASSERT(l.check_invariant()); - l.insert(m,4,5,2); - SASSERT(l.check_invariant()); - l.insert(m,3,9,0); - // l.display_physical(std::cout); - l.deallocate(m); -} - -static void tst13() { - slist_manager m; - uset s(m); - s.insert(m, 10, 30); - s.insert(m, 32, 40); - s.display(std::cout); - std::cout << ", mem: " << s.memory() << "\n"; - s.deallocate(m); -} - -struct obj { - unsigned m_val; - unsigned m_ref_count; - void inc_ref() { - m_ref_count++; - } - void dec_ref() { - SASSERT(m_ref_count > 0); - m_ref_count--; - if (m_ref_count == 0) - dealloc(this); - } - obj(unsigned v):m_val(v), m_ref_count(0) { - } -}; - -std::ostream & operator<<(std::ostream & out, obj * o) { - out << o->m_val << "{" << o->m_ref_count << "}"; - return out; -} - -struct obj_slist_manager : public sl_manager_base { - void inc_ref_eh(obj * v) { - v->inc_ref(); - } - - void dec_ref_eh(obj * v) { - v->dec_ref(); - } -}; - -struct inc_ref_functor { - unsigned_vector & refs; - inc_ref_functor(unsigned_vector & r):refs(r) {} - bool operator()(unsigned b, unsigned e, obj * val) { - refs[val->m_val]++; - return true; - } -}; - -template class interval_skip_list, 16, 16, true, obj_slist_manager> >; -typedef interval_skip_list, 16, 16, true, obj_slist_manager> > obj_slist; - -void random_tsts_ref(unsigned num_ops, unsigned num_objs, unsigned max_key, unsigned max_interval_size) { - obj_slist_manager m; - obj_slist l(m); - ptr_vector objs; - unsigned_vector refs; - for (unsigned i = 0; i < num_objs; i++) { - objs.push_back(alloc(obj, i)); - objs.back()->inc_ref(); - refs.push_back(1); - } - - for (unsigned i = 0; i < num_ops; i++) { - SASSERT(l.check_invariant()); - TRACE("interval_skip_list", tout << "i: " << i << "\n"; l.display_physical(tout); tout << "\n";); - int op = rand()%5; - if (op < 3) { - unsigned bg = rand() % max_key; - unsigned sz = rand() % max_interval_size; - if (sz == 0) sz = 1; - unsigned val = rand() % num_objs; - TRACE("interval_skip_list", tout << "[inserting]: [" << bg << ", " << (bg+sz) << "] -> " << objs[val] << "\n";); - l.insert(m, bg, bg+sz, objs[val]); - SASSERT(objs[val]->m_ref_count > 1); - } - else if (op < 4) { - unsigned bg = rand() % max_key; - unsigned sz = rand() % max_interval_size; - if (sz == 0) sz = 1; - TRACE("interval_skip_list", tout << "[erasing]: [" << bg << ", " << (bg+sz) << "]\n";); - l.erase(m, bg, bg+sz); - } - else if (op < 5) { - obj_slist l_copy(m); - l_copy.copy(m, l); - TRACE("interval_skip_list", tout << "[copying]\n";); - l_copy.deallocate(m); - TRACE("interval_skip_list", tout << "[deleting copy]\n";); - } - else { - TRACE("interval_skip_list", tout << "[compressing]\n";); - l.compress(m, 3); - } - // check ref-counts - inc_ref_functor proc(refs); - l.for_each(proc); - for (unsigned i = 0; i < num_objs; i++) { - CTRACE("interval_skip_list", refs[i] != objs[i]->m_ref_count, - tout << "i: " << i << ", objs[i]: " << objs[i] << ", refs[i]: " << refs[i] << "\n\n"; - l.display_physical(tout);); - SASSERT(refs[i] == objs[i]->m_ref_count); - refs[i] = 1; - } - } - l.deallocate(m); - for (unsigned i = 0; i < num_objs; i++) { - SASSERT(objs[i]->m_ref_count == 1); - objs[i]->dec_ref(); - } -} - -void tst_ref() { - obj_slist_manager m; - obj_slist l(m); - for (unsigned i = 0; i < 30; i++) { - obj * n = alloc(obj, i); - l.insert(m, i*10, i*10+3, n); - // l.display_physical(std::cout); - // std::cout << "memory: " << l.memory() << "\n"; - } - l.deallocate(m); - -} - -void tst_push_back_aux(slist::push_back_proc & push_back, unsigned num_ops, unsigned max_int, unsigned max_sep, unsigned max_val) { - unsigned prev_key; - - if (push_back.empty()) - prev_key = 0; - else - prev_key = push_back.last_key(); - - for (unsigned i = 0; i < num_ops; i++) { - unsigned next_key = prev_key + 1; - next_key += (rand() % max_sep); - unsigned sz = rand() % max_int; - if (sz == 0) sz = 1; - unsigned val = rand() % max_val; - push_back(next_key, next_key+sz, val); - SASSERT(!push_back.empty()); - prev_key = push_back.last_key(); - } -} - -void tst_push_back1(unsigned num_ops, unsigned max_int, unsigned max_sep, unsigned max_val) { - slist_manager m; - slist l(m); - slist::push_back_proc push_back(m, l); - - tst_push_back_aux(push_back, num_ops, max_int, max_sep, max_val); - // l.display_physical(std::cout); - SASSERT(l.check_invariant()); - l.deallocate(m); -} - -void tst_push_back2(unsigned num_ops, unsigned max_int, unsigned max_sep, unsigned max_val) { - slist_manager m; - slist l(m); - - // insert some random values before creating push_back functor - for (unsigned i = 0; i < num_ops; i++) { - unsigned next_key = rand() % (num_ops * max_int/2); - unsigned sz = rand() % max_int; - if (sz == 0) sz = 1; - unsigned val = rand() % max_val; - l.insert(m, next_key, next_key+sz, val); - } - - slist::push_back_proc push_back(m, l); - - tst_push_back_aux(push_back, num_ops, max_int, max_sep, max_val); - - // l.display_physical(std::cout); - SASSERT(l.check_invariant()); - l.deallocate(m); -} - -void tst_find_geq1() { - slist_manager m; - slist l(m); - l.insert(m, 10, 20, 4); - l.insert(m, 23, 30, 3); - l.insert(m, 40, 45, 10); - l.insert(m, 50, 66, 1); - l.insert(m, 100, 120, 21); - l.insert(m, 140, 200, 2); - slist::iterator it = l.find_geq(22); - SASSERT(it->begin_key() == 23); - it = l.find_geq(42); - SASSERT(it->begin_key() == 40); - it.move_to(130); - SASSERT(it->begin_key() == 140); - it.move_to(400); - SASSERT(it == l.end()); - it = l.find_geq(300); - SASSERT(it == l.end()); - it = l.find_geq(9); - SASSERT(it->begin_key() == 10); - it.move_to(105); - SASSERT(it->begin_key() == 100); - it = l.find_geq(15); - SASSERT(it->begin_key() == 10); - it.move_to(31); - SASSERT(it->begin_key() == 40); - it = l.find_geq(22); - SASSERT(it->begin_key() == 23); - it = l.find_geq(124); - SASSERT(it->begin_key() == 140); - it = l.find_geq(102); - SASSERT(it->begin_key() == 100); - // l.display_physical(std::cout); - l.deallocate(m); -} - -struct add42 { - unsigned operator()(unsigned v) { return v + 42; } -}; - -void tst_move_to() { - slist_manager m; - slist l(m); - for (unsigned i = 0; i < 500; i++) - l.insert(m, i*10, i*10 + 5, i); - l.compress(m, 4); - slist::iterator it = l.find_geq(137); - SASSERT(it->begin_key() == 140); - it.move_to(947); - SASSERT(it->begin_key() == 950); - it.move_to(4955); - SASSERT(it->begin_key() == 4950); - it.move_to(4955); - SASSERT(it->begin_key() == 4950); - it.move_to(4956); - SASSERT(it->begin_key() == 4960); - it.move_to(4982); - SASSERT(it->begin_key() == 4980); - it.move_to(4987); - SASSERT(it->begin_key() == 4990); - it.move_to(4990); - SASSERT(it->begin_key() == 4990); - it.move_to(4995); - SASSERT(it->begin_key() == 4990); - it.move_to(4996); - SASSERT(it.at_end()); - // l.display_physical(std::cout); - add42 f; - // l.display(std::cout); std::cout << "\n"; - l.update_values(m, f); - // l.display(std::cout); std::cout << "\n"; - l.deallocate(m); -} - -static void tst_ext_iterator() { - slist_manager m; - slist l(m); - for (unsigned i = 0; i < 20; i++) - l.insert(m, i*10, i*10 + 5, i); - l.compress(m, 4); - l.display_physical(std::cout); std::cout << "\n"; - slist::ext_iterator it; - slist::ext_iterator end; - SASSERT(end.at_end()); - l.move_geq(it, 92); - SASSERT(!it.at_end()); - SASSERT(it->begin_key() == 90); - it++; - SASSERT(it->begin_key() == 100); - it.erase(m); - SASSERT(it->begin_key() == 110); - it.erase(m); - SASSERT(it->begin_key() == 120); - it.erase(m); - it.erase(m); - it.erase(m); - it.erase(m); - SASSERT(it->begin_key() == 160); - SASSERT(l.check_invariant()); - l.display_physical(std::cout); std::cout << "\n"; - l.move_geq(it, 0); - SASSERT(it->begin_key() == 0); - it.erase(m); - SASSERT(it->begin_key() == 10); - it.erase(m); - SASSERT(it->begin_key() == 20); - it.erase(m); - SASSERT(it->begin_key() == 30); - it.erase(m); - SASSERT(it->begin_key() == 40); - it.erase(m); - SASSERT(it->begin_key() == 50); - l.display_physical(std::cout); std::cout << "\n"; - l.deallocate(m); -} - -void tst_interval_skip_list() { - std::cout << "unsigned map stats:\n"; - slist::display_size_info(std::cout); - std::cout << "\nunsigned set stats:\n"; - uset::display_size_info(std::cout); - std::cout << "\n"; - tst1(); -// enable_trace("interval_skip_list_insert_bug"); -// enable_trace("interval_skip_list_bug"); -// enable_trace("del_entries_upto_bug"); -// enable_trace("insert_inside_bug"); -// enable_trace("insert_at_bug"); - tst2(); - tst4(); - tst5(); - tst6(); - tst7(); - tst8(); - tst9(); - tst10(); - tst11(); - tst12(); - tst13(); - tst_find_geq1(); - tst_move_to(); - tst_push_back1(300, 4, 2, 10); - tst_push_back2(300, 4, 2, 10); - random_tsts(1000, 20, 20, 5); - random_tsts_ref(1000, 20, 20, 5); - tst_ref(); - tst_ext_iterator(); -} - - diff --git a/src/test/main.cpp b/src/test/main.cpp index 6ecfd6d4f..6f802cec1 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -22,7 +22,7 @@ if (do_display_usage) \ std::cout << #MODULE << "\n"; \ for (int i = 0; i < argc; i++) \ - if (strcmp(argv[i], #MODULE) == 0) { \ + if (test_all || strcmp(argv[i], #MODULE) == 0) { \ enable_trace(#MODULE); \ enable_debug(#MODULE); \ timeit timeit(true, s.c_str()); \ @@ -60,6 +60,7 @@ void display_usage() { std::cout << " /h prints this message.\n"; std::cout << " /v:level be verbose, where is the verbosity level.\n"; std::cout << " /w enable warning messages.\n"; + std::cout << " /a run all unit tests that don't require arguments.\n"; #if defined(Z3DEBUG) || defined(_TRACE) std::cout << "\nDebugging support:\n"; #endif @@ -71,7 +72,7 @@ void display_usage() { #endif } -void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage) { +void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& test_all) { int i = 1; while (i < argc) { char * arg = argv[i]; @@ -99,6 +100,9 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage) { else if (strcmp(opt_name, "w") == 0) { enable_warning_messages(true); } + else if (strcmp(opt_name, "a") == 0) { + test_all = true; + } #ifdef _TRACE else if (strcmp(opt_name, "tr") == 0) { if (!opt_arg) @@ -122,7 +126,8 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage) { int main(int argc, char ** argv) { memory::initialize(0); bool do_display_usage = false; - parse_cmd_line_args(argc, argv, do_display_usage); + bool test_all = false; + parse_cmd_line_args(argc, argv, do_display_usage, test_all); TST(random); TST(vector); TST(symbol_table); @@ -151,7 +156,6 @@ int main(int argc, char ** argv) { TST(simple_parser); TST(api); TST(old_interval); - TST(interval_skip_list); TST(no_overflow); TST(memory); TST(get_implied_equalities); @@ -170,7 +174,6 @@ int main(int argc, char ** argv) { TST(dl_util); TST(dl_product_relation); TST(dl_relation); - TST(imdd); TST(parray); TST(stack); TST(escaped); diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index c77978647..df0124aea 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -1299,9 +1299,10 @@ bool mpz_manager::is_int64(mpz const & a) const { if (is_small(a)) return true; #ifndef _MP_GMP - if (!is_uint64(a)) + if (!is_uint64(a)) { return false; - uint64 num = get_uint64(a); + } + uint64 num get_uint64(a); uint64 msb = static_cast(1) << 63; uint64 msb_val = msb & num; if (a.m_val >= 0) { From 03c1b24dea7a5eec1747968a829ae7e014aa4809 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 8 Apr 2013 14:25:25 -0700 Subject: [PATCH 070/281] Fix get_int64 and is_int64 methods in mpz. Fix INT64_MAX constant definition. Signed-off-by: Leonardo de Moura --- src/util/mpz.cpp | 15 ++++----------- src/util/mpz.h | 24 ++++++++++++++++++++++++ src/util/util.h | 2 +- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index c77978647..9473621cf 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -1299,9 +1299,9 @@ bool mpz_manager::is_int64(mpz const & a) const { if (is_small(a)) return true; #ifndef _MP_GMP - if (!is_uint64(a)) + if (!is_abs_uint64(a)) return false; - uint64 num = get_uint64(a); + uint64 num = big_abs_to_uint64(a); uint64 msb = static_cast(1) << 63; uint64 msb_val = msb & num; if (a.m_val >= 0) { @@ -1327,14 +1327,7 @@ uint64 mpz_manager::get_uint64(mpz const & a) const { return static_cast(a.m_val); #ifndef _MP_GMP SASSERT(a.m_ptr->m_size > 0); - if (a.m_ptr->m_size == 1) - return digits(a)[0]; - if (sizeof(digit_t) == sizeof(uint64)) - // 64-bit machine - return digits(a)[0]; - else - // 32-bit machine - return ((static_cast(digits(a)[1]) << 32) | (static_cast(digits(a)[0]))); + return big_abs_to_uint64(a); #else // GMP version if (sizeof(uint64) == sizeof(unsigned long)) { @@ -1359,7 +1352,7 @@ int64 mpz_manager::get_int64(mpz const & a) const { return static_cast(a.m_val); #ifndef _MP_GMP SASSERT(is_int64(a)); - uint64 num = get_uint64(a); + uint64 num = big_abs_to_uint64(a); if (a.m_val < 0) { if (num != 0 && (num << 1) == 0) return INT64_MIN; diff --git a/src/util/mpz.h b/src/util/mpz.h index b5c301d82..7b40a89f5 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -211,6 +211,30 @@ class mpz_manager { static digit_t * digits(mpz const & c) { return c.m_ptr->m_digits; } + // Return true if the absolute value fits in a UINT64 + static bool is_abs_uint64(mpz const & a) { + if (is_small(a)) + return true; + if (sizeof(digit_t) == sizeof(uint64)) + return size(a) <= 1; + else + return size(a) <= 2; + } + + // CAST the absolute value into a UINT64 + static uint64 big_abs_to_uint64(mpz const & a) { + SASSERT(is_abs_uint64(a)); + SASSERT(!is_small(a)); + if (a.m_ptr->m_size == 1) + return digits(a)[0]; + if (sizeof(digit_t) == sizeof(uint64)) + // 64-bit machine + return digits(a)[0]; + else + // 32-bit machine + return ((static_cast(digits(a)[1]) << 32) | (static_cast(digits(a)[0]))); + } + template void get_sign_cell(mpz const & a, int & sign, mpz_cell * & cell) { if (is_small(a)) { diff --git a/src/util/util.h b/src/util/util.h index 8bcbce4a3..0aa8f881d 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -45,7 +45,7 @@ COMPILE_TIME_ASSERT(sizeof(int64) == 8); #define INT64_MIN static_cast(0x8000000000000000ull) #endif #ifndef INT64_MAX -#define INT64_MAX static_cast(0x0fffffffffffffffull) +#define INT64_MAX static_cast(0x7fffffffffffffffull) #endif #ifndef UINT64_MAX #define UINT64_MAX 0xffffffffffffffffull From 3d34aa7f010cab7dceacd756ddbf7dbd8c74687a Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 8 Apr 2013 14:50:17 -0700 Subject: [PATCH 071/281] Fix is_int64 bug in mpz when compiling with GMP Signed-off-by: Leonardo de Moura --- src/test/rational.cpp | 2 +- src/util/mpz.cpp | 5 ++++- src/util/mpz.h | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/rational.cpp b/src/test/rational.cpp index 9cbcdb00e..834aab92f 100644 --- a/src/test/rational.cpp +++ b/src/test/rational.cpp @@ -171,7 +171,7 @@ static void tst2() { rational int64_max("9223372036854775807"); - rational int64_min(-int64_max - rational(1)); + rational int64_min((-int64_max) - rational(1)); // is_int64 SASSERT(int64_max.is_int64()); SASSERT(int64_min.is_int64()); diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index 9473621cf..a7c904c64 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -128,6 +128,8 @@ mpz_manager::mpz_manager(): mpz_mul(m_int64_max, m_tmp, m_int64_max); mpz_set_ui(m_tmp, max_l); mpz_add(m_int64_max, m_tmp, m_int64_max); + mpz_neg(m_int64_min, m_int64_max); + mpz_sub_ui(m_int64_min, m_int64_min, 1); #endif mpz one(1); @@ -152,6 +154,7 @@ mpz_manager::~mpz_manager() { deallocate(m_arg[1]); mpz_clear(m_uint64_max); mpz_clear(m_int64_max); + mpz_clear(m_int64_min); #endif if (SYNCH) omp_destroy_nest_lock(&m_lock); @@ -1317,7 +1320,7 @@ bool mpz_manager::is_int64(mpz const & a) const { } #else // GMP version - return mpz_cmp(*a.m_ptr, m_int64_max) <= 0; + return mpz_cmp(m_int64_min, *a.m_ptr) <= 0 && mpz_cmp(*a.m_ptr, m_int64_max) <= 0; #endif } diff --git a/src/util/mpz.h b/src/util/mpz.h index 7b40a89f5..923d5b3a7 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -168,6 +168,7 @@ class mpz_manager { mpz_t * m_arg[2]; mpz_t m_uint64_max; mpz_t m_int64_max; + mpz_t m_int64_min; mpz_t * allocate() { mpz_t * cell = reinterpret_cast(m_allocator.allocate(sizeof(mpz_t))); From 75ad174567627e7da15fa365e8a564f1ee96122c Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 8 Apr 2013 15:02:51 -0700 Subject: [PATCH 072/281] Initialize int64_min constant when using GMP Signed-off-by: Leonardo de Moura --- src/util/mpz.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/mpz.cpp b/src/util/mpz.cpp index a7c904c64..bd7f30a76 100644 --- a/src/util/mpz.cpp +++ b/src/util/mpz.cpp @@ -120,6 +120,7 @@ mpz_manager::mpz_manager(): mpz_set_ui(m_tmp, max_l); mpz_add(m_uint64_max, m_uint64_max, m_tmp); mpz_init(m_int64_max); + mpz_init(m_int64_min); max_l = static_cast(INT64_MAX % static_cast(UINT_MAX)); max_h = static_cast(INT64_MAX / static_cast(UINT_MAX)); From 90c808bde91fc010b699003076345327017f074b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 8 Apr 2013 17:14:43 -0700 Subject: [PATCH 073/281] [datalog] fix memory leak in union instructions the source operand was never cleaned up Signed-off-by: Nuno Lopes --- src/muz_qe/dl_compiler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index c898f7964..acedc3619 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -707,6 +707,7 @@ namespace datalog { //update the head relation make_union(new_head_reg, head_reg, delta_reg, use_widening, acc); + make_dealloc_non_void(new_head_reg, acc); } finish: From 93297fa9e72f750fc8115f0568217f474888563e Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 8 Apr 2013 18:00:43 -0700 Subject: [PATCH 074/281] Fix bug in purify_arith reported at https://z3.codeplex.com/workitem/32 Signed-off-by: Leonardo de Moura --- src/tactic/arith/purify_arith_tactic.cpp | 61 +++++++++++------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 169e27927..1a38ac10e 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -29,6 +29,7 @@ Revision History: #include"th_rewriter.h" #include"filter_model_converter.h" #include"ast_smt2_pp.h" +#include"expr_replacer.h" /* ---- @@ -131,18 +132,16 @@ struct purify_arith_proc { proof_ref_vector m_new_cnstr_prs; expr_ref m_subst; proof_ref m_subst_pr; - bool m_in_q; - unsigned m_var_idx; + expr_ref_vector m_new_vars; - rw_cfg(purify_arith_proc & o, bool in_q): + rw_cfg(purify_arith_proc & o): m_owner(o), m_pinned(o.m()), m_new_cnstrs(o.m()), m_new_cnstr_prs(o.m()), m_subst(o.m()), m_subst_pr(o.m()), - m_in_q(in_q), - m_var_idx(0) { + m_new_vars(o.m()) { } ast_manager & m() { return m_owner.m(); } @@ -155,14 +154,9 @@ struct purify_arith_proc { bool elim_inverses() const { return m_owner.m_elim_inverses; } expr * mk_fresh_var(bool is_int) { - if (m_in_q) { - unsigned idx = m_var_idx; - m_var_idx++; - return m().mk_var(idx, is_int ? u().mk_int() : u().mk_real()); - } - else { - return m().mk_fresh_const(0, is_int ? u().mk_int() : u().mk_real()); - } + expr * r = m().mk_fresh_const(0, is_int ? u().mk_int() : u().mk_real()); + m_new_vars.push_back(r); + return r; } expr * mk_fresh_real_var() { return mk_fresh_var(false); } @@ -596,9 +590,9 @@ struct purify_arith_proc { struct rw : public rewriter_tpl { rw_cfg m_cfg; - rw(purify_arith_proc & o, bool in_q): + rw(purify_arith_proc & o): rewriter_tpl(o.m(), o.m_produce_proofs, m_cfg), - m_cfg(o, in_q) { + m_cfg(o) { } }; @@ -661,40 +655,43 @@ struct purify_arith_proc { void process_quantifier(quantifier * q, expr_ref & result, proof_ref & result_pr) { result_pr = 0; - num_vars_proc p(u(), m_elim_root_objs); - expr_ref body(m()); - unsigned num_vars = p(q->get_expr()); - if (num_vars > 0) { - // open space for aux vars - var_shifter shifter(m()); - shifter(q->get_expr(), num_vars, body); - } - else { - body = q->get_expr(); - } - - rw r(*this, true); + rw r(*this); expr_ref new_body(m()); proof_ref new_body_pr(m()); - r(body, new_body, new_body_pr); + r(q->get_expr(), new_body, new_body_pr); + unsigned num_vars = r.cfg().m_new_vars.size(); TRACE("purify_arith", tout << "num_vars: " << num_vars << "\n"; - tout << "body: " << mk_ismt2_pp(body, m()) << "\nnew_body: " << mk_ismt2_pp(new_body, m()) << "\n";); + tout << "body: " << mk_ismt2_pp(q->get_expr(), m()) << "\nnew_body: " << mk_ismt2_pp(new_body, m()) << "\n";); if (num_vars == 0) { + SASSERT(r.cfg().m_new_cnstrs.empty()); result = m().update_quantifier(q, new_body); if (m_produce_proofs) result_pr = m().mk_quant_intro(q, to_quantifier(result.get()), result_pr); } else { + // Add new constraints expr_ref_vector & cnstrs = r.cfg().m_new_cnstrs; cnstrs.push_back(new_body); new_body = m().mk_and(cnstrs.size(), cnstrs.c_ptr()); + // Open space for new variables + var_shifter shifter(m()); + shifter(new_body, num_vars, new_body); + // Rename fresh constants in r.cfg().m_new_vars to variables ptr_buffer sorts; buffer names; + expr_substitution subst(m(), false, false); for (unsigned i = 0; i < num_vars; i++) { - sorts.push_back(u().mk_real()); + expr * c = r.cfg().m_new_vars.get(i); + sort * s = get_sort(c); + sorts.push_back(s); names.push_back(m().mk_fresh_var_name("x")); + unsigned idx = num_vars - i - 1; + subst.insert(c, m().mk_var(idx, s)); } + scoped_ptr replacer = mk_default_expr_replacer(m()); + replacer->set_substitution(&subst); + (*replacer)(new_body, new_body); new_body = m().mk_exists(num_vars, sorts.c_ptr(), names.c_ptr(), new_body); result = m().update_quantifier(q, new_body); if (m_produce_proofs) { @@ -708,7 +705,7 @@ struct purify_arith_proc { } void operator()(goal & g, model_converter_ref & mc, bool produce_models) { - rw r(*this, false); + rw r(*this); // purify expr_ref new_curr(m()); proof_ref new_pr(m()); From 8627f6f1d5e5afc23335c29ad150ef375d07cb16 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 8 Apr 2013 18:02:28 -0700 Subject: [PATCH 075/281] Remove dead code Signed-off-by: Leonardo de Moura --- src/tactic/arith/purify_arith_tactic.cpp | 57 ------------------------ 1 file changed, 57 deletions(-) diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 1a38ac10e..f2ddd86ce 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -595,63 +595,6 @@ struct purify_arith_proc { m_cfg(o) { } }; - - /** - \brief Return the number of (auxiliary) variables needed for converting an expression. - */ - struct num_vars_proc { - arith_util & m_util; - expr_fast_mark1 m_visited; - ptr_vector m_todo; - unsigned m_num_vars; - bool m_elim_root_objs; - - num_vars_proc(arith_util & u, bool elim_root_objs): - m_util(u), - m_elim_root_objs(elim_root_objs) { - } - - void visit(expr * t) { - if (m_visited.is_marked(t)) - return; - m_visited.mark(t); - m_todo.push_back(t); - } - - void process(app * t) { - if (t->get_family_id() == m_util.get_family_id()) { - if (m_util.is_power(t)) { - rational k; - if (m_util.is_numeral(t->get_arg(1), k) && (k.is_zero() || !k.is_int())) { - m_num_vars++; - } - } - else if (m_util.is_div(t) || - m_util.is_idiv(t) || - m_util.is_mod(t) || - m_util.is_to_int(t) || - (m_util.is_irrational_algebraic_numeral(t) && m_elim_root_objs)) { - m_num_vars++; - } - } - unsigned num_args = t->get_num_args(); - for (unsigned i = 0; i < num_args; i++) - visit(t->get_arg(i)); - } - - unsigned operator()(expr * t) { - m_num_vars = 0; - visit(t); - while (!m_todo.empty()) { - expr * t = m_todo.back(); - m_todo.pop_back(); - if (is_app(t)) - process(to_app(t)); - } - m_visited.reset(); - return m_num_vars; - } - }; void process_quantifier(quantifier * q, expr_ref & result, proof_ref & result_pr) { result_pr = 0; From d26f0e1c28e9784e5c931dc326cc300089d8d03b Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 9 Apr 2013 08:42:14 -0700 Subject: [PATCH 076/281] Fix bug in the SAT solver. Signed-off-by: Leonardo de Moura --- src/sat/sat_solver.cpp | 54 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 399fb2c61..3e9b60260 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -1745,6 +1745,12 @@ namespace sat { mark_lit(m_lemma[i]); } + literal l0 = m_lemma[0]; + // l0 is the FUIP, and we never remove the FUIP. + // + // In the following loop, we use unmark_lit(l) to remove a + // literal from m_lemma. + for (unsigned i = 0; i < sz; i++) { literal l = m_lemma[i]; if (!is_marked_lit(l)) @@ -1754,9 +1760,15 @@ namespace sat { watch_list::const_iterator it = wlist.begin(); watch_list::const_iterator end = wlist.end(); for (; it != end; ++it) { + // In this for-loop, the conditions l0 != ~l2 and l0 != ~l3 + // are not really needed if the solver does not miss unit propagations. + // However, we add them anyway because we don't want to rely on this + // property of the propagator. + // For example, if this property is relaxed in the future, then the code + // without the conditions l0 != ~l2 and l0 != ~l3 may remove the FUIP if (it->is_binary_clause()) { literal l2 = it->get_literal(); - if (is_marked_lit(~l2)) { + if (is_marked_lit(~l2) && l0 != ~l2) { // eliminate ~l2 from lemma because we have the clause l \/ l2 unmark_lit(~l2); } @@ -1764,11 +1776,11 @@ namespace sat { else if (it->is_ternary_clause()) { literal l2 = it->get_literal1(); literal l3 = it->get_literal2(); - if (is_marked_lit(l2) && is_marked_lit(~l3)) { + if (is_marked_lit(l2) && is_marked_lit(~l3) && l0 != ~l3) { // eliminate ~l3 from lemma because we have the clause l \/ l2 \/ l3 unmark_lit(~l3); } - else if (is_marked_lit(~l2) && is_marked_lit(l3)) { + else if (is_marked_lit(~l2) && is_marked_lit(l3) && l0 != ~l2) { // eliminate ~l2 from lemma because we have the clause l \/ l2 \/ l3 unmark_lit(~l2); } @@ -1786,7 +1798,41 @@ namespace sat { literal_vector::iterator end = implied_lits->end(); for (; it != end; ++it) { literal l2 = *it; - if (is_marked_lit(~l2)) { + // Here, we must check l0 != ~l2. + // l \/ l2 is an implied binary clause. + // However, it may have been deduced using a lemma that has been deleted. + // For example, consider the following sequence of events: + // + // 1. Initial clause database: + // + // l \/ ~p1 + // p1 \/ ~p2 + // p2 \/ ~p3 + // p3 \/ ~p4 + // q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 + // q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 + // ~q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 + // ~q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2 + // ... + // + // 2. Now suppose we learned the lemma + // + // p1 \/ p2 \/ p3 \/ p4 \/ l2 (*) + // + // 3. Probing is executed and we notice hat (~l => l2) when we assign l to false. + // That is, l \/ l2 is an implied clause. Note that probing does not add + // this clause to the clause database (there are too many). + // + // 4. Lemma (*) is deleted (garbage collected). + // + // 5. l is decided to be false, p1, p2, p3 and p4 are propagated using BCP, + // but l2 is not since the lemma (*) was deleted. + // + // Probing module still "knows" that l \/ l2 is valid binary clause + // + // 6. A new lemma is created where ~l2 is the FUIP and the lemma also contains l. + // If we remove l0 != ~l2 may try to delete the FUIP. + if (is_marked_lit(~l2) && l0 != ~l2) { // eliminate ~l2 from lemma because we have the clause l \/ l2 unmark_lit(~l2); } From d5a14c0b51bf5a7a25dc450b81288dda56c915fb Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 9 Apr 2013 08:49:04 -0700 Subject: [PATCH 077/281] Fix problem reported at http://stackoverflow.com/questions/15882140/z3-smt2-in-get-z3-version/15882868#comment22637420_15882868 Signed-off-by: Leonardo de Moura --- src/cmd_context/basic_cmds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 21a986fda..9f18608d3 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -568,7 +568,7 @@ public: ctx.regular_stream() << "(:authors \"Leonardo de Moura and Nikolaj Bjorner\")" << std::endl; } else if (opt == m_version) { - ctx.regular_stream() << "(:version \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "\")" << std::endl; + ctx.regular_stream() << "(:version \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER << "\")" << std::endl; } else if (opt == m_status) { ctx.regular_stream() << "(:status " << ctx.get_status() << ")" << std::endl; From 6a36116b5cd537e159a0fcc8f8e12d78d6f3cf0c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 9 Apr 2013 10:16:37 -0700 Subject: [PATCH 078/281] stash --- src/muz_qe/dl_compiler.cpp | 7 ++++--- src/muz_qe/dl_instruction.cpp | 3 ++- src/muz_qe/dl_mk_magic_sets.cpp | 1 - src/muz_qe/dl_sparse_table.cpp | 5 +++++ src/muz_qe/dl_util.h | 6 ++++++ src/muz_qe/rel_context.cpp | 17 ++++++++--------- src/test/dl_query.cpp | 13 +++++++++---- 7 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index c898f7964..1bc39d213 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -61,13 +61,14 @@ namespace datalog { void compiler::make_join_project(reg_idx t1, reg_idx t2, const variable_intersection & vars, const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc) { relation_signature aux_sig; - relation_signature::from_join(m_reg_signatures[t1], m_reg_signatures[t2], vars.size(), - vars.get_cols1(), vars.get_cols2(), aux_sig); + relation_signature sig1 = m_reg_signatures[t1]; + relation_signature sig2 = m_reg_signatures[t2]; + relation_signature::from_join(sig1, sig2, vars.size(), vars.get_cols1(), vars.get_cols2(), aux_sig); relation_signature res_sig; relation_signature::from_project(aux_sig, removed_cols.size(), removed_cols.c_ptr(), res_sig); - result = get_fresh_register(res_sig); + acc.push_back(instruction::mk_join_project(t1, t2, vars.size(), vars.get_cols1(), vars.get_cols2(), removed_cols.size(), removed_cols.c_ptr(), result)); } diff --git a/src/muz_qe/dl_instruction.cpp b/src/muz_qe/dl_instruction.cpp index 401a42e98..547752563 100644 --- a/src/muz_qe/dl_instruction.cpp +++ b/src/muz_qe/dl_instruction.cpp @@ -723,7 +723,8 @@ namespace datalog { instr_join_project(reg_idx rel1, reg_idx rel2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols, reg_idx result) : m_rel1(rel1), m_rel2(rel2), m_cols1(joined_col_cnt, cols1), - m_cols2(joined_col_cnt, cols2), m_removed_cols(removed_col_cnt, removed_cols), m_res(result) {} + m_cols2(joined_col_cnt, cols2), m_removed_cols(removed_col_cnt, removed_cols), m_res(result) { + } virtual bool perform(execution_context & ctx) { ctx.make_empty(m_res); if (!ctx.reg(m_rel1) || !ctx.reg(m_rel2)) { diff --git a/src/muz_qe/dl_mk_magic_sets.cpp b/src/muz_qe/dl_mk_magic_sets.cpp index 6885edc4e..e69be05da 100644 --- a/src/muz_qe/dl_mk_magic_sets.cpp +++ b/src/muz_qe/dl_mk_magic_sets.cpp @@ -318,7 +318,6 @@ namespace datalog { } rule_set * mk_magic_sets::operator()(rule_set const & source) { - SASSERT(!m_context.get_model_converter()); unsigned init_rule_cnt = source.get_num_rules(); { func_decl_set intentional; diff --git a/src/muz_qe/dl_sparse_table.cpp b/src/muz_qe/dl_sparse_table.cpp index 1449b7d3d..dde09428f 100644 --- a/src/muz_qe/dl_sparse_table.cpp +++ b/src/muz_qe/dl_sparse_table.cpp @@ -500,6 +500,11 @@ namespace datalog { char * reserve = m_data.get_reserve_ptr(); unsigned col_cnt = m_column_layout.size(); for(unsigned i=0; i= get_signature()[i]) { + std::cout << "***************************\n"; + std::cout << f[i] << " " << get_signature()[i] << "\n"; + } //the value fits into the table signature + SASSERT(f[i]get_fact(tf); @@ -127,6 +128,7 @@ void dl_query_test(ast_manager & m, smt_params & fparams, params_ref& params, void dl_query_test_wpa(smt_params & fparams, params_ref& params) { params.set_bool("magic_sets_for_queries", true); ast_manager m; + random_gen ran(0); reg_decl_plugins(m); arith_util arith(m); const char * problem_dir = "C:\\tvm\\src\\z3_2\\debug\\test\\w0.datalog"; @@ -151,8 +153,8 @@ void dl_query_test_wpa(smt_params & fparams, params_ref& params) { TRUSTME( ctx.try_get_sort_constant_count(var_sort, var_sz) ); for(unsigned attempt=0; attempt Date: Wed, 10 Apr 2013 11:54:35 -0700 Subject: [PATCH 079/281] add .gitattributes Signed-off-by: Nuno Lopes --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..b86ed5df7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +src/api/dotnet/Properties/AssemblyInfo.cs text eol=crlf From 14172d3fae2960398b7ffc3563bb09baf12e0368 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 10 Apr 2013 14:49:07 -0700 Subject: [PATCH 080/281] fix crash in dl_interp_tail_simplifier when no transformation is performed Signed-off-by: Nuno Lopes --- src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index 51bbd52df..d0b94f582 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -583,11 +583,12 @@ namespace datalog { } rule_set * res = alloc(rule_set, m_context); - if (!transform_rules(source, *res)) { + if (transform_rules(source, *res)) { + res->inherit_predicates(source); + } else { dealloc(res); res = 0; } - res->inherit_predicates(source); return res; } From 2685c605e54fe5461c3f6d1b593b16c20354eb13 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 10 Apr 2013 16:37:47 -0700 Subject: [PATCH 081/281] [datalog] fix a few bugs related with output predicates (by me & Nikolaj) Signed-off-by: Nuno Lopes --- src/muz_qe/dl_mk_rule_inliner.cpp | 14 +++++++------- src/muz_qe/dl_mk_rule_inliner.h | 4 ++-- src/muz_qe/dl_mk_similarity_compressor.cpp | 6 +++--- src/muz_qe/dl_mk_similarity_compressor.h | 2 +- src/muz_qe/dl_rule_set.cpp | 10 +++++----- src/muz_qe/rel_context.cpp | 2 ++ 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp index c6ffa1378..8428d9049 100644 --- a/src/muz_qe/dl_mk_rule_inliner.cpp +++ b/src/muz_qe/dl_mk_rule_inliner.cpp @@ -667,7 +667,7 @@ namespace datalog { return et->get_data().m_value; } - void mk_rule_inliner::add_rule(rule* r, unsigned i) { + void mk_rule_inliner::add_rule(rule_set const& source, rule* r, unsigned i) { svector& can_remove = m_head_visitor.can_remove(); svector& can_expand = m_head_visitor.can_expand(); app* head = r->get_head(); @@ -676,7 +676,7 @@ namespace datalog { m_head_index.insert(head); m_pinned.push_back(r); - if (m_context.get_rules().is_output_predicate(headd) || + if (source.is_output_predicate(headd) || m_preds_with_facts.contains(headd)) { can_remove.set(i, false); TRACE("dl", output_predicate(m_context, head, tout << "cannot remove: " << i << " "); tout << "\n";); @@ -692,7 +692,7 @@ namespace datalog { tl_sz == 1 && r->get_positive_tail_size() == 1 && !m_preds_with_facts.contains(r->get_decl(0)) - && !m_context.get_rules().is_output_predicate(r->get_decl(0)); + && !source.is_output_predicate(r->get_decl(0)); can_expand.set(i, can_exp); } @@ -709,7 +709,7 @@ namespace datalog { #define PRT(_x_) ((_x_)?"T":"F") - bool mk_rule_inliner::inline_linear(scoped_ptr& rules) { + bool mk_rule_inliner::inline_linear(rule_set const& source, scoped_ptr& rules) { scoped_ptr res = alloc(rule_set, m_context); bool done_something = false; unsigned sz = rules->get_num_rules(); @@ -731,7 +731,7 @@ namespace datalog { svector& can_expand = m_head_visitor.can_expand(); for (unsigned i = 0; i < sz; ++i) { - add_rule(acc[i].get(), i); + add_rule(source, acc[i].get(), i); } // initialize substitution. @@ -808,7 +808,7 @@ namespace datalog { TRACE("dl", r->display(m_context, tout); r2->display(m_context, tout); rl_res->display(m_context, tout); ); del_rule(r, i); - add_rule(rl_res.get(), i); + add_rule(source, rl_res.get(), i); r = rl_res; @@ -875,7 +875,7 @@ namespace datalog { TRACE("dl", res->display(tout << "after eager inlining\n");); } - if (m_context.get_params().inline_linear() && inline_linear(res)) { + if (m_context.get_params().inline_linear() && inline_linear(source, res)) { something_done = true; } diff --git a/src/muz_qe/dl_mk_rule_inliner.h b/src/muz_qe/dl_mk_rule_inliner.h index bec788ffe..476c6b4b0 100644 --- a/src/muz_qe/dl_mk_rule_inliner.h +++ b/src/muz_qe/dl_mk_rule_inliner.h @@ -172,9 +172,9 @@ namespace datalog { /** Inline predicates that are known to not be join-points. */ - bool inline_linear(scoped_ptr& rules); + bool inline_linear(rule_set const& source, scoped_ptr& rules); - void add_rule(rule* r, unsigned i); + void add_rule(rule_set const& rule_set, rule* r, unsigned i); void del_rule(rule* r, unsigned i); public: diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index 969f1444a..040cbfa78 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -429,7 +429,7 @@ namespace datalog { m_modified = true; } - void mk_similarity_compressor::process_class(rule_vector::iterator first, + void mk_similarity_compressor::process_class(rule_set const& source, rule_vector::iterator first, rule_vector::iterator after_last) { SASSERT(first!=after_last); //remove duplicates @@ -487,7 +487,7 @@ namespace datalog { //TODO: compress also rules with pairs (or tuples) of equal constants #if 1 - if (const_cnt>0) { + if (const_cnt>0 && !source.is_output_predicate((*first)->get_decl())) { unsigned rule_cnt = static_cast(after_last-first); if (rule_cnt>m_threshold_count) { merge_class(first, after_last); @@ -521,7 +521,7 @@ namespace datalog { rule_vector::iterator prev = it; ++it; if (it==end || rough_compare(*prev, *it)!=0) { - process_class(cl_begin, it); + process_class(source, cl_begin, it); cl_begin = it; } } diff --git a/src/muz_qe/dl_mk_similarity_compressor.h b/src/muz_qe/dl_mk_similarity_compressor.h index 6e0ca9db5..49704b8cd 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.h +++ b/src/muz_qe/dl_mk_similarity_compressor.h @@ -63,7 +63,7 @@ namespace datalog { ast_ref_vector m_pinned; void merge_class(rule_vector::iterator first, rule_vector::iterator after_last); - void process_class(rule_vector::iterator first, rule_vector::iterator after_last); + void process_class(rule_set const& source, rule_vector::iterator first, rule_vector::iterator after_last); void reset(); public: diff --git a/src/muz_qe/dl_rule_set.cpp b/src/muz_qe/dl_rule_set.cpp index b0bcdec89..cb129ab37 100644 --- a/src/muz_qe/dl_rule_set.cpp +++ b/src/muz_qe/dl_rule_set.cpp @@ -332,15 +332,12 @@ namespace datalog { void rule_set::inherit_predicates(rule_set const& other) { m_refs.append(other.m_refs); - SASSERT(m_refs.size() < 1000); set_union(m_output_preds, other.m_output_preds); { obj_map::iterator it = other.m_orig2pred.begin(); obj_map::iterator end = other.m_orig2pred.end(); for (; it != end; ++it) { m_orig2pred.insert(it->m_key, it->m_value); - m_refs.push_back(it->m_key); - m_refs.push_back(it->m_value); } } { @@ -348,8 +345,6 @@ namespace datalog { obj_map::iterator end = other.m_pred2orig.end(); for (; it != end; ++it) { m_pred2orig.insert(it->m_key, it->m_value); - m_refs.push_back(it->m_key); - m_refs.push_back(it->m_value); } } } @@ -515,6 +510,11 @@ namespace datalog { void rule_set::display(std::ostream & out) const { out << "; rule count: " << get_num_rules() << "\n"; out << "; predicate count: " << m_head2rules.size() << "\n"; + func_decl_set::iterator pit = m_output_preds.begin(); + func_decl_set::iterator pend = m_output_preds.end(); + for (; pit != pend; ++pit) { + out << "; output: " << (*pit)->get_name() << '\n'; + } decl2rules::iterator it = m_head2rules.begin(); decl2rules::iterator end = m_head2rules.end(); for (; it != end; ++it) { diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 327e63c0f..00181b18c 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -253,6 +253,8 @@ namespace datalog { m_context.transform_rules(alloc(mk_magic_sets, m_context, query_pred)); } + query_pred = m_context.get_rules().get_pred(query_pred); + lbool res = saturate(); if (res != l_undef) { From f6f59ad6bc675347a227b008459c4c89dfb0d073 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 10 Apr 2013 19:03:25 -0700 Subject: [PATCH 082/281] Fix memory allocation problems in RCF module Signed-off-by: Leonardo de Moura --- src/math/realclosure/realclosure.cpp | 21 ++++++++------------- src/test/rcf.cpp | 2 -- src/util/array.h | 2 +- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/math/realclosure/realclosure.cpp b/src/math/realclosure/realclosure.cpp index 87b1ef8a4..84ba606fd 100644 --- a/src/math/realclosure/realclosure.cpp +++ b/src/math/realclosure/realclosure.cpp @@ -660,8 +660,7 @@ namespace realclosure { return; // interval was already saved. to_restore.push_back(v); inc_ref(v); - void * mem = allocator().allocate(sizeof(mpbqi)); - v->m_old_interval = new (mem) mpbqi(); + v->m_old_interval = new (allocator()) mpbqi(); set_interval(*(v->m_old_interval), v->m_interval); } void save_interval(value * v) { @@ -1237,8 +1236,7 @@ namespace realclosure { } sign_condition * mk_sign_condition(unsigned qidx, int sign, sign_condition * prev_sc) { - void * mem = allocator().allocate(sizeof(sign_condition)); - return new (mem) sign_condition(qidx, sign, prev_sc); + return new (allocator()) sign_condition(qidx, sign, prev_sc); } /** @@ -1246,7 +1244,7 @@ namespace realclosure { This method does not set the interval. It remains (-oo, oo) */ rational_function_value * mk_rational_function_value_core(extension * ext, unsigned num_sz, value * const * num, unsigned den_sz, value * const * den) { - rational_function_value * r = alloc(rational_function_value, ext); + rational_function_value * r = new (allocator()) rational_function_value(ext); inc_ref(ext); set_p(r->num(), num_sz, num); if (ext->is_algebraic()) { @@ -1283,7 +1281,7 @@ namespace realclosure { */ void mk_infinitesimal(symbol const & n, symbol const & pp_n, numeral & r) { unsigned idx = next_infinitesimal_idx(); - infinitesimal * eps = alloc(infinitesimal, idx, n, pp_n); + infinitesimal * eps = new (allocator()) infinitesimal(idx, n, pp_n); m_extensions[extension::INFINITESIMAL].push_back(eps); set_lower(eps->interval(), mpbq(0)); @@ -1335,7 +1333,7 @@ namespace realclosure { void mk_transcendental(symbol const & n, symbol const & pp_n, mk_interval & proc, numeral & r) { unsigned idx = next_transcendental_idx(); - transcendental * t = alloc(transcendental, idx, n, pp_n, proc); + transcendental * t = new (allocator()) transcendental(idx, n, pp_n, proc); m_extensions[extension::TRANSCENDENTAL].push_back(t); while (contains_zero(t->interval())) { @@ -1798,8 +1796,7 @@ namespace realclosure { M and scs will be empty after this operation. */ sign_det * mk_sign_det(mpz_matrix & M_s, scoped_polynomial_seq const & prs, int_buffer const & taqrs, scoped_polynomial_seq const & qs, scoped_sign_conditions & scs) { - void * mem = allocator().allocate(sizeof(sign_det)); - sign_det * r = new (mem) sign_det(); + sign_det * r = new (allocator()) sign_det(); r->M_s.swap(M_s); set_array_p(r->m_prs, prs); r->m_taqrs.set(allocator(), taqrs.size(), taqrs.c_ptr()); @@ -1814,8 +1811,7 @@ namespace realclosure { */ algebraic * mk_algebraic(unsigned p_sz, value * const * p, mpbqi const & interval, mpbqi const & iso_interval, sign_det * sd, unsigned sc_idx) { unsigned idx = next_algebraic_idx(); - void * mem = allocator().allocate(sizeof(algebraic)); - algebraic * r = new (mem) algebraic(idx); + algebraic * r = new (allocator()) algebraic(idx); m_extensions[extension::ALGEBRAIC].push_back(r); set_p(r->m_p, p_sz, p); @@ -2561,8 +2557,7 @@ namespace realclosure { } rational_value * mk_rational() { - void * mem = allocator().allocate(sizeof(rational_value)); - return new (mem) rational_value(); + return new (allocator()) rational_value(); } /** diff --git a/src/test/rcf.cpp b/src/test/rcf.cpp index d6cfd8b86..294a7df29 100644 --- a/src/test/rcf.cpp +++ b/src/test/rcf.cpp @@ -137,7 +137,6 @@ static void tst_lin_indep(unsigned m, unsigned n, int _A[], unsigned ex_sz, unsi r.resize(A.n()); scoped_mpz_matrix B(mm); mm.linear_independent_rows(A, r.c_ptr(), B); - SASSERT(r.size() == ex_sz); for (unsigned i = 0; i < ex_sz; i++) { SASSERT(r[i] == ex_r[i]); } @@ -164,7 +163,6 @@ void tst_rcf() { enable_trace("rcf_clean"); enable_trace("rcf_clean_bug"); tst_denominators(); - return; tst1(); tst2(); { int A[] = {0, 1, 1, 1, 0, 1, 1, 1, -1}; int c[] = {10, 4, -4}; int b[] = {-2, 4, 6}; tst_solve(3, A, b, c, true); } diff --git a/src/util/array.h b/src/util/array.h index a3658c354..f983f7dec 100644 --- a/src/util/array.h +++ b/src/util/array.h @@ -122,7 +122,7 @@ public: if (m_data) { if (CallDestructors) destroy_elements(); - a.deallocate(size(), raw_ptr()); + a.deallocate(space(size()), raw_ptr()); m_data = 0; } } From dc77141dce86d7049b2e33f0be13f974fda4ca5b Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 10 Apr 2013 19:14:10 -0700 Subject: [PATCH 083/281] Fix warning messages Signed-off-by: Leonardo de Moura --- src/util/small_object_allocator.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/util/small_object_allocator.h b/src/util/small_object_allocator.h index 538a9e035..957c4f475 100644 --- a/src/util/small_object_allocator.h +++ b/src/util/small_object_allocator.h @@ -21,6 +21,7 @@ Revision History: #define _SMALL_OBJECT_ALLOCATOR_H_ #include"machine.h" +#include"debug.h" class small_object_allocator { static const unsigned CHUNK_SIZE = (8192 - sizeof(void*)*2); @@ -52,8 +53,8 @@ public: inline void * operator new(size_t s, small_object_allocator & r) { return r.allocate(s); } inline void * operator new[](size_t s, small_object_allocator & r) { return r.allocate(s); } -inline void operator delete(void * p, size_t s, small_object_allocator & r) { r.deallocate(s,p); } -inline void operator delete[](void * p, size_t s, small_object_allocator & r) { r.deallocate(s,p); } +inline void operator delete(void * p, small_object_allocator & r) { UNREACHABLE(); } +inline void operator delete[](void * p, small_object_allocator & r) { UNREACHABLE(); } #endif /* _SMALL_OBJECT_ALLOCATOR_H_ */ From cdb90968e31de612747d04e5345ccb056f525c97 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 10 Apr 2013 20:06:21 -0700 Subject: [PATCH 084/281] minor fixes to rel_context Signed-off-by: Nikolaj Bjorner --- src/muz_qe/rel_context.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 327e63c0f..0e84ce4f6 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -40,7 +40,9 @@ namespace datalog { rule_set m_rules; decl_set m_preds; bool m_was_closed; + public: + scoped_query(context& ctx): m_ctx(ctx), m_rules(ctx.get_rules()), @@ -51,6 +53,7 @@ namespace datalog { ctx.reopen(); } } + ~scoped_query() { m_ctx.reopen(); m_ctx.restrict_predicates(m_preds); @@ -235,7 +238,6 @@ namespace datalog { query_pred = rm.mk_query(query, m_context.get_rules()); } catch (default_exception& exn) { - m_context.close(); m_context.set_status(INPUT_ERROR); throw exn; } From cb31a294c8b5fe4ba4ba1ca372b101def93b537b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 11 Apr 2013 08:50:04 -0700 Subject: [PATCH 085/281] use unsigned_vector where appropriate Signed-off-by: Nuno Lopes --- src/muz_qe/dl_instruction.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/muz_qe/dl_instruction.cpp b/src/muz_qe/dl_instruction.cpp index 401a42e98..478af3127 100644 --- a/src/muz_qe/dl_instruction.cpp +++ b/src/muz_qe/dl_instruction.cpp @@ -452,7 +452,7 @@ namespace datalog { class instr_filter_identical : public instruction { - typedef vector column_vector; + typedef unsigned_vector column_vector; reg_idx m_reg; column_vector m_cols; public: @@ -651,7 +651,7 @@ namespace datalog { class instr_project_rename : public instruction { - typedef vector column_vector; + typedef unsigned_vector column_vector; bool m_projection; reg_idx m_src; column_vector m_cols; @@ -830,7 +830,7 @@ namespace datalog { class instr_filter_by_negation : public instruction { - typedef vector column_vector; + typedef unsigned_vector column_vector; reg_idx m_tgt; reg_idx m_neg_rel; column_vector m_cols1; From 1f5097cdaa40fab3e788412e3ed402fdfe372834 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 15 Apr 2013 16:53:25 -0700 Subject: [PATCH 086/281] [datalog] fix stratum cycle break for rules with multiple looping dependecies e.g. a -> b b-> a a -> a this change makes the cycle breaker quadratic on the number of predicates. This should be revisited later Signed-off-by: Nuno Lopes --- src/muz_qe/dl_compiler.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index 9110c5edb..215a438fc 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -803,17 +803,15 @@ namespace datalog { context& m_context; item_set & m_removed; svector m_stack; - ast_mark m_stack_content; ast_mark m_visited; void traverse(T v) { - SASSERT(!m_stack_content.is_marked(v)); - if(m_visited.is_marked(v) || m_removed.contains(v)) { + SASSERT(!m_visited.is_marked(v)); + if (m_removed.contains(v)) { return; } m_stack.push_back(v); - m_stack_content.mark(v, true); m_visited.mark(v, true); const item_set & deps = m_deps.get_deps(v); @@ -821,33 +819,34 @@ namespace datalog { item_set::iterator end = deps.end(); for(; it!=end; ++it) { T d = *it; - if(m_stack_content.is_marked(d)) { + if (m_visited.is_marked(d)) { //TODO: find the best vertex to remove in the cycle remove_from_stack(); - break; + continue; } traverse(d); } SASSERT(m_stack.back()==v); m_stack.pop_back(); - m_stack_content.mark(v, false); + m_visited.mark(v, false); } void remove_from_stack() { for (unsigned i = 0; i < m_stack.size(); ++i) { func_decl* p = m_stack[i]; - rule_vector const& rules = m_rules.get_predicate_rules(p); - unsigned stratum = m_rules.get_predicate_strat(p); if (m_context.has_facts(p)) { m_removed.insert(p); return; } + + rule_vector const& rules = m_rules.get_predicate_rules(p); + unsigned stratum = m_rules.get_predicate_strat(p); for (unsigned j = 0; j < rules.size(); ++j) { rule const& r = *rules[j]; bool ok = true; for (unsigned k = 0; ok && k < r.get_uninterpreted_tail_size(); ++k) { - ok &= m_rules.get_predicate_strat(r.get_decl(k)) < stratum; + ok = m_rules.get_predicate_strat(r.get_decl(k)) < stratum; } if (ok) { m_removed.insert(p); @@ -858,8 +857,8 @@ namespace datalog { // nothing was found. m_removed.insert(m_stack.back()); - } + public: cycle_breaker(rule_dependencies & deps, rule_set const& rules, context& ctx, item_set & removed) : m_deps(deps), m_rules(rules), m_context(ctx), m_removed(removed) { SASSERT(removed.empty()); } From 38823d6c79b121fca6e6392a2fb4e45ca74deea1 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 16 Apr 2013 08:16:02 -0700 Subject: [PATCH 087/281] [PDR] fix expansion of BV literals Signed-off-by: Nuno Lopes --- src/muz_qe/pdr_prop_solver.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/muz_qe/pdr_prop_solver.cpp b/src/muz_qe/pdr_prop_solver.cpp index daa52992f..863e5c03e 100644 --- a/src/muz_qe/pdr_prop_solver.cpp +++ b/src/muz_qe/pdr_prop_solver.cpp @@ -145,7 +145,8 @@ namespace pdr { rational two(2); for (unsigned j = 0; j < bv_size; ++j) { parameter p(j); - expr* e = m.mk_app(bv.get_family_id(), OP_BIT2BOOL, 1, &p, 1, &c); + //expr* e = m.mk_app(bv.get_family_id(), OP_BIT2BOOL, 1, &p, 1, &c); + expr* e = m.mk_eq(m.mk_app(bv.get_family_id(), OP_BIT1), bv.mk_extract(j, j, c)); if ((r % two).is_zero()) { e = m.mk_not(e); } From adc8224dbae9ceffd87ef1b179caa1dcb118f777 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 16 Apr 2013 09:02:40 -0700 Subject: [PATCH 088/281] use svector instead of vector where appropriate Signed-off-by: Nuno Lopes --- src/ast/ast.cpp | 2 +- src/util/bit_vector.cpp | 6 ++---- src/util/bit_vector.h | 2 +- src/util/mpff.h | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 8d643a348..fefb400ed 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2755,7 +2755,7 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro app const * cls = to_app(f1); unsigned num_args = cls->get_num_args(); #ifdef Z3DEBUG - vector found; + svector found; #endif for (unsigned i = 0; i < num_args; i++) { expr * lit = cls->get_arg(i); diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index e3a2bc331..0d67f1f79 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -208,8 +208,8 @@ void bit_vector::display(std::ostream & out) const { void fr_bit_vector::reset() { unsigned sz = size(); - vector::const_iterator it = m_one_idxs.begin(); - vector::const_iterator end = m_one_idxs.end(); + unsigned_vector::const_iterator it = m_one_idxs.begin(); + unsigned_vector::const_iterator end = m_one_idxs.end(); for (; it != end; ++it) { unsigned idx = *it; if (idx < sz) @@ -217,5 +217,3 @@ void fr_bit_vector::reset() { } m_one_idxs.reset(); } - - diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 1d6083717..2c641c5a6 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -204,7 +204,7 @@ inline std::ostream & operator<<(std::ostream & out, bit_vector const & b) { This class should be used if the reset is frequently called. */ class fr_bit_vector : private bit_vector { - svector m_one_idxs; + unsigned_vector m_one_idxs; public: void reset(); diff --git a/src/util/mpff.h b/src/util/mpff.h index de71ec75e..8d4c853af 100644 --- a/src/util/mpff.h +++ b/src/util/mpff.h @@ -107,7 +107,7 @@ class mpff_manager { unsigned m_precision; //!< Number of words in the significand. Must be an even number. unsigned m_precision_bits; //!< Number of bits in the significand. Must be 32*m_precision. - vector m_significands; //!< Array containing all significands. + unsigned_vector m_significands; //!< Array containing all significands. unsigned m_capacity; //!< Number of significands that can be stored in m_significands. bool m_to_plus_inf; //!< If True, then round to plus infinity, otherwise to minus infinity id_gen m_id_gen; From 51d3db8105facdbdaf18be56ed3afee09bc1eda9 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 16 Apr 2013 10:48:57 -0700 Subject: [PATCH 089/281] [dl] remove 2 uneeded fields from sparse_table::rename_fn Signed-off-by: Nuno Lopes --- src/muz_qe/dl_sparse_table.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/muz_qe/dl_sparse_table.cpp b/src/muz_qe/dl_sparse_table.cpp index 47f518ee2..52d9618b8 100644 --- a/src/muz_qe/dl_sparse_table.cpp +++ b/src/muz_qe/dl_sparse_table.cpp @@ -1022,19 +1022,16 @@ namespace datalog { class sparse_table_plugin::rename_fn : public convenient_table_rename_fn { - const unsigned m_cycle_len; - const unsigned m_col_cnt; unsigned_vector m_out_of_cycle; public: rename_fn(const table_signature & orig_sig, unsigned permutation_cycle_len, const unsigned * permutation_cycle) - : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle), - m_cycle_len(permutation_cycle_len), m_col_cnt(orig_sig.size()) { + : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle) { SASSERT(permutation_cycle_len>=2); idx_set cycle_cols; - for (unsigned i=0; i Date: Tue, 16 Apr 2013 13:54:41 -0700 Subject: [PATCH 090/281] cleanup front end parameters to datalog engine Signed-off-by: Nikolaj Bjorner --- src/shell/datalog_frontend.cpp | 19 +------------------ src/shell/datalog_frontend.h | 5 ----- src/shell/main.cpp | 2 +- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 6cdfe1623..efcab14ea 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -43,17 +43,7 @@ static datalog::context * g_ctx = 0; static datalog::rule_set * g_orig_rules; static datalog::instruction_block * g_code; static datalog::execution_context * g_ectx; -static smt_params * g_params; -datalog_params::datalog_params(): - m_default_table("sparse"), - m_default_table_checked(false) -{} - -// void datalog_params::register_params(ini_params& p) { -// p.register_symbol_param("DEFAULT_TABLE", m_default_table, "Datalog engine: default table (sparse)"); -// p.register_bool_param("DEFAULT_TABLE_CHECKED", m_default_table_checked, "Wrap default table with a sanity checker"); -// } static void display_statistics( std::ostream& out, @@ -61,7 +51,6 @@ static void display_statistics( datalog::rule_set& orig_rules, datalog::instruction_block& code, datalog::execution_context& ex_ctx, - smt_params& params, bool verbose ) { @@ -109,7 +98,7 @@ static void display_statistics( static void display_statistics() { if (g_ctx) { - display_statistics(std::cout, *g_ctx, *g_orig_rules, *g_code, *g_ectx, *g_params, true); + display_statistics(std::cout, *g_ctx, *g_orig_rules, *g_code, *g_ectx, true); } } @@ -127,7 +116,6 @@ static void on_ctrl_c(int) { unsigned read_datalog(char const * file) { IF_VERBOSE(1, verbose_stream() << "Z3 Datalog Engine\n";); - datalog_params dl_params; smt_params s_params; ast_manager m; g_overall_time.start(); @@ -135,8 +123,6 @@ unsigned read_datalog(char const * file) { signal(SIGINT, on_ctrl_c); params_ref params; params.set_sym("engine", symbol("datalog")); - params.set_sym("default_table", dl_params.m_default_table); - params.set_bool("default_table_checked", dl_params.m_default_table_checked); datalog::context ctx(m, s_params, params); datalog::relation_manager & rmgr = ctx.get_rel_context().get_rmanager(); @@ -186,7 +172,6 @@ unsigned read_datalog(char const * file) { g_orig_rules = &original_rules; g_code = &rules_code; g_ectx = &ex_ctx; - g_params = &s_params; try { g_piece_timer.reset(); @@ -254,7 +239,6 @@ unsigned read_datalog(char const * file) { original_rules, rules_code, ex_ctx, - s_params, false); } @@ -266,7 +250,6 @@ unsigned read_datalog(char const * file) { original_rules, rules_code, ex_ctx, - s_params, true); return ERR_MEMOUT; } diff --git a/src/shell/datalog_frontend.h b/src/shell/datalog_frontend.h index e53e35c89..8022d5046 100644 --- a/src/shell/datalog_frontend.h +++ b/src/shell/datalog_frontend.h @@ -19,11 +19,6 @@ Revision History: #ifndef _DATALOG_FRONTEND_H_ #define _DATALOG_FRONTEND_H_ -struct datalog_params { - symbol m_default_table; - bool m_default_table_checked; - datalog_params(); -}; unsigned read_datalog(char const * file); diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 63e604719..e0fa4a1f2 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -27,8 +27,8 @@ Revision History: #include"z3_log_frontend.h" #include"warning.h" #include"version.h" -#include"datalog_frontend.h" #include"dimacs_frontend.h" +#include"datalog_frontend.h" #include"timeout.h" #include"z3_exception.h" #include"error_codes.h" From 0b0e5b69121b463a42781a22b43854ff48b9673b Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 16 Apr 2013 15:14:16 -0700 Subject: [PATCH 091/281] add some constness Signed-off-by: Nuno Lopes --- src/ast/dl_decl_plugin.cpp | 4 ++-- src/ast/dl_decl_plugin.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index 1524760e5..d8e2385ec 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -660,9 +660,9 @@ namespace datalog { return 0; } - bool dl_decl_util::is_numeral(expr* e, uint64& v) const { + bool dl_decl_util::is_numeral(const expr* e, uint64& v) const { if (is_numeral(e)) { - app* c = to_app(e); + const app* c = to_app(e); SASSERT(c->get_decl()->get_num_parameters() == 2); parameter const& p = c->get_decl()->get_parameter(0); SASSERT(p.is_rational()); diff --git a/src/ast/dl_decl_plugin.h b/src/ast/dl_decl_plugin.h index 559aff7bd..a662de578 100644 --- a/src/ast/dl_decl_plugin.h +++ b/src/ast/dl_decl_plugin.h @@ -169,11 +169,11 @@ namespace datalog { app* mk_le(expr* a, expr* b); - bool is_lt(expr* a) { return is_app_of(a, m_fid, OP_DL_LT); } + bool is_lt(const expr* a) const { return is_app_of(a, m_fid, OP_DL_LT); } - bool is_numeral(expr* c) const { return is_app_of(c, m_fid, OP_DL_CONSTANT); } + bool is_numeral(const expr* c) const { return is_app_of(c, m_fid, OP_DL_CONSTANT); } - bool is_numeral(expr* e, uint64& v) const; + bool is_numeral(const expr* e, uint64& v) const; // // Utilities for extracting constants From 2afcc493e074afd23d9bf6b4be19ae0c3811a2d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Apr 2013 10:18:26 -0700 Subject: [PATCH 092/281] remove reference count debugging, add substitution to C++ header Signed-off-by: Nikolaj Bjorner --- src/api/api_util.h | 17 ++++++++--------- src/api/c++/z3++.h | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/api/api_util.h b/src/api/api_util.h index 58abf97bf..b49ef8315 100644 --- a/src/api/api_util.h +++ b/src/api/api_util.h @@ -29,7 +29,6 @@ Revision History: #define Z3_CATCH_RETURN_NO_HANDLE(VAL) } catch (z3_exception &) { return VAL; } #define CHECK_REF_COUNT(a) (reinterpret_cast(a)->get_ref_count() > 0) -#define VALIDATE(a) SASSERT(!a || CHECK_REF_COUNT(a)) namespace api { // Generic wrapper for ref-count objects exposed by the API @@ -44,30 +43,30 @@ namespace api { }; }; -inline ast * to_ast(Z3_ast a) { VALIDATE(a); return reinterpret_cast(a); } +inline ast * to_ast(Z3_ast a) { return reinterpret_cast(a); } inline Z3_ast of_ast(ast* a) { return reinterpret_cast(a); } -inline expr * to_expr(Z3_ast a) { VALIDATE(a); return reinterpret_cast(a); } +inline expr * to_expr(Z3_ast a) { return reinterpret_cast(a); } inline Z3_ast of_expr(expr* e) { return reinterpret_cast(e); } inline expr * const * to_exprs(Z3_ast const* a) { return reinterpret_cast(a); } inline Z3_ast * const * of_exprs(expr* const* e) { return reinterpret_cast(e); } -inline app * to_app(Z3_app a) { VALIDATE(a); return reinterpret_cast(a); } -inline app * to_app(Z3_ast a) { VALIDATE(a); return reinterpret_cast(a); } +inline app * to_app(Z3_app a) { return reinterpret_cast(a); } +inline app * to_app(Z3_ast a) { return reinterpret_cast(a); } inline Z3_app of_app(app* a) { return reinterpret_cast(a); } -inline app * const* to_apps(Z3_ast const* a) { VALIDATE(a); return reinterpret_cast(a); } +inline app * const* to_apps(Z3_ast const* a) { return reinterpret_cast(a); } inline ast * const * to_asts(Z3_ast const* a) { return reinterpret_cast(a); } -inline sort * to_sort(Z3_sort a) { VALIDATE(a); return reinterpret_cast(a); } +inline sort * to_sort(Z3_sort a) { return reinterpret_cast(a); } inline Z3_sort of_sort(sort* s) { return reinterpret_cast(s); } inline sort * const * to_sorts(Z3_sort const* a) { return reinterpret_cast(a); } inline Z3_sort const * of_sorts(sort* const* s) { return reinterpret_cast(s); } -inline func_decl * to_func_decl(Z3_func_decl a) { VALIDATE(a); return reinterpret_cast(a); } +inline func_decl * to_func_decl(Z3_func_decl a) { return reinterpret_cast(a); } inline Z3_func_decl of_func_decl(func_decl* f) { return reinterpret_cast(f); } inline func_decl * const * to_func_decls(Z3_func_decl const* f) { return reinterpret_cast(f); } @@ -75,7 +74,7 @@ inline func_decl * const * to_func_decls(Z3_func_decl const* f) { return reinter inline symbol to_symbol(Z3_symbol s) { return symbol::mk_symbol_from_c_ptr(reinterpret_cast(s)); } inline Z3_symbol of_symbol(symbol s) { return reinterpret_cast(const_cast(s.c_ptr())); } -inline Z3_pattern of_pattern(ast* a) { VALIDATE(a); return reinterpret_cast(a); } +inline Z3_pattern of_pattern(ast* a) { return reinterpret_cast(a); } inline app* to_pattern(Z3_pattern p) { return reinterpret_cast(p); } inline Z3_lbool of_lbool(lbool b) { return static_cast(b); } diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 43975fd04..a044149e3 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -872,7 +872,18 @@ namespace z3 { \brief Return a simplified version of this expression. The parameter \c p is a set of parameters for the Z3 simplifier. */ expr simplify(params const & p) const { Z3_ast r = Z3_simplify_ex(ctx(), m_ast, p); check_error(); return expr(ctx(), r); } - }; + + /** + \brief Apply substitution. Replace src expressions by dst. + */ + expr substitute(expr_vector const& src, expr_vector const& dst); + + /** + \brief Apply substitution. Replace bound variables by expressions. + */ + expr substitute(expr_vector const& dst); + + }; /** \brief Wraps a Z3_ast as an expr object. It also checks for errors. @@ -1680,6 +1691,30 @@ namespace z3 { d.check_error(); return expr(d.ctx(), r); } + + inline expr expr::substitute(expr_vector const& src, expr_vector const& dst) { + assert(src.size() == dst.size()); + array _src(src.size()); + array _dst(dst.size()); + for (unsigned i = 0; i < src.size(); ++i) { + _src[i] = src[i]; + _dst[i] = dst[i]; + } + Z3_ast r = Z3_substitute(ctx(), m_ast, src.size(), _src.ptr(), _dst.ptr()); + check_error(); + return expr(ctx(), r); + } + + inline expr expr::substitute(expr_vector const& dst) { + array _dst(dst.size()); + for (unsigned i = 0; i < dst.size(); ++i) { + _dst[i] = dst[i]; + } + Z3_ast r = Z3_substitute_vars(ctx(), m_ast, dst.size(), _dst.ptr()); + check_error(); + return expr(ctx(), r); + } + }; From 63ece8278dac7c883984ad11109e18546a6dba47 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 18 Apr 2013 11:23:21 -0700 Subject: [PATCH 093/281] [datalog] improve compilation to reuse total tables, and to reduce cloning/deallocs. this gives up to 40% in memory reduction and 10% speedup in test cases with many rules Signed-off-by: Nuno Lopes --- src/muz_qe/dl_compiler.cpp | 102 +++++++++++++++++++++++++++---------- src/muz_qe/dl_compiler.h | 10 ++-- 2 files changed, 82 insertions(+), 30 deletions(-) diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index 215a438fc..80b9dee5a 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -146,7 +146,7 @@ namespace datalog { } void compiler::make_add_constant_column(func_decl* head_pred, reg_idx src, const relation_sort & s, const relation_element & val, - reg_idx & result, instruction_block & acc) { + reg_idx & result, bool & dealloc, instruction_block & acc) { reg_idx singleton_table; if(!m_constant_registers.find(s, val, singleton_table)) { singleton_table = get_single_column_register(s); @@ -155,16 +155,18 @@ namespace datalog { m_constant_registers.insert(s, val, singleton_table); } if(src==execution_context::void_register) { - make_clone(singleton_table, result, acc); + result = singleton_table; + dealloc = false; } else { variable_intersection empty_vars(m_context.get_manager()); make_join(src, singleton_table, empty_vars, result, acc); + dealloc = true; } } void compiler::make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort & s, reg_idx & result, - instruction_block & acc) { + bool & dealloc, instruction_block & acc) { TRACE("dl", tout << "Adding unbound column " << mk_pp(pred, m_context.get_manager()) << "\n";); IF_VERBOSE(3, { @@ -173,25 +175,35 @@ namespace datalog { verbose_stream() << "Compiling unsafe rule column " << col_idx << "\n" << mk_ismt2_pp(e, m_context.get_manager()) << "\n"; }); - reg_idx total_table = get_single_column_register(s); - relation_signature sig; - sig.push_back(s); - acc.push_back(instruction::mk_total(sig, pred, total_table)); + reg_idx total_table; + if (!m_total_registers.find(s, pred, total_table)) { + total_table = get_single_column_register(s); + relation_signature sig; + sig.push_back(s); + m_top_level_code.push_back(instruction::mk_total(sig, pred, total_table)); + m_total_registers.insert(s, pred, total_table); + } if(src == execution_context::void_register) { result = total_table; + dealloc = false; } else { variable_intersection empty_vars(m_context.get_manager()); make_join(src, total_table, empty_vars, result, acc); - make_dealloc_non_void(total_table, acc); + dealloc = true; } } void compiler::make_full_relation(func_decl* pred, const relation_signature & sig, reg_idx & result, instruction_block & acc) { + SASSERT(sig.empty()); TRACE("dl", tout << "Adding unbound column " << mk_pp(pred, m_context.get_manager()) << "\n";); + if (m_empty_tables_registers.find(pred, result)) + return; + result = get_fresh_register(sig); - acc.push_back(instruction::mk_total(sig, pred, result)); + m_top_level_code.push_back(instruction::mk_total(sig, pred, result)); + m_empty_tables_registers.insert(pred, result); } @@ -233,6 +245,7 @@ namespace datalog { reg_idx src, const svector & acis0, reg_idx & result, + bool & dealloc, instruction_block & acc) { TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";); @@ -277,7 +290,9 @@ namespace datalog { if(!src_cols_to_remove.empty()) { reg_idx new_curr; make_projection(curr, src_cols_to_remove.size(), src_cols_to_remove.c_ptr(), new_curr, acc); - make_dealloc_non_void(curr, acc); + if (dealloc) + make_dealloc_non_void(curr, acc); + dealloc = true; curr=new_curr; curr_sig = & m_reg_signatures[curr]; @@ -298,16 +313,19 @@ namespace datalog { unsigned bound_column_index; if(acis[i].kind!=ACK_UNBOUND_VAR || !handled_unbound.find(acis[i].var_index,bound_column_index)) { reg_idx new_curr; + bool new_dealloc; bound_column_index=curr_sig->size(); if(acis[i].kind==ACK_CONSTANT) { - make_add_constant_column(head_pred, curr, acis[i].domain, acis[i].constant, new_curr, acc); + make_add_constant_column(head_pred, curr, acis[i].domain, acis[i].constant, new_curr, new_dealloc, acc); } else { SASSERT(acis[i].kind==ACK_UNBOUND_VAR); - make_add_unbound_column(compiled_rule, i, head_pred, curr, acis[i].domain, new_curr, acc); + make_add_unbound_column(compiled_rule, i, head_pred, curr, acis[i].domain, new_curr, new_dealloc, acc); handled_unbound.insert(acis[i].var_index,bound_column_index); } - make_dealloc_non_void(curr, acc); + if (dealloc) + make_dealloc_non_void(curr, acc); + dealloc = new_dealloc; curr=new_curr; curr_sig = & m_reg_signatures[curr]; SASSERT(bound_column_index==curr_sig->size()-1); @@ -328,7 +346,9 @@ namespace datalog { } reg_idx new_curr; make_duplicate_column(curr, col, new_curr, acc); - make_dealloc_non_void(curr, acc); + if (dealloc) + make_dealloc_non_void(curr, acc); + dealloc = true; curr=new_curr; curr_sig = & m_reg_signatures[curr]; unsigned bound_column_index=curr_sig->size()-1; @@ -356,7 +376,9 @@ namespace datalog { reg_idx new_curr; make_rename(curr, permutation.size(), permutation.c_ptr(), new_curr, acc); - make_dealloc_non_void(curr, acc); + if (dealloc) + make_dealloc_non_void(curr, acc); + dealloc = true; curr=new_curr; curr_sig = & m_reg_signatures[curr]; } @@ -365,6 +387,7 @@ namespace datalog { SASSERT(src==execution_context::void_register); SASSERT(acis0.size()==0); make_full_relation(head_pred, empty_signature, curr, acc); + dealloc = false; } result=curr; @@ -416,6 +439,9 @@ namespace datalog { //by the join operation unsigned second_tail_arg_ofs; + // whether to dealloc the previous result + bool dealloc = true; + if(pt_len == 2) { reg_idx t1_reg=tail_regs[0]; reg_idx t2_reg=tail_regs[1]; @@ -488,8 +514,7 @@ namespace datalog { } } if(single_res==t_reg) { - //we may be modifying the register later, so we need a local copy - make_clone(t_reg, single_res, acc); + dealloc = false; } } @@ -500,7 +525,7 @@ namespace datalog { single_res=execution_context::void_register; } - add_unbound_columns_for_negation(r, head_pred, single_res, single_res_expr, acc); + add_unbound_columns_for_negation(r, head_pred, single_res, single_res_expr, dealloc, acc); int2ints var_indexes; @@ -515,7 +540,10 @@ namespace datalog { if(is_app(exp)) { SASSERT(m_context.get_decl_util().is_numeral_ext(exp)); relation_element value = to_app(exp); + if (!dealloc) + make_clone(filtered_res, filtered_res, acc); acc.push_back(instruction::mk_filter_equal(m_context.get_manager(), filtered_res, value, i)); + dealloc = true; } else { SASSERT(is_var(exp)); @@ -542,7 +570,10 @@ namespace datalog { //condition!) continue; } + if (!dealloc) + make_clone(filtered_res, filtered_res, acc); acc.push_back(instruction::mk_filter_identical(filtered_res, indexes.size(), indexes.c_ptr())); + dealloc = true; } //enforce negative predicates @@ -565,9 +596,12 @@ namespace datalog { relation_sort arg_sort; m_context.get_rel_context().get_rmanager().from_predicate(neg_pred, i, arg_sort); reg_idx new_reg; - make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, acc); + bool new_dealloc; + make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, new_dealloc, acc); - make_dealloc_non_void(filtered_res, acc); + if (dealloc) + make_dealloc_non_void(filtered_res, acc); + dealloc = new_dealloc; filtered_res = new_reg; // here filtered_res value gets changed !! t_cols.push_back(single_res_expr.size()); @@ -577,8 +611,11 @@ namespace datalog { SASSERT(t_cols.size()==neg_cols.size()); reg_idx neg_reg = m_pred_regs.find(neg_pred); + if (!dealloc) + make_clone(filtered_res, filtered_res, acc); acc.push_back(instruction::mk_filter_by_negation(filtered_res, neg_reg, t_cols.size(), t_cols.c_ptr(), neg_cols.c_ptr())); + dealloc = true; } //enforce interpreted tail predicates @@ -639,9 +676,12 @@ namespace datalog { reg_idx new_reg; TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";); - make_add_unbound_column(r, 0, head_pred, filtered_res, unbound_sort, new_reg, acc); + bool new_dealloc; + make_add_unbound_column(r, 0, head_pred, filtered_res, unbound_sort, new_reg, new_dealloc, acc); - make_dealloc_non_void(filtered_res, acc); + if (dealloc) + make_dealloc_non_void(filtered_res, acc); + dealloc = new_dealloc; filtered_res = new_reg; // here filtered_res value gets changed !! unsigned unbound_column_index = single_res_expr.size(); @@ -659,7 +699,10 @@ namespace datalog { expr_ref renamed(m); m_context.get_var_subst()(t, binding.size(), binding.c_ptr(), renamed); app_ref app_renamed(to_app(renamed), m); + if (!dealloc) + make_clone(filtered_res, filtered_res, acc); acc.push_back(instruction::mk_filter_interpreted(filtered_res, app_renamed)); + dealloc = true; } { @@ -704,11 +747,12 @@ namespace datalog { SASSERT(head_acis.size()==head_len); reg_idx new_head_reg; - make_assembling_code(r, head_pred, filtered_res, head_acis, new_head_reg, acc); + make_assembling_code(r, head_pred, filtered_res, head_acis, new_head_reg, dealloc, acc); //update the head relation make_union(new_head_reg, head_reg, delta_reg, use_widening, acc); - make_dealloc_non_void(new_head_reg, acc); + if (dealloc) + make_dealloc_non_void(new_head_reg, acc); } finish: @@ -716,7 +760,7 @@ namespace datalog { } void compiler::add_unbound_columns_for_negation(rule* r, func_decl* pred, reg_idx& single_res, ptr_vector& single_res_expr, - instruction_block & acc) { + bool & dealloc, instruction_block & acc) { uint_set pos_vars; u_map neg_vars; ast_manager& m = m_context.get_manager(); @@ -750,7 +794,13 @@ namespace datalog { expr* e = it->m_value; if (!pos_vars.contains(v)) { single_res_expr.push_back(e); - make_add_unbound_column(r, v, pred, single_res, m.get_sort(e), single_res, acc); + reg_idx new_single_res; + bool new_dealloc; + make_add_unbound_column(r, v, pred, single_res, m.get_sort(e), new_single_res, new_dealloc, acc); + if (dealloc) + make_dealloc_non_void(single_res, acc); + dealloc = new_dealloc; + single_res = new_single_res; TRACE("dl", tout << "Adding unbound column: " << mk_pp(e, m) << "\n";); } } diff --git a/src/muz_qe/dl_compiler.h b/src/muz_qe/dl_compiler.h index 92fe1d79b..1dfb7c7d8 100644 --- a/src/muz_qe/dl_compiler.h +++ b/src/muz_qe/dl_compiler.h @@ -114,6 +114,8 @@ namespace datalog { reg_idx m_new_reg; vector m_reg_signatures; obj_pair_map m_constant_registers; + obj_pair_map m_total_registers; + obj_map m_empty_tables_registers; instruction_observer m_instruction_observer; /** @@ -163,20 +165,20 @@ namespace datalog { with empty signature. */ void make_assembling_code(rule* compiled_rule, func_decl* head_pred, reg_idx src, const svector & acis0, - reg_idx & result, instruction_block & acc); + reg_idx & result, bool & dealloc, instruction_block & acc); void make_dealloc_non_void(reg_idx r, instruction_block & acc); void make_add_constant_column(func_decl* pred, reg_idx src, const relation_sort & s, const relation_element & val, - reg_idx & result, instruction_block & acc); + reg_idx & result, bool & dealloc, instruction_block & acc); void make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort & s, reg_idx & result, - instruction_block & acc); + bool & dealloc, instruction_block & acc); void make_full_relation(func_decl* pred, const relation_signature & sig, reg_idx & result, instruction_block & acc); void add_unbound_columns_for_negation(rule* compiled_rule, func_decl* pred, reg_idx& single_res, ptr_vector& single_res_expr, - instruction_block& acc); + bool & dealloc, instruction_block& acc); void make_duplicate_column(reg_idx src, unsigned col, reg_idx & result, instruction_block & acc); From 7ce88d4da9d985380bb3cb033a9e3113e8779703 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Sun, 21 Apr 2013 14:36:39 -0700 Subject: [PATCH 094/281] fix a few compilation warnings - remove unused variables and class fields - add support for gcc 4.5 & clang's __builtin_unreachable - fix 2 bugs related to strict aliasing - remove a few unused function parameters Signed-off-by: Nuno Lopes --- src/ast/ast.cpp | 2 +- src/ast/ast.h | 1 - src/ast/dl_decl_plugin.cpp | 1 + src/ast/float_decl_plugin.cpp | 1 + src/ast/func_decl_dependencies.cpp | 5 ++--- src/ast/macros/quasi_macros.cpp | 3 +-- src/ast/macros/quasi_macros.h | 3 +-- src/ast/recurse_expr.h | 2 +- src/ast/substitution/matcher.cpp | 4 ---- src/ast/substitution/matcher.h | 3 +-- src/ast/substitution/substitution.cpp | 2 +- src/math/subpaving/subpaving.cpp | 4 ---- src/muz_qe/dl_context.cpp | 1 - src/muz_qe/dl_interval_relation.cpp | 16 ++++++---------- src/muz_qe/dl_mk_bit_blast.cpp | 1 - src/muz_qe/dl_mk_explanations.cpp | 3 +-- src/muz_qe/dl_mk_karr_invariants.cpp | 7 ++----- src/muz_qe/dl_mk_subsumption_checker.cpp | 4 +--- src/muz_qe/dl_relation_manager.cpp | 4 +--- src/muz_qe/dl_relation_manager.h | 8 +++----- src/muz_qe/dl_util.h | 4 +--- src/muz_qe/nlarith_util.cpp | 1 - src/muz_qe/pdr_context.cpp | 2 +- src/muz_qe/pdr_farkas_learner.cpp | 5 ++--- src/muz_qe/qe.cpp | 5 +---- src/muz_qe/qe_dl_plugin.cpp | 2 -- src/muz_qe/tab_context.cpp | 4 ---- src/parsers/smt/smtparser.cpp | 8 +++----- src/parsers/smt2/smt2scanner.cpp | 1 - src/parsers/smt2/smt2scanner.h | 1 - src/smt/asserted_formulas.cpp | 2 +- src/smt/database.h | 2 +- src/smt/expr_context_simplifier.cpp | 2 +- src/smt/expr_context_simplifier.h | 2 -- src/smt/mam.cpp | 2 -- src/smt/theory_dl.cpp | 9 +++------ src/tactic/ufbv/quasi_macros_tactic.cpp | 2 +- src/tactic/ufbv/ufbv_rewriter.cpp | 14 ++++++-------- src/test/matcher.cpp | 2 +- src/util/bit_util.cpp | 14 +++++++++++++- src/util/debug.cpp | 4 ++-- src/util/debug.h | 11 +++++++++++ src/util/gparams.cpp | 4 ++-- src/util/hwf.h | 15 ++++++++++----- src/util/memory_manager.cpp | 16 ++++++++-------- src/util/warning.cpp | 10 +++++----- 46 files changed, 97 insertions(+), 122 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index fefb400ed..0555e5fc8 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -300,7 +300,7 @@ std::ostream & operator<<(std::ostream & out, func_decl_info const & info) { // // ----------------------------------- -char const * g_ast_kind_names[] = {"application", "variable", "quantifier", "sort", "function declaration" }; +static char const * g_ast_kind_names[] = {"application", "variable", "quantifier", "sort", "function declaration" }; char const * get_ast_kind_name(ast_kind k) { return g_ast_kind_names[k]; diff --git a/src/ast/ast.h b/src/ast/ast.h index 4c924691c..ef4ab3b55 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1193,7 +1193,6 @@ enum pattern_op_kind { heurisitic quantifier instantiation. */ class pattern_decl_plugin : public decl_plugin { - sort * m_list; public: virtual decl_plugin * mk_fresh() { return alloc(pattern_decl_plugin); } diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index d8e2385ec..4f0c9a75d 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -326,6 +326,7 @@ namespace datalog { } unsigned index0; sort* last_sort = 0; + SASSERT(num_params > 0); for (unsigned i = 0; i < num_params; ++i) { parameter const& p = params[i]; if (!p.is_int()) { diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 26131bc28..2a090fc39 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -200,6 +200,7 @@ func_decl * float_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_par } else { m_manager->raise_exception("sort of floating point constant was not specified"); + UNREACHABLE(); } SASSERT(is_sort_of(s, m_family_id, FLOAT_SORT)); diff --git a/src/ast/func_decl_dependencies.cpp b/src/ast/func_decl_dependencies.cpp index 5e054d5d9..162efb0dd 100644 --- a/src/ast/func_decl_dependencies.cpp +++ b/src/ast/func_decl_dependencies.cpp @@ -79,7 +79,6 @@ void func_decl_dependencies::collect_ng_func_decls(expr * n, func_decl_set * s) */ class func_decl_dependencies::top_sort { enum color { OPEN, IN_PROGRESS, CLOSED }; - ast_manager & m_manager; dependency_graph & m_deps; typedef obj_map color_map; @@ -177,7 +176,7 @@ class func_decl_dependencies::top_sort { } public: - top_sort(ast_manager & m, dependency_graph & deps):m_manager(m), m_deps(deps) {} + top_sort(dependency_graph & deps) : m_deps(deps) {} bool operator()(func_decl * new_decl) { @@ -198,7 +197,7 @@ bool func_decl_dependencies::insert(func_decl * f, func_decl_set * s) { m_deps.insert(f, s); - top_sort cycle_detector(m_manager, m_deps); + top_sort cycle_detector(m_deps); if (cycle_detector(f)) { m_deps.erase(f); dealloc(s); diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index 1b0f0b621..084a33ebf 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -22,10 +22,9 @@ Revision History: #include"uint_set.h" #include"var_subst.h" -quasi_macros::quasi_macros(ast_manager & m, macro_manager & mm, basic_simplifier_plugin & p, simplifier & s) : +quasi_macros::quasi_macros(ast_manager & m, macro_manager & mm, simplifier & s) : m_manager(m), m_macro_manager(mm), - m_bsimp(p), m_simplifier(s), m_new_vars(m), m_new_eqs(m), diff --git a/src/ast/macros/quasi_macros.h b/src/ast/macros/quasi_macros.h index 1731774b2..c5e6b6d4f 100644 --- a/src/ast/macros/quasi_macros.h +++ b/src/ast/macros/quasi_macros.h @@ -32,7 +32,6 @@ class quasi_macros { ast_manager & m_manager; macro_manager & m_macro_manager; - basic_simplifier_plugin & m_bsimp; simplifier & m_simplifier; occurrences_map m_occurrences; ptr_vector m_todo; @@ -57,7 +56,7 @@ class quasi_macros { void apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); public: - quasi_macros(ast_manager & m, macro_manager & mm, basic_simplifier_plugin & p, simplifier & s); + quasi_macros(ast_manager & m, macro_manager & mm, simplifier & s); ~quasi_macros(); /** diff --git a/src/ast/recurse_expr.h b/src/ast/recurse_expr.h index 9cb71872b..6b3220d40 100644 --- a/src/ast/recurse_expr.h +++ b/src/ast/recurse_expr.h @@ -30,7 +30,7 @@ class recurse_expr : public Visitor { vector m_results2; bool is_cached(expr * n) const { T c; return m_cache.find(n, c); } - T get_cached(expr * n) const { T c; m_cache.find(n, c); return c; } + T get_cached(expr * n) const { return m_cache.find(n); } void cache_result(expr * n, T c) { m_cache.insert(n, c); } void visit(expr * n, bool & visited); diff --git a/src/ast/substitution/matcher.cpp b/src/ast/substitution/matcher.cpp index a5560c6a2..ce9bdcb3e 100644 --- a/src/ast/substitution/matcher.cpp +++ b/src/ast/substitution/matcher.cpp @@ -18,10 +18,6 @@ Revision History: --*/ #include"matcher.h" -matcher::matcher(ast_manager & m): - m_manager(m) { -} - bool matcher::operator()(expr * e1, expr * e2, substitution & s) { reset(); m_subst = &s; diff --git a/src/ast/substitution/matcher.h b/src/ast/substitution/matcher.h index 1a71a51ed..84a62e874 100644 --- a/src/ast/substitution/matcher.h +++ b/src/ast/substitution/matcher.h @@ -30,7 +30,6 @@ class matcher { typedef pair_hash, obj_ptr_hash > expr_pair_hash; typedef hashtable > cache; - ast_manager & m_manager; substitution * m_subst; // cache m_cache; svector m_todo; @@ -38,7 +37,7 @@ class matcher { void reset(); public: - matcher(ast_manager & m); + matcher() {} /** \brief Return true if e2 is an instance of e1. diff --git a/src/ast/substitution/substitution.cpp b/src/ast/substitution/substitution.cpp index 11bca0133..be293c5a8 100644 --- a/src/ast/substitution/substitution.cpp +++ b/src/ast/substitution/substitution.cpp @@ -148,7 +148,7 @@ void substitution::apply(unsigned num_actual_offsets, unsigned const * deltas, e expr * arg = to_app(e)->get_arg(i); expr * new_arg; - m_apply_cache.find(expr_offset(arg, off), new_arg); + VERIFY(m_apply_cache.find(expr_offset(arg, off), new_arg)); new_args.push_back(new_arg); if (arg != new_arg) has_new_args = true; diff --git a/src/math/subpaving/subpaving.cpp b/src/math/subpaving/subpaving.cpp index 0bbabc683..ad0819ad8 100644 --- a/src/math/subpaving/subpaving.cpp +++ b/src/math/subpaving/subpaving.cpp @@ -85,7 +85,6 @@ namespace subpaving { }; class context_mpf_wrapper : public context_wrapper { - f2n & m_fm; unsynch_mpq_manager & m_qm; scoped_mpf m_c; scoped_mpf_vector m_as; @@ -103,7 +102,6 @@ namespace subpaving { public: context_mpf_wrapper(f2n & fm, params_ref const & p, small_object_allocator * a): context_wrapper(fm, p, a), - m_fm(fm), m_qm(fm.m().mpq_manager()), m_c(fm.m()), m_as(fm.m()), @@ -145,7 +143,6 @@ namespace subpaving { }; class context_hwf_wrapper : public context_wrapper { - f2n & m_fm; unsynch_mpq_manager & m_qm; hwf m_c; svector m_as; @@ -166,7 +163,6 @@ namespace subpaving { public: context_hwf_wrapper(f2n & fm, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a): context_wrapper(fm, p, a), - m_fm(fm), m_qm(qm) { } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 73ddd22e5..df293aeba 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -647,7 +647,6 @@ namespace datalog { } } ast_manager& m = get_manager(); - datalog::rule_manager& rm = get_rule_manager(); contains_pred contains_p(*this); check_pred check_pred(contains_p, get_manager()); diff --git a/src/muz_qe/dl_interval_relation.cpp b/src/muz_qe/dl_interval_relation.cpp index 3397f2db0..4c8171bc7 100644 --- a/src/muz_qe/dl_interval_relation.cpp +++ b/src/muz_qe/dl_interval_relation.cpp @@ -99,11 +99,9 @@ namespace datalog { } class interval_relation_plugin::rename_fn : public convenient_relation_rename_fn { - interval_relation_plugin& m_plugin; public: - rename_fn(interval_relation_plugin& p, const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) - : convenient_relation_rename_fn(orig_sig, cycle_len, cycle), - m_plugin(p){ + rename_fn(const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) { } virtual relation_base * operator()(const relation_base & _r) { @@ -120,7 +118,7 @@ namespace datalog { if(!check_kind(r)) { return 0; } - return alloc(rename_fn, *this, r.get_signature(), cycle_len, permutation_cycle); + return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle); } interval interval_relation_plugin::unite(interval const& src1, interval const& src2) { @@ -194,11 +192,9 @@ namespace datalog { } class interval_relation_plugin::union_fn : public relation_union_fn { - interval_relation_plugin& m_plugin; bool m_is_widen; public: - union_fn(interval_relation_plugin& p, bool is_widen) : - m_plugin(p), + union_fn(bool is_widen) : m_is_widen(is_widen) { } @@ -223,7 +219,7 @@ namespace datalog { if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { return 0; } - return alloc(union_fn, *this, false); + return alloc(union_fn, false); } relation_union_fn * interval_relation_plugin::mk_widen_fn( @@ -232,7 +228,7 @@ namespace datalog { if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { return 0; } - return alloc(union_fn, *this, true); + return alloc(union_fn, true); } class interval_relation_plugin::filter_identical_fn : public relation_mutator_fn { diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 3f92bbce8..51a9d5927 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -141,7 +141,6 @@ namespace datalog { func_decl_ref_vector const& new_funcs() const { return m_new_funcs; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - rule_manager& rm = m_context.get_rule_manager(); bool found = false; for (unsigned j = 0; !found && j < num; ++j) { found = m_util.is_mkbv(args[j]); diff --git a/src/muz_qe/dl_mk_explanations.cpp b/src/muz_qe/dl_mk_explanations.cpp index bf3548a7a..004b1823d 100644 --- a/src/muz_qe/dl_mk_explanations.cpp +++ b/src/muz_qe/dl_mk_explanations.cpp @@ -527,11 +527,10 @@ namespace datalog { } class explanation_relation_plugin::intersection_filter_fn : public relation_intersection_filter_fn { - explanation_relation_plugin & m_plugin; func_decl_ref m_union_decl; public: intersection_filter_fn(explanation_relation_plugin & plugin) - : m_plugin(plugin), m_union_decl(plugin.m_union_decl) {} + : m_union_decl(plugin.m_union_decl) {} virtual void operator()(relation_base & tgt0, const relation_base & src0) { explanation_relation & tgt = static_cast(tgt0); diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index c8e350eeb..9109f1bda 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -938,11 +938,8 @@ namespace datalog { class karr_relation_plugin::union_fn : public relation_union_fn { - karr_relation_plugin& m_plugin; public: - union_fn(karr_relation_plugin& p) : - m_plugin(p) { - } + union_fn() {} virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { @@ -966,7 +963,7 @@ namespace datalog { if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { return 0; } - return alloc(union_fn, *this); + return alloc(union_fn); } class karr_relation_plugin::filter_identical_fn : public relation_mutator_fn { diff --git a/src/muz_qe/dl_mk_subsumption_checker.cpp b/src/muz_qe/dl_mk_subsumption_checker.cpp index f50bd104c..0e94ba3b9 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.cpp +++ b/src/muz_qe/dl_mk_subsumption_checker.cpp @@ -320,9 +320,7 @@ namespace datalog { if(!m_ground_unconditional_rule_heads.contains(pred)) { m_ground_unconditional_rule_heads.insert(pred, alloc(obj_hashtable)); } - obj_hashtable * head_store; - m_ground_unconditional_rule_heads.find(pred, head_store); - head_store->insert(head); + m_ground_unconditional_rule_heads.find(pred)->insert(head); next_rule:; } diff --git a/src/muz_qe/dl_relation_manager.cpp b/src/muz_qe/dl_relation_manager.cpp index d92ae7dcc..ef8e6ddd4 100644 --- a/src/muz_qe/dl_relation_manager.cpp +++ b/src/muz_qe/dl_relation_manager.cpp @@ -1090,12 +1090,10 @@ namespace datalog { class relation_manager::default_table_rename_fn : public convenient_table_rename_fn, auxiliary_table_transformer_fn { - const unsigned m_cycle_len; public: default_table_rename_fn(const table_signature & orig_sig, unsigned permutation_cycle_len, const unsigned * permutation_cycle) - : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle), - m_cycle_len(permutation_cycle_len) { + : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle) { SASSERT(permutation_cycle_len>=2); } diff --git a/src/muz_qe/dl_relation_manager.h b/src/muz_qe/dl_relation_manager.h index 8715e5cff..26008a830 100644 --- a/src/muz_qe/dl_relation_manager.h +++ b/src/muz_qe/dl_relation_manager.h @@ -661,17 +661,15 @@ namespace datalog { SASSERT(res_idxinsert(m_allocated_kinds[res_idx], spec); } return m_allocated_kinds[res_idx]; } void get_relation_spec(const relation_signature & sig, family_id kind, Spec & spec) { - family_id2spec * idspecs; - VERIFY( m_kind_specs.find(sig, idspecs) ); - VERIFY( idspecs->find(kind, spec) ); + family_id2spec * idspecs = m_kind_specs.find(sig); + spec = idspecs->find(kind); } }; diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index c3644cd74..974ab5862 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -198,8 +198,6 @@ namespace datalog { { bool values_match(const expr * v1, const expr * v2); - ast_manager & m_manager; - unsigned_vector m_args1; unsigned_vector m_args2; @@ -211,7 +209,7 @@ namespace datalog { static unsigned expr_cont_get_size(const ptr_vector & v) { return v.size(); } static expr * expr_cont_get(const ptr_vector & v, unsigned i) { return v[i]; } public: - variable_intersection(ast_manager & m) : m_manager(m), m_consts(m) {} + variable_intersection(ast_manager & m) : m_consts(m) {} unsigned size() const { return m_args1.size(); diff --git a/src/muz_qe/nlarith_util.cpp b/src/muz_qe/nlarith_util.cpp index 5f8a24e99..c555b71f1 100644 --- a/src/muz_qe/nlarith_util.cpp +++ b/src/muz_qe/nlarith_util.cpp @@ -1028,7 +1028,6 @@ namespace nlarith { }; class sqrt_subst : public isubst { - bool m_even; sqrt_form const& m_s; public: sqrt_subst(imp& i, sqrt_form const& s): isubst(i), m_s(s) {} diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index d4027d73d..a240a9aef 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1285,7 +1285,7 @@ namespace pdr { obj_hashtable::iterator itf = deps.begin(), endf = deps.end(); for (; itf != endf; ++itf) { TRACE("pdr", tout << mk_pp(pred, m) << " " << mk_pp(*itf, m) << "\n";); - VERIFY (rels.find(*itf, pt_user)); + pt_user = rels.find(*itf); pt_user->add_use(pt); } } diff --git a/src/muz_qe/pdr_farkas_learner.cpp b/src/muz_qe/pdr_farkas_learner.cpp index 489b2437e..393090299 100644 --- a/src/muz_qe/pdr_farkas_learner.cpp +++ b/src/muz_qe/pdr_farkas_learner.cpp @@ -418,11 +418,10 @@ namespace pdr { class farkas_learner::constant_replacer_cfg : public default_rewriter_cfg { - ast_manager& m; const obj_map& m_translation; public: - constant_replacer_cfg(ast_manager& m, const obj_map& translation) - : m(m), m_translation(translation) + constant_replacer_cfg(const obj_map& translation) + : m_translation(translation) { } bool get_subst(expr * s, expr * & t, proof * & t_pr) { diff --git a/src/muz_qe/qe.cpp b/src/muz_qe/qe.cpp index bb65f8bf8..894a935b5 100644 --- a/src/muz_qe/qe.cpp +++ b/src/muz_qe/qe.cpp @@ -1093,8 +1093,7 @@ namespace qe { bool has_branch(rational const& branch_id) const { return m_branch_index.contains(branch_id); } search_tree* child(rational const& branch_id) const { - unsigned idx; - VERIFY(m_branch_index.find(branch_id, idx)); + unsigned idx = m_branch_index.find(branch_id); return m_children[idx]; } @@ -1963,7 +1962,6 @@ namespace qe { expr_ref m_assumption; bool m_produce_models; ptr_vector m_plugins; - unsigned m_name_counter; // fresh-id volatile bool m_cancel; bool m_eliminate_variables_as_block; @@ -1973,7 +1971,6 @@ namespace qe { m_fparams(p), m_assumption(m), m_produce_models(m_fparams.m_model), - m_name_counter(0), m_cancel(false), m_eliminate_variables_as_block(true) { diff --git a/src/muz_qe/qe_dl_plugin.cpp b/src/muz_qe/qe_dl_plugin.cpp index 15e972e88..61466795b 100644 --- a/src/muz_qe/qe_dl_plugin.cpp +++ b/src/muz_qe/qe_dl_plugin.cpp @@ -12,14 +12,12 @@ namespace qe { // dl_plugin class eq_atoms { - ast_manager& m; expr_ref_vector m_eqs; expr_ref_vector m_neqs; app_ref_vector m_eq_atoms; app_ref_vector m_neq_atoms; public: eq_atoms(ast_manager& m): - m(m), m_eqs(m), m_neqs(m), m_eq_atoms(m), diff --git a/src/muz_qe/tab_context.cpp b/src/muz_qe/tab_context.cpp index 44d9d94e2..653f5f188 100644 --- a/src/muz_qe/tab_context.cpp +++ b/src/muz_qe/tab_context.cpp @@ -740,7 +740,6 @@ namespace tb { typedef svector double_vector; typedef obj_map score_map; typedef obj_map pred_map; - datalog::context& m_ctx; ast_manager& m; datatype_util dt; score_map m_score_map; @@ -750,19 +749,16 @@ namespace tb { pred_map m_pred_map; expr_ref_vector m_refs; double m_weight_multiply; - unsigned m_num_invocations; unsigned m_update_frequency; unsigned m_next_update; public: selection(datalog::context& ctx): - m_ctx(ctx), m(ctx.get_manager()), dt(m), m_refs(m), m_weight_multiply(1.0), - m_num_invocations(0), m_update_frequency(20), m_next_update(20) { set_strategy(ctx.get_params().tab_selection()); diff --git a/src/parsers/smt/smtparser.cpp b/src/parsers/smt/smtparser.cpp index b6b40c01a..d26190541 100644 --- a/src/parsers/smt/smtparser.cpp +++ b/src/parsers/smt/smtparser.cpp @@ -1472,7 +1472,7 @@ private: SASSERT(sorts.size() > 0); - idbuilder* pop_q = new (region) pop_quantifier(this, (head_symbol == m_forall), weight, qid, skid, patterns, no_patterns, sorts, vars, local_scope, current); + idbuilder* pop_q = new (region) pop_quantifier(this, (head_symbol == m_forall), weight, qid, skid, patterns, no_patterns, sorts, vars, local_scope); expr_ref_vector * empty_v = alloc(expr_ref_vector, m_manager); up.push_back(new (region) parse_frame(current, pop_q, empty_v, 0, m_binding_level)); @@ -2522,7 +2522,7 @@ private: class pop_quantifier : public idbuilder { public: pop_quantifier(smtparser * smt, bool is_forall, int weight, symbol const& qid, symbol const& skid, expr_ref_buffer & patterns, expr_ref_buffer & no_patterns, sort_ref_buffer & sorts, - svector& vars, symbol_table & local_scope, proto_expr* p_expr): + svector& vars, symbol_table & local_scope): m_smt(smt), m_is_forall(is_forall), m_weight(weight), @@ -2531,8 +2531,7 @@ private: m_patterns(m_smt->m_manager), m_no_patterns(m_smt->m_manager), m_sorts(m_smt->m_manager), - m_local_scope(local_scope), - m_p_expr(p_expr) { + m_local_scope(local_scope) { SASSERT(sorts.size() == vars.size()); m_vars.append(vars); @@ -2619,7 +2618,6 @@ private: sort_ref_buffer m_sorts; svector m_vars; symbol_table& m_local_scope; - proto_expr* m_p_expr; }; class builtin_builder : public idbuilder { diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp index 0f6101a93..f653cbb25 100644 --- a/src/parsers/smt2/smt2scanner.cpp +++ b/src/parsers/smt2/smt2scanner.cpp @@ -243,7 +243,6 @@ namespace smt2 { } scanner::scanner(cmd_context & ctx, std::istream& stream, bool interactive): - m_ctx(ctx), m_interactive(interactive), m_spos(0), m_curr(0), // avoid Valgrind warning diff --git a/src/parsers/smt2/smt2scanner.h b/src/parsers/smt2/smt2scanner.h index 7b74c752f..631c71f17 100644 --- a/src/parsers/smt2/smt2scanner.h +++ b/src/parsers/smt2/smt2scanner.h @@ -31,7 +31,6 @@ namespace smt2 { class scanner { private: - cmd_context & m_ctx; bool m_interactive; int m_spos; // position in the current line of the stream char m_curr; // current char; diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index c5d3c08cf..4775e44a4 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -408,7 +408,7 @@ void asserted_formulas::apply_quasi_macros() { TRACE("before_quasi_macros", display(tout);); expr_ref_vector new_exprs(m_manager); proof_ref_vector new_prs(m_manager); - quasi_macros proc(m_manager, m_macro_manager, *m_bsimp, m_simplifier); + quasi_macros proc(m_manager, m_macro_manager, m_simplifier); while (proc(m_asserted_formulas.size() - m_asserted_qhead, m_asserted_formulas.c_ptr() + m_asserted_qhead, m_asserted_formula_prs.c_ptr() + m_asserted_qhead, diff --git a/src/smt/database.h b/src/smt/database.h index 2e71cbae4..1975fe3c3 100644 --- a/src/smt/database.h +++ b/src/smt/database.h @@ -1,4 +1,4 @@ -char const * g_pattern_database = +static char const * g_pattern_database = "(benchmark patterns \n" " :status unknown \n" " :logic ALL \n" diff --git a/src/smt/expr_context_simplifier.cpp b/src/smt/expr_context_simplifier.cpp index b23bb3bdc..66252c3cf 100644 --- a/src/smt/expr_context_simplifier.cpp +++ b/src/smt/expr_context_simplifier.cpp @@ -311,7 +311,7 @@ bool expr_context_simplifier::is_false(expr* e) const { // expr_strong_context_simplifier::expr_strong_context_simplifier(smt_params& p, ast_manager& m): - m_manager(m), m_params(p), m_arith(m), m_id(0), m_fn(0,m), m_solver(m, p) { + m_manager(m), m_arith(m), m_fn(0,m), m_solver(m, p) { sort* i_sort = m_arith.mk_int(); m_fn = m.mk_func_decl(symbol(0xbeef101), i_sort, m.mk_bool_sort()); } diff --git a/src/smt/expr_context_simplifier.h b/src/smt/expr_context_simplifier.h index 982b65878..a1d01b78c 100644 --- a/src/smt/expr_context_simplifier.h +++ b/src/smt/expr_context_simplifier.h @@ -57,9 +57,7 @@ private: class expr_strong_context_simplifier { ast_manager& m_manager; - smt_params & m_params; arith_util m_arith; - unsigned m_id; func_decl_ref m_fn; smt::kernel m_solver; diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index c9d6ead88..d92eef5b8 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -1849,11 +1849,9 @@ namespace smt { unsigned m_curr_max_generation; // temporary var used to store a copy of m_max_generation unsigned m_num_args; unsigned m_oreg; - unsigned m_ireg; enode * m_n1; enode * m_n2; enode * m_app; - instruction * m_alt; const bind * m_b; ptr_vector m_used_enodes; unsigned m_curr_used_enodes_size; diff --git a/src/smt/theory_dl.cpp b/src/smt/theory_dl.cpp index 758f78c2c..9c3489aec 100644 --- a/src/smt/theory_dl.cpp +++ b/src/smt/theory_dl.cpp @@ -68,14 +68,11 @@ namespace smt { bv_util& b() { return m_bv; } class dl_value_proc : public smt::model_value_proc { - smt::model_generator & m_mg; theory_dl& m_th; smt::enode* m_node; public: - dl_value_proc(smt::model_generator & m, theory_dl& th, smt::enode* n): - m_mg(m), m_th(th), m_node(n) - { } + dl_value_proc(theory_dl& th, smt::enode* n) : m_th(th), m_node(n) {} virtual void get_dependencies(buffer & result) {} @@ -165,8 +162,8 @@ namespace smt { m.register_factory(alloc(dl_factory, m_util, m.get_model())); } - virtual smt::model_value_proc * mk_value(smt::enode * n, smt::model_generator & m) { - return alloc(dl_value_proc, m, *this, n); + virtual smt::model_value_proc * mk_value(smt::enode * n) { + return alloc(dl_value_proc, *this, n); } virtual void apply_sort_cnstr(enode * n, sort * s) { diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index d7e55379a..393a40603 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -67,7 +67,7 @@ class quasi_macros_tactic : public tactic { simp.register_plugin(bvsimp); macro_manager mm(m_manager, simp); - quasi_macros qm(m_manager, mm, *bsimp, simp); + quasi_macros qm(m_manager, mm, simp); bool more = true; expr_ref_vector forms(m_manager), new_forms(m_manager); diff --git a/src/tactic/ufbv/ufbv_rewriter.cpp b/src/tactic/ufbv/ufbv_rewriter.cpp index e4ed2ec01..40fdf5e3e 100644 --- a/src/tactic/ufbv/ufbv_rewriter.cpp +++ b/src/tactic/ufbv/ufbv_rewriter.cpp @@ -442,11 +442,10 @@ expr * ufbv_rewriter::rewrite(expr * n) { } class ufbv_rewriter::add_back_idx_proc { - ast_manager & m_manager; back_idx_map & m_back_idx; expr * m_expr; public: - add_back_idx_proc(ast_manager & m, back_idx_map & bi, expr * e):m_manager(m),m_back_idx(bi),m_expr(e) {} + add_back_idx_proc(back_idx_map & bi, expr * e):m_back_idx(bi),m_expr(e) {} void operator()(var * n) {} void operator()(quantifier * n) {} void operator()(app * n) { @@ -469,11 +468,10 @@ public: }; class ufbv_rewriter::remove_back_idx_proc { - ast_manager & m_manager; back_idx_map & m_back_idx; expr * m_expr; public: - remove_back_idx_proc(ast_manager & m, back_idx_map & bi, expr * e):m_manager(m),m_back_idx(bi),m_expr(e) {} + remove_back_idx_proc(back_idx_map & bi, expr * e):m_back_idx(bi),m_expr(e) {} void operator()(var * n) {} void operator()(quantifier * n) {} void operator()(app * n) { @@ -511,7 +509,7 @@ void ufbv_rewriter::reschedule_processed(func_decl * f) { expr * p = *sit; // remove p from m_processed and m_back_idx m_processed.remove(p); - remove_back_idx_proc proc(m_manager, m_back_idx, p); // this could change it->m_value, thus we need the `temp' set. + remove_back_idx_proc proc(m_back_idx, p); // this could change it->m_value, thus we need the `temp' set. for_each_expr(proc, p); // insert p into m_todo m_todo.push_back(p); @@ -619,7 +617,7 @@ void ufbv_rewriter::reschedule_demodulators(func_decl * f, expr * lhs) { // remove d from m_back_idx // just remember it here, because otherwise it and/or esit might become invalid? // to_remove.insert(d); - remove_back_idx_proc proc(m_manager, m_back_idx, d); + remove_back_idx_proc proc(m_back_idx, d); for_each_expr(proc, d); // insert d into m_todo m_todo.push_back(d); @@ -674,7 +672,7 @@ void ufbv_rewriter::operator()(unsigned n, expr * const * exprs, proof * const * // insert n' into m_processed m_processed.insert(np); // update m_back_idx (traverse n' and for each uninterpreted function declaration f in n' add the entry f->n' to m_back_idx) - add_back_idx_proc proc(m_manager, m_back_idx, np); + add_back_idx_proc proc(m_back_idx, np); for_each_expr(proc, np); } else { // np is a demodulator that allows us to replace 'large' with 'small'. @@ -702,7 +700,7 @@ void ufbv_rewriter::operator()(unsigned n, expr * const * exprs, proof * const * insert_fwd_idx(large, small, to_quantifier(np)); // update m_back_idx - add_back_idx_proc proc(m_manager, m_back_idx, np); + add_back_idx_proc proc(m_back_idx, np); for_each_expr(proc, np); } } diff --git a/src/test/matcher.cpp b/src/test/matcher.cpp index 05d971e24..598a82ae3 100644 --- a/src/test/matcher.cpp +++ b/src/test/matcher.cpp @@ -26,7 +26,7 @@ void tst_match(ast_manager & m, app * t, app * i) { substitution s(m); s.reserve(2, 10); // reserving a big number of variables to be safe. - matcher match(m); + matcher match; std::cout << "Is " << mk_pp(i, m) << " an instance of " << mk_pp(t, m) << "\n"; if (match(t, i, s)) { std::cout << "yes\n"; diff --git a/src/util/bit_util.cpp b/src/util/bit_util.cpp index 32861f754..0f1fd294d 100644 --- a/src/util/bit_util.cpp +++ b/src/util/bit_util.cpp @@ -19,6 +19,7 @@ Revision History: #include"bit_util.h" #include"util.h" #include"debug.h" +#include /** \brief (Debugging version) Return the position of the most significant (set) bit of a @@ -67,7 +68,11 @@ unsigned msb_pos(unsigned v) { */ unsigned nlz_core(unsigned x) { SASSERT(x != 0); +#ifdef __GNUC__ + return __builtin_clz(x); +#else return 31 - msb_pos(x); +#endif } /** @@ -92,8 +97,15 @@ unsigned nlz(unsigned sz, unsigned const * data) { */ unsigned ntz_core(unsigned x) { SASSERT(x != 0); +#ifdef __GNUC__ + return __builtin_ctz(x); +#else float f = static_cast(x & static_cast(-static_cast(x))); - return (*reinterpret_cast(&f) >> 23) - 0x7f; + unsigned u; + SASSERT(sizeof(u) == sizeof(f)); + memcpy(&u, &f, sizeof(u)); + return (u >> 23) - 0x7f; +#endif } /** diff --git a/src/util/debug.cpp b/src/util/debug.cpp index 75ea8586a..c336ddb73 100644 --- a/src/util/debug.cpp +++ b/src/util/debug.cpp @@ -24,7 +24,7 @@ Revision History: #include"str_hashtable.h" #include"z3_exception.h" -volatile bool g_enable_assertions = true; +static volatile bool g_enable_assertions = true; void enable_assertions(bool f) { g_enable_assertions = f; @@ -41,7 +41,7 @@ void notify_assertion_violation(const char * fileName, int line, const char * co std::cerr << condition << "\n"; } -str_hashtable* g_enabled_debug_tags = 0; +static str_hashtable* g_enabled_debug_tags = 0; static void init_debug_table() { if (!g_enabled_debug_tags) { diff --git a/src/util/debug.h b/src/util/debug.h index c45ee5aa6..9e519982f 100644 --- a/src/util/debug.h +++ b/src/util/debug.h @@ -29,6 +29,10 @@ bool assertions_enabled(); #include #endif +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + #include"error_codes.h" #include"warning.h" @@ -53,7 +57,14 @@ bool is_debug_enabled(const char * tag); #define SASSERT(COND) DEBUG_CODE(if (assertions_enabled() && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); INVOKE_DEBUGGER(); }) #define CASSERT(TAG, COND) DEBUG_CODE(if (assertions_enabled() && is_debug_enabled(TAG) && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); INVOKE_DEBUGGER(); }) #define XASSERT(COND, EXTRA_CODE) DEBUG_CODE(if (assertions_enabled() && !(COND)) { notify_assertion_violation(__FILE__, __LINE__, #COND); { EXTRA_CODE } INVOKE_DEBUGGER(); }) + +#if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 405)) || __has_builtin(__builtin_unreachable) +// only available in gcc >= 4.5 and in newer versions of clang +# define UNREACHABLE() __builtin_unreachable() +#else #define UNREACHABLE() DEBUG_CODE(notify_assertion_violation(__FILE__, __LINE__, "UNREACHABLE CODE WAS REACHED."); INVOKE_DEBUGGER();) +#endif + #define NOT_IMPLEMENTED_YET() { std::cerr << "NOT IMPLEMENTED YET!\n"; UNREACHABLE(); exit(ERR_NOT_IMPLEMENTED_YET); } ((void) 0) #ifdef Z3DEBUG diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 3b2e8edc1..1d9426390 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -22,7 +22,7 @@ Notes: extern void gparams_register_modules(); -char const * g_old_params_names[] = { +static char const * g_old_params_names[] = { "arith_adaptive","arith_adaptive_assertion_threshold","arith_adaptive_gcd","arith_adaptive_propagation_threshold","arith_add_binary_bounds","arith_blands_rule_threshold","arith_branch_cut_ratio","arith_dump_lemmas","arith_eager_eq_axioms","arith_eager_gcd","arith_eq_bounds","arith_euclidean_solver","arith_expand_eqs","arith_force_simplex","arith_gcd_test","arith_ignore_int","arith_lazy_adapter","arith_lazy_pivoting","arith_max_lemma_size","arith_process_all_eqs","arith_propagate_eqs","arith_propagation_mode","arith_propagation_threshold","arith_prop_strategy","arith_random_initial_value","arith_random_lower","arith_random_seed","arith_random_upper","arith_reflect","arith_skip_big_coeffs","arith_small_lemma_size","arith_solver","arith_stronger_lemmas","array_always_prop_upward","array_canonize","array_cg","array_delay_exp_axiom","array_extensional","array_laziness","array_lazy_ieq","array_lazy_ieq_delay","array_solver","array_weak","async_commands","at_labels_cex","auto_config","bb_eager","bb_ext_gates","bb_quantifiers","bin_clauses","bit2int","bv2int_distribute","bv_blast_max_size","bv_cc","bv_enable_int2bv_propagation","bv_lazy_le","bv_max_sharing","bv_reflect","bv_solver","case_split","check_at_labels","check_proof","cnf_factor","cnf_mode","context_simplifier","dack","dack_eq","dack_factor","dack_gc","dack_gc_inv_decay","dack_threshold","default_qid","default_table","default_table_checked","delay_units","delay_units_threshold","der","display_config","display_dot_proof","display_error_for_visual_studio","display_features","display_proof","display_unsat_core","distribute_forall","dt_lazy_splits","dump_goal_as_smt","elim_and","elim_bounds","elim_nlarith_quantifiers","elim_quantifiers","elim_term_ite","ematching","engine","eq_propagation","hi_div0","ignore_bad_patterns","ignore_setparameter","instruction_max","inst_gen","interactive","internalizer_nnf","lemma_gc_factor","lemma_gc_half","lemma_gc_initial","lemma_gc_new_clause_activity","lemma_gc_new_clause_relevancy","lemma_gc_new_old_ratio","lemma_gc_old_clause_activity","lemma_gc_old_clause_relevancy","lemma_gc_strategy","lift_ite","lookahead_diseq","macro_finder","max_conflicts","max_counterexamples","mbqi","mbqi_force_template","mbqi_max_cexs","mbqi_max_cexs_incr","mbqi_max_iterations","mbqi_trace","minimize_lemmas","model","model_compact","model_completion","model_display_arg_sort","model_hide_unused_partitions","model_on_final_check","model_on_timeout","model_partial","model_v1","model_v2","model_validate","new_core2th_eq","ng_lift_ite","nl_arith","nl_arith_branching","nl_arith_gb","nl_arith_gb_eqs","nl_arith_gb_perturbate","nl_arith_gb_threshold","nl_arith_max_degree","nl_arith_rounds","nnf_factor","nnf_ignore_labels","nnf_mode","nnf_sk_hack","order","order_var_weight","order_weights","phase_selection","pi_arith","pi_arith_weight","pi_avoid_skolems","pi_block_looop_patterns","pi_max_multi_patterns","pi_non_nested_arith_weight","pi_nopat_weight","pi_pull_quantifiers","pi_use_database","pi_warnings","pp_bounded","pp_bv_literals","pp_bv_neg","pp_decimal","pp_decimal_precision","pp_fixed_indent","pp_flat_assoc","pp_max_depth","pp_max_indent","pp_max_num_lines","pp_max_ribbon","pp_max_width","pp_min_alias_size","pp_simplify_implies","pp_single_line","precedence","precedence_gen","pre_demodulator","pre_simplifier","pre_simplify_expr","profile_res_sub","progress_sampling_freq","proof_mode","propagate_booleans","propagate_values","pull_cheap_ite_trees","pull_nested_quantifiers","qi_conservative_final_check","qi_cost","qi_eager_threshold","qi_lazy_instantiation","qi_lazy_quick_checker","qi_lazy_threshold","qi_max_eager_multi_patterns","qi_max_instances","qi_max_lazy_multi_pattern_matching","qi_new_gen","qi_profile","qi_profile_freq","qi_promote_unsat","qi_quick_checker","quasi_macros","random_case_split_freq","random_initial_activity","random_seed","recent_lemma_threshold","reduce_args","refine_inj_axiom","relevancy","relevancy_lemma","rel_case_split_order","restart_adaptive","restart_agility_threshold","restart_factor","restart_initial","restart_strategy","restricted_quasi_macros","simplify_clauses","smtlib2_compliant","smtlib_category","smtlib_dump_lemmas","smtlib_logic","smtlib_source_info","smtlib_trace_path","soft_timeout","solver","spc_bs","spc_es","spc_factor_subsumption_index_opt","spc_initial_subsumption_index_opt","spc_max_subsumption_index_features","spc_min_func_freq_subsumption_index","spc_num_iterations","spc_trace","statistics","strong_context_simplifier","tick","trace","trace_file_name","type_check","user_theory_persist_axioms","user_theory_preprocess_axioms","verbose","warning","well_sorted_check","z3_solver_ll_pp","z3_solver_smt_pp", 0 }; bool is_old_param_name(symbol const & name) { @@ -35,7 +35,7 @@ bool is_old_param_name(symbol const & name) { return false; } -char const * g_params_renames[] = { +static char const * g_params_renames[] = { "proof_mode", "proof", "soft_timeout", "timeout", "mbqi", "smt.mbqi", diff --git a/src/util/hwf.h b/src/util/hwf.h index 3b7a0e94b..9059869a0 100644 --- a/src/util/hwf.h +++ b/src/util/hwf.h @@ -28,6 +28,12 @@ class hwf { friend class hwf_manager; double value; hwf & operator=(hwf const & other) { UNREACHABLE(); return *this; } + uint64 get_raw() const { + uint64 n; + SASSERT(sizeof(n) == sizeof(value)); + memcpy(&n, &value, sizeof(value)); + return n; + } public: hwf() {} @@ -122,16 +128,15 @@ public: bool sgn(hwf const & x) const { - uint64 raw = *reinterpret_cast(&x.value); - return (raw & 0x8000000000000000ull) != 0; + return (x.get_raw() & 0x8000000000000000ull) != 0; } const uint64 sig(hwf const & x) const { - return *reinterpret_cast(&x.value) & 0x000FFFFFFFFFFFFFull; + return x.get_raw() & 0x000FFFFFFFFFFFFFull; } const int exp(hwf const & x) const { - return ((*reinterpret_cast(&x.value) & 0x7FF0000000000000ull) >> 52) - 1023; + return ((x.get_raw() & 0x7FF0000000000000ull) >> 52) - 1023; } bool is_nan(hwf const & x); @@ -151,7 +156,7 @@ public: void mk_pinf(hwf & o); void mk_ninf(hwf & o); - unsigned hash(hwf const & a) { return hash_ull(*reinterpret_cast(&a.value)); } + unsigned hash(hwf const & a) { return hash_ull(a.get_raw()); } inline void set_rounding_mode(mpf_rounding_mode rm); diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index de4e760d7..f5e5fa9fa 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -27,14 +27,14 @@ void mem_finalize(); out_of_memory_error::out_of_memory_error():z3_error(ERR_MEMOUT) { } -volatile bool g_memory_out_of_memory = false; -bool g_memory_initialized = false; -long long g_memory_alloc_size = 0; -long long g_memory_max_size = 0; -long long g_memory_max_used_size = 0; -long long g_memory_watermark = 0; -bool g_exit_when_out_of_memory = false; -char const * g_out_of_memory_msg = "ERROR: out of memory"; +static volatile bool g_memory_out_of_memory = false; +static bool g_memory_initialized = false; +static long long g_memory_alloc_size = 0; +static long long g_memory_max_size = 0; +static long long g_memory_max_used_size = 0; +static long long g_memory_watermark = 0; +static bool g_exit_when_out_of_memory = false; +static char const * g_out_of_memory_msg = "ERROR: out of memory"; void memory::exit_when_out_of_memory(bool flag, char const * msg) { g_exit_when_out_of_memory = flag; diff --git a/src/util/warning.cpp b/src/util/warning.cpp index 0a1ac9bbc..88f807e3c 100644 --- a/src/util/warning.cpp +++ b/src/util/warning.cpp @@ -60,11 +60,11 @@ void myInvalidParameterHandler( #define END_ERR_HANDLER() {} #endif -bool g_warning_msgs = true; -bool g_use_std_stdout = false; -std::ostream* g_error_stream = 0; -std::ostream* g_warning_stream = 0; -bool g_show_error_msg_prefix = true; +static bool g_warning_msgs = true; +static bool g_use_std_stdout = false; +static std::ostream* g_error_stream = 0; +static std::ostream* g_warning_stream = 0; +static bool g_show_error_msg_prefix = true; void send_warnings_to_stdout(bool flag) { g_use_std_stdout = flag; From 0fbdd37e8947c0c8a5c09db182b2447ba668b318 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 21 Apr 2013 18:17:49 -0700 Subject: [PATCH 095/281] working on horn difference logic Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 2 +- src/ast/arith_decl_plugin.h | 2 + src/muz_qe/dl_bmc_engine.cpp | 1 - src/muz_qe/dl_context.cpp | 1 - src/muz_qe/dl_mk_bit_blast.cpp | 1 - src/muz_qe/dl_mk_karr_invariants.cpp | 47 +++++++++++++++++----- src/muz_qe/dl_mk_karr_invariants.h | 2 +- src/muz_qe/dl_mk_loop_counter.cpp | 60 +++++++++++++++++++++++----- src/muz_qe/dl_mk_loop_counter.h | 5 ++- src/muz_qe/dl_rule_set.cpp | 7 ++-- src/smt/diff_logic.h | 4 -- src/smt/theory_diff_logic_def.h | 9 +---- src/util/inf_rational.h | 5 +++ 13 files changed, 105 insertions(+), 41 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 680b59c68..c4b5c97d7 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -46,7 +46,7 @@ extern "C" { Z3_TRY; LOG_Z3_mk_int_symbol(c, i); RESET_ERROR_CODE(); - if (i < 0 || (unsigned)i >= (SIZE_MAX >> PTR_ALIGNMENT)) { + if (i < 0 || (size_t)i >= (SIZE_MAX >> PTR_ALIGNMENT)) { SET_ERROR_CODE(Z3_IOB); return 0; } diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index d048bb2f7..cd33c7782 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -268,6 +268,8 @@ public: bool is_int_real(expr const * n) const { return is_int_real(get_sort(n)); } MATCH_UNARY(is_uminus); + MATCH_UNARY(is_to_real); + MATCH_UNARY(is_to_int); MATCH_BINARY(is_sub); MATCH_BINARY(is_add); MATCH_BINARY(is_mul); diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp index 15876b631..c313f7d7b 100644 --- a/src/muz_qe/dl_bmc_engine.cpp +++ b/src/muz_qe/dl_bmc_engine.cpp @@ -1004,7 +1004,6 @@ namespace datalog { symbol is_name(_name.str().c_str()); std::stringstream _name2; _name2 << "get_succ#" << i; - symbol acc_name(_name2.str().c_str()); ptr_vector accs; type_ref tr(0); accs.push_back(mk_accessor_decl(name, tr)); diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 73ddd22e5..df293aeba 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -647,7 +647,6 @@ namespace datalog { } } ast_manager& m = get_manager(); - datalog::rule_manager& rm = get_rule_manager(); contains_pred contains_p(*this); check_pred check_pred(contains_p, get_manager()); diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 3f92bbce8..51a9d5927 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -141,7 +141,6 @@ namespace datalog { func_decl_ref_vector const& new_funcs() const { return m_new_funcs; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - rule_manager& rm = m_context.get_rule_manager(); bool found = false; for (unsigned j = 0; !found && j < num; ++j) { found = m_util.is_mkbv(args[j]); diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index c8e350eeb..0a85f9abf 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -35,6 +35,8 @@ Revision History: #include"dl_mk_karr_invariants.h" #include"expr_safe_replace.h" #include"bool_rewriter.h" +#include"dl_mk_backwards.h" +#include"dl_mk_loop_counter.h" namespace datalog { @@ -199,6 +201,29 @@ namespace datalog { return 0; } } + + mk_loop_counter lc(m_ctx); + mk_backwards bwd(m_ctx); + + scoped_ptr src_loop = lc(source); + TRACE("dl", src_loop->display(tout << "source loop\n");); + + // run propagation forwards, then backwards + scoped_ptr src_annot = update_using_propagation(*src_loop, *src_loop); + TRACE("dl", src_annot->display(tout << "updated using propagation\n");); + +#if 0 + // figure out whether to update same rules as used for saturation. + scoped_ptr rev_source = bwd(*src_annot); + src_annot = update_using_propagation(*src_annot, *rev_source); +#endif + rule_set* rules = lc.revert(*src_annot); + rules->inherit_predicates(source); + TRACE("dl", rules->display(tout);); + return rules; + } + + rule_set* mk_karr_invariants::update_using_propagation(rule_set const& src, rule_set const& srcref) { m_inner_ctx.reset(); rel_context& rctx = m_inner_ctx.get_rel_context(); ptr_vector heads; @@ -207,24 +232,24 @@ namespace datalog { m_inner_ctx.register_predicate(*fit, false); } m_inner_ctx.ensure_opened(); - m_inner_ctx.replace_rules(source); + m_inner_ctx.replace_rules(srcref); m_inner_ctx.close(); - rule_set::decl2rules::iterator dit = source.begin_grouped_rules(); - rule_set::decl2rules::iterator dend = source.end_grouped_rules(); + rule_set::decl2rules::iterator dit = srcref.begin_grouped_rules(); + rule_set::decl2rules::iterator dend = srcref.end_grouped_rules(); for (; dit != dend; ++dit) { heads.push_back(dit->m_key); } m_inner_ctx.rel_query(heads.size(), heads.c_ptr()); - rule_set* rules = alloc(rule_set, m_ctx); - it = source.begin(); + rule_set* dst = alloc(rule_set, m_ctx); + rule_set::iterator it = src.begin(), end = src.end(); for (; it != end; ++it) { - update_body(rctx, *rules, **it); + update_body(rctx, *dst, **it); } if (m_ctx.get_model_converter()) { add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m); - rule_set::decl2rules::iterator git = source.begin_grouped_rules(); - rule_set::decl2rules::iterator gend = source.end_grouped_rules(); + rule_set::decl2rules::iterator git = src.begin_grouped_rules(); + rule_set::decl2rules::iterator gend = src.end_grouped_rules(); for (; git != gend; ++git) { func_decl* p = git->m_key; expr_ref fml(m); @@ -236,9 +261,9 @@ namespace datalog { } m_ctx.add_model_converter(kmc); } - TRACE("dl", rules->display(tout);); - rules->inherit_predicates(source); - return rules; + + dst->inherit_predicates(src); + return dst; } void mk_karr_invariants::update_body(rel_context& rctx, rule_set& rules, rule& r) { diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index 414953e4f..330260671 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -56,7 +56,7 @@ namespace datalog { context m_inner_ctx; arith_util a; void update_body(rel_context& rctx, rule_set& result, rule& r); - + rule_set* update_using_propagation(rule_set const& src, rule_set const& srcref); public: mk_karr_invariants(context & ctx, unsigned priority); diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz_qe/dl_mk_loop_counter.cpp index 144826639..678bfc5a3 100644 --- a/src/muz_qe/dl_mk_loop_counter.cpp +++ b/src/muz_qe/dl_mk_loop_counter.cpp @@ -32,7 +32,7 @@ namespace datalog { mk_loop_counter::~mk_loop_counter() { } - app_ref mk_loop_counter::add_arg(app* fn, unsigned idx) { + app_ref mk_loop_counter::add_arg(rule_set const& src, rule_set& dst, app* fn, unsigned idx) { expr_ref_vector args(m); func_decl* new_fn, *old_fn = fn->get_decl(); args.append(fn->get_num_args(), fn->get_args()); @@ -46,17 +46,29 @@ namespace datalog { m_old2new.insert(old_fn, new_fn); m_new2old.insert(new_fn, old_fn); m_refs.push_back(new_fn); + m_ctx.register_predicate(new_fn, false); + if (src.is_output_predicate(old_fn)) { + dst.set_output_predicate(new_fn); + } } return app_ref(m.mk_app(new_fn, args.size(), args.c_ptr()), m); } + + app_ref mk_loop_counter::del_arg(app* fn) { + expr_ref_vector args(m); + func_decl* old_fn, *new_fn = fn->get_decl(); + SASSERT(fn->get_num_args() > 0); + args.append(fn->get_num_args()-1, fn->get_args()); + VERIFY (m_new2old.find(new_fn, old_fn)); + return app_ref(m.mk_app(old_fn, args.size(), args.c_ptr()), m); + } rule_set * mk_loop_counter::operator()(rule_set const & source) { m_refs.reset(); m_old2new.reset(); m_new2old.reset(); - context& ctx = source.get_context(); rule_manager& rm = source.get_rule_manager(); - rule_set * result = alloc(rule_set, ctx); + rule_set * result = alloc(rule_set, m_ctx); unsigned sz = source.get_num_rules(); rule_ref new_rule(rm); app_ref_vector tail(m); @@ -71,16 +83,14 @@ namespace datalog { unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); for (unsigned j = 0; j < utsz; ++j, ++cnt) { - tail.push_back(add_arg(r.get_tail(j), cnt)); + tail.push_back(add_arg(source, *result, r.get_tail(j), cnt)); neg.push_back(r.is_neg_tail(j)); - m_ctx.register_predicate(tail.back()->get_decl(), false); } for (unsigned j = utsz; j < tsz; ++j) { tail.push_back(r.get_tail(j)); neg.push_back(false); } - head = add_arg(r.get_head(), cnt); - m_ctx.register_predicate(head->get_decl(), false); + head = add_arg(source, *result, r.get_head(), cnt); // set the loop counter to be an increment of the previous bool found = false; unsigned last = head->get_num_args()-1; @@ -108,9 +118,41 @@ namespace datalog { // model converter: remove references to extra argument. // proof converter: remove references to extra argument as well. - result->inherit_predicates(source); - return result; } + rule_set * mk_loop_counter::revert(rule_set const & source) { + context& ctx = source.get_context(); + rule_manager& rm = source.get_rule_manager(); + rule_set * result = alloc(rule_set, ctx); + unsigned sz = source.get_num_rules(); + rule_ref new_rule(rm); + app_ref_vector tail(m); + app_ref head(m); + svector neg; + for (unsigned i = 0; i < sz; ++i) { + tail.reset(); + neg.reset(); + rule & r = *source.get_rule(i); + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + for (unsigned j = 0; j < utsz; ++j) { + tail.push_back(del_arg(r.get_tail(j))); + neg.push_back(r.is_neg_tail(j)); + } + for (unsigned j = utsz; j < tsz; ++j) { + tail.push_back(r.get_tail(j)); + neg.push_back(false); + } + head = del_arg(r.get_head()); + new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + result->add_rule(new_rule); + } + + // model converter: ... + // proof converter: ... + + return result; + + } }; diff --git a/src/muz_qe/dl_mk_loop_counter.h b/src/muz_qe/dl_mk_loop_counter.h index fc4d7e32f..d67c88e0e 100644 --- a/src/muz_qe/dl_mk_loop_counter.h +++ b/src/muz_qe/dl_mk_loop_counter.h @@ -32,7 +32,8 @@ namespace datalog { obj_map m_new2old; obj_map m_old2new; - app_ref add_arg(app* fn, unsigned idx); + app_ref add_arg(rule_set const& src, rule_set& dst, app* fn, unsigned idx); + app_ref del_arg(app* fn); public: mk_loop_counter(context & ctx, unsigned priority = 33000); ~mk_loop_counter(); @@ -40,6 +41,8 @@ namespace datalog { rule_set * operator()(rule_set const & source); func_decl* get_old(func_decl* f) const { return m_new2old.find(f); } + + rule_set * revert(rule_set const& source); }; }; diff --git a/src/muz_qe/dl_rule_set.cpp b/src/muz_qe/dl_rule_set.cpp index cb129ab37..ad3b512a3 100644 --- a/src/muz_qe/dl_rule_set.cpp +++ b/src/muz_qe/dl_rule_set.cpp @@ -409,9 +409,10 @@ namespace datalog { } void rule_set::reopen() { - SASSERT(is_closed()); - m_stratifier = 0; - m_deps.reset(); + if (is_closed()) { + m_stratifier = 0; + m_deps.reset(); + } } /** diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 49d7313d1..6d5101a80 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -1643,7 +1643,3 @@ public: #endif /* _DIFF_LOGIC_H_ */ -#if 0 - - -#endif diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 9f2c97a84..7493f81c2 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -318,7 +318,7 @@ template void theory_diff_logic::assign_eh(bool_var v, bool is_true) { m_stats.m_num_assertions++; atom * a = 0; - m_bool_var2atom.find(v, a); + VERIFY (m_bool_var2atom.find(v, a)); SASSERT(a); SASSERT(get_context().get_assignment(v) != l_undef); SASSERT((get_context().get_assignment(v) == l_true) == is_true); @@ -376,13 +376,6 @@ final_check_status theory_diff_logic::final_check_eh() { SASSERT(is_consistent()); -#if 0 - TBD: - if (propagate_cheap_equalities()) { - return FC_CONTINUE; - } -#endif - if (m_non_diff_logic_exprs) { return FC_GIVEUP; } diff --git a/src/util/inf_rational.h b/src/util/inf_rational.h index 9e1753484..5cdfe9e93 100644 --- a/src/util/inf_rational.h +++ b/src/util/inf_rational.h @@ -223,6 +223,7 @@ class inf_rational { } friend inline inf_rational operator*(const rational & r1, const inf_rational & r2); + friend inline inf_rational operator*(const inf_rational & r1, const rational & r2); friend inline inf_rational operator/(const inf_rational & r1, const rational & r2); inf_rational & operator++() { @@ -426,6 +427,10 @@ inline inf_rational operator*(const rational & r1, const inf_rational & r2) { return result; } +inline inf_rational operator*(const inf_rational & r1, const rational & r2) { + return r2 * r1; +} + inline inf_rational operator/(const inf_rational & r1, const rational & r2) { inf_rational result(r1); result.m_first /= r2; From db653a6e686da6cd0ca8bf7f291a099c976ccced Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Mon, 22 Apr 2013 09:05:27 -0700 Subject: [PATCH 096/281] [datalog] merge changes from the hassel branch Signed-off-by: Nuno Lopes --- src/muz_qe/dl_check_table.h | 9 ----- src/muz_qe/dl_compiler.cpp | 53 ++++++++++-------------------- src/muz_qe/dl_compiler.h | 2 +- src/muz_qe/dl_context.cpp | 9 ++++- src/muz_qe/dl_relation_manager.cpp | 1 - src/muz_qe/dl_util.h | 2 ++ 6 files changed, 29 insertions(+), 47 deletions(-) diff --git a/src/muz_qe/dl_check_table.h b/src/muz_qe/dl_check_table.h index 7126bde66..40a3d5207 100644 --- a/src/muz_qe/dl_check_table.h +++ b/src/muz_qe/dl_check_table.h @@ -89,15 +89,6 @@ namespace datalog { class check_table : public table_base { friend class check_table_plugin; - friend class check_table_plugin::join_fn; - friend class check_table_plugin::union_fn; - friend class check_table_plugin::transformer_fn; - friend class check_table_plugin::rename_fn; - friend class check_table_plugin::project_fn; - friend class check_table_plugin::filter_equal_fn; - friend class check_table_plugin::filter_identical_fn; - friend class check_table_plugin::filter_interpreted_fn; - friend class check_table_plugin::filter_by_negation_fn; table_base* m_checker; table_base* m_tocheck; diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index 80b9dee5a..34dd94214 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -421,6 +421,7 @@ namespace datalog { void compiler::compile_rule_evaluation_run(rule * r, reg_idx head_reg, const reg_idx * tail_regs, reg_idx delta_reg, bool use_widening, instruction_block & acc) { + ast_manager & m = m_context.get_manager(); m_instruction_observer.start_rule(r); const app * h = r->get_head(); @@ -433,7 +434,7 @@ namespace datalog { SASSERT(pt_len<=2); //we require rules to be processed by the mk_simple_joins rule transformer plugin reg_idx single_res; - ptr_vector single_res_expr; + expr_ref_vector single_res_expr(m); //used to save on filter_identical instructions where the check is already done //by the join operation @@ -536,7 +537,7 @@ namespace datalog { unsigned srlen=single_res_expr.size(); SASSERT((single_res==execution_context::void_register) ? (srlen==0) : (srlen==m_reg_signatures[single_res].size())); for(unsigned i=0; iget_tail_size(); //full tail for(unsigned tail_index=ut_len; tail_indexget_tail(tail_index); - var_idx_set t_vars; - ast_manager & m = m_context.get_manager(); - collect_vars(m, t, t_vars); - + ptr_vector t_vars; + ::get_free_vars(t, t_vars); + if(t_vars.empty()) { expr_ref simplified(m); m_context.get_rewriter()(t, simplified); @@ -639,40 +639,23 @@ namespace datalog { } //determine binding size - unsigned max_var=0; - var_idx_set::iterator vit = t_vars.begin(); - var_idx_set::iterator vend = t_vars.end(); - for(; vit!=vend; ++vit) { - unsigned v = *vit; - if(v>max_var) { max_var = v; } + while (!t_vars.back()) { + t_vars.pop_back(); } + unsigned max_var = t_vars.size(); //create binding expr_ref_vector binding(m); binding.resize(max_var+1); - vit = t_vars.begin(); - for(; vit!=vend; ++vit) { - unsigned v = *vit; + + for(unsigned v = 0; v < t_vars.size(); ++v) { + if (!t_vars[v]) { + continue; + } int2ints::entry * e = var_indexes.find_core(v); if(!e) { //we have an unbound variable, so we add an unbound column for it - relation_sort unbound_sort = 0; - - for(unsigned hindex = 0; hindexget_arg(hindex); - if(!is_var(harg) || to_var(harg)->get_idx()!=v) { - continue; - } - unbound_sort = to_var(harg)->get_sort(); - } - if(!unbound_sort) { - // the variable in the interpreted tail is neither bound in the - // uninterpreted tail nor present in the head - std::stringstream sstm; - sstm << "rule with unbound variable #" << v << " in interpreted tail: "; - r->display(m_context, sstm); - throw default_exception(sstm.str()); - } + relation_sort unbound_sort = t_vars[v]; reg_idx new_reg; TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";); @@ -759,7 +742,7 @@ namespace datalog { m_instruction_observer.finish_rule(); } - void compiler::add_unbound_columns_for_negation(rule* r, func_decl* pred, reg_idx& single_res, ptr_vector& single_res_expr, + void compiler::add_unbound_columns_for_negation(rule* r, func_decl* pred, reg_idx& single_res, expr_ref_vector& single_res_expr, bool & dealloc, instruction_block & acc) { uint_set pos_vars; u_map neg_vars; @@ -782,7 +765,7 @@ namespace datalog { } // populate positive variables: for (unsigned i = 0; i < single_res_expr.size(); ++i) { - expr* e = single_res_expr[i]; + expr* e = single_res_expr[i].get(); if (is_var(e)) { pos_vars.insert(to_var(e)->get_idx()); } diff --git a/src/muz_qe/dl_compiler.h b/src/muz_qe/dl_compiler.h index 1dfb7c7d8..e5b62f54b 100644 --- a/src/muz_qe/dl_compiler.h +++ b/src/muz_qe/dl_compiler.h @@ -177,7 +177,7 @@ namespace datalog { void make_full_relation(func_decl* pred, const relation_signature & sig, reg_idx & result, instruction_block & acc); - void add_unbound_columns_for_negation(rule* compiled_rule, func_decl* pred, reg_idx& single_res, ptr_vector& single_res_expr, + void add_unbound_columns_for_negation(rule* compiled_rule, func_decl* pred, reg_idx& single_res, expr_ref_vector& single_res_expr, bool & dealloc, instruction_block& acc); void make_duplicate_column(reg_idx src, unsigned col, reg_idx & result, instruction_block & acc); diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index df293aeba..8ac32f4a7 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -823,7 +823,14 @@ namespace datalog { if (similarity_compressor()) { m_transf.register_plugin(alloc(mk_similarity_compressor, *this)); } - m_transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this)); + m_transf.register_plugin(alloc(mk_partial_equivalence_transformer, *this)); + m_transf.register_plugin(alloc(mk_rule_inliner, *this)); + m_transf.register_plugin(alloc(mk_interp_tail_simplifier, *this)); + + if (get_params().bit_blast()) { + m_transf.register_plugin(alloc(mk_bit_blast, *this, 22000)); + m_transf.register_plugin(alloc(mk_interp_tail_simplifier, *this, 21000)); + } transform_rules(m_transf); } diff --git a/src/muz_qe/dl_relation_manager.cpp b/src/muz_qe/dl_relation_manager.cpp index ef8e6ddd4..986a1f2c4 100644 --- a/src/muz_qe/dl_relation_manager.cpp +++ b/src/muz_qe/dl_relation_manager.cpp @@ -740,7 +740,6 @@ namespace datalog { relation_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const relation_base & t, const relation_element & value, unsigned col) { relation_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col); - TRACE("dl", tout << t.get_plugin().get_name() << " " << value << " " << col << "\n";); if(!res) { relation_mutator_fn * selector = mk_filter_equal_fn(t, value, col); if(selector) { diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index 974ab5862..2da0463e8 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -207,7 +207,9 @@ namespace datalog { static unsigned expr_cont_get_size(app * a) { return a->get_num_args(); } static expr * expr_cont_get(app * a, unsigned i) { return a->get_arg(i); } static unsigned expr_cont_get_size(const ptr_vector & v) { return v.size(); } + static unsigned expr_cont_get_size(const expr_ref_vector & v) { return v.size(); } static expr * expr_cont_get(const ptr_vector & v, unsigned i) { return v[i]; } + static expr * expr_cont_get(const expr_ref_vector & v, unsigned i) { return v[i]; } public: variable_intersection(ast_manager & m) : m_consts(m) {} From e1d5f484f15df705cf05d98c92d9ef11e5142bb1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Apr 2013 08:46:46 -0700 Subject: [PATCH 097/281] simplify result from tactics, remove unused features from difference logic solver Signed-off-by: Nikolaj Bjorner --- src/smt/theory_diff_logic.h | 15 +--- src/smt/theory_diff_logic_def.h | 97 +------------------------ src/tactic/core/ctx_simplify_tactic.cpp | 6 ++ 3 files changed, 11 insertions(+), 107 deletions(-) diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 4140f683c..9c80d8c34 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -259,8 +259,6 @@ namespace smt { theory_var m_zero_int; // cache the variable representing the zero variable. theory_var m_zero_real; // cache the variable representing the zero variable. int_vector m_scc_id; // Cheap equality propagation - bool m_modified_since_eq_prop; // true if new constraints were asserted - // since last eq propagation. eq_prop_info_set m_eq_prop_info_set; // set of existing equality prop infos ptr_vector m_eq_prop_infos; @@ -289,18 +287,14 @@ namespace smt { virtual theory_var mk_var(enode* n); virtual theory_var mk_var(app* n); - - void mark_as_modified_since_eq_prop(); - - void unmark_as_modified_since_eq_prop(); - - bool propagate_cheap_equalities(); - + void compute_delta(); void found_non_diff_logic_expr(expr * n); - bool is_interpreted(app* n) const; + bool is_interpreted(app* n) const { + return get_family_id() == n->get_family_id(); + } void del_clause_eh(clause* cls); @@ -312,7 +306,6 @@ namespace smt { m_arith_eq_adapter(*this, params, m_util), m_zero_int(null_theory_var), m_zero_real(null_theory_var), - m_modified_since_eq_prop(false), m_asserted_qhead(0), m_num_core_conflicts(0), m_num_propagation_calls(0), diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 9f2c97a84..28c14b18f 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -374,15 +374,7 @@ final_check_status theory_diff_logic::final_check_eh() { // either will already be zero (as we don't do mixed constraints). m_graph.set_to_zero(m_zero_int, m_zero_real); SASSERT(is_consistent()); - - -#if 0 - TBD: - if (propagate_cheap_equalities()) { - return FC_CONTINUE; - } -#endif - + if (m_non_diff_logic_exprs) { return FC_GIVEUP; } @@ -540,22 +532,6 @@ bool theory_diff_logic::propagate_atom(atom* a) { return true; } - - -template -void theory_diff_logic::mark_as_modified_since_eq_prop() { - if (!m_modified_since_eq_prop) { - get_context().push_trail(value_trail(m_modified_since_eq_prop)); - m_modified_since_eq_prop = true; - } -} - -template -void theory_diff_logic::unmark_as_modified_since_eq_prop() { - get_context().push_trail(value_trail(m_modified_since_eq_prop)); - m_modified_since_eq_prop = false; -} - template void theory_diff_logic::del_clause_eh(clause* cls) { @@ -802,7 +778,6 @@ theory_var theory_diff_logic::mk_num(app* n, rational const& r) { template theory_var theory_diff_logic::mk_var(enode* n) { - mark_as_modified_since_eq_prop(); theory_var v = theory::mk_var(n); TRACE("diff_logic_vars", tout << "mk_var: " << v << "\n";); m_graph.init_var(v); @@ -810,10 +785,6 @@ theory_var theory_diff_logic::mk_var(enode* n) { return v; } -template -bool theory_diff_logic::is_interpreted(app* n) const { - return n->get_family_id() == get_family_id(); -} template theory_var theory_diff_logic::mk_var(app* n) { @@ -854,7 +825,6 @@ void theory_diff_logic::reset_eh() { m_asserted_atoms .reset(); m_stats .reset(); m_scopes .reset(); - m_modified_since_eq_prop = false; m_asserted_qhead = 0; m_num_core_conflicts = 0; m_num_propagation_calls = 0; @@ -865,70 +835,6 @@ void theory_diff_logic::reset_eh() { } -template -bool theory_diff_logic::propagate_cheap_equalities() { - bool result = false; - TRACE("dl_new_eq", get_context().display(tout);); - context& ctx = get_context(); - region& reg = ctx.get_region(); - SASSERT(m_eq_prop_info_set.empty()); - SASSERT(m_eq_prop_infos.empty()); - if (m_modified_since_eq_prop) { - m_graph.compute_zero_edge_scc(m_scc_id); - int n = get_num_vars(); - for (theory_var v = 0; v < n; v++) { - rational delta_r; - theory_var x_v = expand(true, v, delta_r); - numeral delta(delta_r); - int scc_id = m_scc_id[x_v]; - if (scc_id != -1) { - delta += m_graph.get_assignment(x_v); - TRACE("eq_scc", tout << v << " " << x_v << " " << scc_id << " " << delta << "\n";); - eq_prop_info info(scc_id, delta); - typename eq_prop_info_set::entry * entry = m_eq_prop_info_set.find_core(&info); - if (entry == 0) { - eq_prop_info * new_info = alloc(eq_prop_info, scc_id, delta, v); - m_eq_prop_info_set.insert(new_info); - m_eq_prop_infos.push_back(new_info); - } - else { - // new equality found - theory_var r = entry->get_data()->get_root(); - - enode * n1 = get_enode(v); - enode * n2 = get_enode(r); - if (n1->get_root() != n2->get_root()) { - // r may be an alias (i.e., it is not realy in the graph). So, I should expand it. - // nsb: ?? - rational r_delta; - theory_var x_r = expand(true, r, r_delta); - - justification* j = new (reg) implied_eq_justification(*this, x_v, x_r, m_graph.get_timestamp()); - (void)j; - - m_stats.m_num_th2core_eqs++; - // TBD: get equality into core. - - NOT_IMPLEMENTED_YET(); - // new_eq_eh(x_v, x_r, *j); - result = true; - } - } - } - } - m_eq_prop_info_set.reset(); - std::for_each(m_eq_prop_infos.begin(), m_eq_prop_infos.end(), delete_proc()); - m_eq_prop_infos.reset(); - unmark_as_modified_since_eq_prop(); - } - - TRACE("dl_new_eq", get_context().display(tout);); - SASSERT(!m_modified_since_eq_prop); - - return result; -} - - template void theory_diff_logic::compute_delta() { m_delta = rational(1); @@ -1087,7 +993,6 @@ void theory_diff_logic::new_eq_or_diseq(bool is_eq, theory_var v1, theory_v // assign the corresponding equality literal. // - mark_as_modified_since_eq_prop(); app_ref eq(m), s2(m), t2(m); app* s1 = get_enode(s)->get_owner(); diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 831efa087..be4dfd516 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -371,6 +371,12 @@ struct ctx_simplify_tactic::imp { if (!modified) { r = t; } + if (new_new_args.empty()) { + r = OR?m.mk_false():m.mk_true(); + } + else if (new_new_args.size() == 1) { + r = new_new_args[0]; + } else { std::reverse(new_new_args.c_ptr(), new_new_args.c_ptr() + new_new_args.size()); m_mk_app(t->get_decl(), new_new_args.size(), new_new_args.c_ptr(), r); From eead1bbc4878ffd5362cb465a8cb565734c0aca3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Apr 2013 09:24:39 -0700 Subject: [PATCH 098/281] missing else Signed-off-by: Nikolaj Bjorner --- src/tactic/core/ctx_simplify_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index be4dfd516..2c2afab6f 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -371,7 +371,7 @@ struct ctx_simplify_tactic::imp { if (!modified) { r = t; } - if (new_new_args.empty()) { + else if (new_new_args.empty()) { r = OR?m.mk_false():m.mk_true(); } else if (new_new_args.size() == 1) { From d849dbf21f218663e9c9ffa01eea168c7b7765c9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Apr 2013 00:22:14 -0700 Subject: [PATCH 099/281] remove pointer comparisons/hash Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_base.h | 11 +++++--- src/muz_qe/dl_compiler.cpp | 2 +- src/muz_qe/dl_compiler.h | 3 ++- src/muz_qe/dl_context.cpp | 4 +-- src/muz_qe/dl_finite_product_relation.h | 2 +- src/muz_qe/dl_mk_filter_rules.h | 8 ++++-- src/muz_qe/dl_mk_magic_sets.h | 7 +++++- src/muz_qe/dl_mk_similarity_compressor.cpp | 10 +++++--- src/muz_qe/dl_product_relation.h | 6 ++++- src/muz_qe/dl_relation_manager.h | 2 +- src/muz_qe/dl_rule_transformer.cpp | 3 +++ src/muz_qe/dl_sieve_relation.h | 2 +- src/muz_qe/dl_sparse_table.h | 2 +- src/muz_qe/dl_table.h | 2 +- src/muz_qe/dl_util.h | 29 ++++++++++++++-------- src/muz_qe/rel_context.cpp | 2 ++ src/util/hash.h | 6 +++++ src/util/vector.h | 17 ++++++++----- 18 files changed, 81 insertions(+), 37 deletions(-) diff --git a/src/muz_qe/dl_base.h b/src/muz_qe/dl_base.h index e7243cb70..491bb261d 100644 --- a/src/muz_qe/dl_base.h +++ b/src/muz_qe/dl_base.h @@ -656,6 +656,7 @@ namespace datalog { typedef sort * relation_sort; typedef ptr_vector relation_signature_base0; + typedef ptr_hash relation_sort_hash; typedef app * relation_element; typedef app_ref relation_element_ref; @@ -739,8 +740,8 @@ namespace datalog { struct hash { unsigned operator()(relation_signature const& s) const { - relation_sort const* sorts = s.c_ptr(); - return string_hash(reinterpret_cast(sorts), sizeof(*sorts)*s.size(), 12); } + return obj_vector_hash(s); + } }; struct eq { @@ -816,9 +817,11 @@ namespace datalog { typedef uint64 table_sort; typedef svector table_signature_base0; + typedef uint64_hash table_sort_hash; typedef uint64 table_element; typedef svector table_fact; + typedef uint64_hash table_element_hash; struct table_traits { typedef table_plugin plugin; @@ -881,8 +884,8 @@ namespace datalog { public: struct hash { unsigned operator()(table_signature const& s) const { - table_sort const* sorts = s.c_ptr(); - return string_hash(reinterpret_cast(sorts), sizeof(*sorts)*s.size(), 12); } + return svector_hash()(s); + } }; struct eq { diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index 34dd94214..e4528426a 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -36,7 +36,7 @@ namespace datalog { } void compiler::ensure_predicate_loaded(func_decl * pred, instruction_block & acc) { - pred2idx::entry * e = m_pred_regs.insert_if_not_there2(pred, UINT_MAX); + pred2idx::obj_map_entry * e = m_pred_regs.insert_if_not_there2(pred, UINT_MAX); if(e->get_data().m_value!=UINT_MAX) { //predicate is already loaded return; diff --git a/src/muz_qe/dl_compiler.h b/src/muz_qe/dl_compiler.h index e5b62f54b..8f40f814a 100644 --- a/src/muz_qe/dl_compiler.h +++ b/src/muz_qe/dl_compiler.h @@ -41,7 +41,8 @@ namespace datalog { typedef hashtable int_set; typedef u_map int2int; typedef u_map int2ints; - typedef map,ptr_eq > pred2idx; + typedef obj_map pred2idx; +// typedef map,ptr_eq > pred2idx; typedef unsigned_vector var_vector; typedef ptr_vector func_decl_vector; diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 8ac32f4a7..50915946a 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -813,9 +813,7 @@ namespace datalog { void context::transform_rules() { m_transf.reset(); - if (get_params().filter_rules()) { - m_transf.register_plugin(alloc(mk_filter_rules, *this)); - } + m_transf.register_plugin(alloc(mk_filter_rules, *this)); m_transf.register_plugin(alloc(mk_simple_joins, *this)); if (unbound_compressor()) { m_transf.register_plugin(alloc(mk_unbound_compressor, *this)); diff --git a/src/muz_qe/dl_finite_product_relation.h b/src/muz_qe/dl_finite_product_relation.h index 165422661..d5181d122 100644 --- a/src/muz_qe/dl_finite_product_relation.h +++ b/src/muz_qe/dl_finite_product_relation.h @@ -47,7 +47,7 @@ namespace datalog { } struct hash { unsigned operator()(const rel_spec & o) const { - return o.m_inner_kind^int_vector_hash(o.m_table_cols); + return o.m_inner_kind^svector_hash()(o.m_table_cols); } }; }; diff --git a/src/muz_qe/dl_mk_filter_rules.h b/src/muz_qe/dl_mk_filter_rules.h index 4a247fdb5..91751f9b8 100644 --- a/src/muz_qe/dl_mk_filter_rules.h +++ b/src/muz_qe/dl_mk_filter_rules.h @@ -45,14 +45,18 @@ namespace datalog { filter_key(ast_manager & m) : new_pred(m), filter_args(m) {} unsigned hash() const { - return new_pred->hash() ^ int_vector_hash(filter_args); + unsigned r = new_pred->hash(); + for (unsigned i = 0; i < filter_args.size(); ++i) { + r ^= filter_args[i]->hash(); + } + return r; } bool operator==(const filter_key & o) const { return o.new_pred==new_pred && vectors_equal(o.filter_args, filter_args); } }; - typedef map, deref_eq > filter_cache; + typedef obj_map filter_cache; context & m_context; ast_manager & m_manager; diff --git a/src/muz_qe/dl_mk_magic_sets.h b/src/muz_qe/dl_mk_magic_sets.h index 507f6c2bf..dfc66e7ea 100644 --- a/src/muz_qe/dl_mk_magic_sets.h +++ b/src/muz_qe/dl_mk_magic_sets.h @@ -47,6 +47,11 @@ namespace datalog { AD_BOUND }; + struct a_flag_hash { + typedef a_flag data; + unsigned operator()(a_flag x) const { return x; } + }; + struct adornment : public svector { void populate(app * lit, const var_idx_set & bound_vars); @@ -71,7 +76,7 @@ namespace datalog { return m_pred==o.m_pred && m_adornment==o.m_adornment; } unsigned hash() const { - return m_pred->hash()^int_vector_hash(m_adornment); + return m_pred->hash()^svector_hash()(m_adornment); } }; diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index 8e77785b8..b600811f0 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -29,6 +29,7 @@ namespace datalog { m_manager(ctx.get_manager()), m_threshold_count(ctx.similarity_compressor_threshold()), m_result_rules(ctx.get_rule_manager()), + m_modified(false), m_pinned(m_manager) { SASSERT(m_threshold_count>1); } @@ -55,6 +56,9 @@ namespace datalog { return (a>b) ? 1 : ( (a==b) ? 0 : -1); } + template + static int aux_compare(T* a, T* b); + static int compare_var_args(app* t1, app* t2) { SASSERT(t1->get_num_args()==t2->get_num_args()); int res; @@ -88,7 +92,7 @@ namespace datalog { if ((skip_countdown--) == 0) { continue; } - res = aux_compare(t1->get_arg(i), t2->get_arg(i)); + res = aux_compare(t1->get_arg(i)->get_id(), t2->get_arg(i)->get_id()); if (res!=0) { return res; } } return 0; @@ -113,7 +117,7 @@ namespace datalog { for (int i=-1; iget_decl(), t2->get_decl()); + res = aux_compare(t1->get_decl()->get_id(), t2->get_decl()->get_id()); if (res!=0) { return res; } res = compare_var_args(t1, t2); if (res!=0) { return res; } @@ -121,7 +125,7 @@ namespace datalog { unsigned tail_sz = r1->get_tail_size(); for (unsigned i=pos_tail_sz; iget_tail(i), r2->get_tail(i)); + res = aux_compare(r1->get_tail(i)->get_id(), r2->get_tail(i)->get_id()); if (res!=0) { return res; } } diff --git a/src/muz_qe/dl_product_relation.h b/src/muz_qe/dl_product_relation.h index c5e755939..91c2286a7 100644 --- a/src/muz_qe/dl_product_relation.h +++ b/src/muz_qe/dl_product_relation.h @@ -40,8 +40,12 @@ namespace datalog { class filter_equal_fn; class filter_identical_fn; class filter_interpreted_fn; + struct fid_hash { + typedef family_id data; + unsigned operator()(data x) const { return static_cast(x); } + }; - rel_spec_store m_spec_store; + rel_spec_store > m_spec_store; family_id get_relation_kind(const product_relation & r); diff --git a/src/muz_qe/dl_relation_manager.h b/src/muz_qe/dl_relation_manager.h index 26008a830..f22ae7923 100644 --- a/src/muz_qe/dl_relation_manager.h +++ b/src/muz_qe/dl_relation_manager.h @@ -605,7 +605,7 @@ namespace datalog { /** This is a helper class for relation_plugins whose relations can be of various kinds. */ - template, class Eq=vector_eq_proc > + template > class rel_spec_store { typedef relation_signature::hash r_hash; typedef relation_signature::eq r_eq; diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index 0cad08cb4..21021ca43 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -107,6 +107,9 @@ namespace datalog { tout << typeid(p).name()<<":\n"; new_rules->display(tout); ); + IF_VERBOSE(1, new_rules->get_rule(0)->display(m_context, verbose_stream() << typeid(p).name() <<"\n");); + IF_VERBOSE(1, verbose_stream() << new_rules->get_dependencies().begin()->m_key->get_name() << "\n";); + } if (modified) { rules.replace_rules(*new_rules); diff --git a/src/muz_qe/dl_sieve_relation.h b/src/muz_qe/dl_sieve_relation.h index d6df3af55..551f5d705 100644 --- a/src/muz_qe/dl_sieve_relation.h +++ b/src/muz_qe/dl_sieve_relation.h @@ -52,7 +52,7 @@ namespace datalog { struct hash { unsigned operator()(const rel_spec & s) const { - return int_vector_hash(s.m_inner_cols)^s.m_inner_kind; + return svector_hash()(s.m_inner_cols)^s.m_inner_kind; } }; }; diff --git a/src/muz_qe/dl_sparse_table.h b/src/muz_qe/dl_sparse_table.h index 3920836e6..010277b6b 100644 --- a/src/muz_qe/dl_sparse_table.h +++ b/src/muz_qe/dl_sparse_table.h @@ -359,7 +359,7 @@ namespace datalog { typedef svector key_spec; //sequence of columns in a key typedef svector key_value; //values of key columns - typedef map, + typedef map, vector_eq_proc > key_index_map; static const store_offset NO_RESERVE = UINT_MAX; diff --git a/src/muz_qe/dl_table.h b/src/muz_qe/dl_table.h index 8dc0a355b..3a240c337 100644 --- a/src/muz_qe/dl_table.h +++ b/src/muz_qe/dl_table.h @@ -73,7 +73,7 @@ namespace datalog { class our_iterator_core; - typedef hashtable, + typedef hashtable, vector_eq_proc > storage; storage m_data; diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index 2da0463e8..96bc8c326 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -587,17 +587,31 @@ namespace datalog { } template - unsigned int_vector_hash(const T & cont) { - return string_hash(reinterpret_cast(cont.c_ptr()), - cont.size()*sizeof(typename T::data), 0); + struct default_obj_chash { + unsigned operator()(T const& cont, unsigned i) const { + return cont[i]->hash(); + } + }; + template + unsigned obj_vector_hash(const T & cont) { + return get_composite_hash(cont, cont.size(),default_kind_hash_proc(), default_obj_chash()); } template - struct int_vector_hash_proc { + struct obj_vector_hash_proc { unsigned operator()(const T & cont) const { - return int_vector_hash(cont); + return obj_vector_hash(cont); } }; + + template + struct svector_hash_proc { + unsigned operator()(const svector & cont) const { + return svector_hash()(cont); + } + }; + + template struct vector_eq_proc { bool operator()(const T & c1, const T & c2) const { return vectors_equal(c1, c2); } @@ -765,11 +779,6 @@ namespace datalog { // // ----------------------------------- - struct uint64_hash { - typedef uint64 data; - unsigned operator()(uint64 x) const { return hash_ull(x); } - }; - template void universal_delete(T* ptr) { dealloc(ptr); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index ef5639279..be6d999b6 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -113,10 +113,12 @@ namespace datalog { TRACE("dl", m_context.display(tout);); while (true) { + m_ectx.reset(); m_code.reset(); termination_code.reset(); m_context.ensure_closed(); + IF_VERBOSE(1, verbose_stream() << "num rules: " << m_context.get_rules().get_num_rules() << "\n";); m_context.transform_rules(); if (m_context.canceled()) { result = l_undef; diff --git a/src/util/hash.h b/src/util/hash.h index 3c7e50a6c..4232dd2af 100644 --- a/src/util/hash.h +++ b/src/util/hash.h @@ -20,6 +20,7 @@ Revision History: #define _HASH_H_ #include +#include"util.h" #ifndef __fallthrough #define __fallthrough @@ -142,6 +143,11 @@ struct size_t_hash { unsigned operator()(size_t x) const { return static_cast(x); } }; +struct uint64_hash { + typedef uint64 data; + unsigned operator()(uint64 x) const { return static_cast(x); } +}; + struct bool_hash { typedef bool data; unsigned operator()(bool x) const { return static_cast(x); } diff --git a/src/util/vector.h b/src/util/vector.h index 704452d0f..c9ed900a9 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -432,24 +432,29 @@ typedef svector unsigned_vector; typedef svector char_vector; typedef svector double_vector; -template -struct vector_hash { +template +struct vector_hash_tpl { Hash m_hash; - typedef vector data; + typedef Vec data; unsigned operator()(data const& v, unsigned idx) const { return m_hash(v[idx]); } - vector_hash(Hash const& h = Hash()):m_hash(h) {} + vector_hash_tpl(Hash const& h = Hash()):m_hash(h) {} unsigned operator()(data const& v) const { if (v.empty()) { return 778; } - return get_composite_hash, vector_hash>(v, v.size()); + return get_composite_hash, vector_hash_tpl>(v, v.size()); } - }; +template +struct vector_hash : public vector_hash_tpl > {}; + +template +struct svector_hash : public vector_hash_tpl > {}; + #endif /* _VECTOR_H_ */ From 6250a29602026b8ecd79ebecb90c8951cb8a3dcf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Apr 2013 10:02:37 -0700 Subject: [PATCH 100/281] resolved conflicts Signed-off-by: Nikolaj Bjorner --- src/smt/theory_diff_logic_def.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 6700b4c37..aeb4f73d6 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -374,12 +374,6 @@ final_check_status theory_diff_logic::final_check_eh() { // either will already be zero (as we don't do mixed constraints). m_graph.set_to_zero(m_zero_int, m_zero_real); SASSERT(is_consistent()); -<<<<<<< HEAD - - -======= - ->>>>>>> d849dbf21f218663e9c9ffa01eea168c7b7765c9 if (m_non_diff_logic_exprs) { return FC_GIVEUP; } From 08eb85fe3def5ab5d2ded01d1a14192119bf6996 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 23 Apr 2013 10:02:44 -0700 Subject: [PATCH 101/281] minor cleanup Signed-off-by: Nuno Lopes --- src/muz_qe/dl_compiler.h | 1 - src/muz_qe/dl_rule_transformer.cpp | 3 --- src/muz_qe/fixedpoint_params.pyg | 1 - src/muz_qe/rel_context.cpp | 2 -- 4 files changed, 7 deletions(-) diff --git a/src/muz_qe/dl_compiler.h b/src/muz_qe/dl_compiler.h index 8f40f814a..78b4623de 100644 --- a/src/muz_qe/dl_compiler.h +++ b/src/muz_qe/dl_compiler.h @@ -42,7 +42,6 @@ namespace datalog { typedef u_map int2int; typedef u_map int2ints; typedef obj_map pred2idx; -// typedef map,ptr_eq > pred2idx; typedef unsigned_vector var_vector; typedef ptr_vector func_decl_vector; diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index 21021ca43..0cad08cb4 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -107,9 +107,6 @@ namespace datalog { tout << typeid(p).name()<<":\n"; new_rules->display(tout); ); - IF_VERBOSE(1, new_rules->get_rule(0)->display(m_context, verbose_stream() << typeid(p).name() <<"\n");); - IF_VERBOSE(1, verbose_stream() << new_rules->get_dependencies().begin()->m_key->get_name() << "\n";); - } if (modified) { rules.replace_rules(*new_rules); diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index fd7dbdcae..774559cdb 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -13,7 +13,6 @@ def_module_params('fixedpoint', ('unbound_compressor', BOOL, True, "auxiliary relations will be introduced to avoid unbound variables in rule heads"), ('similarity_compressor', BOOL, True, "(DATALOG) rules that differ only in values of constants will be merged into a single rule"), ('similarity_compressor_threshold', UINT, 11, "(DATALOG) if similarity_compressor is on, this value determines how many similar rules there must be in order for them to be merged"), - ('filter_rules', BOOL, True, "(DATALOG) apply filter compression on rules"), ('all_or_nothing_deltas', BOOL, False, "(DATALOG) compile rules so that it is enough for the delta relation in union and widening operations to determine only whether the updated relation was modified or not"), ('compile_with_widening', BOOL, False, "(DATALOG) widening will be used to compile recursive rules"), ('eager_emptiness_checking', BOOL, True, "(DATALOG) emptiness of affected relations will be checked after each instruction, so that we may ommit unnecessary instructions"), diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index be6d999b6..ef5639279 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -113,12 +113,10 @@ namespace datalog { TRACE("dl", m_context.display(tout);); while (true) { - m_ectx.reset(); m_code.reset(); termination_code.reset(); m_context.ensure_closed(); - IF_VERBOSE(1, verbose_stream() << "num rules: " << m_context.get_rules().get_num_rules() << "\n";); m_context.transform_rules(); if (m_context.canceled()) { result = l_undef; From 12b092c45fdde206bbc12e2446cb786d021ef1a3 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 23 Apr 2013 11:27:27 -0700 Subject: [PATCH 102/281] [datalog] restore the old (linear) cycle breaker force the compiler to use all preds as global deltas for correctness. This is a temporary fix. Signed-off-by: Nuno Lopes --- src/muz_qe/dl_compiler.cpp | 58 +- src/muz_qe/dl_compiler.cpp.orig | 1245 +++++++++++++++++++++++++++++++ 2 files changed, 1263 insertions(+), 40 deletions(-) create mode 100644 src/muz_qe/dl_compiler.cpp.orig diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index e4528426a..57d9880c0 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -832,19 +832,19 @@ namespace datalog { typedef rule_dependencies::item_set item_set; //set of T rule_dependencies & m_deps; - rule_set const& m_rules; - context& m_context; item_set & m_removed; svector m_stack; + ast_mark m_stack_content; ast_mark m_visited; void traverse(T v) { - SASSERT(!m_visited.is_marked(v)); - if (m_removed.contains(v)) { + SASSERT(!m_stack_content.is_marked(v)); + if(m_visited.is_marked(v) || m_removed.contains(v)) { return; } m_stack.push_back(v); + m_stack_content.mark(v, true); m_visited.mark(v, true); const item_set & deps = m_deps.get_deps(v); @@ -852,49 +852,22 @@ namespace datalog { item_set::iterator end = deps.end(); for(; it!=end; ++it) { T d = *it; - if (m_visited.is_marked(d)) { + if(m_stack_content.is_marked(d)) { //TODO: find the best vertex to remove in the cycle - remove_from_stack(); - continue; + m_removed.insert(v); + break; } traverse(d); } SASSERT(m_stack.back()==v); m_stack.pop_back(); - m_visited.mark(v, false); - } - - void remove_from_stack() { - for (unsigned i = 0; i < m_stack.size(); ++i) { - func_decl* p = m_stack[i]; - if (m_context.has_facts(p)) { - m_removed.insert(p); - return; - } - - rule_vector const& rules = m_rules.get_predicate_rules(p); - unsigned stratum = m_rules.get_predicate_strat(p); - for (unsigned j = 0; j < rules.size(); ++j) { - rule const& r = *rules[j]; - bool ok = true; - for (unsigned k = 0; ok && k < r.get_uninterpreted_tail_size(); ++k) { - ok = m_rules.get_predicate_strat(r.get_decl(k)) < stratum; - } - if (ok) { - m_removed.insert(p); - return; - } - } - } - - // nothing was found. - m_removed.insert(m_stack.back()); + m_stack_content.mark(v, false); } public: - cycle_breaker(rule_dependencies & deps, rule_set const& rules, context& ctx, item_set & removed) - : m_deps(deps), m_rules(rules), m_context(ctx), m_removed(removed) { SASSERT(removed.empty()); } + cycle_breaker(rule_dependencies & deps, item_set & removed) + : m_deps(deps), m_removed(removed) { SASSERT(removed.empty()); } void operator()() { rule_dependencies::iterator it = m_deps.begin(); @@ -916,7 +889,7 @@ namespace datalog { rule_dependencies deps(m_rule_set.get_dependencies()); deps.restrict(preds); - cycle_breaker(deps, m_rule_set, m_context, global_deltas)(); + cycle_breaker(deps, global_deltas)(); VERIFY( deps.sort_deps(ordered_preds) ); //the predicates that were removed to get acyclic induced subgraph are put last @@ -1052,12 +1025,17 @@ namespace datalog { } func_decl_vector preds_vector; - func_decl_set global_deltas; + func_decl_set global_deltas_dummy; - detect_chains(head_preds, preds_vector, global_deltas); + detect_chains(head_preds, preds_vector, global_deltas_dummy); + /* + FIXME: right now we use all preds as global deltas for correctness purposes func_decl_set local_deltas(head_preds); set_difference(local_deltas, global_deltas); + */ + func_decl_set local_deltas; + func_decl_set global_deltas(head_preds); pred2idx d_global_src; //these deltas serve as sources of tuples for rule evaluation inside the loop get_fresh_registers(global_deltas, d_global_src); diff --git a/src/muz_qe/dl_compiler.cpp.orig b/src/muz_qe/dl_compiler.cpp.orig new file mode 100644 index 000000000..e4528426a --- /dev/null +++ b/src/muz_qe/dl_compiler.cpp.orig @@ -0,0 +1,1245 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_compiler.cpp + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-14. + +Revision History: + +--*/ + + +#include +#include"ref_vector.h" +#include"dl_context.h" +#include"dl_rule.h" +#include"dl_util.h" +#include"dl_compiler.h" +#include"ast_pp.h" +#include"ast_smt2_pp.h" + + +namespace datalog { + + void compiler::reset() { + m_pred_regs.reset(); + m_new_reg = 0; + } + + void compiler::ensure_predicate_loaded(func_decl * pred, instruction_block & acc) { + pred2idx::obj_map_entry * e = m_pred_regs.insert_if_not_there2(pred, UINT_MAX); + if(e->get_data().m_value!=UINT_MAX) { + //predicate is already loaded + return; + } + relation_signature sig; + m_context.get_rel_context().get_rmanager().from_predicate(pred, sig); + reg_idx reg = get_fresh_register(sig); + e->get_data().m_value=reg; + + acc.push_back(instruction::mk_load(m_context.get_manager(), pred, reg)); + } + + void compiler::make_join(reg_idx t1, reg_idx t2, const variable_intersection & vars, reg_idx & result, + instruction_block & acc) { + relation_signature res_sig; + relation_signature::from_join(m_reg_signatures[t1], m_reg_signatures[t2], vars.size(), + vars.get_cols1(), vars.get_cols2(), res_sig); + result = get_fresh_register(res_sig); + acc.push_back(instruction::mk_join(t1, t2, vars.size(), vars.get_cols1(), vars.get_cols2(), result)); + } + + void compiler::make_join_project(reg_idx t1, reg_idx t2, const variable_intersection & vars, + const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc) { + relation_signature aux_sig; + relation_signature sig1 = m_reg_signatures[t1]; + relation_signature sig2 = m_reg_signatures[t2]; + relation_signature::from_join(sig1, sig2, vars.size(), vars.get_cols1(), vars.get_cols2(), aux_sig); + relation_signature res_sig; + relation_signature::from_project(aux_sig, removed_cols.size(), removed_cols.c_ptr(), + res_sig); + result = get_fresh_register(res_sig); + + acc.push_back(instruction::mk_join_project(t1, t2, vars.size(), vars.get_cols1(), + vars.get_cols2(), removed_cols.size(), removed_cols.c_ptr(), result)); + } + + void compiler::make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col, + reg_idx & result, instruction_block & acc) { + relation_signature res_sig; + relation_signature::from_project(m_reg_signatures[src], 1, &col, res_sig); + result = get_fresh_register(res_sig); + acc.push_back(instruction::mk_select_equal_and_project(m_context.get_manager(), + src, val, col, result)); + } + + void compiler::make_clone(reg_idx src, reg_idx & result, instruction_block & acc) { + relation_signature sig = m_reg_signatures[src]; + result = get_fresh_register(sig); + acc.push_back(instruction::mk_clone(src, result)); + } + + void compiler::make_union(reg_idx src, reg_idx tgt, reg_idx delta, bool use_widening, + instruction_block & acc) { + SASSERT(m_reg_signatures[src]==m_reg_signatures[tgt]); + SASSERT(delta==execution_context::void_register || m_reg_signatures[src]==m_reg_signatures[delta]); + + if (use_widening) { + acc.push_back(instruction::mk_widen(src, tgt, delta)); + } + else { + acc.push_back(instruction::mk_union(src, tgt, delta)); + } + } + + void compiler::make_projection(reg_idx src, unsigned col_cnt, const unsigned * removed_cols, + reg_idx & result, instruction_block & acc) { + SASSERT(col_cnt>0); + + relation_signature res_sig; + relation_signature::from_project(m_reg_signatures[src], col_cnt, removed_cols, res_sig); + result = get_fresh_register(res_sig); + acc.push_back(instruction::mk_projection(src, col_cnt, removed_cols, result)); + } + + compiler::reg_idx compiler::get_fresh_register(const relation_signature & sig) { + //since we might be resizing the m_reg_signatures vector, the argument must not point inside it + SASSERT((&sig>=m_reg_signatures.end()) || (&sigto_formula(e); + verbose_stream() << "Compiling unsafe rule column " << col_idx << "\n" + << mk_ismt2_pp(e, m_context.get_manager()) << "\n"; + }); + reg_idx total_table; + if (!m_total_registers.find(s, pred, total_table)) { + total_table = get_single_column_register(s); + relation_signature sig; + sig.push_back(s); + m_top_level_code.push_back(instruction::mk_total(sig, pred, total_table)); + m_total_registers.insert(s, pred, total_table); + } + if(src == execution_context::void_register) { + result = total_table; + dealloc = false; + } + else { + variable_intersection empty_vars(m_context.get_manager()); + make_join(src, total_table, empty_vars, result, acc); + dealloc = true; + } + } + + void compiler::make_full_relation(func_decl* pred, const relation_signature & sig, reg_idx & result, + instruction_block & acc) { + SASSERT(sig.empty()); + TRACE("dl", tout << "Adding unbound column " << mk_pp(pred, m_context.get_manager()) << "\n";); + if (m_empty_tables_registers.find(pred, result)) + return; + + result = get_fresh_register(sig); + m_top_level_code.push_back(instruction::mk_total(sig, pred, result)); + m_empty_tables_registers.insert(pred, result); + } + + + void compiler::make_duplicate_column(reg_idx src, unsigned col, reg_idx & result, + instruction_block & acc) { + + relation_signature & src_sig = m_reg_signatures[src]; + reg_idx single_col_reg; + unsigned src_col_cnt = src_sig.size(); + if(src_col_cnt==1) { + single_col_reg = src; + } + else { + unsigned_vector removed_cols; + for(unsigned i=0; i & acis0, + reg_idx & result, + bool & dealloc, + instruction_block & acc) { + + TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";); + + unsigned col_cnt = acis0.size(); + reg_idx curr = src; + + relation_signature empty_signature; + + relation_signature * curr_sig; + if(curr!=execution_context::void_register) { + curr_sig = & m_reg_signatures[curr]; + } + else { + curr_sig = & empty_signature; + } + unsigned src_col_cnt=curr_sig->size(); + + svector acis(acis0); + int2int handled_unbound; + + //first remove unused source columns + int_set referenced_src_cols; + for(unsigned i=0; isize(); + if(acis[i].kind==ACK_CONSTANT) { + make_add_constant_column(head_pred, curr, acis[i].domain, acis[i].constant, new_curr, new_dealloc, acc); + } + else { + SASSERT(acis[i].kind==ACK_UNBOUND_VAR); + make_add_unbound_column(compiled_rule, i, head_pred, curr, acis[i].domain, new_curr, new_dealloc, acc); + handled_unbound.insert(acis[i].var_index,bound_column_index); + } + if (dealloc) + make_dealloc_non_void(curr, acc); + dealloc = new_dealloc; + curr=new_curr; + curr_sig = & m_reg_signatures[curr]; + SASSERT(bound_column_index==curr_sig->size()-1); + } + SASSERT((*curr_sig)[bound_column_index]==acis[i].domain); + acis[i].kind=ACK_BOUND_VAR; + acis[i].source_column=bound_column_index; + } + + //duplicate needed source columns + int_set used_cols; + for(unsigned i=0; isize()-1; + SASSERT((*curr_sig)[bound_column_index]==acis[i].domain); + acis[i].source_column=bound_column_index; + } + + //reorder source columns to match target + SASSERT(curr_sig->size()==col_cnt); //now the intermediate table is a permutation + for(unsigned i=0; i=i); //columns below i are already reordered + SASSERT(nextget_num_args(); + for(unsigned i = 0; iget_arg(i); + if(!is_var(e) || globals.get(to_var(e)->get_idx())!=0) { + continue; + } + res.push_back(i+ofs); + } + } + + void compiler::get_local_indexes_for_projection(rule * r, unsigned_vector & res) { + SASSERT(r->get_positive_tail_size()==2); + ast_manager & m = m_context.get_manager(); + rule_counter counter; + counter.count_rule_vars(m, r); + app * t1 = r->get_tail(0); + app * t2 = r->get_tail(1); + counter.count_vars(m, t1, -1); + counter.count_vars(m, t2, -1); + get_local_indexes_for_projection(t1, counter, 0, res); + get_local_indexes_for_projection(t2, counter, t1->get_num_args(), res); + } + + void compiler::compile_rule_evaluation_run(rule * r, reg_idx head_reg, const reg_idx * tail_regs, + reg_idx delta_reg, bool use_widening, instruction_block & acc) { + + ast_manager & m = m_context.get_manager(); + m_instruction_observer.start_rule(r); + + const app * h = r->get_head(); + unsigned head_len = h->get_num_args(); + func_decl * head_pred = h->get_decl(); + + TRACE("dl", r->display(m_context, tout); ); + + unsigned pt_len = r->get_positive_tail_size(); + SASSERT(pt_len<=2); //we require rules to be processed by the mk_simple_joins rule transformer plugin + + reg_idx single_res; + expr_ref_vector single_res_expr(m); + + //used to save on filter_identical instructions where the check is already done + //by the join operation + unsigned second_tail_arg_ofs; + + // whether to dealloc the previous result + bool dealloc = true; + + if(pt_len == 2) { + reg_idx t1_reg=tail_regs[0]; + reg_idx t2_reg=tail_regs[1]; + app * a1 = r->get_tail(0); + app * a2 = r->get_tail(1); + SASSERT(m_reg_signatures[t1_reg].size()==a1->get_num_args()); + SASSERT(m_reg_signatures[t2_reg].size()==a2->get_num_args()); + + variable_intersection a1a2(m_context.get_manager()); + a1a2.populate(a1,a2); + + unsigned_vector removed_cols; + get_local_indexes_for_projection(r, removed_cols); + + if(removed_cols.empty()) { + make_join(t1_reg, t2_reg, a1a2, single_res, acc); + } + else { + make_join_project(t1_reg, t2_reg, a1a2, removed_cols, single_res, acc); + } + + unsigned rem_index = 0; + unsigned rem_sz = removed_cols.size(); + unsigned a1len=a1->get_num_args(); + for(unsigned i=0; i=i); + if(rem_indexget_arg(i)); + } + second_tail_arg_ofs = single_res_expr.size(); + unsigned a2len=a2->get_num_args(); + for(unsigned i=0; i=i+a1len); + if(rem_indexget_arg(i)); + } + SASSERT(rem_index==rem_sz); + } + else if(pt_len==1) { + reg_idx t_reg=tail_regs[0]; + app * a = r->get_tail(0); + SASSERT(m_reg_signatures[t_reg].size()==a->get_num_args()); + + single_res = t_reg; + + unsigned n=a->get_num_args(); + for(unsigned i=0; iget_arg(i); + if(is_app(arg)) { + app * c = to_app(arg); //argument is a constant + SASSERT(c->get_num_args()==0); + SASSERT(m_context.get_decl_util().is_numeral_ext(arg)); + reg_idx new_reg; + make_select_equal_and_project(single_res, c, single_res_expr.size(), new_reg, acc); + if(single_res!=t_reg) { + //since single_res is a local register, we deallocate it + make_dealloc_non_void(single_res, acc); + } + single_res = new_reg; + } + else { + SASSERT(is_var(arg)); + single_res_expr.push_back(arg); + } + } + if(single_res==t_reg) { + dealloc = false; + } + + } + else { + SASSERT(pt_len==0); + + //single_res register should never be used in this case + single_res=execution_context::void_register; + } + + add_unbound_columns_for_negation(r, head_pred, single_res, single_res_expr, dealloc, acc); + + int2ints var_indexes; + + reg_idx filtered_res = single_res; + + { + //enforce equality to constants + unsigned srlen=single_res_expr.size(); + SASSERT((single_res==execution_context::void_register) ? (srlen==0) : (srlen==m_reg_signatures[single_res].size())); + for(unsigned i=0; iget_idx(); + int2ints::entry * e = var_indexes.insert_if_not_there2(var_num, unsigned_vector()); + e->get_data().m_value.push_back(i); + } + } + } + + //enforce equality of columns + int2ints::iterator vit=var_indexes.begin(); + int2ints::iterator vend=var_indexes.end(); + for(; vit!=vend; ++vit) { + int2ints::key_data & k = *vit; + unsigned_vector & indexes = k.m_value; + if(indexes.size()==1) { + continue; + } + SASSERT(indexes.size()>1); + if(pt_len==2 && indexes[0]=second_tail_arg_ofs) { + //If variable appears in multiple tails, the identicity will already be enforced by join. + //(If behavior the join changes so that it is not enforced anymore, remove this + //condition!) + continue; + } + if (!dealloc) + make_clone(filtered_res, filtered_res, acc); + acc.push_back(instruction::mk_filter_identical(filtered_res, indexes.size(), indexes.c_ptr())); + dealloc = true; + } + + //enforce negative predicates + unsigned ut_len=r->get_uninterpreted_tail_size(); + for(unsigned i=pt_len; iget_tail(i); + func_decl * neg_pred = neg_tail->get_decl(); + variable_intersection neg_intersection(m_context.get_manager()); + neg_intersection.populate(single_res_expr, neg_tail); + unsigned_vector t_cols(neg_intersection.size(), neg_intersection.get_cols1()); + unsigned_vector neg_cols(neg_intersection.size(), neg_intersection.get_cols2()); + + unsigned neg_len = neg_tail->get_num_args(); + for(unsigned i=0; iget_arg(i); + if(is_var(e)) { + continue; + } + SASSERT(is_app(e)); + relation_sort arg_sort; + m_context.get_rel_context().get_rmanager().from_predicate(neg_pred, i, arg_sort); + reg_idx new_reg; + bool new_dealloc; + make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, new_dealloc, acc); + + if (dealloc) + make_dealloc_non_void(filtered_res, acc); + dealloc = new_dealloc; + filtered_res = new_reg; // here filtered_res value gets changed !! + + t_cols.push_back(single_res_expr.size()); + neg_cols.push_back(i); + single_res_expr.push_back(e); + } + SASSERT(t_cols.size()==neg_cols.size()); + + reg_idx neg_reg = m_pred_regs.find(neg_pred); + if (!dealloc) + make_clone(filtered_res, filtered_res, acc); + acc.push_back(instruction::mk_filter_by_negation(filtered_res, neg_reg, t_cols.size(), + t_cols.c_ptr(), neg_cols.c_ptr())); + dealloc = true; + } + + // enforce interpreted tail predicates + unsigned ft_len=r->get_tail_size(); //full tail + for(unsigned tail_index=ut_len; tail_indexget_tail(tail_index); + ptr_vector t_vars; + ::get_free_vars(t, t_vars); + + if(t_vars.empty()) { + expr_ref simplified(m); + m_context.get_rewriter()(t, simplified); + if(m.is_true(simplified)) { + //this tail element is always true + continue; + } + //the tail of this rule is never satisfied + SASSERT(m.is_false(simplified)); + goto finish; + } + + //determine binding size + while (!t_vars.back()) { + t_vars.pop_back(); + } + unsigned max_var = t_vars.size(); + + //create binding + expr_ref_vector binding(m); + binding.resize(max_var+1); + + for(unsigned v = 0; v < t_vars.size(); ++v) { + if (!t_vars[v]) { + continue; + } + int2ints::entry * e = var_indexes.find_core(v); + if(!e) { + //we have an unbound variable, so we add an unbound column for it + relation_sort unbound_sort = t_vars[v]; + + reg_idx new_reg; + TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";); + bool new_dealloc; + make_add_unbound_column(r, 0, head_pred, filtered_res, unbound_sort, new_reg, new_dealloc, acc); + + if (dealloc) + make_dealloc_non_void(filtered_res, acc); + dealloc = new_dealloc; + filtered_res = new_reg; // here filtered_res value gets changed !! + + unsigned unbound_column_index = single_res_expr.size(); + single_res_expr.push_back(m.mk_var(v, unbound_sort)); + + e = var_indexes.insert_if_not_there2(v, unsigned_vector()); + e->get_data().m_value.push_back(unbound_column_index); + } + unsigned src_col=e->get_data().m_value.back(); + relation_sort var_sort = m_reg_signatures[filtered_res][src_col]; + binding[max_var-v]=m.mk_var(src_col, var_sort); + } + + + expr_ref renamed(m); + m_context.get_var_subst()(t, binding.size(), binding.c_ptr(), renamed); + app_ref app_renamed(to_app(renamed), m); + if (!dealloc) + make_clone(filtered_res, filtered_res, acc); + acc.push_back(instruction::mk_filter_interpreted(filtered_res, app_renamed)); + dealloc = true; + } + + { + //put together the columns of head relation + relation_signature & head_sig = m_reg_signatures[head_reg]; + svector head_acis; + unsigned_vector head_src_cols; + for(unsigned i=0; iget_arg(i); + if(is_var(exp)) { + unsigned var_num=to_var(exp)->get_idx(); + int2ints::entry * e = var_indexes.find_core(var_num); + if(e) { + unsigned_vector & binding_indexes = e->get_data().m_value; + aci.kind=ACK_BOUND_VAR; + aci.source_column=binding_indexes.back(); + SASSERT(aci.source_column1) { + //if possible, we do not want multiple head columns + //point to a single column in the intermediate table, + //since then we would have to duplicate the column + //(and remove columns we did not point to at all) + binding_indexes.pop_back(); + } + } + else { + aci.kind=ACK_UNBOUND_VAR; + aci.var_index=var_num; + } + } + else { + SASSERT(is_app(exp)); + SASSERT(m_context.get_decl_util().is_numeral_ext(exp)); + aci.kind=ACK_CONSTANT; + aci.constant=to_app(exp); + } + head_acis.push_back(aci); + } + SASSERT(head_acis.size()==head_len); + + reg_idx new_head_reg; + make_assembling_code(r, head_pred, filtered_res, head_acis, new_head_reg, dealloc, acc); + + //update the head relation + make_union(new_head_reg, head_reg, delta_reg, use_widening, acc); + if (dealloc) + make_dealloc_non_void(new_head_reg, acc); + } + + finish: + m_instruction_observer.finish_rule(); + } + + void compiler::add_unbound_columns_for_negation(rule* r, func_decl* pred, reg_idx& single_res, expr_ref_vector& single_res_expr, + bool & dealloc, instruction_block & acc) { + uint_set pos_vars; + u_map neg_vars; + ast_manager& m = m_context.get_manager(); + unsigned pt_len = r->get_positive_tail_size(); + unsigned ut_len = r->get_uninterpreted_tail_size(); + if (pt_len == ut_len || pt_len == 0) { + return; + } + // populate negative variables: + for (unsigned i = pt_len; i < ut_len; ++i) { + app * neg_tail = r->get_tail(i); + unsigned neg_len = neg_tail->get_num_args(); + for (unsigned j = 0; j < neg_len; ++j) { + expr * e = neg_tail->get_arg(j); + if (is_var(e)) { + neg_vars.insert(to_var(e)->get_idx(), e); + } + } + } + // populate positive variables: + for (unsigned i = 0; i < single_res_expr.size(); ++i) { + expr* e = single_res_expr[i].get(); + if (is_var(e)) { + pos_vars.insert(to_var(e)->get_idx()); + } + } + // add negative variables that are not in positive: + u_map::iterator it = neg_vars.begin(), end = neg_vars.end(); + for (; it != end; ++it) { + unsigned v = it->m_key; + expr* e = it->m_value; + if (!pos_vars.contains(v)) { + single_res_expr.push_back(e); + reg_idx new_single_res; + bool new_dealloc; + make_add_unbound_column(r, v, pred, single_res, m.get_sort(e), new_single_res, new_dealloc, acc); + if (dealloc) + make_dealloc_non_void(single_res, acc); + dealloc = new_dealloc; + single_res = new_single_res; + TRACE("dl", tout << "Adding unbound column: " << mk_pp(e, m) << "\n";); + } + } + } + + void compiler::compile_rule_evaluation(rule * r, const pred2idx * input_deltas, + reg_idx output_delta, bool use_widening, instruction_block & acc) { + typedef std::pair tail_delta_info; //(delta register, tail index) + typedef svector tail_delta_infos; + + unsigned rule_len = r->get_uninterpreted_tail_size(); + reg_idx head_reg = m_pred_regs.find(r->get_decl()); + + svector tail_regs; + tail_delta_infos tail_deltas; + for(unsigned j=0;jget_tail(j)->get_decl(); + reg_idx tail_reg = m_pred_regs.find(tail_pred); + tail_regs.push_back(tail_reg); + + if(input_deltas && !all_or_nothing_deltas()) { + reg_idx tail_delta_idx; + if(input_deltas->find(tail_pred, tail_delta_idx)) { + tail_deltas.push_back(tail_delta_info(tail_delta_idx, j)); + } + } + } + + if(!input_deltas || all_or_nothing_deltas()) { + compile_rule_evaluation_run(r, head_reg, tail_regs.c_ptr(), output_delta, use_widening, acc); + } + else { + tail_delta_infos::iterator tdit = tail_deltas.begin(); + tail_delta_infos::iterator tdend = tail_deltas.end(); + for(; tdit!=tdend; ++tdit) { + tail_delta_info tdinfo = *tdit; + flet flet_tail_reg(tail_regs[tdinfo.second], tdinfo.first); + compile_rule_evaluation_run(r, head_reg, tail_regs.c_ptr(), output_delta, use_widening, acc); + } + } + } + + class cycle_breaker + { + typedef func_decl * T; + typedef rule_dependencies::item_set item_set; //set of T + + rule_dependencies & m_deps; + rule_set const& m_rules; + context& m_context; + item_set & m_removed; + svector m_stack; + ast_mark m_visited; + + void traverse(T v) { + SASSERT(!m_visited.is_marked(v)); + if (m_removed.contains(v)) { + return; + } + + m_stack.push_back(v); + m_visited.mark(v, true); + + const item_set & deps = m_deps.get_deps(v); + item_set::iterator it = deps.begin(); + item_set::iterator end = deps.end(); + for(; it!=end; ++it) { + T d = *it; + if (m_visited.is_marked(d)) { + //TODO: find the best vertex to remove in the cycle + remove_from_stack(); + continue; + } + traverse(d); + } + SASSERT(m_stack.back()==v); + + m_stack.pop_back(); + m_visited.mark(v, false); + } + + void remove_from_stack() { + for (unsigned i = 0; i < m_stack.size(); ++i) { + func_decl* p = m_stack[i]; + if (m_context.has_facts(p)) { + m_removed.insert(p); + return; + } + + rule_vector const& rules = m_rules.get_predicate_rules(p); + unsigned stratum = m_rules.get_predicate_strat(p); + for (unsigned j = 0; j < rules.size(); ++j) { + rule const& r = *rules[j]; + bool ok = true; + for (unsigned k = 0; ok && k < r.get_uninterpreted_tail_size(); ++k) { + ok = m_rules.get_predicate_strat(r.get_decl(k)) < stratum; + } + if (ok) { + m_removed.insert(p); + return; + } + } + } + + // nothing was found. + m_removed.insert(m_stack.back()); + } + + public: + cycle_breaker(rule_dependencies & deps, rule_set const& rules, context& ctx, item_set & removed) + : m_deps(deps), m_rules(rules), m_context(ctx), m_removed(removed) { SASSERT(removed.empty()); } + + void operator()() { + rule_dependencies::iterator it = m_deps.begin(); + rule_dependencies::iterator end = m_deps.end(); + for(; it!=end; ++it) { + T v = it->m_key; + traverse(v); + } + m_deps.remove(m_removed); + } + }; + + void compiler::detect_chains(const func_decl_set & preds, func_decl_vector & ordered_preds, + func_decl_set & global_deltas) { + typedef obj_map pred2pred; + + SASSERT(ordered_preds.empty()); + SASSERT(global_deltas.empty()); + + rule_dependencies deps(m_rule_set.get_dependencies()); + deps.restrict(preds); + cycle_breaker(deps, m_rule_set, m_context, global_deltas)(); + VERIFY( deps.sort_deps(ordered_preds) ); + + //the predicates that were removed to get acyclic induced subgraph are put last + //so that all their local input deltas are already populated + func_decl_set::iterator gdit = global_deltas.begin(); + func_decl_set::iterator gend = global_deltas.end(); + for(; gdit!=gend; ++gdit) { + ordered_preds.push_back(*gdit); + } + } + + void compiler::compile_preds(const func_decl_vector & head_preds, const func_decl_set & widened_preds, + const pred2idx * input_deltas, const pred2idx & output_deltas, instruction_block & acc) { + func_decl_vector::const_iterator hpit = head_preds.begin(); + func_decl_vector::const_iterator hpend = head_preds.end(); + for(; hpit!=hpend; ++hpit) { + func_decl * head_pred = *hpit; + + bool widen_predicate_in_loop = widened_preds.contains(head_pred); + + reg_idx d_head_reg; //output delta for the initial rule execution + if(!output_deltas.find(head_pred, d_head_reg)) { + d_head_reg = execution_context::void_register; + } + + const rule_vector & pred_rules = m_rule_set.get_predicate_rules(head_pred); + rule_vector::const_iterator rit = pred_rules.begin(); + rule_vector::const_iterator rend = pred_rules.end(); + for(; rit!=rend; ++rit) { + rule * r = *rit; + SASSERT(head_pred==r->get_decl()); + + compile_rule_evaluation(r, input_deltas, d_head_reg, widen_predicate_in_loop, acc); + } + } + } + + void compiler::compile_preds_init(const func_decl_vector & head_preds, const func_decl_set & widened_preds, + const pred2idx * input_deltas, const pred2idx & output_deltas, instruction_block & acc) { + func_decl_vector::const_iterator hpit = head_preds.begin(); + func_decl_vector::const_iterator hpend = head_preds.end(); + reg_idx void_reg = execution_context::void_register; + for(; hpit!=hpend; ++hpit) { + func_decl * head_pred = *hpit; + const rule_vector & pred_rules = m_rule_set.get_predicate_rules(head_pred); + rule_vector::const_iterator rit = pred_rules.begin(); + rule_vector::const_iterator rend = pred_rules.end(); + unsigned stratum = m_rule_set.get_predicate_strat(head_pred); + + for(; rit != rend; ++rit) { + rule * r = *rit; + SASSERT(head_pred==r->get_decl()); + + for (unsigned i = 0; i < r->get_uninterpreted_tail_size(); ++i) { + unsigned stratum1 = m_rule_set.get_predicate_strat(r->get_decl(i)); + if (stratum1 >= stratum) { + goto next_loop; + } + } + compile_rule_evaluation(r, input_deltas, void_reg, false, acc); + next_loop: + ; + } + + reg_idx d_head_reg; + if (output_deltas.find(head_pred, d_head_reg)) { + acc.push_back(instruction::mk_clone(m_pred_regs.find(head_pred), d_head_reg)); + } + } + } + + void compiler::make_inloop_delta_transition(const pred2idx & global_head_deltas, + const pred2idx & global_tail_deltas, const pred2idx & local_deltas, instruction_block & acc) { + //move global head deltas into tail ones + pred2idx::iterator gdit = global_head_deltas.begin(); + pred2idx::iterator gend = global_head_deltas.end(); + for(; gdit!=gend; ++gdit) { + func_decl * pred = gdit->m_key; + reg_idx head_reg = gdit->m_value; + reg_idx tail_reg = global_tail_deltas.find(pred); + acc.push_back(instruction::mk_move(head_reg, tail_reg)); + } + //empty local deltas + pred2idx::iterator lit = local_deltas.begin(); + pred2idx::iterator lend = local_deltas.end(); + for(; lit!=lend; ++lit) { + acc.push_back(instruction::mk_dealloc(lit->m_value)); + } + } + + void compiler::compile_loop(const func_decl_vector & head_preds, const func_decl_set & widened_preds, + const pred2idx & global_head_deltas, const pred2idx & global_tail_deltas, + const pred2idx & local_deltas, instruction_block & acc) { + instruction_block * loop_body = alloc(instruction_block); + loop_body->set_observer(&m_instruction_observer); + + pred2idx all_head_deltas(global_head_deltas); + unite_disjoint_maps(all_head_deltas, local_deltas); + pred2idx all_tail_deltas(global_tail_deltas); + unite_disjoint_maps(all_tail_deltas, local_deltas); + + //generate code for the iterative fixpoint search + //The order in which we iterate the preds_vector matters, since rules can depend on + //deltas generated earlier in the same iteration. + compile_preds(head_preds, widened_preds, &all_tail_deltas, all_head_deltas, *loop_body); + + svector loop_control_regs; //loop is controlled by global src regs + collect_map_range(loop_control_regs, global_tail_deltas); + //move target deltas into source deltas at the end of the loop + //and clear local deltas + make_inloop_delta_transition(global_head_deltas, global_tail_deltas, local_deltas, *loop_body); + + loop_body->set_observer(0); + acc.push_back(instruction::mk_while_loop(loop_control_regs.size(), + loop_control_regs.c_ptr(), loop_body)); + } + + void compiler::compile_dependent_rules(const func_decl_set & head_preds, + const pred2idx * input_deltas, const pred2idx & output_deltas, + bool add_saturation_marks, instruction_block & acc) { + + if (!output_deltas.empty()) { + func_decl_set::iterator hpit = head_preds.begin(); + func_decl_set::iterator hpend = head_preds.end(); + for(; hpit!=hpend; ++hpit) { + if(output_deltas.contains(*hpit)) { + //we do not support retrieving deltas for rules that are inside a recursive + //stratum, since we would have to maintain this 'global' delta through the loop + //iterations + NOT_IMPLEMENTED_YET(); + } + } + } + + func_decl_vector preds_vector; + func_decl_set global_deltas; + + detect_chains(head_preds, preds_vector, global_deltas); + + func_decl_set local_deltas(head_preds); + set_difference(local_deltas, global_deltas); + + pred2idx d_global_src; //these deltas serve as sources of tuples for rule evaluation inside the loop + get_fresh_registers(global_deltas, d_global_src); + pred2idx d_global_tgt; //these deltas are targets for new tuples in rule evaluation inside the loop + get_fresh_registers(global_deltas, d_global_tgt); + pred2idx d_local; + get_fresh_registers(local_deltas, d_local); + + pred2idx d_all_src(d_global_src); //src together with local deltas + unite_disjoint_maps(d_all_src, d_local); + pred2idx d_all_tgt(d_global_tgt); //tgt together with local deltas + unite_disjoint_maps(d_all_tgt, d_local); + + + func_decl_set empty_func_decl_set; + + //generate code for the initial run + // compile_preds(preds_vector, empty_func_decl_set, input_deltas, d_global_src, acc); + compile_preds_init(preds_vector, empty_func_decl_set, input_deltas, d_global_src, acc); + + if (compile_with_widening()) { + compile_loop(preds_vector, global_deltas, d_global_tgt, d_global_src, d_local, acc); + } + else { + compile_loop(preds_vector, empty_func_decl_set, d_global_tgt, d_global_src, d_local, acc); + } + + + if(add_saturation_marks) { + //after the loop finishes, all predicates in the group are saturated, + //so we may mark them as such + func_decl_set::iterator fdit = head_preds.begin(); + func_decl_set::iterator fdend = head_preds.end(); + for(; fdit!=fdend; ++fdit) { + acc.push_back(instruction::mk_mark_saturated(m_context.get_manager(), *fdit)); + } + } + } + + bool compiler::is_nonrecursive_stratum(const func_decl_set & preds) const { + SASSERT(preds.size()>0); + if(preds.size()>1) { + return false; + } + func_decl * head_pred = *preds.begin(); + const rule_vector & rules = m_rule_set.get_predicate_rules(head_pred); + rule_vector::const_iterator it = rules.begin(); + rule_vector::const_iterator end = rules.end(); + for(; it!=end; ++it) { + //it is sufficient to check just for presence of the first head predicate, + //since if the rules are recursive and their heads are strongly connected by dependence, + //this predicate must appear in some tail + if((*it)->is_in_tail(head_pred)) { + return false; + } + } + return true; + } + + void compiler::compile_nonrecursive_stratum(const func_decl_set & preds, + const pred2idx * input_deltas, const pred2idx & output_deltas, + bool add_saturation_marks, instruction_block & acc) { + //non-recursive stratum always has just one head predicate + SASSERT(preds.size()==1); + SASSERT(is_nonrecursive_stratum(preds)); + func_decl * head_pred = *preds.begin(); + const rule_vector & rules = m_rule_set.get_predicate_rules(head_pred); + + + + reg_idx output_delta; + if (!output_deltas.find(head_pred, output_delta)) { + output_delta = execution_context::void_register; + } + + rule_vector::const_iterator it = rules.begin(); + rule_vector::const_iterator end = rules.end(); + for (; it != end; ++it) { + rule * r = *it; + SASSERT(r->get_decl()==head_pred); + + compile_rule_evaluation(r, input_deltas, output_delta, false, acc); + } + + if (add_saturation_marks) { + //now the predicate is saturated, so we may mark it as such + acc.push_back(instruction::mk_mark_saturated(m_context.get_manager(), head_pred)); + } + } + + bool compiler::all_saturated(const func_decl_set & preds) const { + func_decl_set::iterator fdit = preds.begin(); + func_decl_set::iterator fdend = preds.end(); + for(; fdit!=fdend; ++fdit) { + if(!m_context.get_rel_context().get_rmanager().is_saturated(*fdit)) { + return false; + } + } + return true; + } + + void compiler::compile_strats(const rule_stratifier & stratifier, + const pred2idx * input_deltas, const pred2idx & output_deltas, + bool add_saturation_marks, instruction_block & acc) { + rule_set::pred_set_vector strats = stratifier.get_strats(); + rule_set::pred_set_vector::const_iterator sit = strats.begin(); + rule_set::pred_set_vector::const_iterator send = strats.end(); + for(; sit!=send; ++sit) { + func_decl_set & strat_preds = **sit; + + if (all_saturated(strat_preds)) { + //all predicates in stratum are saturated, so no need to compile rules for them + continue; + } + + TRACE("dl", + tout << "Stratum: "; + func_decl_set::iterator pit = strat_preds.begin(); + func_decl_set::iterator pend = strat_preds.end(); + for(; pit!=pend; ++pit) { + func_decl * pred = *pit; + tout << pred->get_name() << " "; + } + tout << "\n"; + ); + + if (is_nonrecursive_stratum(strat_preds)) { + //this stratum contains just a single non-recursive rule + compile_nonrecursive_stratum(strat_preds, input_deltas, output_deltas, add_saturation_marks, acc); + } + else { + compile_dependent_rules(strat_preds, input_deltas, output_deltas, + add_saturation_marks, acc); + } + } + } + + void compiler::do_compilation(instruction_block & execution_code, + instruction_block & termination_code) { + + unsigned rule_cnt=m_rule_set.get_num_rules(); + if(rule_cnt==0) { + return; + } + + instruction_block & acc = execution_code; + acc.set_observer(&m_instruction_observer); + + + //load predicate data + for(unsigned i=0;iget_decl(), acc); + + unsigned rule_len = r->get_uninterpreted_tail_size(); + for(unsigned j=0;jget_tail(j)->get_decl(), acc); + } + } + + pred2idx empty_pred2idx_map; + + compile_strats(m_rule_set.get_stratifier(), static_cast(0), + empty_pred2idx_map, true, execution_code); + + + + //store predicate data + pred2idx::iterator pit = m_pred_regs.begin(); + pred2idx::iterator pend = m_pred_regs.end(); + for(; pit!=pend; ++pit) { + pred2idx::key_data & e = *pit; + func_decl * pred = e.m_key; + reg_idx reg = e.m_value; + termination_code.push_back(instruction::mk_store(m_context.get_manager(), pred, reg)); + } + + acc.set_observer(0); + + TRACE("dl", execution_code.display(m_context.get_rel_context(), tout);); + } + + +} + From 1917c909d8ba44a15d6e06b3e13541751bff6d9c Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 23 Apr 2013 11:28:09 -0700 Subject: [PATCH 103/281] delete garbage Signed-off-by: Nuno Lopes --- src/muz_qe/dl_compiler.cpp.orig | 1245 ------------------------------- 1 file changed, 1245 deletions(-) delete mode 100644 src/muz_qe/dl_compiler.cpp.orig diff --git a/src/muz_qe/dl_compiler.cpp.orig b/src/muz_qe/dl_compiler.cpp.orig deleted file mode 100644 index e4528426a..000000000 --- a/src/muz_qe/dl_compiler.cpp.orig +++ /dev/null @@ -1,1245 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_compiler.cpp - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-14. - -Revision History: - ---*/ - - -#include -#include"ref_vector.h" -#include"dl_context.h" -#include"dl_rule.h" -#include"dl_util.h" -#include"dl_compiler.h" -#include"ast_pp.h" -#include"ast_smt2_pp.h" - - -namespace datalog { - - void compiler::reset() { - m_pred_regs.reset(); - m_new_reg = 0; - } - - void compiler::ensure_predicate_loaded(func_decl * pred, instruction_block & acc) { - pred2idx::obj_map_entry * e = m_pred_regs.insert_if_not_there2(pred, UINT_MAX); - if(e->get_data().m_value!=UINT_MAX) { - //predicate is already loaded - return; - } - relation_signature sig; - m_context.get_rel_context().get_rmanager().from_predicate(pred, sig); - reg_idx reg = get_fresh_register(sig); - e->get_data().m_value=reg; - - acc.push_back(instruction::mk_load(m_context.get_manager(), pred, reg)); - } - - void compiler::make_join(reg_idx t1, reg_idx t2, const variable_intersection & vars, reg_idx & result, - instruction_block & acc) { - relation_signature res_sig; - relation_signature::from_join(m_reg_signatures[t1], m_reg_signatures[t2], vars.size(), - vars.get_cols1(), vars.get_cols2(), res_sig); - result = get_fresh_register(res_sig); - acc.push_back(instruction::mk_join(t1, t2, vars.size(), vars.get_cols1(), vars.get_cols2(), result)); - } - - void compiler::make_join_project(reg_idx t1, reg_idx t2, const variable_intersection & vars, - const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc) { - relation_signature aux_sig; - relation_signature sig1 = m_reg_signatures[t1]; - relation_signature sig2 = m_reg_signatures[t2]; - relation_signature::from_join(sig1, sig2, vars.size(), vars.get_cols1(), vars.get_cols2(), aux_sig); - relation_signature res_sig; - relation_signature::from_project(aux_sig, removed_cols.size(), removed_cols.c_ptr(), - res_sig); - result = get_fresh_register(res_sig); - - acc.push_back(instruction::mk_join_project(t1, t2, vars.size(), vars.get_cols1(), - vars.get_cols2(), removed_cols.size(), removed_cols.c_ptr(), result)); - } - - void compiler::make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col, - reg_idx & result, instruction_block & acc) { - relation_signature res_sig; - relation_signature::from_project(m_reg_signatures[src], 1, &col, res_sig); - result = get_fresh_register(res_sig); - acc.push_back(instruction::mk_select_equal_and_project(m_context.get_manager(), - src, val, col, result)); - } - - void compiler::make_clone(reg_idx src, reg_idx & result, instruction_block & acc) { - relation_signature sig = m_reg_signatures[src]; - result = get_fresh_register(sig); - acc.push_back(instruction::mk_clone(src, result)); - } - - void compiler::make_union(reg_idx src, reg_idx tgt, reg_idx delta, bool use_widening, - instruction_block & acc) { - SASSERT(m_reg_signatures[src]==m_reg_signatures[tgt]); - SASSERT(delta==execution_context::void_register || m_reg_signatures[src]==m_reg_signatures[delta]); - - if (use_widening) { - acc.push_back(instruction::mk_widen(src, tgt, delta)); - } - else { - acc.push_back(instruction::mk_union(src, tgt, delta)); - } - } - - void compiler::make_projection(reg_idx src, unsigned col_cnt, const unsigned * removed_cols, - reg_idx & result, instruction_block & acc) { - SASSERT(col_cnt>0); - - relation_signature res_sig; - relation_signature::from_project(m_reg_signatures[src], col_cnt, removed_cols, res_sig); - result = get_fresh_register(res_sig); - acc.push_back(instruction::mk_projection(src, col_cnt, removed_cols, result)); - } - - compiler::reg_idx compiler::get_fresh_register(const relation_signature & sig) { - //since we might be resizing the m_reg_signatures vector, the argument must not point inside it - SASSERT((&sig>=m_reg_signatures.end()) || (&sigto_formula(e); - verbose_stream() << "Compiling unsafe rule column " << col_idx << "\n" - << mk_ismt2_pp(e, m_context.get_manager()) << "\n"; - }); - reg_idx total_table; - if (!m_total_registers.find(s, pred, total_table)) { - total_table = get_single_column_register(s); - relation_signature sig; - sig.push_back(s); - m_top_level_code.push_back(instruction::mk_total(sig, pred, total_table)); - m_total_registers.insert(s, pred, total_table); - } - if(src == execution_context::void_register) { - result = total_table; - dealloc = false; - } - else { - variable_intersection empty_vars(m_context.get_manager()); - make_join(src, total_table, empty_vars, result, acc); - dealloc = true; - } - } - - void compiler::make_full_relation(func_decl* pred, const relation_signature & sig, reg_idx & result, - instruction_block & acc) { - SASSERT(sig.empty()); - TRACE("dl", tout << "Adding unbound column " << mk_pp(pred, m_context.get_manager()) << "\n";); - if (m_empty_tables_registers.find(pred, result)) - return; - - result = get_fresh_register(sig); - m_top_level_code.push_back(instruction::mk_total(sig, pred, result)); - m_empty_tables_registers.insert(pred, result); - } - - - void compiler::make_duplicate_column(reg_idx src, unsigned col, reg_idx & result, - instruction_block & acc) { - - relation_signature & src_sig = m_reg_signatures[src]; - reg_idx single_col_reg; - unsigned src_col_cnt = src_sig.size(); - if(src_col_cnt==1) { - single_col_reg = src; - } - else { - unsigned_vector removed_cols; - for(unsigned i=0; i & acis0, - reg_idx & result, - bool & dealloc, - instruction_block & acc) { - - TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";); - - unsigned col_cnt = acis0.size(); - reg_idx curr = src; - - relation_signature empty_signature; - - relation_signature * curr_sig; - if(curr!=execution_context::void_register) { - curr_sig = & m_reg_signatures[curr]; - } - else { - curr_sig = & empty_signature; - } - unsigned src_col_cnt=curr_sig->size(); - - svector acis(acis0); - int2int handled_unbound; - - //first remove unused source columns - int_set referenced_src_cols; - for(unsigned i=0; isize(); - if(acis[i].kind==ACK_CONSTANT) { - make_add_constant_column(head_pred, curr, acis[i].domain, acis[i].constant, new_curr, new_dealloc, acc); - } - else { - SASSERT(acis[i].kind==ACK_UNBOUND_VAR); - make_add_unbound_column(compiled_rule, i, head_pred, curr, acis[i].domain, new_curr, new_dealloc, acc); - handled_unbound.insert(acis[i].var_index,bound_column_index); - } - if (dealloc) - make_dealloc_non_void(curr, acc); - dealloc = new_dealloc; - curr=new_curr; - curr_sig = & m_reg_signatures[curr]; - SASSERT(bound_column_index==curr_sig->size()-1); - } - SASSERT((*curr_sig)[bound_column_index]==acis[i].domain); - acis[i].kind=ACK_BOUND_VAR; - acis[i].source_column=bound_column_index; - } - - //duplicate needed source columns - int_set used_cols; - for(unsigned i=0; isize()-1; - SASSERT((*curr_sig)[bound_column_index]==acis[i].domain); - acis[i].source_column=bound_column_index; - } - - //reorder source columns to match target - SASSERT(curr_sig->size()==col_cnt); //now the intermediate table is a permutation - for(unsigned i=0; i=i); //columns below i are already reordered - SASSERT(nextget_num_args(); - for(unsigned i = 0; iget_arg(i); - if(!is_var(e) || globals.get(to_var(e)->get_idx())!=0) { - continue; - } - res.push_back(i+ofs); - } - } - - void compiler::get_local_indexes_for_projection(rule * r, unsigned_vector & res) { - SASSERT(r->get_positive_tail_size()==2); - ast_manager & m = m_context.get_manager(); - rule_counter counter; - counter.count_rule_vars(m, r); - app * t1 = r->get_tail(0); - app * t2 = r->get_tail(1); - counter.count_vars(m, t1, -1); - counter.count_vars(m, t2, -1); - get_local_indexes_for_projection(t1, counter, 0, res); - get_local_indexes_for_projection(t2, counter, t1->get_num_args(), res); - } - - void compiler::compile_rule_evaluation_run(rule * r, reg_idx head_reg, const reg_idx * tail_regs, - reg_idx delta_reg, bool use_widening, instruction_block & acc) { - - ast_manager & m = m_context.get_manager(); - m_instruction_observer.start_rule(r); - - const app * h = r->get_head(); - unsigned head_len = h->get_num_args(); - func_decl * head_pred = h->get_decl(); - - TRACE("dl", r->display(m_context, tout); ); - - unsigned pt_len = r->get_positive_tail_size(); - SASSERT(pt_len<=2); //we require rules to be processed by the mk_simple_joins rule transformer plugin - - reg_idx single_res; - expr_ref_vector single_res_expr(m); - - //used to save on filter_identical instructions where the check is already done - //by the join operation - unsigned second_tail_arg_ofs; - - // whether to dealloc the previous result - bool dealloc = true; - - if(pt_len == 2) { - reg_idx t1_reg=tail_regs[0]; - reg_idx t2_reg=tail_regs[1]; - app * a1 = r->get_tail(0); - app * a2 = r->get_tail(1); - SASSERT(m_reg_signatures[t1_reg].size()==a1->get_num_args()); - SASSERT(m_reg_signatures[t2_reg].size()==a2->get_num_args()); - - variable_intersection a1a2(m_context.get_manager()); - a1a2.populate(a1,a2); - - unsigned_vector removed_cols; - get_local_indexes_for_projection(r, removed_cols); - - if(removed_cols.empty()) { - make_join(t1_reg, t2_reg, a1a2, single_res, acc); - } - else { - make_join_project(t1_reg, t2_reg, a1a2, removed_cols, single_res, acc); - } - - unsigned rem_index = 0; - unsigned rem_sz = removed_cols.size(); - unsigned a1len=a1->get_num_args(); - for(unsigned i=0; i=i); - if(rem_indexget_arg(i)); - } - second_tail_arg_ofs = single_res_expr.size(); - unsigned a2len=a2->get_num_args(); - for(unsigned i=0; i=i+a1len); - if(rem_indexget_arg(i)); - } - SASSERT(rem_index==rem_sz); - } - else if(pt_len==1) { - reg_idx t_reg=tail_regs[0]; - app * a = r->get_tail(0); - SASSERT(m_reg_signatures[t_reg].size()==a->get_num_args()); - - single_res = t_reg; - - unsigned n=a->get_num_args(); - for(unsigned i=0; iget_arg(i); - if(is_app(arg)) { - app * c = to_app(arg); //argument is a constant - SASSERT(c->get_num_args()==0); - SASSERT(m_context.get_decl_util().is_numeral_ext(arg)); - reg_idx new_reg; - make_select_equal_and_project(single_res, c, single_res_expr.size(), new_reg, acc); - if(single_res!=t_reg) { - //since single_res is a local register, we deallocate it - make_dealloc_non_void(single_res, acc); - } - single_res = new_reg; - } - else { - SASSERT(is_var(arg)); - single_res_expr.push_back(arg); - } - } - if(single_res==t_reg) { - dealloc = false; - } - - } - else { - SASSERT(pt_len==0); - - //single_res register should never be used in this case - single_res=execution_context::void_register; - } - - add_unbound_columns_for_negation(r, head_pred, single_res, single_res_expr, dealloc, acc); - - int2ints var_indexes; - - reg_idx filtered_res = single_res; - - { - //enforce equality to constants - unsigned srlen=single_res_expr.size(); - SASSERT((single_res==execution_context::void_register) ? (srlen==0) : (srlen==m_reg_signatures[single_res].size())); - for(unsigned i=0; iget_idx(); - int2ints::entry * e = var_indexes.insert_if_not_there2(var_num, unsigned_vector()); - e->get_data().m_value.push_back(i); - } - } - } - - //enforce equality of columns - int2ints::iterator vit=var_indexes.begin(); - int2ints::iterator vend=var_indexes.end(); - for(; vit!=vend; ++vit) { - int2ints::key_data & k = *vit; - unsigned_vector & indexes = k.m_value; - if(indexes.size()==1) { - continue; - } - SASSERT(indexes.size()>1); - if(pt_len==2 && indexes[0]=second_tail_arg_ofs) { - //If variable appears in multiple tails, the identicity will already be enforced by join. - //(If behavior the join changes so that it is not enforced anymore, remove this - //condition!) - continue; - } - if (!dealloc) - make_clone(filtered_res, filtered_res, acc); - acc.push_back(instruction::mk_filter_identical(filtered_res, indexes.size(), indexes.c_ptr())); - dealloc = true; - } - - //enforce negative predicates - unsigned ut_len=r->get_uninterpreted_tail_size(); - for(unsigned i=pt_len; iget_tail(i); - func_decl * neg_pred = neg_tail->get_decl(); - variable_intersection neg_intersection(m_context.get_manager()); - neg_intersection.populate(single_res_expr, neg_tail); - unsigned_vector t_cols(neg_intersection.size(), neg_intersection.get_cols1()); - unsigned_vector neg_cols(neg_intersection.size(), neg_intersection.get_cols2()); - - unsigned neg_len = neg_tail->get_num_args(); - for(unsigned i=0; iget_arg(i); - if(is_var(e)) { - continue; - } - SASSERT(is_app(e)); - relation_sort arg_sort; - m_context.get_rel_context().get_rmanager().from_predicate(neg_pred, i, arg_sort); - reg_idx new_reg; - bool new_dealloc; - make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, new_dealloc, acc); - - if (dealloc) - make_dealloc_non_void(filtered_res, acc); - dealloc = new_dealloc; - filtered_res = new_reg; // here filtered_res value gets changed !! - - t_cols.push_back(single_res_expr.size()); - neg_cols.push_back(i); - single_res_expr.push_back(e); - } - SASSERT(t_cols.size()==neg_cols.size()); - - reg_idx neg_reg = m_pred_regs.find(neg_pred); - if (!dealloc) - make_clone(filtered_res, filtered_res, acc); - acc.push_back(instruction::mk_filter_by_negation(filtered_res, neg_reg, t_cols.size(), - t_cols.c_ptr(), neg_cols.c_ptr())); - dealloc = true; - } - - // enforce interpreted tail predicates - unsigned ft_len=r->get_tail_size(); //full tail - for(unsigned tail_index=ut_len; tail_indexget_tail(tail_index); - ptr_vector t_vars; - ::get_free_vars(t, t_vars); - - if(t_vars.empty()) { - expr_ref simplified(m); - m_context.get_rewriter()(t, simplified); - if(m.is_true(simplified)) { - //this tail element is always true - continue; - } - //the tail of this rule is never satisfied - SASSERT(m.is_false(simplified)); - goto finish; - } - - //determine binding size - while (!t_vars.back()) { - t_vars.pop_back(); - } - unsigned max_var = t_vars.size(); - - //create binding - expr_ref_vector binding(m); - binding.resize(max_var+1); - - for(unsigned v = 0; v < t_vars.size(); ++v) { - if (!t_vars[v]) { - continue; - } - int2ints::entry * e = var_indexes.find_core(v); - if(!e) { - //we have an unbound variable, so we add an unbound column for it - relation_sort unbound_sort = t_vars[v]; - - reg_idx new_reg; - TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";); - bool new_dealloc; - make_add_unbound_column(r, 0, head_pred, filtered_res, unbound_sort, new_reg, new_dealloc, acc); - - if (dealloc) - make_dealloc_non_void(filtered_res, acc); - dealloc = new_dealloc; - filtered_res = new_reg; // here filtered_res value gets changed !! - - unsigned unbound_column_index = single_res_expr.size(); - single_res_expr.push_back(m.mk_var(v, unbound_sort)); - - e = var_indexes.insert_if_not_there2(v, unsigned_vector()); - e->get_data().m_value.push_back(unbound_column_index); - } - unsigned src_col=e->get_data().m_value.back(); - relation_sort var_sort = m_reg_signatures[filtered_res][src_col]; - binding[max_var-v]=m.mk_var(src_col, var_sort); - } - - - expr_ref renamed(m); - m_context.get_var_subst()(t, binding.size(), binding.c_ptr(), renamed); - app_ref app_renamed(to_app(renamed), m); - if (!dealloc) - make_clone(filtered_res, filtered_res, acc); - acc.push_back(instruction::mk_filter_interpreted(filtered_res, app_renamed)); - dealloc = true; - } - - { - //put together the columns of head relation - relation_signature & head_sig = m_reg_signatures[head_reg]; - svector head_acis; - unsigned_vector head_src_cols; - for(unsigned i=0; iget_arg(i); - if(is_var(exp)) { - unsigned var_num=to_var(exp)->get_idx(); - int2ints::entry * e = var_indexes.find_core(var_num); - if(e) { - unsigned_vector & binding_indexes = e->get_data().m_value; - aci.kind=ACK_BOUND_VAR; - aci.source_column=binding_indexes.back(); - SASSERT(aci.source_column1) { - //if possible, we do not want multiple head columns - //point to a single column in the intermediate table, - //since then we would have to duplicate the column - //(and remove columns we did not point to at all) - binding_indexes.pop_back(); - } - } - else { - aci.kind=ACK_UNBOUND_VAR; - aci.var_index=var_num; - } - } - else { - SASSERT(is_app(exp)); - SASSERT(m_context.get_decl_util().is_numeral_ext(exp)); - aci.kind=ACK_CONSTANT; - aci.constant=to_app(exp); - } - head_acis.push_back(aci); - } - SASSERT(head_acis.size()==head_len); - - reg_idx new_head_reg; - make_assembling_code(r, head_pred, filtered_res, head_acis, new_head_reg, dealloc, acc); - - //update the head relation - make_union(new_head_reg, head_reg, delta_reg, use_widening, acc); - if (dealloc) - make_dealloc_non_void(new_head_reg, acc); - } - - finish: - m_instruction_observer.finish_rule(); - } - - void compiler::add_unbound_columns_for_negation(rule* r, func_decl* pred, reg_idx& single_res, expr_ref_vector& single_res_expr, - bool & dealloc, instruction_block & acc) { - uint_set pos_vars; - u_map neg_vars; - ast_manager& m = m_context.get_manager(); - unsigned pt_len = r->get_positive_tail_size(); - unsigned ut_len = r->get_uninterpreted_tail_size(); - if (pt_len == ut_len || pt_len == 0) { - return; - } - // populate negative variables: - for (unsigned i = pt_len; i < ut_len; ++i) { - app * neg_tail = r->get_tail(i); - unsigned neg_len = neg_tail->get_num_args(); - for (unsigned j = 0; j < neg_len; ++j) { - expr * e = neg_tail->get_arg(j); - if (is_var(e)) { - neg_vars.insert(to_var(e)->get_idx(), e); - } - } - } - // populate positive variables: - for (unsigned i = 0; i < single_res_expr.size(); ++i) { - expr* e = single_res_expr[i].get(); - if (is_var(e)) { - pos_vars.insert(to_var(e)->get_idx()); - } - } - // add negative variables that are not in positive: - u_map::iterator it = neg_vars.begin(), end = neg_vars.end(); - for (; it != end; ++it) { - unsigned v = it->m_key; - expr* e = it->m_value; - if (!pos_vars.contains(v)) { - single_res_expr.push_back(e); - reg_idx new_single_res; - bool new_dealloc; - make_add_unbound_column(r, v, pred, single_res, m.get_sort(e), new_single_res, new_dealloc, acc); - if (dealloc) - make_dealloc_non_void(single_res, acc); - dealloc = new_dealloc; - single_res = new_single_res; - TRACE("dl", tout << "Adding unbound column: " << mk_pp(e, m) << "\n";); - } - } - } - - void compiler::compile_rule_evaluation(rule * r, const pred2idx * input_deltas, - reg_idx output_delta, bool use_widening, instruction_block & acc) { - typedef std::pair tail_delta_info; //(delta register, tail index) - typedef svector tail_delta_infos; - - unsigned rule_len = r->get_uninterpreted_tail_size(); - reg_idx head_reg = m_pred_regs.find(r->get_decl()); - - svector tail_regs; - tail_delta_infos tail_deltas; - for(unsigned j=0;jget_tail(j)->get_decl(); - reg_idx tail_reg = m_pred_regs.find(tail_pred); - tail_regs.push_back(tail_reg); - - if(input_deltas && !all_or_nothing_deltas()) { - reg_idx tail_delta_idx; - if(input_deltas->find(tail_pred, tail_delta_idx)) { - tail_deltas.push_back(tail_delta_info(tail_delta_idx, j)); - } - } - } - - if(!input_deltas || all_or_nothing_deltas()) { - compile_rule_evaluation_run(r, head_reg, tail_regs.c_ptr(), output_delta, use_widening, acc); - } - else { - tail_delta_infos::iterator tdit = tail_deltas.begin(); - tail_delta_infos::iterator tdend = tail_deltas.end(); - for(; tdit!=tdend; ++tdit) { - tail_delta_info tdinfo = *tdit; - flet flet_tail_reg(tail_regs[tdinfo.second], tdinfo.first); - compile_rule_evaluation_run(r, head_reg, tail_regs.c_ptr(), output_delta, use_widening, acc); - } - } - } - - class cycle_breaker - { - typedef func_decl * T; - typedef rule_dependencies::item_set item_set; //set of T - - rule_dependencies & m_deps; - rule_set const& m_rules; - context& m_context; - item_set & m_removed; - svector m_stack; - ast_mark m_visited; - - void traverse(T v) { - SASSERT(!m_visited.is_marked(v)); - if (m_removed.contains(v)) { - return; - } - - m_stack.push_back(v); - m_visited.mark(v, true); - - const item_set & deps = m_deps.get_deps(v); - item_set::iterator it = deps.begin(); - item_set::iterator end = deps.end(); - for(; it!=end; ++it) { - T d = *it; - if (m_visited.is_marked(d)) { - //TODO: find the best vertex to remove in the cycle - remove_from_stack(); - continue; - } - traverse(d); - } - SASSERT(m_stack.back()==v); - - m_stack.pop_back(); - m_visited.mark(v, false); - } - - void remove_from_stack() { - for (unsigned i = 0; i < m_stack.size(); ++i) { - func_decl* p = m_stack[i]; - if (m_context.has_facts(p)) { - m_removed.insert(p); - return; - } - - rule_vector const& rules = m_rules.get_predicate_rules(p); - unsigned stratum = m_rules.get_predicate_strat(p); - for (unsigned j = 0; j < rules.size(); ++j) { - rule const& r = *rules[j]; - bool ok = true; - for (unsigned k = 0; ok && k < r.get_uninterpreted_tail_size(); ++k) { - ok = m_rules.get_predicate_strat(r.get_decl(k)) < stratum; - } - if (ok) { - m_removed.insert(p); - return; - } - } - } - - // nothing was found. - m_removed.insert(m_stack.back()); - } - - public: - cycle_breaker(rule_dependencies & deps, rule_set const& rules, context& ctx, item_set & removed) - : m_deps(deps), m_rules(rules), m_context(ctx), m_removed(removed) { SASSERT(removed.empty()); } - - void operator()() { - rule_dependencies::iterator it = m_deps.begin(); - rule_dependencies::iterator end = m_deps.end(); - for(; it!=end; ++it) { - T v = it->m_key; - traverse(v); - } - m_deps.remove(m_removed); - } - }; - - void compiler::detect_chains(const func_decl_set & preds, func_decl_vector & ordered_preds, - func_decl_set & global_deltas) { - typedef obj_map pred2pred; - - SASSERT(ordered_preds.empty()); - SASSERT(global_deltas.empty()); - - rule_dependencies deps(m_rule_set.get_dependencies()); - deps.restrict(preds); - cycle_breaker(deps, m_rule_set, m_context, global_deltas)(); - VERIFY( deps.sort_deps(ordered_preds) ); - - //the predicates that were removed to get acyclic induced subgraph are put last - //so that all their local input deltas are already populated - func_decl_set::iterator gdit = global_deltas.begin(); - func_decl_set::iterator gend = global_deltas.end(); - for(; gdit!=gend; ++gdit) { - ordered_preds.push_back(*gdit); - } - } - - void compiler::compile_preds(const func_decl_vector & head_preds, const func_decl_set & widened_preds, - const pred2idx * input_deltas, const pred2idx & output_deltas, instruction_block & acc) { - func_decl_vector::const_iterator hpit = head_preds.begin(); - func_decl_vector::const_iterator hpend = head_preds.end(); - for(; hpit!=hpend; ++hpit) { - func_decl * head_pred = *hpit; - - bool widen_predicate_in_loop = widened_preds.contains(head_pred); - - reg_idx d_head_reg; //output delta for the initial rule execution - if(!output_deltas.find(head_pred, d_head_reg)) { - d_head_reg = execution_context::void_register; - } - - const rule_vector & pred_rules = m_rule_set.get_predicate_rules(head_pred); - rule_vector::const_iterator rit = pred_rules.begin(); - rule_vector::const_iterator rend = pred_rules.end(); - for(; rit!=rend; ++rit) { - rule * r = *rit; - SASSERT(head_pred==r->get_decl()); - - compile_rule_evaluation(r, input_deltas, d_head_reg, widen_predicate_in_loop, acc); - } - } - } - - void compiler::compile_preds_init(const func_decl_vector & head_preds, const func_decl_set & widened_preds, - const pred2idx * input_deltas, const pred2idx & output_deltas, instruction_block & acc) { - func_decl_vector::const_iterator hpit = head_preds.begin(); - func_decl_vector::const_iterator hpend = head_preds.end(); - reg_idx void_reg = execution_context::void_register; - for(; hpit!=hpend; ++hpit) { - func_decl * head_pred = *hpit; - const rule_vector & pred_rules = m_rule_set.get_predicate_rules(head_pred); - rule_vector::const_iterator rit = pred_rules.begin(); - rule_vector::const_iterator rend = pred_rules.end(); - unsigned stratum = m_rule_set.get_predicate_strat(head_pred); - - for(; rit != rend; ++rit) { - rule * r = *rit; - SASSERT(head_pred==r->get_decl()); - - for (unsigned i = 0; i < r->get_uninterpreted_tail_size(); ++i) { - unsigned stratum1 = m_rule_set.get_predicate_strat(r->get_decl(i)); - if (stratum1 >= stratum) { - goto next_loop; - } - } - compile_rule_evaluation(r, input_deltas, void_reg, false, acc); - next_loop: - ; - } - - reg_idx d_head_reg; - if (output_deltas.find(head_pred, d_head_reg)) { - acc.push_back(instruction::mk_clone(m_pred_regs.find(head_pred), d_head_reg)); - } - } - } - - void compiler::make_inloop_delta_transition(const pred2idx & global_head_deltas, - const pred2idx & global_tail_deltas, const pred2idx & local_deltas, instruction_block & acc) { - //move global head deltas into tail ones - pred2idx::iterator gdit = global_head_deltas.begin(); - pred2idx::iterator gend = global_head_deltas.end(); - for(; gdit!=gend; ++gdit) { - func_decl * pred = gdit->m_key; - reg_idx head_reg = gdit->m_value; - reg_idx tail_reg = global_tail_deltas.find(pred); - acc.push_back(instruction::mk_move(head_reg, tail_reg)); - } - //empty local deltas - pred2idx::iterator lit = local_deltas.begin(); - pred2idx::iterator lend = local_deltas.end(); - for(; lit!=lend; ++lit) { - acc.push_back(instruction::mk_dealloc(lit->m_value)); - } - } - - void compiler::compile_loop(const func_decl_vector & head_preds, const func_decl_set & widened_preds, - const pred2idx & global_head_deltas, const pred2idx & global_tail_deltas, - const pred2idx & local_deltas, instruction_block & acc) { - instruction_block * loop_body = alloc(instruction_block); - loop_body->set_observer(&m_instruction_observer); - - pred2idx all_head_deltas(global_head_deltas); - unite_disjoint_maps(all_head_deltas, local_deltas); - pred2idx all_tail_deltas(global_tail_deltas); - unite_disjoint_maps(all_tail_deltas, local_deltas); - - //generate code for the iterative fixpoint search - //The order in which we iterate the preds_vector matters, since rules can depend on - //deltas generated earlier in the same iteration. - compile_preds(head_preds, widened_preds, &all_tail_deltas, all_head_deltas, *loop_body); - - svector loop_control_regs; //loop is controlled by global src regs - collect_map_range(loop_control_regs, global_tail_deltas); - //move target deltas into source deltas at the end of the loop - //and clear local deltas - make_inloop_delta_transition(global_head_deltas, global_tail_deltas, local_deltas, *loop_body); - - loop_body->set_observer(0); - acc.push_back(instruction::mk_while_loop(loop_control_regs.size(), - loop_control_regs.c_ptr(), loop_body)); - } - - void compiler::compile_dependent_rules(const func_decl_set & head_preds, - const pred2idx * input_deltas, const pred2idx & output_deltas, - bool add_saturation_marks, instruction_block & acc) { - - if (!output_deltas.empty()) { - func_decl_set::iterator hpit = head_preds.begin(); - func_decl_set::iterator hpend = head_preds.end(); - for(; hpit!=hpend; ++hpit) { - if(output_deltas.contains(*hpit)) { - //we do not support retrieving deltas for rules that are inside a recursive - //stratum, since we would have to maintain this 'global' delta through the loop - //iterations - NOT_IMPLEMENTED_YET(); - } - } - } - - func_decl_vector preds_vector; - func_decl_set global_deltas; - - detect_chains(head_preds, preds_vector, global_deltas); - - func_decl_set local_deltas(head_preds); - set_difference(local_deltas, global_deltas); - - pred2idx d_global_src; //these deltas serve as sources of tuples for rule evaluation inside the loop - get_fresh_registers(global_deltas, d_global_src); - pred2idx d_global_tgt; //these deltas are targets for new tuples in rule evaluation inside the loop - get_fresh_registers(global_deltas, d_global_tgt); - pred2idx d_local; - get_fresh_registers(local_deltas, d_local); - - pred2idx d_all_src(d_global_src); //src together with local deltas - unite_disjoint_maps(d_all_src, d_local); - pred2idx d_all_tgt(d_global_tgt); //tgt together with local deltas - unite_disjoint_maps(d_all_tgt, d_local); - - - func_decl_set empty_func_decl_set; - - //generate code for the initial run - // compile_preds(preds_vector, empty_func_decl_set, input_deltas, d_global_src, acc); - compile_preds_init(preds_vector, empty_func_decl_set, input_deltas, d_global_src, acc); - - if (compile_with_widening()) { - compile_loop(preds_vector, global_deltas, d_global_tgt, d_global_src, d_local, acc); - } - else { - compile_loop(preds_vector, empty_func_decl_set, d_global_tgt, d_global_src, d_local, acc); - } - - - if(add_saturation_marks) { - //after the loop finishes, all predicates in the group are saturated, - //so we may mark them as such - func_decl_set::iterator fdit = head_preds.begin(); - func_decl_set::iterator fdend = head_preds.end(); - for(; fdit!=fdend; ++fdit) { - acc.push_back(instruction::mk_mark_saturated(m_context.get_manager(), *fdit)); - } - } - } - - bool compiler::is_nonrecursive_stratum(const func_decl_set & preds) const { - SASSERT(preds.size()>0); - if(preds.size()>1) { - return false; - } - func_decl * head_pred = *preds.begin(); - const rule_vector & rules = m_rule_set.get_predicate_rules(head_pred); - rule_vector::const_iterator it = rules.begin(); - rule_vector::const_iterator end = rules.end(); - for(; it!=end; ++it) { - //it is sufficient to check just for presence of the first head predicate, - //since if the rules are recursive and their heads are strongly connected by dependence, - //this predicate must appear in some tail - if((*it)->is_in_tail(head_pred)) { - return false; - } - } - return true; - } - - void compiler::compile_nonrecursive_stratum(const func_decl_set & preds, - const pred2idx * input_deltas, const pred2idx & output_deltas, - bool add_saturation_marks, instruction_block & acc) { - //non-recursive stratum always has just one head predicate - SASSERT(preds.size()==1); - SASSERT(is_nonrecursive_stratum(preds)); - func_decl * head_pred = *preds.begin(); - const rule_vector & rules = m_rule_set.get_predicate_rules(head_pred); - - - - reg_idx output_delta; - if (!output_deltas.find(head_pred, output_delta)) { - output_delta = execution_context::void_register; - } - - rule_vector::const_iterator it = rules.begin(); - rule_vector::const_iterator end = rules.end(); - for (; it != end; ++it) { - rule * r = *it; - SASSERT(r->get_decl()==head_pred); - - compile_rule_evaluation(r, input_deltas, output_delta, false, acc); - } - - if (add_saturation_marks) { - //now the predicate is saturated, so we may mark it as such - acc.push_back(instruction::mk_mark_saturated(m_context.get_manager(), head_pred)); - } - } - - bool compiler::all_saturated(const func_decl_set & preds) const { - func_decl_set::iterator fdit = preds.begin(); - func_decl_set::iterator fdend = preds.end(); - for(; fdit!=fdend; ++fdit) { - if(!m_context.get_rel_context().get_rmanager().is_saturated(*fdit)) { - return false; - } - } - return true; - } - - void compiler::compile_strats(const rule_stratifier & stratifier, - const pred2idx * input_deltas, const pred2idx & output_deltas, - bool add_saturation_marks, instruction_block & acc) { - rule_set::pred_set_vector strats = stratifier.get_strats(); - rule_set::pred_set_vector::const_iterator sit = strats.begin(); - rule_set::pred_set_vector::const_iterator send = strats.end(); - for(; sit!=send; ++sit) { - func_decl_set & strat_preds = **sit; - - if (all_saturated(strat_preds)) { - //all predicates in stratum are saturated, so no need to compile rules for them - continue; - } - - TRACE("dl", - tout << "Stratum: "; - func_decl_set::iterator pit = strat_preds.begin(); - func_decl_set::iterator pend = strat_preds.end(); - for(; pit!=pend; ++pit) { - func_decl * pred = *pit; - tout << pred->get_name() << " "; - } - tout << "\n"; - ); - - if (is_nonrecursive_stratum(strat_preds)) { - //this stratum contains just a single non-recursive rule - compile_nonrecursive_stratum(strat_preds, input_deltas, output_deltas, add_saturation_marks, acc); - } - else { - compile_dependent_rules(strat_preds, input_deltas, output_deltas, - add_saturation_marks, acc); - } - } - } - - void compiler::do_compilation(instruction_block & execution_code, - instruction_block & termination_code) { - - unsigned rule_cnt=m_rule_set.get_num_rules(); - if(rule_cnt==0) { - return; - } - - instruction_block & acc = execution_code; - acc.set_observer(&m_instruction_observer); - - - //load predicate data - for(unsigned i=0;iget_decl(), acc); - - unsigned rule_len = r->get_uninterpreted_tail_size(); - for(unsigned j=0;jget_tail(j)->get_decl(), acc); - } - } - - pred2idx empty_pred2idx_map; - - compile_strats(m_rule_set.get_stratifier(), static_cast(0), - empty_pred2idx_map, true, execution_code); - - - - //store predicate data - pred2idx::iterator pit = m_pred_regs.begin(); - pred2idx::iterator pend = m_pred_regs.end(); - for(; pit!=pend; ++pit) { - pred2idx::key_data & e = *pit; - func_decl * pred = e.m_key; - reg_idx reg = e.m_value; - termination_code.push_back(instruction::mk_store(m_context.get_manager(), pred, reg)); - } - - acc.set_observer(0); - - TRACE("dl", execution_code.display(m_context.get_rel_context(), tout);); - } - - -} - From 9c230941cc4179ec5aa9a73b3b928bce16f47d4d Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 23 Apr 2013 12:01:50 -0700 Subject: [PATCH 104/281] [datalog] improve performance of smt2 frontend - delay calls to make_annotations and process_costs untill needed - remove debug exception handler in join() Signed-off-by: Nuno Lopes --- src/muz_qe/dl_instruction.cpp | 16 +--------------- src/muz_qe/rel_context.cpp | 9 +++++---- src/muz_qe/rel_context.h | 2 +- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/muz_qe/dl_instruction.cpp b/src/muz_qe/dl_instruction.cpp index 296fa95f3..b103d743e 100644 --- a/src/muz_qe/dl_instruction.cpp +++ b/src/muz_qe/dl_instruction.cpp @@ -359,21 +359,7 @@ namespace datalog { r2.get_signature().output(ctx.get_rel_context().get_manager(), tout); tout<<":"<\n";); - try { - ctx.set_reg(m_res, (*fn)(r1, r2)); - } - catch(...) - { - std::string annotation; - unsigned sz; - ctx.get_register_annotation(m_rel1, annotation); - sz = ctx.reg(m_rel1)?ctx.reg(m_rel1)->get_size_estimate_rows():0; - std::cout << m_rel1 << "\t" << sz << "\t" << annotation << "\n"; - ctx.get_register_annotation(m_rel2, annotation); - sz = ctx.reg(m_rel2)?ctx.reg(m_rel2)->get_size_estimate_rows():0; - std::cout << m_rel2 << "\t" << sz << "\t" << annotation << "\n"; - throw; - } + ctx.set_reg(m_res, (*fn)(r1, r2)); TRACE("dl", ctx.reg(m_res)->get_signature().output(ctx.get_rel_context().get_manager(), tout); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index ef5639279..731ab8b63 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -179,9 +179,7 @@ namespace datalog { scoped_query.reset(); } m_context.record_transformed_rules(); - TRACE("dl", m_ectx.report_big_relations(100, tout);); - m_code.process_all_costs(); - m_code.make_annotations(m_ectx); + TRACE("dl", display_profile(tout);); return result; } @@ -480,7 +478,10 @@ namespace datalog { get_rmanager().display(out); } - void rel_context::display_profile(std::ostream& out) const { + void rel_context::display_profile(std::ostream& out) { + m_code.make_annotations(m_ectx); + m_code.process_all_costs(); + out << "\n--------------\n"; out << "Instructions\n"; m_code.display(*this, out); diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index 3e019cb50..8e4c6f2de 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -105,7 +105,7 @@ namespace datalog { void display_output_facts(rule_set const& rules, std::ostream & out) const; void display_facts(std::ostream & out) const; - void display_profile(std::ostream& out) const; + void display_profile(std::ostream& out); lbool saturate(); From f58e8e961dfd09181407d7be90c8498678c04859 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 23 Apr 2013 14:59:19 -0700 Subject: [PATCH 105/281] fix the build Signed-off-by: Nuno Lopes --- src/muz_qe/dl_mk_filter_rules.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/muz_qe/dl_mk_filter_rules.cpp b/src/muz_qe/dl_mk_filter_rules.cpp index 8ab8412c0..932a644ab 100644 --- a/src/muz_qe/dl_mk_filter_rules.cpp +++ b/src/muz_qe/dl_mk_filter_rules.cpp @@ -152,9 +152,6 @@ namespace datalog { } rule_set * mk_filter_rules::operator()(rule_set const & source) { - if (!m_context.get_params().filter_rules()) { - return 0; - } m_tail2filter.reset(); m_result = alloc(rule_set, m_context); m_modified = false; From 780ad7cc179aa38648a2aca7c6a1d8a99ff42763 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 25 Apr 2013 09:30:51 -0700 Subject: [PATCH 106/281] fix seg-fault caused by neglecting to inherit output predicate in slice Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_slice.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/muz_qe/dl_mk_slice.cpp b/src/muz_qe/dl_mk_slice.cpp index 21c3486b3..89804447b 100644 --- a/src/muz_qe/dl_mk_slice.cpp +++ b/src/muz_qe/dl_mk_slice.cpp @@ -725,6 +725,9 @@ namespace datalog { m_mc->add_predicate(p, f); } } + else if (src.is_output_predicate(p)) { + dst.set_output_predicate(p); + } } } From 83add2bd9bfcd3dab8917b0baf25a75c33f0b343 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 25 Apr 2013 13:39:11 -0700 Subject: [PATCH 107/281] fix bugs reported by Filip Konecny in PDR Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt_pp.cpp | 5 +- src/muz_qe/dl_mk_rule_inliner.cpp | 26 ++++-- src/muz_qe/dl_mk_rule_inliner.h | 2 +- src/muz_qe/dl_mk_subsumption_checker.cpp | 6 +- src/muz_qe/dl_rule.cpp | 8 +- src/muz_qe/horn_tactic.cpp | 16 ++-- src/muz_qe/pdr_context.cpp | 14 ++- src/muz_qe/pdr_context.h | 1 + src/muz_qe/pdr_util.cpp | 30 +++++- src/muz_qe/pdr_util.h | 2 + src/muz_qe/proof_utils.cpp | 91 +++++++++++++++++++ src/muz_qe/proof_utils.h | 6 ++ src/parsers/smt2/smt2parser.cpp | 2 +- src/tactic/portfolio/smt_strategic_solver.cpp | 1 - 14 files changed, 176 insertions(+), 34 deletions(-) diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 5819e3930..f684879ae 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -260,6 +260,7 @@ class smt_printer { else { m_out << sym << "["; } + for (unsigned i = 0; i < num_params; ++i) { parameter const& p = params[i]; if (p.is_ast()) { @@ -642,9 +643,7 @@ class smt_printer { m_out << m_var_names[m_num_var_names - idx - 1]; } else { - if (!m_is_smt2) { - m_out << "?" << idx; - } + m_out << "?" << idx; } } diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp index 8428d9049..5bbeb2378 100644 --- a/src/muz_qe/dl_mk_rule_inliner.cpp +++ b/src/muz_qe/dl_mk_rule_inliner.cpp @@ -709,8 +709,7 @@ namespace datalog { #define PRT(_x_) ((_x_)?"T":"F") - bool mk_rule_inliner::inline_linear(rule_set const& source, scoped_ptr& rules) { - scoped_ptr res = alloc(rule_set, m_context); + bool mk_rule_inliner::inline_linear(scoped_ptr& rules) { bool done_something = false; unsigned sz = rules->get_num_rules(); @@ -731,7 +730,7 @@ namespace datalog { svector& can_expand = m_head_visitor.can_expand(); for (unsigned i = 0; i < sz; ++i) { - add_rule(source, acc[i].get(), i); + add_rule(*rules, acc[i].get(), i); } // initialize substitution. @@ -808,7 +807,7 @@ namespace datalog { TRACE("dl", r->display(m_context, tout); r2->display(m_context, tout); rl_res->display(m_context, tout); ); del_rule(r, i); - add_rule(source, rl_res.get(), i); + add_rule(*rules, rl_res.get(), i); r = rl_res; @@ -828,13 +827,15 @@ namespace datalog { } } if (done_something) { - rules = alloc(rule_set, m_context); + scoped_ptr res = alloc(rule_set, m_context); for (unsigned i = 0; i < sz; ++i) { if (valid.get(i)) { - rules->add_rule(acc[i].get()); + res->add_rule(acc[i].get()); } } - TRACE("dl", rules->display(tout);); + res->inherit_predicates(*rules); + TRACE("dl", res->display(tout);); + rules = res.detach(); } return done_something; } @@ -871,11 +872,17 @@ namespace datalog { // try eager inlining if (do_eager_inlining(res)) { something_done = true; - } + } TRACE("dl", res->display(tout << "after eager inlining\n");); + } + if (something_done) { + res->inherit_predicates(source); + } + else { + res = alloc(rule_set, source); } - if (m_context.get_params().inline_linear() && inline_linear(source, res)) { + if (m_context.get_params().inline_linear() && inline_linear(res)) { something_done = true; } @@ -883,7 +890,6 @@ namespace datalog { res = 0; } else { - res->inherit_predicates(source); m_context.add_model_converter(hsmc.get()); } diff --git a/src/muz_qe/dl_mk_rule_inliner.h b/src/muz_qe/dl_mk_rule_inliner.h index 476c6b4b0..3a933f990 100644 --- a/src/muz_qe/dl_mk_rule_inliner.h +++ b/src/muz_qe/dl_mk_rule_inliner.h @@ -172,7 +172,7 @@ namespace datalog { /** Inline predicates that are known to not be join-points. */ - bool inline_linear(rule_set const& source, scoped_ptr& rules); + bool inline_linear(scoped_ptr& rules); void add_rule(rule_set const& rule_set, rule* r, unsigned i); void del_rule(rule* r, unsigned i); diff --git a/src/muz_qe/dl_mk_subsumption_checker.cpp b/src/muz_qe/dl_mk_subsumption_checker.cpp index 0e94ba3b9..8c9e7e69f 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.cpp +++ b/src/muz_qe/dl_mk_subsumption_checker.cpp @@ -241,6 +241,7 @@ namespace datalog { tgt.add_rule(new_rule); subs_index.add(new_rule); } + tgt.inherit_predicates(orig); TRACE("dl", tout << "original set size: "<inherit_predicates(source); return res; } diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 92f504bcc..32f3a5fe8 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -1004,16 +1004,14 @@ namespace datalog { } svector names; used_symbols<> us; - - us(fml); - sorts.reverse(); - for (unsigned i = 0; i < sorts.size(); ++i) { if (!sorts[i]) { sorts[i] = m.mk_bool_sort(); } } - + + us(fml); + sorts.reverse(); for (unsigned j = 0, i = 0; i < sorts.size(); ++j) { for (char c = 'A'; i < sorts.size() && c <= 'Z'; ++c) { func_decl_ref f(m); diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 1a8f562d9..5db4f1a00 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -125,12 +125,13 @@ class horn_tactic : public tactic { enum formula_kind { IS_RULE, IS_QUERY, IS_NONE }; formula_kind get_formula_kind(expr_ref& f) { - normalize(f); + expr_ref tmp(f); + normalize(tmp); ast_mark mark; expr_ref_vector args(m), body(m); expr_ref head(m); expr* a = 0, *a1 = 0; - datalog::flatten_or(f, args); + datalog::flatten_or(tmp, args); for (unsigned i = 0; i < args.size(); ++i) { a = args[i].get(); check_predicate(mark, a); @@ -147,12 +148,12 @@ class horn_tactic : public tactic { body.push_back(m.mk_not(a)); } } - f = m.mk_and(body.size(), body.c_ptr()); if (head) { - f = m.mk_implies(f, head); + // f = m.mk_implies(f, head); return IS_RULE; } else { + f = m.mk_and(body.size(), body.c_ptr()); return IS_QUERY; } } @@ -171,7 +172,7 @@ class horn_tactic : public tactic { tactic_report report("horn", *g); bool produce_proofs = g->proofs_enabled(); - if (produce_proofs) { + if (produce_proofs) { if (!m_ctx.get_params().generate_proof_trace()) { params_ref params = m_ctx.get_params().p; params.set_bool("generate_proof_trace", true); @@ -239,10 +240,13 @@ class horn_tactic : public tactic { switch (is_reachable) { case l_true: { // goal is unsat - g->assert_expr(m.mk_false()); if (produce_proofs) { proof_ref proof = m_ctx.get_proof(); pc = proof2proof_converter(m, proof); + g->assert_expr(m.mk_false(), proof, 0); + } + else { + g->assert_expr(m.mk_false()); } break; } diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index a240a9aef..62b119538 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -43,6 +43,7 @@ Notes: #include "ast_ll_pp.h" #include "proof_checker.h" #include "smt_value_sort.h" +#include "proof_utils.h" namespace pdr { @@ -275,7 +276,7 @@ namespace pdr { src.pop_back(); } else if (is_invariant(tgt_level, curr, false, assumes_level)) { - + add_property(curr, assumes_level?tgt_level:infty_level); TRACE("pdr", tout << "is invariant: "<< pp_level(tgt_level) << " " << mk_pp(curr, m) << "\n";); src[i] = src.back(); @@ -1225,6 +1226,7 @@ namespace pdr { m_search(m_params.bfs_model_search()), m_last_result(l_undef), m_inductive_lvl(0), + m_expanded_lvl(0), m_cancel(false) { } @@ -1680,6 +1682,9 @@ namespace pdr { proof = m_search.get_proof_trace(*this); TRACE("pdr", tout << "PDR trace: " << mk_pp(proof, m) << "\n";); apply(m, m_pc.get(), proof); + TRACE("pdr", tout << "PDR trace: " << mk_pp(proof, m) << "\n";); + // proof_utils::push_instantiations_up(proof); + // TRACE("pdr", tout << "PDR up: " << mk_pp(proof, m) << "\n";); return proof; } @@ -1711,6 +1716,7 @@ namespace pdr { bool reachable; while (true) { checkpoint(); + m_expanded_lvl = lvl; reachable = check_reachability(lvl); if (reachable) { throw model_exception(); @@ -1769,6 +1775,10 @@ namespace pdr { void context::expand_node(model_node& n) { SASSERT(n.is_open()); expr_ref_vector cube(m); + + if (n.level() < m_expanded_lvl) { + m_expanded_lvl = n.level(); + } if (n.pt().is_reachable(n.state())) { TRACE("pdr", tout << "reachable\n";); @@ -1835,7 +1845,7 @@ namespace pdr { if (m_params.simplify_formulas_pre()) { simplify_formulas(); } - for (unsigned lvl = 0; lvl <= max_prop_lvl; lvl++) { + for (unsigned lvl = m_expanded_lvl; lvl <= max_prop_lvl; lvl++) { checkpoint(); bool all_propagated = true; decl2rel::iterator it = m_rels.begin(), end = m_rels.end(); diff --git a/src/muz_qe/pdr_context.h b/src/muz_qe/pdr_context.h index 6aa02ef10..b5652d1b6 100644 --- a/src/muz_qe/pdr_context.h +++ b/src/muz_qe/pdr_context.h @@ -303,6 +303,7 @@ namespace pdr { mutable model_search m_search; lbool m_last_result; unsigned m_inductive_lvl; + unsigned m_expanded_lvl; ptr_vector m_core_generalizers; stats m_stats; volatile bool m_cancel; diff --git a/src/muz_qe/pdr_util.cpp b/src/muz_qe/pdr_util.cpp index 237cf9415..62185f1d2 100644 --- a/src/muz_qe/pdr_util.cpp +++ b/src/muz_qe/pdr_util.cpp @@ -1081,6 +1081,7 @@ namespace pdr { arith_util a; bv_util bv; bool m_is_dl; + bool m_test_for_utvpi; bool is_numeric(expr* e) const { if (a.is_numeral(e)) { @@ -1115,6 +1116,16 @@ namespace pdr { } return false; } + if (m_test_for_utvpi) { + if (a.is_mul(e, e1, e2)) { + if (is_minus_one(e1)) { + return is_offset(e2); + } + if (is_minus_one(e2)) { + return is_offset(e1); + } + } + } return !is_arith_expr(e); } @@ -1140,6 +1151,9 @@ namespace pdr { if (!a.is_add(lhs, arg1, arg2)) return false; // x + if (m_test_for_utvpi) { + return is_offset(arg1) && is_offset(arg2); + } if (is_arith_expr(arg1)) std::swap(arg1, arg2); if (is_arith_expr(arg1)) @@ -1209,8 +1223,10 @@ namespace pdr { } public: - test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true) {} - + test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true), m_test_for_utvpi(false) {} + + void test_for_utvpi() { m_test_for_utvpi = true; } + void operator()(expr* e) { if (!m_is_dl) { return; @@ -1248,6 +1264,16 @@ namespace pdr { return test.is_dl(); } + bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) { + test_diff_logic test(m); + test.test_for_utvpi(); + expr_fast_mark1 mark; + for (unsigned i = 0; i < num_fmls; ++i) { + quick_for_each_expr(test, mark, fmls[i]); + } + return test.is_dl(); + } + } template class rewriter_tpl; diff --git a/src/muz_qe/pdr_util.h b/src/muz_qe/pdr_util.h index ddbf0d122..5f2d22b76 100644 --- a/src/muz_qe/pdr_util.h +++ b/src/muz_qe/pdr_util.h @@ -151,6 +151,8 @@ namespace pdr { bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); + bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); + } #endif diff --git a/src/muz_qe/proof_utils.cpp b/src/muz_qe/proof_utils.cpp index 369c3aae6..36e721b5c 100644 --- a/src/muz_qe/proof_utils.cpp +++ b/src/muz_qe/proof_utils.cpp @@ -1,6 +1,7 @@ #include "dl_util.h" #include "proof_utils.h" #include "ast_smt2_pp.h" +#include "var_subst.h" class reduce_hypotheses { typedef obj_hashtable expr_set; @@ -517,3 +518,93 @@ void proof_utils::permute_unit_resolution(proof_ref& pr) { obj_map cache; ::permute_unit_resolution(refs, cache, pr); } + +class push_instantiations_up_cl { + ast_manager& m; +public: + push_instantiations_up_cl(ast_manager& m): m(m) {} + + void operator()(proof_ref& p) { + expr_ref_vector s0(m); + p = push(p, s0); + } + +private: + + proof* push(proof* p, expr_ref_vector const& sub) { + proof_ref_vector premises(m); + expr_ref conclusion(m); + svector > positions; + vector substs; + + if (m.is_hyper_resolve(p, premises, conclusion, positions, substs)) { + for (unsigned i = 0; i < premises.size(); ++i) { + compose(substs[i], sub); + premises[i] = push(premises[i].get(), substs[i]); + substs[i].reset(); + } + instantiate(sub, conclusion); + return + m.mk_hyper_resolve(premises.size(), premises.c_ptr(), conclusion, + positions, + substs); + } + if (sub.empty()) { + return p; + } + if (m.is_modus_ponens(p)) { + SASSERT(m.get_num_parents(p) == 2); + proof* p0 = m.get_parent(p, 0); + proof* p1 = m.get_parent(p, 1); + if (m.get_fact(p0) == m.get_fact(p)) { + return push(p0, sub); + } + expr* e1, *e2; + if (m.is_rewrite(p1, e1, e2) && + is_quantifier(e1) && is_quantifier(e2) && + to_quantifier(e1)->get_num_decls() == to_quantifier(e2)->get_num_decls()) { + expr_ref r1(e1,m), r2(e2,m); + instantiate(sub, r1); + instantiate(sub, r2); + p1 = m.mk_rewrite(r1, r2); + return m.mk_modus_ponens(push(p0, sub), p1); + } + } + premises.push_back(p); + substs.push_back(sub); + conclusion = m.get_fact(p); + instantiate(sub, conclusion); + return m.mk_hyper_resolve(premises.size(), premises.c_ptr(), conclusion, positions, substs); + } + + void compose(expr_ref_vector& sub, expr_ref_vector const& s0) { + for (unsigned i = 0; i < sub.size(); ++i) { + expr_ref e(m); + var_subst(m, false)(sub[i].get(), s0.size(), s0.c_ptr(), e); + sub[i] = e; + } + } + + void instantiate(expr_ref_vector const& sub, expr_ref& fml) { + if (sub.empty()) { + return; + } + if (!is_forall(fml)) { + return; + } + quantifier* q = to_quantifier(fml); + if (q->get_num_decls() != sub.size()) { + TRACE("proof_utils", tout << "quantifier has different number of variables than substitution"; + tout << mk_pp(q, m) << "\n"; + tout << sub.size() << "\n";); + return; + } + var_subst(m, false)(q->get_expr(), sub.size(), sub.c_ptr(), fml); + } + +}; + +void proof_utils::push_instantiations_up(proof_ref& pr) { + push_instantiations_up_cl push(pr.get_manager()); + push(pr); +} diff --git a/src/muz_qe/proof_utils.h b/src/muz_qe/proof_utils.h index 53a38592e..dc3cdc3ef 100644 --- a/src/muz_qe/proof_utils.h +++ b/src/muz_qe/proof_utils.h @@ -36,6 +36,12 @@ public: */ static void permute_unit_resolution(proof_ref& pr); + /** + \brief Push instantiations created in hyper-resolutions up to leaves. + This produces a "ground" proof where leaves are annotated by instantiations. + */ + static void push_instantiations_up(proof_ref& pr); + }; #endif diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 0698f4eaf..b5af6353e 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -1159,7 +1159,7 @@ namespace smt2 { m_num_expr_frames++; unsigned num_vars = parse_sorted_vars(); if (num_vars == 0) - throw parser_exception("invalied quantifier, list of sorted variables is empty"); + throw parser_exception("invalid quantifier, list of sorted variables is empty"); } symbol parse_indexed_identifier_core() { diff --git a/src/tactic/portfolio/smt_strategic_solver.cpp b/src/tactic/portfolio/smt_strategic_solver.cpp index 55512f677..ae79446e3 100644 --- a/src/tactic/portfolio/smt_strategic_solver.cpp +++ b/src/tactic/portfolio/smt_strategic_solver.cpp @@ -94,7 +94,6 @@ public: smt_strategic_solver_factory(symbol const & logic):m_logic(logic) {} virtual ~smt_strategic_solver_factory() {} - virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) { symbol l; if (m_logic != symbol::null) From c58b4f9a53e2fae636568157bdbfbc958596ce23 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 26 Apr 2013 11:43:06 -0700 Subject: [PATCH 108/281] optimize rule processing Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/ast_counter.cpp | 4 +- src/ast/rewriter/ast_counter.h | 2 + src/ast/rewriter/var_subst.cpp | 35 ++++--- src/ast/rewriter/var_subst.h | 12 +++ src/muz_qe/dl_context.cpp | 3 +- src/muz_qe/dl_context.h | 1 + src/muz_qe/dl_finite_product_relation.cpp | 4 +- src/muz_qe/dl_mk_array_blast.cpp | 7 +- src/muz_qe/dl_mk_array_blast.h | 1 + src/muz_qe/dl_mk_filter_rules.cpp | 28 +++--- src/muz_qe/dl_mk_filter_rules.h | 3 +- src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 45 ++++++--- src/muz_qe/dl_mk_interp_tail_simplifier.h | 27 +++--- src/muz_qe/dl_mk_magic_sets.cpp | 3 +- src/muz_qe/dl_mk_magic_sets.h | 1 + src/muz_qe/dl_mk_rule_inliner.cpp | 4 - src/muz_qe/dl_mk_simple_joins.cpp | 27 +++--- src/muz_qe/dl_mk_simple_joins.h | 3 +- src/muz_qe/dl_mk_unbound_compressor.cpp | 28 +++--- src/muz_qe/dl_mk_unbound_compressor.h | 1 + src/muz_qe/dl_rule.cpp | 101 +++++++++++++++----- src/muz_qe/dl_rule.h | 41 ++++++++ src/muz_qe/dl_sieve_relation.cpp | 3 +- src/muz_qe/dl_util.cpp | 50 +--------- src/muz_qe/dl_util.h | 20 ---- src/muz_qe/qe_lite.cpp | 8 +- src/smt/theory_diff_logic.h | 2 +- src/util/memory_manager.cpp | 3 +- 28 files changed, 267 insertions(+), 200 deletions(-) diff --git a/src/ast/rewriter/ast_counter.cpp b/src/ast/rewriter/ast_counter.cpp index c542abb60..099bdedec 100644 --- a/src/ast/rewriter/ast_counter.cpp +++ b/src/ast/rewriter/ast_counter.cpp @@ -93,7 +93,9 @@ void var_counter::count_vars(ast_manager & m, const app * pred, int coef) { unsigned n = pred->get_num_args(); for (unsigned i = 0; i < n; i++) { m_sorts.reset(); - ::get_free_vars(pred->get_arg(i), m_sorts); + m_todo.reset(); + m_mark.reset(); + ::get_free_vars(m_mark, m_todo, pred->get_arg(i), m_sorts); for (unsigned j = 0; j < m_sorts.size(); ++j) { if (m_sorts[j]) { update(j, coef); diff --git a/src/ast/rewriter/ast_counter.h b/src/ast/rewriter/ast_counter.h index 2a581c302..e7251079f 100644 --- a/src/ast/rewriter/ast_counter.h +++ b/src/ast/rewriter/ast_counter.h @@ -38,6 +38,7 @@ public: counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {} + void reset() { m_data.reset(); } iterator begin() const { return m_data.begin(); } iterator end() const { return m_data.end(); } void update(unsigned el, int delta); @@ -71,6 +72,7 @@ protected: ptr_vector m_sorts; expr_fast_mark1 m_visited; ptr_vector m_todo; + ast_mark m_mark; unsigned_vector m_scopes; unsigned get_max_var(bool & has_var); public: diff --git a/src/ast/rewriter/var_subst.cpp b/src/ast/rewriter/var_subst.cpp index 3ebc0b573..f7f0c8aef 100644 --- a/src/ast/rewriter/var_subst.cpp +++ b/src/ast/rewriter/var_subst.cpp @@ -17,7 +17,6 @@ Notes: --*/ #include"var_subst.h" -#include"used_vars.h" #include"ast_ll_pp.h" #include"ast_pp.h" #include"ast_smt2_pp.h" @@ -40,7 +39,7 @@ void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, exp tout << mk_ismt2_pp(result, m_reducer.m()) << "\n";); } -void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) { +void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { SASSERT(is_well_sorted(m, q)); if (is_ground(q->get_expr())) { // ignore patterns if the body is a ground formula. @@ -51,11 +50,11 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) { result = q; return; } - used_vars used; - used.process(q->get_expr()); + m_used.reset(); + m_used.process(q->get_expr()); unsigned num_patterns = q->get_num_patterns(); for (unsigned i = 0; i < num_patterns; i++) - used.process(q->get_pattern(i)); + m_used.process(q->get_pattern(i)); unsigned num_no_patterns = q->get_num_no_patterns(); for (unsigned i = 0; i < num_no_patterns; i++) used.process(q->get_no_pattern(i)); @@ -110,9 +109,8 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) { std::reverse(var_mapping.c_ptr(), var_mapping.c_ptr() + var_mapping.size()); expr_ref new_expr(m); - var_subst subst(m); - subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr(), new_expr); + m_subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr(), new_expr); if (num_removed == num_decls) { result = new_expr; @@ -145,7 +143,12 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) { num_no_patterns, new_no_patterns.c_ptr()); to_quantifier(result)->set_no_unused_vars(); - SASSERT(is_well_sorted(m, result)); + SASSERT(is_well_sorted(m, result)); +} + +void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) { + unused_vars_eliminator el(m); + el(q, result); } void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result) { @@ -161,9 +164,7 @@ void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref tout << "\n----->\n" << mk_ismt2_pp(result, m) << "\n";); } -static void get_free_vars_offset(expr* e, unsigned offset, ptr_vector& sorts) { - ast_mark mark; - ptr_vector todo; +static void get_free_vars_offset(ast_mark& mark, ptr_vector& todo, unsigned offset, expr* e, ptr_vector& sorts) { todo.push_back(e); while (!todo.empty()) { e = todo.back(); @@ -175,7 +176,9 @@ static void get_free_vars_offset(expr* e, unsigned offset, ptr_vector& sor switch(e->get_kind()) { case AST_QUANTIFIER: { quantifier* q = to_quantifier(e); - get_free_vars_offset(q->get_expr(), offset+q->get_num_decls(), sorts); + ast_mark mark1; + ptr_vector todo1; + get_free_vars_offset(mark1, todo1, offset+q->get_num_decls(), q->get_expr(), sorts); break; } case AST_VAR: { @@ -207,5 +210,11 @@ static void get_free_vars_offset(expr* e, unsigned offset, ptr_vector& sor void get_free_vars(expr* e, ptr_vector& sorts) { - get_free_vars_offset(e, 0, sorts); + ast_mark mark; + ptr_vector todo; + get_free_vars_offset(mark, todo, 0, e, sorts); +} + +void get_free_vars(ast_mark& mark, ptr_vector& todo, expr* e, ptr_vector& sorts) { + get_free_vars_offset(mark, todo, 0, e, sorts); } diff --git a/src/ast/rewriter/var_subst.h b/src/ast/rewriter/var_subst.h index 9f3c13c0c..ffc21e691 100644 --- a/src/ast/rewriter/var_subst.h +++ b/src/ast/rewriter/var_subst.h @@ -20,6 +20,7 @@ Notes: #define _VAR_SUBST_H_ #include"rewriter.h" +#include"used_vars.h" /** \brief Alias for var_shifter class. @@ -53,6 +54,15 @@ public: /** \brief Eliminate the unused variables from \c q. Store the result in \c r. */ +class unused_vars_eliminator { + ast_manager& m; + var_subst m_subst; + used_vars m_used; +public: + unused_vars_eliminator(ast_manager& m): m(m), m_subst(m) {} + void operator()(quantifier* q, expr_ref& r); +}; + void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & r); /** @@ -73,6 +83,8 @@ void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref */ void get_free_vars(expr* e, ptr_vector& sorts); +void get_free_vars(ast_mark& mark, ptr_vector& todo, expr* e, ptr_vector& sorts); + #endif diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 50915946a..f283bd456 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -226,6 +226,7 @@ namespace datalog { m_rewriter(m), m_var_subst(m), m_rule_manager(*this), + m_elim_unused_vars(m), m_transf(*this), m_trail(*this), m_pinned(m), @@ -332,7 +333,7 @@ namespace datalog { quantifier_ref q(m); sorts.reverse(); q = m.mk_quantifier(is_forall, sorts.size(), sorts.c_ptr(), names.c_ptr(), result); - elim_unused_vars(m, q, result); + m_elim_unused_vars(q, result); } } return result; diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index 74449940c..2798ba8df 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -84,6 +84,7 @@ namespace datalog { th_rewriter m_rewriter; var_subst m_var_subst; rule_manager m_rule_manager; + unused_vars_eliminator m_elim_unused_vars; rule_transformer m_transf; trail_stack m_trail; ast_ref_vector m_pinned; diff --git a/src/muz_qe/dl_finite_product_relation.cpp b/src/muz_qe/dl_finite_product_relation.cpp index 4880e6068..86fef433b 100644 --- a/src/muz_qe/dl_finite_product_relation.cpp +++ b/src/muz_qe/dl_finite_product_relation.cpp @@ -1291,8 +1291,8 @@ namespace datalog { m_renaming_for_inner_rel(m_manager) { relation_manager & rmgr = r.get_manager(); - idx_set cond_columns; - collect_vars(m_manager, m_cond, cond_columns); + rule_manager& rm = r.get_context().get_rule_manager(); + idx_set& cond_columns = rm.collect_vars(m_cond); unsigned sig_sz = r.get_signature().size(); for(unsigned i=0; i m_vars; mk_interp_tail_simplifier m_simplifier; typedef obj_map defs_t; diff --git a/src/muz_qe/dl_mk_filter_rules.cpp b/src/muz_qe/dl_mk_filter_rules.cpp index 932a644ab..ef89c9ffa 100644 --- a/src/muz_qe/dl_mk_filter_rules.cpp +++ b/src/muz_qe/dl_mk_filter_rules.cpp @@ -27,9 +27,10 @@ namespace datalog { mk_filter_rules::mk_filter_rules(context & ctx): plugin(2000), m_context(ctx), - m_manager(ctx.get_manager()), + m(ctx.get_manager()), + rm(ctx.get_rule_manager()), m_result(0), - m_pinned(m_manager) { + m_pinned(m) { } mk_filter_rules::~mk_filter_rules() { @@ -52,14 +53,14 @@ namespace datalog { */ bool mk_filter_rules::is_candidate(app * pred) { if (!m_context.is_predicate(pred)) { - TRACE("mk_filter_rules", tout << mk_pp(pred, m_manager) << "\nis not a candidate because it is interpreted.\n";); + TRACE("mk_filter_rules", tout << mk_pp(pred, m) << "\nis not a candidate because it is interpreted.\n";); return false; } var_idx_set used_vars; unsigned n = pred->get_num_args(); for (unsigned i = 0; i < n; i++) { expr * arg = pred->get_arg(i); - if (m_manager.is_value(arg)) + if (m.is_value(arg)) return true; SASSERT(is_var(arg)); unsigned vidx = to_var(arg)->get_idx(); @@ -74,10 +75,10 @@ namespace datalog { \brief Create a "filter" (if it doesn't exist already) for the given predicate. */ func_decl * mk_filter_rules::mk_filter_decl(app * pred, var_idx_set const & non_local_vars) { - sort_ref_buffer filter_domain(m_manager); + sort_ref_buffer filter_domain(m); - filter_key * key = alloc(filter_key, m_manager); - mk_new_rule_tail(m_manager, pred, non_local_vars, filter_domain, key->filter_args, key->new_pred); + filter_key * key = alloc(filter_key, m); + mk_new_rule_tail(m, pred, non_local_vars, filter_domain, key->filter_args, key->new_pred); func_decl * filter_decl = 0; if (!m_tail2filter.find(key, filter_decl)) { filter_decl = m_context.mk_fresh_head_predicate(pred->get_decl()->get_name(), symbol("filter"), @@ -85,8 +86,8 @@ namespace datalog { m_pinned.push_back(filter_decl); m_tail2filter.insert(key, filter_decl); - app_ref filter_head(m_manager); - filter_head = m_manager.mk_app(filter_decl, key->filter_args.size(), key->filter_args.c_ptr()); + app_ref filter_head(m); + filter_head = m.mk_app(filter_decl, key->filter_args.size(), key->filter_args.c_ptr()); app * filter_tail = key->new_pred; rule * filter_rule = m_context.get_rule_manager().mk(filter_head, 1, &filter_tail, (const bool *)0); filter_rule->set_accounting_parent_object(m_context, m_current); @@ -104,16 +105,15 @@ namespace datalog { void mk_filter_rules::process(rule * r) { m_current = r; app * new_head = r->get_head(); - app_ref_vector new_tail(m_manager); + app_ref_vector new_tail(m); svector new_is_negated; unsigned sz = r->get_tail_size(); bool rule_modified = false; for (unsigned i = 0; i < sz; i++) { app * tail = r->get_tail(i); if (is_candidate(tail)) { - TRACE("mk_filter_rules", tout << "is_candidate: " << mk_pp(tail, m_manager) << "\n";); - var_idx_set non_local_vars; - collect_non_local_vars(m_manager, r, tail, non_local_vars); + TRACE("mk_filter_rules", tout << "is_candidate: " << mk_pp(tail, m) << "\n";); + var_idx_set non_local_vars = rm.collect_rule_vars_ex(r, tail); func_decl * filter_decl = mk_filter_decl(tail, non_local_vars); ptr_buffer new_args; var_idx_set used_vars; @@ -129,7 +129,7 @@ namespace datalog { } } SASSERT(new_args.size() == filter_decl->get_arity()); - new_tail.push_back(m_manager.mk_app(filter_decl, new_args.size(), new_args.c_ptr())); + new_tail.push_back(m.mk_app(filter_decl, new_args.size(), new_args.c_ptr())); rule_modified = true; } else { diff --git a/src/muz_qe/dl_mk_filter_rules.h b/src/muz_qe/dl_mk_filter_rules.h index 91751f9b8..b51cb8e24 100644 --- a/src/muz_qe/dl_mk_filter_rules.h +++ b/src/muz_qe/dl_mk_filter_rules.h @@ -59,7 +59,8 @@ namespace datalog { typedef obj_map filter_cache; context & m_context; - ast_manager & m_manager; + ast_manager & m; + rule_manager & rm; filter_cache m_tail2filter; rule_set * m_result; rule * m_current; diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index d0b94f582..8a9b1257a 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -67,24 +67,23 @@ namespace datalog { void mk_interp_tail_simplifier::rule_substitution::get_result(rule_ref & res) { SASSERT(m_rule); - app_ref new_head(m); - apply(m_rule->get_head(), new_head); + apply(m_rule->get_head(), m_head); - app_ref_vector tail(m); - svector tail_neg; + m_tail.reset(); + m_neg.reset(); unsigned tail_len = m_rule->get_tail_size(); for (unsigned i=0; iget_tail(i), new_tail_el); - tail.push_back(new_tail_el); - tail_neg.push_back(m_rule->is_neg_tail(i)); + m_tail.push_back(new_tail_el); + m_neg.push_back(m_rule->is_neg_tail(i)); } - mk_rule_inliner::remove_duplicate_tails(tail, tail_neg); + mk_rule_inliner::remove_duplicate_tails(m_tail, m_neg); - SASSERT(tail.size() == tail_neg.size()); - res = m_context.get_rule_manager().mk(new_head, tail.size(), tail.c_ptr(), tail_neg.c_ptr()); + SASSERT(m_tail.size() == m_neg.size()); + res = m_context.get_rule_manager().mk(m_head, m_tail.size(), m_tail.c_ptr(), m_neg.c_ptr()); res->set_accounting_parent_object(m_context, m_rule); res->norm_vars(res.get_manager()); } @@ -362,14 +361,34 @@ namespace datalog { } }; + class mk_interp_tail_simplifier::normalizer_rw : public rewriter_tpl { + public: + normalizer_rw(ast_manager& m, normalizer_cfg& cfg): rewriter_tpl(m, false, cfg) {} + }; + + + mk_interp_tail_simplifier::mk_interp_tail_simplifier(context & ctx, unsigned priority) + : plugin(priority), + m(ctx.get_manager()), + m_context(ctx), + m_simp(ctx.get_rewriter()), + a(m), + m_rule_subst(ctx) { + m_cfg = alloc(normalizer_cfg, m); + m_rw = alloc(normalizer_rw, m, *m_cfg); + } + + mk_interp_tail_simplifier::~mk_interp_tail_simplifier() { + dealloc(m_rw); + dealloc(m_cfg); + } + + void mk_interp_tail_simplifier::simplify_expr(app * a, expr_ref& res) { expr_ref simp1_res(m); m_simp(a, simp1_res); - normalizer_cfg r_cfg(m); - rewriter_tpl rwr(m, false, r_cfg); - expr_ref dl_form_e(m); - rwr(simp1_res.get(), res); + (*m_rw)(simp1_res.get(), res); /*if (simp1_res.get()!=res.get()) { std::cout<<"pre norm:\n"< m_neg; + rule * m_rule; void apply(app * a, app_ref& res); public: rule_substitution(context & ctx) - : m(ctx.get_manager()), m_context(ctx), m_subst(m), m_unif(m), m_rule(0) {} + : m(ctx.get_manager()), m_context(ctx), m_subst(m), m_unif(m), m_head(m), m_tail(m), m_rule(0) {} /** Reset substitution and get it ready for working with rule r. @@ -61,13 +63,17 @@ namespace datalog { } }; + class normalizer_cfg; + class normalizer_rw; + ast_manager & m; context & m_context; th_rewriter & m_simp; arith_util a; rule_substitution m_rule_subst; + normalizer_cfg* m_cfg; + normalizer_rw* m_rw; - class normalizer_cfg; void simplify_expr(app * a, expr_ref& res); @@ -77,13 +83,8 @@ namespace datalog { /** Return true if something was modified */ bool transform_rules(const rule_set & orig, rule_set & tgt); public: - mk_interp_tail_simplifier(context & ctx, unsigned priority=40000) - : plugin(priority), - m(ctx.get_manager()), - m_context(ctx), - m_simp(ctx.get_rewriter()), - a(m), - m_rule_subst(ctx) {} + mk_interp_tail_simplifier(context & ctx, unsigned priority=40000); + virtual ~mk_interp_tail_simplifier(); /**If rule should be retained, assign transformed version to res and return true; if rule can be deleted, return false. diff --git a/src/muz_qe/dl_mk_magic_sets.cpp b/src/muz_qe/dl_mk_magic_sets.cpp index 54ffdc805..f6f79f348 100644 --- a/src/muz_qe/dl_mk_magic_sets.cpp +++ b/src/muz_qe/dl_mk_magic_sets.cpp @@ -28,6 +28,7 @@ namespace datalog { plugin(10000, true), m_context(ctx), m(ctx.get_manager()), + rm(ctx.get_rule_manager()), m_pinned(m), m_goal(goal, m) { } @@ -259,7 +260,7 @@ namespace datalog { } new_tail.push_back(curr); negations.push_back(r->is_neg_tail(curr_index)); - collect_vars(m, curr, bound_vars); + bound_vars |= rm.collect_vars(curr); } diff --git a/src/muz_qe/dl_mk_magic_sets.h b/src/muz_qe/dl_mk_magic_sets.h index dfc66e7ea..3496a5967 100644 --- a/src/muz_qe/dl_mk_magic_sets.h +++ b/src/muz_qe/dl_mk_magic_sets.h @@ -95,6 +95,7 @@ namespace datalog { context & m_context; ast_manager & m; + rule_manager& rm; ast_ref_vector m_pinned; /** \brief Predicates from the original set that appear in a head of a rule diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp index 5bbeb2378..4afc1d323 100644 --- a/src/muz_qe/dl_mk_rule_inliner.cpp +++ b/src/muz_qe/dl_mk_rule_inliner.cpp @@ -505,9 +505,6 @@ namespace datalog { unsigned head_arity = head_pred->get_arity(); - //var_idx_set head_vars; - //var_idx_set same_strat_vars; - //collect_vars(m, r->get_head(), head_vars); unsigned pt_len = r->get_positive_tail_size(); for (unsigned ti=0; tiget_head(), same_strat_vars); if (pred->get_arity()>head_arity || (pred->get_arity()==head_arity && pred->get_id()>=head_pred->get_id()) ) { return false; diff --git a/src/muz_qe/dl_mk_simple_joins.cpp b/src/muz_qe/dl_mk_simple_joins.cpp index 2fec78066..990125475 100644 --- a/src/muz_qe/dl_mk_simple_joins.cpp +++ b/src/muz_qe/dl_mk_simple_joins.cpp @@ -29,7 +29,8 @@ namespace datalog { mk_simple_joins::mk_simple_joins(context & ctx): plugin(1000), - m_context(ctx) { + m_context(ctx), + rm(ctx.get_rule_manager()) { } class join_planner { @@ -120,6 +121,7 @@ namespace datalog { context & m_context; ast_manager & m; + rule_manager & rm; var_subst & m_var_subst; rule_set & m_rs_aux_copy; //reference to a rule_set that will allow to ask for stratum levels @@ -130,10 +132,13 @@ namespace datalog { ptr_hashtable, ptr_eq > m_modified_rules; ast_ref_vector m_pinned; + mutable ptr_vector m_vars; public: join_planner(context & ctx, rule_set & rs_aux_copy) - : m_context(ctx), m(ctx.get_manager()), m_var_subst(ctx.get_var_subst()), + : m_context(ctx), m(ctx.get_manager()), + rm(ctx.get_rule_manager()), + m_var_subst(ctx.get_var_subst()), m_rs_aux_copy(rs_aux_copy), m_introduced_rules(ctx.get_rule_manager()), m_pinned(ctx.get_manager()) @@ -175,9 +180,7 @@ namespace datalog { unsigned max_var_idx = 0; { - var_idx_set orig_var_set; - collect_vars(m, t1, orig_var_set); - collect_vars(m, t2, orig_var_set); + var_idx_set& orig_var_set = rm.collect_vars(t1, t2); var_idx_set::iterator ovit = orig_var_set.begin(); var_idx_set::iterator ovend = orig_var_set.end(); for(; ovit!=ovend; ++ovit) { @@ -323,14 +326,13 @@ namespace datalog { } for(unsigned i=0; iget_tail(i); - var_idx_set t1_vars; - collect_vars(m, t1, t1_vars); + var_idx_set t1_vars = rm.collect_vars(t1); counter.count_vars(m, t1, -1); //temporarily remove t1 variables from counter for(unsigned j=i+1; jget_tail(j); counter.count_vars(m, t2, -1); //temporarily remove t2 variables from counter - var_idx_set scope_vars(t1_vars); - collect_vars(m, t2, scope_vars); + var_idx_set scope_vars = rm.collect_vars(t2); + scope_vars |= t1_vars; var_idx_set non_local_vars; counter.collect_positive(non_local_vars); counter.count_vars(m, t2, 1); //restore t2 variables in counter @@ -472,8 +474,7 @@ namespace datalog { while(!added_tails.empty()) { app * a_tail = added_tails.back(); //added tail - var_idx_set a_tail_vars; - collect_vars(m, a_tail, a_tail_vars); + var_idx_set a_tail_vars = rm.collect_vars(a_tail); counter.count_vars(m, a_tail, -1); //temporarily remove a_tail variables from counter for(unsigned i=0; iget_idx(); - var_idx_set tail_vars; - collect_tail_vars(m, r, tail_vars); - - return tail_vars.contains(var_idx); + return rm.collect_tail_vars(r).contains(var_idx); } void mk_unbound_compressor::add_task(func_decl * pred, unsigned arg_index) { @@ -83,8 +81,7 @@ namespace datalog { void mk_unbound_compressor::detect_tasks(rule_set const& source, unsigned rule_index) { rule * r = m_rules.get(rule_index); - var_idx_set tail_vars; - collect_tail_vars(m, r, tail_vars); + var_idx_set& tail_vars = rm.collect_tail_vars(r); app * head = r->get_head(); func_decl * head_pred = head->get_decl(); @@ -94,9 +91,9 @@ namespace datalog { } unsigned n = head_pred->get_arity(); - - var_counter head_var_counter; - head_var_counter.count_vars(m, head, 1); + + rm.get_counter().reset(); + rm.get_counter().count_vars(m, head, 1); for (unsigned i=0; iget_arg(i); @@ -107,7 +104,7 @@ namespace datalog { if (!tail_vars.contains(var_idx)) { //unbound - unsigned occurence_cnt = head_var_counter.get(var_idx); + unsigned occurence_cnt = rm.get_counter().get(var_idx); SASSERT(occurence_cnt>0); if (occurence_cnt == 1) { TRACE("dl", r->display(m_context, tout << "Compress: ");); @@ -121,15 +118,14 @@ namespace datalog { void mk_unbound_compressor::try_compress(rule_set const& source, unsigned rule_index) { start: rule * r = m_rules.get(rule_index); - var_idx_set tail_vars; - collect_tail_vars(m, r, tail_vars); + var_idx_set& tail_vars = rm.collect_tail_vars(r); app * head = r->get_head(); func_decl * head_pred = head->get_decl(); unsigned head_arity = head_pred->get_arity(); - var_counter head_var_counter; - head_var_counter.count_vars(m, head); + rm.get_counter().reset(); + rm.get_counter().count_vars(m, head); unsigned arg_index; for (arg_index = 0; arg_index < head_arity; arg_index++) { @@ -140,7 +136,7 @@ namespace datalog { unsigned var_idx = to_var(arg)->get_idx(); if (!tail_vars.contains(var_idx)) { //unbound - unsigned occurence_cnt = head_var_counter.get(var_idx); + unsigned occurence_cnt = rm.get_counter().get(var_idx); SASSERT(occurence_cnt>0); if ( occurence_cnt==1 && m_in_progress.contains(c_info(head_pred, arg_index)) ) { //we have found what to compress diff --git a/src/muz_qe/dl_mk_unbound_compressor.h b/src/muz_qe/dl_mk_unbound_compressor.h index 4e56a74fc..4e2ff0b3c 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.h +++ b/src/muz_qe/dl_mk_unbound_compressor.h @@ -52,6 +52,7 @@ namespace datalog { context & m_context; ast_manager & m; + rule_manager & rm; rule_ref_vector m_rules; bool m_modified; todo_stack m_todo; diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 32f3a5fe8..59d316ae7 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -48,7 +48,9 @@ namespace datalog { rule_manager::rule_manager(context& ctx) : m(ctx.get_manager()), - m_ctx(ctx) {} + m_ctx(ctx), + m_cfg(m), + m_rwr(m, false, m_cfg) {} void rule_manager::inc_ref(rule * r) { if (r) { @@ -67,29 +69,20 @@ namespace datalog { } } - class remove_label_cfg : public default_rewriter_cfg { - family_id m_label_fid; - public: - remove_label_cfg(ast_manager& m): m_label_fid(m.get_label_family_id()) {} - virtual ~remove_label_cfg() {} - - br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, - proof_ref & result_pr) - { - if (is_decl_of(f, m_label_fid, OP_LABEL)) { - SASSERT(num == 1); - result = args[0]; - return BR_DONE; - } - return BR_FAILED; + br_status rule_manager::remove_label_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, + proof_ref & result_pr) + { + if (is_decl_of(f, m_label_fid, OP_LABEL)) { + SASSERT(num == 1); + result = args[0]; + return BR_DONE; } - }; + return BR_FAILED; + } void rule_manager::remove_labels(expr_ref& fml, proof_ref& pr) { expr_ref tmp(m); - remove_label_cfg r_cfg(m); - rewriter_tpl rwr(m, false, r_cfg); - rwr(fml, tmp); + m_rwr(fml, tmp); if (pr && fml != tmp) { pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp)); @@ -97,6 +90,67 @@ namespace datalog { fml = tmp; } + var_idx_set& rule_manager::collect_vars(expr* e) { + return collect_vars(e, 0); + } + + var_idx_set& rule_manager::collect_vars(expr* e1, expr* e2) { + reset_collect_vars(); + if (e1) accumulate_vars(e1); + if (e2) accumulate_vars(e2); + return finalize_collect_vars(); + } + + void rule_manager::reset_collect_vars() { + m_vars.reset(); + m_var_idx.reset(); + m_todo.reset(); + m_mark.reset(); + } + + var_idx_set& rule_manager::finalize_collect_vars() { + unsigned sz = m_vars.size(); + for (unsigned i=0; iget_tail_size(); + for (unsigned i=0;iget_tail(i)); + } + return finalize_collect_vars(); + } + + var_idx_set& rule_manager::collect_rule_vars_ex(rule * r, app* t) { + reset_collect_vars(); + unsigned n = r->get_tail_size(); + accumulate_vars(r->get_head()); + for (unsigned i=0;iget_tail(i) != t) { + accumulate_vars(r->get_tail(i)); + } + } + return finalize_collect_vars(); + } + + var_idx_set& rule_manager::collect_rule_vars(rule * r) { + reset_collect_vars(); + unsigned n = r->get_tail_size(); + accumulate_vars(r->get_head()); + for (unsigned i=0;iget_tail(i)); + } + return finalize_collect_vars(); + } + + void rule_manager::accumulate_vars(expr* e) { + ::get_free_vars(m_mark, m_todo, e, m_vars); + } + void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) { scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); @@ -570,15 +624,14 @@ namespace datalog { return; } - ptr_vector free_rule_vars; var_counter vctr; app_ref_vector tail(m); svector tail_neg; app_ref head(r->get_head(), m); - get_free_vars(r, free_rule_vars); + collect_rule_vars(r); vctr.count_vars(m, head); - + ptr_vector& free_rule_vars = m_vars; for (unsigned i = 0; i < ut_len; i++) { app * t = r->get_tail(i); @@ -906,7 +959,7 @@ namespace datalog { } void rule::norm_vars(rule_manager & rm) { - used_vars used; + used_vars& used = rm.reset_used(); get_used_vars(used); unsigned first_unsused = used.get_max_found_var_idx_plus_1(); diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index 666ddbd50..5abb64624 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -27,6 +27,7 @@ Revision History: #include"proof_converter.h" #include"model_converter.h" #include"ast_counter.h" +#include"rewriter.h" namespace datalog { @@ -47,9 +48,27 @@ namespace datalog { */ class rule_manager { + class remove_label_cfg : public default_rewriter_cfg { + family_id m_label_fid; + public: + remove_label_cfg(ast_manager& m): m_label_fid(m.get_label_family_id()) {} + virtual ~remove_label_cfg() {} + + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, + proof_ref & result_pr); + }; + ast_manager& m; context& m_ctx; rule_counter m_counter; + used_vars m_used; + ptr_vector m_vars; + var_idx_set m_var_idx; + ptr_vector m_todo; + ast_mark m_mark; + remove_label_cfg m_cfg; + rewriter_tpl m_rwr; + // only the context can create a rule_manager friend class context; @@ -90,6 +109,10 @@ namespace datalog { */ void reduce_unbound_vars(rule_ref& r); + void reset_collect_vars(); + + var_idx_set& finalize_collect_vars(); + public: ast_manager& get_manager() const { return m; } @@ -98,6 +121,24 @@ namespace datalog { void dec_ref(rule * r); + used_vars& reset_used() { m_used.reset(); return m_used; } + + var_idx_set& collect_vars(expr * pred); + + var_idx_set& collect_vars(expr * e1, expr* e2); + + var_idx_set& collect_rule_vars(rule * r); + + var_idx_set& collect_rule_vars_ex(rule * r, app* t); + + var_idx_set& collect_tail_vars(rule * r); + + void accumulate_vars(expr* pred); + + ptr_vector& get_var_sorts() { return m_vars; } + + var_idx_set& get_var_idx() { return m_var_idx; } + /** \brief Create a Datalog rule from a Horn formula. The formula is of the form (forall (...) (forall (...) (=> (and ...) head))) diff --git a/src/muz_qe/dl_sieve_relation.cpp b/src/muz_qe/dl_sieve_relation.cpp index c3ea5a3d0..e80462900 100644 --- a/src/muz_qe/dl_sieve_relation.cpp +++ b/src/muz_qe/dl_sieve_relation.cpp @@ -567,8 +567,7 @@ namespace datalog { const relation_signature sig = r.get_signature(); unsigned sz = sig.size(); - var_idx_set cond_vars; - collect_vars(m, condition, cond_vars); + var_idx_set& cond_vars = get_context().get_rule_manager().collect_vars(condition); expr_ref_vector subst_vect(m); subst_vect.resize(sz); unsigned subst_ofs = sz-1; diff --git a/src/muz_qe/dl_util.cpp b/src/muz_qe/dl_util.cpp index 95d268510..1b1042345 100644 --- a/src/muz_qe/dl_util.cpp +++ b/src/muz_qe/dl_util.cpp @@ -158,36 +158,7 @@ namespace datalog { ::get_free_vars(trm, vars); return var_idx < vars.size() && vars[var_idx] != 0; } - - - void collect_vars(ast_manager & m, expr * e, var_idx_set & result) { - ptr_vector vars; - ::get_free_vars(e, vars); - unsigned sz = vars.size(); - for(unsigned i=0; iget_tail_size(); - for(unsigned i=0;iget_tail(i), result); - } - } - - void get_free_tail_vars(rule * r, ptr_vector& sorts) { - unsigned n = r->get_tail_size(); - for(unsigned i=0;iget_tail(i), sorts); - } - } - - void get_free_vars(rule * r, ptr_vector& sorts) { - get_free_vars(r->get_head(), sorts); - get_free_tail_vars(r, sorts); - } - unsigned count_variable_arguments(app * pred) { SASSERT(is_uninterp(pred)); @@ -202,26 +173,6 @@ namespace datalog { return res; } - void collect_non_local_vars(ast_manager & m, rule const * r, app * t, var_idx_set & result) { - collect_vars(m, r->get_head(), result); - unsigned sz = r->get_tail_size(); - for (unsigned i = 0; i < sz; i++) { - app * curr = r->get_tail(i); - if (curr != t) - collect_vars(m, curr, result); - } - } - - void collect_non_local_vars(ast_manager & m, rule const * r, app * t_1, app * t_2, var_idx_set & result) { - collect_vars(m, r->get_head(), result); - unsigned sz = r->get_tail_size(); - for (unsigned i = 0; i < sz; i++) { - app * curr = r->get_tail(i); - if (curr != t_1 && curr != t_2) - collect_vars(m, curr, result); - } - } - void mk_new_rule_tail(ast_manager & m, app * pred, var_idx_set const & non_local_vars, unsigned & next_idx, varidx2var_map & varidx2var, sort_ref_buffer & new_rule_domain, expr_ref_buffer & new_rule_args, app_ref & new_pred) { expr_ref_buffer new_args(m); @@ -404,6 +355,7 @@ namespace datalog { void rule_counter::count_rule_vars(ast_manager & m, const rule * r, int coef) { + reset(); count_vars(m, r->get_head(), 1); unsigned n = r->get_tail_size(); for (unsigned i = 0; i < n; i++) { diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index 96bc8c326..70e34f91c 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -81,33 +81,13 @@ namespace datalog { void flatten_or(expr* fml, expr_ref_vector& result); - - bool contains_var(expr * trm, unsigned var_idx); - /** - \brief Collect the variables in \c pred. - \pre \c pred must be a valid head or tail. - */ - void collect_vars(ast_manager & m, expr * pred, var_idx_set & result); - void collect_tail_vars(ast_manager & m, rule * r, var_idx_set & result); - - void get_free_vars(rule * r, ptr_vector& sorts); - /** \brief Return number of arguments of \c pred that are variables */ unsigned count_variable_arguments(app * pred); - /** - \brief Store in \c result the set of variables used by \c r when ignoring the tail \c t. - */ - void collect_non_local_vars(ast_manager & m, rule const * r, app * t, var_idx_set & result); - - /** - \brief Store in \c result the set of variables used by \c r when ignoring the tail elements \c t_1 and \c t_2. - */ - void collect_non_local_vars(ast_manager & m, rule const * r, app * t_1, app * t_2, var_idx_set & result); template void copy_nonvariables(app * src, T& tgt) diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp index ff49584ff..50c3347ee 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/muz_qe/qe_lite.cpp @@ -2525,15 +2525,15 @@ public: m_params(p) { m_imp = alloc(imp, m, p); } - - virtual tactic * translate(ast_manager & m) { - return alloc(qe_lite_tactic, m, m_params); - } virtual ~qe_lite_tactic() { dealloc(m_imp); } + virtual tactic * translate(ast_manager & m) { + return alloc(qe_lite_tactic, m, m_params); + } + virtual void updt_params(params_ref const & p) { m_params = p; // m_imp->updt_params(p); diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 9c80d8c34..3e1fef906 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -316,7 +316,7 @@ namespace smt { m_nc_functor(*this) { } - ~theory_diff_logic() { + virtual ~theory_diff_logic() { reset_eh(); } diff --git a/src/util/memory_manager.cpp b/src/util/memory_manager.cpp index f5e5fa9fa..3f2e224d9 100644 --- a/src/util/memory_manager.cpp +++ b/src/util/memory_manager.cpp @@ -231,9 +231,8 @@ void * memory::allocate(size_t s) { return 0; s = s + sizeof(size_t); // we allocate an extra field! void * r = malloc(s); - if (r == 0) { + if (r == 0) throw_out_of_memory(); - } *(static_cast(r)) = s; g_memory_thread_alloc_size += s; if (g_memory_thread_alloc_size > SYNCH_THRESHOLD) { From b644fb987511b8b878c7150c5df73f1657fa26c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 26 Apr 2013 12:02:19 -0700 Subject: [PATCH 109/281] optimize rule processing Signed-off-by: Nikolaj Bjorner --- src/ast/expr_abstract.cpp | 59 ++++++++++++++++++---------------- src/ast/expr_abstract.h | 11 +++++++ src/ast/rewriter/var_subst.cpp | 16 ++++----- src/muz_qe/dl_context.cpp | 4 +-- src/muz_qe/dl_context.h | 2 ++ src/muz_qe/dl_mk_array_blast.h | 1 - 6 files changed, 55 insertions(+), 38 deletions(-) diff --git a/src/ast/expr_abstract.cpp b/src/ast/expr_abstract.cpp index 6deb4bf45..0569eb360 100644 --- a/src/ast/expr_abstract.cpp +++ b/src/ast/expr_abstract.cpp @@ -20,52 +20,50 @@ Notes: #include "expr_abstract.h" #include "map.h" -void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) { - ast_ref_vector pinned(m); - ptr_vector stack; - obj_map map; +void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) { + expr * curr = 0, *b = 0; SASSERT(n->get_ref_count() > 0); - stack.push_back(n); + m_stack.push_back(n); for (unsigned i = 0; i < num_bound; ++i) { b = bound[i]; expr* v = m.mk_var(base + num_bound - i - 1, m.get_sort(b)); - pinned.push_back(v); - map.insert(b, v); + m_pinned.push_back(v); + m_map.insert(b, v); } - while(!stack.empty()) { - curr = stack.back(); - if (map.contains(curr)) { - stack.pop_back(); + while(!m_stack.empty()) { + curr = m_stack.back(); + if (m_map.contains(curr)) { + m_stack.pop_back(); continue; } switch(curr->get_kind()) { case AST_VAR: { - map.insert(curr, curr); - stack.pop_back(); + m_map.insert(curr, curr); + m_stack.pop_back(); break; } case AST_APP: { app* a = to_app(curr); bool all_visited = true; - ptr_vector args; + m_args.reset(); for (unsigned i = 0; i < a->get_num_args(); ++i) { - if (!map.find(a->get_arg(i), b)) { - stack.push_back(a->get_arg(i)); + if (!m_map.find(a->get_arg(i), b)) { + m_stack.push_back(a->get_arg(i)); all_visited = false; } else { - args.push_back(b); + m_args.push_back(b); } } if (all_visited) { - b = m.mk_app(a->get_decl(), args.size(), args.c_ptr()); - pinned.push_back(b); - map.insert(curr, b); - stack.pop_back(); + b = m.mk_app(a->get_decl(), m_args.size(), m_args.c_ptr()); + m_pinned.push_back(b); + m_map.insert(curr, b); + m_stack.pop_back(); } break; } @@ -81,17 +79,24 @@ void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* cons } expr_abstract(m, new_base, num_bound, bound, q->get_expr(), result1); b = m.update_quantifier(q, patterns.size(), patterns.c_ptr(), result1.get()); - pinned.push_back(b); - map.insert(curr, b); - stack.pop_back(); + m_pinned.push_back(b); + m_map.insert(curr, b); + m_stack.pop_back(); break; } default: UNREACHABLE(); } } - if (!map.find(n, b)) { - UNREACHABLE(); - } + VERIFY (m_map.find(n, b)); result = b; + m_pinned.reset(); + m_map.reset(); + m_stack.reset(); + m_args.reset(); +} + +void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) { + expr_abstractor abs(m); + abs(base, num_bound, bound, n, result); } diff --git a/src/ast/expr_abstract.h b/src/ast/expr_abstract.h index c6ec7973b..3d9f3960f 100644 --- a/src/ast/expr_abstract.h +++ b/src/ast/expr_abstract.h @@ -21,6 +21,17 @@ Notes: #include"ast.h" +class expr_abstractor { + ast_manager& m; + expr_ref_vector m_pinned; + ptr_vector m_stack, m_args; + obj_map m_map; + +public: + expr_abstractor(ast_manager& m): m(m), m_pinned(m) {} + void operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result); +}; + void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result); #endif diff --git a/src/ast/rewriter/var_subst.cpp b/src/ast/rewriter/var_subst.cpp index f7f0c8aef..930267dad 100644 --- a/src/ast/rewriter/var_subst.cpp +++ b/src/ast/rewriter/var_subst.cpp @@ -57,10 +57,10 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { m_used.process(q->get_pattern(i)); unsigned num_no_patterns = q->get_num_no_patterns(); for (unsigned i = 0; i < num_no_patterns; i++) - used.process(q->get_no_pattern(i)); + m_used.process(q->get_no_pattern(i)); unsigned num_decls = q->get_num_decls(); - if (used.uses_all_vars(num_decls)) { + if (m_used.uses_all_vars(num_decls)) { q->set_no_unused_vars(); result = q; return; @@ -69,7 +69,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { ptr_buffer used_decl_sorts; buffer used_decl_names; for (unsigned i = 0; i < num_decls; ++i) { - if (used.contains(num_decls - i - 1)) { + if (m_used.contains(num_decls - i - 1)) { used_decl_sorts.push_back(q->get_decl_sort(i)); used_decl_names.push_back(q->get_decl_name(i)); } @@ -78,10 +78,10 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { unsigned num_removed = 0; expr_ref_buffer var_mapping(m); int next_idx = 0; - unsigned sz = used.get_max_found_var_idx_plus_1(); + unsigned sz = m_used.get_max_found_var_idx_plus_1(); for (unsigned i = 0; i < num_decls; ++i) { - sort * s = used.contains(i); + sort * s = m_used.contains(i); if (s) { var_mapping.push_back(m.mk_var(next_idx, s)); next_idx++; @@ -94,7 +94,7 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { // (VAR 0) is in the first position of var_mapping. for (unsigned i = num_decls; i < sz; i++) { - sort * s = used.contains(i); + sort * s = m_used.contains(i); if (s) var_mapping.push_back(m.mk_var(i - num_removed, s)); else @@ -122,11 +122,11 @@ void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) { expr_ref_buffer new_no_patterns(m); for (unsigned i = 0; i < num_patterns; i++) { - subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp); + m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp); new_patterns.push_back(tmp); } for (unsigned i = 0; i < num_no_patterns; i++) { - subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp); + m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp); new_no_patterns.push_back(tmp); } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index f283bd456..592c1ad4b 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -49,7 +49,6 @@ Revision History: #include"dl_mk_quantifier_abstraction.h" #include"dl_mk_quantifier_instantiation.h" #include"datatype_decl_plugin.h" -#include"expr_abstract.h" namespace datalog { @@ -227,6 +226,7 @@ namespace datalog { m_var_subst(m), m_rule_manager(*this), m_elim_unused_vars(m), + m_abstractor(m), m_transf(*this), m_trail(*this), m_pinned(m), @@ -307,7 +307,7 @@ namespace datalog { } else { ptr_vector sorts; - expr_abstract(m, 0, vars.size(), reinterpret_cast(vars.c_ptr()), fml, result); + m_abstractor(0, vars.size(), reinterpret_cast(vars.c_ptr()), fml, result); get_free_vars(result, sorts); if (sorts.empty()) { result = fml; diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index 2798ba8df..aba8577e1 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -45,6 +45,7 @@ Revision History: #include"model2expr.h" #include"smt_params.h" #include"dl_rule_transformer.h" +#include"expr_abstract.h" namespace datalog { @@ -85,6 +86,7 @@ namespace datalog { var_subst m_var_subst; rule_manager m_rule_manager; unused_vars_eliminator m_elim_unused_vars; + expr_abstractor m_abstractor; rule_transformer m_transf; trail_stack m_trail; ast_ref_vector m_pinned; diff --git a/src/muz_qe/dl_mk_array_blast.h b/src/muz_qe/dl_mk_array_blast.h index 74ac9ec97..21f2a0bf7 100644 --- a/src/muz_qe/dl_mk_array_blast.h +++ b/src/muz_qe/dl_mk_array_blast.h @@ -38,7 +38,6 @@ namespace datalog { rule_manager& rm; params_ref m_params; th_rewriter m_rewriter; - ptr_vector m_vars; mk_interp_tail_simplifier m_simplifier; typedef obj_map defs_t; From 8038c719fb2d4fce1c3841f0fa6bbe74e4455d10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 26 Apr 2013 14:40:20 -0700 Subject: [PATCH 110/281] optimize rule preprocessing Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/ast_counter.cpp | 18 +++--- src/muz_qe/dl_context.cpp | 30 ++++------ src/muz_qe/dl_context.h | 17 ++++++ src/muz_qe/dl_mk_interp_tail_simplifier.cpp | 63 +++++++++++---------- src/muz_qe/dl_mk_interp_tail_simplifier.h | 6 ++ src/muz_qe/dl_rule.cpp | 63 ++++++++++----------- src/muz_qe/dl_rule.h | 8 +++ src/muz_qe/hnf.cpp | 33 ++++++----- src/muz_qe/horn_subsume_model_converter.cpp | 17 ++++-- src/muz_qe/horn_subsume_model_converter.h | 6 +- 10 files changed, 149 insertions(+), 112 deletions(-) diff --git a/src/ast/rewriter/ast_counter.cpp b/src/ast/rewriter/ast_counter.cpp index 099bdedec..a807237c5 100644 --- a/src/ast/rewriter/ast_counter.cpp +++ b/src/ast/rewriter/ast_counter.cpp @@ -110,24 +110,27 @@ unsigned var_counter::get_max_var(bool& has_var) { unsigned max_var = 0; while (!m_todo.empty()) { expr* e = m_todo.back(); - unsigned scope = m_scopes.back(); m_todo.pop_back(); - m_scopes.pop_back(); if (m_visited.is_marked(e)) { continue; } m_visited.mark(e, true); switch(e->get_kind()) { case AST_QUANTIFIER: { + var_counter aux_counter; quantifier* q = to_quantifier(e); - m_todo.push_back(q->get_expr()); - m_scopes.push_back(scope + q->get_num_decls()); + bool has_var1 = false; + unsigned max_v = aux_counter.get_max_var(has_var1); + if (max_v > max_var + q->get_num_decls()) { + max_var = max_v - q->get_num_decls(); + has_var = true; + } break; } case AST_VAR: { - if (to_var(e)->get_idx() >= scope + max_var) { + if (to_var(e)->get_idx() >= max_var) { has_var = true; - max_var = to_var(e)->get_idx() - scope; + max_var = to_var(e)->get_idx(); } break; } @@ -135,7 +138,6 @@ unsigned var_counter::get_max_var(bool& has_var) { app* a = to_app(e); for (unsigned i = 0; i < a->get_num_args(); ++i) { m_todo.push_back(a->get_arg(i)); - m_scopes.push_back(scope); } break; } @@ -152,14 +154,12 @@ unsigned var_counter::get_max_var(bool& has_var) { unsigned var_counter::get_max_var(expr* e) { bool has_var = false; m_todo.push_back(e); - m_scopes.push_back(0); return get_max_var(has_var); } unsigned var_counter::get_next_var(expr* e) { bool has_var = false; m_todo.push_back(e); - m_scopes.push_back(0); unsigned mv = get_max_var(has_var); if (has_var) mv++; return mv; diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 592c1ad4b..6aebf6e43 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -41,7 +41,6 @@ Revision History: #include"for_each_expr.h" #include"ast_smt_pp.h" #include"ast_smt2_pp.h" -#include"expr_functors.h" #include"dl_mk_partial_equiv.h" #include"dl_mk_bit_blast.h" #include"dl_mk_array_blast.h" @@ -227,6 +226,8 @@ namespace datalog { m_rule_manager(*this), m_elim_unused_vars(m), m_abstractor(m), + m_contains_p(*this), + m_check_pred(m_contains_p, m), m_transf(*this), m_trail(*this), m_pinned(m), @@ -302,18 +303,19 @@ namespace datalog { expr_ref context::bind_variables(expr* fml, bool is_forall) { expr_ref result(m); app_ref_vector const & vars = m_vars; + rule_manager& rm = get_rule_manager(); if (vars.empty()) { result = fml; } else { - ptr_vector sorts; + m_names.reset(); m_abstractor(0, vars.size(), reinterpret_cast(vars.c_ptr()), fml, result); - get_free_vars(result, sorts); + rm.collect_vars(result); + ptr_vector& sorts = rm.get_var_sorts(); if (sorts.empty()) { result = fml; } else { - svector names; for (unsigned i = 0; i < sorts.size(); ++i) { if (!sorts[i]) { if (i < vars.size()) { @@ -324,15 +326,15 @@ namespace datalog { } } if (i < vars.size()) { - names.push_back(vars[i]->get_decl()->get_name()); + m_names.push_back(vars[i]->get_decl()->get_name()); } else { - names.push_back(symbol(i)); + m_names.push_back(symbol(i)); } } quantifier_ref q(m); sorts.reverse(); - q = m.mk_quantifier(is_forall, sorts.size(), sorts.c_ptr(), names.c_ptr(), result); + q = m.mk_quantifier(is_forall, sorts.size(), sorts.c_ptr(), m_names.c_ptr(), result); m_elim_unused_vars(q, result); } } @@ -608,28 +610,16 @@ namespace datalog { } } - class context::contains_pred : public i_expr_pred { - context const& ctx; - public: - contains_pred(context& ctx): ctx(ctx) {} - virtual ~contains_pred() {} - - virtual bool operator()(expr* e) { - return ctx.is_predicate(e); - } - }; void context::check_existential_tail(rule_ref& r) { unsigned ut_size = r->get_uninterpreted_tail_size(); unsigned t_size = r->get_tail_size(); - contains_pred contains_p(*this); - check_pred check_pred(contains_p, get_manager()); TRACE("dl", r->display_smt2(get_manager(), tout); tout << "\n";); for (unsigned i = ut_size; i < t_size; ++i) { app* t = r->get_tail(i); TRACE("dl", tout << "checking: " << mk_ismt2_pp(t, get_manager()) << "\n";); - if (check_pred(t)) { + if (m_check_pred(t)) { std::ostringstream out; out << "interpreted body " << mk_ismt2_pp(t, get_manager()) << " contains recursive predicate"; throw default_exception(out.str()); diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index aba8577e1..55b9f3010 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -46,6 +46,8 @@ Revision History: #include"smt_params.h" #include"dl_rule_transformer.h" #include"expr_abstract.h" +#include"expr_functors.h" + namespace datalog { @@ -77,6 +79,18 @@ namespace datalog { typedef obj_map > pred2syms; typedef obj_map sort_domain_map; + class contains_pred : public i_expr_pred { + context const& ctx; + public: + contains_pred(context& ctx): ctx(ctx) {} + virtual ~contains_pred() {} + + virtual bool operator()(expr* e) { + return ctx.is_predicate(e); + } + }; + + ast_manager & m; smt_params & m_fparams; params_ref m_params_ref; @@ -87,10 +101,13 @@ namespace datalog { rule_manager m_rule_manager; unused_vars_eliminator m_elim_unused_vars; expr_abstractor m_abstractor; + contains_pred m_contains_p; + check_pred m_check_pred; rule_transformer m_transf; trail_stack m_trail; ast_ref_vector m_pinned; app_ref_vector m_vars; + svector m_names; sort_domain_map m_sorts; func_decl_set m_preds; sym2decl m_preds_by_name; diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp index 8a9b1257a..afd586627 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.cpp @@ -369,11 +369,14 @@ namespace datalog { mk_interp_tail_simplifier::mk_interp_tail_simplifier(context & ctx, unsigned priority) : plugin(priority), - m(ctx.get_manager()), - m_context(ctx), - m_simp(ctx.get_rewriter()), - a(m), - m_rule_subst(ctx) { + m(ctx.get_manager()), + m_context(ctx), + m_simp(ctx.get_rewriter()), + a(m), + m_rule_subst(ctx), + m_tail(m), + m_itail_members(m), + m_conj(m) { m_cfg = alloc(normalizer_cfg, m); m_rw = alloc(normalizer_rw, m, *m_cfg); } @@ -404,15 +407,15 @@ namespace datalog { return false; } - ptr_vector todo; + m_todo.reset(); + m_leqs.reset(); for (unsigned i = u_len; i < len; i++) { - todo.push_back(r->get_tail(i)); + m_todo.push_back(r->get_tail(i)); SASSERT(!r->is_neg_tail(i)); } m_rule_subst.reset(r); - obj_hashtable leqs; expr_ref_vector trail(m); expr_ref tmp1(m), tmp2(m); bool found_something = false; @@ -420,10 +423,10 @@ namespace datalog { #define TRY_UNIFY(_x,_y) if (m_rule_subst.unify(_x,_y)) { found_something = true; } #define IS_FLEX(_x) (is_var(_x) || m.is_value(_x)) - while (!todo.empty()) { + while (!m_todo.empty()) { expr * arg1, *arg2; - expr * t0 = todo.back(); - todo.pop_back(); + expr * t0 = m_todo.back(); + m_todo.pop_back(); expr* t = t0; bool neg = m.is_not(t, t); if (is_var(t)) { @@ -431,7 +434,7 @@ namespace datalog { } else if (!neg && m.is_and(t)) { app* a = to_app(t); - todo.append(a->get_num_args(), a->get_args()); + m_todo.append(a->get_num_args(), a->get_args()); } else if (!neg && m.is_eq(t, arg1, arg2) && IS_FLEX(arg1) && IS_FLEX(arg2)) { TRY_UNIFY(arg1, arg2); @@ -459,12 +462,12 @@ namespace datalog { else if (!neg && (a.is_le(t, arg1, arg2) || a.is_ge(t, arg2, arg1))) { tmp1 = a.mk_sub(arg1, arg2); tmp2 = a.mk_sub(arg2, arg1); - if (false && leqs.contains(tmp2) && IS_FLEX(arg1) && IS_FLEX(arg2)) { + if (false && m_leqs.contains(tmp2) && IS_FLEX(arg1) && IS_FLEX(arg2)) { TRY_UNIFY(arg1, arg2); } else { trail.push_back(tmp1); - leqs.insert(tmp1); + m_leqs.insert(tmp1); } } } @@ -504,12 +507,12 @@ namespace datalog { } app_ref head(r->get_head(), m); - app_ref_vector tail(m); - svector tail_neg; + m_tail.reset(); + m_tail_neg.reset(); for (unsigned i=0; iget_tail(i)); - tail_neg.push_back(r->is_neg_tail(i)); + m_tail.push_back(r->get_tail(i)); + m_tail_neg.push_back(r->is_neg_tail(i)); } bool modified = false; @@ -521,12 +524,12 @@ namespace datalog { SASSERT(!r->is_neg_tail(u_len)); } else { - expr_ref_vector itail_members(m); + m_itail_members.reset(); for (unsigned i=u_len; iget_tail(i)); + m_itail_members.push_back(r->get_tail(i)); SASSERT(!r->is_neg_tail(i)); } - itail = m.mk_and(itail_members.size(), itail_members.c_ptr()); + itail = m.mk_and(m_itail_members.size(), m_itail_members.c_ptr()); modified = true; } @@ -542,21 +545,21 @@ namespace datalog { SASSERT(m.is_bool(simp_res)); if (modified) { - expr_ref_vector conjs(m); - flatten_and(simp_res, conjs); - for (unsigned i = 0; i < conjs.size(); ++i) { - expr* e = conjs[i].get(); + m_conj.reset(); + flatten_and(simp_res, m_conj); + for (unsigned i = 0; i < m_conj.size(); ++i) { + expr* e = m_conj[i].get(); if (is_app(e)) { - tail.push_back(to_app(e)); + m_tail.push_back(to_app(e)); } else { - tail.push_back(m.mk_eq(e, m.mk_true())); + m_tail.push_back(m.mk_eq(e, m.mk_true())); } - tail_neg.push_back(false); + m_tail_neg.push_back(false); } - SASSERT(tail.size() == tail_neg.size()); - res = m_context.get_rule_manager().mk(head, tail.size(), tail.c_ptr(), tail_neg.c_ptr()); + SASSERT(m_tail.size() == m_tail_neg.size()); + res = m_context.get_rule_manager().mk(head, m_tail.size(), m_tail.c_ptr(), m_tail_neg.c_ptr()); res->set_accounting_parent_object(m_context, r); } else { diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.h b/src/muz_qe/dl_mk_interp_tail_simplifier.h index 99e0b575a..5047e1c6e 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.h +++ b/src/muz_qe/dl_mk_interp_tail_simplifier.h @@ -71,6 +71,12 @@ namespace datalog { th_rewriter & m_simp; arith_util a; rule_substitution m_rule_subst; + ptr_vector m_todo; + obj_hashtable m_leqs; + app_ref_vector m_tail; + expr_ref_vector m_itail_members; + expr_ref_vector m_conj; + svector m_tail_neg; normalizer_cfg* m_cfg; normalizer_rw* m_rw; diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 59d316ae7..e43445396 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -40,15 +40,18 @@ Revision History: #include"quant_hoist.h" #include"expr_replacer.h" #include"bool_rewriter.h" -#include"qe_lite.h" #include"expr_safe_replace.h" -#include"hnf.h" namespace datalog { rule_manager::rule_manager(context& ctx) : m(ctx.get_manager()), m_ctx(ctx), + m_body(m), + m_head(m), + m_args(m), + m_hnf(m), + m_qe(m), m_cfg(m), m_rwr(m, false, m_cfg) {} @@ -179,13 +182,13 @@ namespace datalog { } void rule_manager::mk_rule_core(expr* fml, proof* p, rule_set& rules, symbol const& name) { - hnf h(m); expr_ref_vector fmls(m); proof_ref_vector prs(m); - h.set_name(name); - h(fml, p, fmls, prs); - for (unsigned i = 0; i < h.get_fresh_predicates().size(); ++i) { - m_ctx.register_predicate(h.get_fresh_predicates()[i], false); + m_hnf.reset(); + m_hnf.set_name(name); + m_hnf(fml, p, fmls, prs); + for (unsigned i = 0; i < m_hnf.get_fresh_predicates().size(); ++i) { + m_ctx.register_predicate(m_hnf.get_fresh_predicates()[i], false); } for (unsigned i = 0; i < fmls.size(); ++i) { mk_horn_rule(fmls[i].get(), prs[i].get(), rules, name); @@ -194,24 +197,23 @@ namespace datalog { void rule_manager::mk_horn_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) { - app_ref_vector body(m); - app_ref head(m); - svector is_negated; - unsigned index = extract_horn(fml, body, head); - hoist_compound_predicates(index, head, body); + m_body.reset(); + m_neg.reset(); + unsigned index = extract_horn(fml, m_body, m_head); + hoist_compound_predicates(index, m_head, m_body); TRACE("dl_rule", tout << mk_pp(head, m) << " :- "; - for (unsigned i = 0; i < body.size(); ++i) { - tout << mk_pp(body[i].get(), m) << " "; + for (unsigned i = 0; i < m_body.size(); ++i) { + tout << mk_pp(m_body[i].get(), m) << " "; } tout << "\n";); - mk_negations(body, is_negated); - check_valid_rule(head, body.size(), body.c_ptr()); + mk_negations(m_body, m_neg); + check_valid_rule(m_head, m_body.size(), m_body.c_ptr()); rule_ref r(*this); - r = mk(head.get(), body.size(), body.c_ptr(), is_negated.c_ptr(), name); + r = mk(m_head.get(), m_body.size(), m_body.c_ptr(), m_neg.c_ptr(), name); expr_ref fml1(m); if (p) { @@ -380,28 +382,28 @@ namespace datalog { fml = m.mk_not(fml); return; } - expr_ref_vector args(m); if (!m_ctx.is_predicate(fml)) { return; } + m_args.reset(); for (unsigned i = 0; i < fml->get_num_args(); ++i) { e = fml->get_arg(i); if (!is_app(e)) { - args.push_back(e); + m_args.push_back(e); continue; } app* b = to_app(e); if (m.is_value(b)) { - args.push_back(e); + m_args.push_back(e); } else { var* v = m.mk_var(num_bound++, m.get_sort(b)); - args.push_back(v); + m_args.push_back(v); body.push_back(m.mk_eq(v, b)); } } - fml = m.mk_app(fml->get_decl(), args.size(), args.c_ptr()); + fml = m.mk_app(fml->get_decl(), m_args.size(), m_args.c_ptr()); TRACE("dl_rule", tout << mk_pp(fml.get(), m) << "\n";); } @@ -565,29 +567,22 @@ namespace datalog { void rule_manager::reduce_unbound_vars(rule_ref& r) { unsigned ut_len = r->get_uninterpreted_tail_size(); unsigned t_len = r->get_tail_size(); - ptr_vector vars; - uint_set index_set; - qe_lite qe(m); expr_ref_vector conjs(m); if (ut_len == t_len) { return; } - get_free_vars(r->get_head(), vars); + reset_collect_vars(); + accumulate_vars(r->get_head()); for (unsigned i = 0; i < ut_len; ++i) { - get_free_vars(r->get_tail(i), vars); + accumulate_vars(r->get_tail(i)); } + var_idx_set& index_set = finalize_collect_vars(); for (unsigned i = ut_len; i < t_len; ++i) { conjs.push_back(r->get_tail(i)); } - - for (unsigned i = 0; i < vars.size(); ++i) { - if (vars[i]) { - index_set.insert(i); - } - } - qe(index_set, false, conjs); + m_qe(index_set, false, conjs); bool change = conjs.size() != t_len - ut_len; for (unsigned i = 0; !change && i < conjs.size(); ++i) { change = r->get_tail(ut_len+i) != conjs[i].get(); diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index 5abb64624..6335c506f 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -28,6 +28,8 @@ Revision History: #include"model_converter.h" #include"ast_counter.h" #include"rewriter.h" +#include"hnf.h" +#include"qe_lite.h" namespace datalog { @@ -66,6 +68,12 @@ namespace datalog { var_idx_set m_var_idx; ptr_vector m_todo; ast_mark m_mark; + app_ref_vector m_body; + app_ref m_head; + expr_ref_vector m_args; + svector m_neg; + hnf m_hnf; + qe_lite m_qe; remove_label_cfg m_cfg; rewriter_tpl m_rwr; diff --git a/src/muz_qe/hnf.cpp b/src/muz_qe/hnf.cpp index 5a7d1c4ba..764d31bb6 100644 --- a/src/muz_qe/hnf.cpp +++ b/src/muz_qe/hnf.cpp @@ -71,6 +71,9 @@ class hnf::imp { obj_map m_memoize_disj; obj_map m_memoize_proof; func_decl_ref_vector m_fresh_predicates; + expr_ref_vector m_body; + proof_ref_vector m_defs; + public: imp(ast_manager & m): @@ -82,7 +85,9 @@ public: m_refs(m), m_name("P"), m_qh(m), - m_fresh_predicates(m) { + m_fresh_predicates(m), + m_body(m), + m_defs(m) { } void operator()(expr * n, @@ -182,13 +187,13 @@ private: void mk_horn(expr_ref& fml, proof_ref& premise) { expr* e1, *e2; - expr_ref_vector body(m); - proof_ref_vector defs(m); expr_ref fml0(m), fml1(m), fml2(m), head(m); proof_ref p(m); fml0 = fml; m_names.reset(); m_sorts.reset(); + m_body.reset(); + m_defs.reset(); m_qh.pull_quantifier(true, fml0, &m_sorts, &m_names); if (premise){ fml1 = bind_variables(fml0); @@ -199,12 +204,12 @@ private: } head = fml0; while (m.is_implies(head, e1, e2)) { - body.push_back(e1); + m_body.push_back(e1); head = e2; } - datalog::flatten_and(body); + datalog::flatten_and(m_body); if (premise) { - p = m.mk_rewrite(fml0, mk_implies(body, head)); + p = m.mk_rewrite(fml0, mk_implies(m_body, head)); } // @@ -214,8 +219,8 @@ private: // A -> C // B -> C // - if (body.size() == 1 && m.is_or(body[0].get()) && contains_predicate(body[0].get())) { - app* _or = to_app(body[0].get()); + if (m_body.size() == 1 && m.is_or(m_body[0].get()) && contains_predicate(m_body[0].get())) { + app* _or = to_app(m_body[0].get()); unsigned sz = _or->get_num_args(); expr* const* args = _or->get_args(); for (unsigned i = 0; i < sz; ++i) { @@ -224,7 +229,7 @@ private: } if (premise) { - expr_ref f1 = bind_variables(mk_implies(body, head)); + expr_ref f1 = bind_variables(mk_implies(m_body, head)); expr* f2 = m.mk_and(sz, m_todo.c_ptr()+m_todo.size()-sz); proof_ref p2(m), p3(m); p2 = m.mk_def_axiom(m.mk_iff(f1, f2)); @@ -240,13 +245,13 @@ private: } - eliminate_disjunctions(body, defs); - p = mk_congruence(p, body, head, defs); + eliminate_disjunctions(m_body, m_defs); + p = mk_congruence(p, m_body, head, m_defs); - eliminate_quantifier_body(body, defs); - p = mk_congruence(p, body, head, defs); + eliminate_quantifier_body(m_body, m_defs); + p = mk_congruence(p, m_body, head, m_defs); - fml2 = mk_implies(body, head); + fml2 = mk_implies(m_body, head); fml = bind_variables(fml2); diff --git a/src/muz_qe/horn_subsume_model_converter.cpp b/src/muz_qe/horn_subsume_model_converter.cpp index 374333a9c..ced4e657b 100644 --- a/src/muz_qe/horn_subsume_model_converter.cpp +++ b/src/muz_qe/horn_subsume_model_converter.cpp @@ -28,10 +28,8 @@ Revision History: #include "well_sorted.h" void horn_subsume_model_converter::insert(app* head, expr* body) { - func_decl_ref pred(m); - expr_ref body_res(m); - VERIFY(mk_horn(head, body, pred, body_res)); - insert(pred.get(), body_res.get()); + m_delay_head.push_back(head); + m_delay_body.push_back(body); } void horn_subsume_model_converter::insert(app* head, unsigned sz, expr* const* body) { @@ -148,6 +146,7 @@ bool horn_subsume_model_converter::mk_horn( } void horn_subsume_model_converter::add_default_proc::operator()(app* n) { + // // predicates that have not been assigned values // in the Horn model are assumed false. @@ -174,6 +173,16 @@ void horn_subsume_model_converter::add_default_false_interpretation(expr* e, mod void horn_subsume_model_converter::operator()(model_ref& mr) { + + func_decl_ref pred(m); + expr_ref body_res(m); + for (unsigned i = 0; i < m_delay_head.size(); ++i) { + VERIFY(mk_horn(m_delay_head[i].get(), m_delay_body[i].get(), pred, body_res)); + insert(pred.get(), body_res.get()); + } + m_delay_head.reset(); + m_delay_body.reset(); + TRACE("mc", tout << m_funcs.size() << "\n"; model_smt2_pp(tout, m, *mr, 0);); for (unsigned i = m_funcs.size(); i > 0; ) { --i; diff --git a/src/muz_qe/horn_subsume_model_converter.h b/src/muz_qe/horn_subsume_model_converter.h index edde02b19..993f29cc9 100644 --- a/src/muz_qe/horn_subsume_model_converter.h +++ b/src/muz_qe/horn_subsume_model_converter.h @@ -43,6 +43,8 @@ class horn_subsume_model_converter : public model_converter { func_decl_ref_vector m_funcs; expr_ref_vector m_bodies; th_rewriter m_rewrite; + app_ref_vector m_delay_head; + expr_ref_vector m_delay_body; void add_default_false_interpretation(expr* e, model_ref& md); @@ -56,7 +58,9 @@ class horn_subsume_model_converter : public model_converter { public: - horn_subsume_model_converter(ast_manager& m): m(m), m_funcs(m), m_bodies(m), m_rewrite(m) {} + horn_subsume_model_converter(ast_manager& m): + m(m), m_funcs(m), m_bodies(m), m_rewrite(m), + m_delay_head(m), m_delay_body(m) {} bool mk_horn(expr* clause, func_decl_ref& pred, expr_ref& body); From 65b52ba3e918db250ebdac7ee11836b8ddde6e81 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 26 Apr 2013 16:10:46 -0700 Subject: [PATCH 111/281] add simple bounded CLP backend Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_context.cpp | 34 ++++++++++++++++++++++++++++++++++ src/muz_qe/dl_context.h | 7 ++++++- src/muz_qe/dl_util.h | 1 + 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 6aebf6e43..0099b16f9 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -547,6 +547,8 @@ namespace datalog { throw default_exception("get_num_levels is not supported for bmc"); case TAB_ENGINE: throw default_exception("get_num_levels is not supported for tab"); + case CLP_ENGINE: + throw default_exception("get_num_levels is not supported for clp"); default: throw default_exception("unknown engine"); } @@ -565,6 +567,8 @@ namespace datalog { throw default_exception("operation is not supported for BMC engine"); case TAB_ENGINE: throw default_exception("operation is not supported for TAB engine"); + case CLP_ENGINE: + throw default_exception("operation is not supported for CLP engine"); default: throw default_exception("unknown engine"); } @@ -584,6 +588,8 @@ namespace datalog { throw default_exception("operation is not supported for BMC engine"); case TAB_ENGINE: throw default_exception("operation is not supported for TAB engine"); + case CLP_ENGINE: + throw default_exception("operation is not supported for CLP engine"); default: throw default_exception("unknown engine"); } @@ -711,6 +717,10 @@ namespace datalog { check_existential_tail(r); check_positive_predicates(r); break; + case CLP_ENGINE: + check_existential_tail(r); + check_positive_predicates(r); + break; default: UNREACHABLE(); break; @@ -984,6 +994,9 @@ namespace datalog { else if (e == symbol("tab")) { m_engine = TAB_ENGINE; } + else if (e == symbol("clp")) { + m_engine = CLP_ENGINE; + } if (m_engine == LAST_ENGINE) { expr_fast_mark1 mark; @@ -1019,6 +1032,8 @@ namespace datalog { return bmc_query(query); case TAB_ENGINE: return tab_query(query); + case CLP_ENGINE: + return clp_query(query); default: UNREACHABLE(); return rel_query(query); @@ -1083,11 +1098,22 @@ namespace datalog { } } + void context::ensure_clp() { + if (!m_clp.get()) { + m_clp = alloc(clp, *this); + } + } + lbool context::tab_query(expr* query) { ensure_tab(); return m_tab->query(query); } + lbool context::clp_query(expr* query) { + ensure_clp(); + return m_clp->query(query); + } + void context::ensure_rel() { if (!m_rel.get()) { m_rel = alloc(rel_context, *this); @@ -1128,6 +1154,10 @@ namespace datalog { ensure_tab(); m_last_answer = m_tab->get_answer(); return m_last_answer.get(); + case CLP_ENGINE: + ensure_clp(); + m_last_answer = m_clp->get_answer(); + return m_last_answer.get(); default: UNREACHABLE(); } @@ -1153,6 +1183,10 @@ namespace datalog { ensure_tab(); m_tab->display_certificate(out); return true; + case CLP_ENGINE: + ensure_clp(); + m_clp->display_certificate(out); + return true; default: return false; } diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index 55b9f3010..0a01b3e01 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -47,7 +47,7 @@ Revision History: #include"dl_rule_transformer.h" #include"expr_abstract.h" #include"expr_functors.h" - +#include"clp_context.h" namespace datalog { @@ -124,6 +124,7 @@ namespace datalog { scoped_ptr m_bmc; scoped_ptr m_rel; scoped_ptr m_tab; + scoped_ptr m_clp; bool m_closed; bool m_saturation_was_run; @@ -477,6 +478,8 @@ namespace datalog { void ensure_tab(); + void ensure_clp(); + void ensure_rel(); void new_query(); @@ -489,6 +492,8 @@ namespace datalog { lbool tab_query(expr* query); + lbool clp_query(expr* query); + void check_quantifier_free(rule_ref& r); void check_uninterpreted_free(rule_ref& r); void check_existential_tail(rule_ref& r); diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index 70e34f91c..ea2def025 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -54,6 +54,7 @@ namespace datalog { BMC_ENGINE, QBMC_ENGINE, TAB_ENGINE, + CLP_ENGINE, LAST_ENGINE }; From d1938ce972c2be03486fbb3a56e87aece9fb016d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 26 Apr 2013 16:11:07 -0700 Subject: [PATCH 112/281] add simple bounded CLP backend Signed-off-by: Nikolaj Bjorner --- src/muz_qe/clp_context.cpp | 230 +++++++++++++++++++++++++++++++++++++ src/muz_qe/clp_context.h | 45 ++++++++ 2 files changed, 275 insertions(+) create mode 100644 src/muz_qe/clp_context.cpp create mode 100644 src/muz_qe/clp_context.h diff --git a/src/muz_qe/clp_context.cpp b/src/muz_qe/clp_context.cpp new file mode 100644 index 000000000..5e683a5eb --- /dev/null +++ b/src/muz_qe/clp_context.cpp @@ -0,0 +1,230 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + tab_context.cpp + +Abstract: + + Tabulation/subsumption/cyclic proof context. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-01-15 + +Revision History: + +--*/ + +#include "clp_context.h" +#include "dl_context.h" +#include "unifier.h" +#include "var_subst.h" +#include "substitution.h" + +namespace datalog { + + class clp::imp { + struct stats { + stats() { reset(); } + void reset() { memset(this, 0, sizeof(*this)); } + unsigned m_num_unfold; + unsigned m_num_no_unfold; + unsigned m_num_subsumed; + }; + + context& m_ctx; + ast_manager& m; + rule_manager& rm; + smt_params m_fparams; + smt::kernel m_solver; + unifier m_unify; + substitution m_subst; + var_subst m_var_subst; + expr_ref_vector m_ground; + app_ref_vector m_goals; + volatile bool m_cancel; + unsigned m_deltas[2]; + unsigned m_var_cnt; + stats m_stats; + public: + imp(context& ctx): + m_ctx(ctx), + m(ctx.get_manager()), + rm(ctx.get_rule_manager()), + m_solver(m, m_fparams), + m_unify(m), + m_subst(m), + m_var_subst(m, false), + m_ground(m), + m_goals(m), + m_cancel(false) + { + // m_fparams.m_relevancy_lvl = 0; + m_fparams.m_mbqi = false; + m_fparams.m_soft_timeout = 1000; + m_deltas[0] = 0; + m_deltas[1] = m_var_cnt; + } + + ~imp() {} + + lbool query(expr* query) { + m_ctx.ensure_opened(); + m_solver.reset(); + m_goals.reset(); + rm.mk_query(query, m_ctx.get_rules()); + expr_ref head(m); + head = m_ctx.get_rules().last()->get_head(); + ground(head); + m_goals.push_back(to_app(head)); + return search(20, 0); + } + + void cancel() { + m_cancel = true; + m_solver.cancel(); + } + + void cleanup() { + m_cancel = false; + m_goals.reset(); + m_solver.reset_cancel(); + } + + void reset_statistics() { + m_stats.reset(); + } + + void collect_statistics(statistics& st) const { + //st.update("tab.num_unfold", m_stats.m_num_unfold); + //st.update("tab.num_unfold_fail", m_stats.m_num_no_unfold); + //st.update("tab.num_subsumed", m_stats.m_num_subsumed); + } + + void display_certificate(std::ostream& out) const { + expr_ref ans = get_answer(); + out << mk_pp(ans, m) << "\n"; + + } + + expr_ref get_answer() const { + return expr_ref(m.mk_true(), m); + } + + private: + + void reset_ground() { + m_ground.reset(); + } + + void ground(expr_ref& e) { + ptr_vector sorts; + get_free_vars(e, sorts); + if (m_ground.size() < sorts.size()) { + m_ground.resize(sorts.size()); + } + for (unsigned i = 0; i < sorts.size(); ++i) { + if (sorts[i] && !m_ground[i].get()) { + m_ground[i] = m.mk_fresh_const("c",sorts[i]); + } + } + m_var_subst(e, m_ground.size(), m_ground.c_ptr(), e); + } + + lbool search(unsigned depth, unsigned index) { + IF_VERBOSE(1, verbose_stream() << "search " << depth << " " << index << "\n";); + if (depth == 0) { + return l_undef; + } + if (index == m_goals.size()) { + return l_true; + } + unsigned num_goals = m_goals.size(); + app* head = m_goals[index].get(); + rule_vector const& rules = m_ctx.get_rules().get_predicate_rules(head->get_decl()); + lbool status = l_false; + for (unsigned i = 0; i < rules.size(); ++i) { + IF_VERBOSE(2, verbose_stream() << index << " " << mk_pp(head, m) << "\n";); + rule* r = rules[i]; + m_solver.push(); + reset_ground(); + expr_ref tmp(m); + tmp = r->get_head(); + ground(tmp); + for (unsigned j = 0; j < head->get_num_args(); ++j) { + expr_ref eq(m); + eq = m.mk_eq(head->get_arg(j), to_app(tmp)->get_arg(j)); + m_solver.assert_expr(eq); + } + for (unsigned j = r->get_uninterpreted_tail_size(); j < r->get_tail_size(); ++j) { + tmp = r->get_tail(j); + ground(tmp); + m_solver.assert_expr(tmp); + } + lbool is_sat = m_solver.check(); + switch (is_sat) { + case l_false: + break; + case l_true: + for (unsigned j = 0; j < r->get_uninterpreted_tail_size(); ++j) { + tmp = r->get_tail(j); + ground(tmp); + m_goals.push_back(to_app(tmp)); + } + switch(search(depth-1, index+1)) { + case l_undef: + status = l_undef; + // fallthrough + case l_false: + m_goals.resize(num_goals); + break; + case l_true: + return l_true; + } + break; + case l_undef: + status = l_undef; + throw default_exception("undef"); + } + m_solver.pop(1); + } + return status; + } + + + proof_ref get_proof() const { + return proof_ref(0, m); + } + }; + + clp::clp(context& ctx): + m_imp(alloc(imp, ctx)) { + } + clp::~clp() { + dealloc(m_imp); + } + lbool clp::query(expr* query) { + return m_imp->query(query); + } + void clp::cancel() { + m_imp->cancel(); + } + void clp::cleanup() { + m_imp->cleanup(); + } + void clp::reset_statistics() { + m_imp->reset_statistics(); + } + void clp::collect_statistics(statistics& st) const { + m_imp->collect_statistics(st); + } + void clp::display_certificate(std::ostream& out) const { + m_imp->display_certificate(out); + } + expr_ref clp::get_answer() { + return m_imp->get_answer(); + } + +}; diff --git a/src/muz_qe/clp_context.h b/src/muz_qe/clp_context.h new file mode 100644 index 000000000..cd9117553 --- /dev/null +++ b/src/muz_qe/clp_context.h @@ -0,0 +1,45 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + clp_context.h + +Abstract: + + Bounded CLP (symbolic simulation using Z3) context. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-01-15 + +Revision History: + +--*/ +#ifndef _CLP_CONTEXT_H_ +#define _CLP_CONTEXT_H_ + +#include "ast.h" +#include "lbool.h" +#include "statistics.h" + +namespace datalog { + class context; + + class clp { + class imp; + imp* m_imp; + public: + clp(context& ctx); + ~clp(); + lbool query(expr* query); + void cancel(); + void cleanup(); + void reset_statistics(); + void collect_statistics(statistics& st) const; + void display_certificate(std::ostream& out) const; + expr_ref get_answer(); + }; +}; + +#endif From 80f2b70e787325de8f80463bf7693051371927f1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 26 Apr 2013 16:12:52 -0700 Subject: [PATCH 113/281] fix header information Signed-off-by: Nikolaj Bjorner --- src/muz_qe/clp_context.cpp | 6 +++--- src/muz_qe/clp_context.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/muz_qe/clp_context.cpp b/src/muz_qe/clp_context.cpp index 5e683a5eb..73b065f7d 100644 --- a/src/muz_qe/clp_context.cpp +++ b/src/muz_qe/clp_context.cpp @@ -3,15 +3,15 @@ Copyright (c) 2013 Microsoft Corporation Module Name: - tab_context.cpp + clp_context.cpp Abstract: - Tabulation/subsumption/cyclic proof context. + Bounded CLP (symbolic simulation using Z3) context. Author: - Nikolaj Bjorner (nbjorner) 2013-01-15 + Nikolaj Bjorner (nbjorner) 2013-04-26 Revision History: diff --git a/src/muz_qe/clp_context.h b/src/muz_qe/clp_context.h index cd9117553..635891205 100644 --- a/src/muz_qe/clp_context.h +++ b/src/muz_qe/clp_context.h @@ -11,7 +11,7 @@ Abstract: Author: - Nikolaj Bjorner (nbjorner) 2013-01-15 + Nikolaj Bjorner (nbjorner) 2013-04-26 Revision History: From 3f45782814387106bef3bfaf80840ce746471a65 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 26 Apr 2013 17:22:06 -0700 Subject: [PATCH 114/281] tidy up clp_context a bit Signed-off-by: Nikolaj Bjorner --- src/muz_qe/clp_context.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/muz_qe/clp_context.cpp b/src/muz_qe/clp_context.cpp index 73b065f7d..25ea1455b 100644 --- a/src/muz_qe/clp_context.cpp +++ b/src/muz_qe/clp_context.cpp @@ -39,23 +39,17 @@ namespace datalog { rule_manager& rm; smt_params m_fparams; smt::kernel m_solver; - unifier m_unify; - substitution m_subst; var_subst m_var_subst; expr_ref_vector m_ground; app_ref_vector m_goals; volatile bool m_cancel; - unsigned m_deltas[2]; - unsigned m_var_cnt; stats m_stats; public: imp(context& ctx): m_ctx(ctx), m(ctx.get_manager()), rm(ctx.get_rule_manager()), - m_solver(m, m_fparams), - m_unify(m), - m_subst(m), + m_solver(m, m_fparams), // TBD: can be replaced by efficient BV solver. m_var_subst(m, false), m_ground(m), m_goals(m), @@ -64,8 +58,6 @@ namespace datalog { // m_fparams.m_relevancy_lvl = 0; m_fparams.m_mbqi = false; m_fparams.m_soft_timeout = 1000; - m_deltas[0] = 0; - m_deltas[1] = m_var_cnt; } ~imp() {} @@ -134,24 +126,24 @@ namespace datalog { } lbool search(unsigned depth, unsigned index) { - IF_VERBOSE(1, verbose_stream() << "search " << depth << " " << index << "\n";); - if (depth == 0) { - return l_undef; - } if (index == m_goals.size()) { return l_true; } + if (depth == 0) { + return l_undef; + } + IF_VERBOSE(1, verbose_stream() << "search " << depth << " " << index << "\n";); unsigned num_goals = m_goals.size(); app* head = m_goals[index].get(); rule_vector const& rules = m_ctx.get_rules().get_predicate_rules(head->get_decl()); lbool status = l_false; for (unsigned i = 0; i < rules.size(); ++i) { - IF_VERBOSE(2, verbose_stream() << index << " " << mk_pp(head, m) << "\n";); rule* r = rules[i]; m_solver.push(); reset_ground(); expr_ref tmp(m); tmp = r->get_head(); + IF_VERBOSE(2, verbose_stream() << index << " " << mk_pp(tmp, m) << "\n";); ground(tmp); for (unsigned j = 0; j < head->get_num_args(); ++j) { expr_ref eq(m); @@ -168,6 +160,10 @@ namespace datalog { case l_false: break; case l_true: + if (depth == 1 && (index+1 > m_goals.size() || r->get_uninterpreted_tail_size() > 0)) { + status = l_undef; + break; + } for (unsigned j = 0; j < r->get_uninterpreted_tail_size(); ++j) { tmp = r->get_tail(j); ground(tmp); From 9158fb17c1490a5c0b5fbcbd38f1551855390825 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 28 Apr 2013 12:47:55 -0700 Subject: [PATCH 115/281] add special procedures for UTVPI and horn arithmetic Signed-off-by: Nikolaj Bjorner --- src/smt/diff_logic.h | 34 +- src/smt/params/theory_arith_params.h | 4 +- src/smt/smt_setup.cpp | 14 + src/smt/theory_diff_logic.h | 115 +-- src/smt/theory_diff_logic_def.h | 101 +-- src/smt/theory_horn_ineq.cpp | 236 ++++++ src/smt/theory_horn_ineq.h | 342 ++++++++ src/smt/theory_horn_ineq_def.h | 1166 ++++++++++++++++++++++++++ src/smt/theory_utvpi.cpp | 159 ++++ src/smt/theory_utvpi.h | 331 ++++++++ src/smt/theory_utvpi_def.h | 694 +++++++++++++++ src/util/inf_eps_rational.h | 409 +++++++++ 12 files changed, 3397 insertions(+), 208 deletions(-) create mode 100644 src/smt/theory_horn_ineq.cpp create mode 100644 src/smt/theory_horn_ineq.h create mode 100644 src/smt/theory_horn_ineq_def.h create mode 100644 src/smt/theory_utvpi.cpp create mode 100644 src/smt/theory_utvpi.h create mode 100644 src/smt/theory_utvpi_def.h create mode 100644 src/util/inf_eps_rational.h diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 6d5101a80..b32a74c2c 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -118,7 +118,7 @@ const edge_id null_edge_id = -1; template class dl_graph { - struct statistics { + struct stats { unsigned m_propagation_cost; unsigned m_implied_literal_cost; unsigned m_num_implied_literals; @@ -131,16 +131,16 @@ class dl_graph { m_num_helpful_implied_literals = 0; m_num_relax = 0; } - statistics() { reset(); } - void display(std::ostream& out) const { - out << "num. prop. steps. " << m_propagation_cost << "\n"; - out << "num. impl. steps. " << m_implied_literal_cost << "\n"; - out << "num. impl. lits. " << m_num_implied_literals << "\n"; - out << "num. impl. conf lits. " << m_num_helpful_implied_literals << "\n"; - out << "num. bound relax. " << m_num_relax << "\n"; + stats() { reset(); } + void collect_statistics(::statistics& st) const { + st.update("dl prop steps", m_propagation_cost); + st.update("dl impl steps", m_implied_literal_cost); + st.update("dl impl lits", m_num_implied_literals); + st.update("dl impl conf lits", m_num_helpful_implied_literals); + st.update("dl bound relax", m_num_relax); } }; - statistics m_stats; + stats m_stats; typedef typename Ext::numeral numeral; typedef typename Ext::explanation explanation; typedef vector assignment; @@ -264,6 +264,12 @@ class dl_graph { m_assignment[e.get_target()] - m_assignment[e.get_source()] <= e.get_weight(); } + bool is_tight(edge_id e) const { + edge const& edge = m_edges[e]; + return edge.is_enabled() && + m_assignment[edge.get_target()] - m_assignment[e.get_source()] == e.get_weight(); + } + public: // An assignment is feasible if all edges are feasible. @@ -472,8 +478,9 @@ public: m_bw(m_mark) { } - void display_statistics(std::ostream& out) const { - m_stats.display(out); + + void collect_statistics(::statistics& st) const { + m_stats.collect_statistics(st); } // Create/Initialize a variable with the given id. @@ -655,10 +662,8 @@ public: throw default_exception("edges are not inconsistent"); } -#if 1 - // experimental feature: + // allow theory to introduce shortcut lemmas. prune_edges(edges, f); -#endif for (unsigned i = 0; i < edges.size(); ++i) { edge const& e = m_edges[edges[i]]; @@ -752,7 +757,6 @@ public: f.new_edge(src, dst, idx2-idx1+1, edges.begin()+idx1); } - // Create a new scope. // That is, save the number of edges in the graph. void push() { diff --git a/src/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index 52fef8ca4..30bc65b6d 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -26,7 +26,9 @@ enum arith_solver_id { AS_NO_ARITH, AS_DIFF_LOGIC, AS_ARITH, - AS_DENSE_DIFF_LOGIC + AS_DENSE_DIFF_LOGIC, + AS_UTVPI, + AS_HORN }; enum bound_prop_mode { diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 1f020cdd3..f91a58f87 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -22,6 +22,8 @@ Revision History: #include"theory_arith.h" #include"theory_dense_diff_logic.h" #include"theory_diff_logic.h" +#include"theory_horn_ineq.h" +#include"theory_utvpi.h" #include"theory_array.h" #include"theory_array_full.h" #include"theory_bv.h" @@ -723,6 +725,18 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_dense_mi, m_manager, m_params)); } break; + case AS_HORN: + if (m_params.m_arith_int_only) + m_context.register_plugin(alloc(smt::theory_ihi, m_manager)); + else + m_context.register_plugin(alloc(smt::theory_rhi, m_manager)); + break; + case AS_UTVPI: + if (m_params.m_arith_int_only) + m_context.register_plugin(alloc(smt::theory_iutvpi, m_manager)); + else + m_context.register_plugin(alloc(smt::theory_rutvpi, m_manager)); + break; default: if (m_params.m_arith_int_only) m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params)); diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 9c80d8c34..3bfd33b1e 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -59,109 +59,30 @@ namespace smt { } }; - class dl_conflict : public simple_justification { - public: - dl_conflict(region & r, unsigned nls, literal const * lits): simple_justification(r, nls, lits) { } - - virtual proof * mk_proof(conflict_resolution & cr) { - NOT_IMPLEMENTED_YET(); - return 0; - } - }; - - template class theory_diff_logic : public theory, private Ext { typedef typename Ext::numeral numeral; - class implied_eq_justification : public justification { - theory_diff_logic & m_theory; - theory_var m_v1; - theory_var m_v2; - unsigned m_timestamp; - public: - implied_eq_justification(theory_diff_logic & theory, theory_var v1, theory_var v2, unsigned ts): - m_theory(theory), - m_v1(v1), - m_v2(v2), - m_timestamp(ts) { - } - - virtual void get_antecedents(conflict_resolution & cr) { - m_theory.get_eq_antecedents(m_v1, m_v2, m_timestamp, cr); - } - - virtual proof * mk_proof(conflict_resolution & cr) { NOT_IMPLEMENTED_YET(); return 0; } - }; - - class implied_bound_justification : public justification { - theory_diff_logic& m_theory; - edge_id m_subsumed_edge; - edge_id m_bridge_edge; - public: - implied_bound_justification(theory_diff_logic & theory, edge_id se, edge_id be): - m_theory(theory), - m_subsumed_edge(se), - m_bridge_edge(be) { - } - - virtual void get_antecedents(conflict_resolution & cr) { - m_theory.get_implied_bound_antecedents(m_bridge_edge, m_subsumed_edge, cr); - } - - virtual proof * mk_proof(conflict_resolution & cr) { NOT_IMPLEMENTED_YET(); return 0; } - }; - - enum atom_kind { - LE_ATOM, - EQ_ATOM - }; - class atom { - protected: - atom_kind m_kind; bool_var m_bvar; bool m_true; + int m_pos; + int m_neg; public: - atom(atom_kind k, bool_var bv) : m_kind(k), m_bvar(bv), m_true(false) {} - virtual ~atom() {} - atom_kind kind() const { return m_kind; } - bool_var get_bool_var() const { return m_bvar; } - bool is_true() const { return m_true; } - void assign_eh(bool is_true) { m_true = is_true; } - virtual std::ostream& display(theory_diff_logic const& th, std::ostream& out) const; - }; - - class le_atom : public atom { - int m_pos; - int m_neg; - public: - le_atom(bool_var bv, int pos, int neg): - atom(LE_ATOM, bv), + atom(bool_var bv, int pos, int neg): + m_bvar(bv), m_true(false), m_pos(pos), m_neg(neg) { } - virtual ~le_atom() {} + ~atom() {} + bool_var get_bool_var() const { return m_bvar; } + bool is_true() const { return m_true; } + void assign_eh(bool is_true) { m_true = is_true; } int get_asserted_edge() const { return this->m_true?m_pos:m_neg; } int get_pos() const { return m_pos; } int get_neg() const { return m_neg; } - virtual std::ostream& display(theory_diff_logic const& th, std::ostream& out) const; - }; - - class eq_atom : public atom { - app_ref m_le; - app_ref m_ge; - public: - eq_atom(bool_var bv, app_ref& le, app_ref& ge): - atom(EQ_ATOM, bv), - m_le(le), - m_ge(ge) - {} - virtual ~eq_atom() {} - virtual std::ostream& display(theory_diff_logic const& th, std::ostream& out) const; - app* get_le() const { return m_le.get(); } - app* get_ge() const { return m_ge.get(); } + std::ostream& display(theory_diff_logic const& th, std::ostream& out) const; }; typedef ptr_vector atoms; @@ -239,19 +160,7 @@ namespace smt { unsigned m_asserted_qhead_old; }; - class theory_diff_logic_del_eh : public clause_del_eh { - theory_diff_logic& m_super; - public: - theory_diff_logic_del_eh(theory_diff_logic& s) : m_super(s) {} - virtual ~theory_diff_logic_del_eh() {} - virtual void operator()(ast_manager&, clause* cls) { - TRACE("dl_activity", tout << "deleting " << cls << "\n";); - m_super.del_clause_eh(cls); - dealloc(this); - } - }; - - smt_params & m_params; + smt_params & m_params; arith_util m_util; arith_eq_adapter m_arith_eq_adapter; theory_diff_logic_statistics m_stats; @@ -296,8 +205,6 @@ namespace smt { return get_family_id() == n->get_family_id(); } - void del_clause_eh(clause* cls); - public: theory_diff_logic(ast_manager& m, smt_params & params): theory(m.mk_family_id("arith")), @@ -316,7 +223,7 @@ namespace smt { m_nc_functor(*this) { } - ~theory_diff_logic() { + virtual ~theory_diff_logic() { reset_eh(); } diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index aeb4f73d6..362962620 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -31,34 +31,15 @@ Revision History: using namespace smt; + template -std::ostream& theory_diff_logic::atom::display(theory_diff_logic const& th, std::ostream& out) const { +std::ostream& theory_diff_logic::atom::display(theory_diff_logic const& th, std::ostream& out) const { context& ctx = th.get_context(); lbool asgn = ctx.get_assignment(m_bvar); //SASSERT(asgn == l_undef || ((asgn == l_true) == m_true)); bool sign = (l_undef == asgn) || m_true; return out << literal(m_bvar, sign) << " " << mk_pp(ctx.bool_var2expr(m_bvar), th.get_manager()) << " "; -} - -template -std::ostream& theory_diff_logic::eq_atom::display(theory_diff_logic const& th, std::ostream& out) const { - atom::display(th, out); - lbool asgn = th.get_context().get_assignment(this->m_bvar); - if (l_undef == asgn) { - out << "unassigned\n"; - } - else { - out << mk_pp(m_le.get(), m_le.get_manager()) << " " - << mk_pp(m_ge.get(), m_ge.get_manager()) << "\n"; - } - return out; -} - -template -std::ostream& theory_diff_logic::le_atom::display(theory_diff_logic const& th, std::ostream& out) const { - atom::display(th, out); - lbool asgn = th.get_context().get_assignment(this->m_bvar); if (l_undef == asgn) { out << "unassigned\n"; } @@ -94,7 +75,6 @@ void theory_diff_logic::init(context * ctx) { e = ctx->mk_enode(zero, false, false, true); SASSERT(!is_attached_to_var(e)); m_zero_real = mk_var(e); - } @@ -277,7 +257,7 @@ bool theory_diff_logic::internalize_atom(app * n, bool gate_ctx) { k -= this->m_epsilon; } edge_id neg = m_graph.add_edge(target, source, k, ~l); - le_atom * a = alloc(le_atom, bv, pos, neg); + atom * a = alloc(atom, bv, pos, neg); m_atoms.push_back(a); m_bool_var2atom.insert(bv, a); @@ -334,6 +314,7 @@ void theory_diff_logic::collect_statistics(::statistics & st) const { st.update("dl asserts", m_stats.m_num_assertions); st.update("core->dl eqs", m_stats.m_num_core2th_eqs); m_arith_eq_adapter.collect_statistics(st); + m_graph.collect_statistics(st); } template @@ -497,45 +478,14 @@ bool theory_diff_logic::propagate_atom(atom* a) { if (ctx.inconsistent()) { return false; } - switch(a->kind()) { - case LE_ATOM: { - int edge_id = dynamic_cast(a)->get_asserted_edge(); - if (!m_graph.enable_edge(edge_id)) { - set_neg_cycle_conflict(); - return false; - } -#if 0 - if (m_params.m_arith_bound_prop != BP_NONE) { - svector subsumed; - m_graph.find_subsumed1(edge_id, subsumed); - for (unsigned i = 0; i < subsumed.size(); ++i) { - int subsumed_edge_id = subsumed[i]; - literal l = m_graph.get_explanation(subsumed_edge_id); - context & ctx = get_context(); - region& r = ctx.get_region(); - ++m_stats.m_num_th2core_prop; - ctx.assign(l, new (r) implied_bound_justification(*this, subsumed_edge_id, edge_id)); - } - - } -#endif - break; - } - case EQ_ATOM: - if (!a->is_true()) { - SASSERT(ctx.get_assignment(a->get_bool_var()) == l_false); - // eq_atom * ea = dynamic_cast(a); - } - break; + int edge_id = a->get_asserted_edge(); + if (!m_graph.enable_edge(edge_id)) { + set_neg_cycle_conflict(); + return false; } return true; } -template -void theory_diff_logic::del_clause_eh(clause* cls) { - -} - template void theory_diff_logic::new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) { @@ -584,7 +534,7 @@ 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 = static_cast(a)->get_pos(); + edge_id e_id = a->get_pos(); literal_vector lits; for (unsigned i = 0; i < num_edges; ++i) { @@ -608,11 +558,7 @@ void theory_diff_logic::new_edge(dl_var src, dl_var dst, unsigned num_edges lits.size(), lits.c_ptr(), params.size(), params.c_ptr()); } - clause_del_eh* del_eh = alloc(theory_diff_logic_del_eh, *this); - clause* cls = ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, del_eh); - if (!cls) { - dealloc(del_eh); - } + clause* cls = ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); if (dump_lemmas()) { char const * logic = m_is_lia ? "QF_LIA" : "QF_LRA"; ctx.display_lemma_as_smt_problem(lits.size(), lits.c_ptr(), false_literal, logic); @@ -906,30 +852,9 @@ bool theory_diff_logic::is_consistent() const { lbool asgn = ctx.get_assignment(bv); if (ctx.is_relevant(ctx.bool_var2expr(bv)) && asgn != l_undef) { SASSERT((asgn == l_true) == a->is_true()); - switch(a->kind()) { - case LE_ATOM: { - le_atom* le = dynamic_cast(a); - int edge_id = le->get_asserted_edge(); - SASSERT(m_graph.is_enabled(edge_id)); - SASSERT(m_graph.is_feasible(edge_id)); - break; - } - case EQ_ATOM: { - eq_atom* ea = dynamic_cast(a); - bool_var bv1 = ctx.get_bool_var(ea->get_le()); - bool_var bv2 = ctx.get_bool_var(ea->get_ge()); - lbool val1 = ctx.get_assignment(bv1); - lbool val2 = ctx.get_assignment(bv2); - if (asgn == l_true) { - SASSERT(val1 == l_true); - SASSERT(val2 == l_true); - } - else { - SASSERT(val1 == l_false || val2 == l_false); - } - break; - } - } + 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(); diff --git a/src/smt/theory_horn_ineq.cpp b/src/smt/theory_horn_ineq.cpp new file mode 100644 index 000000000..978b5b003 --- /dev/null +++ b/src/smt/theory_horn_ineq.cpp @@ -0,0 +1,236 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + theory_horn_ineq.h + +Author: + + Nikolaj Bjorner (nbjorner) 2013-04-18 + +Revision History: + + The implementaton is derived from theory_diff_logic. + +--*/ +#include "theory_horn_ineq.h" +#include "theory_horn_ineq_def.h" + +namespace smt { + + template class theory_horn_ineq; + template class theory_horn_ineq; + + // similar to test_diff_logic: + + horn_ineq_tester::horn_ineq_tester(ast_manager& m): m(m), a(m) {} + + bool horn_ineq_tester::operator()(expr* e) { + m_todo.reset(); + m_pols.reset(); + pos_mark.reset(); + neg_mark.reset(); + m_todo.push_back(e); + m_pols.push_back(l_true); + while (!m_todo.empty()) { + expr* e = m_todo.back(); + lbool p = m_pols.back(); + m_todo.pop_back(); + m_pols.pop_back(); + switch (p) { + case l_true: + if (pos_mark.is_marked(e)) { + continue; + } + pos_mark.mark(e, true); + break; + case l_false: + if (neg_mark.is_marked(e)) { + continue; + } + neg_mark.mark(e, true); + break; + case l_undef: + if (pos_mark.is_marked(e) && neg_mark.is_marked(e)) { + continue; + } + pos_mark.mark(e, true); + neg_mark.mark(e, true); + break; + } + if (!test_expr(p, e)) { + return false; + } + } + return true; + } + + vector > const& horn_ineq_tester::get_linearization() const { + return m_terms; + } + + bool horn_ineq_tester::test_expr(lbool p, expr* e) { + expr* e1, *e2, *e3; + if (is_var(e)) { + return true; + } + if (!is_app(e)) { + return false; + } + app* ap = to_app(e); + if (m.is_and(ap) || m.is_or(ap)) { + for (unsigned i = 0; i < ap->get_num_args(); ++i) { + m_todo.push_back(ap->get_arg(i)); + m_pols.push_back(p); + } + } + else if (m.is_not(e, e1)) { + m_todo.push_back(e); + m_pols.push_back(~p); + } + else if (m.is_ite(e, e1, e2, e3)) { + m_todo.push_back(e1); + m_pols.push_back(l_undef); + m_todo.push_back(e2); + m_pols.push_back(p); + m_todo.push_back(e3); + m_pols.push_back(p); + } + else if (m.is_iff(e, e1, e2)) { + m_todo.push_back(e1); + m_pols.push_back(l_undef); + m_todo.push_back(e2); + m_pols.push_back(l_undef); + m_todo.push_back(e2); + } + else if (m.is_implies(e, e1, e2)) { + m_todo.push_back(e1); + m_pols.push_back(~p); + m_todo.push_back(e2); + m_pols.push_back(p); + } + else if (m.is_eq(e, e1, e2)) { + return linearize(e1, e2) == diff; + } + else if (m.is_true(e) || m.is_false(e)) { + // no-op + } + else if (a.is_le(e, e1, e2) || a.is_ge(e, e2, e1) || + a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) { + if (p == l_false) { + std::swap(e2, e1); + } + classify_t cl = linearize(e1, e2); + switch(p) { + case l_undef: + return cl == diff; + case l_true: + case l_false: + return cl == horn || cl == diff; + } + } + else if (!is_uninterp_const(e)) { + return false; + } + return true; + } + + bool horn_ineq_tester::operator()(unsigned num_fmls, expr* const* fmls) { + for (unsigned i = 0; i < num_fmls; ++i) { + if (!(*this)(fmls[i])) { + return false; + } + } + return true; + } + + horn_ineq_tester::classify_t horn_ineq_tester::linearize(expr* e) { + m_terms.reset(); + m_terms.push_back(std::make_pair(e, rational(1))); + return linearize(); + } + + horn_ineq_tester::classify_t horn_ineq_tester::linearize(expr* e1, expr* e2) { + m_terms.reset(); + m_terms.push_back(std::make_pair(e1, rational(1))); + m_terms.push_back(std::make_pair(e2, rational(-1))); + return linearize(); + } + + horn_ineq_tester::classify_t horn_ineq_tester::linearize() { + + m_weight.reset(); + m_coeff_map.reset(); + + while (!m_terms.empty()) { + expr* e1, *e2; + rational num; + rational mul = m_terms.back().second; + expr* e = m_terms.back().first; + m_terms.pop_back(); + if (a.is_add(e)) { + for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { + m_terms.push_back(std::make_pair(to_app(e)->get_arg(i), mul)); + } + } + else if (a.is_mul(e, e1, e2) && a.is_numeral(e1, num)) { + m_terms.push_back(std::make_pair(e2, mul*num)); + } + else if (a.is_mul(e, e2, e1) && a.is_numeral(e1, num)) { + m_terms.push_back(std::make_pair(e2, mul*num)); + } + else if (a.is_sub(e, e1, e2)) { + m_terms.push_back(std::make_pair(e1, mul)); + m_terms.push_back(std::make_pair(e2, -mul)); + } + else if (a.is_uminus(e, e1)) { + m_terms.push_back(std::make_pair(e1, -mul)); + } + else if (a.is_numeral(e, num)) { + m_weight += num*mul; + } + else if (a.is_to_real(e, e1)) { + m_terms.push_back(std::make_pair(e1, mul)); + } + else if (!is_uninterp_const(e)) { + return non_horn; + } + else { + m_coeff_map.insert_if_not_there2(e, rational(0))->get_data().m_value += mul; + } + } + unsigned num_negative = 0; + unsigned num_positive = 0; + bool is_unit_pos = true, is_unit_neg = true; + obj_map::iterator it = m_coeff_map.begin(); + obj_map::iterator end = m_coeff_map.end(); + for (; it != end; ++it) { + rational r = it->m_value; + if (r.is_zero()) { + continue; + } + m_terms.push_back(std::make_pair(it->m_key, r)); + if (r.is_pos()) { + is_unit_pos = is_unit_pos && r.is_one(); + num_positive++; + } + else { + is_unit_neg = is_unit_neg && r.is_minus_one(); + num_negative++; + } + } + if (num_negative <= 1 && is_unit_pos && is_unit_neg && num_positive <= 1) { + return diff; + } + if (num_positive <= 1 && is_unit_pos) { + return horn; + } + if (num_negative <= 1 && is_unit_neg) { + return co_horn; + } + return non_horn; + } + + +} diff --git a/src/smt/theory_horn_ineq.h b/src/smt/theory_horn_ineq.h new file mode 100644 index 000000000..f5fb41263 --- /dev/null +++ b/src/smt/theory_horn_ineq.h @@ -0,0 +1,342 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + theory_horn_ineq.h + +Abstract: + + + A*x <= b + D*x, coefficients to A and D are non-negative, + D is a diagonal matrix. + Coefficients to b may have both signs. + + + Ford-Fulkerson variant: + Label variables by weight. + Select inequality that is not satisfied. + Set gamma(LHS) := 0 + Set gamma(RHS(x)) := weight(x) - b + Propagate gamma through inequalities. + Gamma is the increment. + Maintain Heap of variables weighted by gamma. + When processing inequality, + then update gamma of variables by gamma := A(gamma + weight) - b + If some variable in the premise of the original rule gets + relabeled (assignment is increased), then the set of + inequalities is unsatisfiable. + + Propagation updates lower bounds on gamma by taking into + account integer inequalities. The greatest lower bound + is computable by taking integer floor/ceilings. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-04-18 + +Revision History: + + The implementaton is derived from theory_diff_logic. + +--*/ + +#ifndef _THEORY_HORN_INEQ_H_ +#define _THEORY_HORN_INEQ_H_ + +#include"rational.h" +#include"inf_rational.h" +#include"inf_int_rational.h" +#include"inf_eps_rational.h" +#include"smt_theory.h" +#include"arith_decl_plugin.h" +#include"smt_justification.h" +#include"map.h" +#include"smt_params.h" +#include"arith_eq_adapter.h" +#include"smt_model_generator.h" +#include"numeral_factory.h" +#include"smt_clause.h" + +namespace smt { + + class horn_ineq_tester { + ast_manager& m; + arith_util a; + ptr_vector m_todo; + svector m_pols; + ast_mark pos_mark, neg_mark; + obj_map m_coeff_map; + rational m_weight; + vector > m_terms; + + public: + enum classify_t { + co_horn, + horn, + diff, + non_horn + }; + horn_ineq_tester(ast_manager& m); + + // test if formula is in the Horn inequality fragment: + bool operator()(expr* fml); + bool operator()(unsigned num_fmls, expr* const* fmls); + + // linearize inequality/equality + classify_t linearize(expr* e); + classify_t linearize(expr* e1, expr* e2); + + // retrieve linearization + vector > const& get_linearization() const; + rational const& get_weight() const { return m_weight; } + private: + bool test_expr(lbool p, expr* e); + classify_t linearize(); + }; + + template + class theory_horn_ineq : public theory, private Ext { + + typedef typename Ext::numeral numeral; + typedef literal explanation; + typedef theory_var th_var; + typedef svector th_var_vector; + typedef unsigned clause_id; + typedef vector > coeffs; + static const clause_id null_clause_id = UINT_MAX; + + class clause; + class graph; + class assignment_trail; + class parent_trail; + + class atom { + protected: + bool_var m_bvar; + bool m_true; + int m_pos; + int m_neg; + public: + atom(bool_var bv, int pos, int neg) : + m_bvar(bv), m_true(false), + m_pos(pos), m_neg(neg) {} + virtual ~atom() {} + bool_var get_bool_var() const { return m_bvar; } + bool is_true() const { return m_true; } + void assign_eh(bool is_true) { m_true = is_true; } + int get_asserted_edge() const { return this->m_true?m_pos:m_neg; } + int get_pos() const { return m_pos; } + int get_neg() const { return m_neg; } + std::ostream& display(theory_horn_ineq const& th, std::ostream& out) const; + }; + typedef svector atoms; + + struct scope { + unsigned m_atoms_lim; + unsigned m_asserted_atoms_lim; + unsigned m_asserted_qhead_old; + }; + + struct stats { + unsigned m_num_conflicts; + unsigned m_num_assertions; + unsigned m_num_core2th_eqs; + unsigned m_num_core2th_diseqs; + + void reset() { + memset(this, 0, sizeof(*this)); + } + + stats() { + reset(); + } + }; + + stats m_stats; + smt_params m_params; + arith_util a; + arith_eq_adapter m_arith_eq_adapter; + th_var m_zero_int; // cache the variable representing the zero variable. + th_var m_zero_real; // cache the variable representing the zero variable. + + graph* m_graph; + atoms m_atoms; + unsigned_vector m_asserted_atoms; // set of asserted atoms + unsigned m_asserted_qhead; + u_map m_bool_var2atom; + svector m_scopes; + + double m_agility; + bool m_lia; + bool m_lra; + bool m_non_horn_ineq_exprs; + + horn_ineq_tester m_test; + + + arith_factory * m_factory; + rational m_delta; + rational m_lambda; + + + // Set a conflict due to a negative cycle. + void set_neg_cycle_conflict(); + + // Create a new theory variable. + virtual th_var mk_var(enode* n); + + virtual th_var mk_var(expr* n); + + void compute_delta(); + + void found_non_horn_ineq_expr(expr * n); + + bool is_interpreted(app* n) const { + return n->get_family_id() == get_family_id(); + } + + public: + theory_horn_ineq(ast_manager& m); + + virtual ~theory_horn_ineq(); + + virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_horn_ineq, get_manager()); } + + virtual char const * get_name() const { return "horn-inequality-logic"; } + + /** + \brief See comment in theory::mk_eq_atom + */ + virtual app * mk_eq_atom(expr * lhs, expr * rhs) { return a.mk_eq(lhs, rhs); } + + virtual void init(context * ctx); + + virtual bool internalize_atom(app * atom, bool gate_ctx); + + virtual bool internalize_term(app * term); + + virtual void internalize_eq_eh(app * atom, bool_var v); + + virtual void assign_eh(bool_var v, bool is_true); + + virtual void new_eq_eh(th_var v1, th_var v2) { + m_arith_eq_adapter.new_eq_eh(v1, v2); + } + + virtual bool use_diseqs() const { return true; } + + virtual void new_diseq_eh(th_var v1, th_var v2) { + m_arith_eq_adapter.new_diseq_eh(v1, v2); + } + + virtual void push_scope_eh(); + + virtual void pop_scope_eh(unsigned num_scopes); + + virtual void restart_eh() { + m_arith_eq_adapter.restart_eh(); + } + + virtual void relevant_eh(app* e) {} + + virtual void init_search_eh() { + m_arith_eq_adapter.init_search_eh(); + } + + virtual final_check_status final_check_eh(); + + virtual bool is_shared(th_var v) const { + return false; + } + + virtual bool can_propagate() { + SASSERT(m_asserted_qhead <= m_asserted_atoms.size()); + return m_asserted_qhead != m_asserted_atoms.size(); + } + + virtual void propagate(); + + virtual justification * why_is_diseq(th_var v1, th_var v2) { + UNREACHABLE(); + return 0; + } + + virtual void reset_eh(); + + virtual void init_model(model_generator & m); + + virtual model_value_proc * mk_value(enode * n, model_generator & mg); + + virtual bool validate_eq_in_model(th_var v1, th_var v2, bool is_true) const { + return true; + } + + virtual void display(std::ostream & out) const; + + virtual void collect_statistics(::statistics & st) const; + + private: + + virtual void new_eq_eh(th_var v1, th_var v2, justification& j) { + m_stats.m_num_core2th_eqs++; + new_eq_or_diseq(true, v1, v2, j); + } + + virtual void new_diseq_eh(th_var v1, th_var v2, justification& j) { + m_stats.m_num_core2th_diseqs++; + new_eq_or_diseq(false, v1, v2, j); + } + + void negate(coeffs& coeffs, rational& weight); + numeral mk_weight(bool is_real, bool is_strict, rational const& w) const; + void mk_coeffs(vector >const& terms, coeffs& coeffs, rational& w); + + void del_atoms(unsigned old_size); + + void propagate_core(); + + bool propagate_atom(atom const& a); + + th_var mk_term(app* n); + + th_var mk_num(app* n, rational const& r); + + bool is_consistent() const; + + th_var expand(bool pos, th_var v, rational & k); + + void new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just); + + th_var get_zero(sort* s) const { return a.is_int(s)?m_zero_int:m_zero_real; } + + th_var get_zero(expr* e) const { return get_zero(get_manager().get_sort(e)); } + + void inc_conflicts(); + + }; + + struct rhi_ext { + typedef inf_rational inf_numeral; + typedef inf_eps_rational numeral; + numeral m_epsilon; + numeral m_minus_infty; + rhi_ext() : m_epsilon(inf_rational(rational(), true)), m_minus_infty(rational(-1),inf_rational()) {} + }; + + struct ihi_ext { + typedef rational inf_numeral; + typedef inf_eps_rational numeral; + numeral m_epsilon; + numeral m_minus_infty; + ihi_ext() : m_epsilon(rational(1)), m_minus_infty(rational(-1),rational(0)) {} + }; + + typedef theory_horn_ineq theory_rhi; + typedef theory_horn_ineq theory_ihi; +}; + + + + +#endif /* _THEORY_HORN_INEQ_H_ */ diff --git a/src/smt/theory_horn_ineq_def.h b/src/smt/theory_horn_ineq_def.h new file mode 100644 index 000000000..b86d45819 --- /dev/null +++ b/src/smt/theory_horn_ineq_def.h @@ -0,0 +1,1166 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + theory_horn_ineq_def.h + +Abstract: + + A*x <= b + D*x, coefficients to A and D are non-negative, + D is a diagonal matrix. + Coefficients to b may have both signs. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-04-18 + +Revision History: + +--*/ + +#ifndef _THEORY_HORN_INEQ_DEF_H_ +#define _THEORY_HORN_INEQ_DEF_H_ +#include "theory_horn_ineq.h" +#include "ast_pp.h" +#include "smt_context.h" + +namespace smt { + + /** + A clause represents an inequality of the form + + v1*c1 + v2*c2 + .. + v_n*c_n + w <= v*c + + where + - m_vars: [v1,v2,...,v_n] + - m_coeffs: [c1,c2,...,c_n] + - m_var: v + - m_coeff: c + - m_weight: w + + */ + template + class theory_horn_ineq::clause { + vector m_coeffs; // coefficients of body. + svector m_vars; // variables of body. + rational m_coeff; // coefficient of head. + th_var m_var; // head variable. + numeral m_weight; // constant to add + literal m_explanation; + bool m_enabled; + public: + clause(unsigned sz, rational const* coeffs, th_var const* vars, + rational const& coeff, th_var var, numeral const& w, + const literal& ex): + m_coeffs(sz, coeffs), + m_vars(sz, vars), + m_coeff(coeff), + m_var(var), + m_weight(w), + m_explanation(ex), + m_enabled(false) { + DEBUG_CODE( + { + for (unsigned i = 0; i < size(); ++i) { + SASSERT(coeffs[i].is_pos()); + } + SASSERT(coeff.is_pos()); + }); + } + + th_var vars(unsigned i) const { return m_vars[i]; } + rational const& coeffs(unsigned i) const { return m_coeffs[i]; } + th_var var() const { return m_var; } + rational const& coeff() const { return m_coeff; } + const numeral & get_weight() const { return m_weight; } + const literal & get_explanation() const { return m_explanation; } + bool is_enabled() const { return m_enabled; } + unsigned size() const { return m_vars.size(); } + + void enable() { m_enabled = true; } + void disable() { m_enabled = false; } + + void display(std::ostream& out) const { + out << (is_enabled()?"+ ":"- "); + for (unsigned i = 0; i < size(); ++i) { + if (i > 0 && coeffs(i).is_pos()) { + out << " + "; + } + display(out, coeffs(i), vars(i)); + } + if (!get_weight().is_zero()) { + out << " + " << get_weight(); + } + display(out << " <= ", coeff(), var()); + out << "\n"; + } + + private: + + void display(std::ostream& out, rational const& c, th_var v) const { + if (!c.is_one()) { + out << c << "*"; + } + out << "v" << v; + } + }; + + template + class theory_horn_ineq::assignment_trail { + th_var m_var; + numeral m_old_value; + public: + assignment_trail(th_var v, const numeral & val): + m_var(v), + m_old_value(val) {} + th_var get_var() const { return m_var; } + const numeral & get_old_value() const { return m_old_value; } + }; + + template + class theory_horn_ineq::parent_trail { + th_var m_var; + clause_id m_old_value; + public: + parent_trail(th_var v, clause_id val): + m_var(v), + m_old_value(val) {} + th_var get_var() const { return m_var; } + clause_id get_old_value() const { return m_old_value; } + }; + + + template + class theory_horn_ineq::graph : private Ext { + + typedef vector assignment_stack; + typedef vector parent_stack; + typedef unsigned_vector clause_id_vector; + + struct stats { + unsigned m_propagation_cost; + + void reset() { + memset(this, 0, sizeof(*this)); + } + }; + + struct scope { + unsigned m_clauses_lim; + unsigned m_enabled_clauses_lim; + unsigned m_assignment_lim; + unsigned m_parent_lim; + scope(unsigned e, unsigned enabled, unsigned alim, unsigned plim): + m_clauses_lim(e), + m_enabled_clauses_lim(enabled), + m_assignment_lim(alim), + m_parent_lim(plim) { + } + }; + + stats m_stats; + vector m_clauses; + vector m_assignment; // per var + clause_id_vector m_parent; // per var + assignment_stack m_assignment_stack; // stack for restoring the assignment + parent_stack m_parent_stack; // stack for restoring parents + clause_id_vector m_enabled_clauses; + vector m_out_clauses; // use-list for clauses. + vector m_in_clauses; // clauses that have variable in head. + // forward reachability + unsigned_vector m_onstack; + unsigned m_ts; + unsigned_vector m_todo; + literal_vector m_lits; + vector m_coeffs; + th_var m_zero; + clause_id m_unsat_clause; + svector m_trail_stack; + + + public: + + graph(): m_ts(0), m_zero(null_theory_var), m_unsat_clause(null_clause_id) {} + + void reset() { + m_clauses .reset(); + m_assignment .reset(); + m_parent .reset(); + m_assignment_stack .reset(); + m_parent_stack .reset(); + m_out_clauses .reset(); + m_in_clauses .reset(); + m_enabled_clauses .reset(); + m_onstack .reset(); + m_ts = 0; + m_lits .reset(); + m_trail_stack .reset(); + m_unsat_clause = null_clause_id; + } + + + void traverse_neg_cycle1(bool /*stronger_lemmas*/) { + TRACE("horn_ineq", display(tout);); + SASSERT(!m_enabled_clauses.empty()); + clause_id id = m_unsat_clause; + SASSERT(id != null_clause_id); + SASSERT(!is_feasible(m_clauses[id])); + clause_id_vector todo; + vector muls; + todo.push_back(id); + muls.push_back(rational(1)); + u_map lits; + while (!todo.empty()) { + id = todo.back(); + rational mul = muls.back(); + todo.pop_back(); + muls.pop_back(); + clause const& cl = m_clauses[id]; + literal lit = cl.get_explanation(); + if (lit != null_literal) { + lits.insert_if_not_there2(id, rational(0))->get_data().m_value += mul; + } + for (unsigned i = 0; i < cl.size(); ++i) { + id = m_parent[cl.vars(i)]; + if (id != null_clause_id) { + todo.push_back(id); + muls.push_back(mul*cl.coeffs(i)); + } + } + } + u_map::iterator it = lits.begin(), end = lits.end(); + m_lits.reset(); + m_coeffs.reset(); + for (; it != end; ++it) { + m_lits.push_back(m_clauses[it->m_key].get_explanation()); + m_coeffs.push_back(it->m_value); + } + + // TODO: use topological sort to tune traversal of parents to linear. + // (current traversal can be exponential). + // TODO: negative cycle traversal with inline resolution to find + // stronger conflict clauses. + // follow heuristic used in theory_diff_logic_def.h: + } + + unsigned get_num_clauses() const { + return m_clauses.size(); + } + + literal_vector const& get_lits() const { + return m_lits; + } + + vector const& get_coeffs() const { + return m_coeffs; + } + + numeral get_assignment(th_var v) const { + return m_assignment[v]; + } + + numeral eval_body(clause const& cl) const { + numeral v(0); + for (unsigned i = 0; i < cl.size(); ++i) { + v += cl.coeffs(i)*m_assignment[cl.vars(i)]; + } + v += cl.get_weight(); + return v; + } + + numeral eval_body(clause_id id) const { + return eval_body(m_clauses[id]); + } + + numeral eval_head(clause_id id) const { + return eval_head(m_clauses[id]); + } + + numeral eval_head(clause const& cl) const { + return cl.coeff()*m_assignment[cl.var()]; + } + + clause const& get_clause(clause_id id) const { + return m_clauses[id]; + } + + void display_clause(std::ostream& out, clause_id id) const { + if (id == null_clause_id) { + out << "null\n"; + } + else { + m_clauses[id].display(out); + } + } + + void display(std::ostream& out) const { + for (unsigned i = 0; i < m_clauses.size(); ++i) { + display_clause(out, i); + } + for (unsigned i = 0; i < m_assignment.size(); ++i) { + out << m_assignment[i] << "\n"; + } + } + + void collect_statistics(::statistics& st) const { + st.update("hi_propagation_cst", m_stats.m_propagation_cost); + } + + void push() { + m_trail_stack.push_back(scope(m_clauses.size(), m_enabled_clauses.size(), + m_assignment_stack.size(), m_parent_stack.size())); + } + + void pop(unsigned num_scopes) { + unsigned lvl = m_trail_stack.size(); + SASSERT(num_scopes <= lvl); + unsigned new_lvl = lvl - num_scopes; + scope & s = m_trail_stack[new_lvl]; + // restore enabled clauses + for (unsigned i = m_enabled_clauses.size(); i > s.m_enabled_clauses_lim; ) { + --i; + m_clauses[m_enabled_clauses[i]].disable(); + } + m_enabled_clauses.shrink(s.m_enabled_clauses_lim); + + // restore assignment stack + for (unsigned i = m_assignment_stack.size(); i > s.m_assignment_lim; ) { + --i; + m_assignment[m_assignment_stack[i].get_var()] = m_assignment_stack[i].get_old_value(); + } + m_assignment_stack.shrink(s.m_assignment_lim); + + // restore parent stack + for (unsigned i = m_parent_stack.size(); i > s.m_parent_lim; ) { + --i; + m_parent[m_parent_stack[i].get_var()] = m_parent_stack[i].get_old_value(); + } + m_assignment_stack.shrink(s.m_assignment_lim); + + // restore clauses + unsigned old_num_clauses = s.m_clauses_lim; + unsigned num_clauses = m_clauses.size(); + SASSERT(old_num_clauses <= num_clauses); + unsigned to_delete = num_clauses - old_num_clauses; + for (unsigned i = 0; i < to_delete; i++) { + const clause & cl = m_clauses.back(); + TRACE("horn_ineq", tout << "deleting clause:\n"; cl.display(tout);); + for (unsigned j = 0; j < cl.size(); ++j) { + m_out_clauses[cl.vars(j)].pop_back(); + } + m_in_clauses[cl.var()].pop_back(); + m_clauses.pop_back(); + } + m_trail_stack.shrink(new_lvl); + SASSERT(check_invariant()); + } + + /** + \brief Add clause z <= z and the assignment z := 0 + Then z cannot be incremented without causing a loop (and therefore a contradiction). + */ + void set_to_zero(th_var z) { + m_zero = z; + } + + bool enable_clause(clause_id id) { + if (id == null_clause_id) { + return true; + } + clause& cl = m_clauses[id]; + bool r = true; + if (!cl.is_enabled()) { + cl.enable(); + if (!is_feasible(cl)) { + r = make_feasible(id); + } + m_enabled_clauses.push_back(id); + } + return r; + } + + void init_var(th_var v) { + unsigned sz = static_cast(v); + while (m_assignment.size() <= sz) { + m_assignment.push_back(Ext::m_minus_infty); + m_out_clauses.push_back(clause_id_vector()); + m_in_clauses.push_back(clause_id_vector()); + m_parent.push_back(null_clause_id); + m_onstack.push_back(0); + } + m_assignment[v] = Ext::m_minus_infty; + SASSERT(m_out_clauses[v].empty()); + SASSERT(m_in_clauses[v].empty()); + SASSERT(check_invariant()); + } + + clause_id add_ineq(vector > const& terms, numeral const& weight, literal l) { + vector coeffs; + svector vars; + rational coeff(1); + th_var var = null_theory_var; + bool found_negative = false; + for (unsigned i = 0; i < terms.size(); ++i) { + rational const& r = terms[i].second; + if (r.is_pos()) { + coeffs.push_back(terms[i].second); + vars.push_back(terms[i].first); + } + else if (found_negative) { + return null_clause_id; + } + else { + SASSERT(r.is_neg()); + found_negative = true; + coeff = -r; + var = terms[i].first; + } + } + if (!found_negative) { + coeff = rational(1); + var = m_zero; + } + if (!coeff.is_one()) { + // so far just support unit coefficients on right. + return null_clause_id; + } + clause_id id = m_clauses.size(); + m_clauses.push_back(clause(coeffs.size(), coeffs.c_ptr(), vars.c_ptr(), coeff, var, weight, l)); + for (unsigned i = 0; i < vars.size(); ++i) { + m_out_clauses[vars[i]].push_back(id); + } + m_in_clauses[var].push_back(id); + + return id; + } + + bool is_feasible() const { + for (unsigned i = 0; i < m_clauses.size(); ++i) { + if (!is_feasible(m_clauses[i])) { + return false; + } + } + return true; + } + + private: + + bool check_invariant() { + return true; + } + + /** + assignments are fully retraced on backtracking. + This is not always necessary. + */ + + void acc_assignment(th_var v, const numeral & inc) { + m_assignment_stack.push_back(assignment_trail(v, m_assignment[v])); + m_assignment[v] += inc; + } + + void acc_parent(th_var v, clause_id parent) { + m_parent[v] = parent; + m_parent_stack.push_back(parent_trail(v, parent)); + } + + numeral get_delta(const clause & cl) const { + SASSERT(cl.coeff().is_one() && "Not yet support for non-units"); + return eval_body(cl) - eval_head(cl); + } + + void set_onstack(th_var v) { + SASSERT(m_ts != 0); + m_onstack[v] = m_ts; + } + + void reset_onstack(th_var v) { + m_onstack[v] = 0; + } + + bool is_onstack(th_var v) const { + return m_onstack[v] == m_ts; + } + + void inc_ts() { + m_ts++; + if (m_ts == 0) { + m_ts++; + m_onstack.reset(); + m_onstack.resize(m_assignment.size(), 0); + } + } + + // Make the assignment feasible. An assignment is feasible if + // Forall clause cl. eval_body(cl) <= eval_head(cl) + // + // This method assumes that if the assignment is not feasible, + // then the only infeasible clause is the last added clause. + // + // Traversal is by naive DFS search. + // + bool make_feasible(clause_id id) { + SASSERT(is_almost_feasible(id)); + SASSERT(!m_clauses.empty()); + SASSERT(!is_feasible(m_clauses[id])); + const clause & cl0 = m_clauses[id]; + inc_ts(); + for (unsigned i = 0; i < cl0.size(); ++i) { + set_onstack(cl0.vars(i)); + } + th_var source = cl0.var(); + numeral delta = get_delta(cl0); + acc_parent(source, id); + SASSERT(delta.is_pos()); + acc_assignment(source, delta); + m_todo.reset(); + m_todo.push_back(source); + + TRACE("horn_ineq", cl0.display(tout);); + + do { + ++m_stats.m_propagation_cost; + + typename clause_id_vector::iterator it = m_out_clauses[source].begin(); + typename clause_id_vector::iterator end = m_out_clauses[source].end(); + for (; it != end; ++it) { + clause & cl = m_clauses[*it]; + if (!cl.is_enabled()) { + continue; + } + delta = get_delta(cl); + + if (delta.is_pos()) { + TRACE("horn_ineq", cl.display(tout);); + th_var target = cl.var(); + if (is_onstack(target)) { + m_unsat_clause = *it; + return false; + } + else { + acc_assignment(target, delta); + acc_parent(target, *it); + m_todo.push_back(target); + } + } + } + set_onstack(source); + source = m_todo.back(); + // pop stack until there is a new variable to process. + while (is_onstack(source)) { + m_todo.pop_back(); + reset_onstack(source); + if (m_todo.empty()) { + break; + } + source = m_todo.back(); + } + } + while (!m_todo.empty()); + return true; + } + + bool is_almost_feasible(clause_id id) const { + for (unsigned i = 0; i < m_clauses.size(); ++i) { + if (id != static_cast(i) && !is_feasible(m_clauses[i])) { + return false; + } + } + return true; + } + + bool is_feasible(const clause & cl) const { + return !cl.is_enabled() || get_delta(cl).is_nonpos(); + } + + }; + + template + theory_horn_ineq::theory_horn_ineq(ast_manager& m): + theory(m.mk_family_id("arith")), + a(m), + m_arith_eq_adapter(*this, m_params, a), + m_zero_int(null_theory_var), + m_zero_real(null_theory_var), + m_graph(0), + m_asserted_qhead(0), + m_agility(0.5), + m_lia(false), + m_lra(false), + m_non_horn_ineq_exprs(false), + m_test(m), + m_factory(0) { + m_graph = alloc(graph); + } + + template + theory_horn_ineq::~theory_horn_ineq() { + reset_eh(); + dealloc(m_graph); + } + + template + std::ostream& theory_horn_ineq::atom::display(theory_horn_ineq const& th, std::ostream& out) const { + context& ctx = th.get_context(); + lbool asgn = ctx.get_assignment(m_bvar); + bool sign = (l_undef == asgn) || m_true; + return out << literal(m_bvar, sign) << " " << mk_pp(ctx.bool_var2expr(m_bvar), th.get_manager()) << " "; + if (l_undef == asgn) { + out << "unassigned\n"; + } + else { + th.m_graph->display_clause(out, get_asserted_edge()); + } + return out; + } + + template + theory_var theory_horn_ineq::mk_var(enode* n) { + th_var v = theory::mk_var(n); + m_graph->init_var(v); + get_context().attach_th_var(n, this, v); + return v; + } + + template + theory_var theory_horn_ineq::mk_var(expr* n) { + context & ctx = get_context(); + enode* e = 0; + th_var v = null_theory_var; + m_lia |= a.is_int(n); + m_lra |= a.is_real(n); + if (!is_app(n)) { + return v; + } + if (ctx.e_internalized(n)) { + e = ctx.get_enode(n); + v = e->get_th_var(get_id()); + } + else { + ctx.internalize(n, false); + e = ctx.get_enode(n); + } + if (v == null_theory_var) { + v = mk_var(e); + } + if (is_interpreted(to_app(n))) { + found_non_horn_ineq_expr(n); + } + return v; + } + + template + void theory_horn_ineq::reset_eh() { + m_graph ->reset(); + m_zero_int = null_theory_var; + m_zero_real = null_theory_var; + m_atoms .reset(); + m_asserted_atoms .reset(); + m_stats .reset(); + m_scopes .reset(); + m_asserted_qhead = 0; + m_agility = 0.5; + m_lia = false; + m_lra = false; + m_non_horn_ineq_exprs = false; + theory::reset_eh(); + } + + + + template + void theory_horn_ineq::new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just) { + rational k; + th_var s = expand(true, v1, k); + th_var t = expand(false, v2, k); + context& ctx = get_context(); + ast_manager& m = get_manager(); + + if (s == t) { + if (is_eq != k.is_zero()) { + // conflict 0 /= k; + inc_conflicts(); + ctx.set_conflict(&eq_just); + } + } + else { + // + // Create equality ast, internalize_atom + // assign the corresponding equality literal. + // + + app_ref eq(m), s2(m), t2(m); + app* s1 = get_enode(s)->get_owner(); + app* t1 = get_enode(t)->get_owner(); + s2 = a.mk_sub(t1, s1); + t2 = a.mk_numeral(k, m.get_sort(s2.get())); + // t1 - s1 = k + eq = m.mk_eq(s2.get(), t2.get()); + + TRACE("horn_ineq", + tout << v1 << " .. " << v2 << "\n"; + tout << mk_pp(eq.get(), m) <<"\n";); + + if (!internalize_atom(eq.get(), false)) { + UNREACHABLE(); + } + + literal l(ctx.get_literal(eq.get())); + if (!is_eq) { + l = ~l; + } + + ctx.assign(l, b_justification(&eq_just), false); + } + } + + template + void theory_horn_ineq::inc_conflicts() { + m_stats.m_num_conflicts++; + if (m_params.m_arith_adaptive) { + double g = m_params.m_arith_adaptive_propagation_threshold; + m_agility = m_agility*g + 1 - g; + } + } + + template + void theory_horn_ineq::set_neg_cycle_conflict() { + m_graph->traverse_neg_cycle1(m_params.m_arith_stronger_lemmas); + inc_conflicts(); + literal_vector const& lits = m_graph->get_lits(); + context & ctx = get_context(); + TRACE("horn_ineq", + tout << "conflict: "; + for (unsigned i = 0; i < lits.size(); ++i) { + ctx.display_literal_info(tout, lits[i]); + } + tout << "\n"; + ); + + if (m_params.m_arith_dump_lemmas) { + char const * logic = m_lra ? (m_lia?"QF_LIRA":"QF_LRA") : "QF_LIA"; + ctx.display_lemma_as_smt_problem(lits.size(), lits.c_ptr(), false_literal, logic); + } + + vector params; + if (get_manager().proofs_enabled()) { + params.push_back(parameter(symbol("farkas"))); + vector const& coeffs = m_graph->get_coeffs(); + for (unsigned i = 0; i < coeffs.size(); ++i) { + params.push_back(parameter(coeffs[i])); + } + } + + ctx.set_conflict( + ctx.mk_justification( + ext_theory_conflict_justification( + get_id(), ctx.get_region(), + lits.size(), lits.c_ptr(), 0, 0, params.size(), params.c_ptr()))); + } + + template + void theory_horn_ineq::found_non_horn_ineq_expr(expr* n) { + if (!m_non_horn_ineq_exprs) { + TRACE("horn_ineq", tout << "found non horn logic expression:\n" << mk_pp(n, get_manager()) << "\n";); + get_context().push_trail(value_trail(m_non_horn_ineq_exprs)); + m_non_horn_ineq_exprs = true; + } + } + + template + void theory_horn_ineq::init(context* ctx) { + theory::init(ctx); + m_zero_int = mk_var(ctx->mk_enode(a.mk_numeral(rational(0), true), false, false, true)); + m_zero_real = mk_var(ctx->mk_enode(a.mk_numeral(rational(0), false), false, false, true)); + m_graph->set_to_zero(m_zero_int); + m_graph->set_to_zero(m_zero_real); + } + + /** + \brief Create negated literal. + + The negation of: E <= 0 + + -E + epsilon <= 0 + or + -E + 1 <= 0 + */ + template + void theory_horn_ineq::negate(coeffs& coeffs, rational& weight) { + for (unsigned i = 0; i < coeffs.size(); ++i) { + coeffs[i].second.neg(); + } + weight.neg(); + } + + template + typename theory_horn_ineq::numeral theory_horn_ineq::mk_weight(bool is_real, bool is_strict, rational const& w) const { + if (is_strict) { + return numeral(inf_numeral(w)) + (is_real?m_epsilon:numeral(1)); + } + else { + return numeral(inf_numeral(w)); + } + } + + template + void theory_horn_ineq::mk_coeffs(vector > const& terms, coeffs& coeffs, rational& w) { + coeffs.reset(); + w = m_test.get_weight(); + for (unsigned i = 0; i < terms.size(); ++i) { + coeffs.push_back(std::make_pair(mk_var(terms[i].first), terms[i].second)); + } + } + + template + bool theory_horn_ineq::internalize_atom(app * n, bool) { + context & ctx = get_context(); + if (!a.is_le(n) && !a.is_ge(n) && !a.is_lt(n) && !a.is_gt(n)) { + found_non_horn_ineq_expr(n); + return false; + } + SASSERT(!ctx.b_internalized(n)); + expr* e1 = n->get_arg(0), *e2 = n->get_arg(1); + if (a.is_ge(n) || a.is_gt(n)) { + std::swap(e1, e2); + } + bool is_strict = a.is_gt(n) || a.is_lt(n); + + horn_ineq_tester::classify_t cl = m_test.linearize(e1, e2); + if (cl == horn_ineq_tester::non_horn) { + found_non_horn_ineq_expr(n); + return false; + } + + rational w; + coeffs coeffs; + mk_coeffs(m_test.get_linearization(), coeffs, w); + bool_var bv = ctx.mk_bool_var(n); + ctx.set_var_theory(bv, get_id()); + literal l(bv); + numeral w1 = mk_weight(a.is_real(e1), is_strict, w); + clause_id pos = m_graph->add_ineq(coeffs, w1, l); + negate(coeffs, w); + numeral w2 = mk_weight(a.is_real(e1), !is_strict, w); + clause_id neg = m_graph->add_ineq(coeffs, w2, ~l); + m_bool_var2atom.insert(bv, m_atoms.size()); + m_atoms.push_back(atom(bv, pos, neg)); + + TRACE("horn_ineq", + tout << mk_pp(n, get_manager()) << "\n"; + m_graph->display_clause(tout << "pos: ", pos); + m_graph->display_clause(tout << "neg: ", neg); + ); + + return true; + } + + template + bool theory_horn_ineq::internalize_term(app * term) { + bool result = null_theory_var != mk_term(term); + CTRACE("horn_ineq", !result, tout << "Did not internalize " << mk_pp(term, get_manager()) << "\n";); + TRACE("horn_ineq", tout << "Terms may not be internalized " << mk_pp(term, get_manager()) << "\n";); + found_non_horn_ineq_expr(term); + return result; + } + + template + void theory_horn_ineq::internalize_eq_eh(app * atom, bool_var) { + // noop + } + + template + void theory_horn_ineq::assign_eh(bool_var v, bool is_true) { + m_stats.m_num_assertions++; + unsigned idx = m_bool_var2atom.find(v); + SASSERT(get_context().get_assignment(v) != l_undef); + SASSERT((get_context().get_assignment(v) == l_true) == is_true); + m_atoms[idx].assign_eh(is_true); + m_asserted_atoms.push_back(idx); + } + + template + void theory_horn_ineq::push_scope_eh() { + theory::push_scope_eh(); + m_graph->push(); + m_scopes.push_back(scope()); + scope & s = m_scopes.back(); + s.m_atoms_lim = m_atoms.size(); + s.m_asserted_atoms_lim = m_asserted_atoms.size(); + s.m_asserted_qhead_old = m_asserted_qhead; + } + + template + void theory_horn_ineq::pop_scope_eh(unsigned num_scopes) { + unsigned lvl = m_scopes.size(); + SASSERT(num_scopes <= lvl); + unsigned new_lvl = lvl - num_scopes; + scope & s = m_scopes[new_lvl]; + del_atoms(s.m_atoms_lim); + m_asserted_atoms.shrink(s.m_asserted_atoms_lim); + m_asserted_qhead = s.m_asserted_qhead_old; + m_scopes.shrink(new_lvl); + m_graph->pop(num_scopes); + theory::pop_scope_eh(num_scopes); + } + + template + final_check_status theory_horn_ineq::final_check_eh() { + SASSERT(is_consistent()); + TRACE("horn_ineq", display(tout);); + if (can_propagate()) { + propagate_core(); + return FC_CONTINUE; + } + else if (m_non_horn_ineq_exprs) { + return FC_GIVEUP; + } + else { + return FC_DONE; + } + } + + template + void theory_horn_ineq::propagate() { + propagate_core(); + } + + template + void theory_horn_ineq::display(std::ostream& out) const { + for (unsigned i = 0; i < m_atoms.size(); ++i) { + m_atoms[i].display(*this, out); + } + out << "\n"; + m_graph->display(out); + } + + template + void theory_horn_ineq::collect_statistics(::statistics& st) const { + st.update("hi conflicts", m_stats.m_num_conflicts); +// st.update("hi propagations", m_stats.m_num_th2core_prop); +// st.update("hi asserts", m_stats.m_num_assertions); +// st.update("core->hi eqs", m_stats.m_num_core2th_eqs); + m_arith_eq_adapter.collect_statistics(st); + m_graph->collect_statistics(st); + } + + template + void theory_horn_ineq::del_atoms(unsigned old_size) { + typename atoms::iterator begin = m_atoms.begin() + old_size; + typename atoms::iterator it = m_atoms.end(); + while (it != begin) { + --it; + m_bool_var2atom.erase(it->get_bool_var()); + } + m_atoms.shrink(old_size); + } + + template + void theory_horn_ineq::propagate_core() { + bool consistent = true; + while (consistent && can_propagate()) { + unsigned idx = m_asserted_atoms[m_asserted_qhead]; + m_asserted_qhead++; + consistent = propagate_atom(m_atoms[idx]); + } + } + + template + bool theory_horn_ineq::propagate_atom(atom const& a) { + context& ctx = get_context(); + TRACE("horn_ineq", a.display(*this, tout); tout << "\n";); + if (ctx.inconsistent()) { + return false; + } + int clause_id = a.get_asserted_edge(); + if (!m_graph->enable_clause(clause_id)) { + set_neg_cycle_conflict(); + return false; + } + return true; + } + + template + theory_var theory_horn_ineq::mk_term(app* n) { + context& ctx = get_context(); + + horn_ineq_tester::classify_t cl = m_test.linearize(n); + if (cl == horn_ineq_tester::non_horn) { + found_non_horn_ineq_expr(n); + return null_theory_var; + } + + coeffs coeffs; + rational w; + mk_coeffs(m_test.get_linearization(), coeffs, w); + if (coeffs.empty()) { + return mk_num(n, w); + } + if (coeffs.size() == 1 && coeffs[0].second.is_one()) { + return coeffs[0].first; + } + th_var target = mk_var(ctx.mk_enode(n, false, false, true)); + coeffs.push_back(std::make_pair(target, rational(-1))); + + VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(w)), null_literal))); + negate(coeffs, w); + VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(w)), null_literal))); + return target; + } + + template + theory_var theory_horn_ineq::mk_num(app* n, rational const& r) { + theory_var v = null_theory_var; + context& ctx = get_context(); + if (r.is_zero()) { + v = a.is_int(n)?m_zero_int:m_zero_real; + } + else if (ctx.e_internalized(n)) { + enode* e = ctx.get_enode(n); + v = e->get_th_var(get_id()); + SASSERT(v != null_theory_var); + } + else { + v = mk_var(ctx.mk_enode(n, false, false, true)); + // v = k: v <= k k <= v + coeffs coeffs; + coeffs.push_back(std::make_pair(v, rational(1))); + VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(r)), null_literal))); + coeffs.back().second.neg(); + VERIFY (m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(-r)), null_literal))); + } + return v; + } + + template + theory_var theory_horn_ineq::expand(bool pos, th_var v, rational & k) { + context& ctx = get_context(); + enode* e = get_enode(v); + expr* x, *y; + rational r; + for (;;) { + app* n = e->get_owner(); + if (a.is_add(n, x, y)) { + if (a.is_numeral(x, r)) { + e = ctx.get_enode(y); + } + else if (a.is_numeral(y, r)) { + e = ctx.get_enode(x); + } + v = e->get_th_var(get_id()); + SASSERT(v != null_theory_var); + if (v == null_theory_var) { + break; + } + if (pos) { + k += r; + } + else { + k -= r; + } + } + else { + break; + } + } + return v; + } + + template + bool theory_horn_ineq::is_consistent() const { + return m_graph->is_feasible(); + } + + // models: + template + void theory_horn_ineq::init_model(model_generator & m) { + m_factory = alloc(arith_factory, get_manager()); + m.register_factory(m_factory); + compute_delta(); + } + + template + model_value_proc * theory_horn_ineq::mk_value(enode * n, model_generator & mg) { + theory_var v = n->get_th_var(get_id()); + SASSERT(v != null_theory_var); + numeral val = m_graph->get_assignment(v); + rational num = val.get_infinity()*m_lambda + val.get_rational() + val.get_infinitesimal()*m_delta; + TRACE("horn_ineq", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";); + return alloc(expr_wrapper_proc, m_factory->mk_value(num, a.is_int(n->get_owner()))); + } + + /** + \brief Compute numeral values for the infinitesimals to satisfy the inequalities. + */ + + template + void theory_horn_ineq::compute_delta() { + m_delta = rational(1); + m_lambda = rational(0); + unsigned sz = m_graph->get_num_clauses(); + + for (unsigned i = 0; i < sz; ++i) { + if (!m_graph->get_clause(i).is_enabled()) { + continue; + } + numeral b = m_graph->eval_body(i); + numeral h = m_graph->eval_head(i); + + if (b.get_infinity() < h.get_infinity()) { + continue; + } + SASSERT(b.get_infinity() == h.get_infinity()); + + // b <= h + // suppose that h.eps < b.eps + // then we have h.num > b.num + // but also h.num + delta*h.eps >= b.num + delta*b.eps + // <=> + // (h.num - b.num)/(b.eps - h.eps) >= delta + rational num_r = h.get_rational() - b.get_rational(); + rational eps_r = b.get_infinitesimal() - h.get_infinitesimal(); + if (eps_r.is_pos()) { + SASSERT(num_r.is_pos()); + rational new_delta = num_r/eps_r; + if (new_delta < m_delta) { + m_delta = new_delta; + } + } + } + + for (unsigned i = 0; i < sz; ++i) { + if (!m_graph->get_clause(i).is_enabled()) { + continue; + } + numeral b = m_graph->eval_body(i); + numeral h = m_graph->eval_head(i); + + rational ir = h.get_infinity() - b.get_infinity(); + rational hr = b.get_rational() - h.get_rational(); + rational num_r = hr + m_delta*(b.get_infinitesimal() - h.get_infinitesimal()); + + SASSERT(b.get_infinity() <= h.get_infinity()); + + // b <= h + // suppose that h.finite < b.finite + // then we have h.infinite > b.infinite + // but also + // h.infinite*lambda + h.finite >= b.infinite*lambda + b.finite + // <=> + // lambda >= (b.finite - h.finite) / (h.infinite - b.infinite) + if (num_r.is_pos()) { + SASSERT(ir.is_pos()); + rational new_lambda = num_r/ir; + if (new_lambda > m_lambda) { + m_lambda = new_lambda; + } + } + } + } + + + +}; + +#endif diff --git a/src/smt/theory_utvpi.cpp b/src/smt/theory_utvpi.cpp new file mode 100644 index 000000000..e811257a6 --- /dev/null +++ b/src/smt/theory_utvpi.cpp @@ -0,0 +1,159 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + theory_utvpi.h + +Author: + + Nikolaj Bjorner (nbjorner) 2013-04-26 + +Revision History: + + The implementaton is derived from theory_diff_logic. + +--*/ +#include "theory_utvpi.h" +#include "theory_utvpi_def.h" + +namespace smt { + + template class theory_utvpi; + template class theory_utvpi; + + // similar to test_diff_logic: + + utvpi_tester::utvpi_tester(ast_manager& m): m(m), a(m) {} + + bool utvpi_tester::operator()(expr* e) { + m_todo.reset(); + m_mark.reset(); + m_todo.push_back(e); + expr* e1, *e2; + + while (!m_todo.empty()) { + expr* e = m_todo.back(); + m_todo.pop_back(); + if (!m_mark.is_marked(e)) { + m_mark.mark(e, true); + if (is_var(e)) { + continue; + } + if (!is_app(e)) { + return false; + } + app* ap = to_app(e); + if (m.is_eq(ap, e1, e2)) { + if (!linearize(e1, e2)) { + return false; + } + } + else if (ap->get_family_id() == m.get_basic_family_id()) { + continue; + } + else if (a.is_le(e, e1, e2) || a.is_ge(e, e2, e1) || + a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) { + if (!linearize(e1, e2)) { + return false; + } + } + else if (is_uninterp_const(e)) { + continue; + } + else { + return false; + } + } + } + return true; + } + + vector > const& utvpi_tester::get_linearization() const { + return m_terms; + } + + bool utvpi_tester::operator()(unsigned num_fmls, expr* const* fmls) { + for (unsigned i = 0; i < num_fmls; ++i) { + if (!(*this)(fmls[i])) { + return false; + } + } + return true; + } + + bool utvpi_tester::linearize(expr* e) { + m_terms.reset(); + m_terms.push_back(std::make_pair(e, rational(1))); + return linearize(); + } + + bool utvpi_tester::linearize(expr* e1, expr* e2) { + m_terms.reset(); + m_terms.push_back(std::make_pair(e1, rational(1))); + m_terms.push_back(std::make_pair(e2, rational(-1))); + return linearize(); + } + + bool utvpi_tester::linearize() { + + m_weight.reset(); + m_coeff_map.reset(); + + while (!m_terms.empty()) { + expr* e1, *e2; + rational num; + rational mul = m_terms.back().second; + expr* e = m_terms.back().first; + m_terms.pop_back(); + if (a.is_add(e)) { + for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { + m_terms.push_back(std::make_pair(to_app(e)->get_arg(i), mul)); + } + } + else if (a.is_mul(e, e1, e2) && a.is_numeral(e1, num)) { + m_terms.push_back(std::make_pair(e2, mul*num)); + } + else if (a.is_mul(e, e2, e1) && a.is_numeral(e1, num)) { + m_terms.push_back(std::make_pair(e2, mul*num)); + } + else if (a.is_sub(e, e1, e2)) { + m_terms.push_back(std::make_pair(e1, mul)); + m_terms.push_back(std::make_pair(e2, -mul)); + } + else if (a.is_uminus(e, e1)) { + m_terms.push_back(std::make_pair(e1, -mul)); + } + else if (a.is_numeral(e, num)) { + m_weight += num*mul; + } + else if (a.is_to_real(e, e1)) { + m_terms.push_back(std::make_pair(e1, mul)); + } + else if (!is_uninterp_const(e)) { + return false; + } + else { + m_coeff_map.insert_if_not_there2(e, rational(0))->get_data().m_value += mul; + } + } + obj_map::iterator it = m_coeff_map.begin(); + obj_map::iterator end = m_coeff_map.end(); + for (; it != end; ++it) { + rational r = it->m_value; + if (r.is_zero()) { + continue; + } + m_terms.push_back(std::make_pair(it->m_key, r)); + if (m_terms.size() > 2) { + return false; + } + if (!r.is_one() && !r.is_minus_one()) { + return false; + } + } + return true; + } + + +} diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h new file mode 100644 index 000000000..044fa11a0 --- /dev/null +++ b/src/smt/theory_utvpi.h @@ -0,0 +1,331 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + theory_utvpi.h + +Abstract: + + use Bellman Ford traversal algorithm for UTVPI. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-04-26 + +Revision History: + + The implementaton is derived from theory_diff_logic. + +--*/ + +#ifndef _THEORY_UTVPI_H_ +#define _THEORY_UTVPI_H_ + +#include"theory_diff_logic.h" + +namespace smt { + + class utvpi_tester { + ast_manager& m; + arith_util a; + ptr_vector m_todo; + ast_mark m_mark; + obj_map m_coeff_map; + rational m_weight; + vector > m_terms; + + public: + utvpi_tester(ast_manager& m); + + // test if formula is in the Horn inequality fragment: + bool operator()(expr* fml); + bool operator()(unsigned num_fmls, expr* const* fmls); + + // linearize inequality/equality + bool linearize(expr* e); + bool linearize(expr* e1, expr* e2); + + // retrieve linearization + vector > const& get_linearization() const; + rational const& get_weight() const { return m_weight; } + private: + bool linearize(); + }; + + template + class theory_utvpi : public theory, private Ext { + + typedef typename Ext::numeral numeral; + typedef theory_var th_var; + typedef svector th_var_vector; + typedef vector > coeffs; + + class assignment_trail; + class parent_trail; + + struct GExt : public Ext { + typedef literal explanation; + }; + + class atom { + protected: + bool_var m_bvar; + bool m_true; + int m_pos; + int m_neg; + public: + atom(bool_var bv, int pos, int neg) : + m_bvar(bv), m_true(false), + m_pos(pos), m_neg(neg) {} + virtual ~atom() {} + bool_var get_bool_var() const { return m_bvar; } + void assign_eh(bool is_true) { m_true = is_true; } + int get_asserted_edge() const { return this->m_true?m_pos:m_neg; } + int get_pos() const { return m_pos; } + int get_neg() const { return m_neg; } + std::ostream& display(theory_utvpi const& th, std::ostream& out) const; + }; + typedef svector atoms; + + struct scope { + unsigned m_atoms_lim; + unsigned m_asserted_atoms_lim; + unsigned m_asserted_qhead_old; + }; + + struct stats { + unsigned m_num_conflicts; + unsigned m_num_assertions; + unsigned m_num_core2th_eqs; + unsigned m_num_core2th_diseqs; + + void reset() { + memset(this, 0, sizeof(*this)); + } + + stats() { + reset(); + } + }; + + // Functor used to collect the proofs for a conflict due to + // a negative cycle. + class nc_functor { + literal_vector m_antecedents; + theory_utvpi& m_super; + public: + nc_functor(theory_utvpi& s) : m_super(s) {} + void reset() { m_antecedents.reset(); } + literal_vector const& get_lits() const { return m_antecedents; } + + void operator()(literal const & ex) { + if (ex != null_literal) { + m_antecedents.push_back(ex); + } + } + + void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) { + m_super.new_edge(src, dst, num_edges, edges); + } + }; + + + stats m_stats; + smt_params m_params; + arith_util a; + arith_eq_adapter m_arith_eq_adapter; + th_var m_zero_int; // cache the variable representing the zero variable. + th_var m_zero_real; // cache the variable representing the zero variable. + + dl_graph m_graph; + nc_functor m_nc_functor; + atoms m_atoms; + unsigned_vector m_asserted_atoms; // set of asserted atoms + unsigned m_asserted_qhead; + u_map m_bool_var2atom; + svector m_scopes; + + double m_agility; + bool m_lia; + bool m_lra; + bool m_non_utvpi_exprs; + + utvpi_tester m_test; + + + arith_factory * m_factory; + rational m_delta; + + + // Set a conflict due to a negative cycle. + void set_conflict(); + + void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {} + + // Create a new theory variable. + virtual th_var mk_var(enode* n); + + virtual th_var mk_var(expr* n); + + void compute_delta(); + + void found_non_utvpi_expr(expr * n); + + bool is_interpreted(app* n) const { + return n->get_family_id() == get_family_id(); + } + + public: + theory_utvpi(ast_manager& m); + + virtual ~theory_utvpi(); + + virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_utvpi, get_manager()); } + + virtual char const * get_name() const { return "utvpi-logic"; } + + /** + \brief See comment in theory::mk_eq_atom + */ + virtual app * mk_eq_atom(expr * lhs, expr * rhs) { return a.mk_eq(lhs, rhs); } + + virtual void init(context * ctx); + + virtual bool internalize_atom(app * atom, bool gate_ctx); + + virtual bool internalize_term(app * term); + + virtual void internalize_eq_eh(app * atom, bool_var v) {} + + virtual void assign_eh(bool_var v, bool is_true); + + virtual void new_eq_eh(th_var v1, th_var v2) { + m_arith_eq_adapter.new_eq_eh(v1, v2); + } + + virtual bool use_diseqs() const { return true; } + + virtual void new_diseq_eh(th_var v1, th_var v2) { + m_arith_eq_adapter.new_diseq_eh(v1, v2); + } + + virtual void push_scope_eh(); + + virtual void pop_scope_eh(unsigned num_scopes); + + virtual void restart_eh() { + m_arith_eq_adapter.restart_eh(); + } + + virtual void relevant_eh(app* e) {} + + virtual void init_search_eh() { + m_arith_eq_adapter.init_search_eh(); + } + + virtual final_check_status final_check_eh(); + + virtual bool is_shared(th_var v) const { + return false; + } + + virtual bool can_propagate() { + SASSERT(m_asserted_qhead <= m_asserted_atoms.size()); + return m_asserted_qhead != m_asserted_atoms.size(); + } + + virtual void propagate(); + + virtual justification * why_is_diseq(th_var v1, th_var v2) { + UNREACHABLE(); + return 0; + } + + virtual void reset_eh(); + + virtual void init_model(model_generator & m); + + virtual model_value_proc * mk_value(enode * n, model_generator & mg); + + virtual bool validate_eq_in_model(th_var v1, th_var v2, bool is_true) const { + return true; + } + + virtual void display(std::ostream & out) const; + + virtual void collect_statistics(::statistics & st) const; + + private: + + bool check_z_consistency(); + + virtual void new_eq_eh(th_var v1, th_var v2, justification& j) { + m_stats.m_num_core2th_eqs++; + new_eq_or_diseq(true, v1, v2, j); + } + + virtual void new_diseq_eh(th_var v1, th_var v2, justification& j) { + m_stats.m_num_core2th_diseqs++; + new_eq_or_diseq(false, v1, v2, j); + } + + void negate(coeffs& coeffs, rational& weight); + numeral mk_weight(bool is_real, bool is_strict, rational const& w) const; + void mk_coeffs(vector >const& terms, coeffs& coeffs, rational& w); + + void del_atoms(unsigned old_size); + + bool propagate_atom(atom const& a); + + th_var mk_term(app* n); + + th_var mk_num(app* n, rational const& r); + + bool is_consistent() const; + + th_var expand(bool pos, th_var v, rational & k); + + void new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just); + + th_var get_zero(sort* s) const { return a.is_int(s)?m_zero_int:m_zero_real; } + + th_var get_zero(expr* e) const { return get_zero(get_manager().get_sort(e)); } + + void inc_conflicts(); + + edge_id add_ineq(vector > const& terms, numeral const& weight, literal l); + + bool enable_edge(edge_id id); + + th_var to_var(th_var v) const { + return 2*v; + } + + th_var from_var(th_var v) const { + return v/2; + } + + th_var pos(th_var v) const { + return v & 0xFFFFFFFE; + } + + th_var neg(th_var v) const { + return v | 0x1; + } + + th_var not(th_var v) const { + return v ^ 0x1; + } + + }; + + + typedef theory_utvpi theory_rutvpi; + typedef theory_utvpi theory_iutvpi; +}; + + + + +#endif /* _THEORY_UTVPI_H_ */ diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h new file mode 100644 index 000000000..c369d6826 --- /dev/null +++ b/src/smt/theory_utvpi_def.h @@ -0,0 +1,694 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + theory_utvpi_def.h + +Abstract: + + Implementation of UTVPI solver. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-04-26 + +Revision History: + + 1. introduce x^+ and x^-, such that 2*x := x^+ - x^- + 2. rewrite constraints as follows: + + x - y <= k => x^+ - y^+ <= k + y^- - x^- <= k + + x <= k => x^+ - x^- <= 2k + + + x + y <= k => x^+ - y^- <= k + y^+ - x^- <= k + + + - x - y <= k => x^- - y^+ <= k + y^- - x^+ <= k + + 3. Solve for x^+ and x^- + 4. Check parity condition for integers (see Lahiri and Musuvathi 05) + 5. extract model for M(x) := (M(x^+)- M(x^-))/2 + +--*/ + +#ifndef _THEORY_UTVPI_DEF_H_ +#define _THEORY_UTVPI_DEF_H_ +#include "theory_utvpi.h" +#include "heap.h" +#include "ast_pp.h" +#include "smt_context.h" + +namespace smt { + + + template + theory_utvpi::theory_utvpi(ast_manager& m): + theory(m.mk_family_id("arith")), + a(m), + m_arith_eq_adapter(*this, m_params, a), + m_zero_int(null_theory_var), + m_zero_real(null_theory_var), + m_asserted_qhead(0), + m_nc_functor(*this), + m_agility(0.5), + m_lia(false), + m_lra(false), + m_non_utvpi_exprs(false), + m_test(m), + m_factory(0) { + } + + template + theory_utvpi::~theory_utvpi() { + reset_eh(); + } + + template + std::ostream& theory_utvpi::atom::display(theory_utvpi const& th, std::ostream& out) const { + context& ctx = th.get_context(); + lbool asgn = ctx.get_assignment(m_bvar); + bool sign = (l_undef == l_false); + return out << literal(m_bvar, sign) << " " << mk_pp(ctx.bool_var2expr(m_bvar), th.get_manager()) << " "; + if (l_undef == asgn) { + out << "unassigned\n"; + } + else { + th.m_graph.display_edge(out, get_asserted_edge()); + } + return out; + } + + template + theory_var theory_utvpi::mk_var(enode* n) { + th_var v = theory::mk_var(n); + TRACE("utvpi", tout << v << " " << mk_pp(n->get_owner(), get_manager()) << "\n";); + m_graph.init_var(to_var(v)); + m_graph.init_var(neg(to_var(v))); + get_context().attach_th_var(n, this, v); + return v; + } + + template + theory_var theory_utvpi::mk_var(expr* n) { + context & ctx = get_context(); + enode* e = 0; + th_var v = null_theory_var; + m_lia |= a.is_int(n); + m_lra |= a.is_real(n); + if (!is_app(n)) { + return v; + } + if (ctx.e_internalized(n)) { + e = ctx.get_enode(n); + v = e->get_th_var(get_id()); + } + else { + ctx.internalize(n, false); + e = ctx.get_enode(n); + } + if (v == null_theory_var) { + v = mk_var(e); + } + if (is_interpreted(to_app(n))) { + found_non_utvpi_expr(n); + } + return v; + } + + template + void theory_utvpi::reset_eh() { + m_graph .reset(); + m_zero_int = null_theory_var; + m_zero_real = null_theory_var; + m_atoms .reset(); + m_asserted_atoms .reset(); + m_stats .reset(); + m_scopes .reset(); + m_asserted_qhead = 0; + m_agility = 0.5; + m_lia = false; + m_lra = false; + m_non_utvpi_exprs = false; + theory::reset_eh(); + } + + template + void theory_utvpi::new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just) { + rational k; + th_var s = expand(true, v1, k); + th_var t = expand(false, v2, k); + context& ctx = get_context(); + ast_manager& m = get_manager(); + + if (s == t) { + if (is_eq != k.is_zero()) { + // conflict 0 /= k; + inc_conflicts(); + ctx.set_conflict(&eq_just); + } + } + else { + // + // Create equality ast, internalize_atom + // assign the corresponding equality literal. + // + + app_ref eq(m), s2(m), t2(m); + app* s1 = get_enode(s)->get_owner(); + app* t1 = get_enode(t)->get_owner(); + s2 = a.mk_sub(t1, s1); + t2 = a.mk_numeral(k, m.get_sort(s2.get())); + // t1 - s1 = k + eq = m.mk_eq(s2.get(), t2.get()); + + TRACE("utvpi", + tout << v1 << " .. " << v2 << "\n"; + tout << mk_pp(eq.get(), m) <<"\n";); + + if (!internalize_atom(eq.get(), false)) { + UNREACHABLE(); + } + + literal l(ctx.get_literal(eq.get())); + if (!is_eq) { + l = ~l; + } + ctx.assign(l, b_justification(&eq_just), false); + } + } + + template + void theory_utvpi::inc_conflicts() { + m_stats.m_num_conflicts++; + if (m_params.m_arith_adaptive) { + double g = m_params.m_arith_adaptive_propagation_threshold; + m_agility = m_agility*g + 1 - g; + } + } + + template + void theory_utvpi::set_conflict() { + inc_conflicts(); + literal_vector const& lits = m_nc_functor.get_lits(); + context & ctx = get_context(); + TRACE("utvpi", + tout << "conflict: "; + for (unsigned i = 0; i < lits.size(); ++i) { + ctx.display_literal_info(tout, lits[i]); + } + tout << "\n"; + ); + + if (m_params.m_arith_dump_lemmas) { + char const * logic = m_lra ? (m_lia?"QF_LIRA":"QF_LRA") : "QF_LIA"; + ctx.display_lemma_as_smt_problem(lits.size(), lits.c_ptr(), false_literal, logic); + } + + vector params; + if (get_manager().proofs_enabled()) { + params.push_back(parameter(symbol("farkas"))); + params.resize(lits.size()+1, parameter(rational(1))); + } + + ctx.set_conflict( + ctx.mk_justification( + ext_theory_conflict_justification( + get_id(), ctx.get_region(), + lits.size(), lits.c_ptr(), 0, 0, params.size(), params.c_ptr()))); + + m_nc_functor.reset(); + } + + template + void theory_utvpi::found_non_utvpi_expr(expr* n) { + if (!m_non_utvpi_exprs) { + TRACE("utvpi", tout << "found non horn logic expression:\n" << mk_pp(n, get_manager()) << "\n";); + get_context().push_trail(value_trail(m_non_utvpi_exprs)); + m_non_utvpi_exprs = true; + } + } + + template + void theory_utvpi::init(context* ctx) { + theory::init(ctx); + m_zero_int = mk_var(ctx->mk_enode(a.mk_numeral(rational(0), true), false, false, true)); + m_zero_real = mk_var(ctx->mk_enode(a.mk_numeral(rational(0), false), false, false, true)); + } + + /** + \brief Create negated literal. + + The negation of: E <= 0 + + -E + epsilon <= 0 + or + -E + 1 <= 0 + */ + template + void theory_utvpi::negate(coeffs& coeffs, rational& weight) { + for (unsigned i = 0; i < coeffs.size(); ++i) { + coeffs[i].second.neg(); + } + weight.neg(); + } + + template + typename theory_utvpi::numeral theory_utvpi::mk_weight(bool is_real, bool is_strict, rational const& w) const { + if (is_strict) { + return numeral(w) + (is_real?m_epsilon:numeral(1)); + } + else { + return numeral(w); + } + } + + template + void theory_utvpi::mk_coeffs(vector > const& terms, coeffs& coeffs, rational& w) { + coeffs.reset(); + w = m_test.get_weight(); + for (unsigned i = 0; i < terms.size(); ++i) { + coeffs.push_back(std::make_pair(mk_var(terms[i].first), terms[i].second)); + } + } + + template + bool theory_utvpi::internalize_atom(app * n, bool) { + context & ctx = get_context(); + if (!a.is_le(n) && !a.is_ge(n) && !a.is_lt(n) && !a.is_gt(n)) { + found_non_utvpi_expr(n); + return false; + } + SASSERT(!ctx.b_internalized(n)); + expr* e1 = n->get_arg(0), *e2 = n->get_arg(1); + if (a.is_ge(n) || a.is_gt(n)) { + std::swap(e1, e2); + } + bool is_strict = a.is_gt(n) || a.is_lt(n); + + bool cl = m_test.linearize(e1, e2); + if (!cl) { + found_non_utvpi_expr(n); + return false; + } + + rational w; + coeffs coeffs; + mk_coeffs(m_test.get_linearization(), coeffs, w); + bool_var bv = ctx.mk_bool_var(n); + ctx.set_var_theory(bv, get_id()); + literal l(bv); + numeral w1 = mk_weight(a.is_real(e1), is_strict, w); + edge_id pos = add_ineq(coeffs, w1, l); + negate(coeffs, w); + numeral w2 = mk_weight(a.is_real(e1), !is_strict, w); + edge_id neg = add_ineq(coeffs, w2, ~l); + m_bool_var2atom.insert(bv, m_atoms.size()); + m_atoms.push_back(atom(bv, pos, neg)); + + TRACE("utvpi", + tout << mk_pp(n, get_manager()) << "\n"; + m_graph.display_edge(tout << "pos: ", pos); + m_graph.display_edge(tout << "neg: ", neg); + ); + + return true; + } + + template + bool theory_utvpi::internalize_term(app * term) { + bool result = null_theory_var != mk_term(term); + CTRACE("utvpi", !result, tout << "Did not internalize " << mk_pp(term, get_manager()) << "\n";); + TRACE("utvpi", tout << "Terms may not be internalized " << mk_pp(term, get_manager()) << "\n";); + found_non_utvpi_expr(term); + return result; + } + + template + void theory_utvpi::assign_eh(bool_var v, bool is_true) { + m_stats.m_num_assertions++; + unsigned idx = m_bool_var2atom.find(v); + SASSERT(get_context().get_assignment(v) != l_undef); + SASSERT((get_context().get_assignment(v) == l_true) == is_true); + m_atoms[idx].assign_eh(is_true); + m_asserted_atoms.push_back(idx); + } + + template + void theory_utvpi::push_scope_eh() { + theory::push_scope_eh(); + m_graph.push(); + m_scopes.push_back(scope()); + scope & s = m_scopes.back(); + s.m_atoms_lim = m_atoms.size(); + s.m_asserted_atoms_lim = m_asserted_atoms.size(); + s.m_asserted_qhead_old = m_asserted_qhead; + } + + template + void theory_utvpi::pop_scope_eh(unsigned num_scopes) { + unsigned lvl = m_scopes.size(); + SASSERT(num_scopes <= lvl); + unsigned new_lvl = lvl - num_scopes; + scope & s = m_scopes[new_lvl]; + del_atoms(s.m_atoms_lim); + m_asserted_atoms.shrink(s.m_asserted_atoms_lim); + m_asserted_qhead = s.m_asserted_qhead_old; + m_scopes.shrink(new_lvl); + m_graph.pop(num_scopes); + theory::pop_scope_eh(num_scopes); + } + + template + final_check_status theory_utvpi::final_check_eh() { + SASSERT(is_consistent()); + TRACE("utvpi", display(tout);); + if (can_propagate()) { + propagate(); + return FC_CONTINUE; + } + else if (!check_z_consistency()) { + return FC_CONTINUE; + } + else if (m_non_utvpi_exprs) { + return FC_GIVEUP; + } + else { + m_graph.set_to_zero(to_var(m_zero_int), to_var(m_zero_real)); + m_graph.set_to_zero(neg(to_var(m_zero_int)), neg(to_var(m_zero_real))); + m_graph.set_to_zero(to_var(m_zero_int), neg(to_var(m_zero_int))); + return FC_DONE; + } + } + + template + bool theory_utvpi::check_z_consistency() { + int_vector scc_id; + m_graph.compute_zero_edge_scc(scc_id); + + unsigned sz = get_num_vars(); + for (unsigned i = 0; i < sz; ++i) { + enode* e = get_enode(i); + if (a.is_int(e->get_owner())) { + continue; + } + th_var v1 = to_var(i); + th_var v2 = neg(v1); + rational r1 = m_graph.get_assignment(v1).get_rational(); + rational r2 = m_graph.get_assignment(v2).get_rational(); + SASSERT(r1.is_int()); + SASSERT(r2.is_int()); + if (r1.is_even() == r2.is_even()) { + continue; + } + if (scc_id[v1] != scc_id[v2]) { + continue; + } + if (scc_id[v1] == -1) { + continue; + } + // they are in the same SCC and have different parities => contradiction. + m_nc_functor.reset(); + VERIFY(m_graph.find_shortest_zero_edge_path(v1, v2, UINT_MAX, m_nc_functor)); + VERIFY(m_graph.find_shortest_zero_edge_path(v2, v1, UINT_MAX, m_nc_functor)); + set_conflict(); + + return false; + } + return true; + } + + template + void theory_utvpi::display(std::ostream& out) const { + for (unsigned i = 0; i < m_atoms.size(); ++i) { + m_atoms[i].display(*this, out); out << "\n"; + } + m_graph.display(out); + } + + template + void theory_utvpi::collect_statistics(::statistics& st) const { + st.update("utvpi conflicts", m_stats.m_num_conflicts); + st.update("utvpi assignments", m_stats.m_num_assertions); + m_arith_eq_adapter.collect_statistics(st); + m_graph.collect_statistics(st); + } + + template + void theory_utvpi::del_atoms(unsigned old_size) { + typename atoms::iterator begin = m_atoms.begin() + old_size; + typename atoms::iterator it = m_atoms.end(); + while (it != begin) { + --it; + m_bool_var2atom.erase(it->get_bool_var()); + } + m_atoms.shrink(old_size); + } + + template + void theory_utvpi::propagate() { + bool consistent = true; + while (consistent && can_propagate()) { + unsigned idx = m_asserted_atoms[m_asserted_qhead]; + m_asserted_qhead++; + consistent = propagate_atom(m_atoms[idx]); + } + } + + template + bool theory_utvpi::propagate_atom(atom const& a) { + context& ctx = get_context(); + TRACE("utvpi", a.display(*this, tout); tout << "\n";); + if (ctx.inconsistent()) { + return false; + } + int edge_id = a.get_asserted_edge(); + if (!enable_edge(edge_id)) { + m_graph.traverse_neg_cycle2(m_params.m_arith_stronger_lemmas, m_nc_functor); + set_conflict(); + return false; + } + return true; + } + + template + theory_var theory_utvpi::mk_term(app* n) { + context& ctx = get_context(); + + bool cl = m_test.linearize(n); + if (!cl) { + found_non_utvpi_expr(n); + return null_theory_var; + } + + coeffs coeffs; + rational w; + mk_coeffs(m_test.get_linearization(), coeffs, w); + if (coeffs.empty()) { + return mk_num(n, w); + } + if (coeffs.size() == 1 && coeffs[0].second.is_one()) { + return coeffs[0].first; + } + th_var target = mk_var(ctx.mk_enode(n, false, false, true)); + coeffs.push_back(std::make_pair(target, rational(-1))); + + VERIFY(enable_edge(add_ineq(coeffs, numeral(w), null_literal))); + negate(coeffs, w); + VERIFY(enable_edge(add_ineq(coeffs, numeral(w), null_literal))); + return target; + } + + template + theory_var theory_utvpi::mk_num(app* n, rational const& r) { + theory_var v = null_theory_var; + context& ctx = get_context(); + if (r.is_zero()) { + v = a.is_int(n)?m_zero_int:m_zero_real; + } + else if (ctx.e_internalized(n)) { + enode* e = ctx.get_enode(n); + v = e->get_th_var(get_id()); + SASSERT(v != null_theory_var); + } + else { + v = mk_var(ctx.mk_enode(n, false, false, true)); + // v = k: v <= k k <= v + coeffs coeffs; + coeffs.push_back(std::make_pair(v, rational(1))); + VERIFY(enable_edge(add_ineq(coeffs, numeral(r), null_literal))); + coeffs.back().second.neg(); + VERIFY(enable_edge(add_ineq(coeffs, numeral(-r), null_literal))); + } + return v; + } + + template + theory_var theory_utvpi::expand(bool pos, th_var v, rational & k) { + context& ctx = get_context(); + enode* e = get_enode(v); + expr* x, *y; + rational r; + for (;;) { + app* n = e->get_owner(); + if (a.is_add(n, x, y)) { + if (a.is_numeral(x, r)) { + e = ctx.get_enode(y); + } + else if (a.is_numeral(y, r)) { + e = ctx.get_enode(x); + } + v = e->get_th_var(get_id()); + SASSERT(v != null_theory_var); + if (v == null_theory_var) { + break; + } + if (pos) { + k += r; + } + else { + k -= r; + } + } + else { + break; + } + } + return v; + } + + // m_graph(source, target, weight, ex); + // target - source <= weight + + template + edge_id theory_utvpi::add_ineq(vector > const& terms, numeral const& weight, literal l) { + + SASSERT(terms.size() <= 2); + SASSERT(terms.size() < 1 || terms[0].second.is_one() || terms[0].second.is_minus_one()); + SASSERT(terms.size() < 2 || terms[1].second.is_one() || terms[1].second.is_minus_one()); + + th_var v1 = null_theory_var, v2 = null_theory_var; + bool pos1 = true, pos2 = true; + if (terms.size() >= 1) { + v1 = terms[0].first; + pos1 = terms[0].second.is_one(); + SASSERT(v1 != null_theory_var); + SASSERT(pos1 || terms[0].second.is_minus_one()); + } + if (terms.size() >= 2) { + v2 = terms[1].first; + pos2 = terms[1].second.is_one(); + SASSERT(v1 != null_theory_var); + SASSERT(pos2 || terms[1].second.is_minus_one()); + } +// TRACE("utvpi", tout << (pos1?"$":"-$") << v1 << (pos2?" + $":" - $") << v2 << " + " << weight << " <= 0\n";); + edge_id id = m_graph.get_num_edges(); + th_var w1 = to_var(v1), w2 = to_var(v2); + if (terms.size() == 1 && pos1) { + m_graph.add_edge(neg(w1), pos(w1), -weight-weight, l); + m_graph.add_edge(neg(w1), pos(w1), -weight-weight, l); + } + else if (terms.size() == 1 && !pos1) { + m_graph.add_edge(pos(w1), neg(w1), -weight-weight, l); + m_graph.add_edge(pos(w1), neg(w1), -weight-weight, l); + } + else if (pos1 && pos2) { + m_graph.add_edge(neg(w2), pos(w1), -weight, l); + m_graph.add_edge(neg(w1), pos(w2), -weight, l); + } + else if (pos1 && !pos2) { + m_graph.add_edge(pos(w2), pos(w1), -weight, l); + m_graph.add_edge(neg(w1), neg(w2), -weight, l); + } + else if (!pos1 && pos2) { + m_graph.add_edge(neg(w2), neg(w1), -weight, l); + m_graph.add_edge(pos(w1), pos(w2), -weight, l); + } + else { + m_graph.add_edge(pos(w1), neg(w2), -weight, l); + m_graph.add_edge(pos(w2), neg(w1), -weight, l); + } + return id; + } + + template + bool theory_utvpi::enable_edge(edge_id id) { + return (id == null_edge_id) || (m_graph.enable_edge(id) && m_graph.enable_edge(id+1)); + } + + template + bool theory_utvpi::is_consistent() const { + return m_graph.is_feasible(); + } + + // models: + template + void theory_utvpi::init_model(model_generator & m) { + m_factory = alloc(arith_factory, get_manager()); + m.register_factory(m_factory); + // TBD: enforce strong or tight coherence? + compute_delta(); + } + + template + model_value_proc * theory_utvpi::mk_value(enode * n, model_generator & mg) { + theory_var v = n->get_th_var(get_id()); + SASSERT(v != null_theory_var); + numeral val1 = m_graph.get_assignment(to_var(v)); + numeral val2 = m_graph.get_assignment(neg(to_var(v))); + numeral val = val1 - val2; + rational num = val.get_rational() + (m_delta * val.get_infinitesimal().to_rational()); + num = num/rational(2); + TRACE("utvpi", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";); + return alloc(expr_wrapper_proc, m_factory->mk_value(num, a.is_int(n->get_owner()))); + } + + /** + \brief Compute numeral values for the infinitesimals to satisfy the inequalities. + */ + + template + void theory_utvpi::compute_delta() { + m_delta = rational(1); + unsigned sz = m_graph.get_num_edges(); + + for (unsigned i = 0; i < sz; ++i) { + if (!m_graph.is_enabled(i)) { + continue; + } + numeral w = m_graph.get_weight(i); + numeral tgt = m_graph.get_assignment(m_graph.get_target(i)); + numeral src = m_graph.get_assignment(m_graph.get_source(i)); + numeral b = tgt - src - w; + SASSERT(b.is_nonpos()); + rational eps_r = b.get_infinitesimal(); + + // Given: b <= 0 + // suppose that 0 < b.eps + // then we have 0 > b.num + // then delta must ensure: + // 0 >= b.num + delta*b.eps + // <=> + // -b.num/b.eps >= delta + if (eps_r.is_pos()) { + rational num_r = -b.get_rational(); + SASSERT(num_r.is_pos()); + rational new_delta = num_r/eps_r; + if (new_delta < m_delta) { + m_delta = new_delta; + } + } + } + } + + + +}; + +#endif + diff --git a/src/util/inf_eps_rational.h b/src/util/inf_eps_rational.h new file mode 100644 index 000000000..659fdc400 --- /dev/null +++ b/src/util/inf_eps_rational.h @@ -0,0 +1,409 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + inf_eps_rational.h + +Abstract: + + Rational numbers with infinity and epsilon. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-4-23. + +Revision History: + +--*/ +#ifndef _INF_EPS_RATIONAL_H_ +#define _INF_EPS_RATIONAL_H_ +#include +#include +#include"debug.h" +#include"vector.h" +#include"rational.h" + +template +class inf_eps_rational { + rational m_infty; + Numeral m_r; + public: + + unsigned hash() const { + return m_infty.hash() ^ m_r.hash(); + } + + struct hash_proc { unsigned operator()(inf_eps_rational const& r) const { return r.hash(); } }; + + struct eq_proc { bool operator()(inf_eps_rational const& r1, inf_eps_rational const& r2) const { return r1 == r2; } }; + + void swap(inf_eps_rational & n) { + m_infty.swap(n.m_infty); + m_r.swap(n.m_r); + } + + std::string to_string() const { + if (m_infty.is_zero()) { + return m_r.to_string(); + } + std::string si; + if (m_infty.is_one()) { + si = "oo"; + } + else if (m_infty.is_minus_one()) { + si = "-oo"; + } + else { + si = m_infty.to_string() += "*oo"; + } + if (m_r.is_zero()) { + return si; + } + std::string s = "("; + s += si; + s += " + "; + s += m_r.to_string(); + s += ")"; + return s; + } + + inf_eps_rational(): + m_infty(), + m_r() + {} + + inf_eps_rational(const inf_eps_rational & r): + m_infty(r.m_infty), + m_r(r.m_r) + {} + + explicit inf_eps_rational(int n): + m_infty(), + m_r(n) + {} + + explicit inf_eps_rational(Numeral const& r): + m_infty(), + m_r(r) + {} + + explicit inf_eps_rational(rational const& i, Numeral const& r): + m_infty(i), + m_r(r) { + } + + ~inf_eps_rational() {} + + /** + \brief Set inf_eps_rational to 0. + */ + void reset() { + m_infty.reset(); + m_r.reset(); + } + + bool is_int() const { + return m_infty.is_zero() && m_r.is_int(); + } + + bool is_int64() const { + return m_infty.is_zero() && m_r.is_int64(); + } + + bool is_uint64() const { + return m_infty.is_zero() && m_r.is_uint64(); + } + + bool is_rational() const { return m_infty.is_zero() && m_r.is_rational(); } + + int64 get_int64() const { + SASSERT(is_int64()); + return m_r.get_int64(); + } + + uint64 get_uint64() const { + SASSERT(is_uint64()); + return m_r.get_uint64(); + } + + rational const& get_rational() const { + return m_r.get_rational(); + } + + rational const& get_infinitesimal() const { + return m_r.get_infinitesimal(); + } + + rational const& get_infinity() const { + return m_infty; + } + + inf_eps_rational & operator=(const inf_eps_rational & r) { + m_infty = r.m_infty; + m_r = r.m_r; + return *this; + } + + inf_eps_rational & operator=(const rational & r) { + m_infty.reset(); + m_r = r; + return *this; + } + + inf_eps_rational & operator+=(const inf_eps_rational & r) { + m_infty += r.m_infty; + m_r += r.m_r; + return *this; + } + + inf_eps_rational & operator-=(const inf_eps_rational & r) { + m_infty -= r.m_infty; + m_r -= r.m_r; + return *this; + } + + inf_eps_rational & operator+=(const rational & r) { + m_r += r; + return *this; + } + + inf_eps_rational & operator-=(const rational & r) { + m_r -= r; + return *this; + } + + inf_eps_rational & operator*=(const rational & r1) { + m_infty *= r1; + m_r *= r1; + return *this; + } + + inf_eps_rational & operator/=(const rational & r) { + m_infty /= r; + m_r /= r; + return *this; + } + + + inf_eps_rational & operator++() { + ++m_r; + return *this; + } + + const inf_eps_rational operator++(int) { inf_eps_rational tmp(*this); ++(*this); return tmp; } + + inf_eps_rational & operator--() { + --m_r; + return *this; + } + + const inf_eps_rational operator--(int) { inf_eps_rational tmp(*this); --(*this); return tmp; } + + friend inline bool operator==(const inf_eps_rational & r1, const inf_eps_rational & r2) { + return r1.m_infty == r2.m_infty && r1.m_r == r2.m_r; + } + + friend inline bool operator==(const rational & r1, const inf_eps_rational & r2) { + return r1 == r2.m_infty && r2.m_r.is_zero(); + } + + friend inline bool operator==(const inf_eps_rational & r1, const rational & r2) { + return r1.m_infty == r2 && r1.m_r.is_zero(); + } + + friend inline bool operator<(const inf_eps_rational & r1, const inf_eps_rational & r2) { + return + (r1.m_infty < r2.m_infty) || + (r1.m_infty == r2.m_infty && r1.m_r < r2.m_r); + } + + friend inline bool operator<(const rational & r1, const inf_eps_rational & r2) { + return + r2.m_infty.is_pos() || + (r2.m_infty.is_zero() && r1 < r2.m_r); + } + + friend inline bool operator<(const inf_eps_rational & r1, const rational & r2) { + return + r1.m_infty.is_neg() || + (r1.m_infty.is_zero() && r1.m_r < r2); + } + + void neg() { + m_infty.neg(); + m_r.neg(); + } + + bool is_zero() const { + return m_infty.is_zero() && m_r.is_zero(); + } + + bool is_one() const { + return m_infty.is_zero() && m_r.is_one(); + } + + bool is_minus_one() const { + return m_infty.is_zero() && m_r.is_minus_one(); + } + + bool is_neg() const { + return + m_infty.is_neg() || + (m_infty.is_zero() && m_r.is_neg()); + } + + bool is_pos() const { + return + m_infty.is_pos() || + (m_infty.is_zero() && m_r.is_pos()); + } + + bool is_nonneg() const { + return + m_infty.is_pos() || + (m_infty.is_zero() && m_r.is_nonneg()); + } + + bool is_nonpos() const { + return + m_infty.is_neg() || + (m_infty.is_zero() && m_r.is_nonpos()); + } + + friend inline rational floor(const inf_eps_rational & r) { + SASSERT(r.m_infty.is_zero()); + return floor(r.m_r); + } + + friend inline rational ceil(const inf_eps_rational & r) { + SASSERT(r.m_infty.is_zero()); + return ceil(r.m_r); + } + + + // Perform: this += c * k + void addmul(const rational & c, const inf_eps_rational & k) { + m_infty.addmul(c, k.m_infty); + m_r.addmul(c, k.m_r); + } + + // Perform: this += c * k + void submul(const rational & c, const inf_eps_rational & k) { + m_infty.submul(c, k.m_infty); + m_r.submul(c, k.m_r); + } +}; + +template +inline bool operator!=(const inf_eps_rational & r1, const inf_eps_rational & r2) { + return !operator==(r1, r2); +} + +template +inline bool operator!=(const rational & r1, const inf_eps_rational & r2) { + return !operator==(r1, r2); +} + +template +inline bool operator!=(const inf_eps_rational & r1, const rational & r2) { + return !operator==(r1, r2); +} + +template +inline bool operator>(const inf_eps_rational & r1, const inf_eps_rational & r2) { + return operator<(r2, r1); +} + +template +inline bool operator>(const inf_eps_rational & r1, const rational & r2) { + return operator<(r2, r1); +} + +template +inline bool operator>(const rational & r1, const inf_eps_rational & r2) { + return operator<(r2, r1); +} + +template +inline bool operator<=(const inf_eps_rational & r1, const inf_eps_rational & r2) { + return !operator>(r1, r2); +} + +template +inline bool operator<=(const rational & r1, const inf_eps_rational & r2) { + return !operator>(r1, r2); +} + +template +inline bool operator<=(const inf_eps_rational & r1, const rational & r2) { + return !operator>(r1, r2); +} + +template +inline bool operator>=(const inf_eps_rational & r1, const inf_eps_rational & r2) { + return !operator<(r1, r2); +} + +template +inline bool operator>=(const rational & r1, const inf_eps_rational & r2) { + return !operator<(r1, r2); +} + +template +inline bool operator>=(const inf_eps_rational & r1, const rational & r2) { + return !operator<(r1, r2); +} + +template +inline inf_eps_rational operator+(const inf_eps_rational & r1, const inf_eps_rational & r2) { + return inf_eps_rational(r1) += r2; +} + +template +inline inf_eps_rational operator-(const inf_eps_rational & r1, const inf_eps_rational & r2) { + return inf_eps_rational(r1) -= r2; +} + +template +inline inf_eps_rational operator-(const inf_eps_rational & r) { + inf_eps_rational result(r); + result.neg(); + return result; +} + +template +inline inf_eps_rational operator*(const rational & r1, const inf_eps_rational & r2) { + inf_eps_rational result(r2); + result *= r1; + return result; +} + +template +inline inf_eps_rational operator*(const inf_eps_rational & r1, const rational & r2) { + return r2 * r1; +} + +template +inline inf_eps_rational operator/(const inf_eps_rational & r1, const rational & r2) { + inf_eps_rational result(r1); + result /= r2; + return result; +} + +template +inline std::ostream & operator<<(std::ostream & target, const inf_eps_rational & r) { + target << r.to_string(); + return target; +} + +template +inline inf_eps_rational abs(const inf_eps_rational & r) { + inf_eps_rational result(r); + if (result.is_neg()) { + result.neg(); + } + return result; +} + +#endif /* _INF_EPS_RATIONAL_H_ */ From 3ac7cbe1c5316dc8eaab62fbc3b338e390c5867a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 28 Apr 2013 12:51:33 -0700 Subject: [PATCH 116/281] fix build breaker Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_rule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index e43445396..1bbb1f342 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -202,7 +202,7 @@ namespace datalog { unsigned index = extract_horn(fml, m_body, m_head); hoist_compound_predicates(index, m_head, m_body); TRACE("dl_rule", - tout << mk_pp(head, m) << " :- "; + tout << mk_pp(m_head, m) << " :- "; for (unsigned i = 0; i < m_body.size(); ++i) { tout << mk_pp(m_body[i].get(), m) << " "; } From 4471d929f7c2b6b9409e37eec638cdb2b8afe98f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 28 Apr 2013 13:20:31 -0700 Subject: [PATCH 117/281] fix linking error in debug mode Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_rule.cpp | 7 ++++++- src/muz_qe/dl_rule.h | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 1bbb1f342..db8189c64 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -72,6 +72,8 @@ namespace datalog { } } + rule_manager::remove_label_cfg::~remove_label_cfg() {} + br_status rule_manager::remove_label_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { @@ -83,6 +85,9 @@ namespace datalog { return BR_FAILED; } + template class rewriter_tpl; + + void rule_manager::remove_labels(expr_ref& fml, proof_ref& pr) { expr_ref tmp(m); m_rwr(fml, tmp); @@ -1113,6 +1118,6 @@ namespace datalog { } - + }; diff --git a/src/muz_qe/dl_rule.h b/src/muz_qe/dl_rule.h index 6335c506f..77bf9ac74 100644 --- a/src/muz_qe/dl_rule.h +++ b/src/muz_qe/dl_rule.h @@ -53,8 +53,8 @@ namespace datalog { class remove_label_cfg : public default_rewriter_cfg { family_id m_label_fid; public: - remove_label_cfg(ast_manager& m): m_label_fid(m.get_label_family_id()) {} - virtual ~remove_label_cfg() {} + remove_label_cfg(ast_manager& m): m_label_fid(m.get_label_family_id()) {} + virtual ~remove_label_cfg(); br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr); From be64e4b238c097f20862502685b01e3f8a0caf88 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 28 Apr 2013 13:37:03 -0700 Subject: [PATCH 118/281] add special procedures for UTVPI and horn arithmetic Signed-off-by: Nikolaj Bjorner --- src/smt/theory_horn_ineq.h | 24 +++++------------------- src/smt/theory_horn_ineq_def.h | 6 ++---- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/src/smt/theory_horn_ineq.h b/src/smt/theory_horn_ineq.h index f5fb41263..441e46a18 100644 --- a/src/smt/theory_horn_ineq.h +++ b/src/smt/theory_horn_ineq.h @@ -6,30 +6,16 @@ Module Name: theory_horn_ineq.h Abstract: - - A*x <= b + D*x, coefficients to A and D are non-negative, + A*x <= weight + D*x, coefficients to A and D are non-negative, D is a diagonal matrix. - Coefficients to b may have both signs. - + Coefficients to weight may have both signs. - Ford-Fulkerson variant: Label variables by weight. Select inequality that is not satisfied. - Set gamma(LHS) := 0 - Set gamma(RHS(x)) := weight(x) - b - Propagate gamma through inequalities. - Gamma is the increment. - Maintain Heap of variables weighted by gamma. - When processing inequality, - then update gamma of variables by gamma := A(gamma + weight) - b - If some variable in the premise of the original rule gets - relabeled (assignment is increased), then the set of - inequalities is unsatisfiable. - - Propagation updates lower bounds on gamma by taking into - account integer inequalities. The greatest lower bound - is computable by taking integer floor/ceilings. + Set delta(LHS) := 0 + Set delta(RHS(x)) := weight(x) - b + Propagate weight increment through inequalities. Author: diff --git a/src/smt/theory_horn_ineq_def.h b/src/smt/theory_horn_ineq_def.h index b86d45819..1fc51a86c 100644 --- a/src/smt/theory_horn_ineq_def.h +++ b/src/smt/theory_horn_ineq_def.h @@ -937,10 +937,8 @@ namespace smt { template void theory_horn_ineq::collect_statistics(::statistics& st) const { - st.update("hi conflicts", m_stats.m_num_conflicts); -// st.update("hi propagations", m_stats.m_num_th2core_prop); -// st.update("hi asserts", m_stats.m_num_assertions); -// st.update("core->hi eqs", m_stats.m_num_core2th_eqs); + st.update("horn ineq conflicts", m_stats.m_num_conflicts); + st.update("horn ineq assertions", m_stats.m_num_assertions); m_arith_eq_adapter.collect_statistics(st); m_graph->collect_statistics(st); } From fbe4af633665204a49bdda5c79f187c9d2678ffc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 28 Apr 2013 13:39:26 -0700 Subject: [PATCH 119/281] add backward propagation transformation Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_backwards.cpp | 78 ++++++++++++++++++++++++++++++++++ src/muz_qe/dl_mk_backwards.h | 38 +++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 src/muz_qe/dl_mk_backwards.cpp create mode 100644 src/muz_qe/dl_mk_backwards.h diff --git a/src/muz_qe/dl_mk_backwards.cpp b/src/muz_qe/dl_mk_backwards.cpp new file mode 100644 index 000000000..b1d8b7d36 --- /dev/null +++ b/src/muz_qe/dl_mk_backwards.cpp @@ -0,0 +1,78 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_backwards.cpp + +Abstract: + + Create Horn clauses for backwards flow. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-04-17 + +Revision History: + +--*/ + +#include"dl_mk_backwards.h" +#include"dl_context.h" + +namespace datalog { + + mk_backwards::mk_backwards(context & ctx, unsigned priority): + plugin(priority), + m(ctx.get_manager()), + m_ctx(ctx) { + } + + mk_backwards::~mk_backwards() { } + + rule_set * mk_backwards::operator()(rule_set const & source) { + context& ctx = source.get_context(); + rule_manager& rm = source.get_rule_manager(); + rule_set * result = alloc(rule_set, ctx); + unsigned sz = source.get_num_rules(); + rule_ref new_rule(rm); + app_ref_vector tail(m); + app_ref head(m); + svector neg; + app_ref query(m); + query = m.mk_fresh_const("Q", m.mk_bool_sort()); + result->set_output_predicate(query->get_decl()); + m_ctx.register_predicate(query->get_decl(), false); + for (unsigned i = 0; i < sz; ++i) { + tail.reset(); + neg.reset(); + rule & r = *source.get_rule(i); + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + if (!source.is_output_predicate(r.get_decl())) { + tail.push_back(r.get_head()); + neg.push_back(false); + } + for (unsigned j = utsz; j < tsz; ++j) { + tail.push_back(r.get_tail(j)); + neg.push_back(false); + } + for (unsigned j = 0; j <= utsz; ++j) { + if (j == utsz && j > 0) { + break; + } + if (j == utsz) { + head = query; + } + else { + head = r.get_tail(j); + } + new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + result->add_rule(new_rule); + } + } + TRACE("dl", result->display(tout);); + return result; + } + +}; diff --git a/src/muz_qe/dl_mk_backwards.h b/src/muz_qe/dl_mk_backwards.h new file mode 100644 index 000000000..4e546c848 --- /dev/null +++ b/src/muz_qe/dl_mk_backwards.h @@ -0,0 +1,38 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_backwards.h + +Abstract: + + Create Horn clauses for backwards flow. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-04-17 + +Revision History: + +--*/ +#ifndef _DL_MK_BACKWARDS_H_ +#define _DL_MK_BACKWARDS_H_ + +#include"dl_rule_transformer.h" + +namespace datalog { + + class mk_backwards : public rule_transformer::plugin { + ast_manager& m; + context& m_ctx; + public: + mk_backwards(context & ctx, unsigned priority = 33000); + ~mk_backwards(); + rule_set * operator()(rule_set const & source); + }; + +}; + +#endif /* _DL_MK_BACKWARDS_H_ */ + From f40df22ccc6d66895bca326ec5056d67809c48a0 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 30 Apr 2013 10:29:41 -0700 Subject: [PATCH 120/281] enable COI transformation in datalog mode Signed-off-by: Nuno Lopes --- src/muz_qe/dl_context.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 0099b16f9..dfcaac791 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -814,6 +814,7 @@ namespace datalog { void context::transform_rules() { m_transf.reset(); + m_transf.register_plugin(alloc(mk_coi_filter, *this)); m_transf.register_plugin(alloc(mk_filter_rules, *this)); m_transf.register_plugin(alloc(mk_simple_joins, *this)); if (unbound_compressor()) { From 21b0a4fcbbe1a77eb6c54203114aee761b710cbe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Apr 2013 11:53:10 -0700 Subject: [PATCH 121/281] testing utvpi Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_context.cpp | 17 +++- src/muz_qe/pdr_context.h | 2 +- src/muz_qe/pdr_farkas_learner.cpp | 3 + src/muz_qe/pdr_prop_solver.cpp | 44 +++++----- src/smt/theory_utvpi.cpp | 1 + src/smt/theory_utvpi.h | 10 ++- src/smt/theory_utvpi_def.h | 132 +++++++++++++++++++++++++++--- 7 files changed, 176 insertions(+), 33 deletions(-) diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 62b119538..df95b1f26 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -597,7 +597,7 @@ namespace pdr { expr_ref fml = pm.mk_and(conj); th_rewriter rw(m); rw(fml); - if (ctx.is_dl()) { + if (ctx.is_dl() || ctx.is_utvpi()) { hoist_non_bool_if(fml); } TRACE("pdr", tout << mk_pp(fml, m) << "\n";); @@ -1359,9 +1359,10 @@ namespace pdr { bool m_is_bool_arith; bool m_has_arith; bool m_is_dl; + bool m_is_utvpi; public: classifier_proc(ast_manager& m, datalog::rule_set& rules): - m(m), a(m), m_is_bool(true), m_is_bool_arith(true), m_has_arith(false), m_is_dl(false) { + m(m), a(m), m_is_bool(true), m_is_bool_arith(true), m_has_arith(false), m_is_dl(false), m_is_utvpi(false) { classify(rules); } void operator()(expr* e) { @@ -1407,6 +1408,7 @@ namespace pdr { bool is_dl() const { return m_is_dl; } + bool is_utvpi() const { return m_is_utvpi; } private: @@ -1427,6 +1429,7 @@ namespace pdr { mark.reset(); m_is_dl = false; + m_is_utvpi = false; if (m_has_arith) { ptr_vector forms; for (it = rules.begin(); it != end; ++it) { @@ -1438,6 +1441,11 @@ namespace pdr { } } m_is_dl = is_difference_logic(m, forms.size(), forms.c_ptr()); +#if 0 + if (!m_is_dl) { + m_is_utvpi = is_utvpi_logic(m, forms.size(), forms.c_ptr()); + } +#endif } } @@ -1561,6 +1569,11 @@ namespace pdr { m_fparams.m_arith_mode = AS_DIFF_LOGIC; m_fparams.m_arith_expand_eqs = true; } + else if (classify.is_utvpi()) { + IF_VERBOSE(1, verbose_stream() << "UTVPI\n";); + m_fparams.m_arith_mode = AS_UTVPI; + m_fparams.m_arith_expand_eqs = true; + } } if (!use_mc && m_params.use_inductive_generalizer()) { m_core_generalizers.push_back(alloc(core_bool_inductive_generalizer, *this, 0)); diff --git a/src/muz_qe/pdr_context.h b/src/muz_qe/pdr_context.h index b5652d1b6..1785991c6 100644 --- a/src/muz_qe/pdr_context.h +++ b/src/muz_qe/pdr_context.h @@ -367,7 +367,7 @@ namespace pdr { expr_ref get_answer(); bool is_dl() const { return m_fparams.m_arith_mode == AS_DIFF_LOGIC; } - + bool is_utvpi() const { return m_fparams.m_arith_mode == AS_UTVPI; } void collect_statistics(statistics& st) const; void reset_statistics(); diff --git a/src/muz_qe/pdr_farkas_learner.cpp b/src/muz_qe/pdr_farkas_learner.cpp index 393090299..71404ab12 100644 --- a/src/muz_qe/pdr_farkas_learner.cpp +++ b/src/muz_qe/pdr_farkas_learner.cpp @@ -216,6 +216,9 @@ namespace pdr { } res = m.mk_not(res); th_rewriter rw(m); + params_ref params; + params.set_bool("gcd_rounding", true); + rw.updt_params(params); proof_ref pr(m); expr_ref tmp(m); rw(res, tmp, pr); diff --git a/src/muz_qe/pdr_prop_solver.cpp b/src/muz_qe/pdr_prop_solver.cpp index 863e5c03e..f69af93e9 100644 --- a/src/muz_qe/pdr_prop_solver.cpp +++ b/src/muz_qe/pdr_prop_solver.cpp @@ -383,26 +383,32 @@ namespace pdr { fl.get_lemmas(pr, bs, lemmas); safe.elim_proxies(lemmas); fl.simplify_lemmas(lemmas); // redundant? - if (m_fparams.m_arith_mode == AS_DIFF_LOGIC && - !is_difference_logic(m, lemmas.size(), lemmas.c_ptr())) { - IF_VERBOSE(1, - verbose_stream() << "not diff\n"; - for (unsigned i = 0; i < lemmas.size(); ++i) { - verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n"; - }); - extract_subset_core(safe); - return; + + bool outside_of_logic = + (m_fparams.m_arith_mode == AS_DIFF_LOGIC && + !is_difference_logic(m, lemmas.size(), lemmas.c_ptr())) || + (m_fparams.m_arith_mode == AS_UTVPI && + !is_utvpi_logic(m, lemmas.size(), lemmas.c_ptr())); + + if (outside_of_logic) { + IF_VERBOSE(1, + verbose_stream() << "not diff\n"; + for (unsigned i = 0; i < lemmas.size(); ++i) { + verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n"; + }); + extract_subset_core(safe); + } + else { + + IF_VERBOSE(2, + verbose_stream() << "Lemmas\n"; + for (unsigned i = 0; i < lemmas.size(); ++i) { + verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n"; + }); + + m_core->reset(); + m_core->append(lemmas); } - - - IF_VERBOSE(2, - verbose_stream() << "Lemmas\n"; - for (unsigned i = 0; i < lemmas.size(); ++i) { - verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n"; - }); - - m_core->reset(); - m_core->append(lemmas); } lbool prop_solver::check_assumptions(const expr_ref_vector & atoms) { diff --git a/src/smt/theory_utvpi.cpp b/src/smt/theory_utvpi.cpp index e811257a6..c45cfe74a 100644 --- a/src/smt/theory_utvpi.cpp +++ b/src/smt/theory_utvpi.cpp @@ -70,6 +70,7 @@ namespace smt { } vector > const& utvpi_tester::get_linearization() const { + SASSERT(m_terms.size() <= 2); return m_terms; } diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index 044fa11a0..40a837136 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -196,7 +196,7 @@ namespace smt { virtual bool internalize_term(app * term); - virtual void internalize_eq_eh(app * atom, bool_var v) {} + virtual void internalize_eq_eh(app * atom, bool_var v); virtual void assign_eh(bool_var v, bool is_true); @@ -258,6 +258,14 @@ namespace smt { private: + rational mk_value(theory_var v); + + void validate_model(); + + bool eval(expr* e); + + rational eval_num(expr* e); + bool check_z_consistency(); virtual void new_eq_eh(th_var v1, th_var v2, justification& j) { diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index c369d6826..97e00c54f 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -228,7 +228,10 @@ namespace smt { template void theory_utvpi::found_non_utvpi_expr(expr* n) { if (!m_non_utvpi_exprs) { - TRACE("utvpi", tout << "found non horn logic expression:\n" << mk_pp(n, get_manager()) << "\n";); + std::stringstream msg; + msg << "found non utvpi logic expression:\n" << mk_pp(n, get_manager()) << "\n"; + TRACE("utvpi", tout << msg.str();); + warning_msg(msg.str().c_str()); get_context().push_trail(value_trail(m_non_utvpi_exprs)); m_non_utvpi_exprs = true; } @@ -277,6 +280,24 @@ namespace smt { } } + template + void theory_utvpi::internalize_eq_eh(app * atom, bool_var v) { + context & ctx = get_context(); + app * lhs = to_app(atom->get_arg(0)); + app * rhs = to_app(atom->get_arg(1)); + if (a.is_numeral(rhs)) { + std::swap(rhs, lhs); + } + if (!a.is_numeral(rhs)) { + return; + } + if (a.is_add(lhs) || a.is_sub(lhs)) { + // force axioms for (= (+ x y) k) + // this is necessary because (+ x y) is not expressible as a utvpi term. + m_arith_eq_adapter.mk_axioms(ctx.get_enode(lhs), ctx.get_enode(rhs)); + } + } + template bool theory_utvpi::internalize_atom(app * n, bool) { context & ctx = get_context(); @@ -291,7 +312,7 @@ namespace smt { } bool is_strict = a.is_gt(n) || a.is_lt(n); - bool cl = m_test.linearize(e1, e2); + bool cl = m_test.linearize(e1, e2); if (!cl) { found_non_utvpi_expr(n); return false; @@ -324,8 +345,6 @@ namespace smt { bool theory_utvpi::internalize_term(app * term) { bool result = null_theory_var != mk_term(term); CTRACE("utvpi", !result, tout << "Did not internalize " << mk_pp(term, get_manager()) << "\n";); - TRACE("utvpi", tout << "Terms may not be internalized " << mk_pp(term, get_manager()) << "\n";); - found_non_utvpi_expr(term); return result; } @@ -478,6 +497,7 @@ namespace smt { template theory_var theory_utvpi::mk_term(app* n) { + TRACE("utvpi", tout << mk_pp(n, get_manager()) << "\n";); context& ctx = get_context(); bool cl = m_test.linearize(n); @@ -485,7 +505,7 @@ namespace smt { found_non_utvpi_expr(n); return null_theory_var; } - + coeffs coeffs; rational w; mk_coeffs(m_test.get_linearization(), coeffs, w); @@ -495,7 +515,14 @@ namespace smt { if (coeffs.size() == 1 && coeffs[0].second.is_one()) { return coeffs[0].first; } - th_var target = mk_var(ctx.mk_enode(n, false, false, true)); + if (coeffs.size() == 2) { + // do not create an alias. + return null_theory_var; + } + for (unsigned i = 0; i < n->get_num_args(); ++i) { + mk_term(to_app(n->get_arg(i))); + } + th_var target = mk_var(ctx.mk_enode(n, false, false, true)); coeffs.push_back(std::make_pair(target, rational(-1))); VERIFY(enable_edge(add_ineq(coeffs, numeral(w), null_literal))); @@ -520,7 +547,7 @@ namespace smt { v = mk_var(ctx.mk_enode(n, false, false, true)); // v = k: v <= k k <= v coeffs coeffs; - coeffs.push_back(std::make_pair(v, rational(1))); + coeffs.push_back(std::make_pair(v, rational(-1))); VERIFY(enable_edge(add_ineq(coeffs, numeral(r), null_literal))); coeffs.back().second.neg(); VERIFY(enable_edge(add_ineq(coeffs, numeral(-r), null_literal))); @@ -633,17 +660,102 @@ namespace smt { m.register_factory(m_factory); // TBD: enforce strong or tight coherence? compute_delta(); + DEBUG_CODE(validate_model();); } - + template - model_value_proc * theory_utvpi::mk_value(enode * n, model_generator & mg) { - theory_var v = n->get_th_var(get_id()); + void theory_utvpi::validate_model() { + context& ctx = get_context(); + unsigned sz = m_atoms.size(); + for (unsigned i = 0; i < sz; ++i) { + bool_var b = m_atoms[i].get_bool_var(); + bool ok = true; + expr* e = ctx.bool_var2expr(b); + switch(ctx.get_assignment(b)) { + case l_true: + ok = eval(e); + break; + case l_false: + ok = !eval(e); + break; + default: + break; + } + CTRACE("utvpi", !ok, tout << "validation failed: " << mk_pp(e, get_manager()) << "\n";); + } + } + + template + bool theory_utvpi::eval(expr* e) { + expr* e1, *e2; + if (a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) { + return eval_num(e1) <= eval_num(e2); + } + if (a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) { + return eval_num(e1) < eval_num(e2); + } + if (get_manager().is_eq(e, e1, e2)) { + return eval_num(e1) == eval_num(e2); + } + TRACE("utvpi", tout << "expression not handled: " << mk_pp(e, get_manager()) << "\n";); + return false; + } + + template + rational theory_utvpi::eval_num(expr* e) { + rational r; + expr* e1, *e2; + if (a.is_numeral(e, r)) { + return r; + } + if (a.is_sub(e, e1, e2)) { + return eval_num(e1) - eval_num(e2); + } + if (a.is_add(e)) { + r.reset(); + for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { + r += eval_num(to_app(e)->get_arg(i)); + } + return r; + } + if (a.is_mul(e)) { + r = rational(1); + for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { + r *= eval_num(to_app(e)->get_arg(i)); + } + return r; + } + if (a.is_uminus(e, e1)) { + return -eval_num(e1); + } + if (a.is_to_real(e, e1)) { + return eval_num(e1); + } + if (is_uninterp_const(e)) { + return mk_value(mk_var(e)); + } + TRACE("utvpi", tout << "expression not handled: " << mk_pp(e, get_manager()) << "\n";); + UNREACHABLE(); + return rational(0); + } + + + template + rational theory_utvpi::mk_value(th_var v) { SASSERT(v != null_theory_var); numeral val1 = m_graph.get_assignment(to_var(v)); numeral val2 = m_graph.get_assignment(neg(to_var(v))); numeral val = val1 - val2; rational num = val.get_rational() + (m_delta * val.get_infinitesimal().to_rational()); num = num/rational(2); + return num; + } + + template + model_value_proc * theory_utvpi::mk_value(enode * n, model_generator & mg) { + theory_var v = n->get_th_var(get_id()); + rational num = mk_value(v); + num = ceil(num); TRACE("utvpi", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";); return alloc(expr_wrapper_proc, m_factory->mk_value(num, a.is_int(n->get_owner()))); } From b4d0216728dc3fdaa7f22ccf510e0b8652d4007b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Apr 2013 13:06:59 -0700 Subject: [PATCH 122/281] try to fix gcc build Signed-off-by: Nikolaj Bjorner --- src/smt/theory_horn_ineq_def.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/smt/theory_horn_ineq_def.h b/src/smt/theory_horn_ineq_def.h index 1fc51a86c..0b32c2c8d 100644 --- a/src/smt/theory_horn_ineq_def.h +++ b/src/smt/theory_horn_ineq_def.h @@ -797,10 +797,10 @@ namespace smt { template typename theory_horn_ineq::numeral theory_horn_ineq::mk_weight(bool is_real, bool is_strict, rational const& w) const { if (is_strict) { - return numeral(inf_numeral(w)) + (is_real?m_epsilon:numeral(1)); + return numeral(Ext::inf_numeral(w)) + (is_real?Ext::m_epsilon:numeral(1)); } else { - return numeral(inf_numeral(w)); + return numeral(Ext::inf_numeral(w)); } } @@ -1001,9 +1001,9 @@ namespace smt { th_var target = mk_var(ctx.mk_enode(n, false, false, true)); coeffs.push_back(std::make_pair(target, rational(-1))); - VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(w)), null_literal))); + VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(Ext::inf_numeral(w)), null_literal))); negate(coeffs, w); - VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(w)), null_literal))); + VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(Ext::inf_numeral(w)), null_literal))); return target; } @@ -1024,9 +1024,9 @@ namespace smt { // v = k: v <= k k <= v coeffs coeffs; coeffs.push_back(std::make_pair(v, rational(1))); - VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(r)), null_literal))); + VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(Ext::inf_numeral(r)), null_literal))); coeffs.back().second.neg(); - VERIFY (m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(-r)), null_literal))); + VERIFY (m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(Ext::inf_numeral(-r)), null_literal))); } return v; } From 7cb9e7381df1045a7859bf747b62ff62e080ed56 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 May 2013 02:35:57 -0700 Subject: [PATCH 123/281] fix build errors on ubuntu and gcc Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_rule.cpp | 4 ++-- src/muz_qe/fixedpoint_params.pyg | 1 + src/muz_qe/hnf.cpp | 1 + src/muz_qe/pdr_context.cpp | 16 ++++++---------- src/muz_qe/pdr_prop_solver.cpp | 2 +- src/muz_qe/pdr_util.cpp | 6 +++++- src/smt/diff_logic.h | 7 ------- src/smt/theory_diff_logic.h | 3 +-- src/smt/theory_diff_logic_def.h | 7 +------ src/smt/theory_horn_ineq.h | 1 + src/smt/theory_horn_ineq_def.h | 12 ++++++------ src/smt/theory_utvpi.h | 5 +---- src/smt/theory_utvpi_def.h | 16 ++++++++++++---- 13 files changed, 38 insertions(+), 43 deletions(-) diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index db8189c64..ac683eca9 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -85,8 +85,6 @@ namespace datalog { return BR_FAILED; } - template class rewriter_tpl; - void rule_manager::remove_labels(expr_ref& fml, proof_ref& pr) { expr_ref tmp(m); @@ -1121,3 +1119,5 @@ namespace datalog { }; +template class rewriter_tpl; + diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index 774559cdb..c516806a6 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -60,6 +60,7 @@ def_module_params('fixedpoint', ('print_answer', BOOL, False, 'print answer instance(s) to query'), ('print_certificate', BOOL, False, 'print certificate for reachability or non-reachability'), ('print_statistics', BOOL, False, 'print statistics'), + ('use_utvpi', BOOL, False, 'experimental use UTVPI strategy'), ('tab_selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), )) diff --git a/src/muz_qe/hnf.cpp b/src/muz_qe/hnf.cpp index 764d31bb6..bcc3501de 100644 --- a/src/muz_qe/hnf.cpp +++ b/src/muz_qe/hnf.cpp @@ -186,6 +186,7 @@ private: void mk_horn(expr_ref& fml, proof_ref& premise) { + SASSERT(!premise || fml == m.get_fact(premise)); expr* e1, *e2; expr_ref fml0(m), fml1(m), fml2(m), head(m); proof_ref p(m); diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index df95b1f26..dcfbcca2b 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1441,11 +1441,7 @@ namespace pdr { } } m_is_dl = is_difference_logic(m, forms.size(), forms.c_ptr()); -#if 0 - if (!m_is_dl) { - m_is_utvpi = is_utvpi_logic(m, forms.size(), forms.c_ptr()); - } -#endif + m_is_utvpi = m_is_dl || is_utvpi_logic(m, forms.size(), forms.c_ptr()); } } @@ -1565,15 +1561,15 @@ namespace pdr { m_fparams.m_arith_auto_config_simplex = true; m_fparams.m_arith_propagate_eqs = false; m_fparams.m_arith_eager_eq_axioms = false; - if (classify.is_dl()) { - m_fparams.m_arith_mode = AS_DIFF_LOGIC; - m_fparams.m_arith_expand_eqs = true; - } - else if (classify.is_utvpi()) { + if (classify.is_utvpi() && m_params.use_utvpi()) { IF_VERBOSE(1, verbose_stream() << "UTVPI\n";); m_fparams.m_arith_mode = AS_UTVPI; m_fparams.m_arith_expand_eqs = true; } + else if (classify.is_dl()) { + m_fparams.m_arith_mode = AS_DIFF_LOGIC; + m_fparams.m_arith_expand_eqs = true; + } } if (!use_mc && m_params.use_inductive_generalizer()) { m_core_generalizers.push_back(alloc(core_bool_inductive_generalizer, *this, 0)); diff --git a/src/muz_qe/pdr_prop_solver.cpp b/src/muz_qe/pdr_prop_solver.cpp index f69af93e9..e3cd0d9c5 100644 --- a/src/muz_qe/pdr_prop_solver.cpp +++ b/src/muz_qe/pdr_prop_solver.cpp @@ -391,7 +391,7 @@ namespace pdr { !is_utvpi_logic(m, lemmas.size(), lemmas.c_ptr())); if (outside_of_logic) { - IF_VERBOSE(1, + IF_VERBOSE(2, verbose_stream() << "not diff\n"; for (unsigned i = 0; i < lemmas.size(); ++i) { verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n"; diff --git a/src/muz_qe/pdr_util.cpp b/src/muz_qe/pdr_util.cpp index 62185f1d2..9711cffc2 100644 --- a/src/muz_qe/pdr_util.cpp +++ b/src/muz_qe/pdr_util.cpp @@ -1248,7 +1248,11 @@ namespace pdr { } if (!m_is_dl) { - IF_VERBOSE(1, verbose_stream() << "non-diff: " << mk_pp(e, m) << "\n";); + char const* msg = "non-diff: "; + if (m_test_for_utvpi) { + msg = "non-utvpi: "; + } + IF_VERBOSE(1, verbose_stream() << msg << mk_pp(e, m) << "\n";); } } diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index b32a74c2c..f6576a41f 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -264,13 +264,6 @@ class dl_graph { m_assignment[e.get_target()] - m_assignment[e.get_source()] <= e.get_weight(); } - bool is_tight(edge_id e) const { - edge const& edge = m_edges[e]; - return edge.is_enabled() && - m_assignment[edge.get_target()] - m_assignment[e.get_source()] == e.get_weight(); - } - - public: // An assignment is feasible if all edges are feasible. bool is_feasible() const { diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 3bfd33b1e..7302ccfd4 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -46,7 +46,6 @@ namespace smt { unsigned m_num_conflicts; unsigned m_num_assertions; unsigned m_num_th2core_eqs; - unsigned m_num_th2core_prop; unsigned m_num_core2th_eqs; unsigned m_num_core2th_diseqs; @@ -260,7 +259,7 @@ namespace smt { m_arith_eq_adapter.restart_eh(); } - virtual void relevant_eh(app* e); + virtual void relevant_eh(app* e) {} virtual void init_search_eh() { m_arith_eq_adapter.init_search_eh(); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 362962620..20448dc74 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -310,9 +310,9 @@ void theory_diff_logic::assign_eh(bool_var v, bool is_true) { template void theory_diff_logic::collect_statistics(::statistics & st) const { st.update("dl conflicts", m_stats.m_num_conflicts); - st.update("dl propagations", m_stats.m_num_th2core_prop); st.update("dl asserts", m_stats.m_num_assertions); st.update("core->dl eqs", m_stats.m_num_core2th_eqs); + st.update("core->dl diseqs", m_stats.m_num_core2th_diseqs); m_arith_eq_adapter.collect_statistics(st); m_graph.collect_statistics(st); } @@ -598,7 +598,6 @@ void theory_diff_logic::set_neg_cycle_conflict() { literal_vector const& lits = m_nc_functor.get_lits(); context & ctx = get_context(); TRACE("arith_conflict", - //display(tout); tout << "conflict: "; for (unsigned i = 0; i < lits.size(); ++i) { ctx.display_literal_info(tout, lits[i]); @@ -971,10 +970,6 @@ void theory_diff_logic::new_diseq_eh(theory_var v1, theory_var v2) { } -template -void theory_diff_logic::relevant_eh(app* e) { -} - struct imp_functor { conflict_resolution & m_cr; diff --git a/src/smt/theory_horn_ineq.h b/src/smt/theory_horn_ineq.h index 441e46a18..fac6e96df 100644 --- a/src/smt/theory_horn_ineq.h +++ b/src/smt/theory_horn_ineq.h @@ -85,6 +85,7 @@ namespace smt { class theory_horn_ineq : public theory, private Ext { typedef typename Ext::numeral numeral; + typedef typename Ext::inf_numeral inf_numeral; typedef literal explanation; typedef theory_var th_var; typedef svector th_var_vector; diff --git a/src/smt/theory_horn_ineq_def.h b/src/smt/theory_horn_ineq_def.h index 0b32c2c8d..505815b4f 100644 --- a/src/smt/theory_horn_ineq_def.h +++ b/src/smt/theory_horn_ineq_def.h @@ -797,10 +797,10 @@ namespace smt { template typename theory_horn_ineq::numeral theory_horn_ineq::mk_weight(bool is_real, bool is_strict, rational const& w) const { if (is_strict) { - return numeral(Ext::inf_numeral(w)) + (is_real?Ext::m_epsilon:numeral(1)); + return numeral(inf_numeral(w)) + (is_real?Ext::m_epsilon:numeral(1)); } else { - return numeral(Ext::inf_numeral(w)); + return numeral(inf_numeral(w)); } } @@ -1001,9 +1001,9 @@ namespace smt { th_var target = mk_var(ctx.mk_enode(n, false, false, true)); coeffs.push_back(std::make_pair(target, rational(-1))); - VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(Ext::inf_numeral(w)), null_literal))); + VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(w)), null_literal))); negate(coeffs, w); - VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(Ext::inf_numeral(w)), null_literal))); + VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(w)), null_literal))); return target; } @@ -1024,9 +1024,9 @@ namespace smt { // v = k: v <= k k <= v coeffs coeffs; coeffs.push_back(std::make_pair(v, rational(1))); - VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(Ext::inf_numeral(r)), null_literal))); + VERIFY(m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(r)), null_literal))); coeffs.back().second.neg(); - VERIFY (m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(Ext::inf_numeral(-r)), null_literal))); + VERIFY (m_graph->enable_clause(m_graph->add_ineq(coeffs, numeral(inf_numeral(-r)), null_literal))); } return v; } diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index 40a837136..8b19bdab8 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -201,6 +201,7 @@ namespace smt { virtual void assign_eh(bool_var v, bool is_true); virtual void new_eq_eh(th_var v1, th_var v2) { + m_stats.m_num_core2th_eqs++; m_arith_eq_adapter.new_eq_eh(v1, v2); } @@ -322,10 +323,6 @@ namespace smt { return v | 0x1; } - th_var not(th_var v) const { - return v ^ 0x1; - } - }; diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index 97e00c54f..905270a46 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -264,7 +264,7 @@ namespace smt { template typename theory_utvpi::numeral theory_utvpi::mk_weight(bool is_real, bool is_strict, rational const& w) const { if (is_strict) { - return numeral(w) + (is_real?m_epsilon:numeral(1)); + return numeral(w) + (is_real?Ext::m_epsilon:numeral(1)); } else { return numeral(w); @@ -435,6 +435,7 @@ namespace smt { m_nc_functor.reset(); VERIFY(m_graph.find_shortest_zero_edge_path(v1, v2, UINT_MAX, m_nc_functor)); VERIFY(m_graph.find_shortest_zero_edge_path(v2, v1, UINT_MAX, m_nc_functor)); + IF_VERBOSE(1, verbose_stream() << "parity conflict " << mk_pp(e->get_owner(), get_manager()) << "\n";); set_conflict(); return false; @@ -453,7 +454,9 @@ namespace smt { template void theory_utvpi::collect_statistics(::statistics& st) const { st.update("utvpi conflicts", m_stats.m_num_conflicts); - st.update("utvpi assignments", m_stats.m_num_assertions); + st.update("utvpi asserts", m_stats.m_num_assertions); + st.update("core->utvpi eqs", m_stats.m_num_core2th_eqs); + st.update("core->utvpi diseqs", m_stats.m_num_core2th_diseqs); m_arith_eq_adapter.collect_statistics(st); m_graph.collect_statistics(st); } @@ -669,6 +672,9 @@ namespace smt { unsigned sz = m_atoms.size(); for (unsigned i = 0; i < sz; ++i) { bool_var b = m_atoms[i].get_bool_var(); + if (!ctx.is_relevant(b)) { + continue; + } bool ok = true; expr* e = ctx.bool_var2expr(b); switch(ctx.get_assignment(b)) { @@ -681,7 +687,9 @@ namespace smt { default: break; } - CTRACE("utvpi", !ok, tout << "validation failed: " << mk_pp(e, get_manager()) << "\n";); + CTRACE("utvpi", !ok, tout << "validation failed: " << mk_pp(e, get_manager()) << "\n";); + // CTRACE("utvpi", ok, tout << "validation success: " << mk_pp(e, get_manager()) << "\n";); + SASSERT(ok); } } @@ -748,6 +756,7 @@ namespace smt { numeral val = val1 - val2; rational num = val.get_rational() + (m_delta * val.get_infinitesimal().to_rational()); num = num/rational(2); + num = floor(num); return num; } @@ -755,7 +764,6 @@ namespace smt { model_value_proc * theory_utvpi::mk_value(enode * n, model_generator & mg) { theory_var v = n->get_th_var(get_id()); rational num = mk_value(v); - num = ceil(num); TRACE("utvpi", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";); return alloc(expr_wrapper_proc, m_factory->mk_value(num, a.is_int(n->get_owner()))); } From 65af658fd7c3302a876621cec028d27089e7f285 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 1 May 2013 14:08:53 +0100 Subject: [PATCH 124/281] FPA: min/max special cases fixed. Signed-off-by: Christoph M. Wintersteiger --- src/ast/rewriter/float_rewriter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 70ba09581..b43f07b65 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -242,13 +242,13 @@ br_status float_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) { return BR_DONE; } // expand as using ite's - result = m().mk_ite(mk_eq_nan(arg1), + result = m().mk_ite(m().mk_or(mk_eq_nan(arg1), m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2))), arg2, m().mk_ite(mk_eq_nan(arg2), arg1, m().mk_ite(m_util.mk_lt(arg1, arg2), - arg1, - arg2))); + arg1, + arg2))); return BR_REWRITE_FULL; } @@ -262,7 +262,7 @@ br_status float_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) { return BR_DONE; } // expand as using ite's - result = m().mk_ite(mk_eq_nan(arg1), + result = m().mk_ite(m().mk_or(mk_eq_nan(arg1), m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2))), arg2, m().mk_ite(mk_eq_nan(arg2), arg1, From e50a9e8dbfabdc7678c753d2a21796756d61a12c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 1 May 2013 14:10:50 +0100 Subject: [PATCH 125/281] MPF: fused-mul-add fixes. Sometimes this is still off by a bit. Signed-off-by: Christoph M. Wintersteiger --- src/util/mpf.cpp | 211 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 184 insertions(+), 27 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index dfac97626..def9f4fd5 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -453,16 +453,14 @@ bool mpf_manager::lt(mpf const & x, mpf const & y) { else if (sgn(x)) { if (!sgn(y)) return true; - else - // CMW: Problem with denormal numbers? + else return exp(y) < exp(x) || (exp(y) == exp(x) && m_mpz_manager.lt(sig(y), sig(x))); } else { // !sgn(x) if (sgn(y)) return false; - else - // CMW: Problem with denormal numbers? + else return exp(x) < exp(y) || (exp(x)==exp(y) && m_mpz_manager.lt(sig(x), sig(y))); } @@ -545,7 +543,7 @@ void mpf_manager::add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mp b.get().sign = sgn_y; // Unpack a/b, this inserts the hidden bit and adjusts the exponent. - unpack(a, true); + unpack(a, false); unpack(b, false); if (exp(b) > exp(a)) @@ -556,25 +554,21 @@ void mpf_manager::add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mp SASSERT(exp(a) >= exp(b)); SASSERT(exp_delta >= 0); - mpf_exp_t u_delta = exp_delta; - if (u_delta > x.sbits+2) - u_delta = x.sbits+2; + if (exp_delta > x.sbits+2) + exp_delta = x.sbits+2; TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); TRACE("mpf_dbg", tout << "B = " << to_string(b) << std::endl;); - TRACE("mpf_dbg", tout << "d = " << u_delta << std::endl;); - - TRACE("mpf_dbg", tout << "UP A = " << to_string(a) << std::endl;); - TRACE("mpf_dbg", tout << "UP B = " << to_string(b) << std::endl;); + TRACE("mpf_dbg", tout << "d = " << exp_delta << std::endl;); // Introduce 3 extra bits into both numbers. m_mpz_manager.mul2k(a.significand(), 3, a.significand()); m_mpz_manager.mul2k(b.significand(), 3, b.significand()); // Alignment shift with sticky bit computation. - SASSERT(u_delta <= INT_MAX); + SASSERT(exp_delta <= INT_MAX); scoped_mpz sticky_rem(m_mpz_manager); - m_mpz_manager.machine_div_rem(b.significand(), m_powers2((int)u_delta), b.significand(), sticky_rem); + m_mpz_manager.machine_div_rem(b.significand(), m_powers2((int)exp_delta), b.significand(), sticky_rem); if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(b.significand())) m_mpz_manager.inc(b.significand()); @@ -582,7 +576,7 @@ void mpf_manager::add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mp TRACE("mpf_dbg", tout << "B' = " << m_mpz_manager.to_string(b.significand()) << std::endl;); // Significand addition - if (sgn(a) ^ sgn(b)) { + if (sgn(a) != sgn(b)) { TRACE("mpf_dbg", tout << "SUBTRACTING" << std::endl;); m_mpz_manager.sub(a.significand(), b.significand(), o.significand); } @@ -765,9 +759,167 @@ void mpf_manager::div(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & } void mpf_manager::fused_mul_add(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf const &z, mpf & o) { - // CMW: Is this precise enough? - mul(rm, x, y, o); - add(rm, o, z, o); + SASSERT(x.sbits == y.sbits && x.ebits == y.ebits && + x.sbits == y.sbits && z.ebits == z.ebits); + + TRACE("mpf_dbg", tout << "X = " << to_string(x) << std::endl;); + TRACE("mpf_dbg", tout << "Y = " << to_string(y) << std::endl;); + TRACE("mpf_dbg", tout << "Z = " << to_string(z) << std::endl;); + + if (is_nan(x) || is_nan(y) || is_nan(z)) + mk_nan(x.ebits, x.sbits, o); + else if (is_pinf(x)) { + if (is_zero(y)) + mk_nan(x.ebits, x.sbits, o); + else if (is_inf(z) && sgn(x) ^ sgn (y) ^ sgn(z)) + mk_nan(x.ebits, x.sbits, o); + else + mk_inf(x.ebits, x.sbits, y.sign, o); + } + else if (is_pinf(y)) { + if (is_zero(x)) + mk_nan(x.ebits, x.sbits, o); + else if (is_inf(z) && sgn(x) ^ sgn (y) ^ sgn(z)) + mk_nan(x.ebits, x.sbits, o); + else + mk_inf(x.ebits, x.sbits, x.sign, o); + } + else if (is_ninf(x)) { + if (is_zero(y)) + mk_nan(x.ebits, x.sbits, o); + else if (is_inf(z) && sgn(x) ^ sgn (y) ^ sgn(z)) + mk_nan(x.ebits, x.sbits, o); + else + mk_inf(x.ebits, x.sbits, !y.sign, o); + } + else if (is_ninf(y)) { + if (is_zero(x)) + mk_nan(x.ebits, x.sbits, o); + else if (is_inf(z) && sgn(x) ^ sgn (y) ^ sgn(z)) + mk_nan(x.ebits, x.sbits, o); + else + mk_inf(x.ebits, x.sbits, !x.sign, o); + } + else if (is_inf(z)) { + set(o, z); + } + else if (is_zero(x) || is_zero(y)) { + if (is_zero(z) && rm != MPF_ROUND_TOWARD_NEGATIVE) + mk_pzero(x.ebits, x.sbits, o); + else + set(o, z); + } + else { + o.ebits = x.ebits; + o.sbits = x.sbits; + + scoped_mpf mul_res(*this, x.ebits+2, 2*x.sbits); + scoped_mpf a(*this, x.ebits, x.sbits), b(*this, x.ebits, x.sbits), c(*this, x.ebits, x.sbits); + set(a, x); + set(b, y); + set(c, z); + unpack(a, true); + unpack(b, true); + unpack(c, true); + + TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); + TRACE("mpf_dbg", tout << "B = " << to_string(b) << std::endl;); + TRACE("mpf_dbg", tout << "C = " << to_string(c) << std::endl;); + + SASSERT(m_mpz_manager.lt(a.significand(), m_powers2(x.sbits))); + SASSERT(m_mpz_manager.lt(b.significand(), m_powers2(x.sbits))); + SASSERT(m_mpz_manager.lt(c.significand(), m_powers2(x.sbits))); + SASSERT(m_mpz_manager.ge(a.significand(), m_powers2(x.sbits-1))); + SASSERT(m_mpz_manager.ge(b.significand(), m_powers2(x.sbits-1))); + + mul_res.get().sign = (a.sign() != b.sign()); + mul_res.get().exponent = a.exponent() + b.exponent(); + m_mpz_manager.mul(a.significand(), b.significand(), mul_res.get().significand); + + TRACE("mpf_dbg", tout << "PRODUCT = " << to_string(mul_res) << std::endl;); + + // mul_res is [-1][0].[2*sbits - 2], i.e., between 2*sbits-1 and 2*sbits. + SASSERT(m_mpz_manager.lt(mul_res.significand(), m_powers2(2*x.sbits))); + SASSERT(m_mpz_manager.ge(mul_res.significand(), m_powers2(2*x.sbits - 2))); + + // Introduce extra bits into c. + m_mpz_manager.mul2k(c.significand(), x.sbits-1, c.significand()); + + SASSERT(m_mpz_manager.lt(c.significand(), m_powers2(2 * x.sbits - 1))); + SASSERT(m_mpz_manager.is_zero(c.significand()) || + m_mpz_manager.ge(c.significand(), m_powers2(2 * x.sbits - 2))); + + TRACE("mpf_dbg", tout << "C = " << to_string(c) << std::endl;); + + if (exp(c) > exp(mul_res)) + mul_res.swap(c); + + mpf_exp_t exp_delta = exp(mul_res) - exp(c); + + SASSERT(exp(mul_res) >= exp(c) && exp_delta >= 0); + + if (exp_delta > 2 * x.sbits) + exp_delta = 2 * x.sbits; + TRACE("mpf_dbg", tout << "exp_delta = " << exp_delta << std::endl;); + + // Alignment shift with sticky bit computation. + scoped_mpz sticky_rem(m_mpz_manager); + m_mpz_manager.machine_div_rem(c.significand(), m_powers2((int)exp_delta), c.significand(), sticky_rem); + TRACE("mpf_dbg", tout << "alignment shift -> sig = " << m_mpz_manager.to_string(c.significand()) << + " sticky_rem = " << m_mpz_manager.to_string(sticky_rem) << std::endl;); + if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(c.significand())) + m_mpz_manager.inc(c.significand()); + + TRACE("mpf_dbg", tout << "M' = " << m_mpz_manager.to_string(mul_res.significand()) << std::endl;); + TRACE("mpf_dbg", tout << "C' = " << m_mpz_manager.to_string(c.significand()) << std::endl;); + + // Significand addition + if (sgn(mul_res) != sgn(c)) { + TRACE("mpf_dbg", tout << "SUBTRACTING" << std::endl;); + m_mpz_manager.sub(mul_res.significand(), c.significand(), o.significand); + } + else { + TRACE("mpf_dbg", tout << "ADDING" << std::endl;); + m_mpz_manager.add(mul_res.significand(), c.significand(), o.significand); + } + + TRACE("mpf_dbg", tout << "sum[-1:] = " << m_mpz_manager.to_string(o.significand) << std::endl;); + + bool neg = m_mpz_manager.is_neg(o.significand); + TRACE("mpf_dbg", tout << "NEG=" << neg << std::endl;); + if (neg) m_mpz_manager.abs(o.significand); + + o.exponent = mul_res.exponent(); + + unsigned extra = x.sbits-4; + // Result could overflow into 4.xxx ... + SASSERT(m_mpz_manager.lt(o.significand, m_powers2(2 * x.sbits + 2))); + if(m_mpz_manager.ge(o.significand, m_powers2(2 * x.sbits + 1))) + { + extra++; + o.exponent++; + TRACE("mpf_dbg", tout << "Addition overflew!" << std::endl;); + } + + // Get rid of the extra bits. + m_mpz_manager.machine_div_rem(o.significand, m_powers2(extra), o.significand, sticky_rem); + if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(o.significand)) + m_mpz_manager.inc(o.significand); + + TRACE("mpf_dbg", tout << "sum[-1:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl;); + + if (m_mpz_manager.is_zero(o.significand)) + mk_zero(x.ebits, x.sbits, rm == MPF_ROUND_TOWARD_NEGATIVE, o); + else { + o.sign = ((!mul_res.sign() && c.sign() && neg) || + ( mul_res.sign() && !c.sign() && !neg) || + ( mul_res.sign() && c.sign())); + TRACE("mpf_dbg", tout << "before round = " << to_string(o) << std::endl << + "fs[-1:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl;); + round(rm, o); + } + } + } void my_mpz_sqrt(unsynch_mpz_manager & m, unsigned sbits, bool odd_exp, mpz & in, mpz & o) { @@ -938,8 +1090,8 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { mk_nan(x.ebits, x.sbits, o); else if (is_inf(y)) set(o, x); - else if (is_zero(x)) - mk_pzero(x.ebits, x.sbits, o); + else if (is_zero(x)) + set(o, x); else if (is_zero(y)) mk_nan(x.ebits, x.sbits, o); else { @@ -955,7 +1107,7 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); TRACE("mpf_dbg", tout << "B = " << to_string(b) << std::endl;); - + if (a.exponent() < b.exponent()) set(o, x); else { @@ -986,22 +1138,22 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { } void mpf_manager::maximum(mpf const & x, mpf const & y, mpf & o) { - if (is_nan(x)) + if (is_nan(x) || (is_zero(x) && is_zero(y))) set(o, y); else if (is_nan(y)) set(o, x); - else if (gt(x, y) || (is_zero(x) && is_nzero(y))) + else if (gt(x, y)) set(o, x); else set(o, y); } void mpf_manager::minimum(mpf const & x, mpf const & y, mpf & o) { - if (is_nan(x)) + if (is_nan(x) || (is_zero(x) && is_zero(y))) set(o, y); else if (is_nan(y)) set(o, x); - else if (lt(x, y) || (is_nzero(x) && is_zero(y))) + else if (lt(x, y)) set(o, x); else set(o, y); @@ -1340,6 +1492,11 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { TRACE("mpf_dbg", tout << "RND: " << to_string(o) << std::endl;); + DEBUG_CODE({ + const mpz & p_m3 = m_powers2(o.sbits+5); + SASSERT(m_mpz_manager.lt(o.significand, p_m3)); + }); + // Structure of the rounder: // (s, e_out, f_out) == (s, exprd(s, post(e, sigrd(s, f)))). @@ -1354,7 +1511,7 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { "e_max_norm = " << e_max_norm << std::endl;); const mpz & p_m1 = m_powers2(o.sbits+2); - const mpz & p_m2 = m_powers2(o.sbits+3); + const mpz & p_m2 = m_powers2(o.sbits+3); 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;); @@ -1530,7 +1687,7 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { TRACE("mpf_dbg", tout << "DENORMAL: " << m_mpz_manager.to_string(o.significand) << std::endl;); o.exponent = mk_bot_exp(o.ebits); } - } + } TRACE("mpf_dbg", tout << "ROUNDED = " << to_string(o) << std::endl;); } From 717f131942ed31caee5ef70e13db75a8f6dfe0c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 1 May 2013 19:54:40 +0100 Subject: [PATCH 126/281] fix warnings and errors from the mint64 build Signed-off-by: Nikolaj Bjorner --- src/muz_qe/hnf.cpp | 1 + src/smt/theory_diff_logic_def.h | 2 +- src/smt/theory_horn_ineq.h | 3 +-- src/smt/theory_horn_ineq_def.h | 2 ++ src/smt/theory_utvpi.h | 2 +- src/smt/theory_utvpi_def.h | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/muz_qe/hnf.cpp b/src/muz_qe/hnf.cpp index bcc3501de..75a85061c 100644 --- a/src/muz_qe/hnf.cpp +++ b/src/muz_qe/hnf.cpp @@ -201,6 +201,7 @@ private: if (!m_sorts.empty()) { proof* p1 = m.mk_pull_quant(fml, to_quantifier(fml1)); premise = mk_modus_ponens(premise, p1); + fml = fml1; } } head = fml0; diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index 20448dc74..390803957 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -558,7 +558,7 @@ void theory_diff_logic::new_edge(dl_var src, dl_var dst, unsigned num_edges lits.size(), lits.c_ptr(), params.size(), params.c_ptr()); } - clause* cls = ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); + ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0); if (dump_lemmas()) { char const * logic = m_is_lia ? "QF_LIA" : "QF_LRA"; ctx.display_lemma_as_smt_problem(lits.size(), lits.c_ptr(), false_literal, logic); diff --git a/src/smt/theory_horn_ineq.h b/src/smt/theory_horn_ineq.h index fac6e96df..ed96f25f6 100644 --- a/src/smt/theory_horn_ineq.h +++ b/src/smt/theory_horn_ineq.h @@ -91,7 +91,6 @@ namespace smt { typedef svector th_var_vector; typedef unsigned clause_id; typedef vector > coeffs; - static const clause_id null_clause_id = UINT_MAX; class clause; class graph; @@ -108,7 +107,7 @@ namespace smt { atom(bool_var bv, int pos, int neg) : m_bvar(bv), m_true(false), m_pos(pos), m_neg(neg) {} - virtual ~atom() {} + ~atom() {} bool_var get_bool_var() const { return m_bvar; } bool is_true() const { return m_true; } void assign_eh(bool is_true) { m_true = is_true; } diff --git a/src/smt/theory_horn_ineq_def.h b/src/smt/theory_horn_ineq_def.h index 505815b4f..f4fa7e8d7 100644 --- a/src/smt/theory_horn_ineq_def.h +++ b/src/smt/theory_horn_ineq_def.h @@ -27,6 +27,8 @@ Revision History: namespace smt { + static const unsigned null_clause_id = UINT_MAX; + /** A clause represents an inequality of the form diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index 8b19bdab8..9e8073ec2 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -78,7 +78,7 @@ namespace smt { atom(bool_var bv, int pos, int neg) : m_bvar(bv), m_true(false), m_pos(pos), m_neg(neg) {} - virtual ~atom() {} + ~atom() {} bool_var get_bool_var() const { return m_bvar; } void assign_eh(bool is_true) { m_true = is_true; } int get_asserted_edge() const { return this->m_true?m_pos:m_neg; } diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index 905270a46..af372ea50 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -54,8 +54,8 @@ namespace smt { m_arith_eq_adapter(*this, m_params, a), m_zero_int(null_theory_var), m_zero_real(null_theory_var), - m_asserted_qhead(0), m_nc_functor(*this), + m_asserted_qhead(0), m_agility(0.5), m_lia(false), m_lra(false), From 78db1d0f86c35b424522ea600b52f9604c2e1eae Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 1 May 2013 16:13:24 -0700 Subject: [PATCH 127/281] fix build of unit tests Signed-off-by: Nuno Lopes --- src/smt/diff_logic.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index f6576a41f..7216bba7e 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -21,6 +21,7 @@ Revision History: #include"vector.h" #include"heap.h" +#include"statistics.h" #include"trace.h" #include"warning.h" From 00d5dea9a5694aae8df2d9a78ae7fce04effd4af Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 2 May 2013 15:24:07 +0100 Subject: [PATCH 128/281] FPA: added support for rewriting quantified floats to quantified bit-vectors. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 14 +++++ src/tactic/fpa/fpa2bv_converter.h | 4 +- src/tactic/fpa/fpa2bv_rewriter.h | 84 +++++++++++++++++++++++++++-- 3 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 84a1efaff..2e2a270ee 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -150,6 +150,20 @@ void fpa2bv_converter::mk_const(func_decl * f, expr_ref & result) { } } +void fpa2bv_converter::mk_var(unsigned base_inx, sort * srt, expr_ref & result) { + SASSERT(is_float(srt)); + unsigned ebits = m_util.get_ebits(srt); + unsigned sbits = m_util.get_sbits(srt); + + expr_ref sgn(m), s(m), e(m); + + sgn = m.mk_var(base_inx, m_bv_util.mk_sort(1)); + s = m.mk_var(base_inx + 1, m_bv_util.mk_sort(sbits-1)); + e = m.mk_var(base_inx + 2, m_bv_util.mk_sort(ebits)); + + mk_triple(sgn, s, e, result); +} + void fpa2bv_converter::mk_rm_const(func_decl * f, expr_ref & result) { SASSERT(f->get_family_id() == null_family_id); diff --git a/src/tactic/fpa/fpa2bv_converter.h b/src/tactic/fpa/fpa2bv_converter.h index e5d546763..4ed794a7c 100644 --- a/src/tactic/fpa/fpa2bv_converter.h +++ b/src/tactic/fpa/fpa2bv_converter.h @@ -35,7 +35,7 @@ class fpa2bv_converter { ast_manager & m; basic_simplifier_plugin m_simp; float_util m_util; - mpf_manager & m_mpf_manager; + mpf_manager & m_mpf_manager; unsynch_mpz_manager & m_mpz_manager; bv_util m_bv_util; float_decl_plugin * m_plugin; @@ -48,6 +48,7 @@ public: ~fpa2bv_converter(); float_util & fu() { return m_util; } + bv_util & bu() { return m_bv_util; } bool is_float(sort * s) { return m_util.is_float(s); } bool is_float(expr * e) { return is_app(e) && m_util.is_float(to_app(e)->get_decl()->get_range()); } @@ -68,6 +69,7 @@ public: void mk_value(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_const(func_decl * f, expr_ref & result); void mk_rm_const(func_decl * f, expr_ref & result); + void mk_var(unsigned base_inx, sort * srt, expr_ref & result); void mk_plus_inf(func_decl * f, expr_ref & result); void mk_minus_inf(func_decl * f, expr_ref & result); diff --git a/src/tactic/fpa/fpa2bv_rewriter.h b/src/tactic/fpa/fpa2bv_rewriter.h index 4b3525a32..02b40840a 100644 --- a/src/tactic/fpa/fpa2bv_rewriter.h +++ b/src/tactic/fpa/fpa2bv_rewriter.h @@ -29,6 +29,8 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { ast_manager & m_manager; expr_ref_vector m_out; fpa2bv_converter & m_conv; + sort_ref_vector m_bindings; + expr_ref_vector m_mappings; unsigned long long m_max_memory; unsigned m_max_steps; @@ -38,7 +40,9 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c, params_ref const & p): m_manager(m), m_out(m), - m_conv(c) { + m_conv(c), + m_bindings(m), + m_mappings(m) { updt_params(p); // We need to make sure that the mananger has the BV plugin loaded. symbol s_bv("bv"); @@ -53,6 +57,9 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { m_out.finalize(); } + void reset() { + } + void updt_params(params_ref const & p) { m_max_memory = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX)); m_max_steps = p.get_uint("max_steps", UINT_MAX); @@ -140,17 +147,88 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { return BR_FAILED; } + bool pre_visit(expr * t) + { + if (is_quantifier(t)) { + quantifier * q = to_quantifier(t); + TRACE("fpa2bv", tout << "pre_visit [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m()) << std::endl;); + sort_ref_vector new_bindings(m_manager); + for (unsigned i = 0 ; i < q->get_num_decls(); i++) + new_bindings.push_back(q->get_decl_sort(i)); + SASSERT(new_bindings.size() == q->get_num_decls()); + m_bindings.append(new_bindings); + m_mappings.resize(m_bindings.size(), 0); + } + return true; + } + bool reduce_quantifier(quantifier * old_q, expr * new_body, expr * const * new_patterns, expr * const * new_no_patterns, expr_ref & result, proof_ref & result_pr) { - return false; + unsigned curr_sz = m_bindings.size(); + SASSERT(old_q->get_num_decls() <= curr_sz); + unsigned num_decls = old_q->get_num_decls(); + unsigned old_sz = curr_sz - num_decls; + string_buffer<> name_buffer; + ptr_buffer new_decl_sorts; + sbuffer new_decl_names; + for (unsigned i = 0; i < num_decls; i++) { + symbol const & n = old_q->get_decl_name(i); + sort * s = old_q->get_decl_sort(i); + if (m_conv.is_float(s)) { + unsigned ebits = m_conv.fu().get_ebits(s); + unsigned sbits = m_conv.fu().get_sbits(s); + name_buffer.reset(); + name_buffer << n << ".exp"; + new_decl_names.push_back(symbol(name_buffer.c_str())); + new_decl_sorts.push_back(m_conv.bu().mk_sort(ebits)); + name_buffer.reset(); + name_buffer << n << ".sig"; + new_decl_names.push_back(symbol(name_buffer.c_str())); + new_decl_sorts.push_back(m_conv.bu().mk_sort(sbits-1)); + name_buffer.reset(); + name_buffer << n << ".sgn"; + new_decl_names.push_back(symbol(name_buffer.c_str())); + new_decl_sorts.push_back(m_conv.bu().mk_sort(1)); + } + else { + new_decl_sorts.push_back(s); + new_decl_names.push_back(n); + } + } + result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(), + new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(), + old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns); + result_pr = 0; + m_bindings.shrink(old_sz); + m_mappings.shrink(old_sz); + TRACE("fpa2bv", tout << "reduce_quantifier[" << old_q->get_depth() << "]: " << + mk_ismt2_pp(old_q->get_expr(), m()) << std::endl << + " new body: " << mk_ismt2_pp(new_body, m()) << std::endl; + tout << "result = " << mk_ismt2_pp(result, m()) << std::endl;); + return true; } bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { - return false; + if (t->get_idx() >= m_bindings.size()) + return false; + unsigned inx = m_bindings.size() - t->get_idx() - 1; + if (m_mappings[inx] == 0) + { + unsigned shift = 0; + for (unsigned i = m_bindings.size() - 1; i > inx; i--) + if (m_conv.is_float(m_bindings[i].get())) shift += 2; + expr_ref new_var(m()); + m_conv.mk_var(t->get_idx() + shift, t->get_sort(), new_var); + m_mappings[inx] = new_var; + } + result = m_mappings[inx].get(); + result_pr = 0; + TRACE("fpa2bv", tout << "reduce_var: " << mk_ismt2_pp(t, m()) << " -> " << mk_ismt2_pp(result, m()) << std::endl;); + return true; } }; From 8f60a936d2b0f0f0a9f71f3c8339cd364e3d2750 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 3 May 2013 15:57:42 +0100 Subject: [PATCH 129/281] FPA: Added support for float-UF to BV-UF translation. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 98 ++++++++++++++++++++++++++++- src/tactic/fpa/fpa2bv_converter.h | 20 +++++- src/tactic/fpa/fpa2bv_rewriter.h | 22 ++++++- 3 files changed, 136 insertions(+), 4 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 2e2a270ee..acb41a2b1 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -38,6 +38,17 @@ fpa2bv_converter::fpa2bv_converter(ast_manager & m) : fpa2bv_converter::~fpa2bv_converter() { dec_ref_map_key_values(m, m_const2bv); dec_ref_map_key_values(m, m_rm_const2bv); + dec_ref_map_key_values(m, m_uf2bvuf); + + obj_map::iterator it = m_uf23bvuf.begin(); + obj_map::iterator end = m_uf23bvuf.end(); + for (; it != end; ++it) { + m.dec_ref(it->m_key); + m.dec_ref(it->m_value.f_sgn); + m.dec_ref(it->m_value.f_sig); + m.dec_ref(it->m_value.f_exp); + } + m_uf23bvuf.reset(); } void fpa2bv_converter::mk_eq(expr * a, expr * b, expr_ref & result) { @@ -164,6 +175,90 @@ void fpa2bv_converter::mk_var(unsigned base_inx, sort * srt, expr_ref & result) mk_triple(sgn, s, e, result); } +void fpa2bv_converter::mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result) +{ + TRACE("fpa2bv_dbg", 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, * sig, * exp; + split(args[i], sgn, sig, exp); + new_args.push_back(sgn); + new_args.push_back(sig); + new_args.push_back(exp); + } + else + new_args.push_back(args[i]); + + func_decl * fd; + func_decl_triple fd3; + if (m_uf2bvuf.find(f, fd)) { + result = m.mk_app(fd, new_args.size(), new_args.c_ptr()); + } + else if (m_uf23bvuf.find(f, fd3)) + { + expr_ref a_sgn(m), a_sig(m), a_exp(m); + a_sgn = m.mk_app(fd3.f_sgn, new_args.size(), new_args.c_ptr()); + a_sig = m.mk_app(fd3.f_sig, new_args.size(), new_args.c_ptr()); + a_exp = m.mk_app(fd3.f_exp, new_args.size(), new_args.c_ptr()); + mk_triple(a_sgn, a_sig, a_exp, result); + } + else { + sort_ref_buffer new_domain(m); + + for (unsigned i = 0; i < f->get_arity() ; i ++) + if (is_float(f->get_domain()[i])) + { + new_domain.push_back(m_bv_util.mk_sort(1)); + new_domain.push_back(m_bv_util.mk_sort(m_util.get_sbits(f->get_domain()[i])-1)); + new_domain.push_back(m_bv_util.mk_sort(m_util.get_ebits(f->get_domain()[i]))); + } + else + new_domain.push_back(f->get_domain()[i]); + + if (!is_float(f->get_range())) + { + func_decl * fbv = m.mk_func_decl(f->get_name(), new_domain.size(), new_domain.c_ptr(), f->get_range(), *f->get_info()); + TRACE("fpa2bv_dbg", 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); + result = m.mk_app(fbv, new_args.size(), new_args.c_ptr()); + } + else + { + string_buffer<> name_buffer; + name_buffer.reset(); name_buffer << f->get_name() << ".sgn"; + func_decl * f_sgn = m.mk_func_decl(symbol(name_buffer.c_str()), new_domain.size(), new_domain.c_ptr(), m_bv_util.mk_sort(1)); + name_buffer.reset(); name_buffer << f->get_name() << ".sig"; + func_decl * f_sig = m.mk_func_decl(symbol(name_buffer.c_str()), new_domain.size(), new_domain.c_ptr(), m_bv_util.mk_sort(m_util.get_sbits(f->get_range())-1)); + name_buffer.reset(); name_buffer << f->get_name() << ".exp"; + func_decl * f_exp = m.mk_func_decl(symbol(name_buffer.c_str()), new_domain.size(), new_domain.c_ptr(), m_bv_util.mk_sort(m_util.get_ebits(f->get_range()))); + expr_ref a_sgn(m), a_sig(m), a_exp(m); + a_sgn = m.mk_app(f_sgn, new_args.size(), new_args.c_ptr()); + a_sig = m.mk_app(f_sig, new_args.size(), new_args.c_ptr()); + a_exp = m.mk_app(f_exp, new_args.size(), new_args.c_ptr()); + TRACE("fpa2bv_dbg", tout << "New UF func_decls : " << std::endl; + tout << mk_ismt2_pp(f_sgn, m) << std::endl; + tout << mk_ismt2_pp(f_sig, m) << std::endl; + tout << mk_ismt2_pp(f_exp, m) << std::endl; ); + m_uf23bvuf.insert(f, func_decl_triple(f_sgn, f_sig, f_exp)); + m.inc_ref(f); + m.inc_ref(f_sgn); + m.inc_ref(f_sig); + m.inc_ref(f_exp); + mk_triple(a_sgn, a_sig, a_exp, result); + } + } + + TRACE("fpa2bv_dbg", tout << "UF result: " << mk_ismt2_pp(result, m) << std::endl; ); + + SASSERT(is_well_sorted(m, result)); +} void fpa2bv_converter::mk_rm_const(func_decl * f, expr_ref & result) { SASSERT(f->get_family_id() == null_family_id); @@ -1953,7 +2048,8 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef _DEBUG - // return; + return; + // CMW: This works only for quantifier-free formulas. expr_ref new_e(m); new_e = m.mk_fresh_const(prefix, m.get_sort(e)); extra_assertions.push_back(m.mk_eq(new_e, e)); diff --git a/src/tactic/fpa/fpa2bv_converter.h b/src/tactic/fpa/fpa2bv_converter.h index 4ed794a7c..f090e3e8d 100644 --- a/src/tactic/fpa/fpa2bv_converter.h +++ b/src/tactic/fpa/fpa2bv_converter.h @@ -42,6 +42,21 @@ class fpa2bv_converter { obj_map m_const2bv; obj_map m_rm_const2bv; + obj_map m_uf2bvuf; + + struct func_decl_triple { + func_decl_triple () { f_sgn = 0; f_sig = 0; f_exp = 0; } + func_decl_triple (func_decl * sgn, func_decl * sig, func_decl * exp) + { + f_sgn = sgn; + f_sig = sig; + f_exp = exp; + } + func_decl * f_sgn; + func_decl * f_sig; + func_decl * f_exp; + }; + obj_map m_uf23bvuf; public: fpa2bv_converter(ast_manager & m); @@ -67,8 +82,9 @@ public: void mk_rounding_mode(func_decl * f, expr_ref & result); void mk_value(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_const(func_decl * f, expr_ref & result); + void mk_const(func_decl * f, expr_ref & result); void mk_rm_const(func_decl * f, expr_ref & result); + void mk_uninterpreted_function(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_var(unsigned base_inx, sort * srt, expr_ref & result); void mk_plus_inf(func_decl * f, expr_ref & result); @@ -102,7 +118,7 @@ public: void mk_is_sign_minus(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_float(func_decl * f, unsigned num, expr * const * args, expr_ref & result); - void mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); obj_map const & const2bv() const { return m_const2bv; } obj_map const & rm_const2bv() const { return m_rm_const2bv; } diff --git a/src/tactic/fpa/fpa2bv_rewriter.h b/src/tactic/fpa/fpa2bv_rewriter.h index 02b40840a..aec00d30c 100644 --- a/src/tactic/fpa/fpa2bv_rewriter.h +++ b/src/tactic/fpa/fpa2bv_rewriter.h @@ -143,6 +143,23 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { throw tactic_exception("NYI"); } } + + if (f->get_family_id() == null_family_id) + { + bool is_float_uf = m_conv.is_float(f->get_range()); + unsigned i = 0; + while (!is_float_uf && i < num) + { + is_float_uf = m_conv.is_float(f->get_domain()[i]); + i++; + } + + if (is_float_uf) + { + m_conv.mk_uninterpreted_function(f, num, args, result); + return BR_DONE; + } + } return BR_FAILED; } @@ -222,7 +239,10 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { for (unsigned i = m_bindings.size() - 1; i > inx; i--) if (m_conv.is_float(m_bindings[i].get())) shift += 2; expr_ref new_var(m()); - m_conv.mk_var(t->get_idx() + shift, t->get_sort(), new_var); + if (m_conv.is_float(t->get_sort())) + m_conv.mk_var(t->get_idx() + shift, t->get_sort(), new_var); + else + new_var = m().mk_var(t->get_idx() + shift, t->get_sort()); m_mappings[inx] = new_var; } result = m_mappings[inx].get(); From 121e83b6b7960263b5fec710202a070ad2477ed4 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 3 May 2013 17:54:30 +0100 Subject: [PATCH 130/281] FPA: bugfixes for UF in model converter for fpa2bv. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 44 ++++++++++++++++++++--- src/tactic/fpa/fpa2bv_converter.h | 55 ++++++++++++++++++++--------- src/tactic/fpa/fpa2bv_tactic.cpp | 2 +- 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index acb41a2b1..363cf1df8 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -2403,6 +2403,25 @@ void fpa2bv_model_converter::display(std::ostream & out) { unsigned indent = n.size() + 4; out << mk_ismt2_pp(it->m_value, m, indent) << ")"; } + for (obj_map::iterator it = m_uf2bvuf.begin(); + it != m_uf2bvuf.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value, m, indent) << ")"; + } + for (obj_map::iterator it = m_uf23bvuf.begin(); + it != m_uf23bvuf.end(); + it++) { + const symbol & n = it->m_key->get_name(); + out << "\n (" << n << " "; + unsigned indent = n.size() + 4; + out << mk_ismt2_pp(it->m_value.f_sgn, m, indent) << " ; " << + mk_ismt2_pp(it->m_value.f_sig, m, indent) << " ; " << + mk_ismt2_pp(it->m_value.f_exp, m, indent) << " ; " << + ")"; + } out << ")" << std::endl; } @@ -2523,6 +2542,20 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { } } + for (obj_map::iterator it = m_uf2bvuf.begin(); + it != m_uf2bvuf.end(); + it++) + seen.insert(it->m_value); + + for (obj_map::iterator it = m_uf23bvuf.begin(); + it != m_uf23bvuf.end(); + it++) + { + seen.insert(it->m_value.f_sgn); + seen.insert(it->m_value.f_sig); + seen.insert(it->m_value.f_exp); + } + fu.fm().del(fp_val); // Keep all the non-float constants. @@ -2530,7 +2563,7 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { for (unsigned i = 0; i < sz; i++) { func_decl * c = bv_mdl->get_constant(i); - if (!seen.contains(c)) + if (!seen.contains(c)) float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); } @@ -2539,7 +2572,8 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { for (unsigned i = 0; i < sz; i++) { func_decl * c = bv_mdl->get_function(i); - float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); + if (!seen.contains(c)) + float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); } sz = bv_mdl->get_num_uninterpreted_sorts(); @@ -2553,6 +2587,8 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { model_converter * mk_fpa2bv_model_converter(ast_manager & m, obj_map const & const2bv, - obj_map const & rm_const2bv) { - return alloc(fpa2bv_model_converter, m, const2bv, rm_const2bv); + obj_map const & rm_const2bv, + obj_map const & uf2bvuf, + obj_map const & uf23bvuf) { + return alloc(fpa2bv_model_converter, m, const2bv, rm_const2bv, uf2bvuf, uf23bvuf); } diff --git a/src/tactic/fpa/fpa2bv_converter.h b/src/tactic/fpa/fpa2bv_converter.h index f090e3e8d..2a68342f8 100644 --- a/src/tactic/fpa/fpa2bv_converter.h +++ b/src/tactic/fpa/fpa2bv_converter.h @@ -31,20 +31,7 @@ typedef enum { BV_RM_TIES_TO_AWAY=0, BV_RM_TIES_TO_EVEN=1, BV_RM_TO_NEGATIVE=2, class fpa2bv_model_converter; -class fpa2bv_converter { - ast_manager & m; - basic_simplifier_plugin m_simp; - float_util m_util; - mpf_manager & m_mpf_manager; - unsynch_mpz_manager & m_mpz_manager; - bv_util m_bv_util; - float_decl_plugin * m_plugin; - - obj_map m_const2bv; - obj_map m_rm_const2bv; - obj_map m_uf2bvuf; - - struct func_decl_triple { +struct func_decl_triple { func_decl_triple () { f_sgn = 0; f_sig = 0; f_exp = 0; } func_decl_triple (func_decl * sgn, func_decl * sig, func_decl * exp) { @@ -56,6 +43,19 @@ class fpa2bv_converter { func_decl * f_sig; func_decl * f_exp; }; + +class fpa2bv_converter { + ast_manager & m; + basic_simplifier_plugin m_simp; + float_util m_util; + mpf_manager & m_mpf_manager; + unsynch_mpz_manager & m_mpz_manager; + bv_util m_bv_util; + float_decl_plugin * m_plugin; + + obj_map m_const2bv; + obj_map m_rm_const2bv; + obj_map m_uf2bvuf; obj_map m_uf23bvuf; public: @@ -122,6 +122,8 @@ public: obj_map const & const2bv() const { return m_const2bv; } obj_map const & rm_const2bv() const { return m_rm_const2bv; } + obj_map const & uf2bvuf() const { return m_uf2bvuf; } + obj_map const & uf23bvuf() const { return m_uf23bvuf; } void dbg_decouple(const char * prefix, expr_ref & e); expr_ref_vector extra_assertions; @@ -166,10 +168,14 @@ class fpa2bv_model_converter : public model_converter { ast_manager & m; obj_map m_const2bv; obj_map m_rm_const2bv; + obj_map m_uf2bvuf; + obj_map m_uf23bvuf; public: fpa2bv_model_converter(ast_manager & m, obj_map const & const2bv, - obj_map const & rm_const2bv) : + obj_map const & rm_const2bv, + obj_map const & uf2bvuf, + obj_map const & uf23bvuf) : m(m) { // Just create a copy? for (obj_map::iterator it = const2bv.begin(); @@ -188,6 +194,21 @@ public: m.inc_ref(it->m_key); m.inc_ref(it->m_value); } + for (obj_map::iterator it = uf2bvuf.begin(); + it != uf2bvuf.end(); + it++) + { + m_uf2bvuf.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + m.inc_ref(it->m_value); + } + for (obj_map::iterator it = uf23bvuf.begin(); + it != uf23bvuf.end(); + it++) + { + m_uf23bvuf.insert(it->m_key, it->m_value); + m.inc_ref(it->m_key); + } } virtual ~fpa2bv_model_converter() { @@ -220,6 +241,8 @@ protected: model_converter * mk_fpa2bv_model_converter(ast_manager & m, obj_map const & const2bv, - obj_map const & rm_const2bv); + obj_map const & rm_const2bv, + obj_map const & uf2bvuf, + obj_map const & uf23bvuf); #endif diff --git a/src/tactic/fpa/fpa2bv_tactic.cpp b/src/tactic/fpa/fpa2bv_tactic.cpp index a90ff9317..9bb35eea6 100644 --- a/src/tactic/fpa/fpa2bv_tactic.cpp +++ b/src/tactic/fpa/fpa2bv_tactic.cpp @@ -90,7 +90,7 @@ class fpa2bv_tactic : public tactic { } if (g->models_enabled()) - mc = mk_fpa2bv_model_converter(m, m_conv.const2bv(), m_conv.rm_const2bv()); + mc = mk_fpa2bv_model_converter(m, m_conv.const2bv(), m_conv.rm_const2bv(), m_conv.uf2bvuf(), m_conv.uf23bvuf()); g->inc_depth(); result.push_back(g.get()); From 622484929f6b4665362f968311de2e8a9bd5188d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 6 May 2013 01:33:40 +0200 Subject: [PATCH 131/281] postpone rule flushing dependent on engine Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 3 ++ src/muz_qe/dl_context.cpp | 79 +++++++++++++++++++-------------- src/muz_qe/dl_context.h | 3 +- src/muz_qe/dl_mk_slice.cpp | 24 +++++----- src/muz_qe/pdr_dl_interface.cpp | 4 +- 5 files changed, 66 insertions(+), 47 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index c138bcd62..bbd267292 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -585,6 +585,9 @@ class FuncDeclRef(AstRef): def as_ast(self): return Z3_func_decl_to_ast(self.ctx_ref(), self.ast) + def as_func_decl(self): + return self.ast + def name(self): """Return the name of the function declaration `self`. diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index dfcaac791..f8e572ab1 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -234,6 +234,7 @@ namespace datalog { m_vars(m), m_rule_set(*this), m_transformed_rule_set(*this), + m_rule_fmls_head(0), m_rule_fmls(m), m_background(m), m_mc(0), @@ -243,8 +244,6 @@ namespace datalog { m_last_answer(m), m_engine(LAST_ENGINE), m_cancel(false) { - - //register plugins for builtin tables } context::~context() { @@ -254,6 +253,9 @@ namespace datalog { void context::reset() { m_trail.reset(); m_rule_set.reset(); + m_rule_fmls_head = 0; + m_rule_fmls.reset(); + m_rule_names.reset(); m_argument_var_names.reset(); m_preds.reset(); m_preds_by_name.reset(); @@ -457,13 +459,18 @@ namespace datalog { void context::flush_add_rules() { datalog::rule_manager& rm = get_rule_manager(); scoped_proof_mode _scp(m, generate_proof_trace()?PGM_FINE:PGM_DISABLED); - for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { - expr* fml = m_rule_fmls[i].get(); + while (m_rule_fmls_head < m_rule_fmls.size()) { + expr* fml = m_rule_fmls[m_rule_fmls_head].get(); proof* p = generate_proof_trace()?m.mk_asserted(fml):0; - rm.mk_rule(fml, p, m_rule_set, m_rule_names[i]); + rm.mk_rule(fml, p, m_rule_set, m_rule_names[m_rule_fmls_head]); + ++m_rule_fmls_head; + } + rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); + rule_ref r(m_rule_manager); + for (; it != end; ++it) { + r = *it; + check_rule(r); } - m_rule_fmls.reset(); - m_rule_names.reset(); } // @@ -958,18 +965,21 @@ namespace datalog { engine_type_proc(ast_manager& m): m(m), a(m), dt(m), m_engine(DATALOG_ENGINE) {} DL_ENGINE get_engine() const { return m_engine; } + void operator()(expr* e) { if (is_quantifier(e)) { m_engine = QPDR_ENGINE; } - else if (a.is_int_real(e) && m_engine != QPDR_ENGINE) { - m_engine = PDR_ENGINE; - } - else if (is_var(e) && m.is_bool(e)) { - m_engine = PDR_ENGINE; - } - else if (dt.is_datatype(m.get_sort(e))) { - m_engine = PDR_ENGINE; + else if (m_engine != QPDR_ENGINE) { + if (a.is_int_real(e)) { + m_engine = PDR_ENGINE; + } + else if (is_var(e) && m.is_bool(e)) { + m_engine = PDR_ENGINE; + } + else if (dt.is_datatype(m.get_sort(e))) { + m_engine = PDR_ENGINE; + } } } }; @@ -1002,7 +1012,7 @@ namespace datalog { if (m_engine == LAST_ENGINE) { expr_fast_mark1 mark; engine_type_proc proc(m); - m_engine = DATALOG_ENGINE; + m_engine = DATALOG_ENGINE; for (unsigned i = 0; m_engine == DATALOG_ENGINE && i < m_rule_set.get_num_rules(); ++i) { rule * r = m_rule_set.get_rule(i); quick_for_each_expr(proc, mark, r->get_head()); @@ -1011,29 +1021,38 @@ namespace datalog { } m_engine = proc.get_engine(); } + for (unsigned i = m_rule_fmls_head; m_engine == DATALOG_ENGINE && i < m_rule_fmls.size(); ++i) { + expr* fml = m_rule_fmls[i].get(); + while (is_quantifier(fml)) { + fml = to_quantifier(fml)->get_expr(); + } + quick_for_each_expr(proc, mark, fml); + m_engine = proc.get_engine(); + } } } lbool context::query(expr* query) { - new_query(); - rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); - rule_ref r(m_rule_manager); - for (; it != end; ++it) { - r = *it; - check_rule(r); - } - switch(get_engine()) { + m_mc = mk_skip_model_converter(); + m_last_status = OK; + m_last_answer = 0; + switch (get_engine()) { case DATALOG_ENGINE: + flush_add_rules(); return rel_query(query); case PDR_ENGINE: case QPDR_ENGINE: + flush_add_rules(); return pdr_query(query); case BMC_ENGINE: case QBMC_ENGINE: + flush_add_rules(); return bmc_query(query); case TAB_ENGINE: + flush_add_rules(); return tab_query(query); case CLP_ENGINE: + flush_add_rules(); return clp_query(query); default: UNREACHABLE(); @@ -1041,14 +1060,6 @@ namespace datalog { } } - void context::new_query() { - m_mc = mk_skip_model_converter(); - - flush_add_rules(); - m_last_status = OK; - m_last_answer = 0; - } - model_ref context::get_model() { switch(get_engine()) { case PDR_ENGINE: @@ -1277,7 +1288,7 @@ namespace datalog { datalog::rule_manager& rm = get_rule_manager(); // ensure that rules are all using bound variables. - for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { + for (unsigned i = m_rule_fmls_head; i < m_rule_fmls.size(); ++i) { ptr_vector sorts; get_free_vars(m_rule_fmls[i].get(), sorts); if (!sorts.empty()) { @@ -1295,7 +1306,7 @@ namespace datalog { rules.push_back(fml); names.push_back((*it)->name()); } - for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { + for (unsigned i = m_rule_fmls_head; i < m_rule_fmls.size(); ++i) { rules.push_back(m_rule_fmls[i].get()); names.push_back(m_rule_names[i]); } diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index 0a01b3e01..e9abf7f23 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -114,6 +114,7 @@ namespace datalog { pred2syms m_argument_var_names; rule_set m_rule_set; rule_set m_transformed_rule_set; + unsigned m_rule_fmls_head; expr_ref_vector m_rule_fmls; svector m_rule_names; expr_ref_vector m_background; @@ -482,8 +483,6 @@ namespace datalog { void ensure_rel(); - void new_query(); - lbool rel_query(expr* query); lbool pdr_query(expr* query); diff --git a/src/muz_qe/dl_mk_slice.cpp b/src/muz_qe/dl_mk_slice.cpp index 89804447b..1a97c1b81 100644 --- a/src/muz_qe/dl_mk_slice.cpp +++ b/src/muz_qe/dl_mk_slice.cpp @@ -120,12 +120,11 @@ namespace datalog { obj_map::iterator end = m_rule2slice.end(); expr_ref fml(m); for (; it != end; ++it) { - TRACE("dl", - it->m_key->display(m_ctx, tout << "orig:\n"); - it->m_value->display(m_ctx, tout << "new:\n");); - it->m_value->to_formula(fml); m_pinned_exprs.push_back(fml); + TRACE("dl", + tout << "orig: " << mk_pp(fml, m) << "\n"; + it->m_value->display(m_ctx, tout << "new:\n");); m_sliceform2rule.insert(fml, it->m_key); } } @@ -202,9 +201,10 @@ namespace datalog { proof* p0_new = m_new_proof.find(p0); expr* fact0 = m.get_fact(p0); TRACE("dl", tout << "fact0: " << mk_pp(fact0, m) << "\n";); - rule* orig0 = m_sliceform2rule.find(fact0); - /* rule* slice0 = */ m_rule2slice.find(orig0); - /* unsigned_vector const& renaming0 = m_renaming.find(orig0); */ + rule* orig0; + if (!m_sliceform2rule.find(fact0, orig0)) { + return false; + } premises.push_back(p0_new); rule_ref r1(rm), r2(rm), r3(rm); r1 = orig0; @@ -214,9 +214,10 @@ namespace datalog { proof* p1_new = m_new_proof.find(p1); expr* fact1 = m.get_fact(p1); TRACE("dl", tout << "fact1: " << mk_pp(fact1, m) << "\n";); - rule* orig1 = m_sliceform2rule.find(fact1); - /* rule* slice1 = */ m_rule2slice.find(orig1); - /* unsigned_vector const& renaming1 = m_renaming.find(orig1); TBD */ + rule* orig1 = 0; + if (!m_sliceform2rule.find(fact1, orig1)) { + return false; + } premises.push_back(p1_new); // TODO: work with substitutions. @@ -241,6 +242,9 @@ namespace datalog { proof* new_p = m.mk_hyper_resolve(premises.size(), premises.c_ptr(), concl, positions, substs); m_pinned_exprs.push_back(new_p); m_pinned_rules.push_back(r1.get()); + TRACE("dl", + tout << "orig: " << mk_pp(slice_concl, m) << "\n"; + r1->display(m_ctx, tout << "new:");); m_sliceform2rule.insert(slice_concl, r1.get()); m_rule2slice.insert(r1.get(), 0); m_renaming.insert(r1.get(), unsigned_vector()); diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index 63ac6cf4b..3ff54e68e 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -32,6 +32,7 @@ Revision History: #include "dl_mk_slice.h" #include "dl_mk_unfold.h" #include "dl_mk_coalesce.h" +#include "model_smt2_pp.h" using namespace pdr; @@ -134,10 +135,10 @@ lbool dl_interface::query(expr * query) { } query_pred = m_ctx.get_rules().get_output_predicate(); - IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); m_pdr_rules.replace_rules(m_ctx.get_rules()); m_pdr_rules.close(); + m_ctx.record_transformed_rules(); m_ctx.reopen(); m_ctx.replace_rules(old_rules); @@ -151,6 +152,7 @@ lbool dl_interface::query(expr * query) { if (m_pdr_rules.get_rules().empty()) { m_context->set_unsat(); + IF_VERBOSE(1, model_smt2_pp(verbose_stream(), m, *m_context->get_model(),0);); return l_false; } From 157b5f0d9ce1a7618ce11f7708a72342bf5db55d Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 7 May 2013 08:10:43 -0700 Subject: [PATCH 132/281] Add expr_vector example Signed-off-by: Leonardo de Moura --- examples/c++/example.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index ab5d0132c..bec8c59a1 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -906,6 +906,28 @@ void enum_sort_example() { std::cout << "2: " << result_goal.as_expr() << std::endl; } +void expr_vector_example() { + context c; + const unsigned N = 10; + + expr_vector x(c); + + for (unsigned i = 0; i < N; i++) { + std::stringstream x_name; + x_name << "x_" << i; + x.push_back(c.int_const(x_name.str().c_str())); + } + + solver s(c); + for (unsigned i = 0; i < N; i++) { + s.add(x[i] >= 1); + } + + std::cout << s << "\n" << "solving...\n" << s.check() << "\n"; + model m = s.get_model(); + std::cout << "solution\n" << m; +} + int main() { try { demorgan(); std::cout << "\n"; @@ -941,6 +963,7 @@ int main() { incremental_example2(); std::cout << "\n"; incremental_example3(); std::cout << "\n"; enum_sort_example(); std::cout << "\n"; + expr_vector_example(); std::cout << "\n"; std::cout << "done\n"; } catch (exception & ex) { From b65adc10da41a90f883592424c52e1f9bd683d12 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 7 May 2013 17:58:43 +0100 Subject: [PATCH 133/281] FPA: bugfix for quantified FP -> quantified BV conversion. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_rewriter.h | 41 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_rewriter.h b/src/tactic/fpa/fpa2bv_rewriter.h index aec00d30c..a891337ec 100644 --- a/src/tactic/fpa/fpa2bv_rewriter.h +++ b/src/tactic/fpa/fpa2bv_rewriter.h @@ -166,9 +166,11 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { bool pre_visit(expr * t) { + TRACE("fpa2bv", tout << "pre_visit: " << mk_ismt2_pp(t, m()) << std::endl;); + if (is_quantifier(t)) { quantifier * q = to_quantifier(t); - TRACE("fpa2bv", tout << "pre_visit [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m()) << std::endl;); + TRACE("fpa2bv", tout << "pre_visit quantifier [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m()) << std::endl;); sort_ref_vector new_bindings(m_manager); for (unsigned i = 0 ; i < q->get_num_decls(); i++) new_bindings.push_back(q->get_decl_sort(i)); @@ -199,17 +201,9 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { unsigned ebits = m_conv.fu().get_ebits(s); unsigned sbits = m_conv.fu().get_sbits(s); name_buffer.reset(); - name_buffer << n << ".exp"; + name_buffer << n << ".bv"; new_decl_names.push_back(symbol(name_buffer.c_str())); - new_decl_sorts.push_back(m_conv.bu().mk_sort(ebits)); - name_buffer.reset(); - name_buffer << n << ".sig"; - new_decl_names.push_back(symbol(name_buffer.c_str())); - new_decl_sorts.push_back(m_conv.bu().mk_sort(sbits-1)); - name_buffer.reset(); - name_buffer << n << ".sgn"; - new_decl_names.push_back(symbol(name_buffer.c_str())); - new_decl_sorts.push_back(m_conv.bu().mk_sort(1)); + new_decl_sorts.push_back(m_conv.bu().mk_sort(sbits+ebits)); } else { new_decl_sorts.push_back(s); @@ -231,19 +225,26 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { if (t->get_idx() >= m_bindings.size()) - return false; + return false; unsigned inx = m_bindings.size() - t->get_idx() - 1; if (m_mappings[inx] == 0) { - unsigned shift = 0; - for (unsigned i = m_bindings.size() - 1; i > inx; i--) - if (m_conv.is_float(m_bindings[i].get())) shift += 2; - expr_ref new_var(m()); - if (m_conv.is_float(t->get_sort())) - m_conv.mk_var(t->get_idx() + shift, t->get_sort(), new_var); + 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_triple(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var), + m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var), + m_conv.bu().mk_extract(ebits-1, 0, new_var), + new_exp); + } else - new_var = m().mk_var(t->get_idx() + shift, t->get_sort()); - m_mappings[inx] = new_var; + new_exp = m().mk_var(t->get_idx(), s); + m_mappings[inx] = new_exp; } result = m_mappings[inx].get(); result_pr = 0; From 787a65be299e88eb7dd4628e5858b5ecb53026ba Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 7 May 2013 18:27:47 +0100 Subject: [PATCH 134/281] FPA: bugfix for QFPA -> QBV conversion. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_rewriter.h | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_rewriter.h b/src/tactic/fpa/fpa2bv_rewriter.h index a891337ec..3398874f5 100644 --- a/src/tactic/fpa/fpa2bv_rewriter.h +++ b/src/tactic/fpa/fpa2bv_rewriter.h @@ -30,7 +30,8 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { expr_ref_vector m_out; fpa2bv_converter & m_conv; sort_ref_vector m_bindings; - expr_ref_vector m_mappings; + expr_ref_vector m_mappings; + unsigned long long m_max_memory; unsigned m_max_steps; @@ -227,25 +228,24 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { if (t->get_idx() >= m_bindings.size()) return false; unsigned inx = m_bindings.size() - t->get_idx() - 1; - if (m_mappings[inx] == 0) + + expr_ref new_exp(m()); + sort * s = t->get_sort(); + if (m_conv.is_float(s)) { - 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_triple(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var), - m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var), - m_conv.bu().mk_extract(ebits-1, 0, new_var), - new_exp); - } - else - new_exp = m().mk_var(t->get_idx(), s); - m_mappings[inx] = new_exp; + 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_triple(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var), + m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var), + m_conv.bu().mk_extract(ebits-1, 0, new_var), + new_exp); } + else + new_exp = m().mk_var(t->get_idx(), s); + m_mappings[inx] = new_exp; + result = m_mappings[inx].get(); result_pr = 0; TRACE("fpa2bv", tout << "reduce_var: " << mk_ismt2_pp(t, m()) << " -> " << mk_ismt2_pp(result, m()) << std::endl;); From c8c5f30b49405fe2ae9bcd74021f84258f91ed5d Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 9 May 2013 21:30:31 -0700 Subject: [PATCH 135/281] Add new C++ APIs for creating forall/exists expressions. Signed-off-by: Leonardo de Moura --- examples/c++/example.cpp | 25 +++++++++ src/api/c++/z3++.h | 106 +++++++++++++++++++++++---------------- 2 files changed, 88 insertions(+), 43 deletions(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index bec8c59a1..55dbebe27 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -907,6 +907,7 @@ void enum_sort_example() { } void expr_vector_example() { + std::cout << "expr_vector example\n"; context c; const unsigned N = 10; @@ -928,6 +929,29 @@ void expr_vector_example() { std::cout << "solution\n" << m; } +void exists_expr_vector_example() { + std::cout << "exists expr_vector example\n"; + context c; + const unsigned N = 10; + + expr_vector xs(c); + expr x(c); + expr b(c); + b = c.bool_val(true); + + for (unsigned i = 0; i < N; i++) { + std::stringstream x_name; + x_name << "x_" << i; + x = c.int_const(x_name.str().c_str()); + xs.push_back(x); + b = b && x >= 0; + } + + expr ex(c); + ex = exists(xs, b); + std::cout << ex << std::endl; +} + int main() { try { demorgan(); std::cout << "\n"; @@ -964,6 +988,7 @@ int main() { incremental_example3(); std::cout << "\n"; enum_sort_example(); std::cout << "\n"; expr_vector_example(); std::cout << "\n"; + exists_expr_vector_example(); std::cout << "\n"; std::cout << "done\n"; } catch (exception & ex) { diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index a044149e3..a255c2d97 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -249,6 +249,8 @@ namespace z3 { array & operator=(array const & s); public: array(unsigned sz):m_size(sz) { m_array = new T[sz]; } + template + array(ast_vector_tpl const & v); ~array() { delete[] m_array; } unsigned size() const { return m_size; } T & operator[](int i) { assert(0 <= i); assert(static_cast(i) < m_size); return m_array[i]; } @@ -939,49 +941,6 @@ namespace z3 { inline expr udiv(expr const & a, int b) { return udiv(a, a.ctx().num_val(b, a.get_sort())); } inline expr udiv(int a, expr const & b) { return udiv(b.ctx().num_val(a, b.get_sort()), b); } - // Basic functions for creating quantified formulas. - // The C API should be used for creating quantifiers with patterns, weights, many variables, etc. - inline expr forall(expr const & x, expr const & b) { - check_context(x, b); - Z3_app vars[] = {(Z3_app) x}; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); - } - inline expr forall(expr const & x1, expr const & x2, expr const & b) { - check_context(x1, b); check_context(x2, b); - Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2}; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); - } - inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & b) { - check_context(x1, b); check_context(x2, b); check_context(x3, b); - Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 }; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); - } - inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) { - check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b); - Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 }; - Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); - } - inline expr exists(expr const & x, expr const & b) { - check_context(x, b); - Z3_app vars[] = {(Z3_app) x}; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); - } - inline expr exists(expr const & x1, expr const & x2, expr const & b) { - check_context(x1, b); check_context(x2, b); - Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2}; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); - } - inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & b) { - check_context(x1, b); check_context(x2, b); check_context(x3, b); - Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 }; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); - } - inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) { - check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b); - Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 }; - Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); - } - template class cast_ast; template<> class cast_ast { @@ -1043,6 +1002,67 @@ namespace z3 { friend std::ostream & operator<<(std::ostream & out, ast_vector_tpl const & v) { out << Z3_ast_vector_to_string(v.ctx(), v); return out; } }; + template + template + array::array(ast_vector_tpl const & v) { + m_array = new T[v.size()]; + m_size = v.size(); + for (unsigned i = 0; i < m_size; i++) { + m_array[i] = v[i]; + } + } + + // Basic functions for creating quantified formulas. + // The C API should be used for creating quantifiers with patterns, weights, many variables, etc. + inline expr forall(expr const & x, expr const & b) { + check_context(x, b); + Z3_app vars[] = {(Z3_app) x}; + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + } + inline expr forall(expr const & x1, expr const & x2, expr const & b) { + check_context(x1, b); check_context(x2, b); + Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2}; + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + } + inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & b) { + check_context(x1, b); check_context(x2, b); check_context(x3, b); + Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 }; + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + } + inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) { + check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b); + Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 }; + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + } + inline expr forall(expr_vector const & xs, expr const & b) { + array vars(xs); + Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r); + } + inline expr exists(expr const & x, expr const & b) { + check_context(x, b); + Z3_app vars[] = {(Z3_app) x}; + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + } + inline expr exists(expr const & x1, expr const & x2, expr const & b) { + check_context(x1, b); check_context(x2, b); + Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2}; + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + } + inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & b) { + check_context(x1, b); check_context(x2, b); check_context(x3, b); + Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 }; + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + } + inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) { + check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b); + Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 }; + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r); + } + inline expr exists(expr_vector const & xs, expr const & b) { + array vars(xs); + Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r); + } + class func_entry : public object { Z3_func_entry m_entry; void init(Z3_func_entry e) { From 5eed106ffe81565dcfb345d25c7f9f69dcbfbc0b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 12 May 2013 17:02:25 -0700 Subject: [PATCH 136/281] fix parameters in utvpi and make Karr invariants use backward propagation Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_compiler.cpp | 3 +- src/muz_qe/dl_mk_karr_invariants.cpp | 83 +++++++++++++++++----------- src/muz_qe/dl_mk_karr_invariants.h | 16 +++--- src/muz_qe/dl_product_relation.cpp | 10 ++-- src/muz_qe/dl_sieve_relation.cpp | 5 +- src/smt/theory_utvpi.h | 13 +++-- src/smt/theory_utvpi_def.h | 37 ++++++++----- 7 files changed, 101 insertions(+), 66 deletions(-) diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index 57d9880c0..05a0d24b2 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -499,8 +499,7 @@ namespace datalog { expr * arg = a->get_arg(i); if(is_app(arg)) { app * c = to_app(arg); //argument is a constant - SASSERT(c->get_num_args()==0); - SASSERT(m_context.get_decl_util().is_numeral_ext(arg)); + SASSERT(m.is_value(c)); reg_idx new_reg; make_select_equal_and_project(single_res, c, single_res_expr.size(), new_reg, acc); if(single_res!=t_reg) { diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index d676c3dd4..143a38636 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -37,6 +37,7 @@ Revision History: #include"bool_rewriter.h" #include"dl_mk_backwards.h" #include"dl_mk_loop_counter.h" +#include "for_each_expr.h" namespace datalog { @@ -47,7 +48,8 @@ namespace datalog { m(ctx.get_manager()), rm(ctx.get_rule_manager()), m_inner_ctx(m, ctx.get_fparams()), - a(m) { + a(m), + m_pinned(m) { params_ref params; params.set_sym("default_relation", symbol("karr_relation")); params.set_sym("engine", symbol("datalog")); @@ -201,29 +203,27 @@ namespace datalog { return 0; } } - mk_loop_counter lc(m_ctx); mk_backwards bwd(m_ctx); scoped_ptr src_loop = lc(source); TRACE("dl", src_loop->display(tout << "source loop\n");); - // run propagation forwards, then backwards - scoped_ptr src_annot = update_using_propagation(*src_loop, *src_loop); - TRACE("dl", src_annot->display(tout << "updated using propagation\n");); + get_invariants(*src_loop); -#if 0 // figure out whether to update same rules as used for saturation. - scoped_ptr rev_source = bwd(*src_annot); - src_annot = update_using_propagation(*src_annot, *rev_source); -#endif + scoped_ptr rev_source = bwd(*src_loop); + get_invariants(*rev_source); + scoped_ptr src_annot = update_rules(*src_loop); rule_set* rules = lc.revert(*src_annot); rules->inherit_predicates(source); TRACE("dl", rules->display(tout);); + m_pinned.reset(); + m_fun2inv.reset(); return rules; } - rule_set* mk_karr_invariants::update_using_propagation(rule_set const& src, rule_set const& srcref) { + void mk_karr_invariants::get_invariants(rule_set const& src) { m_inner_ctx.reset(); rel_context& rctx = m_inner_ctx.get_rel_context(); ptr_vector heads; @@ -232,19 +232,41 @@ namespace datalog { m_inner_ctx.register_predicate(*fit, false); } m_inner_ctx.ensure_opened(); - m_inner_ctx.replace_rules(srcref); + m_inner_ctx.replace_rules(src); m_inner_ctx.close(); - rule_set::decl2rules::iterator dit = srcref.begin_grouped_rules(); - rule_set::decl2rules::iterator dend = srcref.end_grouped_rules(); + rule_set::decl2rules::iterator dit = src.begin_grouped_rules(); + rule_set::decl2rules::iterator dend = src.end_grouped_rules(); for (; dit != dend; ++dit) { heads.push_back(dit->m_key); } m_inner_ctx.rel_query(heads.size(), heads.c_ptr()); - - rule_set* dst = alloc(rule_set, m_ctx); + + // retrieve invariants. + dit = src.begin_grouped_rules(); + for (; dit != dend; ++dit) { + func_decl* p = dit->m_key; + relation_base* rb = rctx.try_get_relation(p); + if (rb) { + expr_ref fml(m); + rb->to_formula(fml); + if (m.is_true(fml)) { + continue; + } + expr* inv = 0; + if (m_fun2inv.find(p, inv)) { + fml = m.mk_and(inv, fml); + } + m_pinned.push_back(fml); + m_fun2inv.insert(p, fml); + } + } + } + + rule_set* mk_karr_invariants::update_rules(rule_set const& src) { + scoped_ptr dst = alloc(rule_set, m_ctx); rule_set::iterator it = src.begin(), end = src.end(); for (; it != end; ++it) { - update_body(rctx, *dst, **it); + update_body(*dst, **it); } if (m_ctx.get_model_converter()) { add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m); @@ -252,10 +274,8 @@ namespace datalog { rule_set::decl2rules::iterator gend = src.end_grouped_rules(); for (; git != gend; ++git) { func_decl* p = git->m_key; - expr_ref fml(m); - relation_base* rb = rctx.try_get_relation(p); - if (rb) { - rb->to_formula(fml); + expr* fml = 0; + if (m_fun2inv.find(p, fml)) { kmc->add(p, fml); } } @@ -263,10 +283,10 @@ namespace datalog { } dst->inherit_predicates(src); - return dst; + return dst.detach(); } - void mk_karr_invariants::update_body(rel_context& rctx, rule_set& rules, rule& r) { + void mk_karr_invariants::update_body(rule_set& rules, rule& r) { unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); app_ref_vector tail(m); @@ -275,17 +295,17 @@ namespace datalog { tail.push_back(r.get_tail(i)); } for (unsigned i = 0; i < utsz; ++i) { - func_decl* q = r.get_decl(i); - relation_base* rb = rctx.try_get_relation(r.get_decl(i)); - if (rb) { - rb->to_formula(fml); + func_decl* q = r.get_decl(i); + expr* fml = 0; + if (m_fun2inv.find(q, fml)) { expr_safe_replace rep(m); for (unsigned j = 0; j < q->get_arity(); ++j) { rep.insert(m.mk_var(j, q->get_domain(j)), r.get_tail(i)->get_arg(j)); } - rep(fml); - tail.push_back(to_app(fml)); + expr_ref tmp(fml, m); + rep(tmp); + tail.push_back(to_app(tmp)); } } rule* new_rule = &r; @@ -1029,16 +1049,17 @@ namespace datalog { class karr_relation_plugin::filter_equal_fn : public relation_mutator_fn { unsigned m_col; rational m_value; + bool m_valid; public: filter_equal_fn(relation_manager & m, const relation_element & value, unsigned col) : m_col(col) { arith_util arith(m.get_context().get_manager()); - VERIFY(arith.is_numeral(value, m_value)); + m_valid = arith.is_numeral(value, m_value) && m_value.is_int(); } virtual void operator()(relation_base & _r) { karr_relation & r = get(_r); - if (m_value.is_int()) { + if (m_valid) { r.get_ineqs(); vector row; row.resize(r.get_signature().size()); @@ -1054,7 +1075,7 @@ namespace datalog { relation_mutator_fn * karr_relation_plugin::mk_filter_equal_fn(const relation_base & r, const relation_element & value, unsigned col) { - if(check_kind(r)) { + if (check_kind(r)) { return alloc(filter_equal_fn, get_manager(), value, col); } return 0; diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index 330260671..ec554e284 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -55,8 +55,13 @@ namespace datalog { rule_manager& rm; context m_inner_ctx; arith_util a; - void update_body(rel_context& rctx, rule_set& result, rule& r); - rule_set* update_using_propagation(rule_set const& src, rule_set const& srcref); + obj_map m_fun2inv; + ast_ref_vector m_pinned; + + void get_invariants(rule_set const& src); + + void update_body(rule_set& result, rule& r); + rule_set* update_rules(rule_set const& src); public: mk_karr_invariants(context & ctx, unsigned priority); @@ -89,12 +94,7 @@ namespace datalog { {} virtual bool can_handle_signature(const relation_signature & sig) { - for (unsigned i = 0; i < sig.size(); ++i) { - if (a.is_int(sig[i])) { - return true; - } - } - return false; + return true; } static symbol get_name() { return symbol("karr_relation"); } diff --git a/src/muz_qe/dl_product_relation.cpp b/src/muz_qe/dl_product_relation.cpp index 66074d463..c10b5799a 100644 --- a/src/muz_qe/dl_product_relation.cpp +++ b/src/muz_qe/dl_product_relation.cpp @@ -269,7 +269,7 @@ namespace datalog { unsigned_vector r1_tables_indexes; unsigned_vector r2_tables_indexes; for (unsigned i = 0; i < num_rels1; ++i) { - if(is_tableish_relation(*r1[i])) { + if (is_tableish_relation(*r1[i])) { r1_tables_indexes.push_back(i); continue; } @@ -291,7 +291,7 @@ namespace datalog { if (!found) { relation_plugin & r1_plugin = get_nonsieve_plugin(*r1[i]); relation_base* rel2; - if(r1_plugin.can_handle_signature(r2_sig)) { + if (r1_plugin.can_handle_signature(r2_sig)) { rel2 = r1_plugin.mk_full(p, r2_sig, r1_kind); } else { @@ -307,7 +307,7 @@ namespace datalog { } } for (unsigned i = 0; i < num_rels2; ++i) { - if(is_tableish_relation(*r2[i])) { + if (is_tableish_relation(*r2[i])) { r2_tables_indexes.push_back(i); continue; } @@ -315,7 +315,7 @@ namespace datalog { relation_plugin & r2_plugin = get_nonsieve_plugin(*r2[i]); family_id r2_kind = get_nonsieve_kind(*r2[i]); relation_base* rel1; - if(r2_plugin.can_handle_signature(r1_sig)) { + if (r2_plugin.can_handle_signature(r1_sig)) { rel1 = r2_plugin.mk_full(p, r1_sig, r2_kind); } else { @@ -331,7 +331,7 @@ namespace datalog { } } - if(!r1_tables_indexes.empty() && !r2_tables_indexes.empty()) { + if (!r1_tables_indexes.empty() && !r2_tables_indexes.empty()) { //We may perhaps want to group the table relations by kinds so that tables of the same kind //get joined... diff --git a/src/muz_qe/dl_sieve_relation.cpp b/src/muz_qe/dl_sieve_relation.cpp index e80462900..9f9419089 100644 --- a/src/muz_qe/dl_sieve_relation.cpp +++ b/src/muz_qe/dl_sieve_relation.cpp @@ -158,7 +158,7 @@ namespace datalog { inner_sig_singleton.push_back(s[i]); inner_columns[i] = inner.can_handle_signature(inner_sig_singleton); } -#if Z3DEBUG +#if Z3DEBUG //we assume that if a relation plugin can handle two sets of columns separetely, //it can also handle them in one relation relation_signature inner_sig; @@ -246,7 +246,8 @@ namespace datalog { relation_base * sieve_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { relation_signature empty_sig; - relation_base * inner = get_manager().mk_full_relation(empty_sig, p, null_family_id); + relation_plugin& plugin = get_manager().get_appropriate_plugin(s); + relation_base * inner = plugin.mk_full(p, empty_sig, null_family_id); svector inner_cols; inner_cols.resize(s.size(), false); return mk_from_inner(s, inner_cols, inner); diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index 9e8073ec2..a9dd869a9 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -65,7 +65,7 @@ namespace smt { class parent_trail; struct GExt : public Ext { - typedef literal explanation; + typedef std::pair explanation; }; class atom { @@ -113,15 +113,18 @@ namespace smt { // a negative cycle. class nc_functor { literal_vector m_antecedents; + unsigned_vector m_coeffs; theory_utvpi& m_super; public: nc_functor(theory_utvpi& s) : m_super(s) {} - void reset() { m_antecedents.reset(); } + void reset() { m_antecedents.reset(); m_coeffs.reset(); } literal_vector const& get_lits() const { return m_antecedents; } + unsigned_vector const& get_coeffs() const { return m_coeffs; } - void operator()(literal const & ex) { - if (ex != null_literal) { - m_antecedents.push_back(ex); + void operator()(std::pair const & ex) { + if (ex.first != null_literal) { + m_antecedents.push_back(ex.first); + m_coeffs.push_back(ex.second); } } diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index af372ea50..457ac83ad 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -197,6 +197,15 @@ namespace smt { inc_conflicts(); literal_vector const& lits = m_nc_functor.get_lits(); context & ctx = get_context(); + IF_VERBOSE(2, + verbose_stream() << "conflict:\n"; + for (unsigned i = 0; i < lits.size(); ++i) { + ast_manager& m = get_manager(); + expr_ref e(m); + ctx.literal2expr(lits[i], e); + verbose_stream() << mk_pp(e, m) << "\n"; + } + verbose_stream() << "\n";); TRACE("utvpi", tout << "conflict: "; for (unsigned i = 0; i < lits.size(); ++i) { @@ -213,7 +222,9 @@ namespace smt { vector params; if (get_manager().proofs_enabled()) { params.push_back(parameter(symbol("farkas"))); - params.resize(lits.size()+1, parameter(rational(1))); + for (unsigned i = 0; i < m_nc_functor.get_coeffs().size(); ++i) { + params.push_back(parameter(rational(m_nc_functor.get_coeffs()[i]))); + } } ctx.set_conflict( @@ -620,28 +631,28 @@ namespace smt { edge_id id = m_graph.get_num_edges(); th_var w1 = to_var(v1), w2 = to_var(v2); if (terms.size() == 1 && pos1) { - m_graph.add_edge(neg(w1), pos(w1), -weight-weight, l); - m_graph.add_edge(neg(w1), pos(w1), -weight-weight, l); + m_graph.add_edge(neg(w1), pos(w1), -weight-weight, std::make_pair(l,2)); + m_graph.add_edge(neg(w1), pos(w1), -weight-weight, std::make_pair(l,2)); } else if (terms.size() == 1 && !pos1) { - m_graph.add_edge(pos(w1), neg(w1), -weight-weight, l); - m_graph.add_edge(pos(w1), neg(w1), -weight-weight, l); + m_graph.add_edge(pos(w1), neg(w1), -weight-weight, std::make_pair(l,2)); + m_graph.add_edge(pos(w1), neg(w1), -weight-weight, std::make_pair(l,2)); } else if (pos1 && pos2) { - m_graph.add_edge(neg(w2), pos(w1), -weight, l); - m_graph.add_edge(neg(w1), pos(w2), -weight, l); + m_graph.add_edge(neg(w2), pos(w1), -weight, std::make_pair(l,1)); + m_graph.add_edge(neg(w1), pos(w2), -weight, std::make_pair(l,1)); } else if (pos1 && !pos2) { - m_graph.add_edge(pos(w2), pos(w1), -weight, l); - m_graph.add_edge(neg(w1), neg(w2), -weight, l); + m_graph.add_edge(pos(w2), pos(w1), -weight, std::make_pair(l,1)); + m_graph.add_edge(neg(w1), neg(w2), -weight, std::make_pair(l,1)); } else if (!pos1 && pos2) { - m_graph.add_edge(neg(w2), neg(w1), -weight, l); - m_graph.add_edge(pos(w1), pos(w2), -weight, l); + m_graph.add_edge(neg(w2), neg(w1), -weight, std::make_pair(l,1)); + m_graph.add_edge(pos(w1), pos(w2), -weight, std::make_pair(l,1)); } else { - m_graph.add_edge(pos(w1), neg(w2), -weight, l); - m_graph.add_edge(pos(w2), neg(w1), -weight, l); + m_graph.add_edge(pos(w1), neg(w2), -weight, std::make_pair(l,1)); + m_graph.add_edge(pos(w2), neg(w1), -weight, std::make_pair(l,1)); } return id; } From e35fd58968ec08dd4184e20b639e81a6aa4a9aa6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 May 2013 11:43:30 -0700 Subject: [PATCH 137/281] add rewriting option to simplify store equalities Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/array_rewriter.cpp | 38 ++++++++++++++++++++++ src/ast/rewriter/array_rewriter.h | 3 ++ src/ast/rewriter/array_rewriter_params.pyg | 1 + src/ast/rewriter/mk_simplified_app.cpp | 2 ++ src/ast/rewriter/th_rewriter.cpp | 4 ++- 5 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 0bb7378f4..1f4418fd5 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -25,6 +25,7 @@ void array_rewriter::updt_params(params_ref const & _p) { array_rewriter_params p(_p); m_sort_store = p.sort_store(); m_expand_select_store = p.expand_select_store(); + m_expand_store_eq = p.expand_store_eq(); } void array_rewriter::get_param_descrs(param_descrs & r) { @@ -365,3 +366,40 @@ br_status array_rewriter::mk_set_subset(expr * arg1, expr * arg2, expr_ref & res return BR_REWRITE3; } +br_status array_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { + if (!m_expand_store_eq) { + return BR_FAILED; + } + expr* lhs1 = lhs; + while (m_util.is_store(lhs1)) { + lhs1 = to_app(lhs1)->get_arg(0); + } + expr* rhs1 = rhs; + while (m_util.is_store(rhs1)) { + rhs1 = to_app(rhs1)->get_arg(0); + } + if (lhs1 != rhs1) { + return BR_FAILED; + } + ptr_buffer fmls, args; + expr* e; + expr_ref tmp1(m()), tmp2(m()); +#define MK_EQ() \ + while (m_util.is_store(e)) { \ + args.push_back(lhs); \ + args.append(to_app(e)->get_num_args()-2,to_app(e)->get_args()+1); \ + mk_select(args.size(), args.c_ptr(), tmp1); \ + args[0] = rhs; \ + mk_select(args.size(), args.c_ptr(), tmp2); \ + fmls.push_back(m().mk_eq(tmp1, tmp2)); \ + e = to_app(e)->get_arg(0); \ + args.reset(); \ + } \ + + e = lhs; + MK_EQ(); + e = rhs; + MK_EQ(); + result = m().mk_and(fmls.size(), fmls.c_ptr()); + return BR_REWRITE_FULL; +} diff --git a/src/ast/rewriter/array_rewriter.h b/src/ast/rewriter/array_rewriter.h index f1362802d..5f20f61ba 100644 --- a/src/ast/rewriter/array_rewriter.h +++ b/src/ast/rewriter/array_rewriter.h @@ -31,12 +31,14 @@ class array_rewriter { array_util m_util; bool m_sort_store; bool m_expand_select_store; + bool m_expand_store_eq; template lbool compare_args(unsigned num_args, expr * const * args1, expr * const * args2); public: array_rewriter(ast_manager & m, params_ref const & p = params_ref()): m_util(m) { updt_params(p); + } ast_manager & m() const { return m_util.get_manager(); } family_id get_fid() const { return m_util.get_family_id(); } @@ -60,6 +62,7 @@ public: br_status mk_set_complement(expr * arg, expr_ref & result); br_status mk_set_difference(expr * arg1, expr * arg2, expr_ref & result); br_status mk_set_subset(expr * arg1, expr * arg2, expr_ref & result); + br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result); }; #endif diff --git a/src/ast/rewriter/array_rewriter_params.pyg b/src/ast/rewriter/array_rewriter_params.pyg index 2e3ae9f6a..a43fadecf 100644 --- a/src/ast/rewriter/array_rewriter_params.pyg +++ b/src/ast/rewriter/array_rewriter_params.pyg @@ -2,4 +2,5 @@ def_module_params(module_name='rewriter', class_name='array_rewriter_params', export=True, params=(("expand_select_store", BOOL, False, "replace a (select (store ...) ...) term by an if-then-else term"), + ("expand_store_eq", BOOL, False, "reduce (store ...) = (store ...) with a common base into selects"), ("sort_store", BOOL, False, "sort nested stores when the indices are known to be different"))) diff --git a/src/ast/rewriter/mk_simplified_app.cpp b/src/ast/rewriter/mk_simplified_app.cpp index da615e195..a46e71582 100644 --- a/src/ast/rewriter/mk_simplified_app.cpp +++ b/src/ast/rewriter/mk_simplified_app.cpp @@ -62,6 +62,8 @@ struct mk_simplified_app::imp { st = m_dt_rw.mk_eq_core(args[0], args[1], result); else if (s_fid == m_f_rw.get_fid()) st = m_f_rw.mk_eq_core(args[0], args[1], result); + else if (s_fid == m_ar_rw.get_fid()) + st = m_ar_rw.mk_eq_core(args[0], args[1], result); if (st != BR_FAILED) return st; diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 966544b78..5d19c53e3 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -169,7 +169,9 @@ struct th_rewriter_cfg : public default_rewriter_cfg { st = m_dt_rw.mk_eq_core(args[0], args[1], result); else if (s_fid == m_f_rw.get_fid()) st = m_f_rw.mk_eq_core(args[0], args[1], result); - + else if (s_fid == m_ar_rw.get_fid()) + st = m_ar_rw.mk_eq_core(args[0], args[1], result); + if (st != BR_FAILED) return st; } From ac6488a19533166798b9cb733748cd844d3ed343 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 13 May 2013 13:21:45 -0700 Subject: [PATCH 138/281] relax pre-processing to untangle non-horn formulas, based on Eldarica/linear benchmarks Signed-off-by: Nikolaj Bjorner --- src/muz_qe/horn_tactic.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 5db4f1a00..9d331cbfa 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -124,6 +124,15 @@ class horn_tactic : public tactic { enum formula_kind { IS_RULE, IS_QUERY, IS_NONE }; + bool is_implication(expr* f) { + expr* e1; + while (is_forall(f)) { + f = to_quantifier(f)->get_expr(); + } + while (m.is_implies(f, e1, f)) ; + return is_predicate(f); + } + formula_kind get_formula_kind(expr_ref& f) { expr_ref tmp(f); normalize(tmp); @@ -149,7 +158,10 @@ class horn_tactic : public tactic { } } if (head) { - // f = m.mk_implies(f, head); + if (!is_implication(f)) { + f = m.mk_and(body.size(), body.c_ptr()); + f = m.mk_implies(f, head); + } return IS_RULE; } else { @@ -200,6 +212,7 @@ class horn_tactic : public tactic { break; default: msg << "formula is not in Horn fragment: " << mk_pp(g->form(i), m) << "\n"; + TRACE("horn", tout << msg.str();); throw tactic_exception(msg.str().c_str()); } } @@ -230,7 +243,15 @@ class horn_tactic : public tactic { model_converter_ref & mc, proof_converter_ref & pc) { - lbool is_reachable = m_ctx.query(q); + lbool is_reachable = l_undef; + + try { + is_reachable = m_ctx.query(q); + } + catch (default_exception& ex) { + IF_VERBOSE(1, verbose_stream() << ex.msg() << "\n";); + throw ex; + } g->inc_depth(); bool produce_models = g->models_enabled(); From 7fc93b94f54439fec2dc993415fdb0c6c0c86342 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 14 May 2013 08:54:04 -0700 Subject: [PATCH 139/281] remove unimplemented method Signed-off-by: Nuno Lopes --- src/tactic/aig/aig.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tactic/aig/aig.h b/src/tactic/aig/aig.h index 96aa59ee6..c8befd9b2 100644 --- a/src/tactic/aig/aig.h +++ b/src/tactic/aig/aig.h @@ -70,7 +70,6 @@ public: void max_sharing(aig_ref & r); void to_formula(aig_ref const & r, expr_ref & result); void to_formula(aig_ref const & r, goal & result); - void to_cnf(aig_ref const & r, goal & result); void display(std::ostream & out, aig_ref const & r) const; void display_smt2(std::ostream & out, aig_ref const & r) const; unsigned get_num_aigs() const; From 878d57d139b4be7344dfb2c0678b06efa8bf06ad Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 15 May 2013 09:23:57 -0700 Subject: [PATCH 140/281] minor code simplification Signed-off-by: Nuno Lopes --- src/tactic/aig/aig.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index 997ec642e..9fdce96e9 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -869,11 +869,7 @@ struct aig_manager::imp { void mk_ite(aig * n) { aig_lit c, t, e; -#ifdef Z3DEBUG - bool ok = -#endif - m.is_ite(n, c, t, e); - SASSERT(ok); + VERIFY(m.is_ite(n, c, t, e)); if (c.is_inverted()) { c.invert(); std::swap(t, e); From e6c814987328f1bc7951f78bf66724f956e19a84 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 15 May 2013 10:50:46 -0700 Subject: [PATCH 141/281] horn rule bit blaster: fix propagation of output predicates when arity == 0 Signed-off-by: Nuno Lopes --- src/muz_qe/dl_mk_bit_blast.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 51a9d5927..a1eeac6f5 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -141,13 +141,17 @@ namespace datalog { func_decl_ref_vector const& new_funcs() const { return m_new_funcs; } br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { - bool found = false; - for (unsigned j = 0; !found && j < num; ++j) { - found = m_util.is_mkbv(args[j]); - } - if (!found) { + if (num == 0) { + if (m_src->is_output_predicate(f)) + m_dst->set_output_predicate(f); return BR_FAILED; } + + for (unsigned i = 0; i < num; ++i) { + if (!m_util.is_mkbv(args[i])) + return BR_FAILED; + } + // // f(mk_bv(args),...) // @@ -260,7 +264,7 @@ namespace datalog { m_rewriter.m_cfg.set_dst(result); for (unsigned i = 0; !m_context.canceled() && i < sz; ++i) { rule * r = source.get_rule(i); - r->to_formula(fml); + r->to_formula(fml); if (blast(r, fml)) { proof_ref pr(m); if (m_context.generate_proof_trace()) { From 5efdc58194ccc00490772c49ff4ba783fb80d520 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 15 May 2013 13:17:00 -0700 Subject: [PATCH 142/281] horn clause bit blasting: propagate output predicates for predicates without rules (most likely an UNSAT prog) Signed-off-by: Nuno Lopes --- src/muz_qe/dl_mk_bit_blast.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index a1eeac6f5..136b8ffae 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -279,6 +279,13 @@ namespace datalog { result->add_rule(r); } } + + // copy output predicates without any rule (bit-blasting not really needed) + const func_decl_set& decls = source.get_output_predicates(); + for (func_decl_set::iterator I = decls.begin(), E = decls.end(); I != E; ++I) { + if (!result->contains(*I)) + result->set_output_predicate(*I); + } if (m_context.get_model_converter()) { filter_model_converter* fmc = alloc(filter_model_converter, m); From 100e396618cef0f836304b24a15572d21146c46c Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 15 May 2013 13:33:42 -0700 Subject: [PATCH 143/281] fix typo in my previous commit Signed-off-by: Nuno Lopes --- src/muz_qe/dl_mk_bit_blast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz_qe/dl_mk_bit_blast.cpp index 136b8ffae..271003fff 100644 --- a/src/muz_qe/dl_mk_bit_blast.cpp +++ b/src/muz_qe/dl_mk_bit_blast.cpp @@ -283,7 +283,7 @@ namespace datalog { // copy output predicates without any rule (bit-blasting not really needed) const func_decl_set& decls = source.get_output_predicates(); for (func_decl_set::iterator I = decls.begin(), E = decls.end(); I != E; ++I) { - if (!result->contains(*I)) + if (!source.contains(*I)) result->set_output_predicate(*I); } From 6560fc0a2c85d8acb4289fc6d760b71877b36500 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 16 May 2013 09:58:31 -0700 Subject: [PATCH 144/281] add experimental Horn clause to AIG (AAG format) converter. Clauses should be over booleans only (or bit-blasted with fixedpoint.bit_blast=true). We will crash if that's not the case. Only linear clauses supported for now Signed-off-by: Nuno Lopes --- scripts/mk_project.py | 2 +- src/muz_qe/aig_exporter.cpp | 321 +++++++++++++++++++++++++++++++ src/muz_qe/aig_exporter.h | 66 +++++++ src/muz_qe/fixedpoint_params.pyg | 1 + src/muz_qe/rel_context.cpp | 8 + src/muz_qe/rel_context.h | 3 +- 6 files changed, 398 insertions(+), 3 deletions(-) create mode 100755 src/muz_qe/aig_exporter.cpp create mode 100755 src/muz_qe/aig_exporter.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 6ea794040..e6e7d5dc8 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -54,7 +54,7 @@ def init_project_def(): add_lib('smt_tactic', ['smt'], 'smt/tactic') add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls') # TODO: split muz_qe into muz, qe. Perhaps, we should also consider breaking muz into muz and pdr. - add_lib('muz_qe', ['smt', 'sat', 'smt2parser']) + add_lib('muz_qe', ['smt', 'sat', 'smt2parser', 'aig_tactic']) add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'muz_qe'], 'tactic/smtlogics') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'muz_qe', 'sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') diff --git a/src/muz_qe/aig_exporter.cpp b/src/muz_qe/aig_exporter.cpp new file mode 100755 index 000000000..1b0dae1ba --- /dev/null +++ b/src/muz_qe/aig_exporter.cpp @@ -0,0 +1,321 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + aig_exporter.cpp + +Abstract: + + Export AIG files from horn clauses + +--*/ + +#include "aig_exporter.h" +#include "dl_context.h" +#include + +namespace datalog { + + aig_exporter::aig_exporter(const rule_set& rules, context& ctx, const fact_vector *facts) : + m_rules(rules), m_facts(facts), m(ctx.get_manager()), m_rm(ctx.get_rule_manager()), + m_aigm(m), m_next_decl_id(1), m_next_aig_expr_id(2), m_num_and_gates(0), + m_latch_vars(m), m_latch_varsp(m), m_ruleid_var_set(m), m_ruleid_varp_set(m) + { + std::set predicates; + unsigned num_variables = 0; + for (rule_set::decl2rules::iterator I = m_rules.begin_grouped_rules(), + E = m_rules.end_grouped_rules(); I != E; ++I) { + predicates.insert(I->m_key); + num_variables = std::max(num_variables, I->m_key->get_arity()); + } + + for (fact_vector::const_iterator I = facts->begin(), E = facts->end(); I != E; ++I) { + predicates.insert(I->first); + num_variables = std::max(num_variables, I->first->get_arity()); + } + + // reserve pred id = 0 for initalization purposes + unsigned num_preds = (unsigned)predicates.size() + 1; + + // poor's man round-up log2 + unsigned preds_bitsize = log2(num_preds); + if ((1U << preds_bitsize) < num_preds) + ++preds_bitsize; + SASSERT((1U << preds_bitsize) >= num_preds); + + for (unsigned i = 0; i < preds_bitsize; ++i) { + m_ruleid_var_set.push_back(m.mk_fresh_const("rule_id", m.mk_bool_sort())); + m_ruleid_varp_set.push_back(m.mk_fresh_const("rule_id_p", m.mk_bool_sort())); + } + + for (unsigned i = 0; i < num_variables; ++i) { + m_latch_vars.push_back(m.mk_fresh_const("latch_var", m.mk_bool_sort())); + m_latch_varsp.push_back(m.mk_fresh_const("latch_varp", m.mk_bool_sort())); + } + } + + void aig_exporter::assert_pred_id(func_decl *decl, const expr_ref_vector& vars, expr_ref_vector& exprs) { + unsigned id = 0; + if (decl && !m_decl_id_map.find(decl, id)) { + id = m_next_decl_id++; + SASSERT(id < (1U << vars.size())); + m_decl_id_map.insert(decl, id); + } + + for (unsigned i = 0; i < vars.size(); ++i) { + exprs.push_back((id & (1U << i)) ? vars[i] : m.mk_not(vars[i])); + } + } + + void aig_exporter::collect_var_substs(substitution& subst, const app *h, + const expr_ref_vector& vars, expr_ref_vector& eqs) { + for (unsigned i = 0; i < h->get_num_args(); ++i) { + expr *arg = h->get_arg(i); + expr *latchvar = vars.get(i); + + if (is_var(arg)) { + var *v = to_var(arg); + expr_offset othervar; + if (subst.find(v, 0, othervar)) { + eqs.push_back(m.mk_eq(latchvar, othervar.get_expr())); + } else { + subst.insert(v, 0, expr_offset(latchvar, 0)); + } + } else { + eqs.push_back(m.mk_eq(latchvar, arg)); + } + } + } + + void aig_exporter::operator()(std::ostream& out) { + expr_ref_vector transition_function(m), output_preds(m); + var_ref_vector input_vars(m); + + rule_counter& vc = m_rm.get_counter(); + expr_ref_vector exprs(m); + substitution subst(m); + + for (rule_set::decl2rules::iterator I = m_rules.begin_grouped_rules(), + E = m_rules.end_grouped_rules(); I != E; ++I) { + for (rule_vector::iterator II = I->get_value()->begin(), + EE = I->get_value()->end(); II != EE; ++II) { + rule *r = *II; + unsigned numqs = r->get_positive_tail_size(); + if (numqs > 1) { + std::cerr << "non-linear clauses not supported\n"; + exit(-1); + } + + if (numqs != r->get_uninterpreted_tail_size()) { + std::cerr << "negation of queries not supported\n"; + exit(-1); + } + + exprs.reset(); + assert_pred_id(numqs ? r->get_tail(0)->get_decl() : 0, m_ruleid_var_set, exprs); + assert_pred_id(r->get_head()->get_decl(), m_ruleid_varp_set, exprs); + + subst.reset(); + subst.reserve(1, vc.get_max_rule_var(*r)+1); + if (numqs) + collect_var_substs(subst, r->get_tail(0), m_latch_vars, exprs); + collect_var_substs(subst, r->get_head(), m_latch_varsp, exprs); + + for (unsigned i = numqs; i < r->get_tail_size(); ++i) { + expr_ref e(m); + subst.apply(r->get_tail(i), e); + exprs.push_back(e); + } + + transition_function.push_back(m.mk_and(exprs.size(), exprs.c_ptr())); + } + } + + // collect table facts + if (m_facts) { + for (fact_vector::const_iterator I = m_facts->begin(), E = m_facts->end(); I != E; ++I) { + exprs.reset(); + assert_pred_id(0, m_ruleid_var_set, exprs); + assert_pred_id(I->first, m_ruleid_varp_set, exprs); + + for (unsigned i = 0; i < I->second.size(); ++i) { + exprs.push_back(m.mk_eq(m_latch_varsp.get(i), I->second[i])); + } + + transition_function.push_back(m.mk_and(exprs.size(), exprs.c_ptr())); + } + } + + expr *tr = m.mk_or(transition_function.size(), transition_function.c_ptr()); + aig_ref aig = m_aigm.mk_aig(tr); + expr_ref aig_expr(m); + m_aigm.to_formula(aig, aig_expr); + +#if 0 + std::cout << mk_pp(tr, m) << "\n\n"; + std::cout << mk_pp(aig_expr, m) << "\n\n"; +#endif + + // make rule_id vars latches + for (unsigned i = 0; i < m_ruleid_var_set.size(); ++i) { + m_latch_vars.push_back(m_ruleid_var_set.get(i)); + m_latch_varsp.push_back(m_ruleid_varp_set.get(i)); + } + + // create vars for latches + for (unsigned i = 0; i < m_latch_vars.size(); ++i) { + mk_var(m_latch_vars.get(i)); + mk_input_var(m_latch_varsp.get(i)); + } + + unsigned tr_id = expr_to_aig(aig_expr); + + // create latch next state variables: (ite tr varp var) + unsigned_vector latch_varp_ids; + for (unsigned i = 0; i < m_latch_vars.size(); ++i) { + unsigned in_val = mk_and(tr_id, get_var(m_latch_varsp.get(i))); + unsigned latch_val = mk_and(neg(tr_id), get_var(m_latch_vars.get(i))); + latch_varp_ids.push_back(mk_or(in_val, latch_val)); + } + m_latch_varsp.reset(); + + // create output variable (true iff an output predicate is derivable) + unsigned output_id = 0; + { + expr_ref_vector output(m); + const func_decl_set& preds = m_rules.get_output_predicates(); + + for (func_decl_set::iterator I = preds.begin(), E = preds.end(); I != E; ++I) { + exprs.reset(); + assert_pred_id(*I, m_ruleid_var_set, exprs); + output.push_back(m.mk_and(exprs.size(), exprs.c_ptr())); + } + + expr *out = m.mk_or(output.size(), output.c_ptr()); + aig = m_aigm.mk_aig(out); + m_aigm.to_formula(aig, aig_expr); + output_id = expr_to_aig(aig_expr); + +#if 0 + std::cout << "output formula\n"; + std::cout << mk_pp(out, m) << "\n\n"; + std::cout << mk_pp(aig_expr, m) << "\n\n"; +#endif + } + + // 1) print header + // aag var_index inputs latches outputs andgates + out << "aag " << (m_next_aig_expr_id-1)/2 << ' ' << m_input_vars.size() + << ' ' << m_latch_vars.size() << " 1 " << m_num_and_gates << '\n'; + + // 2) print inputs + for (unsigned i = 0; i < m_input_vars.size(); ++i) { + out << m_input_vars[i] << '\n'; + } + + // 3) print latches + for (unsigned i = 0; i < m_latch_vars.size(); ++i) { + out << get_var(m_latch_vars.get(i)) << ' ' << latch_varp_ids[i] << '\n'; + } + + // 4) print outputs (just one for now) + out << output_id << '\n'; + + // 5) print formula + out << m_buffer.str(); + } + + unsigned aig_exporter::expr_to_aig(const expr *e) { + unsigned id; + if (m_aig_expr_id_map.find(e, id)) + return id; + + switch (e->get_kind()) { + case AST_APP: { + const app *a = to_app(e); + switch (a->get_decl_kind()) { + case OP_OR: + SASSERT(a->get_num_args() > 0); + id = expr_to_aig(a->get_arg(0)); + for (unsigned i = 1; i < a->get_num_args(); ++i) { + id = mk_or(id, expr_to_aig(a->get_arg(i))); + } + m_aig_expr_id_map.insert(e, id); + return id; + + case null_decl_kind: + return get_var(a); + + case OP_NOT: + return neg(expr_to_aig(a->get_arg(0))); + + case OP_FALSE: + return 0; + + case OP_TRUE: + return 1; + } + break;} + + case AST_VAR: + return get_var(e); + } + + UNREACHABLE(); + return 0; + } + + unsigned aig_exporter::neg(unsigned id) const { + return (id % 2) ? (id-1) : (id+1); + } + + unsigned aig_exporter::mk_and(unsigned id1, unsigned id2) { + if (id1 > id2) + std::swap(id1, id2); + + std::pair key(id1, id2); + and_gates_map::const_iterator I = m_and_gates_map.find(key); + if (I != m_and_gates_map.end()) + return I->second; + + unsigned id = mk_expr_id(); + m_buffer << id << ' ' << id1 << ' ' << id2 << '\n'; + m_and_gates_map[key] = id; + ++m_num_and_gates; + return id; + } + + unsigned aig_exporter::mk_or(unsigned id1, unsigned id2) { + return neg(mk_and(neg(id1), neg(id2))); + } + + unsigned aig_exporter::get_var(const expr *e) { + unsigned id; + if (m_aig_expr_id_map.find(e, id)) + return id; + return mk_input_var(e); + } + + unsigned aig_exporter::mk_var(const expr *e) { + SASSERT(!m_aig_expr_id_map.contains(e)); + unsigned id = mk_expr_id(); + m_aig_expr_id_map.insert(e, id); + return id; + } + + unsigned aig_exporter::mk_input_var(const expr *e) { + SASSERT(!m_aig_expr_id_map.contains(e)); + unsigned id = mk_expr_id(); + m_input_vars.push_back(id); + if (e) + m_aig_expr_id_map.insert(e, id); + return id; + } + + unsigned aig_exporter::mk_expr_id() { + unsigned id = m_next_aig_expr_id; + m_next_aig_expr_id += 2; + return id; + } +} diff --git a/src/muz_qe/aig_exporter.h b/src/muz_qe/aig_exporter.h new file mode 100755 index 000000000..f70945e7f --- /dev/null +++ b/src/muz_qe/aig_exporter.h @@ -0,0 +1,66 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + aig_exporter.h + +Abstract: + + Export AIG files from horn clauses + +--*/ + +#ifndef _AIG_EXPORTER_H_ +#define _AIG_EXPORTER_H_ + +#include "aig.h" +#include "dl_rule_set.h" +#include "rel_context.h" +#include +#include + +namespace datalog { + class aig_exporter { + public: + aig_exporter(const rule_set& rules, context& ctx, const fact_vector *facts = 0); + void operator()(std::ostream& out); + + private: + typedef obj_map decl_id_map; + typedef obj_map aig_expr_id_map; + typedef std::map, unsigned> and_gates_map; + + const rule_set& m_rules; + const fact_vector *m_facts; + ast_manager& m; + rule_manager& m_rm; + aig_manager m_aigm; + decl_id_map m_decl_id_map; + unsigned m_next_decl_id; + aig_expr_id_map m_aig_expr_id_map; + unsigned m_next_aig_expr_id; + and_gates_map m_and_gates_map; + unsigned m_num_and_gates; + + expr_ref_vector m_latch_vars, m_latch_varsp; + expr_ref_vector m_ruleid_var_set, m_ruleid_varp_set; + unsigned_vector m_input_vars; + + std::stringstream m_buffer; + + void assert_pred_id(func_decl *decl, const expr_ref_vector& vars, expr_ref_vector& exprs); + void collect_var_substs(substitution& subst, const app *h, + const expr_ref_vector& vars, expr_ref_vector& eqs); + unsigned expr_to_aig(const expr *e); + unsigned neg(unsigned id) const; + unsigned mk_and(unsigned id1, unsigned id2); + unsigned mk_or(unsigned id1, unsigned id2); + unsigned get_var(const expr *e); + unsigned mk_var(const expr *e); + unsigned mk_input_var(const expr *e = 0); + unsigned mk_expr_id(); + }; +} + +#endif diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index c516806a6..c2d33cb05 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -62,6 +62,7 @@ def_module_params('fixedpoint', ('print_statistics', BOOL, False, 'print statistics'), ('use_utvpi', BOOL, False, 'experimental use UTVPI strategy'), ('tab_selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), + ('dump_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'), )) diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index b42adca79..7ad91ecb6 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -32,6 +32,7 @@ Revision History: #include"dl_sparse_table.h" #include"dl_table.h" #include"dl_table_relation.h" +#include"aig_exporter.h" namespace datalog { @@ -127,6 +128,13 @@ namespace datalog { } TRACE("dl", m_context.display(tout);); + if (m_context.get_params().dump_aig().size()) { + const char *filename = static_cast(m_context.get_params().dump_aig().c_ptr()); + aig_exporter aig(m_context.get_rules(), get_context(), &m_table_facts); + aig(std::ofstream(filename, std::ios_base::binary)); + exit(0); + } + compiler::compile(m_context, m_context.get_rules(), m_code, termination_code); TRACE("dl", m_code.display(*this, tout); ); diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index 8e4c6f2de..7b4ee551c 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -28,10 +28,9 @@ Revision History: namespace datalog { class context; + typedef vector > fact_vector; class rel_context { - typedef vector > fact_vector; - context& m_context; ast_manager& m; relation_manager m_rmanager; From 69b7c3ede7ef06e90a8529aac2c29975c3cb9d41 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 16 May 2013 15:36:27 -0700 Subject: [PATCH 145/281] fixing parity bug in model generation for UTVPI Signed-off-by: Nikolaj Bjorner --- src/smt/diff_logic.h | 80 +++++++++++++++++++++++--- src/smt/theory_utvpi.h | 6 +- src/smt/theory_utvpi_def.h | 115 ++++++++++++++++++++++++++++++++----- 3 files changed, 179 insertions(+), 22 deletions(-) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 7216bba7e..020268e57 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -306,14 +306,6 @@ private: return true; } - // Update the assignment of variable v, that is, - // m_assignment[v] += inc - // This method also stores the old value of v in the assignment stack. - void acc_assignment(dl_var v, const numeral & inc) { - TRACE("diff_logic_bug", tout << "update v: " << v << " += " << inc << " m_assignment[v] " << m_assignment[v] << "\n";); - m_assignment_stack.push_back(assignment_trail(v, m_assignment[v])); - m_assignment[v] += inc; - } // Restore the assignment using the information in m_assignment_stack. // This method is called when make_feasible fails. @@ -827,6 +819,16 @@ public: } } + // Update the assignment of variable v, that is, + // m_assignment[v] += inc + // This method also stores the old value of v in the assignment stack. + void acc_assignment(dl_var v, const numeral & inc) { + TRACE("diff_logic_bug", tout << "update v: " << v << " += " << inc << " m_assignment[v] " << m_assignment[v] << "\n";); + m_assignment_stack.push_back(assignment_trail(v, m_assignment[v])); + m_assignment[v] += inc; + } + + struct every_var_proc { bool operator()(dl_var v) const { return true; @@ -837,6 +839,36 @@ public: display_core(out, every_var_proc()); } + void display_agl(std::ostream & out) const { + uint_set vars; + typename edges::const_iterator it = m_edges.begin(); + typename edges::const_iterator end = m_edges.end(); + for (; it != end; ++it) { + edge const& e = *it; + if (e.is_enabled()) { + vars.insert(e.get_source()); + vars.insert(e.get_target()); + } + } + out << "digraph "" {\n"; + + unsigned n = m_assignment.size(); + for (unsigned v = 0; v < n; v++) { + if (vars.contains(v)) { + out << "\"" << v << "\" [label=\"" << v << ":" << m_assignment[v] << "\"]\n"; + } + } + it = m_edges.begin(); + for (; it != end; ++it) { + edge const& e = *it; + if (e.is_enabled()) { + out << "\"" << e.get_source() << "\"->\"" << e.get_target() << "\"[label=\"" << e.get_weight() << "\"]\n"; + } + } + + out << "}\n"; + } + template void display_core(std::ostream & out, FilterAssignmentProc p) const { display_edges(out); @@ -1000,6 +1032,38 @@ public: } } + void compute_zero_succ(dl_var v, int_vector& succ) { + unsigned n = m_assignment.size(); + m_dfs_time.reset(); + m_dfs_time.resize(n, -1); + m_dfs_time[v] = 0; + succ.push_back(v); + numeral gamma; + for (unsigned i = 0; i < succ.size(); ++i) { + v = succ[i]; + edge_id_vector & edges = m_out_edges[v]; + typename edge_id_vector::iterator it = edges.begin(); + typename edge_id_vector::iterator end = edges.end(); + for (; it != end; ++it) { + edge_id e_id = *it; + edge & e = m_edges[e_id]; + if (!e.is_enabled()) { + continue; + } + SASSERT(e.get_source() == v); + set_gamma(e, gamma); + if (gamma.is_zero()) { + dl_var target = e.get_target(); + if (m_dfs_time[target] == -1) { + succ.push_back(target); + m_dfs_time[target] = 0; + } + } + } + + } + } + numeral get_assignment(dl_var v) const { return m_assignment[v]; } diff --git a/src/smt/theory_utvpi.h b/src/smt/theory_utvpi.h index a9dd869a9..4a5d97d52 100644 --- a/src/smt/theory_utvpi.h +++ b/src/smt/theory_utvpi.h @@ -262,7 +262,11 @@ namespace smt { private: - rational mk_value(theory_var v); + rational mk_value(theory_var v, bool is_int); + + bool is_parity_ok(unsigned v) const; + + void enforce_parity(); void validate_model(); diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index 457ac83ad..6c59b568e 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -397,7 +397,6 @@ namespace smt { template final_check_status theory_utvpi::final_check_eh() { SASSERT(is_consistent()); - TRACE("utvpi", display(tout);); if (can_propagate()) { propagate(); return FC_CONTINUE; @@ -424,7 +423,7 @@ namespace smt { unsigned sz = get_num_vars(); for (unsigned i = 0; i < sz; ++i) { enode* e = get_enode(i); - if (a.is_int(e->get_owner())) { + if (!a.is_int(e->get_owner())) { continue; } th_var v1 = to_var(i); @@ -511,7 +510,7 @@ namespace smt { template theory_var theory_utvpi::mk_term(app* n) { - TRACE("utvpi", tout << mk_pp(n, get_manager()) << "\n";); + TRACE("utvpi", tout << mk_pp(n, get_manager()) << "\n";); context& ctx = get_context(); bool cl = m_test.linearize(n); @@ -519,7 +518,7 @@ namespace smt { found_non_utvpi_expr(n); return null_theory_var; } - + coeffs coeffs; rational w; mk_coeffs(m_test.get_linearization(), coeffs, w); @@ -667,14 +666,80 @@ namespace smt { return m_graph.is_feasible(); } + + template + bool theory_utvpi::is_parity_ok(unsigned i) const { + th_var v1 = to_var(i); + th_var v2 = neg(v1); + rational r1 = m_graph.get_assignment(v1).get_rational(); + rational r2 = m_graph.get_assignment(v2).get_rational(); + return r1.is_even() == r2.is_even(); + } + + + template + void theory_utvpi::enforce_parity() { + unsigned_vector todo; + + unsigned sz = get_num_vars(); + for (unsigned i = 0; i < sz; ++i) { + enode* e = get_enode(i); + if (a.is_int(e->get_owner()) && !is_parity_ok(i)) { + todo.push_back(i); + } + } + if (todo.empty()) { + return; + } + while (!todo.empty()) { + unsigned i = todo.back(); + if (is_parity_ok(i)) { + continue; + } + todo.pop_back(); + th_var v1 = to_var(i); + th_var v2 = neg(v1); + TRACE("utvpi", tout << "disparity: " << v1 << "\n";); + int_vector zero_v; + m_graph.compute_zero_succ(v1, zero_v); + bool found0 = false; + for (unsigned j = 0; !found0 && j < zero_v.size(); ++j) { + found0 = + (to_var(m_zero_int) == zero_v[j]) || + (neg(to_var(m_zero_int)) == zero_v[j]); + } + if (found0) { + zero_v.reset(); + m_graph.compute_zero_succ(v2, zero_v); + } + TRACE("utvpi", + for (unsigned j = 0; j < zero_v.size(); ++j) { + tout << "increment: " << zero_v[j] << "\n"; + }); + + for (unsigned j = 0; j < zero_v.size(); ++j) { + int v = zero_v[j]; + m_graph.acc_assignment(v, numeral(1)); + th_var k = from_var(v); + if (!is_parity_ok(k)) { + TRACE("utvpi", tout << "new disparity: " << k << "\n";); + todo.push_back(k); + } + } + } + } + + // models: template void theory_utvpi::init_model(model_generator & m) { m_factory = alloc(arith_factory, get_manager()); m.register_factory(m_factory); - // TBD: enforce strong or tight coherence? + // TBD: enforce strong or tight coherence + enforce_parity(); compute_delta(); - DEBUG_CODE(validate_model();); + // DEBUG_CODE(validate_model();); + validate_model(); } template @@ -688,7 +753,8 @@ namespace smt { } bool ok = true; expr* e = ctx.bool_var2expr(b); - switch(ctx.get_assignment(b)) { + lbool assign = ctx.get_assignment(b); + switch(assign) { case l_true: ok = eval(e); break; @@ -698,7 +764,23 @@ namespace smt { default: break; } - CTRACE("utvpi", !ok, tout << "validation failed: " << mk_pp(e, get_manager()) << "\n";); + CTRACE("utvpi", !ok, + tout << "validation failed:\n"; + tout << "Assignment: " << assign << "\n"; + m_atoms[i].display(*this, tout); + tout << "\n"; + display(tout); + m_graph.display_agl(tout); + ); + if (!ok) { + std::cout << "validation failed:\n"; + std::cout << "Assignment: " << assign << "\n"; + m_atoms[i].display(*this, std::cout); + std::cout << "\n"; + display(std::cout); + m_graph.display_agl(std::cout); + + } // CTRACE("utvpi", ok, tout << "validation success: " << mk_pp(e, get_manager()) << "\n";); SASSERT(ok); } @@ -751,7 +833,7 @@ namespace smt { return eval_num(e1); } if (is_uninterp_const(e)) { - return mk_value(mk_var(e)); + return mk_value(mk_var(e), a.is_int(e)); } TRACE("utvpi", tout << "expression not handled: " << mk_pp(e, get_manager()) << "\n";); UNREACHABLE(); @@ -760,23 +842,30 @@ namespace smt { template - rational theory_utvpi::mk_value(th_var v) { + rational theory_utvpi::mk_value(th_var v, bool is_int) { SASSERT(v != null_theory_var); numeral val1 = m_graph.get_assignment(to_var(v)); numeral val2 = m_graph.get_assignment(neg(to_var(v))); numeral val = val1 - val2; rational num = val.get_rational() + (m_delta * val.get_infinitesimal().to_rational()); num = num/rational(2); - num = floor(num); + if (is_int && !num.is_int()) { + num = floor(num); + } + TRACE("utvpi", + expr* n = get_enode(v)->get_owner(); + tout << mk_pp(n, get_manager()) << " |-> (" << val1 << " - " << val2 << ")/2 = " << num << "\n";); + return num; } template model_value_proc * theory_utvpi::mk_value(enode * n, model_generator & mg) { theory_var v = n->get_th_var(get_id()); - rational num = mk_value(v); + bool is_int = a.is_int(n->get_owner()); + rational num = mk_value(v, is_int); TRACE("utvpi", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";); - return alloc(expr_wrapper_proc, m_factory->mk_value(num, a.is_int(n->get_owner()))); + return alloc(expr_wrapper_proc, m_factory->mk_value(num, is_int)); } /** From ef2a9994a92ca23f683862371677fbe7ff7eea76 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 16 May 2013 19:58:14 -0700 Subject: [PATCH 146/281] fix UTVPI model generation Signed-off-by: Nikolaj Bjorner --- src/smt/theory_utvpi_def.h | 48 ++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index 6c59b568e..6c85e40b9 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -33,7 +33,17 @@ Revision History: 3. Solve for x^+ and x^- 4. Check parity condition for integers (see Lahiri and Musuvathi 05) - 5. extract model for M(x) := (M(x^+)- M(x^-))/2 + This checks if x^+ and x^- are in the same component but of different + parities. + 5. Enforce parity on variables. This checks if x^+ and x^- have different + parities. If they have different parities, the assignment to one + of the variables is decremented (choose the variable that is not tightly + constrained with 0). + The process that adjusts parities converges: Suppose we break a parity + of a different variable y while fixing x's parity. A cyclic breaking/fixing + of parities implies there is a strongly connected component between x, y + and the two polarities of the variables. This contradicts the test in 4. + 6. extract model for M(x) := (M(x^+)- M(x^-))/2 --*/ @@ -677,6 +687,17 @@ namespace smt { } + /** + \brief adjust values for variables in the difference graph + such that for variables of integer sort it is + the case that x^+ - x^- is even. + The informal justification for the procedure enforce_parity is that + the graph does not contain a strongly connected component where + x^+ and x+- are connected. They can be independently changed. + Since we would like variables representing 0 (zero) map to 0, + we selectively update the subgraph that can be updated without + changing the value of zero (which should be 0). + */ template void theory_utvpi::enforce_parity() { unsigned_vector todo; @@ -693,10 +714,10 @@ namespace smt { } while (!todo.empty()) { unsigned i = todo.back(); + todo.pop_back(); if (is_parity_ok(i)) { continue; } - todo.pop_back(); th_var v1 = to_var(i); th_var v2 = neg(v1); TRACE("utvpi", tout << "disparity: " << v1 << "\n";); @@ -708,18 +729,20 @@ namespace smt { (to_var(m_zero_int) == zero_v[j]) || (neg(to_var(m_zero_int)) == zero_v[j]); } + // variables that are tightly connected + // to 0 should not have their values changed. if (found0) { zero_v.reset(); m_graph.compute_zero_succ(v2, zero_v); } TRACE("utvpi", for (unsigned j = 0; j < zero_v.size(); ++j) { - tout << "increment: " << zero_v[j] << "\n"; + tout << "decrement: " << zero_v[j] << "\n"; }); for (unsigned j = 0; j < zero_v.size(); ++j) { int v = zero_v[j]; - m_graph.acc_assignment(v, numeral(1)); + m_graph.acc_assignment(v, numeral(-1)); th_var k = from_var(v); if (!is_parity_ok(k)) { TRACE("utvpi", tout << "new disparity: " << k << "\n";); @@ -727,6 +750,15 @@ namespace smt { } } } + SASSERT(m_graph.is_feasible()); + DEBUG_CODE( + for (unsigned i = 0; i < sz; ++i) { + enode* e = get_enode(i); + if (a.is_int(e->get_owner()) && !is_parity_ok(i)) { + IF_VERBOSE(0, verbose_stream() << "disparities not fixed\n";); + UNREACHABLE(); + } + }); } @@ -735,11 +767,9 @@ namespace smt { void theory_utvpi::init_model(model_generator & m) { m_factory = alloc(arith_factory, get_manager()); m.register_factory(m_factory); - // TBD: enforce strong or tight coherence enforce_parity(); compute_delta(); - // DEBUG_CODE(validate_model();); - validate_model(); + DEBUG_CODE(validate_model();); } template @@ -849,9 +879,7 @@ namespace smt { numeral val = val1 - val2; rational num = val.get_rational() + (m_delta * val.get_infinitesimal().to_rational()); num = num/rational(2); - if (is_int && !num.is_int()) { - num = floor(num); - } + SASSERT(!is_int || num.is_int()); TRACE("utvpi", expr* n = get_enode(v)->get_owner(); tout << mk_pp(n, get_manager()) << " |-> (" << val1 << " - " << val2 << ")/2 = " << num << "\n";); From 5d1339beec902151e801dba46cac633d201c2d8d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 17 May 2013 13:43:32 +0100 Subject: [PATCH 147/281] .NET/Java: API doc update for Context constructor. Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Context.cs | 15 +++++++++++++++ src/api/java/Context.java | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 35fe6611d..68cca046e 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -44,6 +44,21 @@ namespace Microsoft.Z3 /// /// Constructor. /// + /// + /// The following parameters can be set: + /// - proof (Boolean) Enable proof generation + /// - debug_ref_count (Boolean) Enable debug support for Z3_ast reference counting + /// - trace (Boolean) Tracing support for VCC + /// - trace_file_name (String) Trace out file for VCC traces + /// - timeout (unsigned) default timeout (in milliseconds) used for solvers + /// - well_sorted_check type checker + /// - auto_config use heuristics to automatically select solver and configure it + /// - model model generation for solvers, this parameter can be overwritten when creating a solver + /// - model_validate validate models produced by solvers + /// - unsat_core unsat-core generation for solvers, this parameter can be overwritten when creating a solver + /// Note that in previous versions of Z3, this constructor was also used to set global and module parameters. + /// For this purpose we should now use + /// public Context(Dictionary settings) : base() { diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 5277dab38..6b6c63ac3 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -27,6 +27,21 @@ public class Context extends IDisposable /** * Constructor. + * + * The following parameters can be set: + * - proof (Boolean) Enable proof generation + * - debug_ref_count (Boolean) Enable debug support for Z3_ast reference counting + * - trace (Boolean) Tracing support for VCC + * - trace_file_name (String) Trace out file for VCC traces + * - timeout (unsigned) default timeout (in milliseconds) used for solvers + * - well_sorted_check type checker + * - auto_config use heuristics to automatically select solver and configure it + * - model model generation for solvers, this parameter can be overwritten when creating a solver + * - model_validate validate models produced by solvers + * - unsat_core unsat-core generation for solvers, this parameter can be overwritten when creating a solver + * Note that in previous versions of Z3, this constructor was also used to set global and + * module parameters. For this purpose we should now use + * **/ public Context(Map settings) throws Z3Exception { From d1999b3424e6ad16a00867549db4ad1eb16b6000 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 17 May 2013 09:46:30 -0700 Subject: [PATCH 148/281] AIG exporter: create latches lazily properly check for constants Signed-off-by: Nuno Lopes --- src/muz_qe/aig_exporter.cpp | 23 ++++++++++++++--------- src/muz_qe/aig_exporter.h | 2 ++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/muz_qe/aig_exporter.cpp b/src/muz_qe/aig_exporter.cpp index 1b0dae1ba..c82ff7245 100755 --- a/src/muz_qe/aig_exporter.cpp +++ b/src/muz_qe/aig_exporter.cpp @@ -23,16 +23,13 @@ namespace datalog { m_latch_vars(m), m_latch_varsp(m), m_ruleid_var_set(m), m_ruleid_varp_set(m) { std::set predicates; - unsigned num_variables = 0; for (rule_set::decl2rules::iterator I = m_rules.begin_grouped_rules(), E = m_rules.end_grouped_rules(); I != E; ++I) { predicates.insert(I->m_key); - num_variables = std::max(num_variables, I->m_key->get_arity()); } for (fact_vector::const_iterator I = facts->begin(), E = facts->end(); I != E; ++I) { predicates.insert(I->first); - num_variables = std::max(num_variables, I->first->get_arity()); } // reserve pred id = 0 for initalization purposes @@ -48,11 +45,19 @@ namespace datalog { m_ruleid_var_set.push_back(m.mk_fresh_const("rule_id", m.mk_bool_sort())); m_ruleid_varp_set.push_back(m.mk_fresh_const("rule_id_p", m.mk_bool_sort())); } + } - for (unsigned i = 0; i < num_variables; ++i) { + void aig_exporter::mk_latch_vars(unsigned n) { + for (int i = m_latch_vars.size() - 1; i <= (int)n; ++i) { m_latch_vars.push_back(m.mk_fresh_const("latch_var", m.mk_bool_sort())); m_latch_varsp.push_back(m.mk_fresh_const("latch_varp", m.mk_bool_sort())); } + SASSERT(m_latch_vars.size() > n); + } + + expr* aig_exporter::get_latch_var(unsigned i, const expr_ref_vector& vars) { + mk_latch_vars(i); + return vars.get(i); } void aig_exporter::assert_pred_id(func_decl *decl, const expr_ref_vector& vars, expr_ref_vector& exprs) { @@ -72,7 +77,7 @@ namespace datalog { const expr_ref_vector& vars, expr_ref_vector& eqs) { for (unsigned i = 0; i < h->get_num_args(); ++i) { expr *arg = h->get_arg(i); - expr *latchvar = vars.get(i); + expr *latchvar = get_latch_var(i, vars); if (is_var(arg)) { var *v = to_var(arg); @@ -140,7 +145,7 @@ namespace datalog { assert_pred_id(I->first, m_ruleid_varp_set, exprs); for (unsigned i = 0; i < I->second.size(); ++i) { - exprs.push_back(m.mk_eq(m_latch_varsp.get(i), I->second[i])); + exprs.push_back(m.mk_eq(get_latch_var(i, m_latch_varsp), I->second[i])); } transition_function.push_back(m.mk_and(exprs.size(), exprs.c_ptr())); @@ -231,6 +236,9 @@ namespace datalog { if (m_aig_expr_id_map.find(e, id)) return id; + if (is_uninterp_const(e)) + return get_var(e); + switch (e->get_kind()) { case AST_APP: { const app *a = to_app(e); @@ -244,9 +252,6 @@ namespace datalog { m_aig_expr_id_map.insert(e, id); return id; - case null_decl_kind: - return get_var(a); - case OP_NOT: return neg(expr_to_aig(a->get_arg(0))); diff --git a/src/muz_qe/aig_exporter.h b/src/muz_qe/aig_exporter.h index f70945e7f..20b31f01b 100755 --- a/src/muz_qe/aig_exporter.h +++ b/src/muz_qe/aig_exporter.h @@ -49,6 +49,8 @@ namespace datalog { std::stringstream m_buffer; + void mk_latch_vars(unsigned n); + expr* get_latch_var(unsigned i, const expr_ref_vector& vars); void assert_pred_id(func_decl *decl, const expr_ref_vector& vars, expr_ref_vector& exprs); void collect_var_substs(substitution& subst, const app *h, const expr_ref_vector& vars, expr_ref_vector& eqs); From aea667d09bdac18dc244bc03a4f1b2301f5a34a8 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 17 May 2013 12:17:35 -0700 Subject: [PATCH 149/281] fix a one-too-many in my previous commit Signed-off-by: Nuno Lopes --- src/muz_qe/aig_exporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz_qe/aig_exporter.cpp b/src/muz_qe/aig_exporter.cpp index c82ff7245..1d6ef3633 100755 --- a/src/muz_qe/aig_exporter.cpp +++ b/src/muz_qe/aig_exporter.cpp @@ -48,7 +48,7 @@ namespace datalog { } void aig_exporter::mk_latch_vars(unsigned n) { - for (int i = m_latch_vars.size() - 1; i <= (int)n; ++i) { + for (unsigned i = m_latch_vars.size(); i <= n; ++i) { m_latch_vars.push_back(m.mk_fresh_const("latch_var", m.mk_bool_sort())); m_latch_varsp.push_back(m.mk_fresh_const("latch_varp", m.mk_bool_sort())); } From 56dedec740b3f7bf4c4ab35fa5758afc109a8e87 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 18 May 2013 10:02:53 -0700 Subject: [PATCH 150/281] fix build break include uint_set.h Signed-off-by: Nikolaj Bjorner --- src/smt/diff_logic.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 020268e57..6fd156e41 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -24,6 +24,7 @@ Revision History: #include"statistics.h" #include"trace.h" #include"warning.h" +#include"uint_set.h" typedef int dl_var; From dc91a754dd405b3348dd13f61a72207852869e9a Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 21 May 2013 10:48:55 -0700 Subject: [PATCH 151/281] improve clp solver - run default rule transformations - sort a predicate's rules by number of queries in the body to bias search Signed-off-by: Nuno Lopes --- src/muz_qe/clp_context.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/muz_qe/clp_context.cpp b/src/muz_qe/clp_context.cpp index 25ea1455b..5dd6fb9d8 100644 --- a/src/muz_qe/clp_context.cpp +++ b/src/muz_qe/clp_context.cpp @@ -66,9 +66,10 @@ namespace datalog { m_ctx.ensure_opened(); m_solver.reset(); m_goals.reset(); - rm.mk_query(query, m_ctx.get_rules()); - expr_ref head(m); - head = m_ctx.get_rules().last()->get_head(); + func_decl *head_decl = rm.mk_query(query, m_ctx.get_rules()); + m_ctx.apply_default_transformation(); + + expr_ref head(m_ctx.get_rules().get_predicate_rules(head_decl)[0]->get_head(), m); ground(head); m_goals.push_back(to_app(head)); return search(20, 0); @@ -125,6 +126,10 @@ namespace datalog { m_var_subst(e, m_ground.size(), m_ground.c_ptr(), e); } + static bool rule_sort_fn(const rule *r1, const rule *r2) { + return r1->get_uninterpreted_tail_size() < r2->get_uninterpreted_tail_size(); + } + lbool search(unsigned depth, unsigned index) { if (index == m_goals.size()) { return l_true; @@ -135,7 +140,10 @@ namespace datalog { IF_VERBOSE(1, verbose_stream() << "search " << depth << " " << index << "\n";); unsigned num_goals = m_goals.size(); app* head = m_goals[index].get(); - rule_vector const& rules = m_ctx.get_rules().get_predicate_rules(head->get_decl()); + + rule_vector rules(m_ctx.get_rules().get_predicate_rules(head->get_decl())); + std::stable_sort(rules.begin(), rules.end(), rule_sort_fn); + lbool status = l_false; for (unsigned i = 0; i < rules.size(); ++i) { rule* r = rules[i]; From 09945dc2cb753ea80951c2f084ec65f9e3528c3e Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 23 May 2013 08:07:19 -0700 Subject: [PATCH 152/281] Fix compilation error with gcc Signed-off-by: Leonardo de Moura --- src/muz_qe/rel_context.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 7ad91ecb6..63e8ba700 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -131,7 +131,8 @@ namespace datalog { if (m_context.get_params().dump_aig().size()) { const char *filename = static_cast(m_context.get_params().dump_aig().c_ptr()); aig_exporter aig(m_context.get_rules(), get_context(), &m_table_facts); - aig(std::ofstream(filename, std::ios_base::binary)); + std::ofstream strm(filename, std::ios_base::binary); + aig(strm); exit(0); } From ccf10d0abe86c86c66bc5e7908d3f5deda042d10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 25 May 2013 14:38:02 -0700 Subject: [PATCH 153/281] fix crash in PDR engine when transformations don't produce output predicates Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_slice.cpp | 6 ++++++ src/muz_qe/pdr_dl_interface.cpp | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/muz_qe/dl_mk_slice.cpp b/src/muz_qe/dl_mk_slice.cpp index 1a97c1b81..5b9d43acc 100644 --- a/src/muz_qe/dl_mk_slice.cpp +++ b/src/muz_qe/dl_mk_slice.cpp @@ -710,6 +710,7 @@ namespace datalog { void mk_slice::declare_predicates(rule_set const& src, rule_set& dst) { obj_map::iterator it = m_sliceable.begin(), end = m_sliceable.end(); ptr_vector domain; + bool has_output = false; func_decl* f; for (; it != end; ++it) { domain.reset(); @@ -731,8 +732,13 @@ namespace datalog { } else if (src.is_output_predicate(p)) { dst.set_output_predicate(p); + has_output = true; } } + // disable slicing if the output predicates don't occur in rules. + if (!has_output) { + m_predicates.reset(); + } } bool mk_slice::rule_updated(rule const& r) { diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index 3ff54e68e..437c08f6a 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -133,6 +133,12 @@ lbool dl_interface::query(expr * query) { --num_unfolds; } } + + if (m_ctx.get_rules().get_output_predicates().empty()) { + m_context->set_unsat(); + return l_false; + } + query_pred = m_ctx.get_rules().get_output_predicate(); IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); From 7c12ab47165a88ab514c8cddcf65b1be6e784ec8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 25 May 2013 14:40:57 -0700 Subject: [PATCH 154/281] fix some compiler warnings Signed-off-by: Nikolaj Bjorner --- src/muz_qe/aig_exporter.cpp | 2 ++ src/muz_qe/clp_context.cpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/muz_qe/aig_exporter.cpp b/src/muz_qe/aig_exporter.cpp index 1d6ef3633..ca0030fc3 100755 --- a/src/muz_qe/aig_exporter.cpp +++ b/src/muz_qe/aig_exporter.cpp @@ -265,6 +265,8 @@ namespace datalog { case AST_VAR: return get_var(e); + default: + UNREACHABLE(); } UNREACHABLE(); diff --git a/src/muz_qe/clp_context.cpp b/src/muz_qe/clp_context.cpp index 5dd6fb9d8..94a956eb9 100644 --- a/src/muz_qe/clp_context.cpp +++ b/src/muz_qe/clp_context.cpp @@ -66,8 +66,9 @@ namespace datalog { m_ctx.ensure_opened(); m_solver.reset(); m_goals.reset(); - func_decl *head_decl = rm.mk_query(query, m_ctx.get_rules()); + rm.mk_query(query, m_ctx.get_rules()); m_ctx.apply_default_transformation(); + func_decl *head_decl = m_ctx.get_rules().get_output_predicate(); expr_ref head(m_ctx.get_rules().get_predicate_rules(head_decl)[0]->get_head(), m); ground(head); From edb2f8554d7418b8a202db374d810a66a18774eb Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 27 May 2013 17:45:56 -0700 Subject: [PATCH 155/281] Add new example Signed-off-by: Leonardo de Moura --- examples/c++/example.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 55dbebe27..77f7702f2 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -952,6 +952,26 @@ void exists_expr_vector_example() { std::cout << ex << std::endl; } +void substitute_example() { + std::cout << "substitute example\n"; + context c; + expr x(c); + x = c.int_const("x"); + expr f(c); + f = (x == 2) || (x == 1); + std::cout << f << std::endl; + + expr two(c), three(c); + two = c.int_val(2); + three = c.int_val(3); + Z3_ast from[] = { two }; + Z3_ast to[] = { three }; + expr new_f(c); + new_f = to_expr(c, Z3_substitute(c, f, 1, from, to)); + + std::cout << new_f << std::endl; +} + int main() { try { demorgan(); std::cout << "\n"; @@ -983,12 +1003,13 @@ int main() { tactic_example9(); std::cout << "\n"; tactic_qe(); std::cout << "\n"; tst_visit(); std::cout << "\n"; - incremental_example1(); std::cout << "\n"; - incremental_example2(); std::cout << "\n"; - incremental_example3(); std::cout << "\n"; + incremental_example1(); std::cout << "\n"; + incremental_example2(); std::cout << "\n"; + incremental_example3(); std::cout << "\n"; enum_sort_example(); std::cout << "\n"; expr_vector_example(); std::cout << "\n"; exists_expr_vector_example(); std::cout << "\n"; + substitute_example(); std::cout << "\n"; std::cout << "done\n"; } catch (exception & ex) { From c6f4cdab0f0b47759c5e686462fd09449de90a0d Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 27 May 2013 17:49:03 -0700 Subject: [PATCH 156/281] Fix bug reported at https://z3.codeplex.com/workitem/41 Signed-off-by: Leonardo de Moura --- src/ast/pattern/database.smt2 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/pattern/database.smt2 b/src/ast/pattern/database.smt2 index 9021e44f0..c42c9c25f 100644 --- a/src/ast/pattern/database.smt2 +++ b/src/ast/pattern/database.smt2 @@ -119,13 +119,13 @@ :pattern (?select (?select (?asElems e) a) i)))) (assert (forall ((x Int) (f Int) (a0 Int)) (! - (or (<= (+ a0 (* -1 (?fClosedTime f))) 0) + (or (<= (+ a0 (* (- 1) (?fClosedTime f))) 0) (not (= (?isAllocated x a0) 1)) (= (?isAllocated (?select f x) a0) 1)) :pattern (?isAllocated (?select f x) a0)))) (assert (forall ((a Int) (e Int) (i Int) (a0 Int)) (! - (or (<= (+ a0 (* -1 (?eClosedTime e))) 0) + (or (<= (+ a0 (* (- 1) (?eClosedTime e))) 0) (not (= (?isAllocated a a0) 1)) (= (?isAllocated (?select (?select e a) i) a0) 1)) :pattern (?isAllocated (?select (?select e a) i) a0)))) @@ -281,13 +281,13 @@ :pattern (IntsAllocated h (?StructGet_ s f))))) (assert (forall ((x Int) (f Int) (a0 Int)) (! - (or (<= (+ a0 (* -1 (?fClosedTime f))) 0) + (or (<= (+ a0 (* (- 1) (?fClosedTime f))) 0) (not (?isAllocated_ x a0)) (?isAllocated_ (?select f x) a0)) :pattern (?isAllocated_ (?select f x) a0)))) (assert (forall ((a Int) (e Int) (i Int) (a0 Int)) (! - (or (<= (+ a0 (* -1 (?eClosedTime e))) 0) + (or (<= (+ a0 (* (- 1) (?eClosedTime e))) 0) (not (?isAllocated_ a a0)) (?isAllocated_ (?select (?select e a) i) a0)) :pattern (?isAllocated_ (?select (?select e a) i) a0)))) From 9a666966398c997bfa0d0b17e5fa0d5e24a84e4d Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 29 May 2013 14:35:32 -0700 Subject: [PATCH 157/281] merge hassel table code from branch Signed-off-by: Nuno Lopes --- src/muz_qe/dl_base.h | 14 +- src/muz_qe/dl_check_table.cpp | 81 +- src/muz_qe/dl_check_table.h | 10 + src/muz_qe/dl_compiler.cpp | 125 +++- src/muz_qe/dl_compiler.h | 2 + src/muz_qe/dl_hassel_common.cpp | 434 +++++++++++ src/muz_qe/dl_hassel_common.h | 1079 +++++++++++++++++++++++++++ src/muz_qe/dl_hassel_diff_table.cpp | 219 ++++++ src/muz_qe/dl_hassel_diff_table.h | 87 +++ src/muz_qe/dl_hassel_table.cpp | 27 + src/muz_qe/dl_hassel_table.h | 39 + src/muz_qe/dl_instruction.cpp | 59 ++ src/muz_qe/dl_instruction.h | 2 + src/muz_qe/dl_relation_manager.cpp | 46 ++ src/muz_qe/dl_relation_manager.h | 7 + src/muz_qe/dl_table_relation.cpp | 15 + src/muz_qe/dl_table_relation.h | 2 + src/muz_qe/rel_context.cpp | 11 + src/util/bit_vector.h | 7 + 19 files changed, 2259 insertions(+), 7 deletions(-) create mode 100755 src/muz_qe/dl_hassel_common.cpp create mode 100755 src/muz_qe/dl_hassel_common.h create mode 100755 src/muz_qe/dl_hassel_diff_table.cpp create mode 100755 src/muz_qe/dl_hassel_diff_table.h create mode 100644 src/muz_qe/dl_hassel_table.cpp create mode 100644 src/muz_qe/dl_hassel_table.h diff --git a/src/muz_qe/dl_base.h b/src/muz_qe/dl_base.h index 491bb261d..200ce2d83 100644 --- a/src/muz_qe/dl_base.h +++ b/src/muz_qe/dl_base.h @@ -331,6 +331,10 @@ namespace datalog { virtual mutator_fn * mk_filter_interpreted_fn(const base_object & t, app * condition) { return 0; } + virtual transformer_fn * mk_filter_interpreted_and_project_fn(const base_object & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) + { return 0; } + virtual transformer_fn * mk_select_equal_and_project_fn(const base_object & t, const element & value, unsigned col) { return 0; } @@ -454,8 +458,8 @@ namespace datalog { class convenient_join_fn : public join_fn { signature m_result_sig; protected: - const unsigned_vector m_cols1; - const unsigned_vector m_cols2; + unsigned_vector m_cols1; + unsigned_vector m_cols2; convenient_join_fn(const signature & o1_sig, const signature & o2_sig, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) @@ -470,8 +474,8 @@ namespace datalog { class convenient_join_project_fn : public join_fn { signature m_result_sig; protected: - const unsigned_vector m_cols1; - const unsigned_vector m_cols2; + unsigned_vector m_cols1; + unsigned_vector m_cols2; //it is non-const because it needs to be modified in sparse_table version of the join_project operator unsigned_vector m_removed_cols; @@ -498,7 +502,7 @@ namespace datalog { class convenient_project_fn : public convenient_transformer_fn { protected: - const unsigned_vector m_removed_cols; + unsigned_vector m_removed_cols; convenient_project_fn(const signature & orig_sig, unsigned col_cnt, const unsigned * removed_cols) : m_removed_cols(col_cnt, removed_cols) { diff --git a/src/muz_qe/dl_check_table.cpp b/src/muz_qe/dl_check_table.cpp index 5081654b5..ea4003e5f 100644 --- a/src/muz_qe/dl_check_table.cpp +++ b/src/muz_qe/dl_check_table.cpp @@ -82,6 +82,34 @@ namespace datalog { return alloc(join_fn, *this, t1, t2, col_cnt, cols1, cols2); } + class check_table_plugin::join_project_fn : public table_join_fn { + scoped_ptr m_tocheck; + scoped_ptr m_checker; + public: + join_project_fn(check_table_plugin& p, const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) { + m_tocheck = p.get_manager().mk_join_project_fn(tocheck(t1), tocheck(t2), col_cnt, cols1, cols2, removed_col_cnt, removed_cols); + m_checker = p.get_manager().mk_join_project_fn(checker(t1), checker(t2), col_cnt, cols1, cols2, removed_col_cnt, removed_cols); + } + + virtual table_base* operator()(const table_base & t1, const table_base & t2) { + table_base* ttocheck = (*m_tocheck)(tocheck(t1), tocheck(t2)); + table_base* tchecker = (*m_checker)(checker(t1), checker(t2)); + check_table* result = alloc(check_table, get(t1).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); + return result; + } + }; + + table_join_fn * check_table_plugin::mk_join_project_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols) { + if (!check_kind(t1) || !check_kind(t2)) { + return 0; + } + return alloc(join_project_fn, *this, t1, t2, col_cnt, cols1, cols2, removed_col_cnt, removed_cols); + } + class check_table_plugin::union_fn : public table_union_fn { scoped_ptr m_tocheck; scoped_ptr m_checker; @@ -120,7 +148,6 @@ namespace datalog { } table_base* operator()(table_base const& src) { - IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); table_base* tchecker = (*m_checker)(checker(src)); table_base* ttocheck = (*m_tocheck)(tocheck(src)); check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker); @@ -135,6 +162,31 @@ namespace datalog { return alloc(project_fn, *this, t, col_cnt, removed_cols); } + class check_table_plugin::select_equal_and_project_fn : public table_transformer_fn { + scoped_ptr m_checker; + scoped_ptr m_tocheck; + public: + select_equal_and_project_fn(check_table_plugin& p, const table_base & t, const table_element & value, unsigned col) { + m_checker = p.get_manager().mk_select_equal_and_project_fn(checker(t), value, col); + m_tocheck = p.get_manager().mk_select_equal_and_project_fn(tocheck(t), value, col); + } + + table_base* operator()(table_base const& src) { + table_base* tchecker = (*m_checker)(checker(src)); + table_base* ttocheck = (*m_tocheck)(tocheck(src)); + check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker); + return result; + } + }; + + table_transformer_fn * check_table_plugin::mk_select_equal_and_project_fn(const table_base & t, + const table_element & value, unsigned col) { + if (!check_kind(t)) { + return 0; + } + return alloc(select_equal_and_project_fn, *this, t, value, col); + } + class check_table_plugin::rename_fn : public table_transformer_fn { scoped_ptr m_checker; scoped_ptr m_tocheck; @@ -233,6 +285,33 @@ namespace datalog { return 0; } + class check_table_plugin::filter_interpreted_and_project_fn : public table_transformer_fn { + scoped_ptr m_checker; + scoped_ptr m_tocheck; + public: + filter_interpreted_and_project_fn(check_table_plugin& p, const table_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols) + { + m_checker = p.get_manager().mk_filter_interpreted_and_project_fn(checker(t), condition, removed_col_cnt, removed_cols); + m_tocheck = p.get_manager().mk_filter_interpreted_and_project_fn(tocheck(t), condition, removed_col_cnt, removed_cols); + } + + table_base* operator()(table_base const& src) { + table_base* tchecker = (*m_checker)(checker(src)); + table_base* ttocheck = (*m_tocheck)(tocheck(src)); + check_table* result = alloc(check_table, get(src).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); + return result; + } + }; + + table_transformer_fn * check_table_plugin::mk_filter_interpreted_and_project_fn(const table_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { + if (check_kind(t)) { + return alloc(filter_interpreted_and_project_fn, *this, t, condition, removed_col_cnt, removed_cols); + } + return 0; + } + class check_table_plugin::filter_by_negation_fn : public table_intersection_filter_fn { scoped_ptr m_checker; scoped_ptr m_tocheck; diff --git a/src/muz_qe/dl_check_table.h b/src/muz_qe/dl_check_table.h index 40a3d5207..e4f439590 100644 --- a/src/muz_qe/dl_check_table.h +++ b/src/muz_qe/dl_check_table.h @@ -35,13 +35,16 @@ namespace datalog { unsigned m_count; protected: class join_fn; + class join_project_fn; class union_fn; class transformer_fn; class rename_fn; class project_fn; + class select_equal_and_project_fn; class filter_equal_fn; class filter_identical_fn; class filter_interpreted_fn; + class filter_interpreted_and_project_fn; class filter_by_negation_fn; public: @@ -54,10 +57,15 @@ namespace datalog { virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols); virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, const table_base * delta); virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, const unsigned * removed_cols); + virtual table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t, + const table_element & value, unsigned col); virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, const unsigned * permutation_cycle); virtual table_mutator_fn * mk_filter_identical_fn(const table_base & t, unsigned col_cnt, @@ -65,6 +73,8 @@ namespace datalog { virtual table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value, unsigned col); virtual table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition); + virtual table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); virtual table_intersection_filter_fn * mk_filter_by_negation_fn( const table_base & t, const table_base & negated_obj, unsigned joined_col_cnt, diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index 05a0d24b2..3f16d0dab 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -73,6 +73,18 @@ namespace datalog { vars.get_cols2(), removed_cols.size(), removed_cols.c_ptr(), result)); } + void compiler::make_filter_interpreted_and_project(reg_idx src, app_ref & cond, + const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc) { + SASSERT(!removed_cols.empty()); + relation_signature res_sig; + relation_signature::from_project(m_reg_signatures[src], removed_cols.size(), + removed_cols.c_ptr(), res_sig); + result = get_fresh_register(res_sig); + + acc.push_back(instruction::mk_filter_interpreted_and_project(src, cond, + removed_cols.size(), removed_cols.c_ptr(), result)); + } + void compiler::make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col, reg_idx & result, instruction_block & acc) { relation_signature res_sig; @@ -619,6 +631,116 @@ namespace datalog { } // enforce interpreted tail predicates + unsigned ft_len = r->get_tail_size(); // full tail + ptr_vector tail; + for (unsigned tail_index = ut_len; tail_index < ft_len; ++tail_index) { + tail.push_back(r->get_tail(tail_index)); + } + + if (!tail.empty()) { + app_ref filter_cond(tail.size() == 1 ? to_app(tail.back()) : m.mk_and(tail.size(), tail.c_ptr()), m); + ptr_vector filter_vars; + get_free_vars(filter_cond, filter_vars); + + // create binding + expr_ref_vector binding(m); + binding.resize(filter_vars.size()+1); + + for (unsigned v = 0; v < filter_vars.size(); ++v) { + if (!filter_vars[v]) + continue; + + int2ints::entry * entry = var_indexes.find_core(v); + unsigned src_col; + if (entry) { + src_col = entry->get_data().m_value.back(); + } else { + // we have an unbound variable, so we add an unbound column for it + relation_sort unbound_sort = filter_vars[v]; + + reg_idx new_reg; + bool new_dealloc; + make_add_unbound_column(r, 0, head_pred, filtered_res, unbound_sort, new_reg, new_dealloc, acc); + if (dealloc) + make_dealloc_non_void(filtered_res, acc); + dealloc = new_dealloc; + filtered_res = new_reg; + + src_col = single_res_expr.size(); + single_res_expr.push_back(m.mk_var(v, unbound_sort)); + + entry = var_indexes.insert_if_not_there2(v, unsigned_vector()); + entry->get_data().m_value.push_back(src_col); + } + relation_sort var_sort = m_reg_signatures[filtered_res][src_col]; + binding[filter_vars.size()-v] = m.mk_var(src_col, var_sort); + } + + // check if there are any columns to remove + unsigned_vector remove_columns; + { + unsigned_vector var_idx_to_remove; + ptr_vector vars; + get_free_vars(r->get_head(), vars); + for (int2ints::iterator I = var_indexes.begin(), E = var_indexes.end(); + I != E; ++I) { + unsigned var_idx = I->m_key; + if (!vars.get(var_idx, 0)) { + unsigned_vector & cols = I->m_value; + for (unsigned i = 0; i < cols.size(); ++i) { + remove_columns.push_back(cols[i]); + } + var_idx_to_remove.push_back(var_idx); + } + } + + for (unsigned i = 0; i < var_idx_to_remove.size(); ++i) { + var_indexes.remove(var_idx_to_remove[i]); + } + + // update column idx for after projection state + if (!remove_columns.empty()) { + unsigned_vector offsets; + offsets.resize(single_res_expr.size(), 0); + + for (unsigned i = 0; i < remove_columns.size(); ++i) { + for (unsigned col = remove_columns[i]; col < offsets.size(); ++col) { + ++offsets[col]; + } + } + + for (int2ints::iterator I = var_indexes.begin(), E = var_indexes.end(); + I != E; ++I) { + unsigned_vector & cols = I->m_value; + for (unsigned i = 0; i < cols.size(); ++i) { + cols[i] -= offsets[cols[i]]; + } + } + } + } + + expr_ref renamed(m); + m_context.get_var_subst()(filter_cond, binding.size(), binding.c_ptr(), renamed); + app_ref app_renamed(to_app(renamed), m); + if (remove_columns.empty()) { + if (!dealloc) + make_clone(filtered_res, filtered_res, acc); + acc.push_back(instruction::mk_filter_interpreted(filtered_res, app_renamed)); + } else { + reg_idx new_reg; + std::sort(remove_columns.begin(), remove_columns.end()); + make_filter_interpreted_and_project(filtered_res, app_renamed, remove_columns, new_reg, acc); + if (dealloc) + make_dealloc_non_void(filtered_res, acc); + filtered_res = new_reg; + } + dealloc = true; + } + +#if 0 + // this version is potentially better for non-symbolic tables, + // since it constraints each unbound column at a time (reducing the + // size of intermediate results). unsigned ft_len=r->get_tail_size(); //full tail for(unsigned tail_index=ut_len; tail_indexget_tail(tail_index); @@ -686,6 +808,7 @@ namespace datalog { acc.push_back(instruction::mk_filter_interpreted(filtered_res, app_renamed)); dealloc = true; } +#endif { //put together the columns of head relation @@ -737,7 +860,7 @@ namespace datalog { make_dealloc_non_void(new_head_reg, acc); } - finish: +// finish: m_instruction_observer.finish_rule(); } diff --git a/src/muz_qe/dl_compiler.h b/src/muz_qe/dl_compiler.h index 78b4623de..e0f9af424 100644 --- a/src/muz_qe/dl_compiler.h +++ b/src/muz_qe/dl_compiler.h @@ -145,6 +145,8 @@ namespace datalog { instruction_block & acc); void make_join_project(reg_idx t1, reg_idx t2, const variable_intersection & vars, const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc); + void make_filter_interpreted_and_project(reg_idx src, app_ref & cond, + const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc); void make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col, reg_idx & result, instruction_block & acc); /** diff --git a/src/muz_qe/dl_hassel_common.cpp b/src/muz_qe/dl_hassel_common.cpp new file mode 100755 index 000000000..6201868ca --- /dev/null +++ b/src/muz_qe/dl_hassel_common.cpp @@ -0,0 +1,434 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_hassel_common.cpp + +Abstract: + + + +Revision History: + +--*/ + +#include "dl_hassel_common.h" +#include "dl_context.h" + +#include + +namespace datalog { + + static void formula_to_dnf_aux(app *and, unsigned idx, std::set& conjexpr, std::set& toplevel, ast_manager& m) { + if (idx == and->get_num_args()) { + std::vector v(conjexpr.begin(), conjexpr.end()); + toplevel.insert(m.mk_and((unsigned)v.size(), &v[0])); + return; + } + + expr *e = and->get_arg(idx); + if (is_app(e) && to_app(e)->get_decl_kind() == OP_OR) { + app *or = to_app(e); + // quick subsumption test: if any of the elements of the OR is already ANDed, then we skip this OR + for (unsigned i = 0; i < or->get_num_args(); ++i) { + if (conjexpr.count(or->get_arg(i))) { + formula_to_dnf_aux(and, idx+1, conjexpr, toplevel, m); + return; + } + } + + for (unsigned i = 0; i < or->get_num_args(); ++i) { + std::set conjexpr2(conjexpr); + conjexpr2.insert(or->get_arg(i)); + formula_to_dnf_aux(and, idx+1, conjexpr2, toplevel, m); + } + } else { + conjexpr.insert(e); + formula_to_dnf_aux(and, idx+1, conjexpr, toplevel, m); + } + } + + expr_ref formula_to_dnf(expr_ref f) { + app *a = to_app(f); + SASSERT(a->get_decl_kind() == OP_AND); + std::set toplevel, conjexpr; + formula_to_dnf_aux(a, 0, conjexpr, toplevel, f.m()); + + if (toplevel.size() > 1) { + std::vector v(toplevel.begin(), toplevel.end()); + return expr_ref(f.m().mk_or((unsigned)v.size(), &v[0]), f.m()); + } else { + return expr_ref(*toplevel.begin(), f.m()); + } + } + + bool bit_vector::contains(const bit_vector & other) const { + unsigned n = num_words(); + if (n == 0) + return true; + + for (unsigned i = 0; i < n - 1; ++i) { + if ((m_data[i] & other.m_data[i]) != other.m_data[i]) + return false; + } + unsigned bit_rest = m_num_bits % 32; + unsigned mask = (1 << bit_rest) - 1; + if (mask == 0) mask = UINT_MAX; + unsigned other_data = other.m_data[n-1] & mask; + return (m_data[n-1] & other_data) == other_data; + } + + bool bit_vector::contains(const bit_vector & other, unsigned idx) const { + // TODO: optimize this to avoid copy + return slice(idx, other.size()).contains(other); + } + + bool bit_vector::contains_consecutive_zeros() const { + unsigned n = num_words(); + if (n == 0) + return false; + + for (unsigned i = 0; i < n - 1; ++i) { + if ((((m_data[i] << 1) | m_data[i]) & 0xAAAAAAAA) != 0xAAAAAAAA) + return true; + } + unsigned bit_rest = m_num_bits % 32; + unsigned mask = (1 << bit_rest) - 1; + if (mask == 0) mask = UINT_MAX; + mask &= 0xAAAAAAAA; + return ((((m_data[n-1] << 1) | m_data[n-1]) & mask) != mask); + } + + bit_vector bit_vector::slice(unsigned idx, unsigned length) const { + bit_vector Res(length); + // TODO: optimize w/ memcpy when possible + for (unsigned i = idx; i < idx + length; ++i) { + Res.push_back(get(i)); + } + SASSERT(Res.size() == length); + return Res; + } + + void bit_vector::append(const bit_vector & other) { + if (other.empty()) + return; + + if ((m_num_bits % 32) == 0) { + unsigned prev_num_bits = m_num_bits; + resize(m_num_bits + other.m_num_bits); + memcpy(&get_bit_word(prev_num_bits), other.m_data, other.num_words() * sizeof(unsigned)); + return; + } + + // TODO: optimize the other cases. + for (unsigned i = 0; i < other.m_num_bits; ++i) { + push_back(other.get(i)); + } + } + + uint64 bit_vector::to_number(unsigned idx, unsigned length) const { + SASSERT(length <= 64); + uint64 r = 0; + for (unsigned i = 0; i < length; ++i) { + r = (r << 1) | (uint64)get(idx+i); + } + return r; + } + + bool bit_vector::operator<(bit_vector const & other) const { + SASSERT(m_num_bits == other.m_num_bits); + unsigned n = num_words(); + if (n == 0) + return false; + + for (unsigned i = 0; i < n - 1; ++i) { + if (m_data[i] > other.m_data[i]) + return false; + if (m_data[i] < other.m_data[i]) + return true; + } + + unsigned bit_rest = m_num_bits % 32; + unsigned mask = (1 << bit_rest) - 1; + if (mask == 0) mask = UINT_MAX; + return (m_data[n-1] & mask) < (other.m_data[n-1] & mask); + } + + table_information::table_information(table_plugin & p, const table_signature& sig) : + m_column_info(sig.size()+1), + m_bv_util(p.get_context().get_manager()), + m_decl_util(p.get_context().get_manager()) { + + unsigned column = 0; + for (unsigned i = 0; i < sig.size(); ++i) { + unsigned num_bits = uint64_log2(sig[i]); + SASSERT(num_bits == 64 || (1ULL << num_bits) == sig[i]); + m_column_info[i] = column; + column += num_bits; + } + m_column_info[sig.size()] = column; + } + + void table_information::expand_column_vector(unsigned_vector& v, const table_information *other) const { + unsigned_vector orig; + orig.swap(v); + + for (unsigned i = 0; i < orig.size(); ++i) { + unsigned col, limit; + if (orig[i] < get_num_cols()) { + col = column_idx(orig[i]); + limit = col + column_num_bits(orig[i]); + } else { + unsigned idx = orig[i] - get_num_cols(); + col = get_num_bits() + other->column_idx(idx); + limit = col + other->column_num_bits(idx); + } + + for (; col < limit; ++col) { + v.push_back(col); + } + } + } + + void table_information::display(std::ostream & out) const { + out << '<'; + for (unsigned i = 0; i < get_num_cols(); ++i) { + if (i > 0) + out << ", "; + out << column_num_bits(i); + } + out << ">\n"; + } + + ternary_bitvector::ternary_bitvector(unsigned size, bool full) : + bit_vector() { + resize(size, full); + } + + ternary_bitvector::ternary_bitvector(uint64 n, unsigned num_bits) : + bit_vector(2 * num_bits) { + append_number(n, num_bits); + } + + ternary_bitvector::ternary_bitvector(const table_fact& f, const table_information& t) : + bit_vector(2 * t.get_num_bits()) { + for (unsigned i = 0; i < f.size(); ++i) { + SASSERT(t.column_idx(i) == size()); + append_number(f[i], t.column_num_bits(i)); + } + SASSERT(size() == t.get_num_bits()); + } + + void ternary_bitvector::fill1() { + memset(m_data, 0xFF, m_capacity * sizeof(unsigned)); + } + + unsigned ternary_bitvector::get(unsigned idx) const { + idx *= 2; + return (bit_vector::get(idx) << 1) | (unsigned)bit_vector::get(idx+1); + } + + void ternary_bitvector::set(unsigned idx, unsigned val) { + SASSERT(val == BIT_0 || val == BIT_1 || val == BIT_x); + idx *= 2; + bit_vector::set(idx, (val >> 1) != 0); + bit_vector::set(idx+1, (val & 1) != 0); + } + + void ternary_bitvector::push_back(unsigned val) { + SASSERT(val == BIT_0 || val == BIT_1 || val == BIT_x); + bit_vector::push_back((val >> 1) != 0); + bit_vector::push_back((val & 1) != 0); + } + + void ternary_bitvector::append_number(uint64 n, unsigned num_bits) { + SASSERT(num_bits <= 64); + for (int bit = num_bits-1; bit >= 0; --bit) { + if (n & (1ULL << bit)) { + push_back(BIT_1); + } else { + push_back(BIT_0); + } + } + } + + void ternary_bitvector::mk_idx_eq(unsigned idx, ternary_bitvector& val) { + for (unsigned i = 0; i < val.size(); ++i) { + set(idx+i, val.get(i)); + } + } + + ternary_bitvector ternary_bitvector::and(const ternary_bitvector& other) const{ + ternary_bitvector result(*this); + result &= other; + return result; + } + + void ternary_bitvector::neg(union_ternary_bitvector& result) const { + ternary_bitvector negated; + negated.resize(size()); + + for (unsigned i = 0; i < size(); ++i) { + switch (get(i)) { + case BIT_0: + negated.fill1(); + negated.set(i, BIT_1); + break; + case BIT_1: + negated.fill1(); + negated.set(i, BIT_0); + break; + default: + continue; + } + result.add_fact(negated); + } + } + + static void join_fix_eqs(ternary_bitvector& TBV, unsigned idx, unsigned col2_offset, + const unsigned_vector& cols1, const unsigned_vector& cols2, + union_ternary_bitvector& result) { + if (idx == cols1.size()) { + result.add_fact(TBV); + return; + } + + unsigned idx1 = cols1[idx]; + unsigned idx2 = cols2[idx] + col2_offset; + unsigned v1 = TBV.get(idx1); + unsigned v2 = TBV.get(idx2); + + if (v1 == BIT_x) { + if (v2 == BIT_x) { + // both x: duplicate row + ternary_bitvector TBV2(TBV); + TBV2.set(idx1, BIT_0); + TBV2.set(idx2, BIT_0); + join_fix_eqs(TBV2, idx+1, col2_offset, cols1, cols2, result); + + TBV.set(idx1, BIT_1); + TBV.set(idx2, BIT_1); + } else { + TBV.set(idx1, v2); + } + } else if (v2 == BIT_x) { + TBV.set(idx2, v1); + } else if (v1 != v2) { + // columns don't match + return; + } + join_fix_eqs(TBV, idx+1, col2_offset, cols1, cols2, result); + } + + void ternary_bitvector::join(const ternary_bitvector& other, + const unsigned_vector& cols1, + const unsigned_vector& cols2, + union_ternary_bitvector& result) const { + ternary_bitvector TBV(*this); + TBV.append(other); + join_fix_eqs(TBV, 0, size(), cols1, cols2, result); + } + + bool ternary_bitvector::project(const unsigned_vector& delcols, ternary_bitvector& result) const { + unsigned *rm_cols = delcols.c_ptr(); + + for (unsigned i = 0; i < size(); ++i) { + if (*rm_cols == i) { + ++rm_cols; + continue; + } + result.push_back(get(i)); + } + return true; + } + + static void copy_column(ternary_bitvector& CopyTo, const ternary_bitvector& CopyFrom, + unsigned col_dst, unsigned col_src, const table_information& src_table, + const table_information& dst_table) { + unsigned idx_dst = dst_table.column_idx(col_dst); + unsigned idx_src = src_table.column_idx(col_src); + unsigned num_bits = dst_table.column_num_bits(col_dst); + SASSERT(num_bits == src_table.column_num_bits(col_src)); + + for (unsigned i = 0; i < num_bits; ++i) { + CopyTo.set(idx_dst+i, CopyFrom.get(idx_src+i)); + } + } + + void ternary_bitvector::rename(const unsigned_vector& cyclecols, + const unsigned_vector& out_of_cycle_cols, + const table_information& src_table, + const table_information& dst_table, + ternary_bitvector& result) const { + result.resize(dst_table.get_num_bits()); + + for (unsigned i = 1; i < cyclecols.size(); ++i) { + copy_column(result, *this, cyclecols[i-1], cyclecols[i], src_table, dst_table); + } + copy_column(result, *this, cyclecols[cyclecols.size()-1], cyclecols[0], src_table, dst_table); + + for (unsigned i = 0; i < out_of_cycle_cols.size(); ++i) { + unsigned col = out_of_cycle_cols[i]; + copy_column(result, *this, col, col, src_table, dst_table); + } + } + + unsigned ternary_bitvector::size_in_bytes() const { + return sizeof(*this) + m_capacity; + } + + void ternary_bitvector::display(std::ostream & out) const { + for (unsigned i = 0; i < size(); ++i) { + switch (get(i)) { + case BIT_0: + out << '0'; + break; + case BIT_1: + out << '1'; + break; + case BIT_x: + out << 'x'; + break; + default: + UNREACHABLE(); + } + } + } + +#if Z3DEBUG + void ternary_bitvector::expand(std::set & BVs) const { + bit_vector BV(m_num_bits); + expand(BVs, BV, 0); + } + + void ternary_bitvector::expand(std::set & BVs, bit_vector &BV, unsigned idx) const { + if (idx == size()) { + BVs.insert(BV); + return; + } + + switch (get(idx)) { + case BIT_0: + BV.push_back(false); + expand(BVs, BV, idx+1); + break; + case BIT_1: + BV.push_back(true); + expand(BVs, BV, idx+1); + break; + case BIT_x: { // x: duplicate + bit_vector BV2(BV); + BV.push_back(false); + BV2.push_back(true); + expand(BVs, BV, idx+1); + expand(BVs, BV2, idx+1); + } + break; + default: + UNREACHABLE(); + } + } +#endif + +} diff --git a/src/muz_qe/dl_hassel_common.h b/src/muz_qe/dl_hassel_common.h new file mode 100755 index 000000000..7c1d1e614 --- /dev/null +++ b/src/muz_qe/dl_hassel_common.h @@ -0,0 +1,1079 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_hassel_common.h + +Abstract: + + + +Revision History: + +--*/ + +#ifndef _DL_HASSEL_COMMON_H_ +#define _DL_HASSEL_COMMON_H_ + +#include "bit_vector.h" +#include "dl_base.h" +#include "bv_decl_plugin.h" +#include "union_find.h" +#include +#include + +#define BIT_0 ((0<<1)|1) +#define BIT_1 ((1<<1)|0) +#define BIT_x ((1<<1)|1) + +namespace datalog { + + expr_ref formula_to_dnf(expr_ref f); + + class bit_vector : public ::bit_vector { + public: + bit_vector() : ::bit_vector() {} + bit_vector(unsigned bits) : ::bit_vector(bits) {} + + bool contains(const bit_vector & other) const; + bool contains(const bit_vector & other, unsigned idx) const; + bool contains_consecutive_zeros() const; + + bit_vector slice(unsigned idx, unsigned length) const; + void append(const bit_vector & other); + + uint64 to_number(unsigned idx, unsigned length) const; + + // for std::less operations + bool operator<(bit_vector const & other) const; + }; + + + class table_information { + unsigned_vector m_column_info; + bv_util m_bv_util; + dl_decl_util m_decl_util; + + public: + table_information(table_plugin & p, const table_signature& sig); + + unsigned get_num_bits() const { + return m_column_info.back(); + } + + unsigned get_num_cols() const { + return m_column_info.size()-1; + } + + unsigned column_idx(unsigned col) const { + return m_column_info[col]; + } + + unsigned column_num_bits(unsigned col) const { + return m_column_info[col+1] - m_column_info[col]; + } + + void expand_column_vector(unsigned_vector& v, const table_information *other = 0) const; + + void display(std::ostream & out) const; + + const bv_util& get_bv_util() const { return m_bv_util; } + const dl_decl_util& get_decl_util() const { return m_decl_util; } + }; + + + template class union_ternary_bitvector; + + + class ternary_bitvector : private bit_vector { + public: + ternary_bitvector() : bit_vector() {} + ternary_bitvector(unsigned size) : bit_vector(2 * size) {} + + ternary_bitvector(unsigned size, bool full); + ternary_bitvector(uint64 n, unsigned num_bits); + ternary_bitvector(const table_fact& f, const table_information& t); + + void swap(ternary_bitvector& other) { + SASSERT(size() == other.size()); + bit_vector::swap(other); + } + + void resize(unsigned new_size, bool val = false) { + bit_vector::resize(2 * new_size, val); + } + + void reset() { + m_num_bits = 0; + } + + unsigned size() const { + SASSERT((m_num_bits % 2) == 0); + return m_num_bits/2; + } + + void fill1(); + + void append(const ternary_bitvector & other) { bit_vector::append(other); } + bool contains(const ternary_bitvector & other) const { return bit_vector::contains(other); } + + bool is_empty() const { return contains_consecutive_zeros(); } + + unsigned get(unsigned idx) const; + void set(unsigned idx, unsigned val); + void push_back(unsigned val); + void append_number(uint64 n, unsigned num_bits); + void mk_idx_eq(unsigned idx, ternary_bitvector& val); + + ternary_bitvector and(const ternary_bitvector& other) const; + void neg(union_ternary_bitvector& result) const; + + void join(const ternary_bitvector& other, const unsigned_vector& cols1, + const unsigned_vector& cols2, union_ternary_bitvector& result) const; + + bool project(const unsigned_vector& delcols, ternary_bitvector& result) const; + + void rename(const unsigned_vector& cyclecols, const unsigned_vector& out_of_cycle_cols, + const table_information& src_table, const table_information& dst_table, + ternary_bitvector& result) const; + + static bool has_subtract() { return false; } + void subtract(const union_ternary_bitvector& other, + union_ternary_bitvector& result) const { UNREACHABLE(); } + + void display(std::ostream & out) const; + unsigned size_in_bytes() const; + +#if Z3DEBUG + void expand(std::set & BVs) const; +#endif + + private: +#if Z3DEBUG + void expand(std::set & BVs, bit_vector &BV, unsigned idx) const; +#endif + }; + + + template + class union_ternary_bitvector { + typedef std::list union_t; + + union_t m_bitvectors; + unsigned m_bv_size; //!< number of ternary bits + + public: + union_ternary_bitvector(unsigned bv_size) : m_bv_size(bv_size) {} + + union_ternary_bitvector(unsigned bv_size, bool full) : m_bv_size(bv_size) { + if (full) + mk_full(); + } + + union_ternary_bitvector and(const union_ternary_bitvector & Other) const { + if (empty()) + return *this; + if (Other.empty()) + return Other; + + union_ternary_bitvector Ret(m_bv_size); + + for (const_iterator I = begin(), E = end(); I != E; ++I) { + for (const_iterator II = Other.begin(), EE = Other.end(); II != EE; ++II) { + T row(I->and(*II)); + if (!row.is_empty()) + Ret.add_fact(row); + } + } + return Ret; + } + + union_ternary_bitvector or(const union_ternary_bitvector & Other) const { + if (empty()) + return Other; + if (Other.empty()) + return *this; + + union_ternary_bitvector Ret(*this); + Ret.add_facts(Other); + return Ret; + } + + union_ternary_bitvector neg() const { + union_ternary_bitvector Ret(m_bv_size); + Ret.mk_full(); + + union_ternary_bitvector negated(m_bv_size); + for (const_iterator I = begin(), E = end(); I != E; ++I) { + negated.reset(); + I->neg(negated); + Ret.swap(Ret.and(negated)); + } + return Ret; + } + + void subtract(const union_ternary_bitvector& other) { + if (!T::has_subtract()) { + swap(this->and(other.neg())); + return; + } + + union_ternary_bitvector subtracted(m_bv_size); + for (const_iterator I = begin(), E = end(); I != E; ++I) { + I->subtract(other, subtracted); + } + swap(subtracted); + } + +#if 0 + union_ternary_bitvector gc() const { + // Simple subsumption-based cleaning. + union_ternary_bitvector Ret(m_bv_size); + for (union_t::const_reverse_iterator I = m_bitvectors.rbegin(), E = m_bitvectors.rend(); I != E; ++I) { + Ret.add_fact(*I); + } + return Ret; + } +#endif + + void join(const union_ternary_bitvector& other, const unsigned_vector& cols1, + const unsigned_vector& cols2, union_ternary_bitvector& result) const { + for (const_iterator I = begin(), E = end(); I != E; ++I) { + for (const_iterator II = other.begin(), EE = other.end(); II != EE; ++II) { + I->join(*II, cols1, cols2, result); + } + } + } + + void rename(const unsigned_vector& cyclecols, const unsigned_vector& out_of_cycle_cols, + const table_information& src_table, const table_information& dst_table, + union_ternary_bitvector& result) const { + T row(m_bv_size); + for (const_iterator I = begin(), E = end(); I != E; ++I) { + row.reset(); + I->rename(cyclecols, out_of_cycle_cols, src_table, dst_table, row); + result.add_new_fact(row); + } + } + + void project(const unsigned_vector& delcols, union_ternary_bitvector& result) const { + unsigned new_size = m_bv_size - (delcols.size()-1); + T row(new_size); + + for (const_iterator I = begin(), E = end(); I != E; ++I) { + row.reset(); + if (I->project(delcols, row)) { + SASSERT(!row.is_empty()); + result.add_fact(row); + } + } + } + + private: + typedef union_find<> subset_ints; + + // returns 1 if row should be removed, 0 otherwise + static int fix_single_bit(T & BV, unsigned idx, unsigned value, const subset_ints& equalities) { + unsigned root = equalities.find(idx); + idx = root; + do { + unsigned bitval = BV.get(idx); + if (bitval == BIT_x) { + BV.set(idx, value); + } else if (bitval != value) { + return 1; + } + idx = equalities.next(idx); + } while (idx != root); + return 0; + } + + static int fix_single_bit(T & BV1, unsigned idx1, T & BV2, unsigned idx2, + subset_ints& equalities, bool discard_col) { + unsigned A = BV1.get(idx1); + unsigned B = BV2.get(idx2); + + if (A == BIT_x) { + if (B == BIT_x) { + // Both are don't cares. + /////// FIXME::: don't duplicate rows with diff table + if (!discard_col) + return 2; // duplicate row + equalities.merge(idx1, idx2); + return 0; + } else { + // only A is don't care. + return fix_single_bit(BV1, idx1, B, equalities); + } + } else if (B == BIT_x) { + // Only B is don't care. + return fix_single_bit(BV2, idx2, A, equalities); + } else if (A == B) { + return 0; + } else { + return 1; // remove row + } + } + + void fix_eq_bits(unsigned idx1, const T *BV, unsigned idx2, unsigned length, + subset_ints& equalities, const bit_vector& discard_cols) { + for (unsigned i = 0; i < length; ++i) { + for (union_t::iterator I = m_bitvectors.begin(), E = m_bitvectors.end(); I != E; ) { + T *eqBV = BV ? const_cast(BV) : &*I; + bool discard_col = discard_cols.get(idx1+i) || (!BV && discard_cols.get(idx2+i)); + + switch (fix_single_bit(*I, idx1+i, *eqBV, idx2+i, equalities, discard_col)) { + case 1: + // remove row + I = m_bitvectors.erase(I); + break; + + case 2: { + // duplicate row + T BV2(*I); + I->set(idx1+i, BIT_0); + I->set(idx2+i, BIT_0); + + BV2.set(idx1+i, BIT_1); + BV2.set(idx2+i, BIT_1); + m_bitvectors.insert(I, BV2); + ++I; + break;} + + default: + // bits fixed + ++I; + } + } + } + } + + /// make bits of table [idx,idx+max_length] equal to e sliced starting at idx2 + unsigned fix_eq_bits(unsigned idx, const expr *e, unsigned idx2, unsigned max_length, + const table_information& t, subset_ints& equalities, + const bit_vector & discard_cols) { + const bv_util& bvu = t.get_bv_util(); + const dl_decl_util& dutil = t.get_decl_util(); + + rational n; + unsigned bv_size; + if (bvu.is_numeral(e, n, bv_size)) { + T num(n.get_int64(), bv_size); + SASSERT(idx2 < bv_size); + max_length = std::min(max_length, bv_size - idx2); + fix_eq_bits(idx, &num, idx2, max_length, equalities, discard_cols); + return idx + max_length; + } + + uint64 num; + if (dutil.is_numeral(e, num)) { + T num_bv(num, max_length); + fix_eq_bits(idx, &num_bv, idx2, max_length, equalities, discard_cols); + return idx + max_length; + } + + if (bvu.is_concat(e)) { + const app *a = to_app(e); + + // skip the first elements of the concat if e.g. we have a top level extract + unsigned i = 0; + for (; i < a->get_num_args(); ++i) { + unsigned arg_size = bvu.get_bv_size(a->get_arg(i)); + if (idx2 < arg_size) + break; + idx2 -= arg_size; + } + + SASSERT(i < a->get_num_args()); + for (; max_length > 0 && i < a->get_num_args(); ++i) { + unsigned idx0 = idx; + idx = fix_eq_bits(idx, a->get_arg(i), idx2, max_length, t, equalities, discard_cols); + idx2 = 0; + SASSERT((idx - idx0) <= max_length); + max_length = max_length - (idx - idx0); + } + return idx; + } + + unsigned low, high; + expr *e2; + if (bvu.is_extract(e, low, high, e2)) { + SASSERT(low <= high); + unsigned size = bvu.get_bv_size(e2); + unsigned offset = size - (high+1) + idx2; + SASSERT(idx2 < (high-low+1)); + max_length = std::min(max_length, high - low + 1 - idx2); + return fix_eq_bits(idx, e2, offset, max_length, t, equalities, discard_cols); + } + + if (e->get_kind() == AST_VAR) { + unsigned idx_var = idx2 + t.column_idx(to_var(e)->get_idx()); + SASSERT(idx2 < t.column_num_bits(to_var(e)->get_idx())); + max_length = std::min(max_length, t.column_num_bits(to_var(e)->get_idx()) - idx2); + fix_eq_bits(idx, 0, idx_var, max_length, equalities, discard_cols); + return idx + max_length; + } + + NOT_IMPLEMENTED_YET(); + return 0; + } + + void filter(const expr *e, subset_ints& equalities, const bit_vector& discard_cols, + const table_information& t) { + switch (e->get_kind()) { + case AST_APP: { + const app *app = to_app(e); + switch (app->get_decl_kind()) { + case OP_AND: + for (unsigned i = 0; i < app->get_num_args(); ++i) { + filter(app->get_arg(i), equalities, discard_cols, t); + } + return; + + case OP_EQ: { + const expr *a = app->get_arg(0); + const var *v; + unsigned vidx = 0; + unsigned length; + + unsigned low, high; + expr *e2; + if (is_var(a)) { + v = to_var(a); + length = t.column_num_bits(v->get_idx()); + } else if (t.get_bv_util().is_extract(a, low, high, e2)) { + vidx = t.get_bv_util().get_bv_size(e2) - high - 1; + length = high - low + 1; + SASSERT(is_var(e2)); + v = to_var(e2); + } else { + NOT_IMPLEMENTED_YET(); + } + vidx += t.column_idx(v->get_idx()); + + unsigned final_idx = fix_eq_bits(vidx, app->get_arg(1), 0, length, t, equalities, discard_cols); + SASSERT(final_idx == vidx + length); + (void)final_idx; + return;} + + case OP_FALSE: + reset(); + return; + + case OP_NOT: { + union_ternary_bitvector sub(m_bv_size, true); + sub.filter(app->get_arg(0), equalities, discard_cols, t); + this->subtract(sub); + return;} + + case OP_OR: { + union_ternary_bitvector orig(m_bv_size); + swap(orig); + for (unsigned i = 0; i < app->get_num_args(); ++i) { + union_ternary_bitvector tmp(orig); + subset_ints eqs(equalities); + tmp.filter(app->get_arg(i), eqs, discard_cols, t); + add_facts(tmp); + } + return;} + + case OP_TRUE: + return; + + default: + std::cerr << "app decl: " << app->get_decl()->get_name() << " (" << app->get_decl_kind() << ")\n"; + NOT_IMPLEMENTED_YET(); + } + break;} + + case AST_VAR: { + // boolean var must be true (10) + SASSERT(t.column_num_bits(to_var(e)->get_idx()) == 1); + unsigned idx = t.column_idx(to_var(e)->get_idx()); + ternary_bitvector BV(1); + BV.push_back(BIT_1); + T BV2(BV); + fix_eq_bits(idx, &BV2, 0, 2, equalities, discard_cols); + return;} + + default: + break; + } + std::cerr << "expr kind: " << get_ast_kind_name(e->get_kind()) << '\n'; + NOT_IMPLEMENTED_YET(); + } + + public: + void filter(const expr *cond, const bit_vector& discard_cols, const table_information& table) { + // datastructure to store equalities with columns that will be projected out + union_find_default_ctx union_ctx; + subset_ints equalities(union_ctx); + for (unsigned i = 0, e = discard_cols.size(); i < e; ++i) { + equalities.mk_var(); + } + + filter(cond, equalities, discard_cols, table); + } + + bool contains(const T & fact) const { + for (const_iterator I = begin(), E = end(); I != E; ++I) { + if (I->contains(fact)) + return true; + } + return false; + } + + bool contains(const union_ternary_bitvector & other) const { + for (const_iterator I = other.begin(), E = other.end(); I != E; ++I) { + for (const_iterator II = begin(), EE = end(); II != EE; ++II) { + if (II->contains(*I)) + goto next_iter; + } + return false; +next_iter: ; + } + return true; + } + + unsigned num_disjs() const { + return (unsigned)m_bitvectors.size(); + } + + unsigned num_bytes() const { + unsigned size = sizeof(*this); + for (const_iterator I = begin(), E = end(); I != E; ++I) { + size += I->size_in_bytes(); + } + return size; + } + +#if Z3DEBUG + void expand(std::set & BVs) const { + for (const_iterator I = begin(), E = end(); I != E; ++I) { + I->expand(BVs); + } + } +#endif + + void add_facts(const union_ternary_bitvector & Other, union_ternary_bitvector *Delta = 0) { + for (const_iterator I = Other.begin(), E = Other.end(); I != E; ++I) { + if (add_fact(*I) && Delta) + Delta->add_fact(*I); + } + } + + bool add_fact(const T & fact) { + if (contains(fact)) + return false; + add_new_fact(fact); + return true; + } + + void add_new_fact(const T & fact) { + SASSERT(m_bv_size == fact.size()); + + // TODO: optimize sequence (karnaugh maps??) + // At least join 1-bit different BVs + m_bitvectors.push_back(fact); + } + + void mk_full() { + reset(); + add_new_fact(T(m_bv_size, true)); + } + + typedef typename union_t::const_iterator const_iterator; + + const_iterator begin() const { return m_bitvectors.begin(); } + const_iterator end() const { return m_bitvectors.end(); } + + bool empty() const { return m_bitvectors.empty(); } + void reset() { m_bitvectors.clear(); } + + void swap(union_ternary_bitvector& other) { + SASSERT(m_bv_size == other.m_bv_size); + m_bitvectors.swap(other.m_bitvectors); + } + + void display(std::ostream & out) const { + out << '#' << num_disjs() << " (bv" << m_bv_size << ") "; + + bool first = true; + for (const_iterator I = begin(), E = end(); I != E; ++I) { + if (!first) + out << " \\/ "; + first = false; + I->display(out); + } + out << '\n'; + } + }; + + + template + class common_hassel_table_plugin : public table_plugin { + public: + common_hassel_table_plugin(symbol &s, relation_manager & manager) : + table_plugin(s, manager) { } + + virtual table_base * mk_empty(const table_signature & s) { + return alloc(T, *this, s); + } + + virtual table_base * mk_full(func_decl* p, const table_signature & s) { + T *t = static_cast(mk_empty(s)); + t->mk_full(); + return t; + } + + virtual bool can_handle_signature(const table_signature & s) { + return s.functional_columns() == 0; + } + + private: + ast_manager& get_ast_manager() { return get_context().get_manager(); } + + class join_fn : public convenient_table_join_fn { + public: + join_fn(const T & t1, const T & t2, unsigned col_cnt, const unsigned *cols1, const unsigned *cols2) + : convenient_table_join_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2) { + t1.expand_column_vector(m_cols1); + t2.expand_column_vector(m_cols2); + } + + virtual table_base * operator()(const table_base & tb1, const table_base & tb2) { + const T & T1 = static_cast(tb1); + const T & T2 = static_cast(tb2); + T * Res = static_cast(T1.get_plugin().mk_empty(get_result_signature())); + T1.m_bitsets.join(T2.m_bitsets, m_cols1, m_cols2, Res->m_bitsets); + TRACE("dl_hassel", tout << "final size: " << Res->get_size_estimate_rows() << '\n';); + return Res; + } + }; + + public: + virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (!check_kind(t1) || !check_kind(t2)) + return 0; + return alloc(join_fn, static_cast(t1), static_cast(t2), col_cnt, cols1, cols2); + } + + private: + class union_fn : public table_union_fn { + public: + virtual void operator()(table_base & tgt0, const table_base & src0, table_base * delta0) { + T & tgt = static_cast(tgt0); + const T & src = static_cast(src0); + T * delta = static_cast(delta0); + tgt.m_bitsets.add_facts(src.m_bitsets, delta ? &delta->m_bitsets : 0); + TRACE("dl_hassel", tout << "final size: " << tgt.get_size_estimate_rows() << '\n';); + } + }; + + public: + virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, + const table_base * delta) { + if (!check_kind(tgt) || !check_kind(src)) + return 0; + return alloc(union_fn); + } + + private: + class project_fn : public convenient_table_project_fn { + public: + project_fn(const T & t, unsigned removed_col_cnt, const unsigned * removed_cols) + : convenient_table_project_fn(t.get_signature(), removed_col_cnt, removed_cols) { + t.expand_column_vector(m_removed_cols); + m_removed_cols.push_back(UINT_MAX); + } + + virtual table_base * operator()(const table_base & tb) { + const T & t = static_cast(tb); + T * res = static_cast(t.get_plugin().mk_empty(get_result_signature())); + t.m_bitsets.project(m_removed_cols, res->m_bitsets); + TRACE("dl_hassel", tout << "final size: " << res->get_size_estimate_rows() << '\n';); + return res; + } + }; + + public: + virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols) { + if (!check_kind(t)) + return 0; + return alloc(project_fn, static_cast(t), col_cnt, removed_cols); + } + + private: + class rename_fn : public convenient_table_rename_fn { + unsigned_vector m_out_of_cycle; + public: + rename_fn(const table_signature & orig_sig, unsigned permutation_cycle_len, const unsigned * permutation_cycle) + : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle) { + SASSERT(permutation_cycle_len >= 2); + idx_set cycle_cols; + for (unsigned i = 0; i < permutation_cycle_len; ++i) { + cycle_cols.insert(permutation_cycle[i]); + } + for (unsigned i = 0; i < orig_sig.size(); ++i) { + if (!cycle_cols.contains(i)) + m_out_of_cycle.push_back(i); + } + } + + virtual table_base * operator()(const table_base & tb) { + const T & t = static_cast(tb); + T * res = static_cast(t.get_plugin().mk_empty(get_result_signature())); + t.m_bitsets.rename(m_cycle, m_out_of_cycle, t, *res, res->m_bitsets); + TRACE("dl_hassel", tout << "final size: " << res->get_size_estimate_rows() << '\n';); + return res; + } + }; + + public: + virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) { + if (!check_kind(t)) + return 0; + return alloc(rename_fn, t.get_signature(), permutation_cycle_len, permutation_cycle); + } + + private: + class filter_equal_fn : public table_mutator_fn { + typename T::bitset_t m_filter; + public: + filter_equal_fn(const T & t, const table_element val, unsigned col) : + m_filter(t.get_num_bits()) { + ternary_bitvector filter_row(t.get_num_bits(), true); + ternary_bitvector column(val, t.column_num_bits(col)); + filter_row.mk_idx_eq(t.column_idx(col), column); + m_filter.add_new_fact(filter_row); + } + + virtual void operator()(table_base & tb) { + T & t = static_cast(tb); + t.m_bitsets.swap(m_filter.and(t.m_bitsets)); + TRACE("dl_hassel", tout << "final size: " << t.get_size_estimate_rows() << '\n';); + } + }; + + public: + virtual table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value, + unsigned col) { + if (!check_kind(t)) + return 0; + return alloc(filter_equal_fn, static_cast(t), value, col); + } + + private: + static bool cond_is_guard(const expr *e, const table_information& t) { + switch (e->get_kind()) { + case AST_APP: { + const app *app = to_app(e); + switch (app->get_decl_kind()) { + case OP_AND: + case OP_OR: + case OP_NOT: + for (unsigned i = 0; i < app->get_num_args(); ++i) { + if (!cond_is_guard(app->get_arg(i), t)) + return false; + } + return true; + + case OP_EQ: { + const expr *a = app->get_arg(0), *b = app->get_arg(1); + + // column equality is not succinctly representable with TBVs + if (is_var(a) && is_var(b)) + return false; + + // (= var (concat var foo)) + if (t.get_bv_util().is_concat(b)) + return false; + + return true;} + + case OP_FALSE: + case OP_TRUE: + return true; + + default: + return false; + } + break;} + + case AST_VAR: + return true; + + default: + break; + } + return false; + } + + static void split_cond_guard(app *cond, expr_ref& guard, expr_ref& leftover, const table_information& t) { + expr_ref_vector guards(guard.m()); + expr_ref_vector leftovers(leftover.m()); + + if (is_app(cond) && to_app(cond)->get_decl_kind() == OP_AND) { + app *a = to_app(cond); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + expr *arg = a->get_arg(i); + if (cond_is_guard(arg, t)) { + guards.push_back(arg); + } else { + leftovers.push_back(arg); + } + } + } else if (cond_is_guard(cond, t)) { + guard = cond; + return; + } else { + leftover = cond; + return; + } + + if (guards.size() > 1) { + guard = formula_to_dnf(expr_ref(guard.m().mk_and(guards.size(), guards.c_ptr()), guard.m())); + } else if (guards.size() == 1) { + guard = guards.get(0); + } + + if (leftovers.size() > 1) { + leftover = formula_to_dnf(expr_ref(leftover.m().mk_and(leftovers.size(), leftovers.c_ptr()), leftover.m())); + } else if (leftovers.size() == 1) { + leftover = leftovers.get(0); + } + } + + class filter_fn : public table_mutator_fn { + expr_ref m_condition; + typename T::bitset_t m_filter; + bit_vector m_empty_bv; + public: + filter_fn(const T & t, ast_manager& m, app *condition) : + m_condition(m), m_filter(t.get_num_bits(), true) { + m_empty_bv.resize(t.get_num_bits(), false); + + expr_ref guard(m); + split_cond_guard(condition, guard, m_condition, t); + if (guard) + m_filter.filter(guard, m_empty_bv, t); + } + + virtual void operator()(table_base & tb) { + T & t = static_cast(tb); + // first apply guard and then run the interpreter on the leftover + t.m_bitsets.swap(m_filter.and(t.m_bitsets)); + if (m_condition) + t.m_bitsets.filter(m_condition, m_empty_bv, t); + TRACE("dl_hassel", tout << "final size: " << t.get_size_estimate_rows() << '\n';); + } + }; + + public: + virtual table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition) { + if (!check_kind(t)) + return 0; + TRACE("dl_hassel", tout << mk_pp(condition, get_ast_manager()) << '\n';); + return alloc(filter_fn, static_cast(t), get_ast_manager(), condition); + } + + private: + class filter_proj_fn : public convenient_table_project_fn { + expr_ref m_condition; + typename T::bitset_t m_filter; + bit_vector m_col_list; // map: col idx -> bool (whether the column is to be removed) + public: + filter_proj_fn(const T & t, ast_manager& m, app *condition, + unsigned col_cnt, const unsigned * removed_cols) : + convenient_table_project_fn(t.get_signature(), col_cnt, removed_cols), + m_condition(m), m_filter(t.get_num_bits(), true) { + t.expand_column_vector(m_removed_cols); + + m_col_list.resize(t.get_num_bits(), false); + for (unsigned i = 0; i < m_removed_cols.size(); ++i) { + m_col_list.set(m_removed_cols[i]); + } + m_removed_cols.push_back(UINT_MAX); + + expr_ref guard(m); + split_cond_guard(condition, guard, m_condition, t); + if (guard) + m_filter.filter(guard, m_col_list, t); + } + + virtual table_base* operator()(const table_base & tb) { + const T & t = static_cast(tb); + // first apply guard and then run the interpreter on the leftover + typename T::bitset_t filtered(t.get_num_bits()); + filtered.swap(m_filter.and(t.m_bitsets)); + if (m_condition) + filtered.filter(m_condition, m_col_list, t); + + T * res = static_cast(t.get_plugin().mk_empty(get_result_signature())); + filtered.project(m_removed_cols, res->m_bitsets); + TRACE("dl_hassel", tout << "final size: " << res->get_size_estimate_rows() << '\n';); + return res; + } + }; + + public: + virtual table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols) { + if (!check_kind(t)) + return 0; + TRACE("dl_hassel", tout << mk_pp(condition, get_ast_manager()) << '\n';); + return alloc(filter_proj_fn, static_cast(t), get_ast_manager(), + condition, removed_col_cnt, removed_cols); + } + + + virtual table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, const unsigned * t_cols, + const unsigned * negated_cols) { + NOT_IMPLEMENTED_YET(); + } + }; + + template + class common_hassel_table : public table_base, public table_information { + public: + typedef T bitset_t; + + common_hassel_table(table_plugin & p, const table_signature & sig) : + table_base(p, sig), table_information(p, sig), m_bitsets(get_num_bits()) { } + + virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const { + SASSERT(!func_columns); + + if (empty()) + return get_plugin().mk_full(p, get_signature()); + + common_hassel_table *res = static_cast(get_plugin().mk_empty(get_signature())); + res->m_bitsets.swap(m_bitsets.neg()); + return res; + } + + virtual void add_fact(const table_fact & f) { + m_bitsets.add_fact(ternary_bitvector(f, *this)); + } + + virtual void add_new_fact(const table_fact & f) { + m_bitsets.add_new_fact(ternary_bitvector(f, *this)); + } + + virtual void remove_fact(table_element const* fact) { + NOT_IMPLEMENTED_YET(); + } + + virtual void reset() { + m_bitsets.reset(); + } + + void mk_full() { + m_bitsets.mk_full(); + } + + virtual table_base * clone() const { + common_hassel_table *res = static_cast(get_plugin().mk_empty(get_signature())); + res->m_bitsets = m_bitsets; + return res; + } + + virtual bool contains_fact(const table_fact & f) { + return m_bitsets.contains(ternary_bitvector(f, *this)); + } + + virtual bool empty() const { + return m_bitsets.empty(); + } + +#if Z3DEBUG + class our_iterator_core : public iterator_core { + class our_row : public row_interface { + const our_iterator_core & m_parent; + const table_information& m_table; + public: + our_row(const common_hassel_table & t, const our_iterator_core & parent) : + row_interface(t), m_parent(parent), m_table(t) {} + + virtual table_element operator[](unsigned col) const { + return m_parent.it->to_number(m_table.column_idx(col), m_table.column_num_bits(col)); + } + }; + + our_row m_row_obj; + std::set BVs; + std::set::iterator it; + + public: + our_iterator_core(const common_hassel_table & t, bool finished) : + m_row_obj(t, *this) { + if (finished) { + it = BVs.end(); + return; + } + t.m_bitsets.expand(BVs); + it = BVs.begin(); + } + + virtual bool is_finished() const { + return it == BVs.end(); + } + + virtual row_interface & operator*() { + SASSERT(!is_finished()); + return m_row_obj; + } + + virtual void operator++() { + SASSERT(!is_finished()); + ++it; + } + }; +#endif + + virtual iterator begin() const { +#if Z3DEBUG + return mk_iterator(alloc(our_iterator_core, *this, false)); +#else + SASSERT(0 && "begin() disabled"); + return mk_iterator(0); +#endif + } + + virtual iterator end() const { +#if Z3DEBUG + return mk_iterator(alloc(our_iterator_core, *this, true)); +#else + SASSERT(0 && "end() disabled"); + return mk_iterator(0); +#endif + } + + virtual void display(std::ostream & out) const { + table_information::display(out); + m_bitsets.display(out); + } + + virtual void to_formula(relation_signature const& sig, expr_ref& fml) const { + // TODO + } + + virtual unsigned get_size_estimate_rows() const { + return m_bitsets.num_disjs(); + } + + virtual unsigned get_size_estimate_bytes() const { + return m_bitsets.num_bytes(); + } + + T m_bitsets; + }; + +} + +#endif diff --git a/src/muz_qe/dl_hassel_diff_table.cpp b/src/muz_qe/dl_hassel_diff_table.cpp new file mode 100755 index 000000000..3ddcb3bbe --- /dev/null +++ b/src/muz_qe/dl_hassel_diff_table.cpp @@ -0,0 +1,219 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_hassel_diff_table.cpp + +Abstract: + + + +Revision History: + +--*/ + +#include "ast_printer.h" +#include "dl_context.h" +#include "dl_util.h" +#include "dl_hassel_diff_table.h" + + +namespace datalog { + + ternary_diff_bitvector::ternary_diff_bitvector(unsigned size, bool full) : + m_pos(size, full), m_neg(size) { } + + ternary_diff_bitvector::ternary_diff_bitvector(uint64 n, unsigned num_bits) : + m_pos(n, num_bits), m_neg(num_bits) { } + + ternary_diff_bitvector::ternary_diff_bitvector(const ternary_bitvector & tbv) : + m_pos(tbv), m_neg(tbv.size()) { } + + bool ternary_diff_bitvector::contains(const ternary_diff_bitvector & other) const { + return m_pos.contains(other.m_pos) && other.m_neg.contains(m_neg); + } + + bool ternary_diff_bitvector::is_empty() const { + if (m_pos.is_empty()) + return true; + + return m_neg.contains(m_pos); + } + + ternary_diff_bitvector ternary_diff_bitvector::and(const ternary_diff_bitvector& other) const { + ternary_diff_bitvector result(m_pos.and(other.m_pos)); + result.m_neg.swap(m_neg.or(other.m_neg)); + return result; + } + + void ternary_diff_bitvector::neg(union_ternary_bitvector& result) const { + // not(A\B) <-> (T\A) U B + ternary_diff_bitvector negated(size(), true); + negated.m_neg.add_new_fact(m_pos); + result.add_fact(negated); + + for (union_ternary_bitvector::const_iterator I = m_neg.begin(), + E = m_neg.end(); I != E; ++I) { + result.add_fact(*I); + } + } + + void ternary_diff_bitvector::subtract(const union_ternary_bitvector& other, + union_ternary_bitvector& result) const { + ternary_diff_bitvector newfact(*this); + for (union_ternary_bitvector::const_iterator I = other.begin(), + E = other.end(); I != E; ++I) { + if (!I->m_neg.empty()) { + NOT_IMPLEMENTED_YET(); + } + newfact.m_neg.add_fact(I->m_pos); + } + + if (!newfact.is_empty()) + result.add_fact(newfact); + } + + void ternary_diff_bitvector::join(const ternary_diff_bitvector& other, + const unsigned_vector& cols1, + const unsigned_vector& cols2, + union_ternary_bitvector& result) const { + unsigned new_size = size() + other.size(); + ternary_diff_bitvector res(new_size); + + res.m_pos = m_pos; + res.m_pos.append(other.m_pos); + + for (unsigned i = 0; i < cols1.size(); ++i) { + unsigned idx1 = cols1[i]; + unsigned idx2 = size() + cols2[i]; + unsigned v1 = res.m_pos.get(idx1); + unsigned v2 = res.m_pos.get(idx2); + + if (v1 == BIT_x) { + if (v2 == BIT_x) { + // add to subtracted TBVs: 1xx0 and 0xx1 + { + ternary_bitvector r(new_size, true); + r.set(idx1, BIT_0); + r.set(idx2, BIT_1); + res.m_neg.add_new_fact(r); + } + { + ternary_bitvector r(new_size, true); + r.set(idx1, BIT_1); + r.set(idx2, BIT_0); + res.m_neg.add_new_fact(r); + } + } else { + res.m_pos.set(idx1, v2); + } + } else if (v2 == BIT_x) { + res.m_pos.set(idx2, v1); + } else if (v1 != v2) { + // columns don't match + return; + } + } + + // handle subtracted TBVs: 1010 -> 1010xxx + if (!m_neg.empty()) { + ternary_bitvector padding(other.size(), true); + for (union_ternary_bitvector::const_iterator I = m_neg.begin(), + E = m_neg.end(); I != E; ++I) { + ternary_bitvector BV(*I); + BV.append(padding); + res.m_neg.add_new_fact(BV); + } + } + + if (!other.m_neg.empty()) { + ternary_bitvector padding(size(), true); + for (union_ternary_bitvector::const_iterator I = other.m_neg.begin(), + E = other.m_neg.end(); I != E; ++I) { + ternary_bitvector BV(padding); + BV.append(*I); + res.m_neg.add_new_fact(BV); + } + } + + result.add_fact(res); + } + + bool ternary_diff_bitvector::project(const unsigned_vector& delcols, ternary_diff_bitvector& result) const { + m_pos.project(delcols, result.m_pos); + if (m_neg.empty()) + return true; + + ternary_bitvector newneg; + for (union_ternary_bitvector::const_iterator I = m_neg.begin(), + E = m_neg.end(); I != E; ++I) { + for (unsigned i = 0; i < delcols.size()-1; ++i) { + unsigned idx = delcols[i]; + if (I->get(idx) != BIT_x && m_pos.get(idx) == BIT_x) + goto skip_row; + } + newneg.reset(); + I->project(delcols, newneg); + result.m_neg.add_fact(newneg); +skip_row: ; + } + return !result.is_empty(); + } + + void ternary_diff_bitvector::rename(const unsigned_vector& cyclecols, + const unsigned_vector& out_of_cycle_cols, + const table_information& src_table, + const table_information& dst_table, + ternary_diff_bitvector& result) const { + m_pos.rename(cyclecols, out_of_cycle_cols, src_table, dst_table, result.m_pos); + m_neg.rename(cyclecols, out_of_cycle_cols, src_table, dst_table, result.m_neg); + } + + unsigned ternary_diff_bitvector::get(unsigned idx) { + return m_pos.get(idx); + } + + void ternary_diff_bitvector::set(unsigned idx, unsigned val) { + m_pos.set(idx, val); + } + + void ternary_diff_bitvector::swap(ternary_diff_bitvector & other) { + m_pos.swap(other.m_pos); + m_neg.swap(other.m_neg); + } + + void ternary_diff_bitvector::reset() { + m_pos.reset(); + m_neg.reset(); + } + + void ternary_diff_bitvector::display(std::ostream & out) const { + m_pos.display(out); + if (!m_neg.empty()) { + out << " \\ "; + if (m_neg.num_disjs() > 1) out << '('; + m_neg.display(out); + if (m_neg.num_disjs() > 1) out << ')'; + } + } + + unsigned ternary_diff_bitvector::size_in_bytes() const { + return m_pos.size_in_bytes() + m_neg.num_bytes(); + } + +#if Z3DEBUG + void ternary_diff_bitvector::expand(std::set & BVs) const { + m_pos.expand(BVs); + SASSERT(!BVs.empty()); + + std::set NegBVs; + m_neg.expand(NegBVs); + BVs.erase(NegBVs.begin(), NegBVs.end()); + } +#endif + + hassel_diff_table_plugin::hassel_diff_table_plugin(relation_manager & manager) + : common_hassel_table_plugin(symbol("hassel_diff"), manager) {} + +} diff --git a/src/muz_qe/dl_hassel_diff_table.h b/src/muz_qe/dl_hassel_diff_table.h new file mode 100755 index 000000000..07340c7e8 --- /dev/null +++ b/src/muz_qe/dl_hassel_diff_table.h @@ -0,0 +1,87 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_hassel_diff_table.h + +Abstract: + + + +Revision History: + +--*/ + +#ifndef _DL_HASSEL_DIFF_TABLE_H_ +#define _DL_HASSEL_DIFF_TABLE_H_ + +#include "dl_hassel_common.h" + +namespace datalog { + + class hassel_diff_table; + + class ternary_diff_bitvector { + // pos \ (neg0 \/ ... \/ negn) + ternary_bitvector m_pos; + union_ternary_bitvector m_neg; + + public: + ternary_diff_bitvector() : m_pos(), m_neg(0) {} + ternary_diff_bitvector(unsigned size) : m_pos(size), m_neg(size) {} + ternary_diff_bitvector(unsigned size, bool full); + ternary_diff_bitvector(uint64 n, unsigned num_bits); + ternary_diff_bitvector(const ternary_bitvector & tbv); + + bool contains(const ternary_diff_bitvector & other) const; + bool is_empty() const; + + ternary_diff_bitvector and(const ternary_diff_bitvector& other) const; + void neg(union_ternary_bitvector& result) const; + + static bool has_subtract() { return true; } + void subtract(const union_ternary_bitvector& other, + union_ternary_bitvector& result) const; + + void join(const ternary_diff_bitvector& other, const unsigned_vector& cols1, + const unsigned_vector& cols2, union_ternary_bitvector& result) const; + + bool project(const unsigned_vector& delcols, ternary_diff_bitvector& result) const; + + void rename(const unsigned_vector& cyclecols, const unsigned_vector& out_of_cycle_cols, + const table_information& src_table, const table_information& dst_table, + ternary_diff_bitvector& result) const; + + unsigned get(unsigned idx); + void set(unsigned idx, unsigned val); + + void swap(ternary_diff_bitvector & other); + void reset(); + + unsigned size() const { return m_pos.size(); } + + void display(std::ostream & out) const; + unsigned size_in_bytes() const; + +#if Z3DEBUG + void expand(std::set & BVs) const; +#endif + }; + + typedef union_ternary_bitvector union_ternary_diff_bitvector; + + class hassel_diff_table : public common_hassel_table { + public: + hassel_diff_table(table_plugin & p, const table_signature & sig) : + common_hassel_table(p, sig) {} + }; + + class hassel_diff_table_plugin : public common_hassel_table_plugin { + public: + hassel_diff_table_plugin(relation_manager & manager); + }; + +} + +#endif diff --git a/src/muz_qe/dl_hassel_table.cpp b/src/muz_qe/dl_hassel_table.cpp new file mode 100644 index 000000000..6ec28df87 --- /dev/null +++ b/src/muz_qe/dl_hassel_table.cpp @@ -0,0 +1,27 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_hassel_table.cpp + +Abstract: + + + +Revision History: + +--*/ + +#include "ast_printer.h" +#include "dl_context.h" +#include "dl_util.h" +#include "dl_hassel_table.h" + + +namespace datalog { + + hassel_table_plugin::hassel_table_plugin(relation_manager & manager) + : common_hassel_table_plugin(symbol("hassel"), manager) {} + +} diff --git a/src/muz_qe/dl_hassel_table.h b/src/muz_qe/dl_hassel_table.h new file mode 100644 index 000000000..6c4e9c1fe --- /dev/null +++ b/src/muz_qe/dl_hassel_table.h @@ -0,0 +1,39 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_hassel_table.h + +Abstract: + + + +Revision History: + +--*/ + +#ifndef _DL_HASSEL_TABLE_H_ +#define _DL_HASSEL_TABLE_H_ + +#include "dl_hassel_common.h" + +namespace datalog { + + class hassel_table; + typedef union_ternary_bitvector union_ternary_bitvectors; + + class hassel_table : public common_hassel_table { + public: + hassel_table(table_plugin & p, const table_signature & sig) : + common_hassel_table(p, sig) {} + }; + + class hassel_table_plugin : public common_hassel_table_plugin { + public: + hassel_table_plugin(relation_manager & manager); + }; + +} + +#endif diff --git a/src/muz_qe/dl_instruction.cpp b/src/muz_qe/dl_instruction.cpp index b103d743e..6b16968c2 100644 --- a/src/muz_qe/dl_instruction.cpp +++ b/src/muz_qe/dl_instruction.cpp @@ -526,6 +526,64 @@ namespace datalog { return alloc(instr_filter_interpreted, reg, condition); } + class instr_filter_interpreted_and_project : public instruction { + reg_idx m_src; + reg_idx m_res; + app_ref m_cond; + unsigned_vector m_cols; + public: + instr_filter_interpreted_and_project(reg_idx src, app_ref & condition, + unsigned col_cnt, const unsigned * removed_cols, reg_idx result) + : m_src(src), m_cond(condition), m_cols(col_cnt, removed_cols), + m_res(result) {} + + virtual bool perform(execution_context & ctx) { + if (!ctx.reg(m_src)) { + ctx.make_empty(m_res); + return true; + } + + relation_transformer_fn * fn; + relation_base & reg = *ctx.reg(m_src); + if (!find_fn(reg, fn)) { + fn = reg.get_manager().mk_filter_interpreted_and_project_fn(reg, m_cond, m_cols.size(), m_cols.c_ptr()); + if (!fn) { + throw default_exception( + "trying to perform unsupported filter_interpreted_and_project operation on a relation of kind %s", + reg.get_plugin().get_name().bare_str()); + } + store_fn(reg, fn); + } + + ctx.set_reg(m_res, (*fn)(reg)); + + if (ctx.eager_emptiness_checking() && ctx.reg(m_res)->empty()) { + ctx.make_empty(m_res); + } + return true; + } + + virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { + out << "filter_interpreted_and_project " << m_src << " into " << m_res; + out << " using " << mk_pp(m_cond, m_cond.get_manager()); + out << " deleting columns "; + print_container(m_cols, out); + } + + virtual void make_annotations(execution_context & ctx) { + std::stringstream s; + std::string a = "rel_src"; + ctx.get_register_annotation(m_src, a); + s << "filter_interpreted_and_project " << mk_pp(m_cond, m_cond.get_manager()); + ctx.set_register_annotation(m_res, s.str()); + } + }; + + instruction * instruction::mk_filter_interpreted_and_project(reg_idx reg, app_ref & condition, + unsigned col_cnt, const unsigned * removed_cols, reg_idx result) { + return alloc(instr_filter_interpreted_and_project, reg, condition, col_cnt, removed_cols, result); + } + class instr_union : public instruction { reg_idx m_src; @@ -592,6 +650,7 @@ namespace datalog { } } + SASSERT(r_src.get_signature().size() == r_tgt.get_signature().size()); TRACE("dl_verbose", r_tgt.display(tout <<"pre-union:");); (*fn)(r_tgt, r_src, r_delta); diff --git a/src/muz_qe/dl_instruction.h b/src/muz_qe/dl_instruction.h index ae6310ba6..97622c6f3 100644 --- a/src/muz_qe/dl_instruction.h +++ b/src/muz_qe/dl_instruction.h @@ -260,6 +260,8 @@ namespace datalog { static instruction * mk_filter_equal(ast_manager & m, reg_idx reg, const relation_element & value, unsigned col); static instruction * mk_filter_identical(reg_idx reg, unsigned col_cnt, const unsigned * identical_cols); static instruction * mk_filter_interpreted(reg_idx reg, app_ref & condition); + static instruction * mk_filter_interpreted_and_project(reg_idx src, app_ref & condition, + unsigned col_cnt, const unsigned * removed_cols, reg_idx result); static instruction * mk_union(reg_idx src, reg_idx tgt, reg_idx delta); static instruction * mk_widen(reg_idx src, reg_idx tgt, reg_idx delta); static instruction * mk_projection(reg_idx src, unsigned col_cnt, const unsigned * removed_cols, diff --git a/src/muz_qe/dl_relation_manager.cpp b/src/muz_qe/dl_relation_manager.cpp index 986a1f2c4..ce20961f1 100644 --- a/src/muz_qe/dl_relation_manager.cpp +++ b/src/muz_qe/dl_relation_manager.cpp @@ -720,6 +720,13 @@ namespace datalog { return t.get_plugin().mk_filter_interpreted_fn(t, condition); } + relation_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn(const relation_base & t, + app * condition, + unsigned removed_col_cnt, + const unsigned * removed_cols) { + return t.get_plugin().mk_filter_interpreted_and_project_fn(t, condition, removed_col_cnt, removed_cols); + } + class relation_manager::default_relation_select_equal_and_project_fn : public relation_transformer_fn { scoped_ptr m_filter; @@ -1387,6 +1394,45 @@ namespace datalog { } + class relation_manager::default_table_filter_interpreted_and_project_fn + : public table_transformer_fn { + scoped_ptr m_filter; + scoped_ptr m_project; + app_ref m_condition; + unsigned_vector m_removed_cols; + public: + default_table_filter_interpreted_and_project_fn(context & ctx, table_mutator_fn * filter, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) + : m_filter(filter), m_condition(condition, ctx.get_manager()), + m_removed_cols(removed_col_cnt, removed_cols) {} + + virtual table_base* operator()(const table_base & tb) { + table_base *t2 = tb.clone(); + (*m_filter)(*t2); + if (!m_project) { + relation_manager & rmgr = t2->get_plugin().get_manager(); + m_project = rmgr.mk_project_fn(*t2, m_removed_cols.size(), m_removed_cols.c_ptr()); + if (!m_project) { + throw default_exception("projection does not exist"); + } + } + return (*m_project)(*t2); + } + }; + + table_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn(const table_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { + table_transformer_fn * res = t.get_plugin().mk_filter_interpreted_and_project_fn(t, condition, removed_col_cnt, removed_cols); + if (res) + return res; + + table_mutator_fn * filter = mk_filter_interpreted_fn(t, condition); + SASSERT(filter); + res = alloc(default_table_filter_interpreted_and_project_fn, get_context(), filter, condition, removed_col_cnt, removed_cols); + return res; + } + + table_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const table_base & t, const table_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) { table_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, src, joined_col_cnt, diff --git a/src/muz_qe/dl_relation_manager.h b/src/muz_qe/dl_relation_manager.h index f22ae7923..ccdba2783 100644 --- a/src/muz_qe/dl_relation_manager.h +++ b/src/muz_qe/dl_relation_manager.h @@ -55,6 +55,7 @@ namespace datalog { class default_table_filter_equal_fn; class default_table_filter_identical_fn; class default_table_filter_interpreted_fn; + class default_table_filter_interpreted_and_project_fn; class default_table_negation_filter_fn; class default_table_filter_not_equal_fn; class default_table_select_equal_and_project_fn; @@ -350,6 +351,9 @@ namespace datalog { relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols); + /** \brief Operations that returns all rows of \c t for which is column \c col equal to \c value with the column \c col removed. @@ -522,6 +526,9 @@ namespace datalog { table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition); + table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols); + /** \brief Operations that returns all rows of \c t for which is column \c col equal to \c value with the column \c col removed. diff --git a/src/muz_qe/dl_table_relation.cpp b/src/muz_qe/dl_table_relation.cpp index fc661366d..3c30c58bb 100644 --- a/src/muz_qe/dl_table_relation.cpp +++ b/src/muz_qe/dl_table_relation.cpp @@ -354,6 +354,21 @@ namespace datalog { return alloc(tr_mutator_fn, tfun); } + relation_transformer_fn * table_relation_plugin::mk_filter_interpreted_and_project_fn(const relation_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { + if (!t.from_table()) + return 0; + + const table_relation & tr = static_cast(t); + table_transformer_fn * tfun = get_manager().mk_filter_interpreted_and_project_fn(tr.get_table(), + condition, removed_col_cnt, removed_cols); + SASSERT(tfun); + + relation_signature sig; + relation_signature::from_project(t.get_signature(), removed_col_cnt, removed_cols, sig); + return alloc(tr_transformer_fn, sig, tfun); + } + class table_relation_plugin::tr_intersection_filter_fn : public relation_intersection_filter_fn { scoped_ptr m_tfun; public: diff --git a/src/muz_qe/dl_table_relation.h b/src/muz_qe/dl_table_relation.h index 12f0d4eaa..f86143c0f 100644 --- a/src/muz_qe/dl_table_relation.h +++ b/src/muz_qe/dl_table_relation.h @@ -71,6 +71,8 @@ namespace datalog { virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, unsigned col); virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); virtual relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & t, const relation_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols); virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 63e8ba700..3d61c04f0 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -18,6 +18,9 @@ Revision History: Extracted from dl_context --*/ + +#define Z3_HASSEL_TABLE + #include"rel_context.h" #include"dl_context.h" #include"dl_compiler.h" @@ -30,6 +33,10 @@ Revision History: #include"dl_mk_karr_invariants.h" #include"dl_finite_product_relation.h" #include"dl_sparse_table.h" +#ifdef Z3_HASSEL_TABLE +# include"dl_hassel_table.h" +# include"dl_hassel_diff_table.h" +#endif #include"dl_table.h" #include"dl_table_relation.h" #include"aig_exporter.h" @@ -87,6 +94,10 @@ namespace datalog { get_rmanager().register_plugin(alloc(bitvector_table_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(equivalence_table_plugin, get_rmanager())); +#ifdef Z3_HASSEL_TABLE + get_rmanager().register_plugin(alloc(hassel_table_plugin, get_rmanager())); + get_rmanager().register_plugin(alloc(hassel_diff_table_plugin, get_rmanager())); +#endif // register plugins for builtin relations diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index 2c641c5a6..cbe7a0618 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -28,6 +28,7 @@ COMPILE_TIME_ASSERT(sizeof(unsigned) == 4); #define BV_DEFAULT_CAPACITY 2 class bit_vector { +protected: unsigned m_num_bits; unsigned m_capacity; //!< in words unsigned * m_data; @@ -64,6 +65,12 @@ public: m_data(0) { } + bit_vector(unsigned reserve_num_bits) : + m_num_bits(0), + m_capacity(num_words(reserve_num_bits)), + m_data(alloc_svect(unsigned, m_capacity)) { + } + bit_vector(bit_vector const & source): m_num_bits(source.m_num_bits), m_capacity(source.m_capacity), From 60c4973c1d133993dbfd15f2052dd95dbc892f21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 29 May 2013 17:56:23 -0700 Subject: [PATCH 158/281] fix crash in proof generation in BMC Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_bmc_engine.cpp | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp index c313f7d7b..8e9fb510e 100644 --- a/src/muz_qe/dl_bmc_engine.cpp +++ b/src/muz_qe/dl_bmc_engine.cpp @@ -297,6 +297,7 @@ namespace datalog { r->to_formula(fml); r2 = r; rm.substitute(r2, sub.size(), sub.c_ptr()); + proof_ref p(m); if (r0) { VERIFY(unifier.unify_rules(*r0.get(), 0, *r2.get())); expr_ref_vector sub1 = unifier.get_rule_subst(*r0.get(), true); @@ -306,7 +307,10 @@ namespace datalog { r1->to_formula(concl); scoped_proof _sp(m); - proof* p = r->get_proof(); + p = r->get_proof(); + if (!p) { + p = m.mk_asserted(fml); + } proof* premises[2] = { pr, p }; positions.push_back(std::make_pair(0, 1)); @@ -319,13 +323,17 @@ namespace datalog { else { r2->to_formula(concl); scoped_proof _sp(m); - proof* p = r->get_proof(); + p = r->get_proof(); + if (!p) { + p = m.mk_asserted(fml); + } if (sub.empty()) { pr = p; } else { substs.push_back(sub); - pr = m.mk_hyper_resolve(1, &p, concl, positions, substs); + proof* ps[1] = { p }; + pr = m.mk_hyper_resolve(1, ps, concl, positions, substs); } r0 = r2; } @@ -1211,6 +1219,15 @@ namespace datalog { r->to_formula(fml); r2 = r; rm.substitute(r2, sub.size(), sub.c_ptr()); + proof_ref p(m); + { + scoped_proof _sp(m); + p = r->get_proof(); + if (!p) { + p = m.mk_asserted(fml); + } + } + if (r0) { VERIFY(unifier.unify_rules(*r0.get(), 0, *r2.get())); expr_ref_vector sub1 = unifier.get_rule_subst(*r0.get(), true); @@ -1218,9 +1235,8 @@ namespace datalog { apply_subst(sub, sub2); unifier.apply(*r0.get(), 0, *r2.get(), r1); r1->to_formula(concl); - scoped_proof _sp(m); - proof* p = r->get_proof(); + scoped_proof _sp(m); proof* premises[2] = { pr, p }; positions.push_back(std::make_pair(0, 1)); @@ -1233,13 +1249,13 @@ namespace datalog { else { r2->to_formula(concl); scoped_proof _sp(m); - proof* p = r->get_proof(); if (sub.empty()) { pr = p; } else { substs.push_back(sub); - pr = m.mk_hyper_resolve(1, &p, concl, positions, substs); + proof * ps[1] = { p }; + pr = m.mk_hyper_resolve(1, ps, concl, positions, substs); } r0 = r2; } From 37215b03bc9e604387f4d32990b0ba5d30e62a1f Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 29 May 2013 18:18:24 -0700 Subject: [PATCH 159/281] Remove redundant register_on_timeout_proc Signed-off-by: Leonardo de Moura --- src/shell/smtlib_frontend.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index ef0b4ad6b..a005462e2 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -103,7 +103,6 @@ unsigned read_smtlib2_commands(char const * file_name) { install_subpaving_cmds(ctx); g_cmd_context = &ctx; - register_on_timeout_proc(on_timeout); signal(SIGINT, on_ctrl_c); bool result = true; From c0895e5548adca97e50624d527f9a7a68a2dcb86 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 31 May 2013 17:48:19 -0700 Subject: [PATCH 160/281] remove hassel table from unstable: does not compile under other plantforms Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Microsoft.Z3.csproj | 2 +- src/api/ml/README-test-win | 46 +- src/api/ml/README-win | 46 +- src/api/ml/build-lib.cmd | 6 +- src/api/ml/build-test.cmd | 38 +- src/api/ml/exec.cmd | 10 +- src/ast/rewriter/poly_rewriter_def.h | 1864 +++++++++++++------------- src/cmd_context/README | 2 +- src/math/euclid/README | 2 +- src/math/interval/README | 2 +- src/math/polynomial/README | 2 +- src/muz_qe/dl_hassel_common.cpp | 434 ------ src/muz_qe/dl_hassel_common.h | 1079 --------------- src/muz_qe/dl_hassel_diff_table.cpp | 219 --- src/muz_qe/dl_hassel_diff_table.h | 87 -- src/muz_qe/dl_hassel_table.cpp | 27 - src/muz_qe/dl_hassel_table.h | 39 - src/muz_qe/pdr_context.cpp | 11 +- src/muz_qe/rel_context.cpp | 9 - src/smt/database.smt | 2 +- src/smt/theory_utvpi_def.h | 78 +- 21 files changed, 1070 insertions(+), 2935 deletions(-) delete mode 100755 src/muz_qe/dl_hassel_common.cpp delete mode 100755 src/muz_qe/dl_hassel_common.h delete mode 100755 src/muz_qe/dl_hassel_diff_table.cpp delete mode 100755 src/muz_qe/dl_hassel_diff_table.h delete mode 100644 src/muz_qe/dl_hassel_table.cpp delete mode 100644 src/muz_qe/dl_hassel_table.h diff --git a/src/api/dotnet/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj index 8f6e34517..9eb9eb660 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj +++ b/src/api/dotnet/Microsoft.Z3.csproj @@ -399,4 +399,4 @@ --> - \ No newline at end of file + diff --git a/src/api/ml/README-test-win b/src/api/ml/README-test-win index d9be0174b..0e8b73ccd 100644 --- a/src/api/ml/README-test-win +++ b/src/api/ml/README-test-win @@ -1,23 +1,23 @@ -This directory contains scripts to build the test application using -OCaml. You also need CamlIDL to be able to generate the OCaml API. - -- To download OCaml: - http://caml.inria.fr/ocaml/ - -- To download CamlIDL: - http://forge.ocamlcore.org/projects/camlidl/ - -- One must build the OCaml library before compiling the example. - Go to directory ../ocaml - -- Use 'build-test.cmd' to build the test application using the OCaml compiler. - -Remark: The OCaml and C compiler tool chains must be configured in your environment. -Running from the Visual Studio Command Prompt configures the Microsoft C compiler. - -- The script 'exec.cmd' adds the bin directory to the path. So, - test_mlapi.exe can find z3.dll. - - - - +This directory contains scripts to build the test application using +OCaml. You also need CamlIDL to be able to generate the OCaml API. + +- To download OCaml: + http://caml.inria.fr/ocaml/ + +- To download CamlIDL: + http://forge.ocamlcore.org/projects/camlidl/ + +- One must build the OCaml library before compiling the example. + Go to directory ../ocaml + +- Use 'build-test.cmd' to build the test application using the OCaml compiler. + +Remark: The OCaml and C compiler tool chains must be configured in your environment. +Running from the Visual Studio Command Prompt configures the Microsoft C compiler. + +- The script 'exec.cmd' adds the bin directory to the path. So, + test_mlapi.exe can find z3.dll. + + + + diff --git a/src/api/ml/README-win b/src/api/ml/README-win index 91d2faa4f..82ddc2652 100644 --- a/src/api/ml/README-win +++ b/src/api/ml/README-win @@ -1,23 +1,23 @@ -The OCaml API for Z3 was tested using OCaml 3.12.1. -You also need CamlIDL to be able to generate the OCaml API. - -- To download OCaml: - http://caml.inria.fr/ocaml/ - -- To download CamlIDL: - http://forge.ocamlcore.org/projects/camlidl/ - -- To build the OCaml API for Z3: - .\build-lib.cmd - -Remark: The OCaml and C compiler tool chains must be configured in your environment. -Running from the Visual Studio Command Prompt configures the Microsoft C compiler. - -Remark: Building the OCaml API copies some pathnames into files, -so the OCaml API must be recompiled if the Z3 library files are moved. - -See ..\examples\ocaml\build-test.cmd for an example of how to compile and link with Z3. - -Acknowledgements: -The OCaml interface for Z3 was written by Josh Berdine and Jakob Lichtenberg. -Many thanks to them! +The OCaml API for Z3 was tested using OCaml 3.12.1. +You also need CamlIDL to be able to generate the OCaml API. + +- To download OCaml: + http://caml.inria.fr/ocaml/ + +- To download CamlIDL: + http://forge.ocamlcore.org/projects/camlidl/ + +- To build the OCaml API for Z3: + .\build-lib.cmd + +Remark: The OCaml and C compiler tool chains must be configured in your environment. +Running from the Visual Studio Command Prompt configures the Microsoft C compiler. + +Remark: Building the OCaml API copies some pathnames into files, +so the OCaml API must be recompiled if the Z3 library files are moved. + +See ..\examples\ocaml\build-test.cmd for an example of how to compile and link with Z3. + +Acknowledgements: +The OCaml interface for Z3 was written by Josh Berdine and Jakob Lichtenberg. +Many thanks to them! diff --git a/src/api/ml/build-lib.cmd b/src/api/ml/build-lib.cmd index 93d667a34..7cf1bbcbd 100755 --- a/src/api/ml/build-lib.cmd +++ b/src/api/ml/build-lib.cmd @@ -1,3 +1,3 @@ -@echo off - -call .\compile_mlapi.cmd ..\include ..\bin ..\bin +@echo off + +call .\compile_mlapi.cmd ..\include ..\bin ..\bin diff --git a/src/api/ml/build-test.cmd b/src/api/ml/build-test.cmd index 7b80dc795..13a752dbb 100755 --- a/src/api/ml/build-test.cmd +++ b/src/api/ml/build-test.cmd @@ -1,19 +1,19 @@ -@echo off - -if not exist ..\..\ocaml\z3.cmxa ( - echo "YOU MUST BUILD OCAML API! Go to directory ..\ocaml" - goto :EOF -) - -REM ocaml (>= 3.11) calls the linker through flexlink -ocamlc -version >> ocaml_version -set /p OCAML_VERSION= = 3.11) calls the linker through flexlink +ocamlc -version >> ocaml_version +set /p OCAML_VERSION= -char const * poly_rewriter::g_ste_blowup_msg = "sum of monomials blowup"; - - -template -void poly_rewriter::updt_params(params_ref const & _p) { - poly_rewriter_params p(_p); - m_flat = p.flat(); - m_som = p.som(); - m_hoist_mul = p.hoist_mul(); - m_hoist_cmul = p.hoist_cmul(); - m_som_blowup = p.som_blowup(); -} - -template -void poly_rewriter::get_param_descrs(param_descrs & r) { - poly_rewriter_params::collect_param_descrs(r); -} - -template -expr * poly_rewriter::mk_add_app(unsigned num_args, expr * const * args) { - switch (num_args) { - case 0: return mk_numeral(numeral(0)); - case 1: return args[0]; - default: return m().mk_app(get_fid(), add_decl_kind(), num_args, args); - } -} - -// t = (^ x y) --> return x, and set k = y if k is an integer >= 1 -// Otherwise return t and set k = 1 -template -expr * poly_rewriter::get_power_body(expr * t, rational & k) { - if (!is_power(t)) { - k = rational(1); - return t; - } - if (is_numeral(to_app(t)->get_arg(1), k) && k.is_int() && k > rational(1)) { - return to_app(t)->get_arg(0); - } - k = rational(1); - return t; -} - -template -expr * poly_rewriter::mk_mul_app(unsigned num_args, expr * const * args) { - switch (num_args) { - case 0: - return mk_numeral(numeral(1)); - case 1: - return args[0]; - default: - if (use_power()) { - rational k_prev; - expr * prev = get_power_body(args[0], k_prev); - rational k; - ptr_buffer new_args; -#define PUSH_POWER() { \ - if (k_prev.is_one()) { \ - new_args.push_back(prev); \ - } \ - else { \ - expr * pargs[2] = { prev, mk_numeral(k_prev) }; \ - new_args.push_back(m().mk_app(get_fid(), power_decl_kind(), 2, pargs)); \ - } \ - } - - for (unsigned i = 1; i < num_args; i++) { - expr * arg = get_power_body(args[i], k); - if (arg == prev) { - k_prev += k; - } - else { - PUSH_POWER(); - prev = arg; - k_prev = k; - } - } - PUSH_POWER(); - SASSERT(new_args.size() > 0); - if (new_args.size() == 1) { - return new_args[0]; - } - else { - return m().mk_app(get_fid(), mul_decl_kind(), new_args.size(), new_args.c_ptr()); - } - } - else { - return m().mk_app(get_fid(), mul_decl_kind(), num_args, args); - } - } -} - -template -expr * poly_rewriter::mk_mul_app(numeral const & c, expr * arg) { - if (c.is_one()) { - return arg; - } - else { - expr * new_args[2] = { mk_numeral(c), arg }; - return mk_mul_app(2, new_args); - } -} - -template -br_status poly_rewriter::mk_flat_mul_core(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args >= 2); - // only try to apply flattening if it is not already in one of the flat monomial forms - // - (* c x) - // - (* c (* x_1 ... x_n)) - if (num_args != 2 || !is_numeral(args[0]) || (is_mul(args[1]) && is_numeral(to_app(args[1])->get_arg(0)))) { - unsigned i; - for (i = 0; i < num_args; i++) { - if (is_mul(args[i])) - break; - } - if (i < num_args) { - // input has nested monomials. - ptr_buffer flat_args; - // we need the todo buffer to handle: (* (* c (* x_1 ... x_n)) (* d (* y_1 ... y_n))) - ptr_buffer todo; - flat_args.append(i, args); - for (unsigned j = i; j < num_args; j++) { - if (is_mul(args[j])) { - todo.push_back(args[j]); - while (!todo.empty()) { - expr * curr = todo.back(); - todo.pop_back(); - if (is_mul(curr)) { - unsigned k = to_app(curr)->get_num_args(); - while (k > 0) { - --k; - todo.push_back(to_app(curr)->get_arg(k)); - } - } - else { - flat_args.push_back(curr); - } - } - } - else { - flat_args.push_back(args[j]); - } - } - TRACE("poly_rewriter", - tout << "flat mul:\n"; - for (unsigned i = 0; i < num_args; i++) tout << mk_bounded_pp(args[i], m()) << "\n"; - tout << "---->\n"; - for (unsigned i = 0; i < flat_args.size(); i++) tout << mk_bounded_pp(flat_args[i], m()) << "\n";); - br_status st = mk_nflat_mul_core(flat_args.size(), flat_args.c_ptr(), result); - if (st == BR_FAILED) { - result = mk_mul_app(flat_args.size(), flat_args.c_ptr()); - return BR_DONE; - } - return st; - } - } - return mk_nflat_mul_core(num_args, args, result); -} - - -template -struct poly_rewriter::mon_pw_lt { - poly_rewriter & m_owner; - mon_pw_lt(poly_rewriter & o):m_owner(o) {} - - bool operator()(expr * n1, expr * n2) const { - rational k; - return lt(m_owner.get_power_body(n1, k), - m_owner.get_power_body(n2, k)); - } -}; - - -template -br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args >= 2); - // cheap case - numeral a; - if (num_args == 2 && is_numeral(args[0], a) && !a.is_one() && !a.is_zero() && - (is_var(args[1]) || to_app(args[1])->get_decl()->get_family_id() != get_fid())) - return BR_FAILED; - numeral c(1); - unsigned num_coeffs = 0; - unsigned num_add = 0; - expr * var = 0; - for (unsigned i = 0; i < num_args; i++) { - expr * arg = args[i]; - if (is_numeral(arg, a)) { - num_coeffs++; - c *= a; - } - else { - var = arg; - if (is_add(arg)) - num_add++; - } - } - - normalize(c); - // (* c_1 ... c_n) --> c_1*...*c_n - if (num_coeffs == num_args) { - result = mk_numeral(c); - return BR_DONE; - } - - // (* s ... 0 ... r) --> 0 - if (c.is_zero()) { - result = mk_numeral(c); - return BR_DONE; - } - - if (num_coeffs == num_args - 1) { - SASSERT(var != 0); - // (* c_1 ... c_n x) --> x if c_1*...*c_n == 1 - if (c.is_one()) { - result = var; - return BR_DONE; - } - - numeral c_prime; - if (is_mul(var)) { - // apply basic simplification even when flattening is not enabled. - // (* c1 (* c2 x)) --> (* c1*c2 x) - if (to_app(var)->get_num_args() == 2 && is_numeral(to_app(var)->get_arg(0), c_prime)) { - c *= c_prime; - normalize(c); - result = mk_mul_app(c, to_app(var)->get_arg(1)); - return BR_REWRITE1; - } - else { - // var is a power-product - return BR_FAILED; - } - } - - if (num_add == 0 || m_hoist_cmul) { - SASSERT(!is_add(var) || m_hoist_cmul); - if (num_args == 2 && args[1] == var) { - DEBUG_CODE({ - numeral c_prime; - SASSERT(is_numeral(args[0], c_prime) && c == c_prime); - }); - // it is already simplified - return BR_FAILED; - } - - // (* c_1 ... c_n x) --> (* c_1*...*c_n x) - result = mk_mul_app(c, var); - return BR_DONE; - } - else { - SASSERT(is_add(var)); - // (* c_1 ... c_n (+ t_1 ... t_m)) --> (+ (* c_1*...*c_n t_1) ... (* c_1*...*c_n t_m)) - ptr_buffer new_add_args; - unsigned num = to_app(var)->get_num_args(); - for (unsigned i = 0; i < num; i++) { - new_add_args.push_back(mk_mul_app(c, to_app(var)->get_arg(i))); - } - result = mk_add_app(new_add_args.size(), new_add_args.c_ptr()); - TRACE("mul_bug", tout << "result: " << mk_bounded_pp(result, m(),5) << "\n";); - return BR_REWRITE2; - } - } - - SASSERT(num_coeffs <= num_args - 2); - - if (!m_som || num_add == 0) { - ptr_buffer new_args; - expr * prev = 0; - bool ordered = true; - for (unsigned i = 0; i < num_args; i++) { - expr * curr = args[i]; - if (is_numeral(curr)) - continue; - if (prev != 0 && lt(curr, prev)) - ordered = false; - new_args.push_back(curr); - prev = curr; - } - TRACE("poly_rewriter", - for (unsigned i = 0; i < new_args.size(); i++) { - if (i > 0) - tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< "); - tout << mk_ismt2_pp(new_args[i], m()); - } - tout << "\nordered: " << ordered << "\n";); - if (ordered && num_coeffs == 0 && !use_power()) - return BR_FAILED; - if (!ordered) { - if (use_power()) - std::sort(new_args.begin(), new_args.end(), mon_pw_lt(*this)); - else - std::sort(new_args.begin(), new_args.end(), ast_to_lt()); - TRACE("poly_rewriter", - tout << "after sorting:\n"; - for (unsigned i = 0; i < new_args.size(); i++) { - if (i > 0) - tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< "); - tout << mk_ismt2_pp(new_args[i], m()); - } - tout << "\n";); - } - SASSERT(new_args.size() >= 2); - result = mk_mul_app(new_args.size(), new_args.c_ptr()); - result = mk_mul_app(c, result); - TRACE("poly_rewriter", tout << "mk_nflat_mul_core result:\n" << mk_ismt2_pp(result, m()) << "\n";); - return BR_DONE; - } - - SASSERT(m_som && num_add > 0); - - sbuffer szs; - sbuffer it; - sbuffer sums; - for (unsigned i = 0; i < num_args; i ++) { - it.push_back(0); - expr * arg = args[i]; - if (is_add(arg)) { - sums.push_back(const_cast(to_app(arg)->get_args())); - szs.push_back(to_app(arg)->get_num_args()); - } - else { - sums.push_back(const_cast(args + i)); - szs.push_back(1); - SASSERT(sums.back()[0] == arg); - } - } - expr_ref_buffer sum(m()); // must be ref_buffer because we may throw an exception - ptr_buffer m_args; - TRACE("som", tout << "starting som...\n";); - do { - TRACE("som", for (unsigned i = 0; i < it.size(); i++) tout << it[i] << " "; - tout << "\n";); - if (sum.size() > m_som_blowup) - throw rewriter_exception(g_ste_blowup_msg); - m_args.reset(); - for (unsigned i = 0; i < num_args; i++) { - expr * const * v = sums[i]; - expr * arg = v[it[i]]; - m_args.push_back(arg); - } - sum.push_back(mk_mul_app(m_args.size(), m_args.c_ptr())); - } - while (product_iterator_next(szs.size(), szs.c_ptr(), it.c_ptr())); - result = mk_add_app(sum.size(), sum.c_ptr()); - return BR_REWRITE2; -} - -template -br_status poly_rewriter::mk_flat_add_core(unsigned num_args, expr * const * args, expr_ref & result) { - unsigned i; - for (i = 0; i < num_args; i++) { - if (is_add(args[i])) - break; - } - if (i < num_args) { - // has nested ADDs - ptr_buffer flat_args; - flat_args.append(i, args); - for (; i < num_args; i++) { - expr * arg = args[i]; - // Remark: all rewrites are depth 1. - if (is_add(arg)) { - unsigned num = to_app(arg)->get_num_args(); - for (unsigned j = 0; j < num; j++) - flat_args.push_back(to_app(arg)->get_arg(j)); - } - else { - flat_args.push_back(arg); - } - } - br_status st = mk_nflat_add_core(flat_args.size(), flat_args.c_ptr(), result); - if (st == BR_FAILED) { - result = mk_add_app(flat_args.size(), flat_args.c_ptr()); - return BR_DONE; - } - return st; - } - return mk_nflat_add_core(num_args, args, result); -} - -template -inline expr * poly_rewriter::get_power_product(expr * t) { - if (is_mul(t) && to_app(t)->get_num_args() == 2 && is_numeral(to_app(t)->get_arg(0))) - return to_app(t)->get_arg(1); - return t; -} - -template -inline expr * poly_rewriter::get_power_product(expr * t, numeral & a) { - if (is_mul(t) && to_app(t)->get_num_args() == 2 && is_numeral(to_app(t)->get_arg(0), a)) - return to_app(t)->get_arg(1); - a = numeral(1); - return t; -} - -template -bool poly_rewriter::is_mul(expr * t, numeral & c, expr * & pp) { - if (!is_mul(t) || to_app(t)->get_num_args() != 2) - return false; - if (!is_numeral(to_app(t)->get_arg(0), c)) - return false; - pp = to_app(t)->get_arg(1); - return true; -} - -template -struct poly_rewriter::hoist_cmul_lt { - poly_rewriter & m_r; - hoist_cmul_lt(poly_rewriter & r):m_r(r) {} - - bool operator()(expr * t1, expr * t2) const { - expr * pp1, * pp2; - numeral c1, c2; - bool is_mul1 = m_r.is_mul(t1, c1, pp1); - bool is_mul2 = m_r.is_mul(t2, c2, pp2); - if (!is_mul1 && is_mul2) - return true; - if (is_mul1 && !is_mul2) - return false; - if (!is_mul1 && !is_mul2) - return t1->get_id() < t2->get_id(); - if (c1 < c2) - return true; - if (c1 > c2) - return false; - return pp1->get_id() < pp2->get_id(); - } -}; - -template -void poly_rewriter::hoist_cmul(expr_ref_buffer & args) { - unsigned sz = args.size(); - std::sort(args.c_ptr(), args.c_ptr() + sz, hoist_cmul_lt(*this)); - numeral c, c_prime; - ptr_buffer pps; - expr * pp, * pp_prime; - unsigned j = 0; - unsigned i = 0; - while (i < sz) { - expr * mon = args[i]; - if (is_mul(mon, c, pp) && i < sz - 1) { - expr * mon_prime = args[i+1]; - if (is_mul(mon_prime, c_prime, pp_prime) && c == c_prime) { - // found target - pps.reset(); - pps.push_back(pp); - pps.push_back(pp_prime); - i += 2; - while (i < sz && is_mul(args[i], c_prime, pp_prime) && c == c_prime) { - pps.push_back(pp_prime); - i++; - } - SASSERT(is_numeral(to_app(mon)->get_arg(0), c_prime) && c == c_prime); - expr * mul_args[2] = { to_app(mon)->get_arg(0), mk_add_app(pps.size(), pps.c_ptr()) }; - args.set(j, mk_mul_app(2, mul_args)); - j++; - continue; - } - } - args.set(j, mon); - j++; - i++; - } - args.resize(j); -} - -template -br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args >= 2); - numeral c; - unsigned num_coeffs = 0; - numeral a; - expr_fast_mark1 visited; // visited.is_marked(power_product) if the power_product occurs in args - expr_fast_mark2 multiple; // multiple.is_marked(power_product) if power_product occurs more than once - bool has_multiple = false; - expr * prev = 0; - bool ordered = true; - for (unsigned i = 0; i < num_args; i++) { - expr * arg = args[i]; - if (is_numeral(arg, a)) { - num_coeffs++; - c += a; - } - else { - // arg is not a numeral - if (m_sort_sums && ordered) { - if (prev != 0 && lt(arg, prev)) - ordered = false; - prev = arg; - } - } - - arg = get_power_product(arg); - if (visited.is_marked(arg)) { - multiple.mark(arg); - has_multiple = true; - } - else { - visited.mark(arg); - } - } - normalize(c); - SASSERT(m_sort_sums || ordered); - TRACE("sort_sums", - tout << "ordered: " << ordered << "\n"; - for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";); - - if (has_multiple) { - // expensive case - buffer coeffs; - m_expr2pos.reset(); - // compute the coefficient of power products that occur multiple times. - for (unsigned i = 0; i < num_args; i++) { - expr * arg = args[i]; - if (is_numeral(arg)) - continue; - expr * pp = get_power_product(arg, a); - if (!multiple.is_marked(pp)) - continue; - unsigned pos; - if (m_expr2pos.find(pp, pos)) { - coeffs[pos] += a; - } - else { - m_expr2pos.insert(pp, coeffs.size()); - coeffs.push_back(a); - } - } - expr_ref_buffer new_args(m()); - if (!c.is_zero()) { - new_args.push_back(mk_numeral(c)); - } - // copy power products with non zero coefficients to new_args - visited.reset(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = args[i]; - if (is_numeral(arg)) - continue; - expr * pp = get_power_product(arg); - if (!multiple.is_marked(pp)) { - new_args.push_back(arg); - } - else if (!visited.is_marked(pp)) { - visited.mark(pp); - unsigned pos = UINT_MAX; - m_expr2pos.find(pp, pos); - SASSERT(pos != UINT_MAX); - a = coeffs[pos]; - normalize(a); - if (!a.is_zero()) - new_args.push_back(mk_mul_app(a, pp)); - } - } - if (m_hoist_cmul) { - hoist_cmul(new_args); - } - else if (m_sort_sums) { - TRACE("sort_sums_bug", tout << "new_args.size(): " << new_args.size() << "\n";); - if (c.is_zero()) - std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt()); - else - std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt()); - } - result = mk_add_app(new_args.size(), new_args.c_ptr()); - if (hoist_multiplication(result)) { - return BR_REWRITE_FULL; - } - return BR_DONE; - } - else { - SASSERT(!has_multiple); - if (ordered && !m_hoist_mul && !m_hoist_cmul) { - if (num_coeffs == 0) - return BR_FAILED; - if (num_coeffs == 1 && is_numeral(args[0], a) && !a.is_zero()) - return BR_FAILED; - } - expr_ref_buffer new_args(m()); - if (!c.is_zero()) - new_args.push_back(mk_numeral(c)); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = args[i]; - if (is_numeral(arg)) - continue; - new_args.push_back(arg); - } - if (m_hoist_cmul) { - hoist_cmul(new_args); - } - else if (!ordered) { - if (c.is_zero()) - std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt()); - else - std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt()); - } - result = mk_add_app(new_args.size(), new_args.c_ptr()); - if (hoist_multiplication(result)) { - return BR_REWRITE_FULL; - } - return BR_DONE; - } -} - - -template -br_status poly_rewriter::mk_uminus(expr * arg, expr_ref & result) { - numeral a; - set_curr_sort(m().get_sort(arg)); - if (is_numeral(arg, a)) { - a.neg(); - normalize(a); - result = mk_numeral(a); - return BR_DONE; - } - else { - result = mk_mul_app(numeral(-1), arg); - return BR_REWRITE1; - } -} - -template -br_status poly_rewriter::mk_sub(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args > 0); - if (num_args == 1) { - result = args[0]; - return BR_DONE; - } - set_curr_sort(m().get_sort(args[0])); - expr * minus_one = mk_numeral(numeral(-1)); - ptr_buffer new_args; - new_args.push_back(args[0]); - for (unsigned i = 1; i < num_args; i++) { - expr * aux_args[2] = { minus_one, args[i] }; - new_args.push_back(mk_mul_app(2, aux_args)); - } - result = mk_add_app(new_args.size(), new_args.c_ptr()); - return BR_REWRITE2; -} - -/** - \brief Cancel/Combine monomials that occur is the left and right hand sides. - - \remark If move = true, then all non-constant monomials are moved to the left-hand-side. -*/ -template -br_status poly_rewriter::cancel_monomials(expr * lhs, expr * rhs, bool move, expr_ref & lhs_result, expr_ref & rhs_result) { - set_curr_sort(m().get_sort(lhs)); - unsigned lhs_sz; - expr * const * lhs_monomials = get_monomials(lhs, lhs_sz); - unsigned rhs_sz; - expr * const * rhs_monomials = get_monomials(rhs, rhs_sz); - - expr_fast_mark1 visited; // visited.is_marked(power_product) if the power_product occurs in lhs or rhs - expr_fast_mark2 multiple; // multiple.is_marked(power_product) if power_product occurs more than once - bool has_multiple = false; - - numeral c(0); - numeral a; - unsigned num_coeffs = 0; - - for (unsigned i = 0; i < lhs_sz; i++) { - expr * arg = lhs_monomials[i]; - if (is_numeral(arg, a)) { - c += a; - num_coeffs++; - } - else { - visited.mark(get_power_product(arg)); - } - } - - if (move && num_coeffs == 0 && is_numeral(rhs)) - return BR_FAILED; - - for (unsigned i = 0; i < rhs_sz; i++) { - expr * arg = rhs_monomials[i]; - if (is_numeral(arg, a)) { - c -= a; - num_coeffs++; - } - else { - expr * pp = get_power_product(arg); - if (visited.is_marked(pp)) { - multiple.mark(pp); - has_multiple = true; - } - } - } - - normalize(c); - - if (!has_multiple && num_coeffs <= 1) { - if (move) { - if (is_numeral(rhs)) - return BR_FAILED; - } - else { - if (num_coeffs == 0 || is_numeral(rhs)) - return BR_FAILED; - } - } - - buffer coeffs; - m_expr2pos.reset(); - for (unsigned i = 0; i < lhs_sz; i++) { - expr * arg = lhs_monomials[i]; - if (is_numeral(arg)) - continue; - expr * pp = get_power_product(arg, a); - if (!multiple.is_marked(pp)) - continue; - unsigned pos; - if (m_expr2pos.find(pp, pos)) { - coeffs[pos] += a; - } - else { - m_expr2pos.insert(pp, coeffs.size()); - coeffs.push_back(a); - } - } - - for (unsigned i = 0; i < rhs_sz; i++) { - expr * arg = rhs_monomials[i]; - if (is_numeral(arg)) - continue; - expr * pp = get_power_product(arg, a); - if (!multiple.is_marked(pp)) - continue; - unsigned pos = UINT_MAX; - m_expr2pos.find(pp, pos); - SASSERT(pos != UINT_MAX); - coeffs[pos] -= a; - } - - - ptr_buffer new_lhs_monomials; - new_lhs_monomials.push_back(0); // save space for coefficient if needed - // copy power products with non zero coefficients to new_lhs_monomials - visited.reset(); - for (unsigned i = 0; i < lhs_sz; i++) { - expr * arg = lhs_monomials[i]; - if (is_numeral(arg)) - continue; - expr * pp = get_power_product(arg); - if (!multiple.is_marked(pp)) { - new_lhs_monomials.push_back(arg); - } - else if (!visited.is_marked(pp)) { - visited.mark(pp); - unsigned pos = UINT_MAX; - m_expr2pos.find(pp, pos); - SASSERT(pos != UINT_MAX); - a = coeffs[pos]; - if (!a.is_zero()) - new_lhs_monomials.push_back(mk_mul_app(a, pp)); - } - } - - ptr_buffer new_rhs_monomials; - new_rhs_monomials.push_back(0); // save space for coefficient if needed - for (unsigned i = 0; i < rhs_sz; i++) { - expr * arg = rhs_monomials[i]; - if (is_numeral(arg)) - continue; - expr * pp = get_power_product(arg, a); - if (!multiple.is_marked(pp)) { - if (move) { - if (!a.is_zero()) { - if (a.is_minus_one()) { - new_lhs_monomials.push_back(pp); - } - else { - a.neg(); - SASSERT(!a.is_one()); - expr * args[2] = { mk_numeral(a), pp }; - new_lhs_monomials.push_back(mk_mul_app(2, args)); - } - } - } - else { - new_rhs_monomials.push_back(arg); - } - } - } - - bool c_at_rhs = false; - if (move) { - if (m_sort_sums) { - // + 1 to skip coefficient - std::sort(new_lhs_monomials.begin() + 1, new_lhs_monomials.end(), ast_to_lt()); - } - c_at_rhs = true; - } - else if (new_rhs_monomials.size() == 1) { // rhs is empty - c_at_rhs = true; - } - else if (new_lhs_monomials.size() > 1) { - c_at_rhs = true; - } - - if (c_at_rhs) { - c.neg(); - normalize(c); - new_rhs_monomials[0] = mk_numeral(c); - lhs_result = mk_add_app(new_lhs_monomials.size() - 1, new_lhs_monomials.c_ptr() + 1); - rhs_result = mk_add_app(new_rhs_monomials.size(), new_rhs_monomials.c_ptr()); - } - else { - new_lhs_monomials[0] = mk_numeral(c); - lhs_result = mk_add_app(new_lhs_monomials.size(), new_lhs_monomials.c_ptr()); - rhs_result = mk_add_app(new_rhs_monomials.size() - 1, new_rhs_monomials.c_ptr() + 1); - } - return BR_DONE; -} - -#define TO_BUFFER(_tester_, _buffer_, _e_) \ - _buffer_.push_back(_e_); \ - for (unsigned _i = 0; _i < _buffer_.size(); ) { \ - expr* _e = _buffer_[_i]; \ - if (_tester_(_e)) { \ - app* a = to_app(_e); \ - _buffer_[_i] = a->get_arg(0); \ - for (unsigned _j = 1; _j < a->get_num_args(); ++_j) { \ - _buffer_.push_back(a->get_arg(_j)); \ - } \ - } \ - else { \ - ++_i; \ - } \ - } \ - -template -bool poly_rewriter::hoist_multiplication(expr_ref& som) { - if (!m_hoist_mul) { - return false; - } - ptr_buffer adds, muls; - TO_BUFFER(is_add, adds, som); - buffer valid(adds.size(), true); - obj_map mul_map; - unsigned j; - bool change = false; - for (unsigned k = 0; k < adds.size(); ++k) { - expr* e = adds[k]; - muls.reset(); - TO_BUFFER(is_mul, muls, e); - for (unsigned i = 0; i < muls.size(); ++i) { - e = muls[i]; - if (is_numeral(e)) { - continue; - } - if (mul_map.find(e, j) && valid[j] && j != k) { - m_curr_sort = m().get_sort(adds[k]); - adds[j] = merge_muls(adds[j], adds[k]); - adds[k] = mk_numeral(rational(0)); - valid[j] = false; - valid[k] = false; - change = true; - break; - } - else { - mul_map.insert(e, k); - } - } - } - if (!change) { - return false; - } - - som = mk_add_app(adds.size(), adds.c_ptr()); - - - return true; -} - -template -expr* poly_rewriter::merge_muls(expr* x, expr* y) { - ptr_buffer m1, m2; - TO_BUFFER(is_mul, m1, x); - TO_BUFFER(is_mul, m2, y); - unsigned k = 0; - for (unsigned i = 0; i < m1.size(); ++i) { - x = m1[i]; - bool found = false; - unsigned j; - for (j = k; j < m2.size(); ++j) { - found = m2[j] == x; - if (found) break; - } - if (found) { - std::swap(m1[i],m1[k]); - std::swap(m2[j],m2[k]); - ++k; - } - } - m_curr_sort = m().get_sort(x); - SASSERT(k > 0); - SASSERT(m1.size() >= k); - SASSERT(m2.size() >= k); - expr* args[2] = { mk_mul_app(m1.size()-k, m1.c_ptr()+k), - mk_mul_app(m2.size()-k, m2.c_ptr()+k) }; - if (k == m1.size()) { - m1.push_back(0); - } - m1[k] = mk_add_app(2, args); - return mk_mul_app(k+1, m1.c_ptr()); -} +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + poly_rewriter_def.h + +Abstract: + + Basic rewriting rules for Polynomials. + +Author: + + Leonardo (leonardo) 2011-04-08 + +Notes: + +--*/ +#include"poly_rewriter.h" +#include"poly_rewriter_params.hpp" +#include"ast_lt.h" +#include"ast_ll_pp.h" +#include"ast_smt2_pp.h" + +template +char const * poly_rewriter::g_ste_blowup_msg = "sum of monomials blowup"; + + +template +void poly_rewriter::updt_params(params_ref const & _p) { + poly_rewriter_params p(_p); + m_flat = p.flat(); + m_som = p.som(); + m_hoist_mul = p.hoist_mul(); + m_hoist_cmul = p.hoist_cmul(); + m_som_blowup = p.som_blowup(); +} + +template +void poly_rewriter::get_param_descrs(param_descrs & r) { + poly_rewriter_params::collect_param_descrs(r); +} + +template +expr * poly_rewriter::mk_add_app(unsigned num_args, expr * const * args) { + switch (num_args) { + case 0: return mk_numeral(numeral(0)); + case 1: return args[0]; + default: return m().mk_app(get_fid(), add_decl_kind(), num_args, args); + } +} + +// t = (^ x y) --> return x, and set k = y if k is an integer >= 1 +// Otherwise return t and set k = 1 +template +expr * poly_rewriter::get_power_body(expr * t, rational & k) { + if (!is_power(t)) { + k = rational(1); + return t; + } + if (is_numeral(to_app(t)->get_arg(1), k) && k.is_int() && k > rational(1)) { + return to_app(t)->get_arg(0); + } + k = rational(1); + return t; +} + +template +expr * poly_rewriter::mk_mul_app(unsigned num_args, expr * const * args) { + switch (num_args) { + case 0: + return mk_numeral(numeral(1)); + case 1: + return args[0]; + default: + if (use_power()) { + rational k_prev; + expr * prev = get_power_body(args[0], k_prev); + rational k; + ptr_buffer new_args; +#define PUSH_POWER() { \ + if (k_prev.is_one()) { \ + new_args.push_back(prev); \ + } \ + else { \ + expr * pargs[2] = { prev, mk_numeral(k_prev) }; \ + new_args.push_back(m().mk_app(get_fid(), power_decl_kind(), 2, pargs)); \ + } \ + } + + for (unsigned i = 1; i < num_args; i++) { + expr * arg = get_power_body(args[i], k); + if (arg == prev) { + k_prev += k; + } + else { + PUSH_POWER(); + prev = arg; + k_prev = k; + } + } + PUSH_POWER(); + SASSERT(new_args.size() > 0); + if (new_args.size() == 1) { + return new_args[0]; + } + else { + return m().mk_app(get_fid(), mul_decl_kind(), new_args.size(), new_args.c_ptr()); + } + } + else { + return m().mk_app(get_fid(), mul_decl_kind(), num_args, args); + } + } +} + +template +expr * poly_rewriter::mk_mul_app(numeral const & c, expr * arg) { + if (c.is_one()) { + return arg; + } + else { + expr * new_args[2] = { mk_numeral(c), arg }; + return mk_mul_app(2, new_args); + } +} + +template +br_status poly_rewriter::mk_flat_mul_core(unsigned num_args, expr * const * args, expr_ref & result) { + SASSERT(num_args >= 2); + // only try to apply flattening if it is not already in one of the flat monomial forms + // - (* c x) + // - (* c (* x_1 ... x_n)) + if (num_args != 2 || !is_numeral(args[0]) || (is_mul(args[1]) && is_numeral(to_app(args[1])->get_arg(0)))) { + unsigned i; + for (i = 0; i < num_args; i++) { + if (is_mul(args[i])) + break; + } + if (i < num_args) { + // input has nested monomials. + ptr_buffer flat_args; + // we need the todo buffer to handle: (* (* c (* x_1 ... x_n)) (* d (* y_1 ... y_n))) + ptr_buffer todo; + flat_args.append(i, args); + for (unsigned j = i; j < num_args; j++) { + if (is_mul(args[j])) { + todo.push_back(args[j]); + while (!todo.empty()) { + expr * curr = todo.back(); + todo.pop_back(); + if (is_mul(curr)) { + unsigned k = to_app(curr)->get_num_args(); + while (k > 0) { + --k; + todo.push_back(to_app(curr)->get_arg(k)); + } + } + else { + flat_args.push_back(curr); + } + } + } + else { + flat_args.push_back(args[j]); + } + } + TRACE("poly_rewriter", + tout << "flat mul:\n"; + for (unsigned i = 0; i < num_args; i++) tout << mk_bounded_pp(args[i], m()) << "\n"; + tout << "---->\n"; + for (unsigned i = 0; i < flat_args.size(); i++) tout << mk_bounded_pp(flat_args[i], m()) << "\n";); + br_status st = mk_nflat_mul_core(flat_args.size(), flat_args.c_ptr(), result); + if (st == BR_FAILED) { + result = mk_mul_app(flat_args.size(), flat_args.c_ptr()); + return BR_DONE; + } + return st; + } + } + return mk_nflat_mul_core(num_args, args, result); +} + + +template +struct poly_rewriter::mon_pw_lt { + poly_rewriter & m_owner; + mon_pw_lt(poly_rewriter & o):m_owner(o) {} + + bool operator()(expr * n1, expr * n2) const { + rational k; + return lt(m_owner.get_power_body(n1, k), + m_owner.get_power_body(n2, k)); + } +}; + + +template +br_status poly_rewriter::mk_nflat_mul_core(unsigned num_args, expr * const * args, expr_ref & result) { + SASSERT(num_args >= 2); + // cheap case + numeral a; + if (num_args == 2 && is_numeral(args[0], a) && !a.is_one() && !a.is_zero() && + (is_var(args[1]) || to_app(args[1])->get_decl()->get_family_id() != get_fid())) + return BR_FAILED; + numeral c(1); + unsigned num_coeffs = 0; + unsigned num_add = 0; + expr * var = 0; + for (unsigned i = 0; i < num_args; i++) { + expr * arg = args[i]; + if (is_numeral(arg, a)) { + num_coeffs++; + c *= a; + } + else { + var = arg; + if (is_add(arg)) + num_add++; + } + } + + normalize(c); + // (* c_1 ... c_n) --> c_1*...*c_n + if (num_coeffs == num_args) { + result = mk_numeral(c); + return BR_DONE; + } + + // (* s ... 0 ... r) --> 0 + if (c.is_zero()) { + result = mk_numeral(c); + return BR_DONE; + } + + if (num_coeffs == num_args - 1) { + SASSERT(var != 0); + // (* c_1 ... c_n x) --> x if c_1*...*c_n == 1 + if (c.is_one()) { + result = var; + return BR_DONE; + } + + numeral c_prime; + if (is_mul(var)) { + // apply basic simplification even when flattening is not enabled. + // (* c1 (* c2 x)) --> (* c1*c2 x) + if (to_app(var)->get_num_args() == 2 && is_numeral(to_app(var)->get_arg(0), c_prime)) { + c *= c_prime; + normalize(c); + result = mk_mul_app(c, to_app(var)->get_arg(1)); + return BR_REWRITE1; + } + else { + // var is a power-product + return BR_FAILED; + } + } + + if (num_add == 0 || m_hoist_cmul) { + SASSERT(!is_add(var) || m_hoist_cmul); + if (num_args == 2 && args[1] == var) { + DEBUG_CODE({ + numeral c_prime; + SASSERT(is_numeral(args[0], c_prime) && c == c_prime); + }); + // it is already simplified + return BR_FAILED; + } + + // (* c_1 ... c_n x) --> (* c_1*...*c_n x) + result = mk_mul_app(c, var); + return BR_DONE; + } + else { + SASSERT(is_add(var)); + // (* c_1 ... c_n (+ t_1 ... t_m)) --> (+ (* c_1*...*c_n t_1) ... (* c_1*...*c_n t_m)) + ptr_buffer new_add_args; + unsigned num = to_app(var)->get_num_args(); + for (unsigned i = 0; i < num; i++) { + new_add_args.push_back(mk_mul_app(c, to_app(var)->get_arg(i))); + } + result = mk_add_app(new_add_args.size(), new_add_args.c_ptr()); + TRACE("mul_bug", tout << "result: " << mk_bounded_pp(result, m(),5) << "\n";); + return BR_REWRITE2; + } + } + + SASSERT(num_coeffs <= num_args - 2); + + if (!m_som || num_add == 0) { + ptr_buffer new_args; + expr * prev = 0; + bool ordered = true; + for (unsigned i = 0; i < num_args; i++) { + expr * curr = args[i]; + if (is_numeral(curr)) + continue; + if (prev != 0 && lt(curr, prev)) + ordered = false; + new_args.push_back(curr); + prev = curr; + } + TRACE("poly_rewriter", + for (unsigned i = 0; i < new_args.size(); i++) { + if (i > 0) + tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< "); + tout << mk_ismt2_pp(new_args[i], m()); + } + tout << "\nordered: " << ordered << "\n";); + if (ordered && num_coeffs == 0 && !use_power()) + return BR_FAILED; + if (!ordered) { + if (use_power()) + std::sort(new_args.begin(), new_args.end(), mon_pw_lt(*this)); + else + std::sort(new_args.begin(), new_args.end(), ast_to_lt()); + TRACE("poly_rewriter", + tout << "after sorting:\n"; + for (unsigned i = 0; i < new_args.size(); i++) { + if (i > 0) + tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< "); + tout << mk_ismt2_pp(new_args[i], m()); + } + tout << "\n";); + } + SASSERT(new_args.size() >= 2); + result = mk_mul_app(new_args.size(), new_args.c_ptr()); + result = mk_mul_app(c, result); + TRACE("poly_rewriter", tout << "mk_nflat_mul_core result:\n" << mk_ismt2_pp(result, m()) << "\n";); + return BR_DONE; + } + + SASSERT(m_som && num_add > 0); + + sbuffer szs; + sbuffer it; + sbuffer sums; + for (unsigned i = 0; i < num_args; i ++) { + it.push_back(0); + expr * arg = args[i]; + if (is_add(arg)) { + sums.push_back(const_cast(to_app(arg)->get_args())); + szs.push_back(to_app(arg)->get_num_args()); + } + else { + sums.push_back(const_cast(args + i)); + szs.push_back(1); + SASSERT(sums.back()[0] == arg); + } + } + expr_ref_buffer sum(m()); // must be ref_buffer because we may throw an exception + ptr_buffer m_args; + TRACE("som", tout << "starting som...\n";); + do { + TRACE("som", for (unsigned i = 0; i < it.size(); i++) tout << it[i] << " "; + tout << "\n";); + if (sum.size() > m_som_blowup) + throw rewriter_exception(g_ste_blowup_msg); + m_args.reset(); + for (unsigned i = 0; i < num_args; i++) { + expr * const * v = sums[i]; + expr * arg = v[it[i]]; + m_args.push_back(arg); + } + sum.push_back(mk_mul_app(m_args.size(), m_args.c_ptr())); + } + while (product_iterator_next(szs.size(), szs.c_ptr(), it.c_ptr())); + result = mk_add_app(sum.size(), sum.c_ptr()); + return BR_REWRITE2; +} + +template +br_status poly_rewriter::mk_flat_add_core(unsigned num_args, expr * const * args, expr_ref & result) { + unsigned i; + for (i = 0; i < num_args; i++) { + if (is_add(args[i])) + break; + } + if (i < num_args) { + // has nested ADDs + ptr_buffer flat_args; + flat_args.append(i, args); + for (; i < num_args; i++) { + expr * arg = args[i]; + // Remark: all rewrites are depth 1. + if (is_add(arg)) { + unsigned num = to_app(arg)->get_num_args(); + for (unsigned j = 0; j < num; j++) + flat_args.push_back(to_app(arg)->get_arg(j)); + } + else { + flat_args.push_back(arg); + } + } + br_status st = mk_nflat_add_core(flat_args.size(), flat_args.c_ptr(), result); + if (st == BR_FAILED) { + result = mk_add_app(flat_args.size(), flat_args.c_ptr()); + return BR_DONE; + } + return st; + } + return mk_nflat_add_core(num_args, args, result); +} + +template +inline expr * poly_rewriter::get_power_product(expr * t) { + if (is_mul(t) && to_app(t)->get_num_args() == 2 && is_numeral(to_app(t)->get_arg(0))) + return to_app(t)->get_arg(1); + return t; +} + +template +inline expr * poly_rewriter::get_power_product(expr * t, numeral & a) { + if (is_mul(t) && to_app(t)->get_num_args() == 2 && is_numeral(to_app(t)->get_arg(0), a)) + return to_app(t)->get_arg(1); + a = numeral(1); + return t; +} + +template +bool poly_rewriter::is_mul(expr * t, numeral & c, expr * & pp) { + if (!is_mul(t) || to_app(t)->get_num_args() != 2) + return false; + if (!is_numeral(to_app(t)->get_arg(0), c)) + return false; + pp = to_app(t)->get_arg(1); + return true; +} + +template +struct poly_rewriter::hoist_cmul_lt { + poly_rewriter & m_r; + hoist_cmul_lt(poly_rewriter & r):m_r(r) {} + + bool operator()(expr * t1, expr * t2) const { + expr * pp1, * pp2; + numeral c1, c2; + bool is_mul1 = m_r.is_mul(t1, c1, pp1); + bool is_mul2 = m_r.is_mul(t2, c2, pp2); + if (!is_mul1 && is_mul2) + return true; + if (is_mul1 && !is_mul2) + return false; + if (!is_mul1 && !is_mul2) + return t1->get_id() < t2->get_id(); + if (c1 < c2) + return true; + if (c1 > c2) + return false; + return pp1->get_id() < pp2->get_id(); + } +}; + +template +void poly_rewriter::hoist_cmul(expr_ref_buffer & args) { + unsigned sz = args.size(); + std::sort(args.c_ptr(), args.c_ptr() + sz, hoist_cmul_lt(*this)); + numeral c, c_prime; + ptr_buffer pps; + expr * pp, * pp_prime; + unsigned j = 0; + unsigned i = 0; + while (i < sz) { + expr * mon = args[i]; + if (is_mul(mon, c, pp) && i < sz - 1) { + expr * mon_prime = args[i+1]; + if (is_mul(mon_prime, c_prime, pp_prime) && c == c_prime) { + // found target + pps.reset(); + pps.push_back(pp); + pps.push_back(pp_prime); + i += 2; + while (i < sz && is_mul(args[i], c_prime, pp_prime) && c == c_prime) { + pps.push_back(pp_prime); + i++; + } + SASSERT(is_numeral(to_app(mon)->get_arg(0), c_prime) && c == c_prime); + expr * mul_args[2] = { to_app(mon)->get_arg(0), mk_add_app(pps.size(), pps.c_ptr()) }; + args.set(j, mk_mul_app(2, mul_args)); + j++; + continue; + } + } + args.set(j, mon); + j++; + i++; + } + args.resize(j); +} + +template +br_status poly_rewriter::mk_nflat_add_core(unsigned num_args, expr * const * args, expr_ref & result) { + SASSERT(num_args >= 2); + numeral c; + unsigned num_coeffs = 0; + numeral a; + expr_fast_mark1 visited; // visited.is_marked(power_product) if the power_product occurs in args + expr_fast_mark2 multiple; // multiple.is_marked(power_product) if power_product occurs more than once + bool has_multiple = false; + expr * prev = 0; + bool ordered = true; + for (unsigned i = 0; i < num_args; i++) { + expr * arg = args[i]; + if (is_numeral(arg, a)) { + num_coeffs++; + c += a; + } + else { + // arg is not a numeral + if (m_sort_sums && ordered) { + if (prev != 0 && lt(arg, prev)) + ordered = false; + prev = arg; + } + } + + arg = get_power_product(arg); + if (visited.is_marked(arg)) { + multiple.mark(arg); + has_multiple = true; + } + else { + visited.mark(arg); + } + } + normalize(c); + SASSERT(m_sort_sums || ordered); + TRACE("sort_sums", + tout << "ordered: " << ordered << "\n"; + for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";); + + if (has_multiple) { + // expensive case + buffer coeffs; + m_expr2pos.reset(); + // compute the coefficient of power products that occur multiple times. + for (unsigned i = 0; i < num_args; i++) { + expr * arg = args[i]; + if (is_numeral(arg)) + continue; + expr * pp = get_power_product(arg, a); + if (!multiple.is_marked(pp)) + continue; + unsigned pos; + if (m_expr2pos.find(pp, pos)) { + coeffs[pos] += a; + } + else { + m_expr2pos.insert(pp, coeffs.size()); + coeffs.push_back(a); + } + } + expr_ref_buffer new_args(m()); + if (!c.is_zero()) { + new_args.push_back(mk_numeral(c)); + } + // copy power products with non zero coefficients to new_args + visited.reset(); + for (unsigned i = 0; i < num_args; i++) { + expr * arg = args[i]; + if (is_numeral(arg)) + continue; + expr * pp = get_power_product(arg); + if (!multiple.is_marked(pp)) { + new_args.push_back(arg); + } + else if (!visited.is_marked(pp)) { + visited.mark(pp); + unsigned pos = UINT_MAX; + m_expr2pos.find(pp, pos); + SASSERT(pos != UINT_MAX); + a = coeffs[pos]; + normalize(a); + if (!a.is_zero()) + new_args.push_back(mk_mul_app(a, pp)); + } + } + if (m_hoist_cmul) { + hoist_cmul(new_args); + } + else if (m_sort_sums) { + TRACE("sort_sums_bug", tout << "new_args.size(): " << new_args.size() << "\n";); + if (c.is_zero()) + std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt()); + else + std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt()); + } + result = mk_add_app(new_args.size(), new_args.c_ptr()); + if (hoist_multiplication(result)) { + return BR_REWRITE_FULL; + } + return BR_DONE; + } + else { + SASSERT(!has_multiple); + if (ordered && !m_hoist_mul && !m_hoist_cmul) { + if (num_coeffs == 0) + return BR_FAILED; + if (num_coeffs == 1 && is_numeral(args[0], a) && !a.is_zero()) + return BR_FAILED; + } + expr_ref_buffer new_args(m()); + if (!c.is_zero()) + new_args.push_back(mk_numeral(c)); + for (unsigned i = 0; i < num_args; i++) { + expr * arg = args[i]; + if (is_numeral(arg)) + continue; + new_args.push_back(arg); + } + if (m_hoist_cmul) { + hoist_cmul(new_args); + } + else if (!ordered) { + if (c.is_zero()) + std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt()); + else + std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt()); + } + result = mk_add_app(new_args.size(), new_args.c_ptr()); + if (hoist_multiplication(result)) { + return BR_REWRITE_FULL; + } + return BR_DONE; + } +} + + +template +br_status poly_rewriter::mk_uminus(expr * arg, expr_ref & result) { + numeral a; + set_curr_sort(m().get_sort(arg)); + if (is_numeral(arg, a)) { + a.neg(); + normalize(a); + result = mk_numeral(a); + return BR_DONE; + } + else { + result = mk_mul_app(numeral(-1), arg); + return BR_REWRITE1; + } +} + +template +br_status poly_rewriter::mk_sub(unsigned num_args, expr * const * args, expr_ref & result) { + SASSERT(num_args > 0); + if (num_args == 1) { + result = args[0]; + return BR_DONE; + } + set_curr_sort(m().get_sort(args[0])); + expr * minus_one = mk_numeral(numeral(-1)); + ptr_buffer new_args; + new_args.push_back(args[0]); + for (unsigned i = 1; i < num_args; i++) { + expr * aux_args[2] = { minus_one, args[i] }; + new_args.push_back(mk_mul_app(2, aux_args)); + } + result = mk_add_app(new_args.size(), new_args.c_ptr()); + return BR_REWRITE2; +} + +/** + \brief Cancel/Combine monomials that occur is the left and right hand sides. + + \remark If move = true, then all non-constant monomials are moved to the left-hand-side. +*/ +template +br_status poly_rewriter::cancel_monomials(expr * lhs, expr * rhs, bool move, expr_ref & lhs_result, expr_ref & rhs_result) { + set_curr_sort(m().get_sort(lhs)); + unsigned lhs_sz; + expr * const * lhs_monomials = get_monomials(lhs, lhs_sz); + unsigned rhs_sz; + expr * const * rhs_monomials = get_monomials(rhs, rhs_sz); + + expr_fast_mark1 visited; // visited.is_marked(power_product) if the power_product occurs in lhs or rhs + expr_fast_mark2 multiple; // multiple.is_marked(power_product) if power_product occurs more than once + bool has_multiple = false; + + numeral c(0); + numeral a; + unsigned num_coeffs = 0; + + for (unsigned i = 0; i < lhs_sz; i++) { + expr * arg = lhs_monomials[i]; + if (is_numeral(arg, a)) { + c += a; + num_coeffs++; + } + else { + visited.mark(get_power_product(arg)); + } + } + + if (move && num_coeffs == 0 && is_numeral(rhs)) + return BR_FAILED; + + for (unsigned i = 0; i < rhs_sz; i++) { + expr * arg = rhs_monomials[i]; + if (is_numeral(arg, a)) { + c -= a; + num_coeffs++; + } + else { + expr * pp = get_power_product(arg); + if (visited.is_marked(pp)) { + multiple.mark(pp); + has_multiple = true; + } + } + } + + normalize(c); + + if (!has_multiple && num_coeffs <= 1) { + if (move) { + if (is_numeral(rhs)) + return BR_FAILED; + } + else { + if (num_coeffs == 0 || is_numeral(rhs)) + return BR_FAILED; + } + } + + buffer coeffs; + m_expr2pos.reset(); + for (unsigned i = 0; i < lhs_sz; i++) { + expr * arg = lhs_monomials[i]; + if (is_numeral(arg)) + continue; + expr * pp = get_power_product(arg, a); + if (!multiple.is_marked(pp)) + continue; + unsigned pos; + if (m_expr2pos.find(pp, pos)) { + coeffs[pos] += a; + } + else { + m_expr2pos.insert(pp, coeffs.size()); + coeffs.push_back(a); + } + } + + for (unsigned i = 0; i < rhs_sz; i++) { + expr * arg = rhs_monomials[i]; + if (is_numeral(arg)) + continue; + expr * pp = get_power_product(arg, a); + if (!multiple.is_marked(pp)) + continue; + unsigned pos = UINT_MAX; + m_expr2pos.find(pp, pos); + SASSERT(pos != UINT_MAX); + coeffs[pos] -= a; + } + + + ptr_buffer new_lhs_monomials; + new_lhs_monomials.push_back(0); // save space for coefficient if needed + // copy power products with non zero coefficients to new_lhs_monomials + visited.reset(); + for (unsigned i = 0; i < lhs_sz; i++) { + expr * arg = lhs_monomials[i]; + if (is_numeral(arg)) + continue; + expr * pp = get_power_product(arg); + if (!multiple.is_marked(pp)) { + new_lhs_monomials.push_back(arg); + } + else if (!visited.is_marked(pp)) { + visited.mark(pp); + unsigned pos = UINT_MAX; + m_expr2pos.find(pp, pos); + SASSERT(pos != UINT_MAX); + a = coeffs[pos]; + if (!a.is_zero()) + new_lhs_monomials.push_back(mk_mul_app(a, pp)); + } + } + + ptr_buffer new_rhs_monomials; + new_rhs_monomials.push_back(0); // save space for coefficient if needed + for (unsigned i = 0; i < rhs_sz; i++) { + expr * arg = rhs_monomials[i]; + if (is_numeral(arg)) + continue; + expr * pp = get_power_product(arg, a); + if (!multiple.is_marked(pp)) { + if (move) { + if (!a.is_zero()) { + if (a.is_minus_one()) { + new_lhs_monomials.push_back(pp); + } + else { + a.neg(); + SASSERT(!a.is_one()); + expr * args[2] = { mk_numeral(a), pp }; + new_lhs_monomials.push_back(mk_mul_app(2, args)); + } + } + } + else { + new_rhs_monomials.push_back(arg); + } + } + } + + bool c_at_rhs = false; + if (move) { + if (m_sort_sums) { + // + 1 to skip coefficient + std::sort(new_lhs_monomials.begin() + 1, new_lhs_monomials.end(), ast_to_lt()); + } + c_at_rhs = true; + } + else if (new_rhs_monomials.size() == 1) { // rhs is empty + c_at_rhs = true; + } + else if (new_lhs_monomials.size() > 1) { + c_at_rhs = true; + } + + if (c_at_rhs) { + c.neg(); + normalize(c); + new_rhs_monomials[0] = mk_numeral(c); + lhs_result = mk_add_app(new_lhs_monomials.size() - 1, new_lhs_monomials.c_ptr() + 1); + rhs_result = mk_add_app(new_rhs_monomials.size(), new_rhs_monomials.c_ptr()); + } + else { + new_lhs_monomials[0] = mk_numeral(c); + lhs_result = mk_add_app(new_lhs_monomials.size(), new_lhs_monomials.c_ptr()); + rhs_result = mk_add_app(new_rhs_monomials.size() - 1, new_rhs_monomials.c_ptr() + 1); + } + return BR_DONE; +} + +#define TO_BUFFER(_tester_, _buffer_, _e_) \ + _buffer_.push_back(_e_); \ + for (unsigned _i = 0; _i < _buffer_.size(); ) { \ + expr* _e = _buffer_[_i]; \ + if (_tester_(_e)) { \ + app* a = to_app(_e); \ + _buffer_[_i] = a->get_arg(0); \ + for (unsigned _j = 1; _j < a->get_num_args(); ++_j) { \ + _buffer_.push_back(a->get_arg(_j)); \ + } \ + } \ + else { \ + ++_i; \ + } \ + } \ + +template +bool poly_rewriter::hoist_multiplication(expr_ref& som) { + if (!m_hoist_mul) { + return false; + } + ptr_buffer adds, muls; + TO_BUFFER(is_add, adds, som); + buffer valid(adds.size(), true); + obj_map mul_map; + unsigned j; + bool change = false; + for (unsigned k = 0; k < adds.size(); ++k) { + expr* e = adds[k]; + muls.reset(); + TO_BUFFER(is_mul, muls, e); + for (unsigned i = 0; i < muls.size(); ++i) { + e = muls[i]; + if (is_numeral(e)) { + continue; + } + if (mul_map.find(e, j) && valid[j] && j != k) { + m_curr_sort = m().get_sort(adds[k]); + adds[j] = merge_muls(adds[j], adds[k]); + adds[k] = mk_numeral(rational(0)); + valid[j] = false; + valid[k] = false; + change = true; + break; + } + else { + mul_map.insert(e, k); + } + } + } + if (!change) { + return false; + } + + som = mk_add_app(adds.size(), adds.c_ptr()); + + + return true; +} + +template +expr* poly_rewriter::merge_muls(expr* x, expr* y) { + ptr_buffer m1, m2; + TO_BUFFER(is_mul, m1, x); + TO_BUFFER(is_mul, m2, y); + unsigned k = 0; + for (unsigned i = 0; i < m1.size(); ++i) { + x = m1[i]; + bool found = false; + unsigned j; + for (j = k; j < m2.size(); ++j) { + found = m2[j] == x; + if (found) break; + } + if (found) { + std::swap(m1[i],m1[k]); + std::swap(m2[j],m2[k]); + ++k; + } + } + m_curr_sort = m().get_sort(x); + SASSERT(k > 0); + SASSERT(m1.size() >= k); + SASSERT(m2.size() >= k); + expr* args[2] = { mk_mul_app(m1.size()-k, m1.c_ptr()+k), + mk_mul_app(m2.size()-k, m2.c_ptr()+k) }; + if (k == m1.size()) { + m1.push_back(0); + } + m1[k] = mk_add_app(2, args); + return mk_mul_app(k+1, m1.c_ptr()); +} diff --git a/src/cmd_context/README b/src/cmd_context/README index c44a00690..feb3abd20 100644 --- a/src/cmd_context/README +++ b/src/cmd_context/README @@ -1,2 +1,2 @@ Command context provides the infrastructure for executing commands in front-ends such as SMT-LIB 2.0. -It is also provides the solver abstraction to plugin solvers in this kind of front-end. \ No newline at end of file +It is also provides the solver abstraction to plugin solvers in this kind of front-end. diff --git a/src/math/euclid/README b/src/math/euclid/README index 7235cd76f..17d408fc9 100644 --- a/src/math/euclid/README +++ b/src/math/euclid/README @@ -1,2 +1,2 @@ Basic Euclidean solver for linear integer equations. -This solver generates "explanations". \ No newline at end of file +This solver generates "explanations". diff --git a/src/math/interval/README b/src/math/interval/README index 75aa2e9c6..06ca1ea7a 100644 --- a/src/math/interval/README +++ b/src/math/interval/README @@ -1,2 +1,2 @@ Template for interval arithmetic. The template can be instantiated using different numeral (integers/mpz, rationals/mpq, floating-point/mpf, etc) packages. -The class im_default_config defines a default configuration for the template that uses rationals. It also shows what is the expected signature used by the template. \ No newline at end of file +The class im_default_config defines a default configuration for the template that uses rationals. It also shows what is the expected signature used by the template. diff --git a/src/math/polynomial/README b/src/math/polynomial/README index 5d079eea0..2d2f9f0a0 100644 --- a/src/math/polynomial/README +++ b/src/math/polynomial/README @@ -1,3 +1,3 @@ Polynomial manipulation package. It contains support for univariate (upolynomial.*) and multivariate polynomials (polynomial.*). -Multivariate polynomial factorization does not work yet (polynomial_factorization.*), and it is disabled. \ No newline at end of file +Multivariate polynomial factorization does not work yet (polynomial_factorization.*), and it is disabled. diff --git a/src/muz_qe/dl_hassel_common.cpp b/src/muz_qe/dl_hassel_common.cpp deleted file mode 100755 index 6201868ca..000000000 --- a/src/muz_qe/dl_hassel_common.cpp +++ /dev/null @@ -1,434 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - dl_hassel_common.cpp - -Abstract: - - - -Revision History: - ---*/ - -#include "dl_hassel_common.h" -#include "dl_context.h" - -#include - -namespace datalog { - - static void formula_to_dnf_aux(app *and, unsigned idx, std::set& conjexpr, std::set& toplevel, ast_manager& m) { - if (idx == and->get_num_args()) { - std::vector v(conjexpr.begin(), conjexpr.end()); - toplevel.insert(m.mk_and((unsigned)v.size(), &v[0])); - return; - } - - expr *e = and->get_arg(idx); - if (is_app(e) && to_app(e)->get_decl_kind() == OP_OR) { - app *or = to_app(e); - // quick subsumption test: if any of the elements of the OR is already ANDed, then we skip this OR - for (unsigned i = 0; i < or->get_num_args(); ++i) { - if (conjexpr.count(or->get_arg(i))) { - formula_to_dnf_aux(and, idx+1, conjexpr, toplevel, m); - return; - } - } - - for (unsigned i = 0; i < or->get_num_args(); ++i) { - std::set conjexpr2(conjexpr); - conjexpr2.insert(or->get_arg(i)); - formula_to_dnf_aux(and, idx+1, conjexpr2, toplevel, m); - } - } else { - conjexpr.insert(e); - formula_to_dnf_aux(and, idx+1, conjexpr, toplevel, m); - } - } - - expr_ref formula_to_dnf(expr_ref f) { - app *a = to_app(f); - SASSERT(a->get_decl_kind() == OP_AND); - std::set toplevel, conjexpr; - formula_to_dnf_aux(a, 0, conjexpr, toplevel, f.m()); - - if (toplevel.size() > 1) { - std::vector v(toplevel.begin(), toplevel.end()); - return expr_ref(f.m().mk_or((unsigned)v.size(), &v[0]), f.m()); - } else { - return expr_ref(*toplevel.begin(), f.m()); - } - } - - bool bit_vector::contains(const bit_vector & other) const { - unsigned n = num_words(); - if (n == 0) - return true; - - for (unsigned i = 0; i < n - 1; ++i) { - if ((m_data[i] & other.m_data[i]) != other.m_data[i]) - return false; - } - unsigned bit_rest = m_num_bits % 32; - unsigned mask = (1 << bit_rest) - 1; - if (mask == 0) mask = UINT_MAX; - unsigned other_data = other.m_data[n-1] & mask; - return (m_data[n-1] & other_data) == other_data; - } - - bool bit_vector::contains(const bit_vector & other, unsigned idx) const { - // TODO: optimize this to avoid copy - return slice(idx, other.size()).contains(other); - } - - bool bit_vector::contains_consecutive_zeros() const { - unsigned n = num_words(); - if (n == 0) - return false; - - for (unsigned i = 0; i < n - 1; ++i) { - if ((((m_data[i] << 1) | m_data[i]) & 0xAAAAAAAA) != 0xAAAAAAAA) - return true; - } - unsigned bit_rest = m_num_bits % 32; - unsigned mask = (1 << bit_rest) - 1; - if (mask == 0) mask = UINT_MAX; - mask &= 0xAAAAAAAA; - return ((((m_data[n-1] << 1) | m_data[n-1]) & mask) != mask); - } - - bit_vector bit_vector::slice(unsigned idx, unsigned length) const { - bit_vector Res(length); - // TODO: optimize w/ memcpy when possible - for (unsigned i = idx; i < idx + length; ++i) { - Res.push_back(get(i)); - } - SASSERT(Res.size() == length); - return Res; - } - - void bit_vector::append(const bit_vector & other) { - if (other.empty()) - return; - - if ((m_num_bits % 32) == 0) { - unsigned prev_num_bits = m_num_bits; - resize(m_num_bits + other.m_num_bits); - memcpy(&get_bit_word(prev_num_bits), other.m_data, other.num_words() * sizeof(unsigned)); - return; - } - - // TODO: optimize the other cases. - for (unsigned i = 0; i < other.m_num_bits; ++i) { - push_back(other.get(i)); - } - } - - uint64 bit_vector::to_number(unsigned idx, unsigned length) const { - SASSERT(length <= 64); - uint64 r = 0; - for (unsigned i = 0; i < length; ++i) { - r = (r << 1) | (uint64)get(idx+i); - } - return r; - } - - bool bit_vector::operator<(bit_vector const & other) const { - SASSERT(m_num_bits == other.m_num_bits); - unsigned n = num_words(); - if (n == 0) - return false; - - for (unsigned i = 0; i < n - 1; ++i) { - if (m_data[i] > other.m_data[i]) - return false; - if (m_data[i] < other.m_data[i]) - return true; - } - - unsigned bit_rest = m_num_bits % 32; - unsigned mask = (1 << bit_rest) - 1; - if (mask == 0) mask = UINT_MAX; - return (m_data[n-1] & mask) < (other.m_data[n-1] & mask); - } - - table_information::table_information(table_plugin & p, const table_signature& sig) : - m_column_info(sig.size()+1), - m_bv_util(p.get_context().get_manager()), - m_decl_util(p.get_context().get_manager()) { - - unsigned column = 0; - for (unsigned i = 0; i < sig.size(); ++i) { - unsigned num_bits = uint64_log2(sig[i]); - SASSERT(num_bits == 64 || (1ULL << num_bits) == sig[i]); - m_column_info[i] = column; - column += num_bits; - } - m_column_info[sig.size()] = column; - } - - void table_information::expand_column_vector(unsigned_vector& v, const table_information *other) const { - unsigned_vector orig; - orig.swap(v); - - for (unsigned i = 0; i < orig.size(); ++i) { - unsigned col, limit; - if (orig[i] < get_num_cols()) { - col = column_idx(orig[i]); - limit = col + column_num_bits(orig[i]); - } else { - unsigned idx = orig[i] - get_num_cols(); - col = get_num_bits() + other->column_idx(idx); - limit = col + other->column_num_bits(idx); - } - - for (; col < limit; ++col) { - v.push_back(col); - } - } - } - - void table_information::display(std::ostream & out) const { - out << '<'; - for (unsigned i = 0; i < get_num_cols(); ++i) { - if (i > 0) - out << ", "; - out << column_num_bits(i); - } - out << ">\n"; - } - - ternary_bitvector::ternary_bitvector(unsigned size, bool full) : - bit_vector() { - resize(size, full); - } - - ternary_bitvector::ternary_bitvector(uint64 n, unsigned num_bits) : - bit_vector(2 * num_bits) { - append_number(n, num_bits); - } - - ternary_bitvector::ternary_bitvector(const table_fact& f, const table_information& t) : - bit_vector(2 * t.get_num_bits()) { - for (unsigned i = 0; i < f.size(); ++i) { - SASSERT(t.column_idx(i) == size()); - append_number(f[i], t.column_num_bits(i)); - } - SASSERT(size() == t.get_num_bits()); - } - - void ternary_bitvector::fill1() { - memset(m_data, 0xFF, m_capacity * sizeof(unsigned)); - } - - unsigned ternary_bitvector::get(unsigned idx) const { - idx *= 2; - return (bit_vector::get(idx) << 1) | (unsigned)bit_vector::get(idx+1); - } - - void ternary_bitvector::set(unsigned idx, unsigned val) { - SASSERT(val == BIT_0 || val == BIT_1 || val == BIT_x); - idx *= 2; - bit_vector::set(idx, (val >> 1) != 0); - bit_vector::set(idx+1, (val & 1) != 0); - } - - void ternary_bitvector::push_back(unsigned val) { - SASSERT(val == BIT_0 || val == BIT_1 || val == BIT_x); - bit_vector::push_back((val >> 1) != 0); - bit_vector::push_back((val & 1) != 0); - } - - void ternary_bitvector::append_number(uint64 n, unsigned num_bits) { - SASSERT(num_bits <= 64); - for (int bit = num_bits-1; bit >= 0; --bit) { - if (n & (1ULL << bit)) { - push_back(BIT_1); - } else { - push_back(BIT_0); - } - } - } - - void ternary_bitvector::mk_idx_eq(unsigned idx, ternary_bitvector& val) { - for (unsigned i = 0; i < val.size(); ++i) { - set(idx+i, val.get(i)); - } - } - - ternary_bitvector ternary_bitvector::and(const ternary_bitvector& other) const{ - ternary_bitvector result(*this); - result &= other; - return result; - } - - void ternary_bitvector::neg(union_ternary_bitvector& result) const { - ternary_bitvector negated; - negated.resize(size()); - - for (unsigned i = 0; i < size(); ++i) { - switch (get(i)) { - case BIT_0: - negated.fill1(); - negated.set(i, BIT_1); - break; - case BIT_1: - negated.fill1(); - negated.set(i, BIT_0); - break; - default: - continue; - } - result.add_fact(negated); - } - } - - static void join_fix_eqs(ternary_bitvector& TBV, unsigned idx, unsigned col2_offset, - const unsigned_vector& cols1, const unsigned_vector& cols2, - union_ternary_bitvector& result) { - if (idx == cols1.size()) { - result.add_fact(TBV); - return; - } - - unsigned idx1 = cols1[idx]; - unsigned idx2 = cols2[idx] + col2_offset; - unsigned v1 = TBV.get(idx1); - unsigned v2 = TBV.get(idx2); - - if (v1 == BIT_x) { - if (v2 == BIT_x) { - // both x: duplicate row - ternary_bitvector TBV2(TBV); - TBV2.set(idx1, BIT_0); - TBV2.set(idx2, BIT_0); - join_fix_eqs(TBV2, idx+1, col2_offset, cols1, cols2, result); - - TBV.set(idx1, BIT_1); - TBV.set(idx2, BIT_1); - } else { - TBV.set(idx1, v2); - } - } else if (v2 == BIT_x) { - TBV.set(idx2, v1); - } else if (v1 != v2) { - // columns don't match - return; - } - join_fix_eqs(TBV, idx+1, col2_offset, cols1, cols2, result); - } - - void ternary_bitvector::join(const ternary_bitvector& other, - const unsigned_vector& cols1, - const unsigned_vector& cols2, - union_ternary_bitvector& result) const { - ternary_bitvector TBV(*this); - TBV.append(other); - join_fix_eqs(TBV, 0, size(), cols1, cols2, result); - } - - bool ternary_bitvector::project(const unsigned_vector& delcols, ternary_bitvector& result) const { - unsigned *rm_cols = delcols.c_ptr(); - - for (unsigned i = 0; i < size(); ++i) { - if (*rm_cols == i) { - ++rm_cols; - continue; - } - result.push_back(get(i)); - } - return true; - } - - static void copy_column(ternary_bitvector& CopyTo, const ternary_bitvector& CopyFrom, - unsigned col_dst, unsigned col_src, const table_information& src_table, - const table_information& dst_table) { - unsigned idx_dst = dst_table.column_idx(col_dst); - unsigned idx_src = src_table.column_idx(col_src); - unsigned num_bits = dst_table.column_num_bits(col_dst); - SASSERT(num_bits == src_table.column_num_bits(col_src)); - - for (unsigned i = 0; i < num_bits; ++i) { - CopyTo.set(idx_dst+i, CopyFrom.get(idx_src+i)); - } - } - - void ternary_bitvector::rename(const unsigned_vector& cyclecols, - const unsigned_vector& out_of_cycle_cols, - const table_information& src_table, - const table_information& dst_table, - ternary_bitvector& result) const { - result.resize(dst_table.get_num_bits()); - - for (unsigned i = 1; i < cyclecols.size(); ++i) { - copy_column(result, *this, cyclecols[i-1], cyclecols[i], src_table, dst_table); - } - copy_column(result, *this, cyclecols[cyclecols.size()-1], cyclecols[0], src_table, dst_table); - - for (unsigned i = 0; i < out_of_cycle_cols.size(); ++i) { - unsigned col = out_of_cycle_cols[i]; - copy_column(result, *this, col, col, src_table, dst_table); - } - } - - unsigned ternary_bitvector::size_in_bytes() const { - return sizeof(*this) + m_capacity; - } - - void ternary_bitvector::display(std::ostream & out) const { - for (unsigned i = 0; i < size(); ++i) { - switch (get(i)) { - case BIT_0: - out << '0'; - break; - case BIT_1: - out << '1'; - break; - case BIT_x: - out << 'x'; - break; - default: - UNREACHABLE(); - } - } - } - -#if Z3DEBUG - void ternary_bitvector::expand(std::set & BVs) const { - bit_vector BV(m_num_bits); - expand(BVs, BV, 0); - } - - void ternary_bitvector::expand(std::set & BVs, bit_vector &BV, unsigned idx) const { - if (idx == size()) { - BVs.insert(BV); - return; - } - - switch (get(idx)) { - case BIT_0: - BV.push_back(false); - expand(BVs, BV, idx+1); - break; - case BIT_1: - BV.push_back(true); - expand(BVs, BV, idx+1); - break; - case BIT_x: { // x: duplicate - bit_vector BV2(BV); - BV.push_back(false); - BV2.push_back(true); - expand(BVs, BV, idx+1); - expand(BVs, BV2, idx+1); - } - break; - default: - UNREACHABLE(); - } - } -#endif - -} diff --git a/src/muz_qe/dl_hassel_common.h b/src/muz_qe/dl_hassel_common.h deleted file mode 100755 index 7c1d1e614..000000000 --- a/src/muz_qe/dl_hassel_common.h +++ /dev/null @@ -1,1079 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - dl_hassel_common.h - -Abstract: - - - -Revision History: - ---*/ - -#ifndef _DL_HASSEL_COMMON_H_ -#define _DL_HASSEL_COMMON_H_ - -#include "bit_vector.h" -#include "dl_base.h" -#include "bv_decl_plugin.h" -#include "union_find.h" -#include -#include - -#define BIT_0 ((0<<1)|1) -#define BIT_1 ((1<<1)|0) -#define BIT_x ((1<<1)|1) - -namespace datalog { - - expr_ref formula_to_dnf(expr_ref f); - - class bit_vector : public ::bit_vector { - public: - bit_vector() : ::bit_vector() {} - bit_vector(unsigned bits) : ::bit_vector(bits) {} - - bool contains(const bit_vector & other) const; - bool contains(const bit_vector & other, unsigned idx) const; - bool contains_consecutive_zeros() const; - - bit_vector slice(unsigned idx, unsigned length) const; - void append(const bit_vector & other); - - uint64 to_number(unsigned idx, unsigned length) const; - - // for std::less operations - bool operator<(bit_vector const & other) const; - }; - - - class table_information { - unsigned_vector m_column_info; - bv_util m_bv_util; - dl_decl_util m_decl_util; - - public: - table_information(table_plugin & p, const table_signature& sig); - - unsigned get_num_bits() const { - return m_column_info.back(); - } - - unsigned get_num_cols() const { - return m_column_info.size()-1; - } - - unsigned column_idx(unsigned col) const { - return m_column_info[col]; - } - - unsigned column_num_bits(unsigned col) const { - return m_column_info[col+1] - m_column_info[col]; - } - - void expand_column_vector(unsigned_vector& v, const table_information *other = 0) const; - - void display(std::ostream & out) const; - - const bv_util& get_bv_util() const { return m_bv_util; } - const dl_decl_util& get_decl_util() const { return m_decl_util; } - }; - - - template class union_ternary_bitvector; - - - class ternary_bitvector : private bit_vector { - public: - ternary_bitvector() : bit_vector() {} - ternary_bitvector(unsigned size) : bit_vector(2 * size) {} - - ternary_bitvector(unsigned size, bool full); - ternary_bitvector(uint64 n, unsigned num_bits); - ternary_bitvector(const table_fact& f, const table_information& t); - - void swap(ternary_bitvector& other) { - SASSERT(size() == other.size()); - bit_vector::swap(other); - } - - void resize(unsigned new_size, bool val = false) { - bit_vector::resize(2 * new_size, val); - } - - void reset() { - m_num_bits = 0; - } - - unsigned size() const { - SASSERT((m_num_bits % 2) == 0); - return m_num_bits/2; - } - - void fill1(); - - void append(const ternary_bitvector & other) { bit_vector::append(other); } - bool contains(const ternary_bitvector & other) const { return bit_vector::contains(other); } - - bool is_empty() const { return contains_consecutive_zeros(); } - - unsigned get(unsigned idx) const; - void set(unsigned idx, unsigned val); - void push_back(unsigned val); - void append_number(uint64 n, unsigned num_bits); - void mk_idx_eq(unsigned idx, ternary_bitvector& val); - - ternary_bitvector and(const ternary_bitvector& other) const; - void neg(union_ternary_bitvector& result) const; - - void join(const ternary_bitvector& other, const unsigned_vector& cols1, - const unsigned_vector& cols2, union_ternary_bitvector& result) const; - - bool project(const unsigned_vector& delcols, ternary_bitvector& result) const; - - void rename(const unsigned_vector& cyclecols, const unsigned_vector& out_of_cycle_cols, - const table_information& src_table, const table_information& dst_table, - ternary_bitvector& result) const; - - static bool has_subtract() { return false; } - void subtract(const union_ternary_bitvector& other, - union_ternary_bitvector& result) const { UNREACHABLE(); } - - void display(std::ostream & out) const; - unsigned size_in_bytes() const; - -#if Z3DEBUG - void expand(std::set & BVs) const; -#endif - - private: -#if Z3DEBUG - void expand(std::set & BVs, bit_vector &BV, unsigned idx) const; -#endif - }; - - - template - class union_ternary_bitvector { - typedef std::list union_t; - - union_t m_bitvectors; - unsigned m_bv_size; //!< number of ternary bits - - public: - union_ternary_bitvector(unsigned bv_size) : m_bv_size(bv_size) {} - - union_ternary_bitvector(unsigned bv_size, bool full) : m_bv_size(bv_size) { - if (full) - mk_full(); - } - - union_ternary_bitvector and(const union_ternary_bitvector & Other) const { - if (empty()) - return *this; - if (Other.empty()) - return Other; - - union_ternary_bitvector Ret(m_bv_size); - - for (const_iterator I = begin(), E = end(); I != E; ++I) { - for (const_iterator II = Other.begin(), EE = Other.end(); II != EE; ++II) { - T row(I->and(*II)); - if (!row.is_empty()) - Ret.add_fact(row); - } - } - return Ret; - } - - union_ternary_bitvector or(const union_ternary_bitvector & Other) const { - if (empty()) - return Other; - if (Other.empty()) - return *this; - - union_ternary_bitvector Ret(*this); - Ret.add_facts(Other); - return Ret; - } - - union_ternary_bitvector neg() const { - union_ternary_bitvector Ret(m_bv_size); - Ret.mk_full(); - - union_ternary_bitvector negated(m_bv_size); - for (const_iterator I = begin(), E = end(); I != E; ++I) { - negated.reset(); - I->neg(negated); - Ret.swap(Ret.and(negated)); - } - return Ret; - } - - void subtract(const union_ternary_bitvector& other) { - if (!T::has_subtract()) { - swap(this->and(other.neg())); - return; - } - - union_ternary_bitvector subtracted(m_bv_size); - for (const_iterator I = begin(), E = end(); I != E; ++I) { - I->subtract(other, subtracted); - } - swap(subtracted); - } - -#if 0 - union_ternary_bitvector gc() const { - // Simple subsumption-based cleaning. - union_ternary_bitvector Ret(m_bv_size); - for (union_t::const_reverse_iterator I = m_bitvectors.rbegin(), E = m_bitvectors.rend(); I != E; ++I) { - Ret.add_fact(*I); - } - return Ret; - } -#endif - - void join(const union_ternary_bitvector& other, const unsigned_vector& cols1, - const unsigned_vector& cols2, union_ternary_bitvector& result) const { - for (const_iterator I = begin(), E = end(); I != E; ++I) { - for (const_iterator II = other.begin(), EE = other.end(); II != EE; ++II) { - I->join(*II, cols1, cols2, result); - } - } - } - - void rename(const unsigned_vector& cyclecols, const unsigned_vector& out_of_cycle_cols, - const table_information& src_table, const table_information& dst_table, - union_ternary_bitvector& result) const { - T row(m_bv_size); - for (const_iterator I = begin(), E = end(); I != E; ++I) { - row.reset(); - I->rename(cyclecols, out_of_cycle_cols, src_table, dst_table, row); - result.add_new_fact(row); - } - } - - void project(const unsigned_vector& delcols, union_ternary_bitvector& result) const { - unsigned new_size = m_bv_size - (delcols.size()-1); - T row(new_size); - - for (const_iterator I = begin(), E = end(); I != E; ++I) { - row.reset(); - if (I->project(delcols, row)) { - SASSERT(!row.is_empty()); - result.add_fact(row); - } - } - } - - private: - typedef union_find<> subset_ints; - - // returns 1 if row should be removed, 0 otherwise - static int fix_single_bit(T & BV, unsigned idx, unsigned value, const subset_ints& equalities) { - unsigned root = equalities.find(idx); - idx = root; - do { - unsigned bitval = BV.get(idx); - if (bitval == BIT_x) { - BV.set(idx, value); - } else if (bitval != value) { - return 1; - } - idx = equalities.next(idx); - } while (idx != root); - return 0; - } - - static int fix_single_bit(T & BV1, unsigned idx1, T & BV2, unsigned idx2, - subset_ints& equalities, bool discard_col) { - unsigned A = BV1.get(idx1); - unsigned B = BV2.get(idx2); - - if (A == BIT_x) { - if (B == BIT_x) { - // Both are don't cares. - /////// FIXME::: don't duplicate rows with diff table - if (!discard_col) - return 2; // duplicate row - equalities.merge(idx1, idx2); - return 0; - } else { - // only A is don't care. - return fix_single_bit(BV1, idx1, B, equalities); - } - } else if (B == BIT_x) { - // Only B is don't care. - return fix_single_bit(BV2, idx2, A, equalities); - } else if (A == B) { - return 0; - } else { - return 1; // remove row - } - } - - void fix_eq_bits(unsigned idx1, const T *BV, unsigned idx2, unsigned length, - subset_ints& equalities, const bit_vector& discard_cols) { - for (unsigned i = 0; i < length; ++i) { - for (union_t::iterator I = m_bitvectors.begin(), E = m_bitvectors.end(); I != E; ) { - T *eqBV = BV ? const_cast(BV) : &*I; - bool discard_col = discard_cols.get(idx1+i) || (!BV && discard_cols.get(idx2+i)); - - switch (fix_single_bit(*I, idx1+i, *eqBV, idx2+i, equalities, discard_col)) { - case 1: - // remove row - I = m_bitvectors.erase(I); - break; - - case 2: { - // duplicate row - T BV2(*I); - I->set(idx1+i, BIT_0); - I->set(idx2+i, BIT_0); - - BV2.set(idx1+i, BIT_1); - BV2.set(idx2+i, BIT_1); - m_bitvectors.insert(I, BV2); - ++I; - break;} - - default: - // bits fixed - ++I; - } - } - } - } - - /// make bits of table [idx,idx+max_length] equal to e sliced starting at idx2 - unsigned fix_eq_bits(unsigned idx, const expr *e, unsigned idx2, unsigned max_length, - const table_information& t, subset_ints& equalities, - const bit_vector & discard_cols) { - const bv_util& bvu = t.get_bv_util(); - const dl_decl_util& dutil = t.get_decl_util(); - - rational n; - unsigned bv_size; - if (bvu.is_numeral(e, n, bv_size)) { - T num(n.get_int64(), bv_size); - SASSERT(idx2 < bv_size); - max_length = std::min(max_length, bv_size - idx2); - fix_eq_bits(idx, &num, idx2, max_length, equalities, discard_cols); - return idx + max_length; - } - - uint64 num; - if (dutil.is_numeral(e, num)) { - T num_bv(num, max_length); - fix_eq_bits(idx, &num_bv, idx2, max_length, equalities, discard_cols); - return idx + max_length; - } - - if (bvu.is_concat(e)) { - const app *a = to_app(e); - - // skip the first elements of the concat if e.g. we have a top level extract - unsigned i = 0; - for (; i < a->get_num_args(); ++i) { - unsigned arg_size = bvu.get_bv_size(a->get_arg(i)); - if (idx2 < arg_size) - break; - idx2 -= arg_size; - } - - SASSERT(i < a->get_num_args()); - for (; max_length > 0 && i < a->get_num_args(); ++i) { - unsigned idx0 = idx; - idx = fix_eq_bits(idx, a->get_arg(i), idx2, max_length, t, equalities, discard_cols); - idx2 = 0; - SASSERT((idx - idx0) <= max_length); - max_length = max_length - (idx - idx0); - } - return idx; - } - - unsigned low, high; - expr *e2; - if (bvu.is_extract(e, low, high, e2)) { - SASSERT(low <= high); - unsigned size = bvu.get_bv_size(e2); - unsigned offset = size - (high+1) + idx2; - SASSERT(idx2 < (high-low+1)); - max_length = std::min(max_length, high - low + 1 - idx2); - return fix_eq_bits(idx, e2, offset, max_length, t, equalities, discard_cols); - } - - if (e->get_kind() == AST_VAR) { - unsigned idx_var = idx2 + t.column_idx(to_var(e)->get_idx()); - SASSERT(idx2 < t.column_num_bits(to_var(e)->get_idx())); - max_length = std::min(max_length, t.column_num_bits(to_var(e)->get_idx()) - idx2); - fix_eq_bits(idx, 0, idx_var, max_length, equalities, discard_cols); - return idx + max_length; - } - - NOT_IMPLEMENTED_YET(); - return 0; - } - - void filter(const expr *e, subset_ints& equalities, const bit_vector& discard_cols, - const table_information& t) { - switch (e->get_kind()) { - case AST_APP: { - const app *app = to_app(e); - switch (app->get_decl_kind()) { - case OP_AND: - for (unsigned i = 0; i < app->get_num_args(); ++i) { - filter(app->get_arg(i), equalities, discard_cols, t); - } - return; - - case OP_EQ: { - const expr *a = app->get_arg(0); - const var *v; - unsigned vidx = 0; - unsigned length; - - unsigned low, high; - expr *e2; - if (is_var(a)) { - v = to_var(a); - length = t.column_num_bits(v->get_idx()); - } else if (t.get_bv_util().is_extract(a, low, high, e2)) { - vidx = t.get_bv_util().get_bv_size(e2) - high - 1; - length = high - low + 1; - SASSERT(is_var(e2)); - v = to_var(e2); - } else { - NOT_IMPLEMENTED_YET(); - } - vidx += t.column_idx(v->get_idx()); - - unsigned final_idx = fix_eq_bits(vidx, app->get_arg(1), 0, length, t, equalities, discard_cols); - SASSERT(final_idx == vidx + length); - (void)final_idx; - return;} - - case OP_FALSE: - reset(); - return; - - case OP_NOT: { - union_ternary_bitvector sub(m_bv_size, true); - sub.filter(app->get_arg(0), equalities, discard_cols, t); - this->subtract(sub); - return;} - - case OP_OR: { - union_ternary_bitvector orig(m_bv_size); - swap(orig); - for (unsigned i = 0; i < app->get_num_args(); ++i) { - union_ternary_bitvector tmp(orig); - subset_ints eqs(equalities); - tmp.filter(app->get_arg(i), eqs, discard_cols, t); - add_facts(tmp); - } - return;} - - case OP_TRUE: - return; - - default: - std::cerr << "app decl: " << app->get_decl()->get_name() << " (" << app->get_decl_kind() << ")\n"; - NOT_IMPLEMENTED_YET(); - } - break;} - - case AST_VAR: { - // boolean var must be true (10) - SASSERT(t.column_num_bits(to_var(e)->get_idx()) == 1); - unsigned idx = t.column_idx(to_var(e)->get_idx()); - ternary_bitvector BV(1); - BV.push_back(BIT_1); - T BV2(BV); - fix_eq_bits(idx, &BV2, 0, 2, equalities, discard_cols); - return;} - - default: - break; - } - std::cerr << "expr kind: " << get_ast_kind_name(e->get_kind()) << '\n'; - NOT_IMPLEMENTED_YET(); - } - - public: - void filter(const expr *cond, const bit_vector& discard_cols, const table_information& table) { - // datastructure to store equalities with columns that will be projected out - union_find_default_ctx union_ctx; - subset_ints equalities(union_ctx); - for (unsigned i = 0, e = discard_cols.size(); i < e; ++i) { - equalities.mk_var(); - } - - filter(cond, equalities, discard_cols, table); - } - - bool contains(const T & fact) const { - for (const_iterator I = begin(), E = end(); I != E; ++I) { - if (I->contains(fact)) - return true; - } - return false; - } - - bool contains(const union_ternary_bitvector & other) const { - for (const_iterator I = other.begin(), E = other.end(); I != E; ++I) { - for (const_iterator II = begin(), EE = end(); II != EE; ++II) { - if (II->contains(*I)) - goto next_iter; - } - return false; -next_iter: ; - } - return true; - } - - unsigned num_disjs() const { - return (unsigned)m_bitvectors.size(); - } - - unsigned num_bytes() const { - unsigned size = sizeof(*this); - for (const_iterator I = begin(), E = end(); I != E; ++I) { - size += I->size_in_bytes(); - } - return size; - } - -#if Z3DEBUG - void expand(std::set & BVs) const { - for (const_iterator I = begin(), E = end(); I != E; ++I) { - I->expand(BVs); - } - } -#endif - - void add_facts(const union_ternary_bitvector & Other, union_ternary_bitvector *Delta = 0) { - for (const_iterator I = Other.begin(), E = Other.end(); I != E; ++I) { - if (add_fact(*I) && Delta) - Delta->add_fact(*I); - } - } - - bool add_fact(const T & fact) { - if (contains(fact)) - return false; - add_new_fact(fact); - return true; - } - - void add_new_fact(const T & fact) { - SASSERT(m_bv_size == fact.size()); - - // TODO: optimize sequence (karnaugh maps??) - // At least join 1-bit different BVs - m_bitvectors.push_back(fact); - } - - void mk_full() { - reset(); - add_new_fact(T(m_bv_size, true)); - } - - typedef typename union_t::const_iterator const_iterator; - - const_iterator begin() const { return m_bitvectors.begin(); } - const_iterator end() const { return m_bitvectors.end(); } - - bool empty() const { return m_bitvectors.empty(); } - void reset() { m_bitvectors.clear(); } - - void swap(union_ternary_bitvector& other) { - SASSERT(m_bv_size == other.m_bv_size); - m_bitvectors.swap(other.m_bitvectors); - } - - void display(std::ostream & out) const { - out << '#' << num_disjs() << " (bv" << m_bv_size << ") "; - - bool first = true; - for (const_iterator I = begin(), E = end(); I != E; ++I) { - if (!first) - out << " \\/ "; - first = false; - I->display(out); - } - out << '\n'; - } - }; - - - template - class common_hassel_table_plugin : public table_plugin { - public: - common_hassel_table_plugin(symbol &s, relation_manager & manager) : - table_plugin(s, manager) { } - - virtual table_base * mk_empty(const table_signature & s) { - return alloc(T, *this, s); - } - - virtual table_base * mk_full(func_decl* p, const table_signature & s) { - T *t = static_cast(mk_empty(s)); - t->mk_full(); - return t; - } - - virtual bool can_handle_signature(const table_signature & s) { - return s.functional_columns() == 0; - } - - private: - ast_manager& get_ast_manager() { return get_context().get_manager(); } - - class join_fn : public convenient_table_join_fn { - public: - join_fn(const T & t1, const T & t2, unsigned col_cnt, const unsigned *cols1, const unsigned *cols2) - : convenient_table_join_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2) { - t1.expand_column_vector(m_cols1); - t2.expand_column_vector(m_cols2); - } - - virtual table_base * operator()(const table_base & tb1, const table_base & tb2) { - const T & T1 = static_cast(tb1); - const T & T2 = static_cast(tb2); - T * Res = static_cast(T1.get_plugin().mk_empty(get_result_signature())); - T1.m_bitsets.join(T2.m_bitsets, m_cols1, m_cols2, Res->m_bitsets); - TRACE("dl_hassel", tout << "final size: " << Res->get_size_estimate_rows() << '\n';); - return Res; - } - }; - - public: - virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (!check_kind(t1) || !check_kind(t2)) - return 0; - return alloc(join_fn, static_cast(t1), static_cast(t2), col_cnt, cols1, cols2); - } - - private: - class union_fn : public table_union_fn { - public: - virtual void operator()(table_base & tgt0, const table_base & src0, table_base * delta0) { - T & tgt = static_cast(tgt0); - const T & src = static_cast(src0); - T * delta = static_cast(delta0); - tgt.m_bitsets.add_facts(src.m_bitsets, delta ? &delta->m_bitsets : 0); - TRACE("dl_hassel", tout << "final size: " << tgt.get_size_estimate_rows() << '\n';); - } - }; - - public: - virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, - const table_base * delta) { - if (!check_kind(tgt) || !check_kind(src)) - return 0; - return alloc(union_fn); - } - - private: - class project_fn : public convenient_table_project_fn { - public: - project_fn(const T & t, unsigned removed_col_cnt, const unsigned * removed_cols) - : convenient_table_project_fn(t.get_signature(), removed_col_cnt, removed_cols) { - t.expand_column_vector(m_removed_cols); - m_removed_cols.push_back(UINT_MAX); - } - - virtual table_base * operator()(const table_base & tb) { - const T & t = static_cast(tb); - T * res = static_cast(t.get_plugin().mk_empty(get_result_signature())); - t.m_bitsets.project(m_removed_cols, res->m_bitsets); - TRACE("dl_hassel", tout << "final size: " << res->get_size_estimate_rows() << '\n';); - return res; - } - }; - - public: - virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols) { - if (!check_kind(t)) - return 0; - return alloc(project_fn, static_cast(t), col_cnt, removed_cols); - } - - private: - class rename_fn : public convenient_table_rename_fn { - unsigned_vector m_out_of_cycle; - public: - rename_fn(const table_signature & orig_sig, unsigned permutation_cycle_len, const unsigned * permutation_cycle) - : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle) { - SASSERT(permutation_cycle_len >= 2); - idx_set cycle_cols; - for (unsigned i = 0; i < permutation_cycle_len; ++i) { - cycle_cols.insert(permutation_cycle[i]); - } - for (unsigned i = 0; i < orig_sig.size(); ++i) { - if (!cycle_cols.contains(i)) - m_out_of_cycle.push_back(i); - } - } - - virtual table_base * operator()(const table_base & tb) { - const T & t = static_cast(tb); - T * res = static_cast(t.get_plugin().mk_empty(get_result_signature())); - t.m_bitsets.rename(m_cycle, m_out_of_cycle, t, *res, res->m_bitsets); - TRACE("dl_hassel", tout << "final size: " << res->get_size_estimate_rows() << '\n';); - return res; - } - }; - - public: - virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle) { - if (!check_kind(t)) - return 0; - return alloc(rename_fn, t.get_signature(), permutation_cycle_len, permutation_cycle); - } - - private: - class filter_equal_fn : public table_mutator_fn { - typename T::bitset_t m_filter; - public: - filter_equal_fn(const T & t, const table_element val, unsigned col) : - m_filter(t.get_num_bits()) { - ternary_bitvector filter_row(t.get_num_bits(), true); - ternary_bitvector column(val, t.column_num_bits(col)); - filter_row.mk_idx_eq(t.column_idx(col), column); - m_filter.add_new_fact(filter_row); - } - - virtual void operator()(table_base & tb) { - T & t = static_cast(tb); - t.m_bitsets.swap(m_filter.and(t.m_bitsets)); - TRACE("dl_hassel", tout << "final size: " << t.get_size_estimate_rows() << '\n';); - } - }; - - public: - virtual table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value, - unsigned col) { - if (!check_kind(t)) - return 0; - return alloc(filter_equal_fn, static_cast(t), value, col); - } - - private: - static bool cond_is_guard(const expr *e, const table_information& t) { - switch (e->get_kind()) { - case AST_APP: { - const app *app = to_app(e); - switch (app->get_decl_kind()) { - case OP_AND: - case OP_OR: - case OP_NOT: - for (unsigned i = 0; i < app->get_num_args(); ++i) { - if (!cond_is_guard(app->get_arg(i), t)) - return false; - } - return true; - - case OP_EQ: { - const expr *a = app->get_arg(0), *b = app->get_arg(1); - - // column equality is not succinctly representable with TBVs - if (is_var(a) && is_var(b)) - return false; - - // (= var (concat var foo)) - if (t.get_bv_util().is_concat(b)) - return false; - - return true;} - - case OP_FALSE: - case OP_TRUE: - return true; - - default: - return false; - } - break;} - - case AST_VAR: - return true; - - default: - break; - } - return false; - } - - static void split_cond_guard(app *cond, expr_ref& guard, expr_ref& leftover, const table_information& t) { - expr_ref_vector guards(guard.m()); - expr_ref_vector leftovers(leftover.m()); - - if (is_app(cond) && to_app(cond)->get_decl_kind() == OP_AND) { - app *a = to_app(cond); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr *arg = a->get_arg(i); - if (cond_is_guard(arg, t)) { - guards.push_back(arg); - } else { - leftovers.push_back(arg); - } - } - } else if (cond_is_guard(cond, t)) { - guard = cond; - return; - } else { - leftover = cond; - return; - } - - if (guards.size() > 1) { - guard = formula_to_dnf(expr_ref(guard.m().mk_and(guards.size(), guards.c_ptr()), guard.m())); - } else if (guards.size() == 1) { - guard = guards.get(0); - } - - if (leftovers.size() > 1) { - leftover = formula_to_dnf(expr_ref(leftover.m().mk_and(leftovers.size(), leftovers.c_ptr()), leftover.m())); - } else if (leftovers.size() == 1) { - leftover = leftovers.get(0); - } - } - - class filter_fn : public table_mutator_fn { - expr_ref m_condition; - typename T::bitset_t m_filter; - bit_vector m_empty_bv; - public: - filter_fn(const T & t, ast_manager& m, app *condition) : - m_condition(m), m_filter(t.get_num_bits(), true) { - m_empty_bv.resize(t.get_num_bits(), false); - - expr_ref guard(m); - split_cond_guard(condition, guard, m_condition, t); - if (guard) - m_filter.filter(guard, m_empty_bv, t); - } - - virtual void operator()(table_base & tb) { - T & t = static_cast(tb); - // first apply guard and then run the interpreter on the leftover - t.m_bitsets.swap(m_filter.and(t.m_bitsets)); - if (m_condition) - t.m_bitsets.filter(m_condition, m_empty_bv, t); - TRACE("dl_hassel", tout << "final size: " << t.get_size_estimate_rows() << '\n';); - } - }; - - public: - virtual table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition) { - if (!check_kind(t)) - return 0; - TRACE("dl_hassel", tout << mk_pp(condition, get_ast_manager()) << '\n';); - return alloc(filter_fn, static_cast(t), get_ast_manager(), condition); - } - - private: - class filter_proj_fn : public convenient_table_project_fn { - expr_ref m_condition; - typename T::bitset_t m_filter; - bit_vector m_col_list; // map: col idx -> bool (whether the column is to be removed) - public: - filter_proj_fn(const T & t, ast_manager& m, app *condition, - unsigned col_cnt, const unsigned * removed_cols) : - convenient_table_project_fn(t.get_signature(), col_cnt, removed_cols), - m_condition(m), m_filter(t.get_num_bits(), true) { - t.expand_column_vector(m_removed_cols); - - m_col_list.resize(t.get_num_bits(), false); - for (unsigned i = 0; i < m_removed_cols.size(); ++i) { - m_col_list.set(m_removed_cols[i]); - } - m_removed_cols.push_back(UINT_MAX); - - expr_ref guard(m); - split_cond_guard(condition, guard, m_condition, t); - if (guard) - m_filter.filter(guard, m_col_list, t); - } - - virtual table_base* operator()(const table_base & tb) { - const T & t = static_cast(tb); - // first apply guard and then run the interpreter on the leftover - typename T::bitset_t filtered(t.get_num_bits()); - filtered.swap(m_filter.and(t.m_bitsets)); - if (m_condition) - filtered.filter(m_condition, m_col_list, t); - - T * res = static_cast(t.get_plugin().mk_empty(get_result_signature())); - filtered.project(m_removed_cols, res->m_bitsets); - TRACE("dl_hassel", tout << "final size: " << res->get_size_estimate_rows() << '\n';); - return res; - } - }; - - public: - virtual table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, app * condition, - unsigned removed_col_cnt, const unsigned * removed_cols) { - if (!check_kind(t)) - return 0; - TRACE("dl_hassel", tout << mk_pp(condition, get_ast_manager()) << '\n';); - return alloc(filter_proj_fn, static_cast(t), get_ast_manager(), - condition, removed_col_cnt, removed_cols); - } - - - virtual table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, const unsigned * t_cols, - const unsigned * negated_cols) { - NOT_IMPLEMENTED_YET(); - } - }; - - template - class common_hassel_table : public table_base, public table_information { - public: - typedef T bitset_t; - - common_hassel_table(table_plugin & p, const table_signature & sig) : - table_base(p, sig), table_information(p, sig), m_bitsets(get_num_bits()) { } - - virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const { - SASSERT(!func_columns); - - if (empty()) - return get_plugin().mk_full(p, get_signature()); - - common_hassel_table *res = static_cast(get_plugin().mk_empty(get_signature())); - res->m_bitsets.swap(m_bitsets.neg()); - return res; - } - - virtual void add_fact(const table_fact & f) { - m_bitsets.add_fact(ternary_bitvector(f, *this)); - } - - virtual void add_new_fact(const table_fact & f) { - m_bitsets.add_new_fact(ternary_bitvector(f, *this)); - } - - virtual void remove_fact(table_element const* fact) { - NOT_IMPLEMENTED_YET(); - } - - virtual void reset() { - m_bitsets.reset(); - } - - void mk_full() { - m_bitsets.mk_full(); - } - - virtual table_base * clone() const { - common_hassel_table *res = static_cast(get_plugin().mk_empty(get_signature())); - res->m_bitsets = m_bitsets; - return res; - } - - virtual bool contains_fact(const table_fact & f) { - return m_bitsets.contains(ternary_bitvector(f, *this)); - } - - virtual bool empty() const { - return m_bitsets.empty(); - } - -#if Z3DEBUG - class our_iterator_core : public iterator_core { - class our_row : public row_interface { - const our_iterator_core & m_parent; - const table_information& m_table; - public: - our_row(const common_hassel_table & t, const our_iterator_core & parent) : - row_interface(t), m_parent(parent), m_table(t) {} - - virtual table_element operator[](unsigned col) const { - return m_parent.it->to_number(m_table.column_idx(col), m_table.column_num_bits(col)); - } - }; - - our_row m_row_obj; - std::set BVs; - std::set::iterator it; - - public: - our_iterator_core(const common_hassel_table & t, bool finished) : - m_row_obj(t, *this) { - if (finished) { - it = BVs.end(); - return; - } - t.m_bitsets.expand(BVs); - it = BVs.begin(); - } - - virtual bool is_finished() const { - return it == BVs.end(); - } - - virtual row_interface & operator*() { - SASSERT(!is_finished()); - return m_row_obj; - } - - virtual void operator++() { - SASSERT(!is_finished()); - ++it; - } - }; -#endif - - virtual iterator begin() const { -#if Z3DEBUG - return mk_iterator(alloc(our_iterator_core, *this, false)); -#else - SASSERT(0 && "begin() disabled"); - return mk_iterator(0); -#endif - } - - virtual iterator end() const { -#if Z3DEBUG - return mk_iterator(alloc(our_iterator_core, *this, true)); -#else - SASSERT(0 && "end() disabled"); - return mk_iterator(0); -#endif - } - - virtual void display(std::ostream & out) const { - table_information::display(out); - m_bitsets.display(out); - } - - virtual void to_formula(relation_signature const& sig, expr_ref& fml) const { - // TODO - } - - virtual unsigned get_size_estimate_rows() const { - return m_bitsets.num_disjs(); - } - - virtual unsigned get_size_estimate_bytes() const { - return m_bitsets.num_bytes(); - } - - T m_bitsets; - }; - -} - -#endif diff --git a/src/muz_qe/dl_hassel_diff_table.cpp b/src/muz_qe/dl_hassel_diff_table.cpp deleted file mode 100755 index 3ddcb3bbe..000000000 --- a/src/muz_qe/dl_hassel_diff_table.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - dl_hassel_diff_table.cpp - -Abstract: - - - -Revision History: - ---*/ - -#include "ast_printer.h" -#include "dl_context.h" -#include "dl_util.h" -#include "dl_hassel_diff_table.h" - - -namespace datalog { - - ternary_diff_bitvector::ternary_diff_bitvector(unsigned size, bool full) : - m_pos(size, full), m_neg(size) { } - - ternary_diff_bitvector::ternary_diff_bitvector(uint64 n, unsigned num_bits) : - m_pos(n, num_bits), m_neg(num_bits) { } - - ternary_diff_bitvector::ternary_diff_bitvector(const ternary_bitvector & tbv) : - m_pos(tbv), m_neg(tbv.size()) { } - - bool ternary_diff_bitvector::contains(const ternary_diff_bitvector & other) const { - return m_pos.contains(other.m_pos) && other.m_neg.contains(m_neg); - } - - bool ternary_diff_bitvector::is_empty() const { - if (m_pos.is_empty()) - return true; - - return m_neg.contains(m_pos); - } - - ternary_diff_bitvector ternary_diff_bitvector::and(const ternary_diff_bitvector& other) const { - ternary_diff_bitvector result(m_pos.and(other.m_pos)); - result.m_neg.swap(m_neg.or(other.m_neg)); - return result; - } - - void ternary_diff_bitvector::neg(union_ternary_bitvector& result) const { - // not(A\B) <-> (T\A) U B - ternary_diff_bitvector negated(size(), true); - negated.m_neg.add_new_fact(m_pos); - result.add_fact(negated); - - for (union_ternary_bitvector::const_iterator I = m_neg.begin(), - E = m_neg.end(); I != E; ++I) { - result.add_fact(*I); - } - } - - void ternary_diff_bitvector::subtract(const union_ternary_bitvector& other, - union_ternary_bitvector& result) const { - ternary_diff_bitvector newfact(*this); - for (union_ternary_bitvector::const_iterator I = other.begin(), - E = other.end(); I != E; ++I) { - if (!I->m_neg.empty()) { - NOT_IMPLEMENTED_YET(); - } - newfact.m_neg.add_fact(I->m_pos); - } - - if (!newfact.is_empty()) - result.add_fact(newfact); - } - - void ternary_diff_bitvector::join(const ternary_diff_bitvector& other, - const unsigned_vector& cols1, - const unsigned_vector& cols2, - union_ternary_bitvector& result) const { - unsigned new_size = size() + other.size(); - ternary_diff_bitvector res(new_size); - - res.m_pos = m_pos; - res.m_pos.append(other.m_pos); - - for (unsigned i = 0; i < cols1.size(); ++i) { - unsigned idx1 = cols1[i]; - unsigned idx2 = size() + cols2[i]; - unsigned v1 = res.m_pos.get(idx1); - unsigned v2 = res.m_pos.get(idx2); - - if (v1 == BIT_x) { - if (v2 == BIT_x) { - // add to subtracted TBVs: 1xx0 and 0xx1 - { - ternary_bitvector r(new_size, true); - r.set(idx1, BIT_0); - r.set(idx2, BIT_1); - res.m_neg.add_new_fact(r); - } - { - ternary_bitvector r(new_size, true); - r.set(idx1, BIT_1); - r.set(idx2, BIT_0); - res.m_neg.add_new_fact(r); - } - } else { - res.m_pos.set(idx1, v2); - } - } else if (v2 == BIT_x) { - res.m_pos.set(idx2, v1); - } else if (v1 != v2) { - // columns don't match - return; - } - } - - // handle subtracted TBVs: 1010 -> 1010xxx - if (!m_neg.empty()) { - ternary_bitvector padding(other.size(), true); - for (union_ternary_bitvector::const_iterator I = m_neg.begin(), - E = m_neg.end(); I != E; ++I) { - ternary_bitvector BV(*I); - BV.append(padding); - res.m_neg.add_new_fact(BV); - } - } - - if (!other.m_neg.empty()) { - ternary_bitvector padding(size(), true); - for (union_ternary_bitvector::const_iterator I = other.m_neg.begin(), - E = other.m_neg.end(); I != E; ++I) { - ternary_bitvector BV(padding); - BV.append(*I); - res.m_neg.add_new_fact(BV); - } - } - - result.add_fact(res); - } - - bool ternary_diff_bitvector::project(const unsigned_vector& delcols, ternary_diff_bitvector& result) const { - m_pos.project(delcols, result.m_pos); - if (m_neg.empty()) - return true; - - ternary_bitvector newneg; - for (union_ternary_bitvector::const_iterator I = m_neg.begin(), - E = m_neg.end(); I != E; ++I) { - for (unsigned i = 0; i < delcols.size()-1; ++i) { - unsigned idx = delcols[i]; - if (I->get(idx) != BIT_x && m_pos.get(idx) == BIT_x) - goto skip_row; - } - newneg.reset(); - I->project(delcols, newneg); - result.m_neg.add_fact(newneg); -skip_row: ; - } - return !result.is_empty(); - } - - void ternary_diff_bitvector::rename(const unsigned_vector& cyclecols, - const unsigned_vector& out_of_cycle_cols, - const table_information& src_table, - const table_information& dst_table, - ternary_diff_bitvector& result) const { - m_pos.rename(cyclecols, out_of_cycle_cols, src_table, dst_table, result.m_pos); - m_neg.rename(cyclecols, out_of_cycle_cols, src_table, dst_table, result.m_neg); - } - - unsigned ternary_diff_bitvector::get(unsigned idx) { - return m_pos.get(idx); - } - - void ternary_diff_bitvector::set(unsigned idx, unsigned val) { - m_pos.set(idx, val); - } - - void ternary_diff_bitvector::swap(ternary_diff_bitvector & other) { - m_pos.swap(other.m_pos); - m_neg.swap(other.m_neg); - } - - void ternary_diff_bitvector::reset() { - m_pos.reset(); - m_neg.reset(); - } - - void ternary_diff_bitvector::display(std::ostream & out) const { - m_pos.display(out); - if (!m_neg.empty()) { - out << " \\ "; - if (m_neg.num_disjs() > 1) out << '('; - m_neg.display(out); - if (m_neg.num_disjs() > 1) out << ')'; - } - } - - unsigned ternary_diff_bitvector::size_in_bytes() const { - return m_pos.size_in_bytes() + m_neg.num_bytes(); - } - -#if Z3DEBUG - void ternary_diff_bitvector::expand(std::set & BVs) const { - m_pos.expand(BVs); - SASSERT(!BVs.empty()); - - std::set NegBVs; - m_neg.expand(NegBVs); - BVs.erase(NegBVs.begin(), NegBVs.end()); - } -#endif - - hassel_diff_table_plugin::hassel_diff_table_plugin(relation_manager & manager) - : common_hassel_table_plugin(symbol("hassel_diff"), manager) {} - -} diff --git a/src/muz_qe/dl_hassel_diff_table.h b/src/muz_qe/dl_hassel_diff_table.h deleted file mode 100755 index 07340c7e8..000000000 --- a/src/muz_qe/dl_hassel_diff_table.h +++ /dev/null @@ -1,87 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - dl_hassel_diff_table.h - -Abstract: - - - -Revision History: - ---*/ - -#ifndef _DL_HASSEL_DIFF_TABLE_H_ -#define _DL_HASSEL_DIFF_TABLE_H_ - -#include "dl_hassel_common.h" - -namespace datalog { - - class hassel_diff_table; - - class ternary_diff_bitvector { - // pos \ (neg0 \/ ... \/ negn) - ternary_bitvector m_pos; - union_ternary_bitvector m_neg; - - public: - ternary_diff_bitvector() : m_pos(), m_neg(0) {} - ternary_diff_bitvector(unsigned size) : m_pos(size), m_neg(size) {} - ternary_diff_bitvector(unsigned size, bool full); - ternary_diff_bitvector(uint64 n, unsigned num_bits); - ternary_diff_bitvector(const ternary_bitvector & tbv); - - bool contains(const ternary_diff_bitvector & other) const; - bool is_empty() const; - - ternary_diff_bitvector and(const ternary_diff_bitvector& other) const; - void neg(union_ternary_bitvector& result) const; - - static bool has_subtract() { return true; } - void subtract(const union_ternary_bitvector& other, - union_ternary_bitvector& result) const; - - void join(const ternary_diff_bitvector& other, const unsigned_vector& cols1, - const unsigned_vector& cols2, union_ternary_bitvector& result) const; - - bool project(const unsigned_vector& delcols, ternary_diff_bitvector& result) const; - - void rename(const unsigned_vector& cyclecols, const unsigned_vector& out_of_cycle_cols, - const table_information& src_table, const table_information& dst_table, - ternary_diff_bitvector& result) const; - - unsigned get(unsigned idx); - void set(unsigned idx, unsigned val); - - void swap(ternary_diff_bitvector & other); - void reset(); - - unsigned size() const { return m_pos.size(); } - - void display(std::ostream & out) const; - unsigned size_in_bytes() const; - -#if Z3DEBUG - void expand(std::set & BVs) const; -#endif - }; - - typedef union_ternary_bitvector union_ternary_diff_bitvector; - - class hassel_diff_table : public common_hassel_table { - public: - hassel_diff_table(table_plugin & p, const table_signature & sig) : - common_hassel_table(p, sig) {} - }; - - class hassel_diff_table_plugin : public common_hassel_table_plugin { - public: - hassel_diff_table_plugin(relation_manager & manager); - }; - -} - -#endif diff --git a/src/muz_qe/dl_hassel_table.cpp b/src/muz_qe/dl_hassel_table.cpp deleted file mode 100644 index 6ec28df87..000000000 --- a/src/muz_qe/dl_hassel_table.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - dl_hassel_table.cpp - -Abstract: - - - -Revision History: - ---*/ - -#include "ast_printer.h" -#include "dl_context.h" -#include "dl_util.h" -#include "dl_hassel_table.h" - - -namespace datalog { - - hassel_table_plugin::hassel_table_plugin(relation_manager & manager) - : common_hassel_table_plugin(symbol("hassel"), manager) {} - -} diff --git a/src/muz_qe/dl_hassel_table.h b/src/muz_qe/dl_hassel_table.h deleted file mode 100644 index 6c4e9c1fe..000000000 --- a/src/muz_qe/dl_hassel_table.h +++ /dev/null @@ -1,39 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - dl_hassel_table.h - -Abstract: - - - -Revision History: - ---*/ - -#ifndef _DL_HASSEL_TABLE_H_ -#define _DL_HASSEL_TABLE_H_ - -#include "dl_hassel_common.h" - -namespace datalog { - - class hassel_table; - typedef union_ternary_bitvector union_ternary_bitvectors; - - class hassel_table : public common_hassel_table { - public: - hassel_table(table_plugin & p, const table_signature & sig) : - common_hassel_table(p, sig) {} - }; - - class hassel_table_plugin : public common_hassel_table_plugin { - public: - hassel_table_plugin(relation_manager & manager); - }; - -} - -#endif diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index dcfbcca2b..76f744325 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1561,15 +1561,16 @@ namespace pdr { m_fparams.m_arith_auto_config_simplex = true; m_fparams.m_arith_propagate_eqs = false; m_fparams.m_arith_eager_eq_axioms = false; - if (classify.is_utvpi() && m_params.use_utvpi()) { + if (classify.is_dl()) { + m_fparams.m_arith_mode = AS_DIFF_LOGIC; + m_fparams.m_arith_expand_eqs = true; + } + else if (classify.is_utvpi() && m_params.use_utvpi()) { IF_VERBOSE(1, verbose_stream() << "UTVPI\n";); m_fparams.m_arith_mode = AS_UTVPI; m_fparams.m_arith_expand_eqs = true; } - else if (classify.is_dl()) { - m_fparams.m_arith_mode = AS_DIFF_LOGIC; - m_fparams.m_arith_expand_eqs = true; - } + } if (!use_mc && m_params.use_inductive_generalizer()) { m_core_generalizers.push_back(alloc(core_bool_inductive_generalizer, *this, 0)); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 3d61c04f0..7aade28e2 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -19,7 +19,6 @@ Revision History: --*/ -#define Z3_HASSEL_TABLE #include"rel_context.h" #include"dl_context.h" @@ -33,10 +32,6 @@ Revision History: #include"dl_mk_karr_invariants.h" #include"dl_finite_product_relation.h" #include"dl_sparse_table.h" -#ifdef Z3_HASSEL_TABLE -# include"dl_hassel_table.h" -# include"dl_hassel_diff_table.h" -#endif #include"dl_table.h" #include"dl_table_relation.h" #include"aig_exporter.h" @@ -94,10 +89,6 @@ namespace datalog { get_rmanager().register_plugin(alloc(bitvector_table_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(equivalence_table_plugin, get_rmanager())); -#ifdef Z3_HASSEL_TABLE - get_rmanager().register_plugin(alloc(hassel_table_plugin, get_rmanager())); - get_rmanager().register_plugin(alloc(hassel_diff_table_plugin, get_rmanager())); -#endif // register plugins for builtin relations diff --git a/src/smt/database.smt b/src/smt/database.smt index 186dd9b95..2f5e5e1c9 100644 --- a/src/smt/database.smt +++ b/src/smt/database.smt @@ -311,4 +311,4 @@ (= (?is (?select (?select (?asElems e) a) i) (?elemtype (?typeof a))) 1) :pats { (?select (?select (?asElems e) a) i) }) - ) \ No newline at end of file + ) diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index 6c85e40b9..498a2a172 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -418,9 +418,6 @@ namespace smt { return FC_GIVEUP; } else { - m_graph.set_to_zero(to_var(m_zero_int), to_var(m_zero_real)); - m_graph.set_to_zero(neg(to_var(m_zero_int)), neg(to_var(m_zero_real))); - m_graph.set_to_zero(to_var(m_zero_int), neg(to_var(m_zero_int))); return FC_DONE; } } @@ -691,16 +688,33 @@ namespace smt { \brief adjust values for variables in the difference graph such that for variables of integer sort it is the case that x^+ - x^- is even. - The informal justification for the procedure enforce_parity is that - the graph does not contain a strongly connected component where - x^+ and x+- are connected. They can be independently changed. - Since we would like variables representing 0 (zero) map to 0, - we selectively update the subgraph that can be updated without - changing the value of zero (which should be 0). + The informal justification for the procedure enforce_parity relies + on a set of properties: + 1. the graph does not contain a strongly connected component where + x^+ and x+- are connected. They can be independently changed. + This is checked prior to enforce_parity. + 2. When x^+ - x^- is odd, the values are adjusted by first + decrementing the value of x^+, provided x^- is not 0-dependent. + Otherwise decrement x^-. + x^- is "0-dependent" if there is a set of tight + inequalities from x^+ to x^-. + 3. The affinity to x^+ (the same component of x^+) ensures that + the parity is broken only a finite number of times when + traversing that component. Namely, suppose that the parity of y + gets broken when fixing 'x'. Then first note that 'y' cannot + be equal to 'x'. If it were, then we have a state where: + parity(x^+) != parity(x^-) and + parity(y^+) == parity(y^-) + but x^+ and y^+ are tightly connected and x^- and y^- are + also tightly connected using two copies of the same inequalities. + This is a contradiction. + Thus, 'y' cannot be equal to 'x' if 'y's parity gets broken when + repairing 'x'. + */ template void theory_utvpi::enforce_parity() { - unsigned_vector todo; + unsigned_vector todo; unsigned sz = get_num_vars(); for (unsigned i = 0; i < sz; ++i) { @@ -712,6 +726,8 @@ namespace smt { if (todo.empty()) { return; } + IF_VERBOSE(2, verbose_stream() << "disparity: " << todo.size() << "\n";); + unsigned iter = 0; while (!todo.empty()) { unsigned i = todo.back(); todo.pop_back(); @@ -720,21 +736,17 @@ namespace smt { } th_var v1 = to_var(i); th_var v2 = neg(v1); - TRACE("utvpi", tout << "disparity: " << v1 << "\n";); + + // IF_VERBOSE(1, verbose_stream() << "disparity: " << v1 << "\n";); int_vector zero_v; m_graph.compute_zero_succ(v1, zero_v); - bool found0 = false; - for (unsigned j = 0; !found0 && j < zero_v.size(); ++j) { - found0 = - (to_var(m_zero_int) == zero_v[j]) || - (neg(to_var(m_zero_int)) == zero_v[j]); - } - // variables that are tightly connected - // to 0 should not have their values changed. - if (found0) { - zero_v.reset(); - m_graph.compute_zero_succ(v2, zero_v); + for (unsigned j = 0; j < zero_v.size(); ++j) { + if (zero_v[j] == v2) { + zero_v.reset(); + m_graph.compute_zero_succ(v2, zero_v); + } } + TRACE("utvpi", for (unsigned j = 0; j < zero_v.size(); ++j) { tout << "decrement: " << zero_v[j] << "\n"; @@ -745,10 +757,23 @@ namespace smt { m_graph.acc_assignment(v, numeral(-1)); th_var k = from_var(v); if (!is_parity_ok(k)) { - TRACE("utvpi", tout << "new disparity: " << k << "\n";); + // IF_VERBOSE(1, verbose_stream() << "new disparity: " << k << "\n";); todo.push_back(k); } - } + } + if (iter >= 10000) { + IF_VERBOSE(1, + verbose_stream() << "decrement: "; + for (unsigned j = 0; j < zero_v.size(); ++j) { + rational r = m_graph.get_assignment(zero_v[j]).get_rational(); + verbose_stream() << zero_v[j] << " (" << r << ") "; + } + verbose_stream() << "\n";); + if (!is_parity_ok(i)) { + IF_VERBOSE(1, verbose_stream() << "Parity not fixed\n";); + } + } + ++iter; } SASSERT(m_graph.is_feasible()); DEBUG_CODE( @@ -764,10 +789,13 @@ namespace smt { // models: template - void theory_utvpi::init_model(model_generator & m) { + void theory_utvpi::init_model(model_generator & m) { m_factory = alloc(arith_factory, get_manager()); m.register_factory(m_factory); enforce_parity(); + m_graph.set_to_zero(to_var(m_zero_int), to_var(m_zero_real)); + m_graph.set_to_zero(neg(to_var(m_zero_int)), neg(to_var(m_zero_real))); + m_graph.set_to_zero(to_var(m_zero_int), neg(to_var(m_zero_int))); compute_delta(); DEBUG_CODE(validate_model();); } From 76a269c85a6522da30dcb603279e9470493e13d4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 1 Jun 2013 17:14:18 -0700 Subject: [PATCH 161/281] clean up parity computation Signed-off-by: unknown --- src/smt/theory_utvpi_def.h | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/smt/theory_utvpi_def.h b/src/smt/theory_utvpi_def.h index 498a2a172..8463eb17f 100644 --- a/src/smt/theory_utvpi_def.h +++ b/src/smt/theory_utvpi_def.h @@ -714,8 +714,7 @@ namespace smt { */ template void theory_utvpi::enforce_parity() { - unsigned_vector todo; - + unsigned_vector todo; unsigned sz = get_num_vars(); for (unsigned i = 0; i < sz; ++i) { enode* e = get_enode(i); @@ -726,8 +725,6 @@ namespace smt { if (todo.empty()) { return; } - IF_VERBOSE(2, verbose_stream() << "disparity: " << todo.size() << "\n";); - unsigned iter = 0; while (!todo.empty()) { unsigned i = todo.back(); todo.pop_back(); @@ -737,17 +734,18 @@ namespace smt { th_var v1 = to_var(i); th_var v2 = neg(v1); - // IF_VERBOSE(1, verbose_stream() << "disparity: " << v1 << "\n";); int_vector zero_v; m_graph.compute_zero_succ(v1, zero_v); for (unsigned j = 0; j < zero_v.size(); ++j) { if (zero_v[j] == v2) { zero_v.reset(); m_graph.compute_zero_succ(v2, zero_v); + break; } } TRACE("utvpi", + tout << "Disparity: " << v1 << "\n"; for (unsigned j = 0; j < zero_v.size(); ++j) { tout << "decrement: " << zero_v[j] << "\n"; }); @@ -757,23 +755,9 @@ namespace smt { m_graph.acc_assignment(v, numeral(-1)); th_var k = from_var(v); if (!is_parity_ok(k)) { - // IF_VERBOSE(1, verbose_stream() << "new disparity: " << k << "\n";); todo.push_back(k); } } - if (iter >= 10000) { - IF_VERBOSE(1, - verbose_stream() << "decrement: "; - for (unsigned j = 0; j < zero_v.size(); ++j) { - rational r = m_graph.get_assignment(zero_v[j]).get_rational(); - verbose_stream() << zero_v[j] << " (" << r << ") "; - } - verbose_stream() << "\n";); - if (!is_parity_ok(i)) { - IF_VERBOSE(1, verbose_stream() << "Parity not fixed\n";); - } - } - ++iter; } SASSERT(m_graph.is_feasible()); DEBUG_CODE( From ec121db5c1a8a41c38fbee3922493d2e0a5e740e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jun 2013 12:02:35 -0700 Subject: [PATCH 162/281] addressing race condition on interrupts Signed-off-by: Nikolaj Bjorner --- src/shell/smtlib_frontend.cpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index a005462e2..b5d8635da 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -54,13 +54,19 @@ static void display_statistics() { } static void on_timeout() { - display_statistics(); - exit(0); + #pragma omp critical (g_display_stats) + { + display_statistics(); + exit(0); + } } static void on_ctrl_c(int) { signal (SIGINT, SIG_DFL); - display_statistics(); + #pragma omp critical (g_display_stats) + { + display_statistics(); + } raise(SIGINT); } @@ -83,9 +89,12 @@ unsigned read_smtlib_file(char const * benchmark_file) { } } - display_statistics(); - register_on_timeout_proc(0); - g_solver = 0; + #pragma omp critical (g_display_stats) + { + display_statistics(); + register_on_timeout_proc(0); + g_solver = 0; + } return solver.get_error_code(); } @@ -118,8 +127,12 @@ unsigned read_smtlib2_commands(char const * file_name) { result = parse_smt2_commands(ctx, std::cin, true); } - display_statistics(); - g_cmd_context = 0; + + #pragma omp critical (g_display_stats) + { + display_statistics(); + g_cmd_context = 0; + } return result ? 0 : 1; } From d569027e369ce834297873e990db098717155f88 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jun 2013 20:54:01 -0700 Subject: [PATCH 163/281] fix reference count bugs in overflow/underflow APIs for bit-vectors Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 4 + src/api/api_bv.cpp | 133 +++++++++++++++++++++---- src/muz_qe/qe.cpp | 2 +- src/smt/params/theory_arith_params.cpp | 1 + src/smt/theory_arith_core.h | 2 +- 5 files changed, 120 insertions(+), 22 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index c4b5c97d7..6855f6209 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1070,6 +1070,10 @@ 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: + return Z3_OP_UNINTERPRETED; default: UNREACHABLE(); return Z3_OP_UNINTERPRETED; diff --git a/src/api/api_bv.cpp b/src/api/api_bv.cpp index 8126c8e2a..07d4fda18 100644 --- a/src/api/api_bv.cpp +++ b/src/api/api_bv.cpp @@ -121,10 +121,20 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ unsigned sz = Z3_get_bv_sort_size(c, s); rational max_bound = power(rational(2), sz); Z3_ast bound = Z3_mk_numeral(c, max_bound.to_string().c_str(), int_s); - Z3_ast pred = Z3_mk_bvslt(c, n, Z3_mk_int(c, 0, s)); + Z3_inc_ref(c, bound); + Z3_ast zero = Z3_mk_int(c, 0, s); + Z3_inc_ref(c, zero); + Z3_ast pred = Z3_mk_bvslt(c, n, zero); + Z3_inc_ref(c, pred); // if n <_sigend 0 then r - s^sz else r Z3_ast args[2] = { r, bound }; - Z3_ast res = Z3_mk_ite(c, pred, Z3_mk_sub(c, 2, args), r); + Z3_ast sub = Z3_mk_sub(c, 2, args); + Z3_inc_ref(c, sub); + Z3_ast res = Z3_mk_ite(c, pred, sub, r); + Z3_dec_ref(c, bound); + Z3_dec_ref(c, pred); + Z3_dec_ref(c, sub); + Z3_dec_ref(c, zero); RETURN_Z3(res); } else { @@ -156,7 +166,14 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - return Z3_mk_bvshl(c, Z3_mk_int64(c, 1, s), Z3_mk_int64(c, sz - 1, s)); + Z3_ast x = Z3_mk_int64(c, 1, s); + Z3_inc_ref(c, x); + Z3_ast y = Z3_mk_int64(c, sz - 1, s); + Z3_inc_ref(c, y); + Z3_ast result = Z3_mk_bvshl(c, x, y); + Z3_dec_ref(c, x); + Z3_dec_ref(c, y); + return result; Z3_CATCH_RETURN(0); } @@ -177,17 +194,40 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ RESET_ERROR_CODE(); if (is_signed) { Z3_ast zero = Z3_mk_int(c, 0, Z3_get_sort(c, t1)); + Z3_inc_ref(c, zero); Z3_ast r = Z3_mk_bvadd(c, t1, t2); - Z3_ast args[2] = { Z3_mk_bvslt(c, zero, t1), Z3_mk_bvslt(c, zero, t2) }; + Z3_inc_ref(c, r); + Z3_ast l1 = Z3_mk_bvslt(c, zero, t1); + Z3_inc_ref(c, l1); + Z3_ast l2 = Z3_mk_bvslt(c, zero, t2); + Z3_inc_ref(c, l2); + Z3_ast args[2] = { l1, l2 }; Z3_ast args_pos = Z3_mk_and(c, 2, args); - return Z3_mk_implies(c, args_pos, Z3_mk_bvslt(c, zero, r)); + Z3_inc_ref(c, args_pos); + Z3_ast result = Z3_mk_implies(c, args_pos, Z3_mk_bvslt(c, zero, r)); + Z3_dec_ref(c, r); + Z3_dec_ref(c, l1); + Z3_dec_ref(c, l2); + Z3_dec_ref(c, args_pos); + Z3_dec_ref(c, zero); + return result; } else { unsigned sz = Z3_get_bv_sort_size(c, Z3_get_sort(c, t1)); t1 = Z3_mk_zero_ext(c, 1, t1); + Z3_inc_ref(c, t1); t2 = Z3_mk_zero_ext(c, 1, t2); + Z3_inc_ref(c, t2); Z3_ast r = Z3_mk_bvadd(c, t1, t2); - return Z3_mk_eq(c, Z3_mk_extract(c, sz, sz, r), Z3_mk_int(c, 0, Z3_mk_bv_sort(c, 1))); + Z3_inc_ref(c, r); + Z3_ast ex = Z3_mk_extract(c, sz, sz, r); + Z3_inc_ref(c, ex); + Z3_ast result = Z3_mk_eq(c, ex, Z3_mk_int(c, 0, Z3_mk_bv_sort(c, 1))); + Z3_dec_ref(c, t1); + Z3_dec_ref(c, t2); + Z3_dec_ref(c, ex); + Z3_dec_ref(c, r); + return result; } Z3_CATCH_RETURN(0); } @@ -197,10 +237,26 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_TRY; RESET_ERROR_CODE(); Z3_ast zero = Z3_mk_int(c, 0, Z3_get_sort(c, t1)); + Z3_inc_ref(c, zero); Z3_ast r = Z3_mk_bvadd(c, t1, t2); - Z3_ast args[2] = { Z3_mk_bvslt(c, t1, zero), Z3_mk_bvslt(c, t2, zero) }; + Z3_inc_ref(c, r); + Z3_ast l1 = Z3_mk_bvslt(c, t1, zero); + Z3_inc_ref(c, l1); + Z3_ast l2 = Z3_mk_bvslt(c, t2, zero); + Z3_inc_ref(c, l2); + Z3_ast args[2] = { l1, l2 }; Z3_ast args_neg = Z3_mk_and(c, 2, args); - return Z3_mk_implies(c, args_neg, Z3_mk_bvslt(c, r, zero)); + Z3_inc_ref(c, args_neg); + Z3_ast lt = Z3_mk_bvslt(c, r, zero); + Z3_inc_ref(c, lt); + Z3_ast result = Z3_mk_implies(c, args_neg, lt); + Z3_dec_ref(c, lt); + Z3_dec_ref(c, l1); + Z3_dec_ref(c, l2); + Z3_dec_ref(c, r); + Z3_dec_ref(c, args_neg); + Z3_dec_ref(c, zero); + return result; Z3_CATCH_RETURN(0); } @@ -208,12 +264,28 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_ast Z3_API Z3_mk_bvsub_no_overflow(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2) { Z3_TRY; RESET_ERROR_CODE(); - Z3_sort s = Z3_get_sort(c, t2); Z3_ast minus_t2 = Z3_mk_bvneg(c, t2); + Z3_inc_ref(c, minus_t2); + Z3_sort s = Z3_get_sort(c, t2); Z3_ast min = Z3_mk_bvsmin(c, s); - return Z3_mk_ite(c, Z3_mk_eq(c, t2, min), - Z3_mk_bvslt(c, t1, Z3_mk_int(c, 0, s)), - Z3_mk_bvadd_no_overflow(c, t1, minus_t2, true)); + Z3_inc_ref(c, min); + Z3_ast x = Z3_mk_eq(c, t2, min); + Z3_inc_ref(c, x); + Z3_ast zero = Z3_mk_int(c, 0, s); + Z3_inc_ref(c, zero); + Z3_ast y = Z3_mk_bvslt(c, t1, zero); + Z3_inc_ref(c, y); + Z3_ast z = Z3_mk_bvadd_no_overflow(c, t1, minus_t2, true); + Z3_inc_ref(c, z); + Z3_ast result = Z3_mk_ite(c, x, y, z); + mk_c(c)->save_ast_trail(to_app(result)); + Z3_dec_ref(c, minus_t2); + Z3_dec_ref(c, min); + Z3_dec_ref(c, x); + Z3_dec_ref(c, y); + Z3_dec_ref(c, z); + Z3_dec_ref(c, zero); + return result; Z3_CATCH_RETURN(0); } @@ -222,10 +294,19 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ RESET_ERROR_CODE(); if (is_signed) { Z3_ast zero = Z3_mk_int(c, 0, Z3_get_sort(c, t1)); - if (Z3_get_error_code(c) != Z3_OK) return 0; + Z3_inc_ref(c, zero); Z3_ast minus_t2 = Z3_mk_bvneg(c, t2); - if (Z3_get_error_code(c) != Z3_OK) return 0; - return Z3_mk_implies(c, Z3_mk_bvslt(c, zero, t2), Z3_mk_bvadd_no_underflow(c, t1, minus_t2)); + Z3_inc_ref(c, minus_t2); + Z3_ast x = Z3_mk_bvslt(c, zero, t2); + Z3_inc_ref(c, x); + Z3_ast y = Z3_mk_bvadd_no_underflow(c, t1, minus_t2); + Z3_inc_ref(c, y); + Z3_ast result = Z3_mk_implies(c, x, y); + Z3_dec_ref(c, zero); + Z3_dec_ref(c, minus_t2); + Z3_dec_ref(c, x); + Z3_dec_ref(c, y); + return result; } else { return Z3_mk_bvule(c, t2, t1); @@ -267,12 +348,24 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \ Z3_TRY; RESET_ERROR_CODE(); Z3_sort s = Z3_get_sort(c, t1); - if (Z3_get_error_code(c) != Z3_OK) return 0; Z3_ast min = Z3_mk_bvmsb(c, s); - if (Z3_get_error_code(c) != Z3_OK) return 0; - Z3_ast args[2] = { Z3_mk_eq(c, t1, min), - Z3_mk_eq(c, t2, Z3_mk_int(c, -1, s)) }; - return Z3_mk_not(c, Z3_mk_and(c, 2, args)); + Z3_inc_ref(c, min); + Z3_ast x = Z3_mk_eq(c, t1, min); + Z3_inc_ref(c, x); + Z3_ast y = Z3_mk_int(c, -1, s); + Z3_inc_ref(c, y); + Z3_ast z = Z3_mk_eq(c, t2, y); + Z3_inc_ref(c, z); + Z3_ast args[2] = { x, z }; + Z3_ast u = Z3_mk_and(c, 2, args); + Z3_inc_ref(c, u); + Z3_ast result = Z3_mk_not(c, u); + Z3_dec_ref(c, min); + Z3_dec_ref(c, x); + Z3_dec_ref(c, y); + Z3_dec_ref(c, z); + Z3_dec_ref(c, u); + return result; Z3_CATCH_RETURN(0); } diff --git a/src/muz_qe/qe.cpp b/src/muz_qe/qe.cpp index 894a935b5..5603b8102 100644 --- a/src/muz_qe/qe.cpp +++ b/src/muz_qe/qe.cpp @@ -2084,7 +2084,7 @@ namespace qe { flet fl1(m_fparams.m_model, true); flet fl2(m_fparams.m_simplify_bit2int, true); - flet fl3(m_fparams.m_arith_enum_const_mod, true); + //flet fl3(m_fparams.m_arith_enum_const_mod, true); flet fl4(m_fparams.m_bv_enable_int2bv2int, true); flet fl5(m_fparams.m_array_canonize_simplify, true); flet fl6(m_fparams.m_relevancy_lvl, 0); diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index 7281a5daa..dcffa83dc 100644 --- a/src/smt/params/theory_arith_params.cpp +++ b/src/smt/params/theory_arith_params.cpp @@ -33,6 +33,7 @@ void theory_arith_params::updt_params(params_ref const & _p) { m_arith_int_eq_branching = p.arith_int_eq_branch(); m_arith_ignore_int = p.arith_ignore_int(); m_arith_bound_prop = static_cast(p.arith_propagation_mode()); + m_arith_enum_const_mod = true; } diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index fafe73a79..195d78e25 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -408,7 +408,7 @@ namespace smt { mk_axiom(eqz, upper); rational k; if (m_params.m_arith_enum_const_mod && m_util.is_numeral(divisor, k) && - k.is_pos() && k < rational(512)) { + k.is_pos() && k < rational(8)) { rational j(0); #if 1 literal_buffer lits; From 56bfc06c4f7e33d4249551e269e443b19f71ef89 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 2 Jun 2013 20:55:15 -0700 Subject: [PATCH 164/281] fix reference count bugs in overflow/underflow APIs for bit-vectors Signed-off-by: Nikolaj Bjorner --- src/muz_qe/qe.cpp | 2 +- src/smt/params/theory_arith_params.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/muz_qe/qe.cpp b/src/muz_qe/qe.cpp index 5603b8102..894a935b5 100644 --- a/src/muz_qe/qe.cpp +++ b/src/muz_qe/qe.cpp @@ -2084,7 +2084,7 @@ namespace qe { flet fl1(m_fparams.m_model, true); flet fl2(m_fparams.m_simplify_bit2int, true); - //flet fl3(m_fparams.m_arith_enum_const_mod, true); + flet fl3(m_fparams.m_arith_enum_const_mod, true); flet fl4(m_fparams.m_bv_enable_int2bv2int, true); flet fl5(m_fparams.m_array_canonize_simplify, true); flet fl6(m_fparams.m_relevancy_lvl, 0); diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index dcffa83dc..7281a5daa 100644 --- a/src/smt/params/theory_arith_params.cpp +++ b/src/smt/params/theory_arith_params.cpp @@ -33,7 +33,6 @@ void theory_arith_params::updt_params(params_ref const & _p) { m_arith_int_eq_branching = p.arith_int_eq_branch(); m_arith_ignore_int = p.arith_ignore_int(); m_arith_bound_prop = static_cast(p.arith_propagation_mode()); - m_arith_enum_const_mod = true; } From 7c32df93a4627f78c6be0dba6d6817967ce28c4d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 3 Jun 2013 18:17:41 +0100 Subject: [PATCH 165/281] SLS tactic: compilation fixes Signed-off-by: Christoph M. Wintersteiger --- src/tactic/sls/sls_tactic.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index f49ce8422..69e1c8bc3 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -1370,7 +1370,7 @@ class sls_tactic : public tactic { void updt_params(params_ref const & p) { m_produce_models = p.get_bool("produce_models", false); - m_max_restarts = p.get_uint("sls_restarts", -1); + m_max_restarts = p.get_uint("sls_restarts", (unsigned)-1); m_tracker.set_random_seed(p.get_uint("random_seed", 0)); m_plateau_limit = p.get_uint("plateau_limit", 100); } @@ -1612,7 +1612,7 @@ class sls_tactic : public tactic { lbool search(goal_ref const & g) { lbool res = l_undef; double score = 0.0, old_score = 0.0; - unsigned new_const = -1, new_bit = 0; + unsigned new_const = (unsigned)-1, new_bit = 0; mpz new_value; move_type move; @@ -1631,7 +1631,7 @@ class sls_tactic : public tactic { checkpoint(); old_score = score; - new_const = -1; + new_const = (unsigned)-1; ptr_vector & to_evaluate = m_tracker.get_unsat_constants(g); From 093fe945bc3e57d5d8c1f9f4afdf597549ef8ab2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 3 Jun 2013 18:19:45 +0100 Subject: [PATCH 166/281] FPA: min/max/fma bugfixes + partial quantifier support Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 223 ++++++++++++++++++++-------- src/tactic/fpa/fpa2bv_rewriter.h | 16 +- 2 files changed, 165 insertions(+), 74 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 363cf1df8..02aff67c6 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1022,13 +1022,15 @@ void fpa2bv_converter::mk_min(func_decl * f, unsigned num, expr * const * args, split(x, x_sgn, x_sig, x_exp); split(y, y_sgn, y_sig, y_exp); - expr_ref c1(m), c2(m), y_is_nan(m), x_is_nzero(m), y_is_zero(m), c2_and(m); - mk_is_nan(x, c1); - mk_is_nan(y, y_is_nan); - mk_is_nzero(x, x_is_nzero); + expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), x_is_zero(m), y_is_zero(m), c1_and(m); + mk_is_zero(x, x_is_zero); mk_is_zero(y, y_is_zero); - m_simp.mk_and(x_is_nzero, y_is_zero, c2_and); - m_simp.mk_or(y_is_nan, c2_and, c2); + m_simp.mk_and(x_is_zero, y_is_zero, c1_and); + mk_is_nan(x, x_is_nan); + m_simp.mk_or(x_is_nan, c1_and, c1); + + mk_is_nan(y, y_is_nan); + c2 = y_is_nan; expr_ref c3(m); mk_float_lt(f, num, args, c3); @@ -1063,13 +1065,15 @@ void fpa2bv_converter::mk_max(func_decl * f, unsigned num, expr * const * args, split(x, x_sgn, x_sig, x_exp); split(y, y_sgn, y_sig, y_exp); - expr_ref c1(m), c2(m), y_is_nan(m), y_is_nzero(m), x_is_zero(m), xy_is_zero(m); - mk_is_nan(x, c1); - mk_is_nan(y, y_is_nan); - mk_is_nzero(y, y_is_nzero); + expr_ref c1(m), c2(m), x_is_nan(m), y_is_nan(m), y_is_zero(m), x_is_zero(m), c1_and(m); + mk_is_zero(y, y_is_zero); mk_is_zero(x, x_is_zero); - m_simp.mk_and(y_is_nzero, x_is_zero, xy_is_zero); - m_simp.mk_or(y_is_nan, xy_is_zero, c2); + m_simp.mk_and(y_is_zero, x_is_zero, c1_and); + mk_is_nan(x, x_is_nan); + m_simp.mk_or(x_is_nan, c1_and, c1); + + mk_is_nan(y, y_is_nan); + c2 = y_is_nan; expr_ref c3(m); mk_float_gt(f, num, args, c3); @@ -1111,20 +1115,23 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar mk_minus_inf(f, ninf); mk_plus_inf(f, pinf); - expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m); - expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m); - expr_ref z_is_nan(m), z_is_zero(m), z_is_pos(m), z_is_inf(m); + expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_neg(m), x_is_inf(m); + expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_neg(m), y_is_inf(m); + expr_ref z_is_nan(m), z_is_zero(m), z_is_pos(m), z_is_neg(m), z_is_inf(m); mk_is_nan(x, x_is_nan); mk_is_zero(x, x_is_zero); mk_is_pos(x, x_is_pos); + mk_is_neg(x, x_is_neg); mk_is_inf(x, x_is_inf); mk_is_nan(y, y_is_nan); mk_is_zero(y, y_is_zero); mk_is_pos(y, y_is_pos); + mk_is_neg(y, y_is_neg); mk_is_inf(y, y_is_inf); mk_is_nan(z, z_is_nan); mk_is_zero(z, z_is_zero); mk_is_pos(z, z_is_pos); + mk_is_neg(z, z_is_neg); mk_is_inf(z, z_is_inf); dbg_decouple("fpa2bv_fma_x_is_nan", x_is_nan); @@ -1140,42 +1147,56 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar dbg_decouple("fpa2bv_fma_z_is_pos", z_is_pos); dbg_decouple("fpa2bv_fma_z_is_inf", z_is_inf); - expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m); - expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m); + expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m), c7(m); + expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m), v8(m); - // (x is NaN) || (y is NaN) -> NaN - m_simp.mk_or(x_is_nan, y_is_nan, c1); + expr_ref inf_xor(m), inf_cond(m); + m_simp.mk_xor(x_is_neg, y_is_neg, inf_xor); + m_simp.mk_xor(inf_xor, z_is_neg, inf_xor); + m_simp.mk_and(z_is_inf, inf_xor, inf_cond); + + // (x is NaN) || (y is NaN) || (z is Nan) -> NaN + m_simp.mk_or(x_is_nan, y_is_nan, z_is_nan, c1); v1 = nan; // (x is +oo) -> if (y is 0) then NaN else inf with y's sign. mk_is_pinf(x, c2); - expr_ref y_sgn_inf(m); + expr_ref y_sgn_inf(m), inf_or(m); mk_ite(y_is_pos, pinf, ninf, y_sgn_inf); - mk_ite(y_is_zero, nan, y_sgn_inf, v2); + m_simp.mk_or(y_is_zero, inf_cond, inf_or); + mk_ite(inf_or, nan, y_sgn_inf, v2); // (y is +oo) -> if (x is 0) then NaN else inf with x's sign. mk_is_pinf(y, c3); expr_ref x_sgn_inf(m); mk_ite(x_is_pos, pinf, ninf, x_sgn_inf); - mk_ite(x_is_zero, nan, x_sgn_inf, v3); + m_simp.mk_or(x_is_zero, inf_cond, inf_or); + mk_ite(inf_or, nan, x_sgn_inf, v3); // (x is -oo) -> if (y is 0) then NaN else inf with -y's sign. mk_is_ninf(x, c4); expr_ref neg_y_sgn_inf(m); mk_ite(y_is_pos, ninf, pinf, neg_y_sgn_inf); - mk_ite(y_is_zero, nan, neg_y_sgn_inf, v4); + m_simp.mk_or(y_is_zero, inf_cond, inf_or); + mk_ite(inf_or, nan, neg_y_sgn_inf, v4); // (y is -oo) -> if (x is 0) then NaN else inf with -x's sign. mk_is_ninf(y, c5); expr_ref neg_x_sgn_inf(m); mk_ite(x_is_pos, ninf, pinf, neg_x_sgn_inf); - mk_ite(x_is_zero, nan, neg_x_sgn_inf, v5); + m_simp.mk_or(x_is_zero, inf_cond, inf_or); + mk_ite(inf_or, nan, neg_x_sgn_inf, v5); + + // z is +-INF -> Z. + mk_is_inf(z, c6); + v6 = z; // (x is 0) || (y is 0) -> x but with sign = x.sign ^ y.sign - m_simp.mk_or(x_is_zero, y_is_zero, c6); + m_simp.mk_or(x_is_zero, y_is_zero, c7); expr_ref sign_xor(m); m_simp.mk_xor(x_is_pos, y_is_pos, sign_xor); - mk_ite(sign_xor, nzero, pzero, v6); + mk_ite(sign_xor, nzero, pzero, v7); + // else comes the fused multiplication. unsigned ebits = m_util.get_ebits(f->get_range()); @@ -1190,54 +1211,57 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar expr_ref c_sgn(m), c_sig(m), c_exp(m), c_lz(m); unpack(x, a_sgn, a_sig, a_exp, a_lz, true); unpack(y, b_sgn, b_sig, b_exp, b_lz, true); - unpack(z, c_sgn, c_sig, c_exp, c_lz, false); + unpack(z, c_sgn, c_sig, c_exp, c_lz, true); - expr_ref a_lz_ext(m), b_lz_ext(m); + expr_ref a_lz_ext(m), b_lz_ext(m), c_lz_ext(m); a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz); + c_lz_ext = m_bv_util.mk_zero_extend(2, c_lz); expr_ref a_sig_ext(m), b_sig_ext(m); a_sig_ext = m_bv_util.mk_zero_extend(sbits, a_sig); b_sig_ext = m_bv_util.mk_zero_extend(sbits, b_sig); - expr_ref a_exp_ext(m), b_exp_ext(m); + expr_ref a_exp_ext(m), b_exp_ext(m), c_exp_ext(m); a_exp_ext = m_bv_util.mk_sign_extend(2, a_exp); b_exp_ext = m_bv_util.mk_sign_extend(2, b_exp); + c_exp_ext = m_bv_util.mk_sign_extend(2, c_exp); expr_ref mul_sgn(m), mul_sig(m), mul_exp(m); expr * signs[2] = { a_sgn, b_sgn }; - mul_sgn = m_bv_util.mk_bv_xor(2, signs); + mul_sgn = m_bv_util.mk_bv_xor(2, signs); dbg_decouple("fpa2bv_fma_mul_sgn", mul_sgn); - mul_exp = m_bv_util.mk_bv_sub( - m_bv_util.mk_bv_add(a_exp_ext, b_exp_ext), - m_bv_util.mk_bv_add(a_lz_ext, b_lz_ext)); + mul_exp = m_bv_util.mk_bv_add(m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext), + m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext)); + dbg_decouple("fpa2bv_fma_mul_exp", mul_exp); mul_sig = m_bv_util.mk_bv_mul(a_sig_ext, b_sig_ext); - dbg_decouple("fpa2bv_fma_mul_sig", mul_sig); SASSERT(m_bv_util.get_bv_size(mul_sig) == 2*sbits); + SASSERT(m_bv_util.get_bv_size(mul_exp) == ebits + 2); - // The result in `product' represents a number of the form 1.*** (unpacked) - // (product = mul_sgn/mul_sig/mul_exp and c_sgn/c_sig/c_exp is unpacked w/o normalization). + // The product has the form [-1][0].[2*sbits - 2]. + + // Extend c + c_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(c_sig, m_bv_util.mk_numeral(0, sbits-1))); - // extend c. - c_sig = m_bv_util.mk_concat(c_sig, m_bv_util.mk_numeral(0, sbits)); - c_exp = m_bv_util.mk_sign_extend(2, c_exp); + SASSERT(m_bv_util.get_bv_size(mul_sig) == 2 * sbits); + SASSERT(m_bv_util.get_bv_size(c_sig) == 2 * sbits); expr_ref swap_cond(m); - swap_cond = m_bv_util.mk_sle(mul_exp, c_exp); + swap_cond = m_bv_util.mk_sle(mul_exp, c_exp_ext); SASSERT(is_well_sorted(m, swap_cond)); expr_ref e_sgn(m), e_sig(m), e_exp(m), f_sgn(m), f_sig(m), f_exp(m); m_simp.mk_ite(swap_cond, c_sgn, mul_sgn, e_sgn); m_simp.mk_ite(swap_cond, c_sig, mul_sig, e_sig); // has 2 * sbits - m_simp.mk_ite(swap_cond, c_exp, mul_exp, e_exp); // has ebits + 2 + m_simp.mk_ite(swap_cond, c_exp_ext, mul_exp, e_exp); // has ebits + 2 m_simp.mk_ite(swap_cond, mul_sgn, c_sgn, f_sgn); m_simp.mk_ite(swap_cond, mul_sig, c_sig, f_sig); // has 2 * sbits - m_simp.mk_ite(swap_cond, mul_exp, c_exp, f_exp); // has ebits + 2 + m_simp.mk_ite(swap_cond, mul_exp, c_exp_ext, f_exp); // has ebits + 2 SASSERT(is_well_sorted(m, e_sgn)); SASSERT(is_well_sorted(m, e_sig)); @@ -1247,26 +1271,94 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar SASSERT(is_well_sorted(m, f_exp)); expr_ref res_sgn(m), res_sig(m), res_exp(m); - add_core(2 * sbits, ebits + 2, rm, - e_sgn, e_sig, e_exp, f_sgn, f_sig, f_exp, - res_sgn, res_sig, res_exp); + + expr_ref exp_delta(m); + exp_delta = m_bv_util.mk_bv_sub(e_exp, f_exp); + dbg_decouple("fpa2bv_fma_add_exp_delta", exp_delta); - // Note: res_sig is now 2 * sbits + 4, i.e., `sbits' too much, which should go into a sticky bit. - unsigned sig_size = m_bv_util.get_bv_size(res_sig); - SASSERT(sig_size == (2*sbits+4)); + // cap the delta + expr_ref cap(m), cap_le_delta(m); + cap = m_bv_util.mk_numeral(sbits+3, ebits+2); + cap_le_delta = m_bv_util.mk_ule(exp_delta, cap); + m_simp.mk_ite(cap_le_delta, cap, exp_delta, exp_delta); + SASSERT(m_bv_util.get_bv_size(exp_delta) == ebits+2); + dbg_decouple("fpa2bv_fma_add_exp_delta_capped", exp_delta); + + // Alignment shift with sticky bit computation. + expr_ref big_f_sig(m); + big_f_sig = m_bv_util.mk_concat(f_sig, m_bv_util.mk_numeral(0, sbits+4)); + SASSERT(is_well_sorted(m, big_f_sig)); - // Note: res_exp is 2 bits too wide. - unsigned exp_size = m_bv_util.get_bv_size(res_exp); - SASSERT(exp_size == ebits+4); - res_exp = m_bv_util.mk_extract(ebits+1, 0, res_exp); + expr_ref shifted_big(m), shifted_f_sig(m), sticky_raw(m); + shifted_big = m_bv_util.mk_bv_lshr(big_f_sig, m_bv_util.mk_concat(m_bv_util.mk_numeral(0, (2*(sbits+4))-(ebits+2)), exp_delta)); + shifted_f_sig = m_bv_util.mk_extract((2*(sbits+4)-1), (sbits+4), shifted_big); + SASSERT(is_well_sorted(m, shifted_f_sig)); - expr_ref sticky(m); - sticky = m.mk_app(m_bv_util.get_fid(), OP_BREDOR, m_bv_util.mk_extract(sbits, 0, res_sig)); - res_sig = m_bv_util.mk_concat(m_bv_util.mk_extract(2*sbits+3, sbits+1, res_sig), sticky); + sticky_raw = m_bv_util.mk_extract(sbits+3, 0, shifted_big); + expr_ref sticky(m), sticky_eq(m), nil_sbit4(m), one_sbit4(m); + nil_sbit4 = m_bv_util.mk_numeral(0, sbits+4); + one_sbit4 = m_bv_util.mk_numeral(1, sbits+4); + m_simp.mk_eq(sticky_raw, nil_sbit4, sticky_eq); + m_simp.mk_ite(sticky_eq, nil_sbit4, one_sbit4, sticky); + SASSERT(is_well_sorted(m, sticky)); + + expr * or_args[2] = { shifted_f_sig, sticky }; + shifted_f_sig = m_bv_util.mk_bv_or(2, or_args); + SASSERT(is_well_sorted(m, shifted_f_sig)); - sig_size = m_bv_util.get_bv_size(res_sig); - SASSERT(sig_size == sbits+4); + expr_ref eq_sgn(m); + m_simp.mk_eq(e_sgn, f_sgn, eq_sgn); + + // two extra bits for catching the overflow. + e_sig = m_bv_util.mk_zero_extend(2, e_sig); + shifted_f_sig = m_bv_util.mk_zero_extend(2, shifted_f_sig); + SASSERT(m_bv_util.get_bv_size(e_sig) == sbits+6); + SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == sbits+6); + + dbg_decouple("fpa2bv_fma_add_e_sig", e_sig); + dbg_decouple("fpa2bv_fma_add_shifted_f_sig", shifted_f_sig); + + expr_ref sum(m); + m_simp.mk_ite(eq_sgn, + m_bv_util.mk_bv_add(e_sig, shifted_f_sig), // ADD LZ + m_bv_util.mk_bv_sub(e_sig, shifted_f_sig), + sum); + + SASSERT(is_well_sorted(m, sum)); + + dbg_decouple("fpa2bv_fma_add_sum", sum); + + expr_ref sign_bv(m), n_sum(m); + sign_bv = m_bv_util.mk_extract(sbits+4, sbits+4, sum); + n_sum = m_bv_util.mk_bv_neg(sum); + + dbg_decouple("fpa2bv_fma_add_sign_bv", sign_bv); + dbg_decouple("fpa2bv_fma_add_n_sum", n_sum); + + family_id bvfid = m_bv_util.get_fid(); + + expr_ref res_sgn_c1(m), res_sgn_c2(m), res_sgn_c3(m); + expr_ref not_e_sgn(m), not_f_sgn(m), not_sign_bv(m); + not_e_sgn = m_bv_util.mk_bv_not(e_sgn); + not_f_sgn = m_bv_util.mk_bv_not(f_sgn); + not_sign_bv = m_bv_util.mk_bv_not(sign_bv); + res_sgn_c1 = m.mk_app(bvfid, OP_BAND, not_e_sgn, e_sgn, sign_bv); + res_sgn_c2 = m.mk_app(bvfid, OP_BAND, e_sgn, not_f_sgn, not_sign_bv); + res_sgn_c3 = m.mk_app(bvfid, OP_BAND, e_sgn, f_sgn); + expr * res_sgn_or_args[3] = { res_sgn_c1, res_sgn_c2, res_sgn_c3 }; + res_sgn = m_bv_util.mk_bv_or(3, res_sgn_or_args); + + expr_ref res_sig_eq(m), sig_abs(m), one_1(m); + one_1 = m_bv_util.mk_numeral(1, 1); + m_simp.mk_eq(sign_bv, one_1, res_sig_eq); + m_simp.mk_ite(res_sig_eq, n_sum, sum, sig_abs); + + dbg_decouple("fpa2bv_fma_add_sig_abs", sig_abs); + + res_sig = m_bv_util.mk_extract(sbits+3, 0, sig_abs); + res_exp = m_bv_util.mk_bv_sub(e_exp, c_lz_ext); + expr_ref is_zero_sig(m), nil_sbits4(m); nil_sbits4 = m_bv_util.mk_numeral(0, sbits+4); m_simp.mk_eq(res_sig, nil_sbits4, is_zero_sig); @@ -1281,10 +1373,11 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar expr_ref rounded(m); round(f->get_range(), rm, res_sgn, res_sig, res_exp, rounded); - mk_ite(is_zero_sig, zero_case, rounded, v7); + mk_ite(is_zero_sig, zero_case, rounded, v8); // And finally, we tie them together. - mk_ite(c6, v6, v7, result); + mk_ite(c7, v7, v8, result); + mk_ite(c6, v6, result, result); mk_ite(c5, v5, result, result); mk_ite(c4, v4, result, result); mk_ite(c3, v3, result, result); @@ -1293,7 +1386,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar SASSERT(is_well_sorted(m, result)); - TRACE("fpa2bv_mul", tout << "MUL = " << mk_ismt2_pp(result, m) << std::endl; ); + TRACE("fpa2bv_fma_", tout << "FMA = " << mk_ismt2_pp(result, m) << std::endl; ); } void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -2571,9 +2664,13 @@ void fpa2bv_model_converter::convert(model * bv_mdl, model * float_mdl) { sz = bv_mdl->get_num_functions(); for (unsigned i = 0; i < sz; i++) { - func_decl * c = bv_mdl->get_function(i); - if (!seen.contains(c)) - float_mdl->register_decl(c, bv_mdl->get_const_interp(c)); + func_decl * f = bv_mdl->get_function(i); + if (!seen.contains(f)) + { + TRACE("fpa2bv_mc", tout << "Keeping: " << mk_ismt2_pp(f, m) << std::endl; ); + func_interp * val = bv_mdl->get_func_interp(f); + float_mdl->register_decl(f, val); + } } sz = bv_mdl->get_num_uninterpreted_sorts(); diff --git a/src/tactic/fpa/fpa2bv_rewriter.h b/src/tactic/fpa/fpa2bv_rewriter.h index 3398874f5..d8a141b62 100644 --- a/src/tactic/fpa/fpa2bv_rewriter.h +++ b/src/tactic/fpa/fpa2bv_rewriter.h @@ -29,9 +29,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { ast_manager & m_manager; expr_ref_vector m_out; fpa2bv_converter & m_conv; - sort_ref_vector m_bindings; - expr_ref_vector m_mappings; - + sort_ref_vector m_bindings; unsigned long long m_max_memory; unsigned m_max_steps; @@ -42,8 +40,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { m_manager(m), m_out(m), m_conv(c), - m_bindings(m), - m_mappings(m) { + m_bindings(m) { updt_params(p); // We need to make sure that the mananger has the BV plugin loaded. symbol s_bv("bv"); @@ -177,7 +174,6 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { new_bindings.push_back(q->get_decl_sort(i)); SASSERT(new_bindings.size() == q->get_num_decls()); m_bindings.append(new_bindings); - m_mappings.resize(m_bindings.size(), 0); } return true; } @@ -215,8 +211,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(), old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns); result_pr = 0; - m_bindings.shrink(old_sz); - m_mappings.shrink(old_sz); + m_bindings.shrink(old_sz); TRACE("fpa2bv", tout << "reduce_quantifier[" << old_q->get_depth() << "]: " << mk_ismt2_pp(old_q->get_expr(), m()) << std::endl << " new body: " << mk_ismt2_pp(new_body, m()) << std::endl; @@ -243,10 +238,9 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { new_exp); } else - new_exp = m().mk_var(t->get_idx(), s); - m_mappings[inx] = new_exp; + new_exp = m().mk_var(t->get_idx(), s); - result = m_mappings[inx].get(); + result = new_exp; result_pr = 0; TRACE("fpa2bv", tout << "reduce_var: " << mk_ismt2_pp(t, m()) << " -> " << mk_ismt2_pp(result, m()) << std::endl;); return true; From bd064bf5d06145a6638d78f565469f571929248e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 3 Jun 2013 11:46:13 -0700 Subject: [PATCH 167/281] enable UTVPI by default Signed-off-by: Nikolaj Bjorner --- src/muz_qe/fixedpoint_params.pyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index c2d33cb05..d38c3c9b0 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -60,7 +60,7 @@ def_module_params('fixedpoint', ('print_answer', BOOL, False, 'print answer instance(s) to query'), ('print_certificate', BOOL, False, 'print certificate for reachability or non-reachability'), ('print_statistics', BOOL, False, 'print statistics'), - ('use_utvpi', BOOL, False, 'experimental use UTVPI strategy'), + ('use_utvpi', BOOL, True, 'PDR: Enable UTVPI strategy'), ('tab_selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), ('dump_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'), )) From b6d9d8a60127da23318dd776bc186539b1530014 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 4 Jun 2013 12:55:35 -0700 Subject: [PATCH 168/281] fix bugs reported by Nuno Lopes Signed-off-by: Nikolaj Bjorner --- src/muz_qe/qe_lite.cpp | 4 ++++ src/util/bit_vector.cpp | 10 ++++++---- src/util/bit_vector.h | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp index 50c3347ee..f840f19d6 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/muz_qe/qe_lite.cpp @@ -1417,6 +1417,7 @@ namespace fm { fm(ast_manager & _m): m(_m), + m_is_variable(0), m_allocator("fm-elim"), m_util(m), m_bvar2expr(m), @@ -1424,6 +1425,9 @@ namespace fm { m_new_fmls(m), m_inconsistent_core(m) { m_cancel = false; + updt_params(); + m_counter = 0; + m_inconsistent = false; } ~fm() { diff --git a/src/util/bit_vector.cpp b/src/util/bit_vector.cpp index 0d67f1f79..6885b93e8 100644 --- a/src/util/bit_vector.cpp +++ b/src/util/bit_vector.cpp @@ -22,6 +22,8 @@ Revision History: #define DEFAULT_CAPACITY 2 +#define MK_MASK(_num_bits_) ((1U << _num_bits_) - 1) + void bit_vector::expand_to(unsigned new_capacity) { unsigned * new_data = alloc_svect(unsigned, new_capacity); memset(new_data, 0, new_capacity * sizeof(unsigned)); @@ -51,7 +53,7 @@ void bit_vector::resize(unsigned new_size, bool val) { unsigned ewidx = num_words(new_size); unsigned * begin = m_data + bwidx; unsigned pos = m_num_bits % 32; - unsigned mask = (1 << pos) - 1; + unsigned mask = MK_MASK(pos); int cval; if (val) { @@ -128,7 +130,7 @@ bool bit_vector::operator==(bit_vector const & source) const { return false; } unsigned bit_rest = source.m_num_bits % 32; - unsigned mask = (1 << bit_rest) - 1; + unsigned mask = MK_MASK(bit_rest); if (mask == 0) mask = UINT_MAX; return (m_data[i] & mask) == (source.m_data[i] & mask); } @@ -149,7 +151,7 @@ bit_vector & bit_vector::operator|=(bit_vector const & source) { unsigned i = 0; for (i = 0; i < n2 - 1; i++) m_data[i] |= source.m_data[i]; - unsigned mask = (1 << bit_rest) - 1; + unsigned mask = MK_MASK(bit_rest); m_data[i] |= source.m_data[i] & mask; } return *this; @@ -175,7 +177,7 @@ bit_vector & bit_vector::operator&=(bit_vector const & source) { else { for (i = 0; i < n2 - 1; i++) m_data[i] &= source.m_data[i]; - unsigned mask = (1 << bit_rest) - 1; + unsigned mask = MK_MASK(bit_rest); m_data[i] &= (source.m_data[i] & mask); } diff --git a/src/util/bit_vector.h b/src/util/bit_vector.h index cbe7a0618..0ccdeae9e 100644 --- a/src/util/bit_vector.h +++ b/src/util/bit_vector.h @@ -69,6 +69,7 @@ public: m_num_bits(0), m_capacity(num_words(reserve_num_bits)), m_data(alloc_svect(unsigned, m_capacity)) { + memset(m_data, 0, m_capacity * sizeof(unsigned)); } bit_vector(bit_vector const & source): From 110fa0b7fb711418fe2be67f033e8ed70b354972 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Wed, 5 Jun 2013 13:50:22 -0700 Subject: [PATCH 169/281] Fix issue http://z3.codeplex.com/workitem/45 Signed-off-by: Leonardo de Moura --- src/ast/simplifier/bv_simplifier_plugin.cpp | 40 +++++++++++++++---- src/ast/simplifier/poly_simplifier_plugin.cpp | 1 + 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/ast/simplifier/bv_simplifier_plugin.cpp b/src/ast/simplifier/bv_simplifier_plugin.cpp index 3ef55baba..8ee353a76 100644 --- a/src/ast/simplifier/bv_simplifier_plugin.cpp +++ b/src/ast/simplifier/bv_simplifier_plugin.cpp @@ -636,7 +636,31 @@ bool bv_simplifier_plugin::try_mk_extract(unsigned high, unsigned low, expr * ar if (!all_found) { return false; } - result = m_manager.mk_app(m_fid, a->get_decl_kind(), new_args.size(), new_args.c_ptr()); + // We should not use mk_app because it does not guarantee that the result would be in simplified form. + // result = m_manager.mk_app(m_fid, a->get_decl_kind(), new_args.size(), new_args.c_ptr()); + if (is_app_of(a, m_fid, OP_BAND)) + mk_bv_and(new_args.size(), new_args.c_ptr(), result); + else if (is_app_of(a, m_fid, OP_BOR)) + mk_bv_or(new_args.size(), new_args.c_ptr(), result); + else if (is_app_of(a, m_fid, OP_BXOR)) + mk_bv_xor(new_args.size(), new_args.c_ptr(), result); + else if (is_app_of(a, m_fid, OP_BNOR)) + mk_bv_nor(new_args.size(), new_args.c_ptr(), result); + else if (is_app_of(a, m_fid, OP_BNAND)) + mk_bv_nand(new_args.size(), new_args.c_ptr(), result); + else if (is_app_of(a, m_fid, OP_BNOT)) { + SASSERT(new_args.size() == 1); + mk_bv_not(new_args[0], result); + } + else if (is_app_of(a, m_fid, OP_BADD)) + mk_add(new_args.size(), new_args.c_ptr(), result); + else if (is_app_of(a, m_fid, OP_BMUL)) + mk_mul(new_args.size(), new_args.c_ptr(), result); + else if (is_app_of(a, m_fid, OP_BSUB)) + mk_sub(new_args.size(), new_args.c_ptr(), result); + else { + UNREACHABLE(); + } return true; } else if (m_manager.is_ite(a)) { @@ -747,16 +771,16 @@ void bv_simplifier_plugin::mk_bv_eq(expr* a1, expr* a2, expr_ref& result) { expr * arg1 = *it1; expr * arg2 = *it2; TRACE("expr_bv_util", tout << "low1: " << low1 << " low2: " << low2 << "\n"; - ast_ll_pp(tout, m_manager, arg1); - ast_ll_pp(tout, m_manager, arg2);); + tout << mk_pp(arg1, m_manager) << "\n"; + tout << mk_pp(arg2, m_manager) << "\n";); unsigned sz1 = get_bv_size(arg1); unsigned sz2 = get_bv_size(arg2); SASSERT(low1 < sz1 && low2 < sz2); unsigned rsz1 = sz1 - low1; unsigned rsz2 = sz2 - low2; TRACE("expr_bv_util", tout << "rsz1: " << rsz1 << " rsz2: " << rsz2 << "\n"; - ast_ll_pp(tout, m_manager, arg1); ast_ll_pp(tout, m_manager, arg2);); - + tout << mk_pp(arg1, m_manager) << "\n"; + tout << mk_pp(arg2, m_manager) << "\n";); if (rsz1 == rsz2) { mk_extract(sz1 - 1, low1, arg1, lhs); @@ -826,9 +850,9 @@ void bv_simplifier_plugin::mk_eq_core(expr * arg1, expr * arg2, expr_ref & resul } m_bsimp.mk_and(tmps.size(), tmps.c_ptr(), result); TRACE("mk_eq_bb", - ast_ll_pp(tout, m_manager, arg1); - ast_ll_pp(tout, m_manager, arg2); - ast_ll_pp(tout, m_manager, result);); + tout << mk_pp(arg1, m_manager) << "\n"; + tout << mk_pp(arg2, m_manager) << "\n"; + tout << mk_pp(result, m_manager) << "\n";); return; } #endif diff --git a/src/ast/simplifier/poly_simplifier_plugin.cpp b/src/ast/simplifier/poly_simplifier_plugin.cpp index 402b078a8..d64123e7b 100644 --- a/src/ast/simplifier/poly_simplifier_plugin.cpp +++ b/src/ast/simplifier/poly_simplifier_plugin.cpp @@ -285,6 +285,7 @@ bool poly_simplifier_plugin::merge_monomials(bool inv, expr * n1, expr * n2, exp else result = m_manager.mk_app(m_fid, m_MUL, mk_numeral(k1), b); } + TRACE("merge_monomials", tout << mk_pp(n1, m_manager) << "\n" << mk_pp(n2, m_manager) << "\n" << mk_pp(result, m_manager) << "\n";); return true; } From f4f1c63abb4a6fd0df908e376b0ab014bce3d9da Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 6 Jun 2013 13:20:43 -0700 Subject: [PATCH 170/281] Fix issue https://z3.codeplex.com/workitem/38 Signed-off-by: Leonardo de Moura --- src/sat/sat_clause_use_list.h | 20 +++++++++++++++++--- src/sat/sat_simplifier.cpp | 27 +++++++++++++++++---------- src/sat/sat_simplifier.h | 4 ++-- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/sat/sat_clause_use_list.h b/src/sat/sat_clause_use_list.h index ccf4b4a5b..0859439d5 100644 --- a/src/sat/sat_clause_use_list.h +++ b/src/sat/sat_clause_use_list.h @@ -20,6 +20,7 @@ Revision History: #define _SAT_CLAUSE_USE_LIST_H_ #include"sat_types.h" +#include"trace.h" namespace sat { @@ -35,6 +36,7 @@ namespace sat { #endif public: clause_use_list() { + STRACE("clause_use_list_bug", tout << "[cul_created] " << this << "\n";); #ifdef LAZY_USE_LIST m_size = 0; #endif @@ -51,22 +53,33 @@ namespace sat { bool empty() const { return size() == 0; } void insert(clause & c) { - SASSERT(!m_clauses.contains(&c)); SASSERT(!c.was_removed()); + STRACE("clause_use_list_bug", tout << "[cul_insert] " << this << " " << &c << "\n";); + SASSERT(!m_clauses.contains(&c)); + SASSERT(!c.was_removed()); m_clauses.push_back(&c); #ifdef LAZY_USE_LIST m_size++; #endif } + void erase_not_removed(clause & c) { + STRACE("clause_use_list_bug", tout << "[cul_erase_not_removed] " << this << " " << &c << "\n";); #ifdef LAZY_USE_LIST - SASSERT(m_clauses.contains(&c)); SASSERT(!c.was_removed()); m_clauses.erase(&c); m_size--; + SASSERT(m_clauses.contains(&c)); + SASSERT(!c.was_removed()); + m_clauses.erase(&c); + m_size--; #else m_clauses.erase(&c); #endif } + void erase(clause & c) { + STRACE("clause_use_list_bug", tout << "[cul_erase] " << this << " " << &c << "\n";); #ifdef LAZY_USE_LIST - SASSERT(m_clauses.contains(&c)); SASSERT(c.was_removed()); m_size--; + SASSERT(m_clauses.contains(&c)); + SASSERT(c.was_removed()); + m_size--; #else m_clauses.erase(&c); #endif @@ -80,6 +93,7 @@ namespace sat { } bool check_invariant() const; + // iterate & compress class iterator { clause_vector & m_clauses; diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 623c73758..51006b2c9 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -146,8 +146,11 @@ namespace sat { m_need_cleanup = false; m_use_list.init(s.num_vars()); init_visited(); - if (learned) + bool learned_in_use_lists = false; + if (learned) { register_clauses(s.m_learned); + learned_in_use_lists = true; + } register_clauses(s.m_clauses); if (!learned && (m_elim_blocked_clauses || m_elim_blocked_clauses_at == m_num_calls)) @@ -179,7 +182,7 @@ namespace sat { if (!m_need_cleanup) { if (vars_eliminated) { // must remove learned clauses with eliminated variables - cleanup_clauses(s.m_learned, true, true); + cleanup_clauses(s.m_learned, true, true, learned_in_use_lists); } CASSERT("sat_solver", s.check_invariant()); TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); @@ -187,8 +190,8 @@ namespace sat { return; } cleanup_watches(); - cleanup_clauses(s.m_learned, true, vars_eliminated); - cleanup_clauses(s.m_clauses, false, vars_eliminated); + cleanup_clauses(s.m_learned, true, vars_eliminated, learned_in_use_lists); + cleanup_clauses(s.m_clauses, false, vars_eliminated, true); TRACE("after_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); CASSERT("sat_solver", s.check_invariant()); free_memory(); @@ -221,7 +224,7 @@ namespace sat { } } - void simplifier::cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated) { + void simplifier::cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists) { clause_vector::iterator it = cs.begin(); clause_vector::iterator it2 = it; clause_vector::iterator end = cs.end(); @@ -245,7 +248,7 @@ namespace sat { } } - if (cleanup_clause(c)) { + if (cleanup_clause(c, in_use_lists)) { s.del_clause(c); continue; } @@ -516,7 +519,7 @@ namespace sat { Return true if the clause is satisfied */ - bool simplifier::cleanup_clause(clause & c) { + bool simplifier::cleanup_clause(clause & c, bool in_use_list) { bool r = false; unsigned sz = c.size(); unsigned j = 0; @@ -529,7 +532,11 @@ namespace sat { break; case l_false: m_need_cleanup = true; - m_use_list.get(l).erase_not_removed(c); + if (in_use_list && !c.frozen()) { + // Remark: if in_use_list is false, then the given clause was not added to the use lists. + // Remark: frozen clauses are not added to the use lists. + m_use_list.get(l).erase_not_removed(c); + } break; case l_true: r = true; @@ -611,7 +618,7 @@ namespace sat { clause_use_list & occurs = m_use_list.get(l); occurs.erase_not_removed(c); m_sub_counter -= occurs.size()/2; - if (cleanup_clause(c)) { + if (cleanup_clause(c, true /* clause is in the use lists */)) { // clause was satisfied TRACE("elim_lit", tout << "clause was satisfied\n";); remove_clause(c); @@ -805,7 +812,7 @@ namespace sat { m_sub_counter--; TRACE("subsumption", tout << "next: " << c << "\n";); if (s.m_trail.size() > m_last_sub_trail_sz) { - if (cleanup_clause(c)) { + if (cleanup_clause(c, true /* clause is in the use_lists */)) { remove_clause(c); continue; } diff --git a/src/sat/sat_simplifier.h b/src/sat/sat_simplifier.h index 44e2f0dee..96d346598 100644 --- a/src/sat/sat_simplifier.h +++ b/src/sat/sat_simplifier.h @@ -125,7 +125,7 @@ namespace sat { void collect_subsumed0(clause const & c1, clause_vector & out); void back_subsumption0(clause & c1); - bool cleanup_clause(clause & c); + bool cleanup_clause(clause & c, bool in_use_list); bool cleanup_clause(literal_vector & c); void propagate_unit(literal l); void elim_lit(clause & c, literal l); @@ -136,7 +136,7 @@ namespace sat { void subsume(); void cleanup_watches(); - void cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated); + void cleanup_clauses(clause_vector & cs, bool learned, bool vars_eliminated, bool in_use_lists); bool is_external(bool_var v) const; bool was_eliminated(bool_var v) const; From 2b59f2ecc2b0cb7621c8558cd635a2b930b71097 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 6 Jun 2013 18:29:29 -0700 Subject: [PATCH 171/281] Fix issue https://z3.codeplex.com/workitem/37 Signed-off-by: Leonardo de Moura --- src/tactic/core/ctx_simplify_tactic.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tactic/core/ctx_simplify_tactic.cpp b/src/tactic/core/ctx_simplify_tactic.cpp index 2c2afab6f..71f4771a9 100644 --- a/src/tactic/core/ctx_simplify_tactic.cpp +++ b/src/tactic/core/ctx_simplify_tactic.cpp @@ -21,7 +21,7 @@ Notes: #include"goal_num_occurs.h" #include"cooperate.h" #include"ast_ll_pp.h" -#include"ast_smt2_pp.h" +#include"ast_pp.h" struct ctx_simplify_tactic::imp { struct cached_result { @@ -105,6 +105,7 @@ struct ctx_simplify_tactic::imp { } bool shared(expr * t) const { + TRACE("ctx_simplify_tactic_bug", tout << mk_pp(t, m) << "\n";); return t->get_ref_count() > 1 && m_occs.get_num_occs(t) > 1; } @@ -242,12 +243,13 @@ struct ctx_simplify_tactic::imp { } void assert_expr(expr * t, bool sign) { + expr * p = t; if (m.is_not(t)) { t = to_app(t)->get_arg(0); sign = !sign; } bool mk_scope = true; - if (shared(t)) { + if (shared(t) || shared(p)) { push(); mk_scope = false; assert_eq_core(t, sign ? m.mk_false() : m.mk_true()); @@ -457,7 +459,7 @@ struct ctx_simplify_tactic::imp { if (visit.is_marked(s)) { continue; } - visit.mark(s, true); + visit.mark(s, true); ++sz; for (unsigned i = 0; is_app(s) && i < to_app(s)->get_num_args(); ++i) { todo.push_back(to_app(s)->get_arg(i)); From e5c720de29f146f3380b7069b3e102a044f3a295 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 7 Jun 2013 17:36:34 +0100 Subject: [PATCH 172/281] FPA: bugfix for abs Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 4ec17addf..5c18e1241 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -223,7 +223,7 @@ public: app * mk_rem(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_REM, arg1, arg2); } app * mk_max(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_MAX, arg1, arg2); } app * mk_min(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_MIN, arg1, arg2); } - app * mk_abs(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_ABS, arg1, arg2); } + app * mk_abs(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_ABS, arg1); } app * mk_sqrt(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_SQRT, arg1, arg2); } app * mk_round(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_ROUND_TO_INTEGRAL, arg1, arg2); } app * mk_fused_ma(expr * arg1, expr * arg2, expr * arg3, expr * arg4) { From 123d3ec3a765ff57b449526f49808efef3a9f36b Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 7 Jun 2013 17:55:29 +0100 Subject: [PATCH 173/281] New FPA operators added. Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 11 ++++++++++- src/ast/float_decl_plugin.h | 8 +++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 2a090fc39..21d4d6a86 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -255,7 +255,10 @@ func_decl * float_decl_plugin::mk_unary_rel_decl(decl_kind k, unsigned num_param case OP_FLOAT_IS_ZERO: name = "isZero"; break; case OP_FLOAT_IS_NZERO: name = "isNZero"; break; case OP_FLOAT_IS_PZERO: name = "isPZero"; break; - case OP_FLOAT_IS_SIGN_MINUS: name = "isSignMinus"; break; + case OP_FLOAT_IS_SIGN_MINUS: name = "isSignMinus"; break; + case OP_FLOAT_IS_INF: name = "isInfinite"; break; + case OP_FLOAT_IS_NORMAL: name = "isNormal"; break; + case OP_FLOAT_IS_SUBNORMAL: name = "isSubnormal"; break; default: UNREACHABLE(); break; @@ -415,6 +418,9 @@ func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_FLOAT_IS_NZERO: case OP_FLOAT_IS_PZERO: case OP_FLOAT_IS_SIGN_MINUS: + case OP_FLOAT_IS_INF: + case OP_FLOAT_IS_NORMAL: + case OP_FLOAT_IS_SUBNORMAL: return mk_unary_rel_decl(k, num_parameters, parameters, arity, domain, range); case OP_FLOAT_ABS: case OP_FLOAT_UMINUS: @@ -473,9 +479,12 @@ void float_decl_plugin::get_op_names(svector & op_names, symbol co op_names.push_back(builtin_name("<=", OP_FLOAT_LE)); op_names.push_back(builtin_name(">=", OP_FLOAT_GE)); + op_names.push_back(builtin_name("isInfinite", OP_FLOAT_IS_INF)); op_names.push_back(builtin_name("isZero", OP_FLOAT_IS_ZERO)); op_names.push_back(builtin_name("isNZero", OP_FLOAT_IS_NZERO)); op_names.push_back(builtin_name("isPZero", OP_FLOAT_IS_PZERO)); + op_names.push_back(builtin_name("isNormal", OP_FLOAT_IS_NORMAL)); + op_names.push_back(builtin_name("isSubnormal", OP_FLOAT_IS_SUBNORMAL)); op_names.push_back(builtin_name("isSignMinus", OP_FLOAT_IS_SIGN_MINUS)); op_names.push_back(builtin_name("min", OP_FLOAT_MIN)); diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index 5c18e1241..fd632a8a1 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -61,9 +61,12 @@ enum float_op_kind { OP_FLOAT_GT, OP_FLOAT_LE, OP_FLOAT_GE, + OP_FLOAT_IS_INF, OP_FLOAT_IS_ZERO, - OP_FLOAT_IS_NZERO, + OP_FLOAT_IS_NORMAL, + OP_FLOAT_IS_SUBNORMAL, OP_FLOAT_IS_PZERO, + OP_FLOAT_IS_NZERO, OP_FLOAT_IS_SIGN_MINUS, OP_TO_FLOAT, @@ -237,7 +240,10 @@ public: app * mk_le(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_LE, arg1, arg2); } app * mk_ge(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_GE, arg1, arg2); } + app * mk_is_inf(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_INF, arg1); } app * mk_is_zero(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_ZERO, arg1); } + app * mk_is_normal(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_NORMAL, arg1); } + app * mk_is_subnormal(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_SUBNORMAL, arg1); } app * mk_is_nzero(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_NZERO, arg1); } app * mk_is_pzero(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_PZERO, arg1); } app * mk_is_sign_minus(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_SIGN_MINUS, arg1); } From d7639557d2867e8cade627237fc686ff76e59580 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 7 Jun 2013 18:03:46 +0100 Subject: [PATCH 174/281] FPA: added rewriting and fpa2bv conversion rules for new operations. Signed-off-by: Christoph M. Wintersteiger --- src/ast/rewriter/float_rewriter.cpp | 33 +++++++++++++++++++++++++++++ src/ast/rewriter/float_rewriter.h | 3 +++ src/tactic/fpa/fpa2bv_converter.cpp | 15 +++++++++++++ src/tactic/fpa/fpa2bv_converter.h | 3 +++ src/tactic/fpa/fpa2bv_rewriter.h | 3 +++ 5 files changed, 57 insertions(+) diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index b43f07b65..bfcfbcbfc 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -58,6 +58,9 @@ br_status float_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c case OP_FLOAT_IS_ZERO: SASSERT(num_args == 1); st = mk_is_zero(args[0], result); break; case OP_FLOAT_IS_NZERO: SASSERT(num_args == 1); st = mk_is_nzero(args[0], result); break; case OP_FLOAT_IS_PZERO: SASSERT(num_args == 1); st = mk_is_pzero(args[0], result); break; + case OP_FLOAT_IS_INF: SASSERT(num_args == 1); st = mk_is_inf(args[0], result); break; + case OP_FLOAT_IS_NORMAL: SASSERT(num_args == 1); st = mk_is_normal(args[0], result); break; + case OP_FLOAT_IS_SUBNORMAL: SASSERT(num_args == 1); st = mk_is_subnormal(args[0], result); break; case OP_FLOAT_IS_SIGN_MINUS: SASSERT(num_args == 1); st = mk_is_sign_minus(args[0], result); break; case OP_TO_IEEE_BV: SASSERT(num_args == 1); st = mk_to_ieee_bv(args[0], result); break; } @@ -428,6 +431,36 @@ br_status float_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) { return BR_FAILED; } +br_status float_rewriter::mk_is_inf(expr * arg1, expr_ref & result) { + scoped_mpf v(m_util.fm()); + if (m_util.is_value(arg1, v)) { + result = (m_util.fm().is_inf(v)) ? m().mk_true() : m().mk_false(); + return BR_DONE; + } + + return BR_FAILED; +} + +br_status float_rewriter::mk_is_normal(expr * arg1, expr_ref & result) { + scoped_mpf v(m_util.fm()); + if (m_util.is_value(arg1, v)) { + result = (m_util.fm().is_normal(v)) ? m().mk_true() : m().mk_false(); + return BR_DONE; + } + + return BR_FAILED; +} + +br_status float_rewriter::mk_is_subnormal(expr * arg1, expr_ref & result) { + scoped_mpf v(m_util.fm()); + if (m_util.is_value(arg1, v)) { + result = (m_util.fm().is_denormal(v)) ? m().mk_true() : m().mk_false(); + return BR_DONE; + } + + return BR_FAILED; +} + br_status float_rewriter::mk_is_sign_minus(expr * arg1, expr_ref & result) { scoped_mpf v(m_util.fm()); if (m_util.is_value(arg1, v)) { diff --git a/src/ast/rewriter/float_rewriter.h b/src/ast/rewriter/float_rewriter.h index 7c86a5bc3..6968d96cf 100644 --- a/src/ast/rewriter/float_rewriter.h +++ b/src/ast/rewriter/float_rewriter.h @@ -66,6 +66,9 @@ public: br_status mk_is_zero(expr * arg1, expr_ref & result); br_status mk_is_nzero(expr * arg1, expr_ref & result); br_status mk_is_pzero(expr * arg1, expr_ref & result); + br_status mk_is_inf(expr * arg1, expr_ref & result); + br_status mk_is_normal(expr * arg1, expr_ref & result); + br_status mk_is_subnormal(expr * arg1, expr_ref & result); br_status mk_is_sign_minus(expr * arg1, expr_ref & result); br_status mk_to_ieee_bv(expr * arg1, expr_ref & result); diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 02aff67c6..d95709813 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1621,6 +1621,21 @@ void fpa2bv_converter::mk_is_pzero(func_decl * f, unsigned num, expr * const * a m_simp.mk_and(a0_is_pos, a0_is_zero, result); } +void fpa2bv_converter::mk_is_inf(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 1); + mk_is_inf(args[0], result); +} + +void fpa2bv_converter::mk_is_normal(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 1); + mk_is_normal(args[0], result); +} + +void fpa2bv_converter::mk_is_subnormal(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 1); + mk_is_denormal(args[0], result); +} + void fpa2bv_converter::mk_is_sign_minus(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 1); mk_is_neg(args[0], result); diff --git a/src/tactic/fpa/fpa2bv_converter.h b/src/tactic/fpa/fpa2bv_converter.h index 2a68342f8..9f9c74c38 100644 --- a/src/tactic/fpa/fpa2bv_converter.h +++ b/src/tactic/fpa/fpa2bv_converter.h @@ -116,6 +116,9 @@ public: void mk_is_nzero(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_is_pzero(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_is_sign_minus(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_is_inf(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_is_normal(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_is_subnormal(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_float(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result); diff --git a/src/tactic/fpa/fpa2bv_rewriter.h b/src/tactic/fpa/fpa2bv_rewriter.h index d8a141b62..59d068626 100644 --- a/src/tactic/fpa/fpa2bv_rewriter.h +++ b/src/tactic/fpa/fpa2bv_rewriter.h @@ -132,6 +132,9 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { case OP_FLOAT_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE; case OP_FLOAT_IS_NZERO: m_conv.mk_is_nzero(f, num, args, result); return BR_DONE; case OP_FLOAT_IS_PZERO: m_conv.mk_is_pzero(f, num, args, result); return BR_DONE; + case OP_FLOAT_IS_INF: m_conv.mk_is_inf(f, num, args, result); return BR_DONE; + case OP_FLOAT_IS_NORMAL: m_conv.mk_is_normal(f, num, args, result); return BR_DONE; + case OP_FLOAT_IS_SUBNORMAL: m_conv.mk_is_subnormal(f, num, args, result); return BR_DONE; case OP_FLOAT_IS_SIGN_MINUS: m_conv.mk_is_sign_minus(f, num, args, result); return BR_DONE; case OP_TO_FLOAT: m_conv.mk_to_float(f, num, args, result); return BR_DONE; case OP_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE; From 455618bb2b1564eb026b0984c2fe022150efcf02 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 7 Jun 2013 18:34:31 +0100 Subject: [PATCH 175/281] FPA: added is_nan Signed-off-by: Christoph M. Wintersteiger --- src/ast/float_decl_plugin.cpp | 3 +++ src/ast/float_decl_plugin.h | 2 ++ src/ast/rewriter/float_rewriter.cpp | 11 +++++++++++ src/ast/rewriter/float_rewriter.h | 1 + src/tactic/fpa/fpa2bv_converter.cpp | 5 +++++ src/tactic/fpa/fpa2bv_converter.h | 1 + src/tactic/fpa/fpa2bv_rewriter.h | 1 + 7 files changed, 24 insertions(+) diff --git a/src/ast/float_decl_plugin.cpp b/src/ast/float_decl_plugin.cpp index 21d4d6a86..4aab6ab32 100644 --- a/src/ast/float_decl_plugin.cpp +++ b/src/ast/float_decl_plugin.cpp @@ -256,6 +256,7 @@ func_decl * float_decl_plugin::mk_unary_rel_decl(decl_kind k, unsigned num_param case OP_FLOAT_IS_NZERO: name = "isNZero"; break; case OP_FLOAT_IS_PZERO: name = "isPZero"; break; case OP_FLOAT_IS_SIGN_MINUS: name = "isSignMinus"; break; + case OP_FLOAT_IS_NAN: name = "isNaN"; break; case OP_FLOAT_IS_INF: name = "isInfinite"; break; case OP_FLOAT_IS_NORMAL: name = "isNormal"; break; case OP_FLOAT_IS_SUBNORMAL: name = "isSubnormal"; break; @@ -418,6 +419,7 @@ func_decl * float_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_FLOAT_IS_NZERO: case OP_FLOAT_IS_PZERO: case OP_FLOAT_IS_SIGN_MINUS: + case OP_FLOAT_IS_NAN: case OP_FLOAT_IS_INF: case OP_FLOAT_IS_NORMAL: case OP_FLOAT_IS_SUBNORMAL: @@ -479,6 +481,7 @@ void float_decl_plugin::get_op_names(svector & op_names, symbol co op_names.push_back(builtin_name("<=", OP_FLOAT_LE)); op_names.push_back(builtin_name(">=", OP_FLOAT_GE)); + op_names.push_back(builtin_name("isNaN", OP_FLOAT_IS_NAN)); op_names.push_back(builtin_name("isInfinite", OP_FLOAT_IS_INF)); op_names.push_back(builtin_name("isZero", OP_FLOAT_IS_ZERO)); op_names.push_back(builtin_name("isNZero", OP_FLOAT_IS_NZERO)); diff --git a/src/ast/float_decl_plugin.h b/src/ast/float_decl_plugin.h index fd632a8a1..f1b60a91b 100644 --- a/src/ast/float_decl_plugin.h +++ b/src/ast/float_decl_plugin.h @@ -61,6 +61,7 @@ enum float_op_kind { OP_FLOAT_GT, OP_FLOAT_LE, OP_FLOAT_GE, + OP_FLOAT_IS_NAN, OP_FLOAT_IS_INF, OP_FLOAT_IS_ZERO, OP_FLOAT_IS_NORMAL, @@ -240,6 +241,7 @@ public: app * mk_le(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_LE, arg1, arg2); } app * mk_ge(expr * arg1, expr * arg2) { return m().mk_app(m_fid, OP_FLOAT_GE, arg1, arg2); } + app * mk_is_nan(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_NAN, arg1); } app * mk_is_inf(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_INF, arg1); } app * mk_is_zero(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_ZERO, arg1); } app * mk_is_normal(expr * arg1) { return m().mk_app(m_fid, OP_FLOAT_IS_NORMAL, arg1); } diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index bfcfbcbfc..015bce0ed 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -58,6 +58,7 @@ br_status float_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c case OP_FLOAT_IS_ZERO: SASSERT(num_args == 1); st = mk_is_zero(args[0], result); break; case OP_FLOAT_IS_NZERO: SASSERT(num_args == 1); st = mk_is_nzero(args[0], result); break; case OP_FLOAT_IS_PZERO: SASSERT(num_args == 1); st = mk_is_pzero(args[0], result); break; + case OP_FLOAT_IS_NAN: SASSERT(num_args == 1); st = mk_is_nan(args[0], result); break; case OP_FLOAT_IS_INF: SASSERT(num_args == 1); st = mk_is_inf(args[0], result); break; case OP_FLOAT_IS_NORMAL: SASSERT(num_args == 1); st = mk_is_normal(args[0], result); break; case OP_FLOAT_IS_SUBNORMAL: SASSERT(num_args == 1); st = mk_is_subnormal(args[0], result); break; @@ -431,6 +432,16 @@ br_status float_rewriter::mk_is_pzero(expr * arg1, expr_ref & result) { return BR_FAILED; } +br_status float_rewriter::mk_is_nan(expr * arg1, expr_ref & result) { + scoped_mpf v(m_util.fm()); + if (m_util.is_value(arg1, v)) { + result = (m_util.fm().is_nan(v)) ? m().mk_true() : m().mk_false(); + return BR_DONE; + } + + return BR_FAILED; +} + br_status float_rewriter::mk_is_inf(expr * arg1, expr_ref & result) { scoped_mpf v(m_util.fm()); if (m_util.is_value(arg1, v)) { diff --git a/src/ast/rewriter/float_rewriter.h b/src/ast/rewriter/float_rewriter.h index 6968d96cf..4a0879d4b 100644 --- a/src/ast/rewriter/float_rewriter.h +++ b/src/ast/rewriter/float_rewriter.h @@ -66,6 +66,7 @@ public: br_status mk_is_zero(expr * arg1, expr_ref & result); br_status mk_is_nzero(expr * arg1, expr_ref & result); br_status mk_is_pzero(expr * arg1, expr_ref & result); + br_status mk_is_nan(expr * arg1, expr_ref & result); br_status mk_is_inf(expr * arg1, expr_ref & result); br_status mk_is_normal(expr * arg1, expr_ref & result); br_status mk_is_subnormal(expr * arg1, expr_ref & result); diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index d95709813..dd40e8453 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1621,6 +1621,11 @@ void fpa2bv_converter::mk_is_pzero(func_decl * f, unsigned num, expr * const * a m_simp.mk_and(a0_is_pos, a0_is_zero, result); } +void fpa2bv_converter::mk_is_nan(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { + SASSERT(num == 1); + mk_is_nan(args[0], result); +} + void fpa2bv_converter::mk_is_inf(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { SASSERT(num == 1); mk_is_inf(args[0], result); diff --git a/src/tactic/fpa/fpa2bv_converter.h b/src/tactic/fpa/fpa2bv_converter.h index 9f9c74c38..821618bae 100644 --- a/src/tactic/fpa/fpa2bv_converter.h +++ b/src/tactic/fpa/fpa2bv_converter.h @@ -116,6 +116,7 @@ public: void mk_is_nzero(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_is_pzero(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_is_sign_minus(func_decl * f, unsigned num, expr * const * args, expr_ref & result); + void mk_is_nan(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_is_inf(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_is_normal(func_decl * f, unsigned num, expr * const * args, expr_ref & result); void mk_is_subnormal(func_decl * f, unsigned num, expr * const * args, expr_ref & result); diff --git a/src/tactic/fpa/fpa2bv_rewriter.h b/src/tactic/fpa/fpa2bv_rewriter.h index 59d068626..24e275c0d 100644 --- a/src/tactic/fpa/fpa2bv_rewriter.h +++ b/src/tactic/fpa/fpa2bv_rewriter.h @@ -132,6 +132,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { case OP_FLOAT_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE; case OP_FLOAT_IS_NZERO: m_conv.mk_is_nzero(f, num, args, result); return BR_DONE; case OP_FLOAT_IS_PZERO: m_conv.mk_is_pzero(f, num, args, result); return BR_DONE; + case OP_FLOAT_IS_NAN: m_conv.mk_is_nan(f, num, args, result); return BR_DONE; case OP_FLOAT_IS_INF: m_conv.mk_is_inf(f, num, args, result); return BR_DONE; case OP_FLOAT_IS_NORMAL: m_conv.mk_is_normal(f, num, args, result); return BR_DONE; case OP_FLOAT_IS_SUBNORMAL: m_conv.mk_is_subnormal(f, num, args, result); return BR_DONE; From 0210156bf0c59844a65aacb4957ce49cd65e3761 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 10 Jun 2013 10:51:56 -0400 Subject: [PATCH 176/281] add convex interior generalizer Signed-off-by: Nikolaj Bjorner --- src/muz_qe/fixedpoint_params.pyg | 1 + src/muz_qe/pdr_context.cpp | 3 + src/muz_qe/pdr_generalizers.cpp | 171 +++++++++++++++++++++++++++++++ src/muz_qe/pdr_generalizers.h | 17 +++ 4 files changed, 192 insertions(+) diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index d38c3c9b0..c2996dd8f 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -48,6 +48,7 @@ def_module_params('fixedpoint', ('use_multicore_generalizer', BOOL, False, "PDR: extract multiple cores for blocking states"), ('use_inductive_generalizer', BOOL, True, "PDR: generalize lemmas using induction strengthening"), ('use_arith_inductive_generalizer', BOOL, False, "PDR: generalize lemmas using arithmetic heuristics for induction strengthening"), + ('use_convex_hull_generalizer', BOOL, False, "PDR: generalize using convex hulls of lemmas"), ('cache_mode', UINT, 0, "PDR: use no (0), symbolic (1) or explicit cache (2) for model search"), ('inductive_reachability_check', BOOL, False, "PDR: assume negation of the cube on the previous level when " "checking for reachability (not only during cube weakening)"), diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 76f744325..1c49e0c83 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1572,6 +1572,9 @@ namespace pdr { } } + if (m_params.use_convex_hull_generalizer()) { + m_core_generalizers.push_back(alloc(core_convex_hull_generalizer, *this)); + } if (!use_mc && m_params.use_inductive_generalizer()) { m_core_generalizers.push_back(alloc(core_bool_inductive_generalizer, *this, 0)); } diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index 1b8ea22f9..800a21eaf 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -147,6 +147,177 @@ namespace pdr { } + core_convex_hull_generalizer::core_convex_hull_generalizer(context& ctx): + core_generalizer(ctx), + m(ctx.get_manager()), + a(m), + m_sigma(m), + m_trail(m) { + m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); + m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); + } + + void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { + manager& pm = n.pt().get_pdr_manager(); + expr_ref_vector conv1(m), conv2(m), core1(m), core2(m), eqs(m); + if (core.empty()) { + return; + } + if (!m_left.contains(n.pt().head())) { + expr_ref left(m), right(m); + m_left.insert(n.pt().head(), 0); + unsigned sz = n.pt().sig_size(); + for (unsigned i = 0; i < sz; ++i) { + func_decl* fn0 = n.pt().sig(i); + sort* srt = fn0->get_range(); + if (a.is_int_real(srt)) { + func_decl* fn1 = pm.o2n(fn0, 0); + left = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); + right = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); + m_left.insert(fn1, left); + m_right.insert(fn1, right); + m_trail.push_back(left); + m_trail.push_back(right); + } + } + } + unsigned sz = n.pt().sig_size(); + for (unsigned i = 0; i < sz; ++i) { + expr* left, *right; + func_decl* fn0 = n.pt().sig(i); + func_decl* fn1 = pm.o2n(fn0, 0); + if (m_left.find(fn1, left) && m_right.find(fn1, right)) { + eqs.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(left, right))); + } + } + if (!mk_convex(core, 0, conv1)) { + IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core), m) << "\n";); + return; + } + conv1.append(eqs); + conv1.push_back(a.mk_gt(m_sigma[0].get(), a.mk_numeral(rational(0), a.mk_real()))); + conv1.push_back(a.mk_gt(m_sigma[1].get(), a.mk_numeral(rational(0), a.mk_real()))); + conv1.push_back(m.mk_eq(a.mk_numeral(rational(1), a.mk_real()), a.mk_add(m_sigma[0].get(), m_sigma[1].get()))); + expr_ref fml = n.pt().get_formulas(n.level(), false); + expr_ref_vector fmls(m); + datalog::flatten_and(fml, fmls); + for (unsigned i = 0; i < fmls.size(); ++i) { + fml = m.mk_not(fmls[i].get()); + core2.reset(); + datalog::flatten_and(fml, core2); + if (!mk_convex(core2, 1, conv2)) { + IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core2), m) << "\n";); + continue; + } + conv2.append(conv1); + expr_ref state = pm.mk_and(conv2); + TRACE("pdr", tout << "Check:\n" << mk_pp(state, m) << "\n"; + tout << "New formula:\n" << mk_pp(pm.mk_and(core), m) << "\n"; + tout << "Old formula:\n" << mk_pp(fml, m) << "\n"; + + ); + model_node nd(0, state, n.pt(), n.level()); + if (l_false == n.pt().is_reachable(nd, &conv2, uses_level)) { + TRACE("pdr", + tout << mk_pp(state, m) << "\n"; + tout << "Generalized to:\n" << mk_pp(pm.mk_and(conv2), m) << "\n";); + IF_VERBOSE(0, + verbose_stream() << mk_pp(state, m) << "\n"; + verbose_stream() << "Generalized to:\n" << mk_pp(pm.mk_and(conv2), m) << "\n";); + core.reset(); + core.append(conv2); + } + } + } + + bool core_convex_hull_generalizer::mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv) { + conv.reset(); + for (unsigned i = 0; i < core.size(); ++i) { + mk_convex(core[i], index, conv); + } + return !conv.empty(); + } + + void core_convex_hull_generalizer::mk_convex(expr* fml, unsigned index, expr_ref_vector& conv) { + expr_ref result(m), r1(m), r2(m); + expr* e1, *e2; + bool is_not = m.is_not(fml, fml); + if (a.is_le(fml, e1, e2) && mk_convex(e1, index, false, r1) && mk_convex(e2, index, false, r2)) { + result = a.mk_le(r1, r2); + } + else if (a.is_ge(fml, e1, e2) && mk_convex(e1, index, false, r1) && mk_convex(e2, index, false, r2)) { + result = a.mk_ge(r1, r2); + } + else if (a.is_gt(fml, e1, e2) && mk_convex(e1, index, false, r1) && mk_convex(e2, index, false, r2)) { + result = a.mk_gt(r1, r2); + } + else if (a.is_lt(fml, e1, e2) && mk_convex(e1, index, false, r1) && mk_convex(e2, index, false, r2)) { + result = a.mk_lt(r1, r2); + } + else if (m.is_eq(fml, e1, e2) && a.is_int_real(e1) && mk_convex(e1, index, false, r1) && mk_convex(e2, index, false, r2)) { + result = m.mk_eq(r1, r2); + } + else { + TRACE("pdr", tout << "Did not handle " << mk_pp(fml, m) << "\n";); + return; + } + if (is_not) { + result = m.mk_not(result); + } + conv.push_back(result); + } + + + bool core_convex_hull_generalizer::translate(func_decl* f, unsigned index, expr_ref& result) { + expr* tmp; + if (index == 0 && m_left.find(f, tmp)) { + result = tmp; + return true; + } + if (index == 1 && m_right.find(f, tmp)) { + result = tmp; + return true; + } + return false; + } + + + bool core_convex_hull_generalizer::mk_convex(expr* term, unsigned index, bool is_mul, expr_ref& result) { + if (!is_app(term)) { + return false; + } + app* app = to_app(term); + expr* e1, *e2; + expr_ref r1(m), r2(m); + if (translate(app->get_decl(), index, result)) { + return true; + } + if (a.is_add(term, e1, e2) && mk_convex(e1, index, is_mul, r1) && mk_convex(e2, index, is_mul, r2)) { + result = a.mk_add(r1, r2); + return true; + } + if (a.is_sub(term, e1, e2) && mk_convex(e1, index, is_mul, r1) && mk_convex(e2, index, is_mul, r2)) { + result = a.mk_sub(r1, r2); + return true; + } + if (a.is_mul(term, e1, e2) && mk_convex(e1, index, true, r1) && mk_convex(e2, index, true, r2)) { + result = a.mk_mul(r1, r2); + return true; + } + if (a.is_numeral(term)) { + if (is_mul) { + result = term; + } + else { + result = a.mk_mul(m_sigma[index].get(), term); + } + return true; + } + IF_VERBOSE(0, verbose_stream() << "Not handled: " << mk_pp(term, m) << "\n";); + return false; + } + + // --------------------------------- // core_arith_inductive_generalizer // NB. this is trying out some ideas for generalization in diff --git a/src/muz_qe/pdr_generalizers.h b/src/muz_qe/pdr_generalizers.h index 03bd89c4d..a4be9d1fa 100644 --- a/src/muz_qe/pdr_generalizers.h +++ b/src/muz_qe/pdr_generalizers.h @@ -73,6 +73,23 @@ namespace pdr { virtual void collect_statistics(statistics& st) const; }; + class core_convex_hull_generalizer : public core_generalizer { + ast_manager& m; + arith_util a; + expr_ref_vector m_sigma; + expr_ref_vector m_trail; + obj_map m_left; + obj_map m_right; + bool mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv); + void mk_convex(expr* fml, unsigned index, expr_ref_vector& conv); + bool mk_convex(expr* term, unsigned index, bool is_mul, expr_ref& result); + bool translate(func_decl* fn, unsigned index, expr_ref& result); + public: + core_convex_hull_generalizer(context& ctx); + virtual ~core_convex_hull_generalizer() {} + virtual void operator()(model_node& n, expr_ref_vector& core, bool& uses_level); + }; + class core_multi_generalizer : public core_generalizer { core_bool_inductive_generalizer m_gen; public: From 6184c5fdbcad3ad666f8220cdebcae4601b03bd1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 11 Jun 2013 15:29:22 -0400 Subject: [PATCH 177/281] reorder attibutes to match initialization order Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_instruction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz_qe/dl_instruction.cpp b/src/muz_qe/dl_instruction.cpp index 6b16968c2..637d9a17f 100644 --- a/src/muz_qe/dl_instruction.cpp +++ b/src/muz_qe/dl_instruction.cpp @@ -528,9 +528,9 @@ namespace datalog { class instr_filter_interpreted_and_project : public instruction { reg_idx m_src; - reg_idx m_res; app_ref m_cond; unsigned_vector m_cols; + reg_idx m_res; public: instr_filter_interpreted_and_project(reg_idx src, app_ref & condition, unsigned col_cnt, const unsigned * removed_cols, reg_idx result) From 2c8b314a15ba1bfc79e508b0266df1405782656b Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 13 Jun 2013 13:34:20 -0700 Subject: [PATCH 178/281] Fix issue https://z3.codeplex.com/workitem/48 Signed-off-by: Leonardo de Moura --- src/sat/sat_simplifier.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index 623c73758..47c4b6150 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -625,7 +625,8 @@ namespace sat { case 1: TRACE("elim_lit", tout << "clause became unit: " << c[0] << "\n";); propagate_unit(c[0]); - remove_clause(c); + // propagate_unit will delete c. + // remove_clause(c); return; case 2: TRACE("elim_lit", tout << "clause became binary: " << c[0] << " " << c[1] << "\n";); @@ -816,7 +817,8 @@ namespace sat { } if (sz == 1) { propagate_unit(c[0]); - remove_clause(c); + // propagate_unit will delete c. + // remove_clause(c); continue; } if (sz == 2) { From 40b1137b30da4914c233001a704928662567f60d Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 13 Jun 2013 13:45:14 -0700 Subject: [PATCH 179/281] Fix issue https://z3.codeplex.com/workitem/47 Signed-off-by: Leonardo de Moura --- src/sat/sat_asymm_branch.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 81d631e4e..b8ac520b2 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -72,11 +72,14 @@ namespace sat { int limit = -static_cast(m_asymm_branch_limit); std::stable_sort(s.m_clauses.begin(), s.m_clauses.end(), clause_size_lt()); m_counter -= s.m_clauses.size(); + SASSERT(s.m_qhead == s.m_trail.size()); clause_vector::iterator it = s.m_clauses.begin(); clause_vector::iterator it2 = it; clause_vector::iterator end = s.m_clauses.end(); try { for (; it != end; ++it) { + if (s.inconsistent()) + break; SASSERT(s.m_qhead == s.m_trail.size()); if (m_counter < limit || s.inconsistent()) { *it2 = *it; @@ -111,6 +114,7 @@ namespace sat { bool asymm_branch::process(clause & c) { TRACE("asymm_branch_detail", tout << "processing: " << c << "\n";); SASSERT(s.scope_lvl() == 0); + SASSERT(s.m_qhead == s.m_trail.size()); #ifdef Z3DEBUG unsigned trail_sz = s.m_trail.size(); #endif @@ -143,6 +147,7 @@ namespace sat { SASSERT(!s.inconsistent()); SASSERT(s.scope_lvl() == 0); SASSERT(trail_sz == s.m_trail.size()); + SASSERT(s.m_qhead == s.m_trail.size()); if (i == sz - 1) { // clause size can't be reduced. s.attach_clause(c); @@ -181,15 +186,18 @@ namespace sat { s.assign(c[0], justification()); s.del_clause(c); s.propagate_core(false); + SASSERT(s.inconsistent() || s.m_qhead == s.m_trail.size()); return false; // check_missed_propagation() may fail, since m_clauses is not in a consistent state. case 2: SASSERT(s.value(c[0]) == l_undef && s.value(c[1]) == l_undef); s.mk_bin_clause(c[0], c[1], false); s.del_clause(c); + SASSERT(s.m_qhead == s.m_trail.size()); return false; default: c.shrink(new_sz); s.attach_clause(c); + SASSERT(s.m_qhead == s.m_trail.size()); return true; } } From 1a26c9726bafca21cdba95f7a9f709ec087f43a0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 14 Jun 2013 13:15:48 +0100 Subject: [PATCH 180/281] .NET API: bugfix Signed-off-by: Christoph M. Wintersteiger --- src/api/dotnet/Solver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/dotnet/Solver.cs b/src/api/dotnet/Solver.cs index 274f8dc4a..555a2466f 100644 --- a/src/api/dotnet/Solver.cs +++ b/src/api/dotnet/Solver.cs @@ -210,7 +210,7 @@ namespace Microsoft.Z3 public Status Check(params Expr[] assumptions) { Z3_lbool r; - if (assumptions == null) + if (assumptions == null || assumptions.Length == 0) r = (Z3_lbool)Native.Z3_solver_check(Context.nCtx, NativeObject); else r = (Z3_lbool)Native.Z3_solver_check_assumptions(Context.nCtx, NativeObject, (uint)assumptions.Length, AST.ArrayToNative(assumptions)); From 76c59cb85c0637c32989f40a85c8c5364afb3e8f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 14 Jun 2013 17:22:25 +0100 Subject: [PATCH 181/281] MPF conversion bugfix. Signed-off-by: Christoph M. Wintersteiger --- src/ast/rewriter/float_rewriter.cpp | 12 ++++++++---- src/util/mpf.cpp | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 015bce0ed..367fa3a4c 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -83,17 +83,21 @@ br_status float_rewriter::mk_to_float(func_decl * f, unsigned num_args, expr * c rational q; mpf q_mpf; if (m_util.au().is_numeral(args[1], q)) { + TRACE("fp_rewriter", tout << "q: " << q << std::endl; ); mpf v; m_util.fm().set(v, ebits, sbits, rm, q.to_mpq()); result = m_util.mk_value(v); - m_util.fm().del(v); + m_util.fm().del(v); + TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); return BR_DONE; } - else if (m_util.is_value(args[1], q_mpf)) { + else if (m_util.is_value(args[1], q_mpf)) { + TRACE("fp_rewriter", tout << "q: " << m_util.fm().to_string(q_mpf) << std::endl; ); mpf v; m_util.fm().set(v, ebits, sbits, rm, q_mpf); result = m_util.mk_value(v); m_util.fm().del(v); + TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); return BR_DONE; } else @@ -117,11 +121,11 @@ br_status float_rewriter::mk_to_float(func_decl * f, unsigned num_args, expr * c return BR_FAILED; TRACE("fp_rewriter", tout << "q: " << q << ", e: " << e << "\n";); - mpf v; m_util.fm().set(v, ebits, sbits, rm, q.to_mpq(), e.to_mpq().numerator()); result = m_util.mk_value(v); - m_util.fm().del(v); + m_util.fm().del(v); + TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); return BR_DONE; } else { diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index def9f4fd5..735d21c99 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -367,7 +367,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode o.ebits = ebits; o.sbits = sbits; - signed ds = sbits - x.sbits + 4; // plus rounding bits + signed ds = sbits - x.sbits + 3; // plus rounding bits if (ds > 0) { m_mpz_manager.mul2k(o.significand, ds); From 92c1b2597869f1bb65cdf68559b45f02127bbb0f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 14 Jun 2013 20:14:00 +0100 Subject: [PATCH 182/281] FPA: bugfix for float to float conversion (subnormal numbers). Thanks to Gabriele Paganelli for reporting this bug! Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index dd40e8453..53ac5a58f 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1698,6 +1698,10 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a expr_ref sgn(m), sig(m), exp(m), lz(m); unpack(x, sgn, sig, exp, lz, true); + dbg_decouple("fpa2bv_to_float_x_sig", sig); + dbg_decouple("fpa2bv_to_float_x_exp", exp); + dbg_decouple("fpa2bv_to_float_lz", lz); + expr_ref res_sgn(m), res_sig(m), res_exp(m); res_sgn = sgn; @@ -1710,10 +1714,13 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a SASSERT(m_bv_util.get_bv_size(sgn) == 1); SASSERT(m_bv_util.get_bv_size(sig) == from_sbits); SASSERT(m_bv_util.get_bv_size(exp) == from_ebits); + SASSERT(m_bv_util.get_bv_size(lz) == from_ebits); - if (from_sbits < (to_sbits + 3)) + if (from_sbits < (to_sbits + 3)) + { // make sure that sig has at least to_sbits + 3 res_sig = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, to_sbits+3-from_sbits)); + } else if (from_sbits > (to_sbits + 3)) { // collapse the extra bits into a sticky bit. @@ -1734,7 +1741,9 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a exponent_overflow = m.mk_false(); if (from_ebits < (to_ebits + 2)) - res_exp = m_bv_util.mk_sign_extend(to_ebits+2-from_ebits, exp); + { + res_exp = m_bv_util.mk_sign_extend(to_ebits-from_ebits+2, exp); + } else if (from_ebits > (to_ebits + 2)) { expr_ref high(m), low(m), lows(m), high_red_or(m), high_red_and(m), h_or_eq(m), h_and_eq(m); @@ -1747,7 +1756,7 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a high_red_and = m.mk_app(m_bv_util.get_fid(), OP_BREDAND, high.get()); zero1 = m_bv_util.mk_numeral(0, 1); - m_simp.mk_eq(high_red_and, one1, h_and_eq); + m_simp.mk_eq(high_red_and, one1, h_and_eq); m_simp.mk_eq(high_red_or, zero1, h_or_eq); m_simp.mk_eq(lows, zero1, s_is_zero); m_simp.mk_eq(lows, one1, s_is_one); @@ -1763,10 +1772,18 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a else res_exp = exp; + // subtract lz for subnormal numbers. + expr_ref lz_ext(m); + lz_ext = m_bv_util.mk_zero_extend(to_ebits-from_ebits+2, lz); + res_exp = m_bv_util.mk_bv_sub(res_exp, lz_ext); SASSERT(m_bv_util.get_bv_size(res_exp) == to_ebits+2); + dbg_decouple("fpa2bv_to_float_res_sig", res_sig); + dbg_decouple("fpa2bv_to_float_res_exp", res_exp); + expr_ref rounded(m); round(s, rm, res_sgn, res_sig, res_exp, rounded); + expr_ref is_neg(m), sig_inf(m); m_simp.mk_eq(sgn, one1, is_neg); @@ -1781,7 +1798,7 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a mk_ite(c4, v4, result, result); mk_ite(c3, v3, result, result); mk_ite(c2, v2, result, result); - mk_ite(c1, v1, result, result); + mk_ite(c1, v1, result, result); } else { // .. other than that, we only support rationals for asFloat @@ -1826,7 +1843,7 @@ void fpa2bv_converter::mk_to_float(func_decl * f, unsigned num, expr * const * a m_util.fm().del(v); } - SASSERT(is_well_sorted(m, result)); + SASSERT(is_well_sorted(m, result)); } void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { @@ -2161,7 +2178,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef _DEBUG - return; + // CMW: This works only for quantifier-free formulas. expr_ref new_e(m); new_e = m.mk_fresh_const(prefix, m.get_sort(e)); From ecceb0accc455fcb0ee6eaf95ad33a91e2783b0c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 14 Jun 2013 20:16:02 +0100 Subject: [PATCH 183/281] FPA: debug output disabled. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 53ac5a58f..0913fbbcf 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -2178,7 +2178,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef _DEBUG - + return; // CMW: This works only for quantifier-free formulas. expr_ref new_e(m); new_e = m.mk_fresh_const(prefix, m.get_sort(e)); From cd485f03dd7118a9990013779febb8432f39bf66 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 20 Jun 2013 17:02:15 -0700 Subject: [PATCH 184/281] Add trace msg Signed-off-by: Leonardo de Moura --- src/api/z3_replayer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 079516145..acdb10bf6 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -26,6 +26,7 @@ Notes: void register_z3_replayer_cmds(z3_replayer & in); void throw_invalid_reference() { + TRACE("z3_replayer", tout << "invalid argument reference\n";); throw z3_replayer_exception("invalid argument reference"); } From 185f125f7a3d356192df272bfb2339ad36d3cdf9 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 20 Jun 2013 17:48:43 -0700 Subject: [PATCH 185/281] Fix problem reported at http://stackoverflow.com/questions/17215640/getting-concrete-values-from-a-model-containing-array-ext Signed-off-by: Leonardo de Moura --- src/smt/smt_model_finder.cpp | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index f3d0ca3bb..c4a48d9f8 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -94,7 +94,7 @@ namespace smt { } obj_map const & get_elems() const { return m_elems; } - + void insert(expr * n, unsigned generation) { if (m_elems.contains(n)) return; @@ -102,6 +102,14 @@ namespace smt { m_elems.insert(n, generation); SASSERT(!m_manager.is_model_value(n)); } + + void remove(expr * n) { + // We can only remove n if it is in m_elems, AND m_inv was not initialized yet. + SASSERT(m_elems.contains(n)); + SASSERT(m_inv.empty()); + m_elems.erase(n); + m_manager.dec_ref(n); + } void display(std::ostream & out) const { obj_map::iterator it = m_elems.begin(); @@ -525,6 +533,30 @@ namespace smt { } } + // For each instantiation_set, reemove entries that do not evaluate to values. + void cleanup_instantiation_sets() { + ptr_vector to_delete; + ptr_vector::const_iterator it = m_nodes.begin(); + ptr_vector::const_iterator end = m_nodes.end(); + for (; it != end; ++it) { + node * curr = *it; + if (curr->is_root()) { + instantiation_set * s = curr->get_instantiation_set(); + to_delete.reset(); + obj_map const & elems = s->get_elems(); + for (obj_map::iterator it = elems.begin(); it != elems.end(); it++) { + expr * n = it->m_key; + expr * n_val = eval(n, true); + if (!m_manager.is_value(n_val)) + to_delete.push_back(n); + } + for (ptr_vector::iterator it = to_delete.begin(); it != to_delete.end(); it++) { + s->remove(*it); + } + } + } + } + void display_nodes(std::ostream & out) const { display_key2node(out, m_uvars); display_A_f_is(out); @@ -545,6 +577,7 @@ namespace smt { r = 0; else r = tmp; + TRACE("model_finder", tout << "eval\n" << mk_pp(n, m_manager) << "\n----->\n" << mk_pp(r, m_manager) << "\n";); m_eval_cache.insert(n, r); m_eval_cache_range.push_back(r); return r; @@ -1047,6 +1080,7 @@ namespace smt { public: void fix_model(expr_ref_vector & new_constraints) { + cleanup_instantiation_sets(); m_new_constraints = &new_constraints; func_decl_set partial_funcs; collect_partial_funcs(partial_funcs); From a60b53bfd8dff26011e8bfd7bbca7801bf645dbf Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 20 Jun 2013 17:52:20 -0700 Subject: [PATCH 186/281] Fix compilation errors/warnings when using GCC Signed-off-by: Leonardo de Moura --- src/ast/rewriter/float_rewriter.cpp | 6 +++--- src/tactic/fpa/fpa2bv_rewriter.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/rewriter/float_rewriter.cpp b/src/ast/rewriter/float_rewriter.cpp index 367fa3a4c..0a4c3fc4e 100644 --- a/src/ast/rewriter/float_rewriter.cpp +++ b/src/ast/rewriter/float_rewriter.cpp @@ -88,7 +88,7 @@ br_status float_rewriter::mk_to_float(func_decl * f, unsigned num_args, expr * c m_util.fm().set(v, ebits, sbits, rm, q.to_mpq()); result = m_util.mk_value(v); m_util.fm().del(v); - TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); + // TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); return BR_DONE; } else if (m_util.is_value(args[1], q_mpf)) { @@ -97,7 +97,7 @@ br_status float_rewriter::mk_to_float(func_decl * f, unsigned num_args, expr * c m_util.fm().set(v, ebits, sbits, rm, q_mpf); result = m_util.mk_value(v); m_util.fm().del(v); - TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); + // TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); return BR_DONE; } else @@ -125,7 +125,7 @@ br_status float_rewriter::mk_to_float(func_decl * f, unsigned num_args, expr * c m_util.fm().set(v, ebits, sbits, rm, q.to_mpq(), e.to_mpq().numerator()); result = m_util.mk_value(v); m_util.fm().del(v); - TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); + // TRACE("fp_rewriter", tout << "result: " << result << std::endl; ); return BR_DONE; } else { diff --git a/src/tactic/fpa/fpa2bv_rewriter.h b/src/tactic/fpa/fpa2bv_rewriter.h index 24e275c0d..d737683a8 100644 --- a/src/tactic/fpa/fpa2bv_rewriter.h +++ b/src/tactic/fpa/fpa2bv_rewriter.h @@ -226,7 +226,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg { bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { if (t->get_idx() >= m_bindings.size()) return false; - unsigned inx = m_bindings.size() - t->get_idx() - 1; + // unsigned inx = m_bindings.size() - t->get_idx() - 1; expr_ref new_exp(m()); sort * s = t->get_sort(); From 42898f327671aa71e259a2966d78c45432a7b18a Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Fri, 21 Jun 2013 10:31:11 -0700 Subject: [PATCH 187/281] Fix bug reported by Florian Signed-off-by: Leonardo de Moura --- src/nlsat/nlsat_explain.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index be60fb052..50466c276 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -993,8 +993,22 @@ namespace nlsat { } return; } - else if (s == -1 && !is_even) { - atom_sign = -atom_sign; + else { + // We have shown the current factor is a constant MODULO the sign of the leading coefficient (of the equation used to rewrite the factor). + if (!info.m_lc_const) { + // If the leading coefficient is not a constant, we must store this information as an extra assumption. + if (d % 2 == 0 || // d is even + is_even || // rewriting a factor of even degree, sign flip doesn't matter + _a->get_kind() == atom::EQ) { // rewriting an equation, sign flip doesn't matter + info.add_lc_diseq(); + } + else { + info.add_lc_ineq(); + } + } + if (s == -1 && !is_even) { + atom_sign = -atom_sign; + } } } else { From 0b6250253a847ae6ba5c99240e8502879f7a1436 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 21 Jun 2013 21:16:03 +0100 Subject: [PATCH 188/281] FPA2BV: added sqrt function (Currently, there are a few corner cases where it doesn't round correctly.) Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 137 +++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 0913fbbcf..d085ce277 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1390,7 +1390,142 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar } void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { - NOT_IMPLEMENTED_YET(); + SASSERT(num == 2); + + expr_ref rm(m), x(m); + rm = args[0]; + x = args[1]; + + expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m); + mk_nan(f, nan); + mk_nzero(f, nzero); + mk_pzero(f, pzero); + mk_minus_inf(f, ninf); + mk_plus_inf(f, pinf); + + expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m); + mk_is_nan(x, x_is_nan); + mk_is_zero(x, x_is_zero); + mk_is_pos(x, x_is_pos); + mk_is_inf(x, x_is_inf); + + expr_ref zero1(m), one1(m); + zero1 = m_bv_util.mk_numeral(0, 1); + one1 = m_bv_util.mk_numeral(1, 1); + + expr_ref c1(m), c2(m), c3(m), c4(m), c5(m), c6(m); + expr_ref v1(m), v2(m), v3(m), v4(m), v5(m), v6(m), v7(m); + + // (x is NaN) -> NaN + c1 = x_is_nan; + v1 = x; + + // (x is +oo) -> +oo + mk_is_pinf(x, c2); + v2 = x; + + // (x is +-0) -> +-0 + mk_is_zero(x, c3); + v3 = x; + + // (x < 0) -> NaN + mk_is_neg(x, c4); + v4 = nan; + + // else comes the actual square root. + unsigned ebits = m_util.get_ebits(f->get_range()); + unsigned sbits = m_util.get_sbits(f->get_range()); + SASSERT(ebits <= sbits); + + expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); + unpack(x, a_sgn, a_sig, a_exp, a_lz, true); + + dbg_decouple("fpa2bv_sqrt_sig", a_sig); + dbg_decouple("fpa2bv_sqrt_exp", a_exp); + + SASSERT(m_bv_util.get_bv_size(a_sig) == sbits); + SASSERT(m_bv_util.get_bv_size(a_exp) == ebits); + + expr_ref res_sgn(m), res_sig(m), res_exp(m); + + res_sgn = zero1; + + expr_ref real_exp(m); + real_exp = m_bv_util.mk_bv_sub(m_bv_util.mk_sign_extend(1, a_exp), m_bv_util.mk_zero_extend(1, a_lz)); + res_exp = m_bv_util.mk_sign_extend(2, m_bv_util.mk_extract(ebits, 1, real_exp)); + + expr_ref e_is_odd(m); + e_is_odd = m.mk_eq(m_bv_util.mk_extract(0, 0, real_exp), one1); + + dbg_decouple("fpa2bv_sqrt_e_is_odd", e_is_odd); + dbg_decouple("fpa2bv_sqrt_real_exp", real_exp); + + expr_ref sig_prime(m); + m_simp.mk_ite(e_is_odd, m_bv_util.mk_concat(a_sig, zero1), + m_bv_util.mk_concat(zero1, a_sig), + sig_prime); + SASSERT(m_bv_util.get_bv_size(sig_prime) == sbits+1); + dbg_decouple("fpa2bv_sqrt_sig_prime", sig_prime); + + // This is algorithm 10.2 in the Handbook of Floating-Point Arithmetic + expr_ref Q(m), R(m), S(m), T(m); + + const mpz & p2 = fu().fm().m_powers2(sbits-1); + Q = m_bv_util.mk_numeral(p2, sbits+2); + R = m_bv_util.mk_bv_sub(m_bv_util.mk_concat(zero1, sig_prime), Q); + S = Q; + + for (unsigned i = 0; i < sbits; i++) { + dbg_decouple("fpa2bv_sqrt_Q", Q); + dbg_decouple("fpa2bv_sqrt_R", R); + + S = m_bv_util.mk_concat(zero1, m_bv_util.mk_extract(sbits+1, 1, S)); + + expr_ref twoQ_plus_S(m); + twoQ_plus_S = m_bv_util.mk_bv_add(m_bv_util.mk_concat(Q, zero1), m_bv_util.mk_concat(zero1, S)); + T = m_bv_util.mk_bv_sub(m_bv_util.mk_concat(R, zero1), twoQ_plus_S); + + dbg_decouple("fpa2bv_sqrt_T", T); + + SASSERT(m_bv_util.get_bv_size(Q) == sbits + 2); + SASSERT(m_bv_util.get_bv_size(R) == sbits + 2); + SASSERT(m_bv_util.get_bv_size(S) == sbits + 2); + SASSERT(m_bv_util.get_bv_size(T) == sbits + 3); + + expr_ref t_lt_0(m); + m_simp.mk_eq(m_bv_util.mk_extract(sbits+2, sbits+2, T), one1, t_lt_0); + + m_simp.mk_ite(t_lt_0, Q, + m_bv_util.mk_bv_add(Q, S), + Q); + m_simp.mk_ite(t_lt_0, m_bv_util.mk_concat(m_bv_util.mk_extract(sbits, 0, R), zero1), + m_bv_util.mk_extract(sbits+1, 0, T), + R); + } + + expr_ref rest(m), last(m), q_is_odd(m), rest_ext(m); + last = m_bv_util.mk_extract(0, 0, Q); + rest = m_bv_util.mk_extract(sbits, 1, Q); + m_simp.mk_eq(last, one1, q_is_odd); + dbg_decouple("fpa2bv_sqrt_q_is_odd", q_is_odd); + rest_ext = m_bv_util.mk_concat(rest, m_bv_util.mk_numeral(0, 4)); + m_simp.mk_ite(q_is_odd, m_bv_util.mk_bv_add(rest_ext, m_bv_util.mk_numeral(8, sbits+4)), + rest_ext, + res_sig); + + SASSERT(m_bv_util.get_bv_size(res_sig) == sbits + 4); + + expr_ref rounded(m); + round(f->get_range(), rm, res_sgn, res_sig, res_exp, rounded); + v5 = rounded; + + // And finally, we tie them together. + mk_ite(c4, v4, v5, result); + mk_ite(c3, v3, result, result); + mk_ite(c2, v2, result, result); + mk_ite(c1, v1, result, result); + + SASSERT(is_well_sorted(m, result)); } void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr * const * args, expr_ref & result) { From 5b5a474b5443b9d7a6e5ca4ad0a61e8cc87166f1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 21 Jun 2013 16:23:37 -0700 Subject: [PATCH 189/281] experiment with point-based generalization method Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_generalizers.cpp | 129 +++++++++++++++++++++++++------- src/muz_qe/pdr_generalizers.h | 4 + 2 files changed, 105 insertions(+), 28 deletions(-) diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index 800a21eaf..5e777bf7e 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -156,40 +156,19 @@ namespace pdr { m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); } - + void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { + method2(n, core, uses_level); + } + + // use the entire region as starting point for generalization. + void core_convex_hull_generalizer::method1(model_node& n, expr_ref_vector& core, bool& uses_level) { manager& pm = n.pt().get_pdr_manager(); expr_ref_vector conv1(m), conv2(m), core1(m), core2(m), eqs(m); if (core.empty()) { return; } - if (!m_left.contains(n.pt().head())) { - expr_ref left(m), right(m); - m_left.insert(n.pt().head(), 0); - unsigned sz = n.pt().sig_size(); - for (unsigned i = 0; i < sz; ++i) { - func_decl* fn0 = n.pt().sig(i); - sort* srt = fn0->get_range(); - if (a.is_int_real(srt)) { - func_decl* fn1 = pm.o2n(fn0, 0); - left = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); - right = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); - m_left.insert(fn1, left); - m_right.insert(fn1, right); - m_trail.push_back(left); - m_trail.push_back(right); - } - } - } - unsigned sz = n.pt().sig_size(); - for (unsigned i = 0; i < sz; ++i) { - expr* left, *right; - func_decl* fn0 = n.pt().sig(i); - func_decl* fn1 = pm.o2n(fn0, 0); - if (m_left.find(fn1, left) && m_right.find(fn1, right)) { - eqs.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(left, right))); - } - } + add_variables(n, eqs); if (!mk_convex(core, 0, conv1)) { IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core), m) << "\n";); return; @@ -230,6 +209,100 @@ namespace pdr { } } + // take as starting point two points from different regions. + void core_convex_hull_generalizer::method2(model_node& n, expr_ref_vector& core, bool& uses_level) { + expr_ref_vector conv1(m), conv2(m), core1(m), core2(m); + if (core.empty()) { + return; + } + manager& pm = n.pt().get_pdr_manager(); + smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); + expr_ref goal(pm.mk_and(core)); + ctx.assert_expr(goal); + lbool r = ctx.check(); + if (r != l_true) { + IF_VERBOSE(0, verbose_stream() << "unexpected result from satisfiability check\n";); + return; + } + add_variables(n, conv1); + model_ref mdl; + ctx.get_model(mdl); + + unsigned sz = n.pt().sig_size(); + for (unsigned i = 0; i < sz; ++i) { + expr_ref_vector constr(m); + expr* left, *right; + func_decl* fn0 = n.pt().sig(i); + func_decl* fn1 = pm.o2n(fn0, 0); + if (m_left.find(fn1, left) && m_right.find(fn1, right)) { + expr_ref val(m); + mdl->eval(fn1, val); + if (val) { + conv1.push_back(m.mk_eq(left, val)); + constr.push_back(m.mk_eq(right, val)); + } + } + expr_ref new_model = pm.mk_and(constr); + m_trail.push_back(new_model); + m_trail.push_back(goal); + m_models.insert(goal, new_model); + } + conv1.push_back(a.mk_gt(m_sigma[0].get(), a.mk_numeral(rational(0), a.mk_real()))); + conv1.push_back(a.mk_gt(m_sigma[1].get(), a.mk_numeral(rational(0), a.mk_real()))); + conv1.push_back(m.mk_eq(a.mk_numeral(rational(1), a.mk_real()), a.mk_add(m_sigma[0].get(), m_sigma[1].get()))); + + obj_map::iterator it = m_models.begin(), end = m_models.end(); + for (; it != end; ++it) { + if (it->m_key == goal) { + continue; + } + conv1.push_back(it->m_value); + expr_ref state = pm.mk_and(conv1); + TRACE("pdr", tout << "Try:\n" << mk_pp(state, m) << "\n";); + model_node nd(0, state, n.pt(), n.level()); + if (l_false == n.pt().is_reachable(nd, &conv2, uses_level)) { + IF_VERBOSE(0, + verbose_stream() << mk_pp(state, m) << "\n"; + verbose_stream() << "Generalized to:\n" << mk_pp(pm.mk_and(conv2), m) << "\n";); + core.reset(); + core.append(conv2); + return; + } + conv1.pop_back(); + } + } + + void core_convex_hull_generalizer::add_variables(model_node& n, expr_ref_vector& eqs) { + manager& pm = n.pt().get_pdr_manager(); + if (!m_left.contains(n.pt().head())) { + expr_ref left(m), right(m); + m_left.insert(n.pt().head(), 0); + unsigned sz = n.pt().sig_size(); + for (unsigned i = 0; i < sz; ++i) { + func_decl* fn0 = n.pt().sig(i); + sort* srt = fn0->get_range(); + if (a.is_int_real(srt)) { + func_decl* fn1 = pm.o2n(fn0, 0); + left = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); + right = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); + m_left.insert(fn1, left); + m_right.insert(fn1, right); + m_trail.push_back(left); + m_trail.push_back(right); + } + } + } + unsigned sz = n.pt().sig_size(); + for (unsigned i = 0; i < sz; ++i) { + expr* left, *right; + func_decl* fn0 = n.pt().sig(i); + func_decl* fn1 = pm.o2n(fn0, 0); + if (m_left.find(fn1, left) && m_right.find(fn1, right)) { + eqs.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(left, right))); + } + } + } + bool core_convex_hull_generalizer::mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv) { conv.reset(); for (unsigned i = 0; i < core.size(); ++i) { diff --git a/src/muz_qe/pdr_generalizers.h b/src/muz_qe/pdr_generalizers.h index a4be9d1fa..0aee94c16 100644 --- a/src/muz_qe/pdr_generalizers.h +++ b/src/muz_qe/pdr_generalizers.h @@ -80,10 +80,14 @@ namespace pdr { expr_ref_vector m_trail; obj_map m_left; obj_map m_right; + obj_map m_models; bool mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv); void mk_convex(expr* fml, unsigned index, expr_ref_vector& conv); bool mk_convex(expr* term, unsigned index, bool is_mul, expr_ref& result); bool translate(func_decl* fn, unsigned index, expr_ref& result); + void method1(model_node& n, expr_ref_vector& core, bool& uses_level); + void method2(model_node& n, expr_ref_vector& core, bool& uses_level); + void add_variables(model_node& n, expr_ref_vector& eqs); public: core_convex_hull_generalizer(context& ctx); virtual ~core_convex_hull_generalizer() {} From 13206f2fe723346cb002b33863750d8a6cacc465 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 24 Jun 2013 13:29:04 +0100 Subject: [PATCH 190/281] FPA: FMA bugfixes. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 79 +++++++++++++++-------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index d085ce277..041d42da1 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1270,6 +1270,11 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar SASSERT(is_well_sorted(m, f_sig)); SASSERT(is_well_sorted(m, f_exp)); + SASSERT(m_bv_util.get_bv_size(e_sig) == 2 * sbits); + SASSERT(m_bv_util.get_bv_size(f_sig) == 2 * sbits); + SASSERT(m_bv_util.get_bv_size(e_exp) == ebits + 2); + SASSERT(m_bv_util.get_bv_size(f_exp) == ebits + 2); + expr_ref res_sgn(m), res_sig(m), res_exp(m); expr_ref exp_delta(m); @@ -1278,43 +1283,39 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar // cap the delta expr_ref cap(m), cap_le_delta(m); - cap = m_bv_util.mk_numeral(sbits+3, ebits+2); - cap_le_delta = m_bv_util.mk_ule(exp_delta, cap); + cap = m_bv_util.mk_numeral(2*sbits, ebits+2); + cap_le_delta = m_bv_util.mk_ule(cap, exp_delta); m_simp.mk_ite(cap_le_delta, cap, exp_delta, exp_delta); SASSERT(m_bv_util.get_bv_size(exp_delta) == ebits+2); + SASSERT(is_well_sorted(m, exp_delta)); dbg_decouple("fpa2bv_fma_add_exp_delta_capped", exp_delta); - // Alignment shift with sticky bit computation. - expr_ref big_f_sig(m); - big_f_sig = m_bv_util.mk_concat(f_sig, m_bv_util.mk_numeral(0, sbits+4)); - SASSERT(is_well_sorted(m, big_f_sig)); - + // Alignment shift with sticky bit computation. expr_ref shifted_big(m), shifted_f_sig(m), sticky_raw(m); - shifted_big = m_bv_util.mk_bv_lshr(big_f_sig, m_bv_util.mk_concat(m_bv_util.mk_numeral(0, (2*(sbits+4))-(ebits+2)), exp_delta)); - shifted_f_sig = m_bv_util.mk_extract((2*(sbits+4)-1), (sbits+4), shifted_big); - SASSERT(is_well_sorted(m, shifted_f_sig)); - - sticky_raw = m_bv_util.mk_extract(sbits+3, 0, shifted_big); + shifted_big = m_bv_util.mk_bv_lshr(f_sig, m_bv_util.mk_zero_extend((2*sbits)-(ebits+2), exp_delta)); + shifted_f_sig = m_bv_util.mk_zero_extend(sbits, m_bv_util.mk_extract(2*sbits-1, sbits, shifted_big)); + sticky_raw = m_bv_util.mk_extract(sbits-1, 0, shifted_big); + SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2 * sbits); + SASSERT(is_well_sorted(m, shifted_f_sig)); + expr_ref sticky(m), sticky_eq(m), nil_sbit4(m), one_sbit4(m); - nil_sbit4 = m_bv_util.mk_numeral(0, sbits+4); - one_sbit4 = m_bv_util.mk_numeral(1, sbits+4); - m_simp.mk_eq(sticky_raw, nil_sbit4, sticky_eq); - m_simp.mk_ite(sticky_eq, nil_sbit4, one_sbit4, sticky); + sticky = m_bv_util.mk_zero_extend(2*sbits-1, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_raw)); SASSERT(is_well_sorted(m, sticky)); expr * or_args[2] = { shifted_f_sig, sticky }; shifted_f_sig = m_bv_util.mk_bv_or(2, or_args); SASSERT(is_well_sorted(m, shifted_f_sig)); - expr_ref eq_sgn(m); - m_simp.mk_eq(e_sgn, f_sgn, eq_sgn); - - // two extra bits for catching the overflow. + // Significant addition. + // Two extra bits for catching the overflow. e_sig = m_bv_util.mk_zero_extend(2, e_sig); shifted_f_sig = m_bv_util.mk_zero_extend(2, shifted_f_sig); - SASSERT(m_bv_util.get_bv_size(e_sig) == sbits+6); - SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == sbits+6); + expr_ref eq_sgn(m); + m_simp.mk_eq(e_sgn, f_sgn, eq_sgn); + + SASSERT(m_bv_util.get_bv_size(e_sig) == 2*sbits + 2); + SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2*sbits + 2); dbg_decouple("fpa2bv_fma_add_e_sig", e_sig); dbg_decouple("fpa2bv_fma_add_shifted_f_sig", shifted_f_sig); @@ -1330,14 +1331,22 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar dbg_decouple("fpa2bv_fma_add_sum", sum); expr_ref sign_bv(m), n_sum(m); - sign_bv = m_bv_util.mk_extract(sbits+4, sbits+4, sum); + sign_bv = m_bv_util.mk_extract(2*sbits+1, 2*sbits+1, sum); n_sum = m_bv_util.mk_bv_neg(sum); + expr_ref res_sig_eq(m), sig_abs(m), one_1(m); + one_1 = m_bv_util.mk_numeral(1, 1); + m_simp.mk_eq(sign_bv, one_1, res_sig_eq); + m_simp.mk_ite(res_sig_eq, n_sum, sum, sig_abs); dbg_decouple("fpa2bv_fma_add_sign_bv", sign_bv); dbg_decouple("fpa2bv_fma_add_n_sum", n_sum); - - family_id bvfid = m_bv_util.get_fid(); + dbg_decouple("fpa2bv_fma_add_sig_abs", sig_abs); + res_exp = m_bv_util.mk_bv_sub(e_exp, c_lz_ext); + + // Result could overflow into 4.xxx ... + + family_id bvfid = m_bv_util.get_fid(); expr_ref res_sgn_c1(m), res_sgn_c2(m), res_sgn_c3(m); expr_ref not_e_sgn(m), not_f_sgn(m), not_sign_bv(m); not_e_sgn = m_bv_util.mk_bv_not(e_sgn); @@ -1348,21 +1357,15 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar res_sgn_c3 = m.mk_app(bvfid, OP_BAND, e_sgn, f_sgn); expr * res_sgn_or_args[3] = { res_sgn_c1, res_sgn_c2, res_sgn_c3 }; res_sgn = m_bv_util.mk_bv_or(3, res_sgn_or_args); - - expr_ref res_sig_eq(m), sig_abs(m), one_1(m); - one_1 = m_bv_util.mk_numeral(1, 1); - m_simp.mk_eq(sign_bv, one_1, res_sig_eq); - m_simp.mk_ite(res_sig_eq, n_sum, sum, sig_abs); - - dbg_decouple("fpa2bv_fma_add_sig_abs", sig_abs); - - res_sig = m_bv_util.mk_extract(sbits+3, 0, sig_abs); - res_exp = m_bv_util.mk_bv_sub(e_exp, c_lz_ext); + + sticky_raw = m_bv_util.mk_extract(sbits-5, 0, sig_abs); + sticky = m_bv_util.mk_zero_extend(sbits+7, m.mk_app(bvfid, OP_BREDOR, sticky_raw)); + res_sig = m_bv_util.mk_extract(2*sbits-1, sbits-4, sig_abs); + SASSERT(m_bv_util.get_bv_size(res_sig) == sbits+4); expr_ref is_zero_sig(m), nil_sbits4(m); nil_sbits4 = m_bv_util.mk_numeral(0, sbits+4); m_simp.mk_eq(res_sig, nil_sbits4, is_zero_sig); - SASSERT(is_well_sorted(m, is_zero_sig)); dbg_decouple("fpa2bv_fma_is_zero_sig", is_zero_sig); @@ -1511,7 +1514,7 @@ void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, rest_ext = m_bv_util.mk_concat(rest, m_bv_util.mk_numeral(0, 4)); m_simp.mk_ite(q_is_odd, m_bv_util.mk_bv_add(rest_ext, m_bv_util.mk_numeral(8, sbits+4)), rest_ext, - res_sig); + res_sig); SASSERT(m_bv_util.get_bv_size(res_sig) == sbits + 4); @@ -2313,7 +2316,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef _DEBUG - return; + //return; // CMW: This works only for quantifier-free formulas. expr_ref new_e(m); new_e = m.mk_fresh_const(prefix, m.get_sort(e)); From 9581055f973cb9980cf2a369f3667253ad549a79 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 24 Jun 2013 13:30:36 +0100 Subject: [PATCH 191/281] FPA: debug output disabled Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 041d42da1..d8e39e9fb 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -2316,7 +2316,7 @@ void fpa2bv_converter::mk_rounding_mode(func_decl * f, expr_ref & result) void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) { #ifdef _DEBUG - //return; + return; // CMW: This works only for quantifier-free formulas. expr_ref new_e(m); new_e = m.mk_fresh_const(prefix, m.get_sort(e)); From 127402c10b661585721367a2d20d827518688802 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 24 Jun 2013 16:33:09 +0100 Subject: [PATCH 192/281] FPA: fpa2bv fma bugfix Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index d8e39e9fb..cb1048325 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1113,7 +1113,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar mk_nzero(f, nzero); mk_pzero(f, pzero); mk_minus_inf(f, ninf); - mk_plus_inf(f, pinf); + mk_plus_inf(f, pinf); expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_neg(m), x_is_inf(m); expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_neg(m), y_is_inf(m); @@ -1227,6 +1227,13 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar b_exp_ext = m_bv_util.mk_sign_extend(2, b_exp); c_exp_ext = m_bv_util.mk_sign_extend(2, c_exp); + dbg_decouple("fpa2bv_fma_a_sig", a_sig_ext); + dbg_decouple("fpa2bv_fma_b_sig", b_sig_ext); + dbg_decouple("fpa2bv_fma_c_sig", c_sig); + dbg_decouple("fpa2bv_fma_a_exp", a_exp_ext); + dbg_decouple("fpa2bv_fma_b_exp", b_exp_ext); + dbg_decouple("fpa2bv_fma_c_exp", c_exp_ext); + expr_ref mul_sgn(m), mul_sig(m), mul_exp(m); expr * signs[2] = { a_sgn, b_sgn }; @@ -1254,6 +1261,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar expr_ref swap_cond(m); swap_cond = m_bv_util.mk_sle(mul_exp, c_exp_ext); SASSERT(is_well_sorted(m, swap_cond)); + dbg_decouple("fpa2bv_fma_swap_cond", swap_cond); expr_ref e_sgn(m), e_sig(m), e_exp(m), f_sgn(m), f_sig(m), f_exp(m); m_simp.mk_ite(swap_cond, c_sgn, mul_sgn, e_sgn); @@ -1292,15 +1300,19 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar // Alignment shift with sticky bit computation. expr_ref shifted_big(m), shifted_f_sig(m), sticky_raw(m); - shifted_big = m_bv_util.mk_bv_lshr(f_sig, m_bv_util.mk_zero_extend((2*sbits)-(ebits+2), exp_delta)); - shifted_f_sig = m_bv_util.mk_zero_extend(sbits, m_bv_util.mk_extract(2*sbits-1, sbits, shifted_big)); + shifted_big = m_bv_util.mk_bv_lshr( + m_bv_util.mk_concat(f_sig, m_bv_util.mk_numeral(0, sbits)), + m_bv_util.mk_zero_extend((3*sbits)-(ebits+2), exp_delta)); + shifted_f_sig = m_bv_util.mk_zero_extend(sbits, m_bv_util.mk_extract(3*sbits-1, 2*sbits, shifted_big)); sticky_raw = m_bv_util.mk_extract(sbits-1, 0, shifted_big); SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2 * sbits); SASSERT(is_well_sorted(m, shifted_f_sig)); - expr_ref sticky(m), sticky_eq(m), nil_sbit4(m), one_sbit4(m); + expr_ref sticky(m); sticky = m_bv_util.mk_zero_extend(2*sbits-1, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_raw)); SASSERT(is_well_sorted(m, sticky)); + dbg_decouple("fpa2bv_fma_f_sig_sticky_raw", sticky_raw); + dbg_decouple("fpa2bv_fma_f_sig_sticky", sticky); expr * or_args[2] = { shifted_f_sig, sticky }; shifted_f_sig = m_bv_util.mk_bv_or(2, or_args); From 205520ed6cd3b79925bffbfcb6eae000c018c025 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Mon, 24 Jun 2013 15:34:42 -0700 Subject: [PATCH 193/281] Move AssemblyInfo.cs AssemblyInfo. Update mk_util.py to generate AssemblyInfo.cs instead of modifying it. Signed-off-by: Leonardo de Moura --- scripts/mk_util.py | 44 ++++++------------- .../{AssemblyInfo.cs => AssemblyInfo} | 0 2 files changed, 13 insertions(+), 31 deletions(-) rename src/api/dotnet/Properties/{AssemblyInfo.cs => AssemblyInfo} (100%) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 06120e2c4..38213a88b 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1785,7 +1785,7 @@ def update_version(): raise MKException("set_version(major, minor, build, revision) must be used before invoking update_version()") if not ONLY_MAKEFILES: mk_version_dot_h(major, minor, build, revision) - update_all_assembly_infos(major, minor, build, revision) + mk_all_assembly_infos(major, minor, build, revision) mk_def_files() # Update files with the version number @@ -1800,49 +1800,32 @@ def mk_version_dot_h(major, minor, build, revision): if VERBOSE: print("Generated '%s'" % os.path.join(c.src_dir, 'version.h')) -# Update version number in AssemblyInfo.cs files -def update_all_assembly_infos(major, minor, build, revision): +# Generate AssemblyInfo.cs files with the right version numbers by using AssemblyInfo files as a template +def mk_all_assembly_infos(major, minor, build, revision): for c in get_components(): if c.has_assembly_info(): - assembly = os.path.join(c.src_dir, c.assembly_info_dir, 'AssemblyInfo.cs') + assembly = os.path.join(c.src_dir, c.assembly_info_dir, 'AssemblyInfo') if os.path.exists(assembly): # It is a CS file - update_assembly_info_version(assembly, - major, minor, build, revision, False) + mk_assembly_info_version(assembly, major, minor, build, revision) else: - assembly = os.path.join(c.src_dir, c.assembly_info_dir, 'AssemblyInfo.cs') - if os.path.exists(assembly): - # It is a cpp file - update_assembly_info_version(assembly, - major, minor, build, revision, True) - else: - raise MKException("Failed to find assembly info file at '%s'" % os.path.join(c.src_dir, c.assembly_info_dir)) + raise MKException("Failed to find assembly info file 'AssemblyInfo' at '%s'" % os.path.join(c.src_dir, c.assembly_info_dir)) -# Update version number in the given AssemblyInfo.cs files -def update_assembly_info_version(assemblyinfo, major, minor, build, revision, is_cpp=False): - if is_cpp: - ver_pat = re.compile('[assembly:AssemblyVersionAttribute\("[\.\d]*"\) *') - fver_pat = re.compile('[assembly:AssemblyFileVersionAttribute\("[\.\d]*"\) *') - else: - ver_pat = re.compile('[assembly: AssemblyVersion\("[\.\d]*"\) *') - fver_pat = re.compile('[assembly: AssemblyFileVersion\("[\.\d]*"\) *') +# Generate version number in the given 'AssemblyInfo.cs' file using 'AssemblyInfo' as a template. +def mk_assembly_info_version(assemblyinfo, major, minor, build, revision): + ver_pat = re.compile('[assembly: AssemblyVersion\("[\.\d]*"\) *') + fver_pat = re.compile('[assembly: AssemblyFileVersion\("[\.\d]*"\) *') fin = open(assemblyinfo, 'r') - tmp = '%s.new' % assemblyinfo + tmp = '%s.cs' % assemblyinfo fout = open(tmp, 'w') num_updates = 0 for line in fin: if ver_pat.match(line): - if is_cpp: - fout.write('[assembly:AssemblyVersionAttribute("%s.%s.%s.%s")];\n' % (major, minor, build, revision)) - else: - fout.write('[assembly: AssemblyVersion("%s.%s.%s.%s")]\n' % (major, minor, build, revision)) + fout.write('[assembly: AssemblyVersion("%s.%s.%s.%s")]\n' % (major, minor, build, revision)) num_updates = num_updates + 1 elif fver_pat.match(line): - if is_cpp: - fout.write('[assembly:AssemblyFileVersionAttribute("%s.%s.%s.%s")];\n' % (major, minor, build, revision)) - else: - fout.write('[assembly: AssemblyFileVersion("%s.%s.%s.%s")]\n' % (major, minor, build, revision)) + fout.write('[assembly: AssemblyFileVersion("%s.%s.%s.%s")]\n' % (major, minor, build, revision)) num_updates = num_updates + 1 else: fout.write(line) @@ -1851,7 +1834,6 @@ def update_assembly_info_version(assemblyinfo, major, minor, build, revision, is assert num_updates == 2, "unexpected number of version number updates" fin.close() fout.close() - shutil.move(tmp, assemblyinfo) if VERBOSE: print("Updated '%s'" % assemblyinfo) diff --git a/src/api/dotnet/Properties/AssemblyInfo.cs b/src/api/dotnet/Properties/AssemblyInfo similarity index 100% rename from src/api/dotnet/Properties/AssemblyInfo.cs rename to src/api/dotnet/Properties/AssemblyInfo From 74792eeec41a5cae57fc1dd94a9235ad581a5051 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 25 Jun 2013 15:06:13 +0100 Subject: [PATCH 194/281] FPA: compilation bugfixes --- src/tactic/fpa/fpa2bv_converter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index d8e39e9fb..b527af780 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1299,7 +1299,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar SASSERT(is_well_sorted(m, shifted_f_sig)); expr_ref sticky(m), sticky_eq(m), nil_sbit4(m), one_sbit4(m); - sticky = m_bv_util.mk_zero_extend(2*sbits-1, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_raw)); + sticky = m_bv_util.mk_zero_extend(2*sbits-1, m.mk_app(m_bv_util.get_fid(), OP_BREDOR, sticky_raw.get())); SASSERT(is_well_sorted(m, sticky)); expr * or_args[2] = { shifted_f_sig, sticky }; @@ -1359,7 +1359,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar res_sgn = m_bv_util.mk_bv_or(3, res_sgn_or_args); sticky_raw = m_bv_util.mk_extract(sbits-5, 0, sig_abs); - sticky = m_bv_util.mk_zero_extend(sbits+7, m.mk_app(bvfid, OP_BREDOR, sticky_raw)); + sticky = m_bv_util.mk_zero_extend(sbits+7, m.mk_app(bvfid, OP_BREDOR, sticky_raw.get())); res_sig = m_bv_util.mk_extract(2*sbits-1, sbits-4, sig_abs); SASSERT(m_bv_util.get_bv_size(res_sig) == sbits+4); From 67aaec872a9d27859312790c9cc36bf72d4464c0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 25 Jun 2013 18:27:53 +0100 Subject: [PATCH 195/281] Java API: status bugfix. Thanks to user Bauna for reporting this issue (#50). Signed-off-by: Christoph M. Wintersteiger --- src/api/java/Status.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/java/Status.java b/src/api/java/Status.java index 117618426..e37631070 100644 --- a/src/api/java/Status.java +++ b/src/api/java/Status.java @@ -12,7 +12,7 @@ package com.microsoft.z3; public enum Status { // / Used to signify an unsatisfiable status. - UNSATISFIABLE(1), + UNSATISFIABLE(-1), // / Used to signify an unknown status. UNKNOWN(0), From 324dc5869da434d84d8d09cf360d36e260456896 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 25 Jun 2013 13:07:28 -0500 Subject: [PATCH 196/281] fix substitution bug in qe, working on boogie trace Signed-off-by: Nikolaj Bjorner --- src/api/api_datalog.cpp | 7 +- src/api/z3_api.h | 6 +- src/ast/rewriter/expr_safe_replace.cpp | 7 + src/ast/rewriter/expr_safe_replace.h | 2 + src/muz_qe/clp_context.cpp | 1 + src/muz_qe/clp_context.h | 17 +- src/muz_qe/dl_bmc_engine.cpp | 1 + src/muz_qe/dl_bmc_engine.h | 2 +- src/muz_qe/dl_boogie_proof.cpp | 297 ++++++++++++++++++ src/muz_qe/dl_boogie_proof.h | 87 ++++++ src/muz_qe/dl_cmds.cpp | 4 +- src/muz_qe/dl_compiler.cpp | 8 +- src/muz_qe/dl_context.cpp | 331 ++++++--------------- src/muz_qe/dl_context.h | 35 +-- src/muz_qe/dl_instruction.cpp | 2 +- src/muz_qe/dl_mk_backwards.cpp | 2 +- src/muz_qe/dl_mk_explanations.cpp | 6 +- src/muz_qe/dl_mk_karr_invariants.cpp | 10 +- src/muz_qe/dl_mk_karr_invariants.h | 1 + src/muz_qe/dl_mk_magic_sets.cpp | 2 +- src/muz_qe/dl_mk_partial_equiv.cpp | 2 +- src/muz_qe/dl_mk_rule_inliner.cpp | 5 +- src/muz_qe/dl_mk_similarity_compressor.cpp | 2 +- src/muz_qe/dl_mk_simple_joins.cpp | 8 +- src/muz_qe/dl_mk_subsumption_checker.cpp | 6 +- src/muz_qe/dl_mk_unbound_compressor.cpp | 6 +- src/muz_qe/dl_relation_manager.cpp | 62 +++- src/muz_qe/dl_relation_manager.h | 1 + src/muz_qe/dl_util.h | 38 +++ src/muz_qe/fixedpoint_params.pyg | 2 + src/muz_qe/pdr_context.cpp | 29 +- src/muz_qe/pdr_dl_interface.cpp | 1 + src/muz_qe/pdr_dl_interface.h | 29 +- src/muz_qe/proof_utils.cpp | 2 + src/muz_qe/proof_utils.h | 1 + src/muz_qe/qe_arith_plugin.cpp | 39 ++- src/muz_qe/qe_array_plugin.cpp | 12 +- src/muz_qe/qe_bool_plugin.cpp | 16 +- src/muz_qe/qe_bv_plugin.cpp | 10 +- src/muz_qe/qe_datatype_plugin.cpp | 24 +- src/muz_qe/qe_dl_plugin.cpp | 14 +- src/muz_qe/rel_context.cpp | 3 +- src/muz_qe/rel_context.h | 9 +- src/muz_qe/tab_context.cpp | 1 + src/muz_qe/tab_context.h | 17 +- src/shell/datalog_frontend.cpp | 12 +- src/smt/theory_array_base.cpp | 4 +- 47 files changed, 769 insertions(+), 414 deletions(-) create mode 100644 src/muz_qe/dl_boogie_proof.cpp create mode 100644 src/muz_qe/dl_boogie_proof.h diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index f6eadfea0..bf4752645 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -48,8 +48,11 @@ namespace api { if (!m.has_plugin(name)) { m.register_plugin(name, alloc(datalog::dl_decl_plugin)); } - datalog::relation_manager& r = m_context.get_rel_context().get_rmanager(); - r.register_plugin(alloc(datalog::external_relation_plugin, *this, r)); + datalog::rel_context* rel = m_context.get_rel_context(); + if (rel) { + datalog::relation_manager& r = rel->get_rmanager(); + r.register_plugin(alloc(datalog::external_relation_plugin, *this, r)); + } } void fixedpoint_context::reduce(func_decl* f, unsigned num_args, expr * const* args, expr_ref& result) { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 6d59cf650..458e2f53f 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -778,11 +778,11 @@ typedef enum } or \nicebox{ - (=> (and ln+1 ln+2 .. ln+m) l0) + (=> (and l1 l2 .. ln) l0) } or in the most general (ground) form: \nicebox{ - (=> (and ln+1 ln+2 .. ln+m) (or l0 l1 .. ln-1)) + (=> (and ln+1 ln+2 .. ln+m) (or l0 l1 .. ln)) } In other words we use the following (Prolog style) convention for Horn implications: @@ -798,7 +798,7 @@ typedef enum general non-ground form is: \nicebox{ - (forall (vars) (=> (and ln+1 ln+2 .. ln+m) (or l0 l1 .. ln-1))) + (forall (vars) (=> (and ln+1 ln+2 .. ln+m) (or l0 l1 .. ln))) } The hyper-resolution rule takes a sequence of parameters. diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index 1ec810414..a4886ad1a 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -106,3 +106,10 @@ void expr_safe_replace::reset() { m_dst.reset(); m_subst.reset(); } + +void expr_safe_replace::apply_substitution(expr* s, expr* def, expr_ref& t) { + reset(); + insert(s, def); + (*this)(t, t); + reset(); +} diff --git a/src/ast/rewriter/expr_safe_replace.h b/src/ast/rewriter/expr_safe_replace.h index b6131906a..ad626d18f 100644 --- a/src/ast/rewriter/expr_safe_replace.h +++ b/src/ast/rewriter/expr_safe_replace.h @@ -39,6 +39,8 @@ public: void operator()(expr* src, expr_ref& e); + void apply_substitution(expr* s, expr* def, expr_ref& t); + void reset(); }; diff --git a/src/muz_qe/clp_context.cpp b/src/muz_qe/clp_context.cpp index 94a956eb9..3a3908f59 100644 --- a/src/muz_qe/clp_context.cpp +++ b/src/muz_qe/clp_context.cpp @@ -205,6 +205,7 @@ namespace datalog { }; clp::clp(context& ctx): + engine_base(ctx.get_manager(), "clp"), m_imp(alloc(imp, ctx)) { } clp::~clp() { diff --git a/src/muz_qe/clp_context.h b/src/muz_qe/clp_context.h index 635891205..5184b474d 100644 --- a/src/muz_qe/clp_context.h +++ b/src/muz_qe/clp_context.h @@ -22,23 +22,24 @@ Revision History: #include "ast.h" #include "lbool.h" #include "statistics.h" +#include "dl_util.h" namespace datalog { class context; - class clp { + class clp : public datalog::engine_base { class imp; imp* m_imp; public: clp(context& ctx); ~clp(); - lbool query(expr* query); - void cancel(); - void cleanup(); - void reset_statistics(); - void collect_statistics(statistics& st) const; - void display_certificate(std::ostream& out) const; - expr_ref get_answer(); + virtual lbool query(expr* query); + virtual void cancel(); + virtual void cleanup(); + virtual void reset_statistics(); + virtual void collect_statistics(statistics& st) const; + virtual void display_certificate(std::ostream& out) const; + virtual expr_ref get_answer(); }; }; diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz_qe/dl_bmc_engine.cpp index 8e9fb510e..65a60cdeb 100644 --- a/src/muz_qe/dl_bmc_engine.cpp +++ b/src/muz_qe/dl_bmc_engine.cpp @@ -1416,6 +1416,7 @@ namespace datalog { }; bmc::bmc(context& ctx): + engine_base(ctx.get_manager(), "bmc"), m_ctx(ctx), m(ctx.get_manager()), m_solver(m, m_fparams), diff --git a/src/muz_qe/dl_bmc_engine.h b/src/muz_qe/dl_bmc_engine.h index 5911f5f72..e20987002 100644 --- a/src/muz_qe/dl_bmc_engine.h +++ b/src/muz_qe/dl_bmc_engine.h @@ -30,7 +30,7 @@ Revision History: namespace datalog { class context; - class bmc { + class bmc : public engine_base { context& m_ctx; ast_manager& m; smt_params m_fparams; diff --git a/src/muz_qe/dl_boogie_proof.cpp b/src/muz_qe/dl_boogie_proof.cpp new file mode 100644 index 000000000..8720b3544 --- /dev/null +++ b/src/muz_qe/dl_boogie_proof.cpp @@ -0,0 +1,297 @@ +/** + +Example from Boogie: + +(derivation +(step s!4 (main_loop_LoopHead true true) + rule!3 (subst + (= assertsPassed@@1 true) + (= assertsPassed@2@@0 true) + (= main_loop_LoopHead_assertsPassed true) + ) + (labels @950 +895 +668 +670 +893 +899 ) + (ref true )) +(step s!3 (main true false) + rule!1 (subst + (= assertsPassed true) + (= assertsPassed@0 true) + (= assertsPassed@2 false) + (= main_assertsPassed false) + ) + (labels @839 +763 +547 +546 +761 +544 +545 +si_fcall_805 +681 +768 ) + (ref s!4 )) +(step s!2 (main_SeqInstr true false) + rule!2 (subst + (= assertsPassed@@0 true) + (= assertsPassed@0@@0 false) + (= main_SeqInstr_assertsPassed false) + ) + (labels @890 +851 +572 +si_fcall_883 +853 ) + (ref s!3 )) +(step s!1 (@Fail!0) + rule!4 (subst + (= assertsPassed@@2 true) + (= main_SeqInstr_assertsPassed@@0 false) + ) + (labels ) + (ref s!2 )) +) +(model +"tickleBool -> { + true -> true + false -> true + else -> true +} +") +*/ + +#include "dl_boogie_proof.h" +#include "model_pp.h" +#include "proof_utils.h" +#include "ast_pp.h" +#include "dl_util.h" + +namespace datalog { + + /** + \brief push hyper-resolution steps upwards such that every use of + hyper-resolution uses a premise that is not derived from hyper-resolution. + + perform the following rewrite: + + hr(hr(p1,p2,p3,..),p4,p5) => hr(p1,hr(p2,p4),p3,..,p5) + + */ + + void mk_input_resolution(proof_ref& pr) { + ast_manager& m = pr.get_manager(); + proof_ref pr1(m); + proof_ref_vector premises1(m), premises2(m), premises(m); + expr_ref conclusion1(m), conclusion2(m), conclusion(m); + svector > positions1, positions2, positions; + vector substs1, substs2, substs; + + if (m.is_hyper_resolve(pr, premises1, conclusion1, positions1, substs1) && + m.is_hyper_resolve(premises1[0].get(), premises, conclusion2, positions, substs2)) { + for (unsigned i = 1; i < premises1.size(); ++i) { + pr1 = premises1[i].get(); + mk_input_resolution(pr1); + premises1[i] = pr1; + } + for (unsigned i = 0; i < premises.size(); ++i) { + pr1 = premises[i].get(); + mk_input_resolution(pr1); + premises[i] = pr1; + } + unsigned sz = premises.size(); + for (unsigned i = 1; i < sz; ++i) { + proof* premise = premises[i].get(); + expr_ref_vector literals(m); + expr* l1, *l2; + if (!m.is_implies(premise, l1, l2)) { + continue; + } + datalog::flatten_and(l1, literals); + positions2.reset(); + premises2.reset(); + premises2.push_back(premise); + substs2.reset(); + for (unsigned j = 0; j < literals.size(); ++j) { + expr* lit = literals[j].get(); + for (unsigned k = 1; k < premises1.size(); ++k) { + if (m.get_fact(premises1[k].get()) == lit) { + premises2.push_back(premises1[k].get()); + positions2.push_back(std::make_pair(j+1,0)); + substs2.push_back(expr_ref_vector(m)); + break; + } + } + } + premises[i] = m.mk_hyper_resolve(premises2.size(), premises2.c_ptr(), l2, positions2, substs2); + } + conclusion = conclusion1; + pr = m.mk_hyper_resolve(premises.size(), premises.c_ptr(), conclusion, positions, substs); + } + } + + void boogie_proof::set_proof(proof* p) { + std::cout << "set proof\n"; + m_proof = p; + proof_utils::push_instantiations_up(m_proof); + mk_input_resolution(m_proof); + std::cout << "proof set\n"; + } + + void boogie_proof::set_model(model* m) { + m_model = m; + } + + void boogie_proof::pp(std::ostream& out) { + if (m_proof) { + pp_proof(out); + } + if (m_model) { + model_pp(out, *m_model); + } + } + + void boogie_proof::pp_proof(std::ostream& out) { + vector steps; + ptr_vector rules; + rules.push_back(m_proof); + steps.push_back(step()); + obj_map index; + index.insert(m_proof, 0); + + for (unsigned j = 0; j < rules.size(); ++j) { + proof* p = rules[j]; + proof_ref_vector premises(m); + expr_ref conclusion(m); + svector > positions; + vector substs; + + expr* tmp; + steps[j].m_fact = m.get_fact(p); + m.is_implies(steps[j].m_fact, tmp, steps[j].m_fact); + get_subst(p, steps[j].m_subst); + get_labels(p, steps[j].m_labels); + + if (m.is_hyper_resolve(p, premises, conclusion, positions, substs)) { + for (unsigned i = 1; i < premises.size(); ++i) { + proof* premise = premises[i].get(); + unsigned position = 0; + if (!index.find(premise, position)) { + position = rules.size(); + rules.push_back(premise); + steps.push_back(step()); + index.insert(premise, position); + } + steps[j].m_refs.push_back(position); + } + get_rule_name(premises[0].get(), steps[j].m_rule_name); + } + } + for (unsigned j = steps.size(); j > 0; ) { + --j; + step &s = steps[j]; + + // TBD + s.m_labels; + + // set references, compensate for reverse ordering. + for (unsigned i = 0; i < s.m_refs.size(); ++i) { + s.m_refs[i] = rules.size()-1-s.m_refs[i]; + } + } + steps.reverse(); + pp_steps(out, steps); + } + + /** + \brief extract the instantiation by searching for the first occurrence of a hyper-resolution + rule that produces an instance. + */ + void boogie_proof::get_subst(proof* p, subst& s) { + ptr_vector todo; + todo.push_back(p); + ast_mark visited; + std::cout << "get_subst\n" << mk_pp(p, m) << "\n"; + while (!todo.empty()) { + proof* p = todo.back(); + todo.pop_back(); + if (visited.is_marked(p)) { + continue; + } + visited.mark(p, true); + proof_ref_vector premises(m); + expr_ref conclusion(m); + svector > positions; + vector substs; + if (m.is_hyper_resolve(p, premises, conclusion, positions, substs)) { + expr_ref_vector const& sub = substs[0]; + if (!sub.empty()) { + quantifier* q = to_quantifier(m.get_fact(premises[0].get())); + unsigned sz = sub.size(); + SASSERT(sz == q->get_num_decls()); + for (unsigned i = 0; i < sz; ++i) { + s.push_back(std::make_pair(q->get_decl_name(sz-1-i), sub[i])); + } + return; + } + } + unsigned sz = m.get_num_parents(p); + for (unsigned i = 0; i < sz; ++i) { + todo.push_back(m.get_parent(p, i)); + } + } + } + + void boogie_proof::get_rule_name(proof* p, symbol& n) { + + } + + void boogie_proof::get_labels(proof* p, labels& lbls) { + + } + + void boogie_proof::pp_steps(std::ostream& out, vector& steps) { + out << "(derivation\n"; + for (unsigned i = 0; i < steps.size(); ++i) { + pp_step(out, i, steps[i]); + } + out << ")\n"; + + } + + // step :: "(" "step" step-name fact rule-name subst labels premises ")" + void boogie_proof::pp_step(std::ostream& out, unsigned id, step& s) { + out << "(step\n"; + out << " s!" << id << " "; + pp_fact(out, s.m_fact); + out << " " << s.m_rule_name << "\n"; + pp_subst(out << " ", s.m_subst); + pp_labels(out << " ", s.m_labels); + pp_premises(out << " ", s.m_refs); + out << ")\n"; + } + + // fact :: "(" predicate theory-term* ")" + void boogie_proof::pp_fact(std::ostream& out, expr* fact) { + out << mk_pp(fact, m) << "\n"; + } + + // subst :: "(" "subst" assignment* ")" + void boogie_proof::pp_subst(std::ostream& out, subst& s) { + out << "(subst"; + for (unsigned i = 0; i < s.size(); ++i) { + pp_assignment(out, s[i].first, s[i].second); + } + out << ")\n"; + } + + // assignment :: "(" "=" variable theory-term ")" + void boogie_proof::pp_assignment(std::ostream& out, symbol const& v, expr* t) { + out << "\n (= " << v << " " << mk_pp(t, m) << ")"; + } + + + // labels :: "(" "labels" label* ")" + void boogie_proof::pp_labels(std::ostream& out, labels& lbls) { + out << "(labels"; + for (unsigned i = 0; i < lbls.size(); ++i) { + out << " " << lbls[i]; + } + out << ")\n"; + } + + // premises "(" "ref" step-name* ")" + void boogie_proof::pp_premises(std::ostream& out, refs& refs) { + out << "(ref"; + for (unsigned i = 0; i < refs.size(); ++i) { + out << " s!" << refs[i]; + } + out << ")\n"; + } + + +} diff --git a/src/muz_qe/dl_boogie_proof.h b/src/muz_qe/dl_boogie_proof.h new file mode 100644 index 000000000..6c8fbbae3 --- /dev/null +++ b/src/muz_qe/dl_boogie_proof.h @@ -0,0 +1,87 @@ +/** + +output :: derivation model + +derivation :: "(" "derivation" step* ")" + +step :: "(" "step" step-name fact rule-name subst labels premises ")" + +step-name :: identifier + +rule-name :: identifier + +fact :: "(" predicate theory-term* ")" + +subst :: "(" "subst" assignment* ")" + +assignment :: "(" "=" variable theory-term ")" + +labels :: "(" "labels" label* ")" + +premises :: "(" "ref" step-name* ")" + +model :: "(" "model" smtlib2-model ")" + +In each step the "fact" is derivable by hyper-resolution from the named +premises and the named rule, under the given substitution for the +universally quantified variables in the rule. The premises of each +step must have occurred previously in the step sequence. The last fact +is a nullary placeholder predicate representing satisfaction of the query +(its name is arbitrary). + +The labels list consists of all the positively labeled sub-formulas whose +truth is used in the proof, and all the negatively labeled formulas whose +negation is used. A theory-term is a ground term using only interpreted +constants of the background theories. + +The smtlib2-model gives an interpretation of the uninterpreted constants +in the background theory under which the derivation is valid. Currently +it is a quoted string in the old z3 model format, for compatibility with +Boogie, however, this should be changed to the new model format (using +define-fun) when Boogie supports this. + +*/ + +#include "ast.h" +#include "model.h" + +namespace datalog { + class boogie_proof { + typedef vector > subst; + typedef svector labels; + typedef unsigned_vector refs; + struct step { + symbol m_rule_name; + expr* m_fact; + subst m_subst; + labels m_labels; + refs m_refs; + }; + + ast_manager& m; + proof_ref m_proof; + model_ref m_model; + + void pp_proof(std::ostream& out); + void pp_steps(std::ostream& out, vector& steps); + void pp_step(std::ostream& out, unsigned i, step& s); + void pp_fact(std::ostream& out, expr* fact); + void pp_subst(std::ostream& out, subst& s); + void pp_assignment(std::ostream& out, symbol const& v, expr* t); + void pp_labels(std::ostream& out, labels& lbls); + void pp_premises(std::ostream& out, refs& refs); + + void get_subst(proof* p, subst& sub); + void get_rule_name(proof* p, symbol&); + void get_labels(proof* p, labels&); + + public: + boogie_proof(ast_manager& m): m(m), m_proof(m), m_model(0) {} + + void set_proof(proof* p); + + void set_model(model* m); + + void pp(std::ostream& out); + }; +} diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp index b82225785..693105e6e 100644 --- a/src/muz_qe/dl_cmds.cpp +++ b/src/muz_qe/dl_cmds.cpp @@ -328,9 +328,7 @@ private: void print_certificate(cmd_context& ctx) { if (m_dl_ctx->get_params().print_certificate()) { datalog::context& dlctx = m_dl_ctx->dlctx(); - if (!dlctx.display_certificate(ctx.regular_stream())) { - throw cmd_exception("certificates are not supported for the selected engine"); - } + dlctx.display_certificate(ctx.regular_stream()); ctx.regular_stream() << "\n"; } } diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index 3f16d0dab..a5f8009e7 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -42,7 +42,7 @@ namespace datalog { return; } relation_signature sig; - m_context.get_rel_context().get_rmanager().from_predicate(pred, sig); + m_context.get_rel_context()->get_rmanager().from_predicate(pred, sig); reg_idx reg = get_fresh_register(sig); e->get_data().m_value=reg; @@ -606,7 +606,7 @@ namespace datalog { } SASSERT(is_app(e)); relation_sort arg_sort; - m_context.get_rel_context().get_rmanager().from_predicate(neg_pred, i, arg_sort); + m_context.get_rel_context()->get_rmanager().from_predicate(neg_pred, i, arg_sort); reg_idx new_reg; bool new_dealloc; make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, new_dealloc, acc); @@ -1252,7 +1252,7 @@ namespace datalog { func_decl_set::iterator fdit = preds.begin(); func_decl_set::iterator fdend = preds.end(); for(; fdit!=fdend; ++fdit) { - if(!m_context.get_rel_context().get_rmanager().is_saturated(*fdit)) { + if(!m_context.get_rel_context()->get_rmanager().is_saturated(*fdit)) { return false; } } @@ -1337,7 +1337,7 @@ namespace datalog { acc.set_observer(0); - TRACE("dl", execution_code.display(m_context.get_rel_context(), tout);); + TRACE("dl", execution_code.display(*m_context.get_rel_context(), tout);); } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index f8e572ab1..2627cbbec 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -45,6 +45,7 @@ Revision History: #include"dl_mk_bit_blast.h" #include"dl_mk_array_blast.h" #include"dl_mk_karr_invariants.h" +#include"dl_mk_magic_symbolic.h" #include"dl_mk_quantifier_abstraction.h" #include"dl_mk_quantifier_instantiation.h" #include"datatype_decl_plugin.h" @@ -238,11 +239,13 @@ namespace datalog { m_rule_fmls(m), m_background(m), m_mc(0), + m_rel(0), + m_engine(0), m_closed(false), m_saturation_was_run(false), m_last_status(OK), m_last_answer(m), - m_engine(LAST_ENGINE), + m_engine_type(LAST_ENGINE), m_cancel(false) { } @@ -260,8 +263,7 @@ namespace datalog { m_preds.reset(); m_preds_by_name.reset(); reset_dealloc_values(m_sorts); - m_pdr = 0; - m_bmc = 0; + m_engine = 0; m_rel = 0; } @@ -432,8 +434,7 @@ namespace datalog { void context::set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, symbol const * relation_names) { - if (relation_name_cnt > 0) { - ensure_rel(); + if (m_rel && relation_name_cnt > 0) { m_rel->set_predicate_representation(pred, relation_name_cnt, relation_names); } } @@ -445,7 +446,7 @@ namespace datalog { register_predicate(new_pred, true); - if (m_rel.get()) { + if (m_rel) { m_rel->inherit_predicate_kind(new_pred, orig_pred); } return new_pred; @@ -542,64 +543,18 @@ namespace datalog { } unsigned context::get_num_levels(func_decl* pred) { - switch(get_engine()) { - case DATALOG_ENGINE: - throw default_exception("get_num_levels is not supported for datalog engine"); - case PDR_ENGINE: - case QPDR_ENGINE: - ensure_pdr(); - return m_pdr->get_num_levels(pred); - case BMC_ENGINE: - case QBMC_ENGINE: - throw default_exception("get_num_levels is not supported for bmc"); - case TAB_ENGINE: - throw default_exception("get_num_levels is not supported for tab"); - case CLP_ENGINE: - throw default_exception("get_num_levels is not supported for clp"); - default: - throw default_exception("unknown engine"); - } + ensure_engine(); + return m_engine->get_num_levels(pred); } expr_ref context::get_cover_delta(int level, func_decl* pred) { - switch(get_engine()) { - case DATALOG_ENGINE: - throw default_exception("operation is not supported for datalog engine"); - case PDR_ENGINE: - case QPDR_ENGINE: - ensure_pdr(); - return m_pdr->get_cover_delta(level, pred); - case BMC_ENGINE: - case QBMC_ENGINE: - throw default_exception("operation is not supported for BMC engine"); - case TAB_ENGINE: - throw default_exception("operation is not supported for TAB engine"); - case CLP_ENGINE: - throw default_exception("operation is not supported for CLP engine"); - default: - throw default_exception("unknown engine"); - } + ensure_engine(); + return m_engine->get_cover_delta(level, pred); } void context::add_cover(int level, func_decl* pred, expr* property) { - switch(get_engine()) { - case DATALOG_ENGINE: - throw default_exception("operation is not supported for datalog engine"); - case PDR_ENGINE: - case QPDR_ENGINE: - ensure_pdr(); - m_pdr->add_cover(level, pred, property); - break; - case BMC_ENGINE: - case QBMC_ENGINE: - throw default_exception("operation is not supported for BMC engine"); - case TAB_ENGINE: - throw default_exception("operation is not supported for TAB engine"); - case CLP_ENGINE: - throw default_exception("operation is not supported for CLP engine"); - default: - throw default_exception("unknown engine"); - } + ensure_engine(); + m_engine->add_cover(level, pred, property); } void context::check_uninterpreted_free(rule_ref& r) { @@ -743,7 +698,7 @@ namespace datalog { void context::add_fact(func_decl * pred, const relation_fact & fact) { if (get_engine() == DATALOG_ENGINE) { - ensure_rel(); + ensure_engine(); m_rel->add_fact(pred, fact); } else { @@ -769,7 +724,7 @@ namespace datalog { void context::add_table_fact(func_decl * pred, const table_fact & fact) { if (get_engine() == DATALOG_ENGINE) { - ensure_rel(); + ensure_engine(); m_rel->add_fact(pred, fact); } else { @@ -907,6 +862,9 @@ namespace datalog { m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); + if (get_params().magic()) { + m_transf.register_plugin(alloc(datalog::mk_magic_symbolic, *this, 36020)); + } transform_rules(m_transf); } @@ -917,7 +875,7 @@ namespace datalog { void context::updt_params(params_ref const& p) { m_params_ref.copy(p); - if (m_pdr.get()) m_pdr->updt_params(); + if (m_engine.get()) m_engine->updt_params(); } expr_ref context::get_background_assertion() { @@ -940,45 +898,39 @@ namespace datalog { m_cancel = true; m_last_status = CANCELED; m_transf.cancel(); - if (m_pdr.get()) m_pdr->cancel(); - if (m_bmc.get()) m_bmc->cancel(); - if (m_tab.get()) m_tab->cancel(); - if (m_rel.get()) m_rel->set_cancel(true); + if (m_engine) m_engine->cancel(); } void context::cleanup() { m_cancel = false; m_last_status = OK; - if (m_pdr.get()) m_pdr->cleanup(); - if (m_bmc.get()) m_bmc->cleanup(); - if (m_tab.get()) m_tab->cleanup(); - if (m_rel.get()) m_rel->set_cancel(false); + if (m_engine) m_engine->cleanup(); } class context::engine_type_proc { ast_manager& m; arith_util a; datatype_util dt; - DL_ENGINE m_engine; + DL_ENGINE m_engine_type; public: - engine_type_proc(ast_manager& m): m(m), a(m), dt(m), m_engine(DATALOG_ENGINE) {} + engine_type_proc(ast_manager& m): m(m), a(m), dt(m), m_engine_type(DATALOG_ENGINE) {} - DL_ENGINE get_engine() const { return m_engine; } + DL_ENGINE get_engine() const { return m_engine_type; } void operator()(expr* e) { if (is_quantifier(e)) { - m_engine = QPDR_ENGINE; + m_engine_type = QPDR_ENGINE; } - else if (m_engine != QPDR_ENGINE) { + else if (m_engine_type != QPDR_ENGINE) { if (a.is_int_real(e)) { - m_engine = PDR_ENGINE; + m_engine_type = PDR_ENGINE; } else if (is_var(e) && m.is_bool(e)) { - m_engine = PDR_ENGINE; + m_engine_type = PDR_ENGINE; } else if (dt.is_datatype(m.get_sort(e))) { - m_engine = PDR_ENGINE; + m_engine_type = PDR_ENGINE; } } } @@ -988,46 +940,46 @@ namespace datalog { symbol e = m_params.engine(); if (e == symbol("datalog")) { - m_engine = DATALOG_ENGINE; + m_engine_type = DATALOG_ENGINE; } else if (e == symbol("pdr")) { - m_engine = PDR_ENGINE; + m_engine_type = PDR_ENGINE; } else if (e == symbol("qpdr")) { - m_engine = QPDR_ENGINE; + m_engine_type = QPDR_ENGINE; } else if (e == symbol("bmc")) { - m_engine = BMC_ENGINE; + m_engine_type = BMC_ENGINE; } else if (e == symbol("qbmc")) { - m_engine = QBMC_ENGINE; + m_engine_type = QBMC_ENGINE; } else if (e == symbol("tab")) { - m_engine = TAB_ENGINE; + m_engine_type = TAB_ENGINE; } else if (e == symbol("clp")) { - m_engine = CLP_ENGINE; + m_engine_type = CLP_ENGINE; } - if (m_engine == LAST_ENGINE) { + if (m_engine_type == LAST_ENGINE) { expr_fast_mark1 mark; engine_type_proc proc(m); - m_engine = DATALOG_ENGINE; - for (unsigned i = 0; m_engine == DATALOG_ENGINE && i < m_rule_set.get_num_rules(); ++i) { + m_engine_type = DATALOG_ENGINE; + for (unsigned i = 0; m_engine_type == DATALOG_ENGINE && i < m_rule_set.get_num_rules(); ++i) { rule * r = m_rule_set.get_rule(i); quick_for_each_expr(proc, mark, r->get_head()); for (unsigned j = 0; j < r->get_tail_size(); ++j) { quick_for_each_expr(proc, mark, r->get_tail(j)); } - m_engine = proc.get_engine(); + m_engine_type = proc.get_engine(); } - for (unsigned i = m_rule_fmls_head; m_engine == DATALOG_ENGINE && i < m_rule_fmls.size(); ++i) { + for (unsigned i = m_rule_fmls_head; m_engine_type == DATALOG_ENGINE && i < m_rule_fmls.size(); ++i) { expr* fml = m_rule_fmls[i].get(); while (is_quantifier(fml)) { fml = to_quantifier(fml)->get_expr(); } quick_for_each_expr(proc, mark, fml); - m_engine = proc.get_engine(); + m_engine_type = proc.get_engine(); } } } @@ -1038,170 +990,78 @@ namespace datalog { m_last_answer = 0; switch (get_engine()) { case DATALOG_ENGINE: - flush_add_rules(); - return rel_query(query); case PDR_ENGINE: case QPDR_ENGINE: - flush_add_rules(); - return pdr_query(query); case BMC_ENGINE: case QBMC_ENGINE: - flush_add_rules(); - return bmc_query(query); case TAB_ENGINE: - flush_add_rules(); - return tab_query(query); case CLP_ENGINE: flush_add_rules(); - return clp_query(query); + break; default: UNREACHABLE(); - return rel_query(query); } + ensure_engine(); + return m_engine->query(query); } model_ref context::get_model() { - switch(get_engine()) { - case PDR_ENGINE: - case QPDR_ENGINE: - ensure_pdr(); - return m_pdr->get_model(); - default: - return model_ref(alloc(model, m)); - } + ensure_engine(); + return m_engine->get_model(); } proof_ref context::get_proof() { - switch(get_engine()) { - case PDR_ENGINE: - case QPDR_ENGINE: - ensure_pdr(); - return m_pdr->get_proof(); - default: - return proof_ref(m.mk_asserted(m.mk_true()), m); - } + ensure_engine(); + return m_engine->get_proof(); } - void context::ensure_pdr() { - if (!m_pdr.get()) { - m_pdr = alloc(pdr::dl_interface, *this); + void context::ensure_engine() { + if (!m_engine.get()) { + switch (get_engine()) { + case PDR_ENGINE: + case QPDR_ENGINE: + m_engine = alloc(pdr::dl_interface, *this); + break; + case DATALOG_ENGINE: + m_rel = alloc(rel_context, *this); + m_engine = m_rel; + break; + case BMC_ENGINE: + case QBMC_ENGINE: + m_engine = alloc(bmc, *this); + break; + case TAB_ENGINE: + m_engine = alloc(tab, *this); + break; + case CLP_ENGINE: + m_engine = alloc(clp, *this); + break; + } } } - lbool context::pdr_query(expr* query) { - ensure_pdr(); - return m_pdr->query(query); - } - - void context::ensure_bmc() { - if (!m_bmc.get()) { - m_bmc = alloc(bmc, *this); + lbool context::rel_query(unsigned num_rels, func_decl * const* rels) { + ensure_engine(); + if (m_rel) { + return m_rel->query(num_rels, rels); + } + else { + return l_undef; } } - - lbool context::bmc_query(expr* query) { - ensure_bmc(); - return m_bmc->query(query); - } - - void context::ensure_tab() { - if (!m_tab.get()) { - m_tab = alloc(tab, *this); - } - } - - void context::ensure_clp() { - if (!m_clp.get()) { - m_clp = alloc(clp, *this); - } - } - - lbool context::tab_query(expr* query) { - ensure_tab(); - return m_tab->query(query); - } - - lbool context::clp_query(expr* query) { - ensure_clp(); - return m_clp->query(query); - } - - void context::ensure_rel() { - if (!m_rel.get()) { - m_rel = alloc(rel_context, *this); - } - } - - lbool context::rel_query(unsigned num_rels, func_decl * const* rels) { - ensure_rel(); - return m_rel->query(num_rels, rels); - } - - lbool context::rel_query(expr* query) { - ensure_rel(); - return m_rel->query(query); - } - - + expr* context::get_answer_as_formula() { if (m_last_answer) { return m_last_answer.get(); } - switch(get_engine()) { - case PDR_ENGINE: - case QPDR_ENGINE: - ensure_pdr(); - m_last_answer = m_pdr->get_answer(); - return m_last_answer.get(); - case BMC_ENGINE: - case QBMC_ENGINE: - ensure_bmc(); - m_last_answer = m_bmc->get_answer(); - return m_last_answer.get(); - case DATALOG_ENGINE: - ensure_rel(); - m_last_answer = m_rel->get_last_answer(); - return m_last_answer.get(); - case TAB_ENGINE: - ensure_tab(); - m_last_answer = m_tab->get_answer(); - return m_last_answer.get(); - case CLP_ENGINE: - ensure_clp(); - m_last_answer = m_clp->get_answer(); - return m_last_answer.get(); - default: - UNREACHABLE(); - } - m_last_answer = m.mk_false(); + ensure_engine(); + m_last_answer = m_engine->get_answer(); return m_last_answer.get(); } - bool context::display_certificate(std::ostream& out) { - switch(get_engine()) { - case DATALOG_ENGINE: - return false; - case PDR_ENGINE: - case QPDR_ENGINE: - ensure_pdr(); - m_pdr->display_certificate(out); - return true; - case BMC_ENGINE: - case QBMC_ENGINE: - ensure_bmc(); - m_bmc->display_certificate(out); - return true; - case TAB_ENGINE: - ensure_tab(); - m_tab->display_certificate(out); - return true; - case CLP_ENGINE: - ensure_clp(); - m_clp->display_certificate(out); - return true; - default: - return false; - } + void context::display_certificate(std::ostream& out) { + ensure_engine(); + m_engine->display_certificate(out); } void context::display_profile(std::ostream& out) const { @@ -1219,26 +1079,14 @@ namespace datalog { } void context::reset_statistics() { - if (m_pdr) { - m_pdr->reset_statistics(); - } - if (m_bmc) { - m_bmc->reset_statistics(); - } - if (m_tab) { - m_tab->reset_statistics(); + if (m_engine) { + m_engine->reset_statistics(); } } void context::collect_statistics(statistics& st) const { - if (m_pdr) { - m_pdr->collect_statistics(st); - } - if (m_bmc) { - m_bmc->collect_statistics(st); - } - if (m_tab) { - m_tab->collect_statistics(st); + if (m_engine) { + m_engine->collect_statistics(st); } } @@ -1246,8 +1094,7 @@ namespace datalog { execution_result context::get_status() { return m_last_status; } bool context::result_contains_fact(relation_fact const& f) { - ensure_rel(); - return m_rel->result_contains_fact(f); + return m_rel && m_rel->result_contains_fact(f); } // NB: algebraic data-types declarations will not be printed. diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index e9abf7f23..c54f7d591 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -121,17 +121,14 @@ namespace datalog { model_converter_ref m_mc; proof_converter_ref m_pc; - scoped_ptr m_pdr; - scoped_ptr m_bmc; - scoped_ptr m_rel; - scoped_ptr m_tab; - scoped_ptr m_clp; + rel_context* m_rel; + scoped_ptr m_engine; bool m_closed; bool m_saturation_was_run; execution_result m_last_status; expr_ref m_last_answer; - DL_ENGINE m_engine; + DL_ENGINE m_engine_type; volatile bool m_cancel; @@ -161,7 +158,7 @@ namespace datalog { rule_manager & get_rule_manager() { return m_rule_manager; } smt_params & get_fparams() const { return m_fparams; } fixedpoint_params const& get_params() const { return m_params; } - DL_ENGINE get_engine() { configure_engine(); return m_engine; } + DL_ENGINE get_engine() { configure_engine(); return m_engine_type; } th_rewriter& get_rewriter() { return m_rewriter; } var_subst & get_var_subst() { return m_var_subst; } dl_decl_util & get_decl_util() { return m_decl_util; } @@ -454,14 +451,14 @@ namespace datalog { /** \brief Display a certificate for reachability and/or unreachability. */ - bool display_certificate(std::ostream& out); + void display_certificate(std::ostream& out); /** \brief query result if it contains fact. */ bool result_contains_fact(relation_fact const& f); - rel_context& get_rel_context() { ensure_rel(); return *m_rel; } + rel_context* get_rel_context() { ensure_engine(); return m_rel; } private: @@ -473,25 +470,7 @@ namespace datalog { void flush_add_rules(); - void ensure_pdr(); - - void ensure_bmc(); - - void ensure_tab(); - - void ensure_clp(); - - void ensure_rel(); - - lbool rel_query(expr* query); - - lbool pdr_query(expr* query); - - lbool bmc_query(expr* query); - - lbool tab_query(expr* query); - - lbool clp_query(expr* query); + void ensure_engine(); void check_quantifier_free(rule_ref& r); void check_uninterpreted_free(rule_ref& r); diff --git a/src/muz_qe/dl_instruction.cpp b/src/muz_qe/dl_instruction.cpp index 637d9a17f..df4736b8e 100644 --- a/src/muz_qe/dl_instruction.cpp +++ b/src/muz_qe/dl_instruction.cpp @@ -59,7 +59,7 @@ namespace datalog { } rel_context& execution_context::get_rel_context() { - return m_context.get_rel_context(); + return *m_context.get_rel_context(); } struct compare_size_proc { diff --git a/src/muz_qe/dl_mk_backwards.cpp b/src/muz_qe/dl_mk_backwards.cpp index b1d8b7d36..771de0dc3 100644 --- a/src/muz_qe/dl_mk_backwards.cpp +++ b/src/muz_qe/dl_mk_backwards.cpp @@ -48,7 +48,7 @@ namespace datalog { neg.reset(); rule & r = *source.get_rule(i); unsigned utsz = r.get_uninterpreted_tail_size(); - unsigned tsz = r.get_tail_size(); + unsigned tsz = r.get_tail_size(); if (!source.is_output_predicate(r.get_decl())) { tail.push_back(r.get_head()); neg.push_back(false); diff --git a/src/muz_qe/dl_mk_explanations.cpp b/src/muz_qe/dl_mk_explanations.cpp index 004b1823d..253bbbec7 100644 --- a/src/muz_qe/dl_mk_explanations.cpp +++ b/src/muz_qe/dl_mk_explanations.cpp @@ -604,7 +604,7 @@ namespace datalog { m_e_sort = m_decl_util.mk_rule_sort(); m_pinned.push_back(m_e_sort); - relation_manager & rmgr = ctx.get_rel_context().get_rmanager(); + relation_manager & rmgr = ctx.get_rel_context()->get_rmanager(); symbol er_symbol = explanation_relation_plugin::get_name(m_relation_level); m_er_plugin = static_cast(rmgr.get_relation_plugin(er_symbol)); if (!m_er_plugin) { @@ -637,7 +637,7 @@ namespace datalog { void mk_explanations::assign_rel_level_kind(func_decl * e_decl, func_decl * orig) { SASSERT(m_relation_level); - relation_manager & rmgr = m_context.get_rel_context().get_rmanager(); + relation_manager & rmgr = m_context.get_rel_context()->get_rmanager(); unsigned sz = e_decl->get_arity(); relation_signature sig; rmgr.from_predicate(e_decl, sig); @@ -871,7 +871,7 @@ namespace datalog { return 0; } rule_set * res = alloc(rule_set, m_context); - transform_facts(m_context.get_rel_context().get_rmanager(), source, *res); + transform_facts(m_context.get_rel_context()->get_rmanager(), source, *res); transform_rules(source, *res); return res; } diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 143a38636..4987a7e3d 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -49,7 +49,8 @@ namespace datalog { rm(ctx.get_rule_manager()), m_inner_ctx(m, ctx.get_fparams()), a(m), - m_pinned(m) { + m_pinned(m), + m_cancel(false) { params_ref params; params.set_sym("default_relation", symbol("karr_relation")); params.set_sym("engine", symbol("datalog")); @@ -189,6 +190,7 @@ namespace datalog { }; void mk_karr_invariants::cancel() { + m_cancel = true; m_inner_ctx.cancel(); } @@ -211,6 +213,10 @@ namespace datalog { get_invariants(*src_loop); + if (m_cancel) { + return 0; + } + // figure out whether to update same rules as used for saturation. scoped_ptr rev_source = bwd(*src_loop); get_invariants(*rev_source); @@ -225,7 +231,7 @@ namespace datalog { void mk_karr_invariants::get_invariants(rule_set const& src) { m_inner_ctx.reset(); - rel_context& rctx = m_inner_ctx.get_rel_context(); + rel_context& rctx = *m_inner_ctx.get_rel_context(); ptr_vector heads; func_decl_set const& predicates = m_ctx.get_predicates(); for (func_decl_set::iterator fit = predicates.begin(); fit != predicates.end(); ++fit) { diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index ec554e284..3d993e60a 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -57,6 +57,7 @@ namespace datalog { arith_util a; obj_map m_fun2inv; ast_ref_vector m_pinned; + volatile bool m_cancel; void get_invariants(rule_set const& src); diff --git a/src/muz_qe/dl_mk_magic_sets.cpp b/src/muz_qe/dl_mk_magic_sets.cpp index f6f79f348..24d9d01cb 100644 --- a/src/muz_qe/dl_mk_magic_sets.cpp +++ b/src/muz_qe/dl_mk_magic_sets.cpp @@ -362,7 +362,7 @@ namespace datalog { rule * r = *it; transform_rule(task.m_adornment, r, *result); } - if (!m_context.get_rel_context().get_relation(task.m_pred).empty()) { + if (!m_context.get_rel_context()->get_relation(task.m_pred).empty()) { //we need a rule to copy facts that are already in a relation into the adorned //relation (since out intentional predicates can have facts, not only rules) create_transfer_rule(task, *result); diff --git a/src/muz_qe/dl_mk_partial_equiv.cpp b/src/muz_qe/dl_mk_partial_equiv.cpp index 5ba1e71dd..4d1a1e860 100644 --- a/src/muz_qe/dl_mk_partial_equiv.cpp +++ b/src/muz_qe/dl_mk_partial_equiv.cpp @@ -97,7 +97,7 @@ namespace datalog { return 0; } - relation_manager & rm = m_context.get_rel_context().get_rmanager(); + relation_manager & rm = m_context.get_rel_context()->get_rmanager(); rule_set::decl2rules::iterator it = source.begin_grouped_rules(); rule_set::decl2rules::iterator end = source.end_grouped_rules(); diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz_qe/dl_mk_rule_inliner.cpp index 4afc1d323..5e0d6446b 100644 --- a/src/muz_qe/dl_mk_rule_inliner.cpp +++ b/src/muz_qe/dl_mk_rule_inliner.cpp @@ -206,7 +206,10 @@ namespace datalog { void mk_rule_inliner::count_pred_occurrences(rule_set const & orig) { - m_context.get_rel_context().get_rmanager().collect_non_empty_predicates(m_preds_with_facts); + rel_context* rel = m_context.get_rel_context(); + if (rel) { + rel->get_rmanager().collect_non_empty_predicates(m_preds_with_facts); + } rule_set::iterator rend = orig.end(); for (rule_set::iterator rit = orig.begin(); rit!=rend; ++rit) { diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz_qe/dl_mk_similarity_compressor.cpp index b600811f0..d4f410130 100644 --- a/src/muz_qe/dl_mk_similarity_compressor.cpp +++ b/src/muz_qe/dl_mk_similarity_compressor.cpp @@ -368,7 +368,7 @@ namespace datalog { collect_orphan_consts(*it, const_infos, val_fact); m_context.add_fact(aux_pred, val_fact); } - m_context.get_rel_context().get_rmanager().mark_saturated(aux_pred); + m_context.get_rel_context()->get_rmanager().mark_saturated(aux_pred); app * new_head = r->get_head(); ptr_vector new_tail; diff --git a/src/muz_qe/dl_mk_simple_joins.cpp b/src/muz_qe/dl_mk_simple_joins.cpp index 990125475..300ed0879 100644 --- a/src/muz_qe/dl_mk_simple_joins.cpp +++ b/src/muz_qe/dl_mk_simple_joins.cpp @@ -570,11 +570,15 @@ namespace datalog { cost estimate_size(app * t) const { func_decl * pred = t->get_decl(); unsigned n=pred->get_arity(); - relation_manager& rm = m_context.get_rel_context().get_rmanager(); + rel_context* rel = m_context.get_rel_context(); + if (!rel) { + return cost(1); + } + relation_manager& rm = rel->get_rmanager(); if( (m_context.saturation_was_run() && rm.try_get_relation(pred)) || rm.is_saturated(pred)) { SASSERT(rm.try_get_relation(pred)); //if it is saturated, it should exist - unsigned rel_size_int = m_context.get_rel_context().get_relation(pred).get_size_estimate_rows(); + unsigned rel_size_int = rel->get_relation(pred).get_size_estimate_rows(); if(rel_size_int!=0) { cost rel_size = static_cast(rel_size_int); cost curr_size = rel_size; diff --git a/src/muz_qe/dl_mk_subsumption_checker.cpp b/src/muz_qe/dl_mk_subsumption_checker.cpp index 8c9e7e69f..0d32a5c3b 100644 --- a/src/muz_qe/dl_mk_subsumption_checker.cpp +++ b/src/muz_qe/dl_mk_subsumption_checker.cpp @@ -249,7 +249,11 @@ namespace datalog { } void mk_subsumption_checker::scan_for_relations_total_due_to_facts(rule_set const& source) { - relation_manager& rm = m_context.get_rel_context().get_rmanager(); + rel_context* rel = m_context.get_rel_context(); + if (!rel) { + return; + } + relation_manager& rm = rel->get_rmanager(); decl_set const& candidate_preds = m_context.get_predicates(); diff --git a/src/muz_qe/dl_mk_unbound_compressor.cpp b/src/muz_qe/dl_mk_unbound_compressor.cpp index 7eb6f829d..71d4d5479 100644 --- a/src/muz_qe/dl_mk_unbound_compressor.cpp +++ b/src/muz_qe/dl_mk_unbound_compressor.cpp @@ -334,8 +334,10 @@ namespace datalog { // TODO mc m_modified = false; - m_context.get_rel_context().get_rmanager().collect_non_empty_predicates(m_non_empty_rels); - + rel_context* rel = m_context.get_rel_context(); + if (rel) { + rel->get_rmanager().collect_non_empty_predicates(m_non_empty_rels); + } unsigned init_rule_cnt = source.get_num_rules(); SASSERT(m_rules.empty()); for (unsigned i=0; i m_filter; + scoped_ptr m_project; + unsigned_vector m_removed_cols; + public: + /** + This constructor should be used only if we know that the projection operation + exists for the result of the join. + */ + default_relation_filter_interpreted_and_project_fn( + relation_mutator_fn* filter, + unsigned removed_col_cnt, + const unsigned * removed_cols) + : m_filter(filter), + m_project(0), + m_removed_cols(removed_col_cnt, removed_cols) {} + + virtual relation_base * operator()(const relation_base & t) { + scoped_rel t1 = t.clone(); + (*m_filter)(*t1); + if( !m_project) { + relation_manager & rmgr = t1->get_plugin().get_manager(); + m_project = rmgr.mk_project_fn(*t1, m_removed_cols.size(), m_removed_cols.c_ptr()); + if (!m_project) { + throw default_exception("projection does not exist"); + } + } + return (*m_project)(*t1); + } + }; + + relation_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn( + const relation_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols) { + + relation_transformer_fn* res = + t.get_plugin().mk_filter_interpreted_and_project_fn( + t, + condition, + removed_col_cnt, + removed_cols); + + if (!res) { + relation_mutator_fn* filter_fn = mk_filter_interpreted_fn(t, condition); + if (filter_fn) { + res = alloc(default_relation_filter_interpreted_and_project_fn, + filter_fn, + removed_col_cnt, + removed_cols); + } + } + return res; + } + class relation_manager::default_relation_join_project_fn : public relation_join_fn { scoped_ptr m_join; @@ -720,14 +774,6 @@ namespace datalog { return t.get_plugin().mk_filter_interpreted_fn(t, condition); } - relation_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn(const relation_base & t, - app * condition, - unsigned removed_col_cnt, - const unsigned * removed_cols) { - return t.get_plugin().mk_filter_interpreted_and_project_fn(t, condition, removed_col_cnt, removed_cols); - } - - class relation_manager::default_relation_select_equal_and_project_fn : public relation_transformer_fn { scoped_ptr m_filter; scoped_ptr m_project; diff --git a/src/muz_qe/dl_relation_manager.h b/src/muz_qe/dl_relation_manager.h index ccdba2783..9f12b4bb6 100644 --- a/src/muz_qe/dl_relation_manager.h +++ b/src/muz_qe/dl_relation_manager.h @@ -42,6 +42,7 @@ namespace datalog { class default_relation_join_project_fn; class default_relation_select_equal_and_project_fn; class default_relation_intersection_filter_fn; + class default_relation_filter_interpreted_and_project_fn; class auxiliary_table_transformer_fn; class auxiliary_table_filter_fn; diff --git a/src/muz_qe/dl_util.h b/src/muz_qe/dl_util.h index ea2def025..b92a33d1a 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz_qe/dl_util.h @@ -28,6 +28,8 @@ Revision History: #include"substitution.h" #include"fixedpoint_params.hpp" #include"ast_counter.h" +#include"statistics.h" +#include"lbool.h" namespace datalog { @@ -58,6 +60,42 @@ namespace datalog { LAST_ENGINE }; + class engine_base { + ast_manager& m; + std::string m_name; + public: + engine_base(ast_manager& m, char const* name): m(m), m_name(name) {} + virtual ~engine_base() {} + + virtual expr_ref get_answer() = 0; + virtual lbool query(expr* q) = 0; + + virtual void reset_statistics() {} + virtual void display_profile(std::ostream& out) const {} + virtual void collect_statistics(statistics& st) const {} + virtual unsigned get_num_levels(func_decl* pred) { + throw default_exception(std::string("get_num_levels is not supported for ") + m_name); + } + virtual expr_ref get_cover_delta(int level, func_decl* pred) { + throw default_exception(std::string("operation is not supported for ") + m_name); + } + virtual void add_cover(int level, func_decl* pred, expr* property) { + throw default_exception(std::string("operation is not supported for ") + m_name); + } + virtual void display_certificate(std::ostream& out) const { + throw default_exception(std::string("certificates are not supported for ") + m_name); + } + virtual model_ref get_model() { + return model_ref(alloc(model, m)); + } + virtual proof_ref get_proof() { + return proof_ref(m.mk_asserted(m.mk_true()), m); + } + virtual void updt_params() {} + virtual void cancel() {} + virtual void cleanup() {} + }; + struct std_string_hash_proc { unsigned operator()(const std::string & s) const { return string_hash(s.c_str(), static_cast(s.length()), 17); } diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index c2996dd8f..860dcb68e 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -10,6 +10,7 @@ def_module_params('fixedpoint', ('bit_blast', BOOL, False, '(PDR) bit-blast bit-vectors'), ('explanations_on_relation_level', BOOL, False, '(DATALOG) if true, explanations are generated as history of each relation, rather than per fact (generate_explanations must be set to true for this option to have any effect)'), ('magic_sets_for_queries', BOOL, False, "(DATALOG) magic set transformation will be used for queries"), + ('magic', BOOL, False, "perform symbolic magic set transformation"), ('unbound_compressor', BOOL, True, "auxiliary relations will be introduced to avoid unbound variables in rule heads"), ('similarity_compressor', BOOL, True, "(DATALOG) rules that differ only in values of constants will be merged into a single rule"), ('similarity_compressor_threshold', UINT, 11, "(DATALOG) if similarity_compressor is on, this value determines how many similar rules there must be in order for them to be merged"), @@ -60,6 +61,7 @@ def_module_params('fixedpoint', "by putting in half of the table columns, if it would have been empty otherwise"), ('print_answer', BOOL, False, 'print answer instance(s) to query'), ('print_certificate', BOOL, False, 'print certificate for reachability or non-reachability'), + ('print_boogie_certificate', BOOL, False, 'print certificate for reachability or non-reachability using a format understood by Boogie'), ('print_statistics', BOOL, False, 'print statistics'), ('use_utvpi', BOOL, True, 'PDR: Enable UTVPI strategy'), ('tab_selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'), diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 1c49e0c83..6f81d93d8 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -44,6 +44,7 @@ Notes: #include "proof_checker.h" #include "smt_value_sort.h" #include "proof_utils.h" +#include "dl_boogie_proof.h" namespace pdr { @@ -1063,7 +1064,7 @@ namespace pdr { ast_manager& m = pt.get_manager(); datalog::context& dctx = ctx.get_context(); datalog::rule_manager& rm = dctx.get_rule_manager(); - datalog::rule_unifier unifier(dctx); + datalog::rule_unifier unif(dctx); datalog::dl_decl_util util(m); datalog::rule_ref r0(rm), r1(rm); obj_map cache; @@ -1072,7 +1073,7 @@ namespace pdr { proof_ref_vector trail(m); datalog::rule_ref_vector rules_trail(rm); proof* pr = 0; - unifier.set_normalize(false); + unif.set_normalize(true); todo.push_back(m_root); update_models(); while (!todo.empty()) { @@ -1134,14 +1135,14 @@ namespace pdr { substs.push_back(binding); // TODO base substitution. for (unsigned i = 1; i < rls.size(); ++i) { datalog::rule& src = *rls[i]; - bool unified = unifier.unify_rules(*reduced_rule, 0, src); + bool unified = unif.unify_rules(*reduced_rule, 0, src); if (!unified) { IF_VERBOSE(0, verbose_stream() << "Could not unify rules: "; reduced_rule->display(dctx, verbose_stream()); src.display(dctx, verbose_stream());); } - expr_ref_vector sub1 = unifier.get_rule_subst(*reduced_rule, true); + expr_ref_vector sub1 = unif.get_rule_subst(*reduced_rule, true); TRACE("pdr", for (unsigned k = 0; k < sub1.size(); ++k) { tout << mk_pp(sub1[k].get(), m) << " "; @@ -1160,8 +1161,8 @@ namespace pdr { } positions.push_back(std::make_pair(i,0)); - substs.push_back(unifier.get_rule_subst(src, false)); - VERIFY(unifier.apply(*reduced_rule.get(), 0, src, r3)); + substs.push_back(unif.get_rule_subst(src, false)); + VERIFY(unif.apply(*reduced_rule.get(), 0, src, r3)); reduced_rule = r3; } @@ -1620,6 +1621,12 @@ namespace pdr { IF_VERBOSE(1, verbose_stream() << "\n"; m_search.display(verbose_stream());); m_last_result = l_true; validate(); + + IF_VERBOSE(1, + if (m_params.print_boogie_certificate()) { + display_certificate(verbose_stream()); + }); + return l_true; } catch (inductive_exception) { @@ -2129,7 +2136,15 @@ namespace pdr { break; } case l_true: { - strm << mk_pp(mk_sat_answer(), m); + if (m_params.print_boogie_certificate()) { + datalog::boogie_proof bp(m); + bp.set_proof(get_proof()); + bp.set_model(0); + bp.pp(strm); + } + else { + strm << mk_pp(mk_sat_answer(), m); + } break; } case l_undef: { diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz_qe/pdr_dl_interface.cpp index 437c08f6a..05a13dfc7 100644 --- a/src/muz_qe/pdr_dl_interface.cpp +++ b/src/muz_qe/pdr_dl_interface.cpp @@ -37,6 +37,7 @@ Revision History: using namespace pdr; dl_interface::dl_interface(datalog::context& ctx) : + engine_base(ctx.get_manager(), "pdr"), m_ctx(ctx), m_pdr_rules(ctx), m_old_rules(ctx), diff --git a/src/muz_qe/pdr_dl_interface.h b/src/muz_qe/pdr_dl_interface.h index c4844f892..2075dff47 100644 --- a/src/muz_qe/pdr_dl_interface.h +++ b/src/muz_qe/pdr_dl_interface.h @@ -23,6 +23,7 @@ Revision History: #include "lbool.h" #include "dl_rule.h" #include "dl_rule_set.h" +#include "dl_util.h" #include "statistics.h" namespace datalog { @@ -33,7 +34,7 @@ namespace pdr { class context; - class dl_interface { + class dl_interface : public datalog::engine_base { datalog::context& m_ctx; datalog::rule_set m_pdr_rules; datalog::rule_set m_old_rules; @@ -47,31 +48,31 @@ namespace pdr { dl_interface(datalog::context& ctx); ~dl_interface(); - lbool query(expr* query); + virtual lbool query(expr* query); - void cancel(); + virtual void cancel(); - void cleanup(); + virtual void cleanup(); - void display_certificate(std::ostream& out) const; + virtual void display_certificate(std::ostream& out) const; - void collect_statistics(statistics& st) const; + virtual void collect_statistics(statistics& st) const; - void reset_statistics(); + virtual void reset_statistics(); - expr_ref get_answer(); + virtual expr_ref get_answer(); - unsigned get_num_levels(func_decl* pred); + virtual unsigned get_num_levels(func_decl* pred); - expr_ref get_cover_delta(int level, func_decl* pred); + virtual expr_ref get_cover_delta(int level, func_decl* pred); - void add_cover(int level, func_decl* pred, expr* property); + virtual void add_cover(int level, func_decl* pred, expr* property); - void updt_params(); + virtual void updt_params(); - model_ref get_model(); + virtual model_ref get_model(); - proof_ref get_proof(); + virtual proof_ref get_proof(); }; } diff --git a/src/muz_qe/proof_utils.cpp b/src/muz_qe/proof_utils.cpp index 36e721b5c..87ecf9985 100644 --- a/src/muz_qe/proof_utils.cpp +++ b/src/muz_qe/proof_utils.cpp @@ -608,3 +608,5 @@ void proof_utils::push_instantiations_up(proof_ref& pr) { push_instantiations_up_cl push(pr.get_manager()); push(pr); } + + diff --git a/src/muz_qe/proof_utils.h b/src/muz_qe/proof_utils.h index dc3cdc3ef..383b5c379 100644 --- a/src/muz_qe/proof_utils.h +++ b/src/muz_qe/proof_utils.h @@ -42,6 +42,7 @@ public: */ static void push_instantiations_up(proof_ref& pr); + }; #endif diff --git a/src/muz_qe/qe_arith_plugin.cpp b/src/muz_qe/qe_arith_plugin.cpp index 1baee51fa..7bf0978f6 100644 --- a/src/muz_qe/qe_arith_plugin.cpp +++ b/src/muz_qe/qe_arith_plugin.cpp @@ -20,7 +20,7 @@ Revision History: #include "qe.h" #include "ast_pp.h" -#include "expr_replacer.h" +#include "expr_safe_replace.h" #include "bool_rewriter.h" #include "bv_decl_plugin.h" #include "arith_decl_plugin.h" @@ -93,7 +93,7 @@ namespace qe { expr_ref m_one_r; expr_ref m_tmp; public: - scoped_ptr m_replace; + expr_safe_replace m_replace; bool_rewriter m_bool_rewriter; arith_rewriter m_arith_rewriter; @@ -111,7 +111,7 @@ namespace qe { m_zero_r(m_arith.mk_numeral(numeral(0), false), m), m_one_r(m_arith.mk_numeral(numeral(1), false), m), m_tmp(m), - m_replace(mk_default_expr_replacer(m)), + m_replace(m), m_bool_rewriter(m), m_arith_rewriter(m) { } @@ -827,7 +827,7 @@ namespace qe { while (index <= up) { expr* n = mk_numeral(index); result = body; - m_replace->apply_substitution(x, n, result); + m_replace.apply_substitution(x, n, result); ors.push_back(result); ++index; } @@ -857,7 +857,7 @@ namespace qe { mk_flat_and(e1, body, result); app_ref z(m); mk_bounded_var(up, z_bv, z); - m_replace->apply_substitution(x, z, result); + m_replace.apply_substitution(x, z, result); } @@ -966,7 +966,7 @@ namespace qe { << mk_pp(e, m) << "\n"; ); expr_ref result(fml, m); - m_replace->apply_substitution(x, e, result); + m_replace.apply_substitution(x, e, result); simplify(result); TRACE("qe", tout << "singular solved:\n" @@ -1044,7 +1044,7 @@ namespace qe { tout << " = 0\n"; ); expr_ref result(fml, m); - m_replace->apply_substitution(x, p1, result); + m_replace.apply_substitution(x, p1, result); simplify(result); m_ctx.elim_var(index-1, result, p1); TRACE("qe", tout << "Reduced: " << mk_pp(result, m) << "\n";); @@ -2080,7 +2080,7 @@ public: app* atm = atoms[i]; t1 = m_util.mk_add(m_util.mk_mul(coeffs[i], z), terms[i]); m_util.mk_divides(divisors[i], t1, new_atom); - m_util.m_replace->apply_substitution(atm, new_atom.get(), result); + m_util.m_replace.apply_substitution(atm, new_atom.get(), result); m_ctx.add_constraint(false, mk_not(atm), new_atom); m_ctx.add_constraint(false, mk_not(new_atom), atm); @@ -2121,7 +2121,7 @@ public: m_util.simplify(mod_term2); m_ctx.add_constraint(false, m.mk_eq(mod_term2, m_util.mk_zero(mod_term2))); - m_util.m_replace->apply_substitution(atm, z1, result); + m_util.m_replace.apply_substitution(atm, z1, result); // // conjoin (coeff*z + rest - z1) mod k == 0 to result @@ -2153,7 +2153,7 @@ public: for (unsigned i = 0; i < sz; ++i) { app* e = bounds.atoms(is_strict, is_lower)[i]; m_ctx.add_constraint(true, mk_not(e)); - m_util.m_replace->apply_substitution(e, m.mk_false(), result); + m_util.m_replace.apply_substitution(e, m.mk_false(), result); } } @@ -2162,7 +2162,7 @@ public: for (unsigned i = 0; i < sz; ++i) { app* e = bounds.atoms(is_strict, !is_lower)[i]; m_ctx.add_constraint(true, e); - m_util.m_replace->apply_substitution(e, m.mk_true(), result); + m_util.m_replace.apply_substitution(e, m.mk_true(), result); } } @@ -2276,7 +2276,7 @@ public: else { m_ctx.add_constraint(true, e); } - m_util.m_replace->apply_substitution(atm, m.mk_true(), result); + m_util.m_replace.apply_substitution(atm, m.mk_true(), result); continue; } @@ -2293,7 +2293,7 @@ public: (same_strict && i < index); mk_bound(result_is_strict, is_lower, a, t, b, s, tmp); - m_util.m_replace->apply_substitution(e, tmp.get(), result); + m_util.m_replace.apply_substitution(e, tmp.get(), result); TRACE("qe", tout << (result_is_strict?"strict result":"non-strict result") << "\n"; @@ -2330,7 +2330,7 @@ public: s = x_t.mk_term(b, s); b = x_t.mk_coeff(b); m_util.mk_resolve(x, strict_resolve, a, t, b, s, tmp); - m_util.m_replace->apply_substitution(e, tmp.get(), result); + m_util.m_replace.apply_substitution(e, tmp.get(), result); m_ctx.add_constraint(true, mk_not(e), tmp); @@ -2398,7 +2398,7 @@ public: weights_t m_weights; th_rewriter m_rewriter; nlarith::util m_util; - scoped_ptr m_replacer; + expr_safe_replace m_replace; expr_ref_vector m_trail; factor_rewriter_star m_factor_rw; bool m_produce_models; @@ -2407,7 +2407,7 @@ public: qe_solver_plugin(m, m.mk_family_id("arith"), ctx), m_rewriter(m), m_util(m), - m_replacer(mk_default_expr_replacer(m)), + m_replace(m), m_trail(m), m_factor_rw(m), m_produce_models(produce_models) { @@ -2480,12 +2480,11 @@ public: SASSERT(vl.is_unsigned()); SASSERT(vl.get_unsigned() < brs->size()); unsigned j = vl.get_unsigned(); - expr_substitution sub(m); + m_replace.reset(); for (unsigned i = 0; i < brs->preds().size(); ++i) { - sub.insert(to_app(brs->preds(i)), brs->subst(j)[i]); + m_replace.insert(brs->preds(i), brs->subst(j)[i]); } - m_replacer->set_substitution(&sub); - (*m_replacer)(fml); + m_replace(fml); expr_ref tmp(m.mk_and(brs->constraints(j), fml), m); m_factor_rw(tmp, fml); if (def) { diff --git a/src/muz_qe/qe_array_plugin.cpp b/src/muz_qe/qe_array_plugin.cpp index 106a42338..c9de1d745 100644 --- a/src/muz_qe/qe_array_plugin.cpp +++ b/src/muz_qe/qe_array_plugin.cpp @@ -1,7 +1,7 @@ #include "qe.h" #include "array_decl_plugin.h" -#include "expr_replacer.h" +#include "expr_safe_replace.h" #include "ast_pp.h" #include "arith_decl_plugin.h" @@ -11,13 +11,13 @@ namespace qe { class array_plugin : public qe_solver_plugin { - scoped_ptr m_replace; + expr_safe_replace m_replace; public: array_plugin(i_solver_context& ctx, ast_manager& m) : qe_solver_plugin(m, m.mk_family_id("array"), ctx), - m_replace(mk_default_expr_replacer(m)) + m_replace(m) { } @@ -123,7 +123,7 @@ namespace qe { if (m_ctx.is_var(a, idx) && !m_ctx.contains(idx)(rhs)) { expr_ref result(fml, m); - m_replace->apply_substitution(a, rhs, result); + m_replace.apply_substitution(a, rhs, result); m_ctx.elim_var(idx, result, rhs); return true; } @@ -175,7 +175,7 @@ namespace qe { tout << "eq: " << mk_pp(lhs, m) << " == " << mk_pp(rhs, m) << "\n"; ); expr_ref result(fml, m); - m_replace->apply_substitution(A, store_B_i_t, result); + m_replace.apply_substitution(A, store_B_i_t, result); m_ctx.add_var(B); m_ctx.elim_var(idx, result, store_B_i_t); return true; @@ -248,7 +248,7 @@ namespace qe { tout << "eq: " << mk_pp(lhs, m) << " == " << mk_pp(rhs, m) << "\n"; ); expr_ref result(fml, m); - m_replace->apply_substitution(A, store_t, result); + m_replace.apply_substitution(A, store_t, result); m_ctx.elim_var(idx, result, store_t); return true; } diff --git a/src/muz_qe/qe_bool_plugin.cpp b/src/muz_qe/qe_bool_plugin.cpp index 782644c28..39a46ae55 100644 --- a/src/muz_qe/qe_bool_plugin.cpp +++ b/src/muz_qe/qe_bool_plugin.cpp @@ -25,18 +25,18 @@ Notes: --*/ #include "qe.h" -#include "expr_replacer.h" +#include "expr_safe_replace.h" #include "ast_pp.h" #include "model_evaluator.h" namespace qe { class bool_plugin : public qe_solver_plugin { - scoped_ptr m_replace; + expr_safe_replace m_replace; public: bool_plugin(i_solver_context& ctx, ast_manager& m): qe_solver_plugin(m, m.get_basic_family_id(), ctx), - m_replace(mk_default_expr_replacer(m)) + m_replace(m) {} virtual void assign(contains_app& x, expr* fml, rational const& vl) { @@ -51,7 +51,7 @@ namespace qe { virtual void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) { SASSERT(vl.is_one() || vl.is_zero()); expr* tf = (vl.is_one())?m.mk_true():m.mk_false(); - m_replace->apply_substitution(x.x(), tf, 0, fml); + m_replace.apply_substitution(x.x(), tf, fml); if (def) { *def = tf; } @@ -103,12 +103,12 @@ namespace qe { app* a = to_app(e); expr* e1; if (m_ctx.is_var(a, idx)) { - m_replace->apply_substitution(a, m.mk_true(), 0, fml); + m_replace.apply_substitution(a, m.mk_true(), fml); m_ctx.elim_var(idx, fml, m.mk_true()); return true; } else if (m.is_not(e, e1) && m_ctx.is_var(e1, idx)) { - m_replace->apply_substitution(to_app(e1), m.mk_false(), 0, fml); + m_replace.apply_substitution(to_app(e1), m.mk_false(), fml); m_ctx.elim_var(idx, fml, m.mk_false()); return true; } @@ -148,7 +148,7 @@ namespace qe { } // only occurrences of 'x' must be in positive atoms def = m.mk_true(); - m_replace->apply_substitution(x, def, 0, fml); + m_replace.apply_substitution(x, def, fml); return true; } else if (!p && n) { @@ -161,7 +161,7 @@ namespace qe { if (x != *it && contains_x(*it)) return false; } def = m.mk_false(); - m_replace->apply_substitution(x, def, 0, fml); + m_replace.apply_substitution(x, def, fml); return true; } else if (contains_x(fml)) { diff --git a/src/muz_qe/qe_bv_plugin.cpp b/src/muz_qe/qe_bv_plugin.cpp index cae567111..df1f8c619 100644 --- a/src/muz_qe/qe_bv_plugin.cpp +++ b/src/muz_qe/qe_bv_plugin.cpp @@ -21,19 +21,19 @@ Notes: --*/ #include "qe.h" -#include "expr_replacer.h" +#include "expr_safe_replace.h" #include "bv_decl_plugin.h" #include "model_evaluator.h" namespace qe { class bv_plugin : public qe_solver_plugin { - scoped_ptr m_replace; - bv_util m_bv; + expr_safe_replace m_replace; + bv_util m_bv; public: bv_plugin(i_solver_context& ctx, ast_manager& m): qe_solver_plugin(m, m.mk_family_id("bv"), ctx), - m_replace(mk_default_expr_replacer(m)), + m_replace(m), m_bv(m) {} @@ -48,7 +48,7 @@ namespace qe { virtual void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) { app_ref c(m_bv.mk_numeral(vl, m_bv.get_bv_size(x.x())), m); - m_replace->apply_substitution(x.x(), c, 0, fml); + m_replace.apply_substitution(x.x(), c, fml); if (def) { *def = m_bv.mk_numeral(vl, m_bv.get_bv_size(x.x())); } diff --git a/src/muz_qe/qe_datatype_plugin.cpp b/src/muz_qe/qe_datatype_plugin.cpp index 0b51f26af..9b77de42a 100644 --- a/src/muz_qe/qe_datatype_plugin.cpp +++ b/src/muz_qe/qe_datatype_plugin.cpp @@ -95,7 +95,7 @@ #include "qe.h" #include "datatype_decl_plugin.h" -#include "expr_replacer.h" +#include "expr_safe_replace.h" #include "obj_pair_hashtable.h" #include "for_each_expr.h" #include "ast_pp.h" @@ -415,7 +415,7 @@ namespace qe { typedef obj_pair_map subst_map; datatype_util m_datatype_util; - scoped_ptr m_replace; + expr_safe_replace m_replace; eqs_cache m_eqs_cache; subst_map m_subst_cache; ast_ref_vector m_trail; @@ -424,7 +424,7 @@ namespace qe { datatype_plugin(i_solver_context& ctx, ast_manager& m) : qe_solver_plugin(m, m.mk_family_id("datatype"), ctx), m_datatype_util(m), - m_replace(mk_default_expr_replacer(m)), + m_replace(m), m_trail(m) { } @@ -518,7 +518,7 @@ namespace qe { subst_clos* sub = 0; if (m_subst_cache.find(x.x(), c, sub)) { - m_replace->apply_substitution(x.x(), sub->first, 0, fml); + m_replace.apply_substitution(x.x(), sub->first, fml); add_def(sub->first, def); for (unsigned i = 0; i < sub->second.size(); ++i) { m_ctx.add_var(sub->second[i]); @@ -541,7 +541,7 @@ namespace qe { m_trail.push_back(t); add_def(t, def); - m_replace->apply_substitution(x.x(), t, 0, fml); + m_replace.apply_substitution(x.x(), t, fml); sub->first = t; m_subst_cache.insert(x.x(), c, sub); } @@ -673,7 +673,7 @@ namespace qe { fml = m.mk_and(is_c, fml); app_ref fresh_x(m.mk_fresh_const("x", s), m); m_ctx.add_var(fresh_x); - m_replace->apply_substitution(x, fresh_x, 0, fml); + m_replace.apply_substitution(x, fresh_x, fml); add_def(fresh_x, def); TRACE("qe", tout << "Add recognizer " << mk_pp(is_c, m) << "\n";); return; @@ -697,33 +697,33 @@ namespace qe { for (unsigned i = 0; i < eqs.num_recognizers(); ++i) { app* rec = eqs.recognizer(i); if (rec->get_decl() == r) { - m_replace->apply_substitution(rec, m.mk_true(), fml); + m_replace.apply_substitution(rec, m.mk_true(), fml); } else { - m_replace->apply_substitution(rec, m.mk_false(), fml); + m_replace.apply_substitution(rec, m.mk_false(), fml); } } for (unsigned i = 0; i < eqs.num_unsat(); ++i) { - m_replace->apply_substitution(eqs.unsat_atom(i), m.mk_false(), fml); + m_replace.apply_substitution(eqs.unsat_atom(i), m.mk_false(), fml); } if (idx < eqs.num_eqs()) { expr* t = eqs.eq(idx); expr* c = eqs.eq_cond(idx); add_def(t, def); - m_replace->apply_substitution(x, t, fml); + m_replace.apply_substitution(x, t, fml); if (!m.is_true(c)) { fml = m.mk_and(c, fml); } } else { for (unsigned i = 0; i < eqs.num_eqs(); ++i) { - m_replace->apply_substitution(eqs.eq_atom(i), m.mk_false(), fml); + m_replace.apply_substitution(eqs.eq_atom(i), m.mk_false(), fml); } for (unsigned i = 0; i < eqs.num_neqs(); ++i) { - m_replace->apply_substitution(eqs.neq_atom(i), m.mk_false(), fml); + m_replace.apply_substitution(eqs.neq_atom(i), m.mk_false(), fml); } if (def) { sort* s = m.get_sort(x); diff --git a/src/muz_qe/qe_dl_plugin.cpp b/src/muz_qe/qe_dl_plugin.cpp index 61466795b..a93301b4f 100644 --- a/src/muz_qe/qe_dl_plugin.cpp +++ b/src/muz_qe/qe_dl_plugin.cpp @@ -1,6 +1,6 @@ #include "qe.h" -#include "expr_replacer.h" +#include "expr_safe_replace.h" #include "dl_decl_plugin.h" #include "obj_pair_hashtable.h" #include "ast_pp.h" @@ -35,7 +35,7 @@ namespace qe { class dl_plugin : public qe_solver_plugin { typedef obj_pair_map eqs_cache; - scoped_ptr m_replace; + expr_safe_replace m_replace; datalog::dl_decl_util m_util; expr_ref_vector m_trail; eqs_cache m_eqs_cache; @@ -44,7 +44,7 @@ namespace qe { public: dl_plugin(i_solver_context& ctx, ast_manager& m) : qe_solver_plugin(m, m.mk_family_id("datalog_relation"), ctx), - m_replace(mk_default_expr_replacer(m)), + m_replace(m), m_util(m), m_trail(m) { @@ -140,7 +140,7 @@ namespace qe { void subst_small_domain(contains_app & x,eq_atoms& eqs, unsigned v,expr_ref & fml) { expr_ref vl(m_util.mk_numeral(v, m.get_sort(x.x())), m); - m_replace->apply_substitution(x.x(), vl, fml); + m_replace.apply_substitution(x.x(), vl, fml); } // assumes that all disequalities can be satisfied. @@ -148,15 +148,15 @@ namespace qe { SASSERT(w <= eqs.num_eqs()); if (w < eqs.num_eqs()) { expr* e = eqs.eq(w); - m_replace->apply_substitution(x.x(), e, fml); + m_replace.apply_substitution(x.x(), e, fml); } else { for (unsigned i = 0; i < eqs.num_eqs(); ++i) { - m_replace->apply_substitution(eqs.eq_atom(i), m.mk_false(), fml); + m_replace.apply_substitution(eqs.eq_atom(i), m.mk_false(), fml); } for (unsigned i = 0; i < eqs.num_neqs(); ++i) { - m_replace->apply_substitution(eqs.neq_atom(i), m.mk_true(), fml); + m_replace.apply_substitution(eqs.neq_atom(i), m.mk_true(), fml); } } } diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 7aade28e2..4ebcbf2fd 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -75,7 +75,8 @@ namespace datalog { }; rel_context::rel_context(context& ctx) - : m_context(ctx), + : engine_base(ctx.get_manager(), "datalog"), + m_context(ctx), m(ctx.get_manager()), m_rmanager(ctx), m_answer(m), diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index 7b4ee551c..057d1c15f 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -30,7 +30,7 @@ namespace datalog { class context; typedef vector > fact_vector; - class rel_context { + class rel_context : public engine_base { context& m_context; ast_manager& m; relation_manager m_rmanager; @@ -59,11 +59,11 @@ namespace datalog { context& get_context() const { return m_context; } relation_base & get_relation(func_decl * pred); relation_base * try_get_relation(func_decl * pred) const; - expr_ref get_last_answer() { return m_answer; } + virtual expr_ref get_answer() { return m_answer; } bool output_profile() const; - lbool query(expr* q); + virtual lbool query(expr* q); lbool query(unsigned num_rels, func_decl * const* rels); void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, @@ -73,6 +73,9 @@ namespace datalog { void set_cancel(bool f); + virtual void cancel() { set_cancel(true); } + virtual void cleanup() { set_cancel(false);} + /** \brief Restrict the set of used predicates to \c res. diff --git a/src/muz_qe/tab_context.cpp b/src/muz_qe/tab_context.cpp index 653f5f188..4f4c14cc7 100644 --- a/src/muz_qe/tab_context.cpp +++ b/src/muz_qe/tab_context.cpp @@ -1657,6 +1657,7 @@ namespace datalog { }; tab::tab(context& ctx): + datalog::engine_base(ctx.get_manager(),"tabulation"), m_imp(alloc(imp, ctx)) { } tab::~tab() { diff --git a/src/muz_qe/tab_context.h b/src/muz_qe/tab_context.h index f0a2eefed..c23ccb7d3 100644 --- a/src/muz_qe/tab_context.h +++ b/src/muz_qe/tab_context.h @@ -22,23 +22,24 @@ Revision History: #include "ast.h" #include "lbool.h" #include "statistics.h" +#include "dl_util.h" namespace datalog { class context; - class tab { + class tab : public engine_base { class imp; imp* m_imp; public: tab(context& ctx); ~tab(); - lbool query(expr* query); - void cancel(); - void cleanup(); - void reset_statistics(); - void collect_statistics(statistics& st) const; - void display_certificate(std::ostream& out) const; - expr_ref get_answer(); + virtual lbool query(expr* query); + virtual void cancel(); + virtual void cleanup(); + virtual void reset_statistics(); + virtual void collect_statistics(statistics& st) const; + virtual void display_certificate(std::ostream& out) const; + virtual expr_ref get_answer(); }; }; diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index efcab14ea..56f60bfa0 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -75,7 +75,7 @@ static void display_statistics( out << "--------------\n"; out << "instructions \n"; - code.display(ctx.get_rel_context(), out); + code.display(*ctx.get_rel_context(), out); out << "--------------\n"; out << "big relations \n"; @@ -83,7 +83,7 @@ static void display_statistics( } out << "--------------\n"; out << "relation sizes\n"; - ctx.get_rel_context().get_rmanager().display_relation_sizes(out); + ctx.get_rel_context()->get_rmanager().display_relation_sizes(out); if (verbose) { out << "--------------\n"; @@ -125,7 +125,7 @@ unsigned read_datalog(char const * file) { params.set_sym("engine", symbol("datalog")); datalog::context ctx(m, s_params, params); - datalog::relation_manager & rmgr = ctx.get_rel_context().get_rmanager(); + datalog::relation_manager & rmgr = ctx.get_rel_context()->get_rmanager(); datalog::relation_plugin & inner_plg = *rmgr.get_relation_plugin(symbol("tr_hashtable")); SASSERT(&inner_plg); rmgr.register_plugin(alloc(datalog::finite_product_relation_plugin, inner_plg, rmgr)); @@ -187,7 +187,7 @@ unsigned read_datalog(char const * file) { datalog::compiler::compile(ctx, ctx.get_rules(), rules_code, termination_code); - TRACE("dl_compiler", rules_code.display(ctx.get_rel_context(), tout);); + TRACE("dl_compiler", rules_code.display(*ctx.get_rel_context(), tout);); rules_code.make_annotations(ex_ctx); @@ -227,10 +227,10 @@ unsigned read_datalog(char const * file) { TRACE("dl_compiler", ctx.display(tout); - rules_code.display(ctx.get_rel_context(), tout);); + rules_code.display(*ctx.get_rel_context(), tout);); if (ctx.get_params().output_tuples()) { - ctx.get_rel_context().display_output_facts(ctx.get_rules(), std::cout); + ctx.get_rel_context()->display_output_facts(ctx.get_rules(), std::cout); } display_statistics( diff --git a/src/smt/theory_array_base.cpp b/src/smt/theory_array_base.cpp index c2c50567f..3f96a1d62 100644 --- a/src/smt/theory_array_base.cpp +++ b/src/smt/theory_array_base.cpp @@ -688,7 +688,7 @@ namespace smt { } } } - + void theory_array_base::propagate_select_to_store_parents(enode * r, enode * sel, svector & todo) { SASSERT(r->get_root() == r); SASSERT(is_select(sel)); @@ -880,7 +880,7 @@ namespace smt { } else { theory_var r = mg_find(v); - void * else_val = m_else_values[r]; + void * else_val = m_else_values[r]; // DISABLED. It seems wrong, since different nodes can share the same // else_val according to the mg class. // SASSERT(else_val == 0 || get_context().is_relevant(UNTAG(app*, else_val))); From 13262a0fc52f9d3919046fb3444ebea22a9be2a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 25 Jun 2013 13:13:47 -0500 Subject: [PATCH 197/281] missing files Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_magic_symbolic.cpp | 133 ++++++++++++++++++++++++++++ src/muz_qe/dl_mk_magic_symbolic.h | 40 +++++++++ 2 files changed, 173 insertions(+) create mode 100644 src/muz_qe/dl_mk_magic_symbolic.cpp create mode 100644 src/muz_qe/dl_mk_magic_symbolic.h diff --git a/src/muz_qe/dl_mk_magic_symbolic.cpp b/src/muz_qe/dl_mk_magic_symbolic.cpp new file mode 100644 index 000000000..2820ecaef --- /dev/null +++ b/src/muz_qe/dl_mk_magic_symbolic.cpp @@ -0,0 +1,133 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_magic_symbolic.cpp + +Abstract: + + Create Horn clauses for magic symbolic flow. + + Q(x) :- A(y), B(z), phi1(x,y,z). + Q(x) :- C(y), phi2(x,y). + A(x) :- C(y), phi3(x,y). + A(x) :- A(y), phi3(x,y). + B(x) :- C(y), A(z), phi4(x,y,z). + C(x) :- phi5(x). + + Transformed clauses: + + Q_ans(x) :- Q_query(x), A_ans(y), B_ans(z), phi1(x,y,z). + Q_ans(x) :- Q_query(x), C_ans(y), phi2(x,y). + Q_query(x) :- true. + + A_ans(x) :- A_query(x), C_ans(y), phi2(x,y) + A_ans(x) :- A_query(x), A_ans(y), phi3(x,y). + A_query(y) :- Q_query(x), phi1(x,y,z). + A_query(y) :- A_query(x), phi3(x,y). + A_query(z) :- B_query(x), C_ans(y), phi4(x,y,z). + + B_ans(x) :- B_query(x), C_ans(y), A_ans(z), phi4(x,y,z). + B_query(z) :- Q_query(x), A_ans(y), phi1(x,y,z). + + C_ans(x) :- C_query(x), phi5(x). + C_query(y) :- Q_query(x), phi2(x,y). + C_query(y) :- Q_query(x), phi3(x,y). + C_query(y) :- B_query(x), phi4(x,y,z). + +General scheme: + A(x) :- P1(x_1), ..., Pn(x_n), phi(x,x1,..,x_n). + + P(x) :- Prefix(x,y,z), A(z) ... + + A_ans(x) :- A_query(x), P_i_ans(x_i), phi(x,..). + A_query(z) :- P_query(x), Prefix_ans(x,y,z). + +Author: + + Nikolaj Bjorner (nbjorner) 2013-06-19 + +Revision History: + +--*/ + +#include"dl_mk_magic_symbolic.h" +#include"dl_context.h" + +namespace datalog { + + + mk_magic_symbolic::mk_magic_symbolic(context & ctx, unsigned priority): + plugin(priority), + m(ctx.get_manager()), + m_ctx(ctx) { + } + + mk_magic_symbolic::~mk_magic_symbolic() { } + + rule_set * mk_magic_symbolic::operator()(rule_set const & source) { + if (!m_ctx.get_params().magic()) { + return 0; + } + context& ctx = source.get_context(); + rule_manager& rm = source.get_rule_manager(); + rule_set * result = alloc(rule_set, ctx); + unsigned sz = source.get_num_rules(); + rule_ref new_rule(rm); + app_ref_vector tail(m); + app_ref head(m); + svector neg; + for (unsigned i = 0; i < sz; ++i) { + rule & r = *source.get_rule(i); + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + tail.reset(); + neg.reset(); + for (unsigned j = utsz; j < tsz; ++j) { + tail.push_back(r.get_tail(j)); + neg.push_back(false); + } + tail.push_back(mk_query(r.get_head())); + neg.push_back(false); + for (unsigned j = 0; j < utsz; ++j) { + tail.push_back(mk_ans(r.get_tail(j))); + neg.push_back(false); + } + new_rule = rm.mk(mk_ans(r.get_head()), tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + if (source.is_output_predicate(r.get_decl())) { + result->set_output_predicate(new_rule->get_decl()); + } + + result->add_rule(new_rule); + for (unsigned j = 0; j < utsz; ++j) { + new_rule = rm.mk(mk_query(r.get_tail(j)), tail.size()-utsz+j, tail.c_ptr(), neg.c_ptr(), r.name(), true); + result->add_rule(new_rule); + } + + } + TRACE("dl", result->display(tout);); + return result; + } + + app_ref mk_magic_symbolic::mk_query(app* q) { + string_buffer<64> name; + func_decl* f = q->get_decl(); + name << f->get_name() << "!query"; + func_decl_ref g(m); + g = m.mk_func_decl(symbol(name.c_str()), f->get_arity(), f->get_domain(), f->get_range()); + m_ctx.register_predicate(g, false); + return app_ref(m.mk_app(g, q->get_num_args(), q->get_args()), m); + } + + app_ref mk_magic_symbolic::mk_ans(app* q) { + string_buffer<64> name; + func_decl* f = q->get_decl(); + func_decl_ref g(m); + name << f->get_name() << "!ans"; + g = m.mk_func_decl(symbol(name.c_str()), f->get_arity(), f->get_domain(), f->get_range()); + m_ctx.register_predicate(g, false); + return app_ref(m.mk_app(g, q->get_num_args(), q->get_args()), m); + } + +}; diff --git a/src/muz_qe/dl_mk_magic_symbolic.h b/src/muz_qe/dl_mk_magic_symbolic.h new file mode 100644 index 000000000..ce9ca1145 --- /dev/null +++ b/src/muz_qe/dl_mk_magic_symbolic.h @@ -0,0 +1,40 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_magic_symbolic.h + +Abstract: + + Create Horn clauses for magic symbolic transformation. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-06-19 + +Revision History: + +--*/ +#ifndef _DL_MK_MAGIC_SYMBOLIC_H_ +#define _DL_MK_MAGIC_SYMBOLIC_H_ + +#include"dl_rule_transformer.h" + +namespace datalog { + + class mk_magic_symbolic : public rule_transformer::plugin { + ast_manager& m; + context& m_ctx; + app_ref mk_ans(app* q); + app_ref mk_query(app* q); + public: + mk_magic_symbolic(context & ctx, unsigned priority = 33037); + ~mk_magic_symbolic(); + rule_set * operator()(rule_set const & source); + }; + +}; + +#endif /* _DL_MK_MAGIC_SYMBOLIC_H_ */ + From 0d2a7f922c82ec0963ee059d2471541a4a11ad48 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 26 Jun 2013 18:16:25 +0100 Subject: [PATCH 198/281] FPA: sqrt precision bugfixes Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 53 +++++++++++++++++------------ 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 64052359e..a4961f555 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1485,16 +1485,16 @@ void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, // This is algorithm 10.2 in the Handbook of Floating-Point Arithmetic expr_ref Q(m), R(m), S(m), T(m); - const mpz & p2 = fu().fm().m_powers2(sbits); - Q = m_bv_util.mk_numeral(p2, sbits+2); - R = m_bv_util.mk_bv_sub(m_bv_util.mk_concat(sig_prime, zero1), Q); + const mpz & p2 = fu().fm().m_powers2(sbits+3); + Q = m_bv_util.mk_numeral(p2, sbits+5); + R = m_bv_util.mk_bv_sub(m_bv_util.mk_concat(sig_prime, m_bv_util.mk_numeral(0, 4)), Q); S = Q; - for (unsigned i = 0; i <= sbits; i++) { + for (unsigned i = 0; i < sbits + 3; i++) { dbg_decouple("fpa2bv_sqrt_Q", Q); dbg_decouple("fpa2bv_sqrt_R", R); - S = m_bv_util.mk_concat(zero1, m_bv_util.mk_extract(sbits+1, 1, S)); + S = m_bv_util.mk_concat(zero1, m_bv_util.mk_extract(sbits+4, 1, S)); expr_ref twoQ_plus_S(m); twoQ_plus_S = m_bv_util.mk_bv_add(m_bv_util.mk_concat(Q, zero1), m_bv_util.mk_concat(zero1, S)); @@ -1502,31 +1502,40 @@ void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args, dbg_decouple("fpa2bv_sqrt_T", T); - SASSERT(m_bv_util.get_bv_size(Q) == sbits + 2); - SASSERT(m_bv_util.get_bv_size(R) == sbits + 2); - SASSERT(m_bv_util.get_bv_size(S) == sbits + 2); - SASSERT(m_bv_util.get_bv_size(T) == sbits + 3); + SASSERT(m_bv_util.get_bv_size(Q) == sbits + 5); + SASSERT(m_bv_util.get_bv_size(R) == sbits + 5); + SASSERT(m_bv_util.get_bv_size(S) == sbits + 5); + SASSERT(m_bv_util.get_bv_size(T) == sbits + 6); expr_ref t_lt_0(m); - m_simp.mk_eq(m_bv_util.mk_extract(sbits+2, sbits+2, T), one1, t_lt_0); + m_simp.mk_eq(m_bv_util.mk_extract(sbits+5, sbits+5, T), one1, t_lt_0); - m_simp.mk_ite(t_lt_0, Q, - m_bv_util.mk_bv_add(Q, S), + expr * or_args[2] = { Q, S }; + + m_simp.mk_ite(t_lt_0, Q, + m_bv_util.mk_bv_or(2, or_args), Q); - m_simp.mk_ite(t_lt_0, m_bv_util.mk_concat(m_bv_util.mk_extract(sbits, 0, R), zero1), - m_bv_util.mk_extract(sbits+1, 0, T), + m_simp.mk_ite(t_lt_0, m_bv_util.mk_concat(m_bv_util.mk_extract(sbits+3, 0, R), zero1), + m_bv_util.mk_extract(sbits+4, 0, T), R); } - + + expr_ref is_exact(m); + m_simp.mk_eq(R, m_bv_util.mk_numeral(0, sbits+5), is_exact); + dbg_decouple("fpa2bv_sqrt_is_exact", is_exact); + expr_ref rest(m), last(m), q_is_odd(m), rest_ext(m); last = m_bv_util.mk_extract(0, 0, Q); - rest = m_bv_util.mk_extract(sbits, 1, Q); - m_simp.mk_eq(last, one1, q_is_odd); - dbg_decouple("fpa2bv_sqrt_q_is_odd", q_is_odd); - rest_ext = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(rest, m_bv_util.mk_numeral(0, 3))); - m_simp.mk_ite(q_is_odd, m_bv_util.mk_bv_add(rest_ext, m_bv_util.mk_numeral(8, sbits+4)), - rest_ext, - res_sig); + rest = m_bv_util.mk_extract(sbits+3, 1, Q); + dbg_decouple("fpa2bv_sqrt_last", last); + dbg_decouple("fpa2bv_sqrt_rest", rest); + rest_ext = m_bv_util.mk_zero_extend(1, rest); + expr_ref sticky(m); + m_simp.mk_ite(is_exact, m_bv_util.mk_zero_extend(sbits+3, last), + m_bv_util.mk_numeral(1, sbits+4), + sticky); + expr * or_args[2] = { rest_ext, sticky }; + res_sig = m_bv_util.mk_bv_or(2, or_args); SASSERT(m_bv_util.get_bv_size(res_sig) == sbits + 4); From 42b3a81ef622ca9fe460d5d59dd4cf7504593245 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 27 Jun 2013 16:08:25 +0100 Subject: [PATCH 199/281] FPA: precision bugfixes for FMA Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 55 +++++++++++++++++------------ 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index a4961f555..234c343b8 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -1134,6 +1134,9 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar mk_is_neg(z, z_is_neg); mk_is_inf(z, z_is_inf); + expr_ref rm_is_to_neg(m); + mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg); + dbg_decouple("fpa2bv_fma_x_is_nan", x_is_nan); dbg_decouple("fpa2bv_fma_x_is_zero", x_is_zero); dbg_decouple("fpa2bv_fma_x_is_pos", x_is_pos); @@ -1187,31 +1190,28 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar m_simp.mk_or(x_is_zero, inf_cond, inf_or); mk_ite(inf_or, nan, neg_x_sgn_inf, v5); - // z is +-INF -> Z. + // z is +-INF -> z. mk_is_inf(z, c6); v6 = z; - // (x is 0) || (y is 0) -> x but with sign = x.sign ^ y.sign + // (x is 0) || (y is 0) -> z m_simp.mk_or(x_is_zero, y_is_zero, c7); - expr_ref sign_xor(m); - m_simp.mk_xor(x_is_pos, y_is_pos, sign_xor); - mk_ite(sign_xor, nzero, pzero, v7); + expr_ref ite_c(m); + m_simp.mk_and(z_is_zero, m.mk_not(rm_is_to_neg), ite_c); + mk_ite(ite_c, pzero, z, v7); // else comes the fused multiplication. unsigned ebits = m_util.get_ebits(f->get_range()); unsigned sbits = m_util.get_sbits(f->get_range()); - SASSERT(ebits <= sbits); - - expr_ref rm_is_to_neg(m); - mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg); + SASSERT(ebits <= sbits); expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m); expr_ref b_sgn(m), b_sig(m), b_exp(m), b_lz(m); expr_ref c_sgn(m), c_sig(m), c_exp(m), c_lz(m); unpack(x, a_sgn, a_sig, a_exp, a_lz, true); unpack(y, b_sgn, b_sig, b_exp, b_lz, true); - unpack(z, c_sgn, c_sig, c_exp, c_lz, true); + unpack(z, c_sgn, c_sig, c_exp, c_lz, true); expr_ref a_lz_ext(m), b_lz_ext(m), c_lz_ext(m); a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz); @@ -1220,12 +1220,12 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar expr_ref a_sig_ext(m), b_sig_ext(m); a_sig_ext = m_bv_util.mk_zero_extend(sbits, a_sig); - b_sig_ext = m_bv_util.mk_zero_extend(sbits, b_sig); + b_sig_ext = m_bv_util.mk_zero_extend(sbits, b_sig); expr_ref a_exp_ext(m), b_exp_ext(m), c_exp_ext(m); a_exp_ext = m_bv_util.mk_sign_extend(2, a_exp); b_exp_ext = m_bv_util.mk_sign_extend(2, b_exp); - c_exp_ext = m_bv_util.mk_sign_extend(2, c_exp); + c_exp_ext = m_bv_util.mk_sign_extend(2, c_exp); dbg_decouple("fpa2bv_fma_a_sig", a_sig_ext); dbg_decouple("fpa2bv_fma_b_sig", b_sig_ext); @@ -1233,6 +1233,9 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar dbg_decouple("fpa2bv_fma_a_exp", a_exp_ext); dbg_decouple("fpa2bv_fma_b_exp", b_exp_ext); dbg_decouple("fpa2bv_fma_c_exp", c_exp_ext); + dbg_decouple("fpa2bv_fma_a_lz", a_lz_ext); + dbg_decouple("fpa2bv_fma_b_lz", b_lz_ext); + dbg_decouple("fpa2bv_fma_c_lz", c_lz_ext); expr_ref mul_sgn(m), mul_sig(m), mul_exp(m); expr * signs[2] = { a_sgn, b_sgn }; @@ -1254,6 +1257,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar // Extend c c_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(c_sig, m_bv_util.mk_numeral(0, sbits-1))); + c_exp_ext = m_bv_util.mk_bv_sub(c_exp_ext, c_lz_ext); SASSERT(m_bv_util.get_bv_size(mul_sig) == 2 * sbits); SASSERT(m_bv_util.get_bv_size(c_sig) == 2 * sbits); @@ -1269,7 +1273,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar m_simp.mk_ite(swap_cond, c_exp_ext, mul_exp, e_exp); // has ebits + 2 m_simp.mk_ite(swap_cond, mul_sgn, c_sgn, f_sgn); m_simp.mk_ite(swap_cond, mul_sig, c_sig, f_sig); // has 2 * sbits - m_simp.mk_ite(swap_cond, mul_exp, c_exp_ext, f_exp); // has ebits + 2 + m_simp.mk_ite(swap_cond, mul_exp, c_exp_ext, f_exp); // has ebits + 2 SASSERT(is_well_sorted(m, e_sgn)); SASSERT(is_well_sorted(m, e_sig)); @@ -1303,7 +1307,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar shifted_big = m_bv_util.mk_bv_lshr( m_bv_util.mk_concat(f_sig, m_bv_util.mk_numeral(0, sbits)), m_bv_util.mk_zero_extend((3*sbits)-(ebits+2), exp_delta)); - shifted_f_sig = m_bv_util.mk_zero_extend(sbits, m_bv_util.mk_extract(3*sbits-1, 2*sbits, shifted_big)); + shifted_f_sig = m_bv_util.mk_extract(3*sbits-1, sbits, shifted_big); sticky_raw = m_bv_util.mk_extract(sbits-1, 0, shifted_big); SASSERT(m_bv_util.get_bv_size(shifted_f_sig) == 2 * sbits); SASSERT(is_well_sorted(m, shifted_f_sig)); @@ -1334,7 +1338,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar expr_ref sum(m); m_simp.mk_ite(eq_sgn, - m_bv_util.mk_bv_add(e_sig, shifted_f_sig), // ADD LZ + m_bv_util.mk_bv_add(e_sig, shifted_f_sig), m_bv_util.mk_bv_sub(e_sig, shifted_f_sig), sum); @@ -1354,7 +1358,7 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar dbg_decouple("fpa2bv_fma_add_n_sum", n_sum); dbg_decouple("fpa2bv_fma_add_sig_abs", sig_abs); - res_exp = m_bv_util.mk_bv_sub(e_exp, c_lz_ext); + res_exp = e_exp; // Result could overflow into 4.xxx ... @@ -1371,8 +1375,11 @@ void fpa2bv_converter::mk_fusedma(func_decl * f, unsigned num, expr * const * ar res_sgn = m_bv_util.mk_bv_or(3, res_sgn_or_args); sticky_raw = m_bv_util.mk_extract(sbits-5, 0, sig_abs); - sticky = m_bv_util.mk_zero_extend(sbits+7, m.mk_app(bvfid, OP_BREDOR, sticky_raw.get())); - res_sig = m_bv_util.mk_extract(2*sbits-1, sbits-4, sig_abs); + sticky = m_bv_util.mk_zero_extend(sbits+3, m.mk_app(bvfid, OP_BREDOR, sticky_raw.get())); + dbg_decouple("fpa2bv_fma_add_sum_sticky", sticky); + + expr * res_or_args[2] = { m_bv_util.mk_extract(2*sbits-1, sbits-4, sig_abs), sticky }; + res_sig = m_bv_util.mk_bv_or(2, res_or_args); SASSERT(m_bv_util.get_bv_size(res_sig) == sbits+4); expr_ref is_zero_sig(m), nil_sbits4(m); @@ -2264,14 +2271,16 @@ void fpa2bv_converter::unpack(expr * e, expr_ref & sgn, expr_ref & sig, expr_ref zero_e = m_bv_util.mk_numeral(0, ebits); if (normalize) { + expr_ref is_sig_zero(m), zero_s(m); + zero_s = m_bv_util.mk_numeral(0, sbits); + m_simp.mk_eq(zero_s, denormal_sig, is_sig_zero); + expr_ref lz_d(m); - mk_leading_zeros(denormal_sig, ebits, lz_d); - m_simp.mk_ite(is_normal, zero_e, lz_d, lz); + mk_leading_zeros(denormal_sig, ebits, lz_d); + m_simp.mk_ite(m.mk_or(is_normal, is_sig_zero), zero_e, lz_d, lz); dbg_decouple("fpa2bv_unpack_lz", lz); - expr_ref is_sig_zero(m), shift(m), zero_s(m); - zero_s = m_bv_util.mk_numeral(0, sbits); - m_simp.mk_eq(zero_s, denormal_sig, is_sig_zero); + expr_ref shift(m); m_simp.mk_ite(is_sig_zero, zero_e, lz, shift); dbg_decouple("fpa2bv_unpack_shift", shift); SASSERT(is_well_sorted(m, is_sig_zero)); From f238720b768ad9262dc7976c907672383195afe7 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 27 Jun 2013 09:19:23 -0700 Subject: [PATCH 200/281] Cherry-pick goodies from mcsat branch Signed-off-by: Leonardo de Moura --- src/ast/ast_util.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++ src/ast/ast_util.h | 31 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/ast/ast_util.cpp b/src/ast/ast_util.cpp index 8b0b3fa04..d77deca01 100644 --- a/src/ast/ast_util.cpp +++ b/src/ast/ast_util.cpp @@ -1,3 +1,21 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + ast_util.cpp + +Abstract: + + Helper functions + +Author: + + Leonardo de Moura (leonardo) 2007-06-08. + +Revision History: + +--*/ #include "ast_util.h" app * mk_list_assoc_app(ast_manager & m, func_decl * f, unsigned num_args, expr * const * args) { @@ -138,3 +156,38 @@ expr * get_clause_literal(ast_manager & m, expr * cls, unsigned idx) { SASSERT(m.is_or(cls)); return to_app(cls)->get_arg(idx); } + +expr * mk_and(ast_manager & m, unsigned num_args, expr * const * args) { + if (num_args == 0) + return m.mk_true(); + else if (num_args == 1) + return args[0]; + else + return m.mk_and(num_args, args); +} + +expr * mk_or(ast_manager & m, unsigned num_args, expr * const * args) { + if (num_args == 0) + return m.mk_false(); + else if (num_args == 1) + return args[0]; + else + return m.mk_or(num_args, args); +} + +expr * mk_not(ast_manager & m, expr * arg) { + expr * atom; + if (m.is_not(arg, atom)) + return atom; + else + return m.mk_not(arg); +} + +expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args) { + expr_ref_buffer new_diseqs(m); + for (unsigned i = 0; i < num_args; i++) { + for (unsigned j = i + 1; j < num_args; j++) + new_diseqs.push_back(m.mk_not(m.mk_eq(args[i], args[j]))); + } + return mk_and(m, new_diseqs.size(), new_diseqs.c_ptr()); +} diff --git a/src/ast/ast_util.h b/src/ast/ast_util.h index c7f54da01..1e813b1b0 100644 --- a/src/ast/ast_util.h +++ b/src/ast/ast_util.h @@ -95,5 +95,36 @@ bool is_clause(ast_manager & m, expr * n); unsigned get_clause_num_literals(ast_manager & m, expr * cls); expr * get_clause_literal(ast_manager & m, expr * cls, unsigned idx); +// ----------------------------------- +// +// Goodies for creating Boolean expressions +// +// ----------------------------------- + +/** + Return (and args[0] ... args[num_args-1]) if num_args >= 2 + Return args[0] if num_args == 1 + Return true if num_args == 0 + */ +expr * mk_and(ast_manager & m, unsigned num_args, expr * const * args); + +/** + Return (or args[0] ... args[num_args-1]) if num_args >= 2 + Return args[0] if num_args == 1 + Return false if num_args == 0 + */ +expr * mk_or(ast_manager & m, unsigned num_args, expr * const * args); + +/** + Return a if arg = (not a) + Retur (not arg) otherwise + */ +expr * mk_not(ast_manager & m, expr * arg); + +/** + Return the expression (and (not (= args[0] args[1])) (not (= args[0] args[2])) ... (not (= args[num_args-2] args[num_args-1]))) +*/ +expr * expand_distinct(ast_manager & m, unsigned num_args, expr * const * args); + #endif /* _AST_UTIL_H_ */ From 5b7201a911a0e5f0e4efabc143ebac4be6e41c13 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Thu, 27 Jun 2013 09:30:25 -0700 Subject: [PATCH 201/281] Fix minor problem Signed-off-by: Leonardo de Moura --- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index 5668ca455..63c14f297 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -23,7 +23,7 @@ Notes: #include"smt_kernel.h" #include"ast_pp.h" #include"mk_simplified_app.h" - +#include"ast_util.h" class ctx_solver_simplify_tactic : public tactic { ast_manager& m; @@ -104,7 +104,7 @@ protected: return; ptr_vector fmls; g.get_formulas(fmls); - fml = m.mk_and(fmls.size(), fmls.c_ptr()); + fml = mk_and(m, fmls.size(), fmls.c_ptr()); m_solver.push(); reduce(fml); m_solver.pop(1); @@ -119,7 +119,7 @@ protected: { m_solver.push(); expr_ref fml1(m); - fml1 = m.mk_and(fmls.size(), fmls.c_ptr()); + fml1 = mk_and(m, fmls.size(), fmls.c_ptr()); fml1 = m.mk_iff(fml, fml1); fml1 = m.mk_not(fml1); m_solver.assert_expr(fml1); From 619bd91ddb30c6b6283409be567336ee390e692d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 27 Jun 2013 11:59:40 -0500 Subject: [PATCH 202/281] fix bug in ctx-solver-simplify reported @ http://z3.codeplex.com/workitem/51 Signed-off-by: Nikolaj Bjorner --- src/smt/tactic/ctx_solver_simplify_tactic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/tactic/ctx_solver_simplify_tactic.cpp b/src/smt/tactic/ctx_solver_simplify_tactic.cpp index 5668ca455..626cb6d22 100644 --- a/src/smt/tactic/ctx_solver_simplify_tactic.cpp +++ b/src/smt/tactic/ctx_solver_simplify_tactic.cpp @@ -218,7 +218,7 @@ protected: else if (m.is_bool(arg)) { res = local_simplify(a, n, id, i); TRACE("ctx_solver_simplify_tactic", - tout << "Already cached: " << path_r.first << " " << mk_pp(res, m) << "\n";); + tout << "Already cached: " << path_r.first << " " << mk_pp(arg, m) << " |-> " << mk_pp(res, m) << "\n";); args.push_back(res); } else { @@ -327,7 +327,7 @@ protected: tmp = m.mk_eq(result, n); m_solver.assert_expr(tmp); if (!simplify_bool(n2, result)) { - result = a; + result = a->get_arg(index); } m_solver.pop(1); return result; From 4f72e1d5289b5afce868377a286e7f325f65e0f0 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 28 Jun 2013 12:14:14 +0100 Subject: [PATCH 203/281] FPA: avoid compiler warnings. Signed-off-by: Christoph M. Wintersteiger --- src/tactic/fpa/fpa2bv_converter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tactic/fpa/fpa2bv_converter.cpp b/src/tactic/fpa/fpa2bv_converter.cpp index 234c343b8..ff24d1ceb 100644 --- a/src/tactic/fpa/fpa2bv_converter.cpp +++ b/src/tactic/fpa/fpa2bv_converter.cpp @@ -2437,7 +2437,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & t = m_bv_util.mk_bv_sub(t, lz); t = m_bv_util.mk_bv_sub(t, m_bv_util.mk_sign_extend(2, e_min)); expr_ref TINY(m); - TINY = m_bv_util.mk_sle(t, m_bv_util.mk_numeral(-1, ebits+2)); + TINY = m_bv_util.mk_sle(t, m_bv_util.mk_numeral((unsigned)-1, ebits+2)); TRACE("fpa2bv_dbg", tout << "TINY = " << mk_ismt2_pp(TINY, m) << std::endl;); SASSERT(is_well_sorted(m, TINY)); @@ -2481,7 +2481,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & m_simp.mk_ite(sigma_le_cap, sigma_neg, sigma_cap, sigma_neg_capped); dbg_decouple("fpa2bv_rnd_sigma_neg", sigma_neg); dbg_decouple("fpa2bv_rnd_sigma_neg_capped", sigma_neg_capped); - sigma_lt_zero = m_bv_util.mk_sle(sigma, m_bv_util.mk_numeral(-1, sigma_size)); + sigma_lt_zero = m_bv_util.mk_sle(sigma, m_bv_util.mk_numeral((unsigned)-1, sigma_size)); dbg_decouple("fpa2bv_rnd_sigma_lt_zero", sigma_lt_zero); sig_ext = m_bv_util.mk_concat(sig, m_bv_util.mk_numeral(0, sig_size)); From d9941c0ccc871881d4bbc1625bfdc005d4618ae8 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Fri, 28 Jun 2013 19:21:27 -0700 Subject: [PATCH 204/281] Add code for rejecting bitvector constants of size 0 Signed-off-by: Leonardo de Moura --- src/ast/bv_decl_plugin.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 8b77244f9..f1c61619a 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -210,6 +210,10 @@ func_decl * bv_decl_plugin::mk_unary(ptr_vector & decls, decl_kind k, func_decl * bv_decl_plugin::mk_int2bv(unsigned bv_size, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain) { + if (bv_size == 0) { + m_manager->raise_exception("bit-vector size must be greater than zero"); + } + force_ptr_array_size(m_int2bv, bv_size + 1); if (arity != 1) { @@ -415,6 +419,9 @@ func_decl * bv_decl_plugin::mk_num_decl(unsigned num_parameters, parameter const return 0; } unsigned bv_size = parameters[1].get_int(); + if (bv_size == 0) { + m_manager->raise_exception("bit-vector size must be greater than zero"); + } // TODO: sign an error if the parameters[0] is out of range, that is, it is a value not in [0, 2^{bv_size}) // This cannot be enforced now, since some Z3 modules try to generate these invalid numerals. // After SMT-COMP, I should find all offending modules. From 210bca8f456361f696152be909e33a4e8b58607f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 2 Jul 2013 12:57:54 +0100 Subject: [PATCH 205/281] .NET Example: Sudoku example bugfix. Many thanks to Ilya Mironov for reporting this issue. Signed-off-by: Christoph M. Wintersteiger --- examples/dotnet/Program.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 2085de296..4361cab96 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -474,7 +474,7 @@ namespace test_mapi cells_c[i] = new BoolExpr[9]; for (uint j = 0; j < 9; j++) cells_c[i][j] = ctx.MkAnd(ctx.MkLe(ctx.MkInt(1), X[i][j]), - ctx.MkLe(X[i][j], ctx.MkInt(9))); + ctx.MkLe(X[i][j], ctx.MkInt(9))); } // each row contains a digit at most once @@ -485,7 +485,13 @@ namespace test_mapi // each column contains a digit at most once BoolExpr[] cols_c = new BoolExpr[9]; for (uint j = 0; j < 9; j++) - cols_c[j] = ctx.MkDistinct(X[j]); + { + IntExpr[] column = new IntExpr[9]; + for (uint i = 0; i < 9; i++) + column[i] = X[i][j]; + + cols_c[j] = ctx.MkDistinct(column); + } // each 3x3 square contains a digit at most once BoolExpr[][] sq_c = new BoolExpr[3][]; @@ -2087,7 +2093,7 @@ namespace test_mapi { QuantifierExample3(ctx); QuantifierExample4(ctx); - } + } Log.Close(); if (Log.isOpen()) From ccb36f1ae7121a895c75500998a9d6e219108e0e Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 9 Jul 2013 08:22:17 -0700 Subject: [PATCH 206/281] Fix issue https://z3.codeplex.com/workitem/54 Signed-off-by: Leonardo de Moura --- src/api/c++/z3++.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index a255c2d97..6f745d620 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1305,7 +1305,7 @@ namespace z3 { expr as_expr() const { unsigned n = size(); if (n == 0) - return ctx().bool_val(false); + return ctx().bool_val(true); else if (n == 1) return operator[](0); else { From 784455d1fc4d7d734ab6ee35dd33bee48b176de4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 10 Jul 2013 17:20:44 +0300 Subject: [PATCH 207/281] detect approximate relations to return unknown, fix product relations, fix symbolic magic set transformation Signed-off-by: Nikolaj Bjorner --- src/api/api_datalog.cpp | 206 +++++++++++++++------------ src/api/api_datalog.h | 36 +---- src/muz_qe/dl_base.h | 3 +- src/muz_qe/dl_bound_relation.cpp | 5 +- src/muz_qe/dl_bound_relation.h | 2 + src/muz_qe/dl_cmds.cpp | 6 +- src/muz_qe/dl_context.cpp | 3 +- src/muz_qe/dl_context.h | 1 + src/muz_qe/dl_instruction.cpp | 7 +- src/muz_qe/dl_interval_relation.cpp | 3 +- src/muz_qe/dl_interval_relation.h | 1 + src/muz_qe/dl_mk_karr_invariants.cpp | 2 + src/muz_qe/dl_mk_karr_invariants.h | 1 + src/muz_qe/dl_mk_magic_symbolic.cpp | 4 +- src/muz_qe/dl_product_relation.cpp | 6 +- src/muz_qe/dl_product_relation.h | 10 ++ src/muz_qe/dl_relation_manager.cpp | 18 +-- src/muz_qe/rel_context.cpp | 23 ++- 18 files changed, 182 insertions(+), 155 deletions(-) diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index bf4752645..64b8b064e 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -29,107 +29,123 @@ Revision History: #include"dl_cmds.h" #include"cmd_context.h" #include"smt2parser.h" +#include"dl_context.h" +#include"dl_external_relation.h" +#include"dl_decl_plugin.h" namespace api { - - fixedpoint_context::fixedpoint_context(ast_manager& m, smt_params& p) : - m_state(0), - m_reduce_app(0), - m_reduce_assign(0), - m_context(m, p), - m_trail(m) {} - - - void fixedpoint_context::set_state(void* state) { - SASSERT(!m_state); - m_state = state; - symbol name("datalog_relation"); - ast_manager& m = m_context.get_manager(); - if (!m.has_plugin(name)) { - m.register_plugin(name, alloc(datalog::dl_decl_plugin)); - } - datalog::rel_context* rel = m_context.get_rel_context(); - if (rel) { - datalog::relation_manager& r = rel->get_rmanager(); - r.register_plugin(alloc(datalog::external_relation_plugin, *this, r)); - } - } - - void fixedpoint_context::reduce(func_decl* f, unsigned num_args, expr * const* args, expr_ref& result) { - expr* r = 0; - if (m_reduce_app) { - m_reduce_app(m_state, f, num_args, args, &r); - result = r; - m_trail.push_back(f); - for (unsigned i = 0; i < num_args; ++i) { - m_trail.push_back(args[i]); - } - m_trail.push_back(r); - } - // allow fallthrough. - if (r == 0) { + + class fixedpoint_context : public datalog::external_relation_context { + void * m_state; + reduce_app_callback_fptr m_reduce_app; + reduce_assign_callback_fptr m_reduce_assign; + datalog::context m_context; + ast_ref_vector m_trail; + public: + fixedpoint_context(ast_manager& m, smt_params& p): + m_state(0), + m_reduce_app(0), + m_reduce_assign(0), + m_context(m, p), + m_trail(m) {} + + virtual ~fixedpoint_context() {} + family_id get_family_id() const { return const_cast(m_context).get_decl_util().get_family_id(); } + void set_state(void* state) { + SASSERT(!m_state); + m_state = state; + symbol name("datalog_relation"); ast_manager& m = m_context.get_manager(); - result = m.mk_app(f, num_args, args); - } - } - - // overwrite terms passed in outs vector with values computed by function. - void fixedpoint_context::reduce_assign(func_decl* f, unsigned num_args, expr * const* args, unsigned num_out, expr* const* outs) { - if (m_reduce_assign) { - m_trail.push_back(f); - for (unsigned i = 0; i < num_args; ++i) { - m_trail.push_back(args[i]); + if (!m.has_plugin(name)) { + m.register_plugin(name, alloc(datalog::dl_decl_plugin)); + } + datalog::rel_context* rel = m_context.get_rel_context(); + if (rel) { + datalog::relation_manager& r = rel->get_rmanager(); + r.register_plugin(alloc(datalog::external_relation_plugin, *this, r)); } - m_reduce_assign(m_state, f, num_args, args, num_out, outs); } - } - - - void fixedpoint_context::add_rule(expr* rule, symbol const& name) { - m_context.add_rule(rule, name); - } - - void fixedpoint_context::update_rule(expr* rule, symbol const& name) { - m_context.update_rule(rule, name); - } - - void fixedpoint_context::add_table_fact(func_decl* r, unsigned num_args, unsigned args[]) { - m_context.add_table_fact(r, num_args, args); - } - - unsigned fixedpoint_context::get_num_levels(func_decl* pred) { - return m_context.get_num_levels(pred); - } - - expr_ref fixedpoint_context::get_cover_delta(int level, func_decl* pred) { - return m_context.get_cover_delta(level, pred); - } - - void fixedpoint_context::add_cover(int level, func_decl* pred, expr* predicate) { - m_context.add_cover(level, pred, predicate); - } - - std::string fixedpoint_context::get_last_status() { - datalog::execution_result status = m_context.get_status(); - switch(status) { - case datalog::INPUT_ERROR: - return "input error"; - case datalog::OK: - return "ok"; - case datalog::TIMEOUT: - return "timeout"; - default: - UNREACHABLE(); - return "unknown"; + void set_reduce_app(reduce_app_callback_fptr f) { + m_reduce_app = f; } - } - - std::string fixedpoint_context::to_string(unsigned num_queries, expr*const* queries) { - std::stringstream str; - m_context.display_smt2(num_queries, queries, str); - return str.str(); - } - + void set_reduce_assign(reduce_assign_callback_fptr f) { + m_reduce_assign = f; + } + virtual void reduce(func_decl* f, unsigned num_args, expr * const* args, expr_ref& result) { + expr* r = 0; + if (m_reduce_app) { + m_reduce_app(m_state, f, num_args, args, &r); + result = r; + m_trail.push_back(f); + for (unsigned i = 0; i < num_args; ++i) { + m_trail.push_back(args[i]); + } + m_trail.push_back(r); + } + // allow fallthrough. + if (r == 0) { + ast_manager& m = m_context.get_manager(); + result = m.mk_app(f, num_args, args); + } + } + virtual void reduce_assign(func_decl* f, unsigned num_args, expr * const* args, unsigned num_out, expr* const* outs) { + if (m_reduce_assign) { + m_trail.push_back(f); + for (unsigned i = 0; i < num_args; ++i) { + m_trail.push_back(args[i]); + } + m_reduce_assign(m_state, f, num_args, args, num_out, outs); + } + } + datalog::context& ctx() { return m_context; } + void add_rule(expr* rule, symbol const& name) { + m_context.add_rule(rule, name); + } + void update_rule(expr* rule, symbol const& name) { + m_context.update_rule(rule, name); + } + void add_table_fact(func_decl* r, unsigned num_args, unsigned args[]) { + m_context.add_table_fact(r, num_args, args); + } + std::string get_last_status() { + datalog::execution_result status = m_context.get_status(); + switch(status) { + case datalog::INPUT_ERROR: + return "input error"; + case datalog::OK: + return "ok"; + case datalog::TIMEOUT: + return "timeout"; + case datalog::APPROX: + return "approximated"; + default: + UNREACHABLE(); + return "unknown"; + } + } + std::string to_string(unsigned num_queries, expr*const* queries) { + std::stringstream str; + m_context.display_smt2(num_queries, queries, str); + return str.str(); + } + void cancel() { + m_context.cancel(); + } + void reset_cancel() { + m_context.reset_cancel(); + } + unsigned get_num_levels(func_decl* pred) { + return m_context.get_num_levels(pred); + } + expr_ref get_cover_delta(int level, func_decl* pred) { + return m_context.get_cover_delta(level, pred); + } + void add_cover(int level, func_decl* pred, expr* predicate) { + m_context.add_cover(level, pred, predicate); + } + void collect_param_descrs(param_descrs & p) { m_context.collect_params(p); } + void updt_params(params_ref const& p) { m_context.updt_params(p); } + }; }; extern "C" { diff --git a/src/api/api_datalog.h b/src/api/api_datalog.h index 51dbb72ec..f5bfada33 100644 --- a/src/api/api_datalog.h +++ b/src/api/api_datalog.h @@ -22,48 +22,14 @@ Revision History: #include"z3.h" #include"ast.h" #include"smt_params.h" -#include"dl_external_relation.h" -#include"dl_decl_plugin.h" #include"smt_kernel.h" #include"api_util.h" -#include"dl_context.h" typedef void (*reduce_app_callback_fptr)(void*, func_decl*, unsigned, expr*const*, expr**); typedef void (*reduce_assign_callback_fptr)(void*, func_decl*, unsigned, expr*const*, unsigned, expr*const*); namespace api { - - class fixedpoint_context : public datalog::external_relation_context { - void * m_state; - reduce_app_callback_fptr m_reduce_app; - reduce_assign_callback_fptr m_reduce_assign; - datalog::context m_context; - ast_ref_vector m_trail; - public: - fixedpoint_context(ast_manager& m, smt_params& p); - virtual ~fixedpoint_context() {} - family_id get_family_id() const { return const_cast(m_context).get_decl_util().get_family_id(); } - void set_state(void* state); - void set_reduce_app(reduce_app_callback_fptr f) { m_reduce_app = f; } - void set_reduce_assign(reduce_assign_callback_fptr f) { m_reduce_assign = f; } - virtual void reduce(func_decl* f, unsigned num_args, expr * const* args, expr_ref& result); - virtual void reduce_assign(func_decl* f, unsigned num_args, expr * const* args, unsigned num_out, expr* const* outs); - datalog::context& ctx() { return m_context; } - void add_rule(expr* rule, symbol const& name); - void update_rule(expr* rule, symbol const& name); - void add_table_fact(func_decl* r, unsigned num_args, unsigned args[]); - std::string get_last_status(); - std::string to_string(unsigned num_queries, expr*const* queries); - void cancel() { m_context.cancel(); } - void reset_cancel() { m_context.reset_cancel(); } - - unsigned get_num_levels(func_decl* pred); - expr_ref get_cover_delta(int level, func_decl* pred); - void add_cover(int level, func_decl* pred, expr* predicate); - void collect_param_descrs(param_descrs & p) { m_context.collect_params(p); } - void updt_params(params_ref const& p) { m_context.updt_params(p); } - - }; + class fixedpoint_context; }; diff --git a/src/muz_qe/dl_base.h b/src/muz_qe/dl_base.h index 200ce2d83..f9078c2f2 100644 --- a/src/muz_qe/dl_base.h +++ b/src/muz_qe/dl_base.h @@ -776,7 +776,7 @@ namespace datalog { bool is_finite_product_relation() const { return m_special_type==ST_FINITE_PRODUCT_RELATION; } bool is_product_relation() const { return m_special_type==ST_PRODUCT_RELATION; } bool is_sieve_relation() const { return m_special_type==ST_SIEVE_RELATION; } - + /** \brief If true, the relation can contain only one or zero elements. @@ -805,6 +805,7 @@ namespace datalog { virtual void to_formula(expr_ref& fml) const = 0; bool from_table() const { return get_plugin().from_table(); } + virtual bool is_precise() const { return true; } }; typedef ptr_vector relation_vector; diff --git a/src/muz_qe/dl_bound_relation.cpp b/src/muz_qe/dl_bound_relation.cpp index 0c76e8e1e..182046c1e 100644 --- a/src/muz_qe/dl_bound_relation.cpp +++ b/src/muz_qe/dl_bound_relation.cpp @@ -677,7 +677,7 @@ namespace datalog { void bound_relation::display_index(unsigned i, uint_set2 const& src, std::ostream & out) const { uint_set::iterator it = src.lt.begin(), end = src.lt.end(); - out << i; + out << "#" << i; if (!src.lt.empty()) { out << " < "; for(; it != end; ++it) { @@ -691,6 +691,9 @@ namespace datalog { out << *it << " "; } } + if (src.lt.empty() && src.le.empty()) { + out << " < oo"; + } out << "\n"; } diff --git a/src/muz_qe/dl_bound_relation.h b/src/muz_qe/dl_bound_relation.h index 603717bd8..04479b3b6 100644 --- a/src/muz_qe/dl_bound_relation.h +++ b/src/muz_qe/dl_bound_relation.h @@ -69,6 +69,7 @@ namespace datalog { unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, const unsigned * removed_cols) { return 0; } + #if 0 virtual intersection_filter_fn * mk_filter_by_intersection_fn( const relation_base & t, @@ -138,6 +139,7 @@ namespace datalog { bool is_lt(unsigned i, unsigned j) const; + virtual bool is_precise() const { return false; } private: typedef uint_set2 T; diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz_qe/dl_cmds.cpp index 693105e6e..dcdf3ebb4 100644 --- a/src/muz_qe/dl_cmds.cpp +++ b/src/muz_qe/dl_cmds.cpp @@ -260,7 +260,11 @@ public: case datalog::TIMEOUT: ctx.regular_stream() << "timeout\n"; break; - + + case datalog::APPROX: + ctx.regular_stream() << "approximated relations\n"; + break; + case datalog::OK: UNREACHABLE(); break; diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 2627cbbec..e44d10c78 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -434,7 +434,8 @@ namespace datalog { void context::set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, symbol const * relation_names) { - if (m_rel && relation_name_cnt > 0) { + ensure_engine(); + if (relation_name_cnt > 0 && m_rel) { m_rel->set_predicate_representation(pred, relation_name_cnt, relation_names); } } diff --git a/src/muz_qe/dl_context.h b/src/muz_qe/dl_context.h index c54f7d591..a3c7e583c 100644 --- a/src/muz_qe/dl_context.h +++ b/src/muz_qe/dl_context.h @@ -56,6 +56,7 @@ namespace datalog { TIMEOUT, MEMOUT, INPUT_ERROR, + APPROX, CANCELED }; diff --git a/src/muz_qe/dl_instruction.cpp b/src/muz_qe/dl_instruction.cpp index df4736b8e..55327f55b 100644 --- a/src/muz_qe/dl_instruction.cpp +++ b/src/muz_qe/dl_instruction.cpp @@ -494,6 +494,7 @@ namespace datalog { relation_mutator_fn * fn; relation_base & r = *ctx.reg(m_reg); + TRACE("dl_verbose", r.display(tout <<"pre-filter-interpreted:\n");); if (!find_fn(r, fn)) { fn = r.get_manager().mk_filter_interpreted_fn(r, m_cond); if (!fn) { @@ -507,7 +508,9 @@ namespace datalog { if (ctx.eager_emptiness_checking() && r.empty()) { ctx.make_empty(m_reg); - } + } + TRACE("dl_verbose", r.display(tout <<"post-filter-interpreted:\n");); + return true; } virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const { @@ -545,6 +548,7 @@ namespace datalog { relation_transformer_fn * fn; relation_base & reg = *ctx.reg(m_src); + TRACE("dl_verbose", reg.display(tout <<"pre-filter-interpreted-and-project:\n");); if (!find_fn(reg, fn)) { fn = reg.get_manager().mk_filter_interpreted_and_project_fn(reg, m_cond, m_cols.size(), m_cols.c_ptr()); if (!fn) { @@ -560,6 +564,7 @@ namespace datalog { if (ctx.eager_emptiness_checking() && ctx.reg(m_res)->empty()) { ctx.make_empty(m_res); } + TRACE("dl_verbose", reg.display(tout << "post-filter-interpreted-and-project:\n");); return true; } diff --git a/src/muz_qe/dl_interval_relation.cpp b/src/muz_qe/dl_interval_relation.cpp index 4c8171bc7..adc8cb760 100644 --- a/src/muz_qe/dl_interval_relation.cpp +++ b/src/muz_qe/dl_interval_relation.cpp @@ -48,7 +48,7 @@ namespace datalog { return alloc(interval_relation, *this, s, true); } - relation_base * interval_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { + relation_base * interval_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { return alloc(interval_relation, *this, s, false); } @@ -317,6 +317,7 @@ namespace datalog { interval_relation::interval_relation(interval_relation_plugin& p, relation_signature const& s, bool is_empty): vector_relation(p, s, is_empty, interval(p.dep())) { + TRACE("interval_relation", tout << s.size() << "\n";); } void interval_relation::add_fact(const relation_fact & f) { diff --git a/src/muz_qe/dl_interval_relation.h b/src/muz_qe/dl_interval_relation.h index 1a25f430f..685ef5c86 100644 --- a/src/muz_qe/dl_interval_relation.h +++ b/src/muz_qe/dl_interval_relation.h @@ -104,6 +104,7 @@ namespace datalog { interval_relation_plugin& get_plugin() const; void filter_interpreted(app* cond); + virtual bool is_precise() const { return false; } private: diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz_qe/dl_mk_karr_invariants.cpp index 4987a7e3d..e4e5a1ff8 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz_qe/dl_mk_karr_invariants.cpp @@ -355,6 +355,8 @@ namespace datalog { return m_empty; } + virtual bool is_precise() const { return false; } + virtual void add_fact(const relation_fact & f) { SASSERT(m_empty); SASSERT(!m_basis_valid); diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz_qe/dl_mk_karr_invariants.h index 3d993e60a..a86f726ef 100644 --- a/src/muz_qe/dl_mk_karr_invariants.h +++ b/src/muz_qe/dl_mk_karr_invariants.h @@ -123,6 +123,7 @@ namespace datalog { virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, unsigned col); virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + private: bool dualizeI(matrix& dst, matrix const& src); void dualizeH(matrix& dst, matrix const& src); diff --git a/src/muz_qe/dl_mk_magic_symbolic.cpp b/src/muz_qe/dl_mk_magic_symbolic.cpp index 2820ecaef..a06a573ad 100644 --- a/src/muz_qe/dl_mk_magic_symbolic.cpp +++ b/src/muz_qe/dl_mk_magic_symbolic.cpp @@ -95,11 +95,13 @@ namespace datalog { neg.push_back(false); } new_rule = rm.mk(mk_ans(r.get_head()), tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + result->add_rule(new_rule); if (source.is_output_predicate(r.get_decl())) { result->set_output_predicate(new_rule->get_decl()); + new_rule = rm.mk(mk_query(r.get_head()), 0, 0, 0, r.name(), true); + result->add_rule(new_rule); } - result->add_rule(new_rule); for (unsigned j = 0; j < utsz; ++j) { new_rule = rm.mk(mk_query(r.get_tail(j)), tail.size()-utsz+j, tail.c_ptr(), neg.c_ptr(), r.name(), true); result->add_rule(new_rule); diff --git a/src/muz_qe/dl_product_relation.cpp b/src/muz_qe/dl_product_relation.cpp index c10b5799a..48cd666e6 100644 --- a/src/muz_qe/dl_product_relation.cpp +++ b/src/muz_qe/dl_product_relation.cpp @@ -174,8 +174,7 @@ namespace datalog { relation_base * product_relation_plugin::mk_empty(const relation_signature & s, family_id kind) { rel_spec spec; - relation_signature sig_empty; - m_spec_store.get_relation_spec(sig_empty, kind, spec); + m_spec_store.get_relation_spec(s, kind, spec); relation_vector inner_rels; unsigned rel_cnt = spec.size(); for(unsigned i=0; iis_precise()) { + return false; + } + } + return true; + } }; }; diff --git a/src/muz_qe/dl_relation_manager.cpp b/src/muz_qe/dl_relation_manager.cpp index 812531e67..457ef28c0 100644 --- a/src/muz_qe/dl_relation_manager.cpp +++ b/src/muz_qe/dl_relation_manager.cpp @@ -80,12 +80,6 @@ namespace datalog { if(m_pred_kinds.find(pred, res)) { return res; } - //This is commented out as the favourite relation might not be suitable for all - //signatures. In the cases where it is suitable, it will be used anyway if we - //now return null_family_id. - //else if (m_favourite_relation_plugin) { - // return m_favourite_relation_plugin->get_kind(); - //} else { return null_family_id; } @@ -115,7 +109,7 @@ namespace datalog { void relation_manager::store_relation(func_decl * pred, relation_base * rel) { SASSERT(rel); relation_map::entry * e = m_relations.insert_if_not_there2(pred, 0); - if(e->get_data().m_value) { + if (e->get_data().m_value) { e->get_data().m_value->deallocate(); } else { @@ -142,7 +136,7 @@ namespace datalog { relation_map::iterator rend = m_relations.end(); for(; rit!=rend; ++rit) { func_decl * pred = rit->m_key; - if(!preds.contains(pred)) { + if (!preds.contains(pred)) { to_remove.insert(pred); } } @@ -152,7 +146,7 @@ namespace datalog { for(; pit!=pend; ++pit) { func_decl * pred = *pit; relation_base * rel; - TRUSTME( m_relations.find(pred, rel) ); + VERIFY( m_relations.find(pred, rel) ); rel->deallocate(); m_relations.remove(pred); get_context().get_manager().dec_ref(pred); @@ -278,7 +272,7 @@ namespace datalog { SASSERT(kind>=0); SASSERT(kindget_num_args()==0); - TRUSTME(get_context().get_decl_util().is_numeral_ext(from, to)); + VERIFY(get_context().get_decl_util().is_numeral_ext(from, to)); } void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from, diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index 4ebcbf2fd..ce1b30b88 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -213,17 +213,25 @@ namespace datalog { expr_ref_vector ans(m); expr_ref e(m); bool some_non_empty = num_rels == 0; + bool is_approx = false; for (unsigned i = 0; i < num_rels; ++i) { relation_base& rel = get_relation(rels[i]); if (!rel.empty()) { some_non_empty = true; } + if (!rel.is_precise()) { + is_approx = true; + } rel.to_formula(e); ans.push_back(e); } SASSERT(!m_last_result_relation); if (some_non_empty) { m_answer = m.mk_and(ans.size(), ans.c_ptr()); + if (is_approx) { + res = l_undef; + m_context.set_status(APPROX); + } } else { m_answer = m.mk_false(); @@ -278,6 +286,10 @@ namespace datalog { } else { m_last_result_relation->to_formula(m_answer); + if (!m_last_result_relation->is_precise()) { + m_context.set_status(APPROX); + res = l_undef; + } } } @@ -365,8 +377,15 @@ namespace datalog { void rel_context::set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, symbol const * relation_names) { - relation_manager & rmgr = get_rmanager(); + TRACE("dl", + tout << pred->get_name() << ": "; + for (unsigned i = 0; i < relation_name_cnt; ++i) { + tout << relation_names[i] << " "; + } + tout << "\n"; + ); + relation_manager & rmgr = get_rmanager(); family_id target_kind = null_family_id; switch (relation_name_cnt) { case 0: @@ -386,7 +405,7 @@ namespace datalog { } else { relation_signature rel_sig; - //rmgr.from_predicate(pred, rel_sig); + rmgr.from_predicate(pred, rel_sig); product_relation_plugin & prod_plugin = product_relation_plugin::get_plugin(rmgr); rel_kind = prod_plugin.get_relation_kind(rel_sig, rel_kinds); } From 6ce0e7cf2562111d6bd03eed12abe531a70f7db6 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 15 Jul 2013 12:22:01 +0100 Subject: [PATCH 208/281] .NET build changes to include /linkresource Signed-off-by: Christoph M. Wintersteiger --- scripts/mk_util.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 38213a88b..59122af32 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1089,20 +1089,19 @@ class DotNetDLLComponent(Component): cs_fp_files.append(os.path.join(self.to_src_dir, self.assembly_info_dir, cs_file)) cs_files.append(os.path.join(self.assembly_info_dir, cs_file)) dllfile = '%s.dll' % self.dll_name - out.write('%s:' % dllfile) + out.write('%s: %s$(SO_EXT)' % (dllfile, get_component(Z3_DLL_COMPONENT).dll_name)) for cs_file in cs_fp_files: out.write(' ') out.write(cs_file) out.write('\n') - out.write(' cd %s && csc /noconfig /unsafe+ /nowarn:1701,1702 /nostdlib+ /errorreport:prompt /warn:4 /define:DEBUG;TRACE /reference:mscorlib.dll /reference:System.Core.dll /reference:System.dll /reference:System.Numerics.dll /debug+ /debug:full /filealign:512 /optimize- /out:%s.dll /target:library' % (self.to_src_dir, self.dll_name)) + out.write(' csc /noconfig /unsafe+ /nowarn:1701,1702 /nostdlib+ /errorreport:prompt /warn:4 /define:DEBUG;TRACE /reference:mscorlib.dll /reference:System.Core.dll /reference:System.dll /reference:System.Numerics.dll /debug+ /debug:full /filealign:512 /optimize- /linkresource:%s.dll /out:%s.dll /target:library' % (get_component(Z3_DLL_COMPONENT).dll_name, self.dll_name)) + if VS_X64: + out.write(' /platform:x64') + else: + out.write(' /platform:x86') for cs_file in cs_files: - out.write(' ') - out.write(cs_file) + out.write(' %s' % os.path.join(self.to_src_dir, cs_file)) out.write('\n') - # HACK - win_to_src_dir = self.to_src_dir.replace('/', '\\') - out.write(' move %s\n' % os.path.join(win_to_src_dir, dllfile)) - out.write(' move %s.pdb\n' % os.path.join(win_to_src_dir, self.dll_name)) out.write('%s: %s\n\n' % (self.name, dllfile)) return From f1d3a13b7f80ed84433c9890de3aa37484deff5e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Jul 2013 11:46:29 +0400 Subject: [PATCH 209/281] add missing case handlers for internal bit-vector operators that leak during simplification Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 6855f6209..293983c9a 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -1073,6 +1073,12 @@ extern "C" { 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; default: UNREACHABLE(); From 0cd3c3364bf3ad7fbcfa67b09778d1ade3e6b6ff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Jul 2013 23:42:50 +0400 Subject: [PATCH 210/281] add control over Farkas parameter for Arie Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_context.cpp | 4 +++- src/muz_qe/pdr_context.cpp | 6 +++--- src/muz_qe/pdr_context.h | 2 ++ src/muz_qe/pdr_generalizers.cpp | 2 ++ src/muz_qe/pdr_prop_solver.cpp | 7 ++++++- src/muz_qe/pdr_prop_solver.h | 3 +++ 6 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index e44d10c78..34513cc76 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -434,7 +434,9 @@ namespace datalog { void context::set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, symbol const * relation_names) { - ensure_engine(); + if (relation_name_cnt > 0) { + ensure_engine(); + } if (relation_name_cnt > 0 && m_rel) { m_rel->set_predicate_representation(pred, relation_name_cnt, relation_names); } diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 6f81d93d8..e2b679756 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1556,13 +1556,13 @@ namespace pdr { if (use_mc) { m_core_generalizers.push_back(alloc(core_multi_generalizer, *this, 0)); } - if (m_params.use_farkas() && !classify.is_bool()) { + if (!classify.is_bool()) { m.toggle_proof_mode(PGM_FINE); m_fparams.m_arith_bound_prop = BP_NONE; m_fparams.m_arith_auto_config_simplex = true; m_fparams.m_arith_propagate_eqs = false; m_fparams.m_arith_eager_eq_axioms = false; - if (classify.is_dl()) { + if (classify.is_dl() && m_params.use_utvpi()) { m_fparams.m_arith_mode = AS_DIFF_LOGIC; m_fparams.m_arith_expand_eqs = true; } @@ -1571,7 +1571,6 @@ namespace pdr { m_fparams.m_arith_mode = AS_UTVPI; m_fparams.m_arith_expand_eqs = true; } - } if (m_params.use_convex_hull_generalizer()) { m_core_generalizers.push_back(alloc(core_convex_hull_generalizer, *this)); @@ -1800,6 +1799,7 @@ namespace pdr { m_expanded_lvl = n.level(); } + n.pt().set_use_farkas(m_params.use_farkas()); if (n.pt().is_reachable(n.state())) { TRACE("pdr", tout << "reachable\n";); close_node(n); diff --git a/src/muz_qe/pdr_context.h b/src/muz_qe/pdr_context.h index 1785991c6..4c26fc1ac 100644 --- a/src/muz_qe/pdr_context.h +++ b/src/muz_qe/pdr_context.h @@ -166,6 +166,8 @@ namespace pdr { prop_solver& get_solver() { return m_solver; } + void set_use_farkas(bool f) { get_solver().set_use_farkas(f); } + }; diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index 5e777bf7e..e73dcdac8 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -196,6 +196,7 @@ namespace pdr { ); model_node nd(0, state, n.pt(), n.level()); + n.pt().set_use_farkas(true); if (l_false == n.pt().is_reachable(nd, &conv2, uses_level)) { TRACE("pdr", tout << mk_pp(state, m) << "\n"; @@ -260,6 +261,7 @@ namespace pdr { expr_ref state = pm.mk_and(conv1); TRACE("pdr", tout << "Try:\n" << mk_pp(state, m) << "\n";); model_node nd(0, state, n.pt(), n.level()); + n.pt().set_use_farkas(true); if (l_false == n.pt().is_reachable(nd, &conv2, uses_level)) { IF_VERBOSE(0, verbose_stream() << mk_pp(state, m) << "\n"; diff --git a/src/muz_qe/pdr_prop_solver.cpp b/src/muz_qe/pdr_prop_solver.cpp index e3cd0d9c5..c7f0bfbc3 100644 --- a/src/muz_qe/pdr_prop_solver.cpp +++ b/src/muz_qe/pdr_prop_solver.cpp @@ -237,6 +237,7 @@ namespace pdr { m_proxies(m), m_core(0), m_subset_based_core(false), + m_use_farkas(false), m_in_level(false) { m_ctx->assert_expr(m_pm.get_background()); @@ -328,7 +329,11 @@ namespace pdr { } } - if (result == l_false && m_core && m.proofs_enabled() && !m_subset_based_core) { + if (result == l_false && + m_core && + m.proofs_enabled() && + m_use_farkas && + !m_subset_based_core) { extract_theory_core(safe); } else if (result == l_false && m_core) { diff --git a/src/muz_qe/pdr_prop_solver.h b/src/muz_qe/pdr_prop_solver.h index 165a37845..7712573ee 100644 --- a/src/muz_qe/pdr_prop_solver.h +++ b/src/muz_qe/pdr_prop_solver.h @@ -50,6 +50,7 @@ namespace pdr { model_ref* m_model; bool m_subset_based_core; bool m_assumes_level; + bool m_use_farkas; func_decl_set m_aux_symbols; bool m_in_level; unsigned m_current_level; // set when m_in_level @@ -97,6 +98,8 @@ namespace pdr { ~scoped_level() { m_lev = false; } }; + void set_use_farkas(bool f) { m_use_farkas = f; } + void add_formula(expr * form); void add_level_formula(expr * form, unsigned level); From 327b2bbe9ce9e70f13c030b2d6f3c8eaf979020d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Jul 2013 00:03:38 +0400 Subject: [PATCH 211/281] add control over Farkas parameter for Arie Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_context.cpp | 18 ++++++++++-------- src/muz_qe/pdr_generalizers.cpp | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index e2b679756..034bb236a 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1562,14 +1562,16 @@ namespace pdr { m_fparams.m_arith_auto_config_simplex = true; m_fparams.m_arith_propagate_eqs = false; m_fparams.m_arith_eager_eq_axioms = false; - if (classify.is_dl() && m_params.use_utvpi()) { - m_fparams.m_arith_mode = AS_DIFF_LOGIC; - m_fparams.m_arith_expand_eqs = true; - } - else if (classify.is_utvpi() && m_params.use_utvpi()) { - IF_VERBOSE(1, verbose_stream() << "UTVPI\n";); - m_fparams.m_arith_mode = AS_UTVPI; - m_fparams.m_arith_expand_eqs = true; + if (m_params.use_utvpi() && !m_params.use_convex_hull_generalizer()) { + if (classify.is_dl()) { + m_fparams.m_arith_mode = AS_DIFF_LOGIC; + m_fparams.m_arith_expand_eqs = true; + } + else if (classify.is_utvpi()) { + IF_VERBOSE(1, verbose_stream() << "UTVPI\n";); + m_fparams.m_arith_mode = AS_UTVPI; + m_fparams.m_arith_expand_eqs = true; + } } } if (m_params.use_convex_hull_generalizer()) { diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index e73dcdac8..5e928ff45 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -158,7 +158,7 @@ namespace pdr { } void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { - method2(n, core, uses_level); + method1(n, core, uses_level); } // use the entire region as starting point for generalization. From a7ed218636eca7f22478dcd4fbd8475e8151f681 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Aug 2013 13:16:46 -0700 Subject: [PATCH 212/281] generalize ackerman reduction to work with nested terms Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_array_blast.cpp | 105 +++++++++++++++++++++++-------- src/muz_qe/dl_mk_array_blast.h | 15 ++++- 2 files changed, 92 insertions(+), 28 deletions(-) diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp index c1f0912c0..2c7d3d5cd 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz_qe/dl_mk_array_blast.cpp @@ -18,7 +18,6 @@ Revision History: --*/ #include "dl_mk_array_blast.h" -#include "expr_safe_replace.h" namespace datalog { @@ -31,7 +30,9 @@ namespace datalog { a(m), rm(ctx.get_rule_manager()), m_rewriter(m, m_params), - m_simplifier(ctx) { + m_simplifier(ctx), + m_sub(m), + m_next_var(0) { m_params.set_bool("expand_select_store",true); m_rewriter.updt_params(m_params); } @@ -50,14 +51,63 @@ namespace datalog { } return false; } + + expr* mk_array_blast::get_select(expr* e) const { + while (a.is_select(e)) { + e = to_app(e)->get_arg(0); + } + return e; + } + + void mk_array_blast::get_select_args(expr* e, ptr_vector& args) const { + while (a.is_select(e)) { + app* ap = to_app(e); + for (unsigned i = 1; i < ap->get_num_args(); ++i) { + args.push_back(ap->get_arg(i)); + } + e = ap->get_arg(0); + } + } + + bool mk_array_blast::insert_def(rule const& r, app* e, var* v) { + // + // For the Ackermann reduction we would like the arrays + // to be variables, so that variables can be + // assumed to represent difference (alias) + // classes. Ehm., Soundness of this approach depends on + // if the arrays are finite domains... + // + + if (!is_var(get_select(e))) { + return false; + } + if (v) { + m_sub.insert(e, v); + m_defs.insert(e, to_var(v)); + } + else { + if (m_next_var == 0) { + ptr_vector vars; + r.get_vars(vars); + m_next_var = vars.size() + 1; + } + v = m.mk_var(m_next_var, m.get_sort(e)); + m_sub.insert(e, v); + m_defs.insert(e, v); + ++m_next_var; + } + return true; + } - bool mk_array_blast::ackermanize(expr_ref& body, expr_ref& head) { + bool mk_array_blast::ackermanize(rule const& r, expr_ref& body, expr_ref& head) { expr_ref_vector conjs(m); flatten_and(body, conjs); - defs_t defs; - expr_safe_replace sub(m); + m_defs.reset(); + m_sub.reset(); + m_next_var = 0; ptr_vector todo; todo.push_back(head); + unsigned next_var = 0; for (unsigned i = 0; i < conjs.size(); ++i) { expr* e = conjs[i].get(); expr* x, *y; @@ -66,22 +116,17 @@ namespace datalog { std::swap(x,y); } if (a.is_select(x) && is_var(y)) { - // - // For the Ackermann reduction we would like the arrays - // to be variables, so that variables can be - // assumed to represent difference (alias) - // classes. - // - if (!is_var(to_app(x)->get_arg(0))) { + if (!insert_def(r, to_app(x), to_var(y))) { return false; } - sub.insert(x, y); - defs.insert(to_app(x), to_var(y)); } } + if (a.is_select(e) && !insert_def(r, to_app(e), 0)) { + return false; + } todo.push_back(e); } - // now check that all occurrences of select have been covered. + // now make sure to cover all occurrences. ast_mark mark; while (!todo.empty()) { expr* e = todo.back(); @@ -97,22 +142,28 @@ namespace datalog { return false; } app* ap = to_app(e); - if (a.is_select(e) && !defs.contains(ap)) { - return false; + if (a.is_select(ap) && !m_defs.contains(ap)) { + if (!insert_def(r, ap, 0)) { + return false; + } + } + if (a.is_select(e)) { + get_select_args(e, todo); + continue; } for (unsigned i = 0; i < ap->get_num_args(); ++i) { todo.push_back(ap->get_arg(i)); } } - sub(body); - sub(head); + m_sub(body); + m_sub(head); conjs.reset(); // perform the Ackermann reduction by creating implications // i1 = i2 => val1 = val2 for each equality pair: // (= val1 (select a_i i1)) // (= val2 (select a_i i2)) - defs_t::iterator it1 = defs.begin(), end = defs.end(); + defs_t::iterator it1 = m_defs.begin(), end = m_defs.end(); for (; it1 != end; ++it1) { app* a1 = it1->m_key; var* v1 = it1->m_value; @@ -121,12 +172,15 @@ namespace datalog { for (; it2 != end; ++it2) { app* a2 = it2->m_key; var* v2 = it2->m_value; - if (a1->get_arg(0) != a2->get_arg(0)) { + if (get_select(a1) != get_select(a2)) { continue; } expr_ref_vector eqs(m); - for (unsigned j = 1; j < a1->get_num_args(); ++j) { - eqs.push_back(m.mk_eq(a1->get_arg(j), a2->get_arg(j))); + ptr_vector args1, args2; + get_select_args(a1, args1); + get_select_args(a2, args2); + for (unsigned j = 0; j < args1.size(); ++j) { + eqs.push_back(m.mk_eq(args1[j], args2[j])); } conjs.push_back(m.mk_implies(m.mk_and(eqs.size(), eqs.c_ptr()), m.mk_eq(v1, v2))); } @@ -179,15 +233,14 @@ namespace datalog { } } - expr_ref fml1(m), fml2(m), body(m), head(m); - r.to_formula(fml1); + expr_ref fml2(m), body(m), head(m); body = m.mk_and(new_conjs.size(), new_conjs.c_ptr()); head = r.get_head(); sub(body); m_rewriter(body); sub(head); m_rewriter(head); - change = ackermanize(body, head) || change; + change = ackermanize(r, body, head) || change; if (!inserted && !change) { rules.add_rule(&r); return false; diff --git a/src/muz_qe/dl_mk_array_blast.h b/src/muz_qe/dl_mk_array_blast.h index 21f2a0bf7..f4b685b7a 100644 --- a/src/muz_qe/dl_mk_array_blast.h +++ b/src/muz_qe/dl_mk_array_blast.h @@ -25,6 +25,7 @@ Revision History: #include"dl_mk_interp_tail_simplifier.h" #include "equiv_proof_converter.h" #include "array_decl_plugin.h" +#include "expr_safe_replace.h" namespace datalog { @@ -32,6 +33,8 @@ namespace datalog { \brief Blast occurrences of arrays in rules */ class mk_array_blast : public rule_transformer::plugin { + typedef obj_map defs_t; + context& m_ctx; ast_manager& m; array_util a; @@ -40,13 +43,21 @@ namespace datalog { th_rewriter m_rewriter; mk_interp_tail_simplifier m_simplifier; - typedef obj_map defs_t; + defs_t m_defs; + expr_safe_replace m_sub; + unsigned m_next_var; bool blast(rule& r, rule_set& new_rules); bool is_store_def(expr* e, expr*& x, expr*& y); - bool ackermanize(expr_ref& body, expr_ref& head); + bool ackermanize(rule const& r, expr_ref& body, expr_ref& head); + + expr* get_select(expr* e) const; + + void get_select_args(expr* e, ptr_vector& args) const; + + bool insert_def(rule const& r, app* e, var* v); public: /** From ec22156ae12754aa79e689be25bc060fb0951fe7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Aug 2013 14:52:34 -0700 Subject: [PATCH 213/281] fix bug in get_answer reported by Anvesh Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_context.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 034bb236a..de0041413 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -765,6 +765,7 @@ namespace pdr { ini_state = m.mk_and(ini_tags, pt().initial_state(), state()); model_ref mdl; pt().get_solver().set_model(&mdl); + TRACE("pdr", tout << mk_pp(ini_state, m) << "\n";); VERIFY(l_true == pt().get_solver().check_conjunction_as_assumptions(ini_state)); datalog::rule const& rl2 = pt().find_rule(*mdl); SASSERT(is_ini(rl2)); @@ -958,12 +959,14 @@ namespace pdr { */ void model_search::update_models() { obj_map models; + obj_map rules; ptr_vector todo; todo.push_back(m_root); while (!todo.empty()) { model_node* n = todo.back(); if (n->get_model_ptr()) { models.insert(n->state(), n->get_model_ptr()); + rules.insert(n->state(), n->get_rule()); } todo.pop_back(); todo.append(n->children().size(), n->children().c_ptr()); @@ -973,9 +976,13 @@ namespace pdr { while (!todo.empty()) { model_node* n = todo.back(); model* md = 0; + ast_manager& m = n->pt().get_manager(); if (!n->get_model_ptr() && models.find(n->state(), md)) { + TRACE("pdr", tout << mk_pp(n->state(), m) << "\n";); model_ref mr(md); n->set_model(mr); + datalog::rule const* rule = rules.find(n->state()); + n->set_rule(rule); } todo.pop_back(); todo.append(n->children().size(), n->children().c_ptr()); @@ -1037,10 +1044,6 @@ namespace pdr { } first = false; predicates.pop_back(); - for (unsigned i = 0; i < rule->get_uninterpreted_tail_size(); ++i) { - subst.apply(2, deltas, expr_offset(rule->get_tail(i), 1), tmp); - predicates.push_back(tmp); - } for (unsigned i = rule->get_uninterpreted_tail_size(); i < rule->get_tail_size(); ++i) { subst.apply(2, deltas, expr_offset(rule->get_tail(i), 1), tmp); dctx.get_rewriter()(tmp); @@ -1051,9 +1054,22 @@ namespace pdr { for (unsigned i = 0; i < constraints.size(); ++i) { max_var = std::max(vc.get_max_var(constraints[i].get()), max_var); } + if (n->children().empty()) { + // nodes whose states are repeated + // in the search tree do not have children. + continue; + } + + SASSERT(n->children().size() == rule->get_uninterpreted_tail_size()); + + for (unsigned i = 0; i < rule->get_uninterpreted_tail_size(); ++i) { + subst.apply(2, deltas, expr_offset(rule->get_tail(i), 1), tmp); + predicates.push_back(tmp); + } for (unsigned i = 0; i < predicates.size(); ++i) { max_var = std::max(vc.get_max_var(predicates[i].get()), max_var); } + children.append(n->children()); } return pm.mk_and(constraints); @@ -1230,6 +1246,7 @@ namespace pdr { m_expanded_lvl(0), m_cancel(false) { + enable_trace("pdr"); } context::~context() { From 5b9ec3dec7584b7212b8bc8991316e98b80a4811 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Aug 2013 19:58:21 -0700 Subject: [PATCH 214/281] add scoped class for controlling Farkas generalization Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_context.cpp | 2 +- src/muz_qe/pdr_context.h | 11 +++++++++++ src/muz_qe/pdr_generalizers.cpp | 4 ++-- src/muz_qe/pdr_prop_solver.h | 1 + 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 034bb236a..4454e2fbf 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1801,7 +1801,7 @@ namespace pdr { m_expanded_lvl = n.level(); } - n.pt().set_use_farkas(m_params.use_farkas()); + pred_transformer::scoped_farkas sf (n.pt(), m_params.use_farkas()); if (n.pt().is_reachable(n.state())) { TRACE("pdr", tout << "reachable\n";); close_node(n); diff --git a/src/muz_qe/pdr_context.h b/src/muz_qe/pdr_context.h index 4c26fc1ac..3501ca7cd 100644 --- a/src/muz_qe/pdr_context.h +++ b/src/muz_qe/pdr_context.h @@ -165,8 +165,19 @@ namespace pdr { void ground_free_vars(expr* e, app_ref_vector& vars, ptr_vector& aux_vars); prop_solver& get_solver() { return m_solver; } + prop_solver const& get_solver() const { return m_solver; } void set_use_farkas(bool f) { get_solver().set_use_farkas(f); } + bool get_use_farkas() const { return get_solver().get_use_farkas(); } + class scoped_farkas { + bool m_old; + pred_transformer& m_p; + public: + scoped_farkas(pred_transformer& p, bool v): m_old(p.get_use_farkas()), m_p(p) { + p.set_use_farkas(v); + } + ~scoped_farkas() { m_p.set_use_farkas(m_old); } + }; }; diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index 5e928ff45..7321a1c03 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -196,7 +196,7 @@ namespace pdr { ); model_node nd(0, state, n.pt(), n.level()); - n.pt().set_use_farkas(true); + pred_transformer::scoped_farkas sf(n.pt(), true); if (l_false == n.pt().is_reachable(nd, &conv2, uses_level)) { TRACE("pdr", tout << mk_pp(state, m) << "\n"; @@ -261,7 +261,7 @@ namespace pdr { expr_ref state = pm.mk_and(conv1); TRACE("pdr", tout << "Try:\n" << mk_pp(state, m) << "\n";); model_node nd(0, state, n.pt(), n.level()); - n.pt().set_use_farkas(true); + pred_transformer::scoped_farkas sf(n.pt(), true); if (l_false == n.pt().is_reachable(nd, &conv2, uses_level)) { IF_VERBOSE(0, verbose_stream() << mk_pp(state, m) << "\n"; diff --git a/src/muz_qe/pdr_prop_solver.h b/src/muz_qe/pdr_prop_solver.h index 7712573ee..5a6b09360 100644 --- a/src/muz_qe/pdr_prop_solver.h +++ b/src/muz_qe/pdr_prop_solver.h @@ -99,6 +99,7 @@ namespace pdr { }; void set_use_farkas(bool f) { m_use_farkas = f; } + bool get_use_farkas() const { return m_use_farkas; } void add_formula(expr * form); void add_level_formula(expr * form, unsigned level); From 0595fe8ceccebd56909f416cc492c9db30cef2cd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Aug 2013 09:36:31 -0700 Subject: [PATCH 215/281] remove tracing Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_context.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index de0041413..e6916050a 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1246,7 +1246,6 @@ namespace pdr { m_expanded_lvl(0), m_cancel(false) { - enable_trace("pdr"); } context::~context() { From dc58bce052dc355c6f3f2aee25d9ffda7ea6ca10 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Aug 2013 14:09:45 -0700 Subject: [PATCH 216/281] initial test for polynormalization Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_coi_filter.cpp | 98 +++++++++++++++++++++++-- src/muz_qe/dl_mk_coi_filter.h | 4 ++ src/test/dl_context.cpp | 2 +- src/test/dl_product_relation.cpp | 4 +- src/test/dl_query.cpp | 8 +-- src/test/dl_relation.cpp | 4 +- src/test/dl_table.cpp | 2 +- src/test/main.cpp | 1 + src/test/polynorm.cpp | 119 +++++++++++++++++++++++++++++++ 9 files changed, 227 insertions(+), 15 deletions(-) create mode 100644 src/test/polynorm.cpp diff --git a/src/muz_qe/dl_mk_coi_filter.cpp b/src/muz_qe/dl_mk_coi_filter.cpp index b253a0e20..308198ff7 100644 --- a/src/muz_qe/dl_mk_coi_filter.cpp +++ b/src/muz_qe/dl_mk_coi_filter.cpp @@ -16,6 +16,9 @@ Author: Revision History: + Andrey Rybalchenko (rybal) 2013-8-8 + Added bottom_up pruning. + --*/ @@ -32,12 +35,97 @@ namespace datalog { // // ----------------------------------- - - rule_set * mk_coi_filter::operator()(rule_set const & source) - { + rule_set * mk_coi_filter::operator()(rule_set const & source) { if (source.empty()) { return 0; } + scoped_ptr result = top_down(source); + return bottom_up(result?*result:source); + } + + rule_set * mk_coi_filter::bottom_up(rule_set const & source) { + decl_set all, reached; + ptr_vector todo; + rule_set::decl2rules body2rules; + // initialization for reachability + for (rule_set::iterator it = source.begin(); it != source.end(); ++it) { + rule * r = *it; + all.insert(r->get_decl()); + if (r->get_uninterpreted_tail_size() == 0) { + if (!reached.contains(r->get_decl())) { + reached.insert(r->get_decl()); + todo.insert(r->get_decl()); + } + } + else { + for (unsigned i = 0; i < r->get_uninterpreted_tail_size(); ++i) { + func_decl * d = r->get_tail(i)->get_decl(); + all.insert(d); + rule_set::decl2rules::obj_map_entry * e = body2rules.insert_if_not_there2(d, 0); + if (!e->get_data().m_value) { + e->get_data().m_value = alloc(ptr_vector); + } + e->get_data().m_value->push_back(r); + } + } + } + // reachability computation + while (!todo.empty()) { + func_decl * d = todo.back(); + todo.pop_back(); + ptr_vector * rules; + if (!body2rules.find(d, rules)) continue; + for (ptr_vector::iterator it = rules->begin(); it != rules->end(); ++it) { + rule * r = *it; + if (reached.contains(r->get_decl())) continue; + bool contained = true; + for (unsigned i = 0; contained && i < r->get_uninterpreted_tail_size(); ++i) { + contained = reached.contains(r->get_tail(i)->get_decl()); + } + if (!contained) continue; + reached.insert(r->get_decl()); + todo.insert(r->get_decl()); + } + } + + // eliminate each rule when some body predicate is not reached + scoped_ptr res = alloc(rule_set, m_context); + res->inherit_predicates(source); + for (rule_set::iterator it = source.begin(); it != source.end(); ++it) { + rule * r = *it; + + bool contained = true; + for (unsigned i = 0; contained && i < r->get_uninterpreted_tail_size(); ++i) { + contained = reached.contains(r->get_tail(i)->get_decl()); + } + if (contained) { + res->add_rule(r); + } + } + + if (res->get_num_rules() == source.get_num_rules()) { + return 0; + } + res->close(); + + // set to false each unreached predicate + if (m_context.get_model_converter()) { + extension_model_converter* mc0 = alloc(extension_model_converter, m); + for (decl_set::iterator it = all.begin(); it != all.end(); ++it) { + if (!reached.contains(*it)) { + mc0->insert(*it, m.mk_false()); + } + } + m_context.add_model_converter(mc0); + } + // clean up body2rules range resources + for (rule_set::decl2rules::iterator it = body2rules.begin(); it != body2rules.end(); ++it) { + dealloc(it->m_value); + } + return res.detach(); + } + + rule_set * mk_coi_filter::top_down(rule_set const & source) { decl_set interesting_preds; decl_set pruned_preds; @@ -60,7 +148,7 @@ namespace datalog { const rule_dependencies::item_set& cdeps = deps.get_deps(curr); rule_dependencies::item_set::iterator dend = cdeps.end(); - for (rule_dependencies::item_set::iterator it = cdeps.begin(); it!=dend; ++it) { + for (rule_dependencies::item_set::iterator it = cdeps.begin(); it != dend; ++it) { func_decl * dep_pred = *it; if (!interesting_preds.contains(dep_pred)) { interesting_preds.insert(dep_pred); @@ -73,7 +161,7 @@ namespace datalog { res->inherit_predicates(source); rule_set::iterator rend = source.end(); - for (rule_set::iterator rit = source.begin(); rit!=rend; ++rit) { + for (rule_set::iterator rit = source.begin(); rit != rend; ++rit) { rule * r = *rit; func_decl * pred = r->get_decl(); if (interesting_preds.contains(pred)) { diff --git a/src/muz_qe/dl_mk_coi_filter.h b/src/muz_qe/dl_mk_coi_filter.h index b02bed9ec..8ec7e80c4 100644 --- a/src/muz_qe/dl_mk_coi_filter.h +++ b/src/muz_qe/dl_mk_coi_filter.h @@ -32,6 +32,10 @@ namespace datalog { ast_manager & m; context & m_context; + + rule_set * bottom_up(rule_set const & source); + rule_set * top_down(rule_set const & source); + public: mk_coi_filter(context & ctx, unsigned priority=45000) : plugin(priority), diff --git a/src/test/dl_context.cpp b/src/test/dl_context.cpp index d5fcddb71..9e8a37974 100644 --- a/src/test/dl_context.cpp +++ b/src/test/dl_context.cpp @@ -60,7 +60,7 @@ void dl_context_saturate_file(params_ref & params, const char * f) { } dealloc(parser); std::cerr << "Saturating...\n"; - ctx.get_rel_context().saturate(); + ctx.get_rel_context()->saturate(); std::cerr << "Done\n"; } diff --git a/src/test/dl_product_relation.cpp b/src/test/dl_product_relation.cpp index ef43258ad..d58603be1 100644 --- a/src/test/dl_product_relation.cpp +++ b/src/test/dl_product_relation.cpp @@ -22,7 +22,7 @@ namespace datalog { void test_functional_columns(smt_params fparams, params_ref& params) { ast_manager m; context ctx(m, fparams); - rel_context& rctx = ctx.get_rel_context(); + rel_context& rctx = *ctx.get_rel_context(); ctx.updt_params(params); relation_manager & rmgr(rctx.get_rmanager()); @@ -127,7 +127,7 @@ namespace datalog { context ctx(m, fparams); ctx.updt_params(params); dl_decl_util dl_util(m); - relation_manager & rmgr = ctx.get_rel_context().get_rmanager(); + relation_manager & rmgr = ctx.get_rel_context()->get_rmanager(); relation_plugin & rel_plugin = *rmgr.get_relation_plugin(params.get_sym("default_relation", symbol("sparse"))); SASSERT(&rel_plugin); diff --git a/src/test/dl_query.cpp b/src/test/dl_query.cpp index d0abfbac0..17781d7bb 100644 --- a/src/test/dl_query.cpp +++ b/src/test/dl_query.cpp @@ -58,7 +58,7 @@ void dl_query_test(ast_manager & m, smt_params & fparams, params_ref& params, TRUSTME( p->parse_file(problem_file) ); dealloc(p); } - relation_manager & rel_mgr_q = ctx_b.get_rel_context().get_rmanager(); + relation_manager & rel_mgr_q = ctx_b.get_rel_context()->get_rmanager(); decl_set out_preds = ctx_b.get_rules().get_output_predicates(); decl_set::iterator it = out_preds.begin(); @@ -69,10 +69,10 @@ void dl_query_test(ast_manager & m, smt_params & fparams, params_ref& params, func_decl * pred_q = ctx_q.try_get_predicate_decl(symbol(pred_b->get_name().bare_str())); SASSERT(pred_q); - relation_base & rel_b = ctx_b.get_rel_context().get_relation(pred_b); + relation_base & rel_b = ctx_b.get_rel_context()->get_relation(pred_b); relation_signature sig_b = rel_b.get_signature(); - relation_signature sig_q = ctx_q.get_rel_context().get_relation(pred_q).get_signature(); + relation_signature sig_q = ctx_q.get_rel_context()->get_relation(pred_q).get_signature(); SASSERT(sig_b.size()==sig_q.size()); std::cerr << "Queries on random facts...\n"; @@ -211,7 +211,7 @@ void tst_dl_query() { TRUSTME( p->parse_file(problem_file) ); dealloc(p); } - ctx_base.get_rel_context().saturate(); + ctx_base.get_rel_context()->saturate(); for(unsigned use_restarts=0; use_restarts<=1; use_restarts++) { params.set_uint("initial_restart_timeout", use_restarts ? 100 : 0); diff --git a/src/test/dl_relation.cpp b/src/test/dl_relation.cpp index 5daf3dc9b..609dca3da 100644 --- a/src/test/dl_relation.cpp +++ b/src/test/dl_relation.cpp @@ -12,7 +12,7 @@ namespace datalog { ast_manager ast_m; context ctx(ast_m, params); arith_util autil(ast_m); - relation_manager & m = ctx.get_rel_context().get_rmanager(); + relation_manager & m = ctx.get_rel_context()->get_rmanager(); m.register_plugin(alloc(interval_relation_plugin, m)); interval_relation_plugin& ip = dynamic_cast(*m.get_relation_plugin(symbol("interval_relation"))); SASSERT(&ip); @@ -115,7 +115,7 @@ namespace datalog { ast_manager ast_m; context ctx(ast_m, params); arith_util autil(ast_m); - relation_manager & m = ctx.get_rel_context().get_rmanager(); + relation_manager & m = ctx.get_rel_context()->get_rmanager(); m.register_plugin(alloc(bound_relation_plugin, m)); bound_relation_plugin& br = dynamic_cast(*m.get_relation_plugin(symbol("bound_relation"))); SASSERT(&br); diff --git a/src/test/dl_table.cpp b/src/test/dl_table.cpp index 32a6f65e3..d7025ed48 100644 --- a/src/test/dl_table.cpp +++ b/src/test/dl_table.cpp @@ -19,7 +19,7 @@ static void test_table(mk_table_fn mk_table) { smt_params params; ast_manager ast_m; datalog::context ctx(ast_m, params); - datalog::relation_manager & m = ctx.get_rel_context().get_rmanager(); + datalog::relation_manager & m = ctx.get_rel_context()->get_rmanager(); m.register_plugin(alloc(datalog::bitvector_table_plugin, m)); diff --git a/src/test/main.cpp b/src/test/main.cpp index c8c011674..b769b20fd 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -213,6 +213,7 @@ int main(int argc, char ** argv) { TST(dl_query); TST(quant_solve); TST(rcf); + TST(polynorm); } void initialize_mam() {} diff --git a/src/test/polynorm.cpp b/src/test/polynorm.cpp new file mode 100644 index 000000000..9853181ca --- /dev/null +++ b/src/test/polynorm.cpp @@ -0,0 +1,119 @@ +#include "th_rewriter.h" +#include "smt2parser.h" +#include "arith_decl_plugin.h" +#include "reg_decl_plugins.h" +#include "ast_pp.h" + + +static expr_ref parse_fml(ast_manager& m, char const* str) { + expr_ref result(m); + cmd_context ctx(false, &m); + ctx.set_ignore_check(true); + std::ostringstream buffer; + buffer << "(declare-const x Int)\n" + << "(declare-const y Int)\n" + << "(declare-const z Int)\n" + << "(declare-const a Int)\n" + << "(declare-const b Int)\n" + << "(assert " << str << ")\n"; + std::istringstream is(buffer.str()); + VERIFY(parse_smt2_commands(ctx, is)); + SASSERT(ctx.begin_assertions() != ctx.end_assertions()); + result = *ctx.begin_assertions(); + return result; +} + +static char const* example1 = "(= (+ (- (* x x) (* 2 y)) y) 0)"; +static char const* example2 = "(= (+ 4 3 (- (* x x) (* 2 y)) y) 0)"; + + +// ast +/// sort : ast +/// func_decl : ast +/// expr : ast +/// app : expr +/// quantifier : expr +/// var : expr +/// + +static expr_ref mk_mul(arith_util& arith, unsigned num_args, expr* const* args) { + ast_manager& m = arith.get_manager(); + expr_ref result(m); + switch (num_args) { + case 0: + UNREACHABLE(); + break; + case 1: + result = args[0]; + break; + default: + result = arith.mk_mul(num_args, args); + break; + } + return result; +} + +static void nf(expr_ref& term) { + ast_manager& m = term.get_manager(); + expr *e1, *e2; + + th_rewriter rw(m); + arith_util arith(m); + + VERIFY(m.is_eq(term, e1, e2)); + term = e1; + + rw(term); + + std::cout << mk_pp(term, m) << "\n"; + std::cout << arith.is_add(term) << "\n"; + + expr_ref_vector factors(m); + vector coefficients; + rational coefficient(0); + + if (arith.is_add(term)) { + factors.append(to_app(term)->get_num_args(), to_app(term)->get_args()); + } + else { + factors.push_back(term); + } + for (unsigned i = 0; i < factors.size(); ++i) { + expr* f = factors[i].get(); + rational r; + if (arith.is_mul(f) && arith.is_numeral(to_app(f)->get_arg(0), r)) { + coefficients.push_back(r); + factors[i] = mk_mul(arith, to_app(f)->get_num_args()-1, to_app(f)->get_args()+1); + } + else if (arith.is_numeral(f, r)) { + factors[i] = factors.back(); + factors.pop_back(); + SASSERT(coefficient.is_zero()); + SASSERT(!r.is_zero()); + coefficient = r; + --i; // repeat examining 'i' + } + else { + coefficients.push_back(rational(1)); + } + } + + std::cout << coefficient << "\n"; + for (unsigned i = 0; i < factors.size(); ++i) { + std::cout << mk_pp(factors[i].get(), m) << " * " << coefficients[i] << "\n"; + } +} + +void tst_polynorm() { + ast_manager m; + reg_decl_plugins(m); + expr_ref fml(m); + + fml = parse_fml(m, example2); + + std::cout << mk_pp(fml, m) << "\n"; + + nf(fml); + + +} From a0d79c8dd766c4781aeaf1389efa362118ed75b8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Aug 2013 15:01:35 -0700 Subject: [PATCH 217/281] fix coi filter to consider 0 cases Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_coi_filter.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/muz_qe/dl_mk_coi_filter.cpp b/src/muz_qe/dl_mk_coi_filter.cpp index 308198ff7..88ec67607 100644 --- a/src/muz_qe/dl_mk_coi_filter.cpp +++ b/src/muz_qe/dl_mk_coi_filter.cpp @@ -36,11 +36,16 @@ namespace datalog { // ----------------------------------- rule_set * mk_coi_filter::operator()(rule_set const & source) { + TRACE("dl", tout << "Hello";); if (source.empty()) { return 0; } - scoped_ptr result = top_down(source); - return bottom_up(result?*result:source); + scoped_ptr result1 = top_down(source); + scoped_ptr result2 = bottom_up(result1?*result1:source); + if (!result2) { + result2 = result1; + } + return result2.detach(); } rule_set * mk_coi_filter::bottom_up(rule_set const & source) { @@ -102,11 +107,13 @@ namespace datalog { res->add_rule(r); } } - if (res->get_num_rules() == source.get_num_rules()) { - return 0; - } - res->close(); + TRACE("dl", tout << "No transformation\n";); + res = 0; + } + else { + res->close(); + } // set to false each unreached predicate if (m_context.get_model_converter()) { @@ -122,6 +129,7 @@ namespace datalog { for (rule_set::decl2rules::iterator it = body2rules.begin(); it != body2rules.end(); ++it) { dealloc(it->m_value); } + CTRACE("dl", 0 != res, res->display(tout);); return res.detach(); } @@ -173,6 +181,7 @@ namespace datalog { } if (res->get_num_rules() == source.get_num_rules()) { + TRACE("dl", tout << "No transformation\n";); res = 0; } @@ -185,7 +194,7 @@ namespace datalog { } m_context.add_model_converter(mc0); } - + CTRACE("dl", 0 != res, res->display(tout);); return res.detach(); } From af700e88cf580b33fc7f179f1863c3e81e8f74d7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Aug 2013 15:02:18 -0700 Subject: [PATCH 218/281] fix coi filter to consider 0 cases Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_coi_filter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz_qe/dl_mk_coi_filter.cpp b/src/muz_qe/dl_mk_coi_filter.cpp index 88ec67607..7bbb14353 100644 --- a/src/muz_qe/dl_mk_coi_filter.cpp +++ b/src/muz_qe/dl_mk_coi_filter.cpp @@ -36,7 +36,6 @@ namespace datalog { // ----------------------------------- rule_set * mk_coi_filter::operator()(rule_set const & source) { - TRACE("dl", tout << "Hello";); if (source.empty()) { return 0; } From 30df2837fbff02f1edf785b861f60dfbc80d8815 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Aug 2013 15:38:13 -0700 Subject: [PATCH 219/281] fix build warnings Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_boogie_proof.cpp | 2 +- src/muz_qe/dl_compiler.cpp | 1 - src/muz_qe/dl_context.cpp | 3 +++ src/muz_qe/dl_mk_array_blast.cpp | 1 - 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/muz_qe/dl_boogie_proof.cpp b/src/muz_qe/dl_boogie_proof.cpp index 8720b3544..e14512973 100644 --- a/src/muz_qe/dl_boogie_proof.cpp +++ b/src/muz_qe/dl_boogie_proof.cpp @@ -176,7 +176,7 @@ namespace datalog { step &s = steps[j]; // TBD - s.m_labels; + // s.m_labels; // set references, compensate for reverse ordering. for (unsigned i = 0; i < s.m_refs.size(); ++i) { diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz_qe/dl_compiler.cpp index a5f8009e7..7a2b47c78 100644 --- a/src/muz_qe/dl_compiler.cpp +++ b/src/muz_qe/dl_compiler.cpp @@ -1004,7 +1004,6 @@ namespace datalog { void compiler::detect_chains(const func_decl_set & preds, func_decl_vector & ordered_preds, func_decl_set & global_deltas) { - typedef obj_map pred2pred; SASSERT(ordered_preds.empty()); SASSERT(global_deltas.empty()); diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 34513cc76..d8a50668b 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -686,6 +686,7 @@ namespace datalog { check_existential_tail(r); check_positive_predicates(r); break; + case LAST_ENGINE: default: UNREACHABLE(); break; @@ -1039,6 +1040,8 @@ namespace datalog { case CLP_ENGINE: m_engine = alloc(clp, *this); break; + case LAST_ENGINE: + UNREACHABLE(); } } } diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp index 2c7d3d5cd..9f057a148 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz_qe/dl_mk_array_blast.cpp @@ -107,7 +107,6 @@ namespace datalog { m_next_var = 0; ptr_vector todo; todo.push_back(head); - unsigned next_var = 0; for (unsigned i = 0; i < conjs.size(); ++i) { expr* e = conjs[i].get(); expr* x, *y; From cb06ce295e888c55f34c1f36951081a8c7bc5b42 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Aug 2013 09:00:40 -0700 Subject: [PATCH 220/281] add comments to generalizer code Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_generalizers.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index 7321a1c03..c094b6c7f 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -162,6 +162,18 @@ namespace pdr { } // use the entire region as starting point for generalization. + // + // Constraints: + // add_variables: y = y1 + y2 + // core: Ay <= b -> conv1: A*y1 <= b*sigma1 + // sigma1 > 0 + // sigma2 > 0 + // 1 = sigma1 + sigma2 + // A'y <= b' -> conv2: A'*y2 <= b'*sigma2 + // + // If Constraints & Transition(y0, y) is unsat, then + // update with new core. + // void core_convex_hull_generalizer::method1(model_node& n, expr_ref_vector& core, bool& uses_level) { manager& pm = n.pt().get_pdr_manager(); expr_ref_vector conv1(m), conv2(m), core1(m), core2(m), eqs(m); From 3b64265c27266bbf69ca62037c89be4f7487dc83 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Aug 2013 09:15:04 -0700 Subject: [PATCH 221/281] remove duplicated definition of is_store and is_select Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 29 ++------------------- src/ast/simplifier/bv_simplifier_plugin.cpp | 2 +- src/muz_qe/qe_lite.cpp | 9 ++++++- 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index bbd267292..739a9e61a 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -3856,32 +3856,6 @@ def is_array(a): """ return isinstance(a, ArrayRef) -def is_select(a): - """Return `True` if `a` is a Z3 array select. - - >>> a = Array('a', IntSort(), IntSort()) - >>> is_select(a) - False - >>> i = Int('i') - >>> is_select(a[i]) - True - """ - return is_app_of(a, Z3_OP_SELECT) - -def is_store(a): - """Return `True` if `a` is a Z3 array store. - - >>> a = Array('a', IntSort(), IntSort()) - >>> is_store(a) - False - >>> i = Int('i') - >>> is_store(a[i]) - False - >>> is_store(Store(a, i, i + 1)) - True - """ - return is_app_of(a, Z3_OP_STORE) - def is_const_array(a): """Return `True` if `a` is a Z3 constant array. @@ -4072,7 +4046,8 @@ def is_select(a): >>> a = Array('a', IntSort(), IntSort()) >>> is_select(a) False - >>> is_select(a[0]) + >>> i = Int('i') + >>> is_select(a[i]) True """ return is_app_of(a, Z3_OP_SELECT) diff --git a/src/ast/simplifier/bv_simplifier_plugin.cpp b/src/ast/simplifier/bv_simplifier_plugin.cpp index 8ee353a76..45fee07e4 100644 --- a/src/ast/simplifier/bv_simplifier_plugin.cpp +++ b/src/ast/simplifier/bv_simplifier_plugin.cpp @@ -179,7 +179,7 @@ bool bv_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const } SASSERT(result.get()); - TRACE("bv_simplifier", + TRACE("bv_simplifier", tout << mk_pp(f, m_manager) << "\n"; for (unsigned i = 0; i < num_args; ++i) { tout << mk_pp(args[i], m_manager) << " "; diff --git a/src/muz_qe/qe_lite.cpp b/src/muz_qe/qe_lite.cpp index f840f19d6..01537b574 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/muz_qe/qe_lite.cpp @@ -799,9 +799,15 @@ namespace ar { } /** - Ex A. A[x] = t & Phi where x \not\in A, t. + Ex A. A[x] = t & Phi where x \not\in A, t. A \not\in t, x => Ex A. Phi[store(A,x,t)] + + Perhaps also: + Ex A. store(A,y,z)[x] = t & Phi where x \not\in A, t, y, z, A \not\in y z, t + => + Ex A, v . (x = y => z = t) & Phi[store(store(A,x,t),y,v)] + */ bool solve_select(expr_ref_vector& conjs, unsigned i, expr* e1, expr* e2) { @@ -827,6 +833,7 @@ namespace ar { expr_safe_replace rep(m); rep.insert(A, B); expr_ref tmp(m); + std::cout << mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n"; for (unsigned j = 0; j < conjs.size(); ++j) { if (i == j) { conjs[j] = m.mk_true(); From d94f1b3fd634a3dd4c2c9edfba4b93a8cbd4e098 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Aug 2013 10:50:03 -0700 Subject: [PATCH 222/281] add normalizer of monomial coefficients Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_util.cpp | 149 ++++++++++++++++++++++++++++++++++++ src/muz_qe/pdr_util.h | 11 +++ src/test/arith_rewriter.cpp | 42 ++++++++++ 3 files changed, 202 insertions(+) diff --git a/src/muz_qe/pdr_util.cpp b/src/muz_qe/pdr_util.cpp index 9711cffc2..169eeec72 100644 --- a/src/muz_qe/pdr_util.cpp +++ b/src/muz_qe/pdr_util.cpp @@ -42,6 +42,10 @@ Notes: #include "arith_decl_plugin.h" #include "expr_replacer.h" #include "model_smt2_pp.h" +#include "poly_rewriter.h" +#include "poly_rewriter_def.h" +#include "arith_rewriter.h" + namespace pdr { @@ -1278,6 +1282,151 @@ namespace pdr { return test.is_dl(); } + class arith_normalizer : public poly_rewriter { + ast_manager& m; + arith_util m_util; + enum op_kind { LE, GE, EQ }; + public: + arith_normalizer(ast_manager& m, params_ref const& p = params_ref()): poly_rewriter(m, p), m(m), m_util(m) {} + + br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) { + br_status st = BR_FAILED; + if (m.is_eq(f)) { + SASSERT(num_args == 2); return mk_eq_core(args[0], args[1], result); + } + + if (f->get_family_id() != get_fid()) { + return st; + } + switch (f->get_decl_kind()) { + case OP_NUM: st = BR_FAILED; break; + case OP_IRRATIONAL_ALGEBRAIC_NUM: st = BR_FAILED; break; + case OP_LE: SASSERT(num_args == 2); st = mk_le_core(args[0], args[1], result); break; + case OP_GE: SASSERT(num_args == 2); st = mk_ge_core(args[0], args[1], result); break; + case OP_LT: SASSERT(num_args == 2); st = mk_lt_core(args[0], args[1], result); break; + case OP_GT: SASSERT(num_args == 2); st = mk_gt_core(args[0], args[1], result); break; + default: st = BR_FAILED; break; + } + return st; + } + + private: + + br_status mk_eq_core(expr* arg1, expr* arg2, expr_ref& result) { + return mk_le_ge_eq_core(arg1, arg2, EQ, result); + } + br_status mk_le_core(expr* arg1, expr* arg2, expr_ref& result) { + return mk_le_ge_eq_core(arg1, arg2, LE, result); + } + br_status mk_ge_core(expr* arg1, expr* arg2, expr_ref& result) { + return mk_le_ge_eq_core(arg1, arg2, GE, result); + } + br_status mk_lt_core(expr* arg1, expr* arg2, expr_ref& result) { + result = m.mk_not(m_util.mk_ge(arg1, arg2)); + return BR_REWRITE2; + } + br_status mk_gt_core(expr* arg1, expr* arg2, expr_ref& result) { + result = m.mk_not(m_util.mk_le(arg1, arg2)); + return BR_REWRITE2; + } + + br_status mk_le_ge_eq_core(expr* arg1, expr* arg2, op_kind kind, expr_ref& result) { + if (m_util.is_real(arg1)) { + numeral g(0); + get_coeffs(arg1, g); + get_coeffs(arg2, g); + if (!g.is_one() && !g.is_zero()) { + SASSERT(g.is_pos()); + expr_ref new_arg1 = rdiv_polynomial(arg1, g); + expr_ref new_arg2 = rdiv_polynomial(arg2, g); + switch(kind) { + case LE: result = m_util.mk_le(new_arg1, new_arg2); return BR_DONE; + case GE: result = m_util.mk_ge(new_arg1, new_arg2); return BR_DONE; + case EQ: result = m_util.mk_eq(new_arg1, new_arg2); return BR_DONE; + } + } + } + return BR_FAILED; + } + + void update_coeff(numeral const& r, numeral& g) { + if (g.is_zero() || abs(r) < g) { + g = abs(r); + } + } + + void get_coeffs(expr* e, numeral& g) { + rational r; + unsigned sz; + expr* const* args = get_monomials(e, sz); + for (unsigned i = 0; i < sz; ++i) { + expr* arg = args[i]; + if (!m_util.is_numeral(arg, r)) { + get_power_product(arg, r); + } + update_coeff(r, g); + } + } + + expr_ref rdiv_polynomial(expr* e, numeral const& g) { + rational r; + SASSERT(g.is_pos()); + SASSERT(!g.is_one()); + expr_ref_vector monomes(m); + unsigned sz; + expr* const* args = get_monomials(e, sz); + for (unsigned i = 0; i < sz; ++i) { + expr* arg = args[i]; + if (m_util.is_numeral(arg, r)) { + monomes.push_back(m_util.mk_numeral(r/g, false)); + } + else { + expr* p = get_power_product(arg, r); + r /= g; + if (r.is_one()) { + monomes.push_back(p); + } + else { + monomes.push_back(m_util.mk_mul(m_util.mk_numeral(r, false), p)); + } + } + } + expr_ref result(m); + mk_add(monomes.size(), monomes.c_ptr(), result); + return result; + } + + }; + + + struct arith_normalizer_cfg: public default_rewriter_cfg { + arith_normalizer m_r; + bool rewrite_patterns() const { return false; } + br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + return m_r.mk_app_core(f, num, args, result); + } + arith_normalizer_cfg(ast_manager & m, params_ref const & p):m_r(m,p) {} + }; + + class arith_normalizer_star : public rewriter_tpl { + arith_normalizer_cfg m_cfg; + public: + arith_normalizer_star(ast_manager & m, params_ref const & p): + rewriter_tpl(m, false, m_cfg), + m_cfg(m, p) {} + }; + + + void normalize_arithmetic(expr_ref& t) { + ast_manager& m = t.get_manager(); + datalog::scoped_no_proof _sp(m); + params_ref p; + arith_normalizer_star rw(m, p); + expr_ref tmp(m); + rw(t, tmp); + t = tmp; + } + } template class rewriter_tpl; diff --git a/src/muz_qe/pdr_util.h b/src/muz_qe/pdr_util.h index 5f2d22b76..67be6751b 100644 --- a/src/muz_qe/pdr_util.h +++ b/src/muz_qe/pdr_util.h @@ -142,6 +142,7 @@ namespace pdr { Assumption: the model satisfies the conjunctions. */ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml); + /** @@ -149,6 +150,16 @@ namespace pdr { */ void hoist_non_bool_if(expr_ref& fml); + + /** + \brief normalize coefficients in polynomials so that least coefficient is 1. + */ + void normalize_arithmetic(expr_ref& t); + + + /** + \brief determine if formulas belong to difference logic or UTVPI fragment. + */ bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls); diff --git a/src/test/arith_rewriter.cpp b/src/test/arith_rewriter.cpp index 0933e9d11..9eb9e559b 100644 --- a/src/test/arith_rewriter.cpp +++ b/src/test/arith_rewriter.cpp @@ -2,6 +2,33 @@ #include "bv_decl_plugin.h" #include "ast_pp.h" #include "reg_decl_plugins.h" +#include "th_rewriter.h" +#include "model.h" +#include "pdr_util.h" +#include "smt2parser.h" + + +static expr_ref parse_fml(ast_manager& m, char const* str) { + expr_ref result(m); + cmd_context ctx(false, &m); + ctx.set_ignore_check(true); + std::ostringstream buffer; + buffer << "(declare-const x Real)\n" + << "(declare-const y Real)\n" + << "(declare-const z Real)\n" + << "(declare-const a Real)\n" + << "(declare-const b Real)\n" + << "(assert " << str << ")\n"; + std::istringstream is(buffer.str()); + VERIFY(parse_smt2_commands(ctx, is)); + SASSERT(ctx.begin_assertions() != ctx.end_assertions()); + result = *ctx.begin_assertions(); + return result; +} + +static char const* example1 = "(<= (+ (* 1.3 x y) (* 2.3 y y) (* (- 1.1 x x))) 2.2)"; +static char const* example2 = "(= (+ 4 3 (- (* 3 x x) (* 5 y)) y) 0)"; + void tst_arith_rewriter() { ast_manager m; @@ -14,4 +41,19 @@ void tst_arith_rewriter() { expr* args[2] = { t1, t2 }; ar.mk_mul(2, args, result); std::cout << mk_pp(result, m) << "\n"; + + + th_rewriter rw(m); + expr_ref fml = parse_fml(m, example1); + rw(fml); + std::cout << mk_pp(fml, m) << "\n"; + pdr::normalize_arithmetic(fml); + std::cout << mk_pp(fml, m) << "\n"; + + + fml = parse_fml(m, example2); + rw(fml); + std::cout << mk_pp(fml, m) << "\n"; + pdr::normalize_arithmetic(fml); + std::cout << mk_pp(fml, m) << "\n"; } From e7f458101c5ccfc5bb64449cc5eb928bd3cc6674 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Aug 2013 10:53:46 -0700 Subject: [PATCH 223/281] add normalizer of monomial coefficients Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz_qe/pdr_util.cpp b/src/muz_qe/pdr_util.cpp index 169eeec72..3d93f8104 100644 --- a/src/muz_qe/pdr_util.cpp +++ b/src/muz_qe/pdr_util.cpp @@ -1430,6 +1430,6 @@ namespace pdr { } template class rewriter_tpl; - +template class rewriter_tpl; From a20656de35f664b922c1f5f47212656abeec03b5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Aug 2013 10:57:25 -0700 Subject: [PATCH 224/281] fix unused variable warning in unit test Signed-off-by: Nikolaj Bjorner --- src/test/polynorm.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/polynorm.cpp b/src/test/polynorm.cpp index 9853181ca..092ac022a 100644 --- a/src/test/polynorm.cpp +++ b/src/test/polynorm.cpp @@ -109,10 +109,12 @@ void tst_polynorm() { reg_decl_plugins(m); expr_ref fml(m); - fml = parse_fml(m, example2); - + fml = parse_fml(m, example1); std::cout << mk_pp(fml, m) << "\n"; + nf(fml); + fml = parse_fml(m, example2); + std::cout << mk_pp(fml, m) << "\n"; nf(fml); From 1c3f715e26ad80346e9ce4128e042d27279f05e0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Aug 2013 12:21:49 -0700 Subject: [PATCH 225/281] switch between convex and interior hull, add multiple cores Signed-off-by: Nikolaj Bjorner --- src/muz_qe/fixedpoint_params.pyg | 3 +- src/muz_qe/pdr_context.cpp | 11 +++-- src/muz_qe/pdr_generalizers.cpp | 80 +++++++++++++++++++++++++------- src/muz_qe/pdr_generalizers.h | 8 +++- 4 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index 860dcb68e..555c44df2 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -49,7 +49,8 @@ def_module_params('fixedpoint', ('use_multicore_generalizer', BOOL, False, "PDR: extract multiple cores for blocking states"), ('use_inductive_generalizer', BOOL, True, "PDR: generalize lemmas using induction strengthening"), ('use_arith_inductive_generalizer', BOOL, False, "PDR: generalize lemmas using arithmetic heuristics for induction strengthening"), - ('use_convex_hull_generalizer', BOOL, False, "PDR: generalize using convex hulls of lemmas"), + ('use_convex_closure_generalizer', BOOL, False, "PDR: generalize using convex closures of lemmas"), + ('use_convex_interior_generalizer', BOOL, False, "PDR: generalize using convex interiors of lemmas"), ('cache_mode', UINT, 0, "PDR: use no (0), symbolic (1) or explicit cache (2) for model search"), ('inductive_reachability_check', BOOL, False, "PDR: assume negation of the cube on the previous level when " "checking for reachability (not only during cube weakening)"), diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index 0121e49b8..fd86a4402 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1578,7 +1578,9 @@ namespace pdr { m_fparams.m_arith_auto_config_simplex = true; m_fparams.m_arith_propagate_eqs = false; m_fparams.m_arith_eager_eq_axioms = false; - if (m_params.use_utvpi() && !m_params.use_convex_hull_generalizer()) { + if (m_params.use_utvpi() && + !m_params.use_convex_closure_generalizer() && + !m_params.use_convex_interior_generalizer()) { if (classify.is_dl()) { m_fparams.m_arith_mode = AS_DIFF_LOGIC; m_fparams.m_arith_expand_eqs = true; @@ -1590,8 +1592,11 @@ namespace pdr { } } } - if (m_params.use_convex_hull_generalizer()) { - m_core_generalizers.push_back(alloc(core_convex_hull_generalizer, *this)); + if (m_params.use_convex_closure_generalizer()) { + m_core_generalizers.push_back(alloc(core_convex_hull_generalizer, *this, true)); + } + if (m_params.use_convex_interior_generalizer()) { + m_core_generalizers.push_back(alloc(core_convex_hull_generalizer, *this, false)); } if (!use_mc && m_params.use_inductive_generalizer()) { m_core_generalizers.push_back(alloc(core_bool_inductive_generalizer, *this, 0)); diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index c094b6c7f..2c49917be 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -147,18 +147,23 @@ namespace pdr { } - core_convex_hull_generalizer::core_convex_hull_generalizer(context& ctx): + core_convex_hull_generalizer::core_convex_hull_generalizer(context& ctx, bool is_closure): core_generalizer(ctx), m(ctx.get_manager()), a(m), m_sigma(m), - m_trail(m) { + m_trail(m), + m_is_closure(is_closure) { m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); } + void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { + method1(n, core, uses_level, new_cores); + } + void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { - method1(n, core, uses_level); + UNREACHABLE(); } // use the entire region as starting point for generalization. @@ -174,20 +179,27 @@ namespace pdr { // If Constraints & Transition(y0, y) is unsat, then // update with new core. // - void core_convex_hull_generalizer::method1(model_node& n, expr_ref_vector& core, bool& uses_level) { + void core_convex_hull_generalizer::method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { manager& pm = n.pt().get_pdr_manager(); expr_ref_vector conv1(m), conv2(m), core1(m), core2(m), eqs(m); if (core.empty()) { return; } + new_cores.push_back(std::make_pair(core, uses_level)); add_variables(n, eqs); if (!mk_convex(core, 0, conv1)) { IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core), m) << "\n";); return; } conv1.append(eqs); - conv1.push_back(a.mk_gt(m_sigma[0].get(), a.mk_numeral(rational(0), a.mk_real()))); - conv1.push_back(a.mk_gt(m_sigma[1].get(), a.mk_numeral(rational(0), a.mk_real()))); + if (m_is_closure) { + conv1.push_back(a.mk_gt(m_sigma[0].get(), a.mk_numeral(rational(0), a.mk_real()))); + conv1.push_back(a.mk_gt(m_sigma[1].get(), a.mk_numeral(rational(0), a.mk_real()))); + } + else { + conv1.push_back(a.mk_ge(m_sigma[0].get(), a.mk_numeral(rational(0), a.mk_real()))); + conv1.push_back(a.mk_ge(m_sigma[1].get(), a.mk_numeral(rational(0), a.mk_real()))); + } conv1.push_back(m.mk_eq(a.mk_numeral(rational(1), a.mk_real()), a.mk_add(m_sigma[0].get(), m_sigma[1].get()))); expr_ref fml = n.pt().get_formulas(n.level(), false); expr_ref_vector fmls(m); @@ -202,22 +214,23 @@ namespace pdr { } conv2.append(conv1); expr_ref state = pm.mk_and(conv2); - TRACE("pdr", tout << "Check:\n" << mk_pp(state, m) << "\n"; - tout << "New formula:\n" << mk_pp(pm.mk_and(core), m) << "\n"; - tout << "Old formula:\n" << mk_pp(fml, m) << "\n"; - + TRACE("pdr", + tout << "Check states:\n" << mk_pp(state, m) << "\n"; + tout << "Old states:\n" << mk_pp(fml, m) << "\n"; ); model_node nd(0, state, n.pt(), n.level()); pred_transformer::scoped_farkas sf(n.pt(), true); - if (l_false == n.pt().is_reachable(nd, &conv2, uses_level)) { + bool uses_level1 = uses_level; + if (l_false == n.pt().is_reachable(nd, &conv2, uses_level1)) { + new_cores.push_back(std::make_pair(conv2, uses_level1)); + + expr_ref state1 = pm.mk_and(conv2); TRACE("pdr", tout << mk_pp(state, m) << "\n"; - tout << "Generalized to:\n" << mk_pp(pm.mk_and(conv2), m) << "\n";); + tout << "Generalized to:\n" << mk_pp(state1, m) << "\n";); IF_VERBOSE(0, verbose_stream() << mk_pp(state, m) << "\n"; - verbose_stream() << "Generalized to:\n" << mk_pp(pm.mk_and(conv2), m) << "\n";); - core.reset(); - core.append(conv2); + verbose_stream() << "Generalized to:\n" << mk_pp(state1, m) << "\n";); } } } @@ -317,12 +330,47 @@ namespace pdr { } } + expr_ref core_convex_hull_generalizer::mk_closure(expr* e) { + expr* e0, *e1, *e2; + expr_ref result(m); + if (a.is_lt(e, e1, e2)) { + result = a.mk_le(e1, e2); + } + else if (a.is_gt(e, e1, e2)) { + result = a.mk_ge(e1, e2); + } + else if (m.is_not(e, e0) && a.is_ge(e0, e1, e2)) { + result = a.mk_le(e1, e2); + } + else if (m.is_not(e, e0) && a.is_le(e0, e1, e2)) { + result = a.mk_ge(e1, e2); + } + else if (a.is_ge(e) || a.is_le(e) || m.is_eq(e) || + (m.is_not(e, e0) && (a.is_gt(e0) || a.is_lt(e0)))) { + result = e; + } + else { + IF_VERBOSE(1, verbose_stream() << "Cannot close: " << mk_pp(e, m) << "\n";); + } + return result; + } + + bool core_convex_hull_generalizer::mk_closure(expr_ref_vector& conj) { + for (unsigned i = 0; i < conj.size(); ++i) { + conj[i] = mk_closure(conj[i].get()); + if (!conj[i].get()) { + return false; + } + } + return true; + } + bool core_convex_hull_generalizer::mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv) { conv.reset(); for (unsigned i = 0; i < core.size(); ++i) { mk_convex(core[i], index, conv); } - return !conv.empty(); + return !conv.empty() && mk_closure(conv); } void core_convex_hull_generalizer::mk_convex(expr* fml, unsigned index, expr_ref_vector& conv) { diff --git a/src/muz_qe/pdr_generalizers.h b/src/muz_qe/pdr_generalizers.h index 0aee94c16..ece1f51f1 100644 --- a/src/muz_qe/pdr_generalizers.h +++ b/src/muz_qe/pdr_generalizers.h @@ -81,16 +81,20 @@ namespace pdr { obj_map m_left; obj_map m_right; obj_map m_models; + bool m_is_closure; + expr_ref mk_closure(expr* e); + bool mk_closure(expr_ref_vector& conj); bool mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv); void mk_convex(expr* fml, unsigned index, expr_ref_vector& conv); bool mk_convex(expr* term, unsigned index, bool is_mul, expr_ref& result); bool translate(func_decl* fn, unsigned index, expr_ref& result); - void method1(model_node& n, expr_ref_vector& core, bool& uses_level); + void method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); void method2(model_node& n, expr_ref_vector& core, bool& uses_level); void add_variables(model_node& n, expr_ref_vector& eqs); public: - core_convex_hull_generalizer(context& ctx); + core_convex_hull_generalizer(context& ctx, bool is_closure); virtual ~core_convex_hull_generalizer() {} + virtual void operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); virtual void operator()(model_node& n, expr_ref_vector& core, bool& uses_level); }; From 0f83e7a251a4d1f094d3abba2c76e6c7512e032f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 10 Aug 2013 12:23:34 -0700 Subject: [PATCH 226/281] fix bug masked by default configuration Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index bce59657a..d08e6f13a 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -118,7 +118,7 @@ public: void mk_eq(expr * arg1, expr * arg2, expr_ref & result) { if (mk_eq_core(arg1, arg2, result) == BR_FAILED) - result = m_util.mk_le(arg1, arg2); + result = m_util.mk_eq(arg1, arg2); } void mk_le(expr * arg1, expr * arg2, expr_ref & result) { if (mk_le_core(arg1, arg2, result) == BR_FAILED) From 6a820adfed83a4db4cc520f877deec4d73c8dfc9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Aug 2013 09:43:17 -0700 Subject: [PATCH 227/281] fix logic for adding cores Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_generalizers.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index 2c49917be..bf1693ce3 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -182,12 +182,14 @@ namespace pdr { void core_convex_hull_generalizer::method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { manager& pm = n.pt().get_pdr_manager(); expr_ref_vector conv1(m), conv2(m), core1(m), core2(m), eqs(m); + unsigned orig_size = new_cores.size(); if (core.empty()) { + new_cores.push_back(std::make_pair(core, uses_level)); return; } - new_cores.push_back(std::make_pair(core, uses_level)); add_variables(n, eqs); if (!mk_convex(core, 0, conv1)) { + new_cores.push_back(std::make_pair(core, uses_level)); IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core), m) << "\n";); return; } @@ -233,6 +235,10 @@ namespace pdr { verbose_stream() << "Generalized to:\n" << mk_pp(state1, m) << "\n";); } } + if (!m_is_closure || new_cores.empty()) { + new_cores.push_back(std::make_pair(core, uses_level)); + } + } // take as starting point two points from different regions. From 661fe7eec9b4db7f86681953248a242d24754992 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 11 Aug 2013 19:10:46 -0700 Subject: [PATCH 228/281] add missing detach in coi_filter Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_coi_filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz_qe/dl_mk_coi_filter.cpp b/src/muz_qe/dl_mk_coi_filter.cpp index 7bbb14353..a0fc845bf 100644 --- a/src/muz_qe/dl_mk_coi_filter.cpp +++ b/src/muz_qe/dl_mk_coi_filter.cpp @@ -42,7 +42,7 @@ namespace datalog { scoped_ptr result1 = top_down(source); scoped_ptr result2 = bottom_up(result1?*result1:source); if (!result2) { - result2 = result1; + result2 = result1.detach(); } return result2.detach(); } From 0fd94a033f86f2c8c3750234cabda95d93cad719 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Aug 2013 09:52:10 -0700 Subject: [PATCH 229/281] change non-null test Signed-off-by: Nikolaj Bjorner --- src/api/api_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index cf179332a..05e1ca675 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -139,7 +139,7 @@ namespace api { if (m_interruptable) (*m_interruptable)(); m().set_cancel(true); - if (m_rcf_manager.get() == 0) + if (m_rcf_manager.get() != 0) m_rcf_manager->set_cancel(true); } } From 6c5f7741b2d100d325228db1de5d1960fc20ea0f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Aug 2013 11:55:23 -0700 Subject: [PATCH 230/281] more on polynorm Signed-off-by: Nikolaj Bjorner --- src/smt/theory_dl.cpp | 2 +- src/test/polynorm.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_dl.cpp b/src/smt/theory_dl.cpp index 9c3489aec..4ef1bd8e0 100644 --- a/src/smt/theory_dl.cpp +++ b/src/smt/theory_dl.cpp @@ -91,7 +91,7 @@ namespace smt { rational val; if (ctx.e_internalized(rep_of) && th_bv && th_bv->get_fixed_value(rep_of.get(), val)) { - result = m_th.u().mk_numeral(val.get_int64(), s); + result = m_th.u().mk_numeral(val.get_int64(), s); } else { result = m_th.u().mk_numeral(0, s); diff --git a/src/test/polynorm.cpp b/src/test/polynorm.cpp index 092ac022a..3593e98ce 100644 --- a/src/test/polynorm.cpp +++ b/src/test/polynorm.cpp @@ -2,6 +2,7 @@ #include "smt2parser.h" #include "arith_decl_plugin.h" #include "reg_decl_plugins.h" +#include "arith_rewriter.h" #include "ast_pp.h" @@ -27,6 +28,114 @@ static char const* example1 = "(= (+ (- (* x x) (* 2 y)) y) 0)"; static char const* example2 = "(= (+ 4 3 (- (* x x) (* 2 y)) y) 0)"; +class poly_nf { + expr_ref m_coefficient; + expr_ref_vector m_coefficients; + expr_ref_vector m_factors; +public: + poly_nf(ast_manager& m): + m_coefficient(m), + m_coefficients(m), + m_factors(m) {} + + expr_ref& coefficient() { return m_coefficient; } + expr_ref_vector& coefficients() { return m_coefficients; } + expr_ref_vector& factors() { return m_factors; } + + void reset() { + m_coefficient.reset(); + m_coefficients.reset(); + m_factors.reset(); + } + +}; + +class polynorm { + ast_manager& m; + arith_util m_arith; + arith_rewriter m_arith_rw; + th_rewriter m_rw; +public: + polynorm(ast_manager& m): m(m), m_arith(m), m_arith_rw(m), m_rw(m) {} + +private: + expr_ref_vector mk_fresh_constants(unsigned num, sort* s) { + expr_ref_vector result(m); + for (unsigned i = 0; i < num; ++i) { + result.push_back(m.mk_fresh_const("fresh", s)); + } + return result; + } + + expr_ref_vector mk_fresh_reals(unsigned num) { + return mk_fresh_constants(num, m_arith.mk_real()); + } + + expr_ref mk_mul(unsigned num_args, expr* const* args) { + expr_ref result(m); + m_arith_rw.mk_mul(num_args, args, result); + return result; + } + + void nf(expr_ref& term, obj_hashtable& constants, poly_nf& poly) { + + expr_ref_vector& factors = poly.factors(); + expr_ref_vector& coefficients = poly.coefficients(); + expr_ref& coefficient = poly.coefficient(); + + m_rw(term); + + if (m_arith.is_add(term)) { + factors.append(to_app(term)->get_num_args(), to_app(term)->get_args()); + } + else { + factors.push_back(term); + } + for (unsigned i = 0; i < factors.size(); ++i) { + expr* f = factors[i].get(); + unsigned num_args = 1; + expr* const* args = &f; + if (m_arith.is_mul(f)) { + num_args = to_app(f)->get_num_args(); + args = to_app(f)->get_args(); + } + for (unsigned j = 0; j < num_args; ++j) { + if (m_arith.is_numeral(args[j]) || constants.contains(args[j])) { + //consts.push_back(args[j]); + } + else { + // vars.push_back(args[j]); + } + // deal with the relevant corner cases. + } +#if 0 + rational r; + if (m_arith.is_mul(f) && m_arith.is_numeral(to_app(f)->get_arg(0), r)) { + coefficients.push_back(r); + factors[i] = mk_mul(to_app(f)->get_num_args()-1, to_app(f)->get_args()+1); + } + else if (m_arith.is_numeral(f, r)) { + factors[i] = factors.back(); + factors.pop_back(); + SASSERT(coefficient.is_zero()); + SASSERT(!r.is_zero()); + coefficient = r; + --i; // repeat examining 'i' + } + else { + coefficients.push_back(rational(1)); + } +#endif + } + + TRACE("polynorm", + tout << mk_pp(coefficient, m) << "\n"; + for (unsigned i = 0; i < factors.size(); ++i) { + tout << mk_pp(factors[i].get(), m) << " * " << mk_pp(coefficients[i].get(), m) << "\n"; + }); + } +}; + // ast /// sort : ast /// func_decl : ast From 04678d96282e7ef62346b5b0877201b3708115a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Aug 2013 17:56:07 -0700 Subject: [PATCH 231/281] improve error message when sorts are non-numeric Signed-off-by: Nikolaj Bjorner --- src/ast/dl_decl_plugin.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ast/dl_decl_plugin.cpp b/src/ast/dl_decl_plugin.cpp index 4f0c9a75d..6d0823a24 100644 --- a/src/ast/dl_decl_plugin.cpp +++ b/src/ast/dl_decl_plugin.cpp @@ -657,7 +657,9 @@ namespace datalog { SASSERT(value == 1); return m.mk_true(); } - m.raise_exception("unrecognized sort"); + std::stringstream strm; + strm << "sort '" << mk_pp(s, m) << "' is not recognized as a sort that contains numeric values.\nUse Bool, BitVec, Int, Real, or a Finite domain sort"; + m.raise_exception(strm.str().c_str()); return 0; } From 01d59d2c9164d1070d895c9db7f9c78f576e169f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Aug 2013 18:36:27 -0700 Subject: [PATCH 232/281] fix bugs reported by Arie Gurfinkel Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_context.cpp | 5 +++++ src/muz_qe/pdr_generalizers.cpp | 11 ++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/muz_qe/pdr_context.cpp b/src/muz_qe/pdr_context.cpp index fd86a4402..ff40be4f3 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz_qe/pdr_context.cpp @@ -1881,6 +1881,11 @@ namespace pdr { // predicate transformer (or some unfolding of it). // lbool context::expand_state(model_node& n, expr_ref_vector& result, bool& uses_level) { + TRACE("pdr", + tout << "expand_state: " << n.pt().head()->get_name(); + tout << " level: " << n.level() << "\n"; + tout << mk_pp(n.state(), m) << "\n";); + return n.pt().is_reachable(n, &result, uses_level); } diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index bf1693ce3..28226dffa 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -195,13 +195,14 @@ namespace pdr { } conv1.append(eqs); if (m_is_closure) { - conv1.push_back(a.mk_gt(m_sigma[0].get(), a.mk_numeral(rational(0), a.mk_real()))); - conv1.push_back(a.mk_gt(m_sigma[1].get(), a.mk_numeral(rational(0), a.mk_real()))); - } - else { conv1.push_back(a.mk_ge(m_sigma[0].get(), a.mk_numeral(rational(0), a.mk_real()))); conv1.push_back(a.mk_ge(m_sigma[1].get(), a.mk_numeral(rational(0), a.mk_real()))); } + else { + // is interior: + conv1.push_back(a.mk_gt(m_sigma[0].get(), a.mk_numeral(rational(0), a.mk_real()))); + conv1.push_back(a.mk_gt(m_sigma[1].get(), a.mk_numeral(rational(0), a.mk_real()))); + } conv1.push_back(m.mk_eq(a.mk_numeral(rational(1), a.mk_real()), a.mk_add(m_sigma[0].get(), m_sigma[1].get()))); expr_ref fml = n.pt().get_formulas(n.level(), false); expr_ref_vector fmls(m); @@ -235,7 +236,7 @@ namespace pdr { verbose_stream() << "Generalized to:\n" << mk_pp(state1, m) << "\n";); } } - if (!m_is_closure || new_cores.empty()) { + if (!m_is_closure || new_cores.size() == orig_size) { new_cores.push_back(std::make_pair(core, uses_level)); } From 7bbabcdf6dadcc133044f7b36e0647583ec63796 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Aug 2013 14:47:48 -0700 Subject: [PATCH 233/281] updated documentation for finite domain sizes Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 8 ++++++++ src/api/z3_api.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 68cca046e..ae8b233d1 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -303,6 +303,9 @@ namespace Microsoft.Z3 /// /// Create a new finite domain sort. + /// The name used to identify the sort + /// The size of the sort + /// The result is a sort /// public FiniteDomainSort MkFiniteDomainSort(Symbol name, ulong size) { @@ -315,6 +318,11 @@ namespace Microsoft.Z3 /// /// Create a new finite domain sort. + /// The name used to identify the sort + /// The size of the sort + /// The result is a sort + /// Elements of the sort are created using , + /// and the elements range from 0 to size-1. /// public FiniteDomainSort MkFiniteDomainSort(string name, ulong size) { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 458e2f53f..2b8c74e65 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1721,6 +1721,8 @@ extern "C" { To create constants that belong to the finite domain, use the APIs for creating numerals and pass a numeric constant together with the sort returned by this call. + The numeric constant should be between 0 and the less + than the size of the domain. \sa Z3_get_finite_domain_sort_size From e43383b6a8fa70afde7a205e3cd6ec27c71ecf13 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Aug 2013 21:11:14 -0700 Subject: [PATCH 234/281] filter query predicates from models Signed-off-by: Nikolaj Bjorner --- src/muz_qe/clp_context.cpp | 10 +++++++--- src/muz_qe/dl_mk_array_blast.cpp | 2 +- src/muz_qe/dl_rule.cpp | 9 ++++++++- src/muz_qe/horn_tactic.cpp | 12 +++++++++++- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/muz_qe/clp_context.cpp b/src/muz_qe/clp_context.cpp index 3a3908f59..01299a2b7 100644 --- a/src/muz_qe/clp_context.cpp +++ b/src/muz_qe/clp_context.cpp @@ -68,9 +68,13 @@ namespace datalog { m_goals.reset(); rm.mk_query(query, m_ctx.get_rules()); m_ctx.apply_default_transformation(); - func_decl *head_decl = m_ctx.get_rules().get_output_predicate(); - - expr_ref head(m_ctx.get_rules().get_predicate_rules(head_decl)[0]->get_head(), m); + func_decl* head_decl = m_ctx.get_rules().get_output_predicate(); + rule_set& rules = m_ctx.get_rules(); + rule_vector const& rv = rules.get_predicate_rules(head_decl); + if (rv.empty()) { + return l_false; + } + expr_ref head(rv[0]->get_head(), m); ground(head); m_goals.push_back(to_app(head)); return search(20, 0); diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz_qe/dl_mk_array_blast.cpp index 9f057a148..2bfb6807a 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz_qe/dl_mk_array_blast.cpp @@ -250,11 +250,11 @@ namespace datalog { rule_set new_rules(m_ctx); rm.mk_rule(fml2, p, new_rules, r.name()); - TRACE("dl", new_rules.last()->display(m_ctx, tout << "new rule\n");); rule_ref new_rule(rm); if (m_simplifier.transform_rule(new_rules.last(), new_rule)) { rules.add_rule(new_rule.get()); rm.mk_rule_rewrite_proof(r, *new_rule.get()); + TRACE("dl", new_rule->display(m_ctx, tout << "new rule\n");); } return true; } diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index ac683eca9..70da4ed4b 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -41,6 +41,7 @@ Revision History: #include"expr_replacer.h" #include"bool_rewriter.h" #include"expr_safe_replace.h" +#include"filter_model_converter.h" namespace datalog { @@ -335,8 +336,14 @@ namespace datalog { vars.reverse(); names.reverse(); func_decl* qpred = m_ctx.mk_fresh_head_predicate(symbol("query"), symbol(), vars.size(), vars.c_ptr(), body_pred); - m_ctx.register_predicate(qpred, false); + m_ctx.register_predicate(qpred, false); rules.set_output_predicate(qpred); + + if (m_ctx.get_model_converter()) { + filter_model_converter* mc = alloc(filter_model_converter, m); + mc->insert(qpred); + m_ctx.add_model_converter(mc); + } expr_ref_vector qhead_args(m); for (unsigned i = 0; i < vars.size(); i++) { diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz_qe/horn_tactic.cpp index 9d331cbfa..1916839f4 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz_qe/horn_tactic.cpp @@ -24,6 +24,7 @@ Revision History: #include"expr_replacer.h" #include"dl_rule_transformer.h" #include"dl_mk_slice.h" +#include"filter_model_converter.h" class horn_tactic : public tactic { struct imp { @@ -226,6 +227,9 @@ class horn_tactic : public tactic { } queries.reset(); queries.push_back(q); + filter_model_converter* mc1 = alloc(filter_model_converter, m); + mc1->insert(to_app(q)->get_decl()); + mc = mc1; } SASSERT(queries.size() == 1); q = queries[0].get(); @@ -276,7 +280,13 @@ class horn_tactic : public tactic { g->reset(); if (produce_models) { model_ref md = m_ctx.get_model(); - mc = model2model_converter(&*md); + model_converter_ref mc2 = model2model_converter(&*md); + if (mc) { + mc = concat(mc.get(), mc2.get()); + } + else { + mc = mc2; + } } break; } From 3b1344f68145771d029266aad8fd49c5af074e47 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Aug 2013 11:53:35 -0700 Subject: [PATCH 235/281] working on scale transformation Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_scale.cpp | 128 +++++++++++++++++++++++++++++++ src/muz_qe/dl_mk_scale.h | 47 ++++++++++++ src/muz_qe/fixedpoint_params.pyg | 1 + 3 files changed, 176 insertions(+) create mode 100644 src/muz_qe/dl_mk_scale.cpp create mode 100644 src/muz_qe/dl_mk_scale.h diff --git a/src/muz_qe/dl_mk_scale.cpp b/src/muz_qe/dl_mk_scale.cpp new file mode 100644 index 000000000..bcd19d0a4 --- /dev/null +++ b/src/muz_qe/dl_mk_scale.cpp @@ -0,0 +1,128 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_scale.cpp + +Abstract: + + +Author: + + Nikolaj Bjorner (nbjorner) 2013-08-19 + +Revision History: + +--*/ + +#include"dl_mk_scale.h" +#include"dl_context.h" + +namespace datalog { + + + mk_scale::mk_scale(context & ctx, unsigned priority): + plugin(priority), + m(ctx.get_manager()), + m_ctx(ctx), + a(m), + m_trail(m) { + } + + mk_scale::~mk_scale() { } + + rule_set * mk_scale::operator()(rule_set const & source) { + if (!m_ctx.get_params().scale()) { + return 0; + } + context& ctx = source.get_context(); + rule_manager& rm = source.get_rule_manager(); + rule_set * result = alloc(rule_set, ctx); + unsigned sz = source.get_num_rules(); + rule_ref new_rule(rm); + app_ref_vector tail(m); + app_ref head(m); + svector neg; + ptr_vector vars; + for (unsigned i = 0; i < sz; ++i) { + rule & r = *source.get_rule(i); + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + tail.reset(); + neg.reset(); + vars.reset(); + r.get_vars(vars); + m_cache.reset(); + m_trail.reset(); + unsigned num_vars = vars.size(); + for (unsigned j = utsz; j < tsz; ++j) { + tail.push_back(mk_pred(num_vars, r.get_tail(j))); + neg.push_back(false); + } + for (unsigned j = 0; j < utsz; ++j) { + tail.push_back(mk_constraint(num_vars, r.get_tail(j))); + neg.push_back(false); + } + tail.push_back(a.mk_gt(m.mk_var(num_vars, a.mk_real()), a.mk_numeral(rational(0), false))); + neg.push_back(false); + new_rule = rm.mk(mk_pred(num_vars, r.get_head()), tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + result->add_rule(new_rule); + if (source.is_output_predicate(r.get_decl())) { + result->set_output_predicate(new_rule->get_decl()); + } + } + TRACE("dl", result->display(tout);); + return result; + } + + app_ref mk_scale::mk_pred(unsigned num_vars, app* q) { + func_decl* f = q->get_decl(); + ptr_vector domain(f->get_arity(), f->get_domain()); + domain.push_back(a.mk_real()); + func_decl_ref g(m); + g = m.mk_func_decl(f->get_name(), f->get_arity() + 1, domain.c_ptr(), f->get_range()); + ptr_vector args(q->get_num_args(), q->get_args()); + args.push_back(m.mk_var(num_vars, a.mk_real())); + m_ctx.register_predicate(g, false); + return app_ref(m.mk_app(g, q->get_num_args() + 1, args.c_ptr()), m); + } + + app_ref mk_scale::mk_constraint(unsigned num_vars, app* q) { + expr* r = linearize(num_vars, q); + SASSERT(is_app(r)); + return app_ref(to_app(r), m); + } + + expr* mk_scale::linearize(unsigned num_vars, expr* e) { + expr* r; + if (m_cache.find(e, r)) { + return expr_ref(r, m); + } + if (!is_app(e)) { + return expr_ref(e, m); + } + expr_ref result(m); + app* ap = to_app(e); + if (ap->get_family_id() == m.get_basic_family_id() || + a.is_add(e) || a.is_sub(e) || + a.is_le(e) || a.is_ge(e) || + a.is_lt(e) || a.is_gt(e)) { + expr_ref_vector args(m); + for (unsigned i = 0; i < ap->get_num_args(); ++i) { + args.push_back(linearize(num_vars, ap->get_arg(i))); + } + result = m.mk_app(ap->get_decl(), args.size(), args.c_ptr()); + } + else if (a.is_numeral(e)) { + result = a.mk_mul(m.mk_var(num_vars, a.mk_real()), e); + } + else { + result = e; + } + m_trail.push_back(result); + m_cache.insert(e, result); + return result; + } + +}; diff --git a/src/muz_qe/dl_mk_scale.h b/src/muz_qe/dl_mk_scale.h new file mode 100644 index 000000000..cff226321 --- /dev/null +++ b/src/muz_qe/dl_mk_scale.h @@ -0,0 +1,47 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_scale.h + +Abstract: + + Add scale factor to linear (Real) arithemetic Horn clauses. + The transformation replaces occurrences of isolated constants by + a scale multiplied to each constant. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-08-19 + +Revision History: + +--*/ +#ifndef _DL_MK_SCALE_H_ +#define _DL_MK_SCALE_H_ + +#include"dl_rule_transformer.h" +#include"arith_decl_plugin.h" + +namespace datalog { + + class mk_scale : public rule_transformer::plugin { + ast_manager& m; + context& m_ctx; + arith_util a; + expr_ref_vector m_trail; + obj_map m_cache; + expr* linearize(unsigned num_vars, expr* e); + app_ref mk_pred(unsigned num_vars, app* q); + app_ref mk_constraint(unsigned num_vars, app* q); + public: + mk_scale(context & ctx, unsigned priority = 33039); + ~mk_scale(); + rule_set * operator()(rule_set const & source); + }; + +}; + +#endif /* _DL_MK_SCALE_H_ */ + diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz_qe/fixedpoint_params.pyg index 555c44df2..46f4fce99 100644 --- a/src/muz_qe/fixedpoint_params.pyg +++ b/src/muz_qe/fixedpoint_params.pyg @@ -11,6 +11,7 @@ def_module_params('fixedpoint', ('explanations_on_relation_level', BOOL, False, '(DATALOG) if true, explanations are generated as history of each relation, rather than per fact (generate_explanations must be set to true for this option to have any effect)'), ('magic_sets_for_queries', BOOL, False, "(DATALOG) magic set transformation will be used for queries"), ('magic', BOOL, False, "perform symbolic magic set transformation"), + ('scale', BOOL, False, "add scaling variable to linear real arithemtic clauses"), ('unbound_compressor', BOOL, True, "auxiliary relations will be introduced to avoid unbound variables in rule heads"), ('similarity_compressor', BOOL, True, "(DATALOG) rules that differ only in values of constants will be merged into a single rule"), ('similarity_compressor_threshold', UINT, 11, "(DATALOG) if similarity_compressor is on, this value determines how many similar rules there must be in order for them to be merged"), From 7c9e3c3b70296ef416e1bdb81fd8ef39e0b95f2d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Aug 2013 14:44:34 -0700 Subject: [PATCH 236/281] debug scale transformer, add model converter Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_context.cpp | 2 + src/muz_qe/dl_mk_scale.cpp | 109 ++++++++++++++++++++++++++--- src/muz_qe/dl_mk_scale.h | 13 ++-- src/muz_qe/dl_rule_transformer.cpp | 2 +- 4 files changed, 113 insertions(+), 13 deletions(-) diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index d8a50668b..9f250742c 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -48,6 +48,7 @@ Revision History: #include"dl_mk_magic_symbolic.h" #include"dl_mk_quantifier_abstraction.h" #include"dl_mk_quantifier_instantiation.h" +#include"dl_mk_scale.h" #include"datatype_decl_plugin.h" @@ -869,6 +870,7 @@ namespace datalog { if (get_params().magic()) { m_transf.register_plugin(alloc(datalog::mk_magic_symbolic, *this, 36020)); } + m_transf.register_plugin(alloc(datalog::mk_scale, *this, 36030)); transform_rules(m_transf); } diff --git a/src/muz_qe/dl_mk_scale.cpp b/src/muz_qe/dl_mk_scale.cpp index bcd19d0a4..90cbedb6c 100644 --- a/src/muz_qe/dl_mk_scale.cpp +++ b/src/muz_qe/dl_mk_scale.cpp @@ -21,6 +21,85 @@ Revision History: namespace datalog { + class mk_scale::scale_model_converter : public model_converter { + ast_manager& m; + func_decl_ref_vector m_trail; + arith_util a; + obj_map m_new2old; + public: + scale_model_converter(ast_manager& m): m(m), m_trail(m), a(m) {} + + virtual ~scale_model_converter() {} + + void add_new2old(func_decl* new_f, func_decl* old_f) { + m_trail.push_back(old_f); + m_trail.push_back(new_f); + m_new2old.insert(new_f, old_f); + } + + virtual void operator()(model_ref& md) { + model_ref old_model = alloc(model, m); + obj_map::iterator it = m_new2old.begin(); + obj_map::iterator end = m_new2old.end(); + for (; it != end; ++it) { + func_decl* old_p = it->m_value; + func_decl* new_p = it->m_key; + func_interp* old_fi = alloc(func_interp, m, old_p->get_arity()); + + if (new_p->get_arity() == 0) { + old_fi->set_else(md->get_const_interp(new_p)); + } + else { + func_interp* new_fi = md->get_func_interp(new_p); + expr_ref_vector subst(m); + var_subst vs(m, false); + expr_ref tmp(m); + + if (!new_fi) { + TRACE("dl", tout << new_p->get_name() << " has no value in the current model\n";); + dealloc(old_fi); + continue; + } + for (unsigned i = 0; i < old_p->get_arity(); ++i) { + subst.push_back(m.mk_var(i, old_p->get_domain(i))); + } + subst.push_back(a.mk_numeral(rational(1), a.mk_real())); + + // Hedge that we don't have to handle the general case for models produced + // by Horn clause solvers. + SASSERT(!new_fi->is_partial() && new_fi->num_entries() == 0); + vs(new_fi->get_else(), subst.size(), subst.c_ptr(), tmp); + old_fi->set_else(tmp); + old_model->register_decl(old_p, old_fi); + } + } + + // register values that have not been scaled. + unsigned sz = md->get_num_constants(); + for (unsigned i = 0; i < sz; ++i) { + func_decl* c = md->get_constant(i); + if (!m_new2old.contains(c)) { + old_model->register_decl(c, md->get_const_interp(c)); + } + } + sz = md->get_num_functions(); + for (unsigned i = 0; i < sz; ++i) { + func_decl* f = md->get_function(i); + if (!m_new2old.contains(f)) { + func_interp* fi = md->get_func_interp(f); + old_model->register_decl(f, fi->copy()); + } + } + md = old_model; + //TRACE("dl", model_smt2_pp(tout, m, *md, 0); ); + } + + virtual model_converter * translate(ast_translation & translator) { + UNREACHABLE(); + return 0; + } + }; + mk_scale::mk_scale(context & ctx, unsigned priority): plugin(priority), @@ -30,21 +109,27 @@ namespace datalog { m_trail(m) { } - mk_scale::~mk_scale() { } + mk_scale::~mk_scale() { + } rule_set * mk_scale::operator()(rule_set const & source) { if (!m_ctx.get_params().scale()) { return 0; } - context& ctx = source.get_context(); rule_manager& rm = source.get_rule_manager(); - rule_set * result = alloc(rule_set, ctx); + rule_set * result = alloc(rule_set, m_ctx); unsigned sz = source.get_num_rules(); rule_ref new_rule(rm); app_ref_vector tail(m); app_ref head(m); svector neg; ptr_vector vars; + ref smc; + if (m_ctx.get_model_converter()) { + smc = alloc(scale_model_converter, m); + } + m_mc = smc.get(); + for (unsigned i = 0; i < sz; ++i) { rule & r = *source.get_rule(i); unsigned utsz = r.get_uninterpreted_tail_size(); @@ -52,15 +137,15 @@ namespace datalog { tail.reset(); neg.reset(); vars.reset(); - r.get_vars(vars); m_cache.reset(); m_trail.reset(); + r.get_vars(vars); unsigned num_vars = vars.size(); - for (unsigned j = utsz; j < tsz; ++j) { + for (unsigned j = 0; j < utsz; ++j) { tail.push_back(mk_pred(num_vars, r.get_tail(j))); neg.push_back(false); } - for (unsigned j = 0; j < utsz; ++j) { + for (unsigned j = utsz; j < tsz; ++j) { tail.push_back(mk_constraint(num_vars, r.get_tail(j))); neg.push_back(false); } @@ -73,6 +158,11 @@ namespace datalog { } } TRACE("dl", result->display(tout);); + if (m_mc) { + m_ctx.add_model_converter(m_mc); + } + m_trail.reset(); + m_cache.reset(); return result; } @@ -85,6 +175,9 @@ namespace datalog { ptr_vector args(q->get_num_args(), q->get_args()); args.push_back(m.mk_var(num_vars, a.mk_real())); m_ctx.register_predicate(g, false); + if (m_mc) { + m_mc->add_new2old(g, f); + } return app_ref(m.mk_app(g, q->get_num_args() + 1, args.c_ptr()), m); } @@ -97,10 +190,10 @@ namespace datalog { expr* mk_scale::linearize(unsigned num_vars, expr* e) { expr* r; if (m_cache.find(e, r)) { - return expr_ref(r, m); + return r; } if (!is_app(e)) { - return expr_ref(e, m); + return e; } expr_ref result(m); app* ap = to_app(e); diff --git a/src/muz_qe/dl_mk_scale.h b/src/muz_qe/dl_mk_scale.h index cff226321..387a8868f 100644 --- a/src/muz_qe/dl_mk_scale.h +++ b/src/muz_qe/dl_mk_scale.h @@ -27,17 +27,22 @@ Revision History: namespace datalog { class mk_scale : public rule_transformer::plugin { + + class scale_model_converter; + ast_manager& m; context& m_ctx; arith_util a; expr_ref_vector m_trail; obj_map m_cache; - expr* linearize(unsigned num_vars, expr* e); - app_ref mk_pred(unsigned num_vars, app* q); - app_ref mk_constraint(unsigned num_vars, app* q); + scale_model_converter* m_mc; + + expr* linearize(unsigned num_vars, expr* e); + app_ref mk_pred(unsigned num_vars, app* q); + app_ref mk_constraint(unsigned num_vars, app* q); public: mk_scale(context & ctx, unsigned priority = 33039); - ~mk_scale(); + virtual ~mk_scale(); rule_set * operator()(rule_set const & source); }; diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index 0cad08cb4..9055007b9 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -37,7 +37,7 @@ namespace datalog { void rule_transformer::reset() { plugin_vector::iterator it = m_plugins.begin(); plugin_vector::iterator end = m_plugins.end(); - for(; it!=end; ++it) { + for(; it!=end; ++it) { dealloc(*it); } m_plugins.reset(); From e9ad4ab5840dccbb7506e3bbf20b8b4013ecb26e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Aug 2013 18:57:10 -0700 Subject: [PATCH 237/281] fix scaling Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_mk_scale.cpp | 48 +++++++++++++++++++++++++++----------- src/muz_qe/dl_mk_scale.h | 1 + 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/muz_qe/dl_mk_scale.cpp b/src/muz_qe/dl_mk_scale.cpp index 90cbedb6c..d666d0ca8 100644 --- a/src/muz_qe/dl_mk_scale.cpp +++ b/src/muz_qe/dl_mk_scale.cpp @@ -106,7 +106,8 @@ namespace datalog { m(ctx.get_manager()), m_ctx(ctx), a(m), - m_trail(m) { + m_trail(m), + m_eqs(m) { } mk_scale::~mk_scale() { @@ -135,23 +136,23 @@ namespace datalog { unsigned utsz = r.get_uninterpreted_tail_size(); unsigned tsz = r.get_tail_size(); tail.reset(); - neg.reset(); vars.reset(); m_cache.reset(); m_trail.reset(); + m_eqs.reset(); r.get_vars(vars); unsigned num_vars = vars.size(); for (unsigned j = 0; j < utsz; ++j) { tail.push_back(mk_pred(num_vars, r.get_tail(j))); - neg.push_back(false); } for (unsigned j = utsz; j < tsz; ++j) { tail.push_back(mk_constraint(num_vars, r.get_tail(j))); - neg.push_back(false); } + app_ref new_pred = mk_pred(num_vars, r.get_head()); + tail.append(m_eqs); tail.push_back(a.mk_gt(m.mk_var(num_vars, a.mk_real()), a.mk_numeral(rational(0), false))); - neg.push_back(false); - new_rule = rm.mk(mk_pred(num_vars, r.get_head()), tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); + neg.resize(tail.size(), false); + new_rule = rm.mk(new_pred, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true); result->add_rule(new_rule); if (source.is_output_predicate(r.get_decl())) { result->set_output_predicate(new_rule->get_decl()); @@ -166,14 +167,33 @@ namespace datalog { return result; } - app_ref mk_scale::mk_pred(unsigned num_vars, app* q) { + app_ref mk_scale::mk_pred(unsigned sigma_idx, app* q) { func_decl* f = q->get_decl(); ptr_vector domain(f->get_arity(), f->get_domain()); domain.push_back(a.mk_real()); func_decl_ref g(m); g = m.mk_func_decl(f->get_name(), f->get_arity() + 1, domain.c_ptr(), f->get_range()); - ptr_vector args(q->get_num_args(), q->get_args()); - args.push_back(m.mk_var(num_vars, a.mk_real())); + expr_ref_vector args(m); + for (unsigned i = 0; i < q->get_num_args(); ++i) { + expr* arg = q->get_arg(i); + rational val; + if (a.is_numeral(arg, val)) { + if (val.is_zero()) { + // arg is unchanged. + } + else if (val.is_one()) { + arg = m.mk_var(sigma_idx, a.mk_real()); + } + else { + // create a fresh variable 'v', add 'v == sigma*arg' + expr* v = m.mk_var(sigma_idx + 1 + m_eqs.size(), a.mk_real()); + m_eqs.push_back(m.mk_eq(v, a.mk_mul(arg, m.mk_var(sigma_idx, a.mk_real())))); + arg = v; + } + } + args.push_back(arg); + } + args.push_back(m.mk_var(sigma_idx, a.mk_real())); m_ctx.register_predicate(g, false); if (m_mc) { m_mc->add_new2old(g, f); @@ -181,13 +201,13 @@ namespace datalog { return app_ref(m.mk_app(g, q->get_num_args() + 1, args.c_ptr()), m); } - app_ref mk_scale::mk_constraint(unsigned num_vars, app* q) { - expr* r = linearize(num_vars, q); + app_ref mk_scale::mk_constraint(unsigned sigma_idx, app* q) { + expr* r = linearize(sigma_idx, q); SASSERT(is_app(r)); return app_ref(to_app(r), m); } - expr* mk_scale::linearize(unsigned num_vars, expr* e) { + expr* mk_scale::linearize(unsigned sigma_idx, expr* e) { expr* r; if (m_cache.find(e, r)) { return r; @@ -203,12 +223,12 @@ namespace datalog { a.is_lt(e) || a.is_gt(e)) { expr_ref_vector args(m); for (unsigned i = 0; i < ap->get_num_args(); ++i) { - args.push_back(linearize(num_vars, ap->get_arg(i))); + args.push_back(linearize(sigma_idx, ap->get_arg(i))); } result = m.mk_app(ap->get_decl(), args.size(), args.c_ptr()); } else if (a.is_numeral(e)) { - result = a.mk_mul(m.mk_var(num_vars, a.mk_real()), e); + result = a.mk_mul(m.mk_var(sigma_idx, a.mk_real()), e); } else { result = e; diff --git a/src/muz_qe/dl_mk_scale.h b/src/muz_qe/dl_mk_scale.h index 387a8868f..8498c891f 100644 --- a/src/muz_qe/dl_mk_scale.h +++ b/src/muz_qe/dl_mk_scale.h @@ -34,6 +34,7 @@ namespace datalog { context& m_ctx; arith_util a; expr_ref_vector m_trail; + app_ref_vector m_eqs; obj_map m_cache; scale_model_converter* m_mc; From 0b56440cba4ce3a9a066362fd36142c7487989b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Aug 2013 19:48:09 -0700 Subject: [PATCH 238/281] fix convex converter for multi-arity addition Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_generalizers.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index 28226dffa..55d8a05f8 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -434,9 +434,19 @@ namespace pdr { if (translate(app->get_decl(), index, result)) { return true; } - if (a.is_add(term, e1, e2) && mk_convex(e1, index, is_mul, r1) && mk_convex(e2, index, is_mul, r2)) { - result = a.mk_add(r1, r2); - return true; + if (a.is_add(term)) { + bool ok = true; + expr_ref_vector args(m); + for (unsigned i = 0; ok && i < app->get_num_args(); ++i) { + ok = mk_convex(app->get_arg(i), index, is_mul, r1); + if (ok) { + args.push_back(r1); + } + } + if (ok) { + result = a.mk_add(args.size(), args.c_ptr()); + } + return ok; } if (a.is_sub(term, e1, e2) && mk_convex(e1, index, is_mul, r1) && mk_convex(e2, index, is_mul, r2)) { result = a.mk_sub(r1, r2); From 5c145dcd4b4f8a03036c1123c18626be52d37c52 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Aug 2013 15:00:52 -0700 Subject: [PATCH 239/281] fix parameter checking on quantifiers (thanks to Esteban Pavese), fix query tracking in rel_context (thanks to Nuno Lopes), fix counter for free variables under quantfiers (thanks to Tomer Weiss) Signed-off-by: Nikolaj Bjorner --- src/api/api_quant.cpp | 5 ++++- src/ast/rewriter/ast_counter.cpp | 24 ++++++++++++++++-------- src/muz_qe/dl_context.cpp | 1 + src/muz_qe/dl_rule.cpp | 13 ++++++++++++- src/muz_qe/hnf.cpp | 7 ++++++- src/muz_qe/rel_context.cpp | 20 ++++++++++---------- src/muz_qe/rel_context.h | 2 +- 7 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/api/api_quant.cpp b/src/api/api_quant.cpp index 883e9e752..4170852a9 100644 --- a/src/api/api_quant.cpp +++ b/src/api/api_quant.cpp @@ -165,7 +165,10 @@ extern "C" { } for (unsigned i = 0; i < num_bound; ++i) { app* a = to_app(bound[i]); - SASSERT(a->get_kind() == AST_APP); + if (a->get_kind() != AST_APP) { + SET_ERROR_CODE(Z3_INVALID_ARG); + RETURN_Z3(0); + } symbol s(to_app(a)->get_decl()->get_name()); names.push_back(of_symbol(s)); types.push_back(of_sort(mk_c(c)->m().get_sort(a))); diff --git a/src/ast/rewriter/ast_counter.cpp b/src/ast/rewriter/ast_counter.cpp index a807237c5..6f49a232f 100644 --- a/src/ast/rewriter/ast_counter.cpp +++ b/src/ast/rewriter/ast_counter.cpp @@ -108,6 +108,7 @@ void var_counter::count_vars(ast_manager & m, const app * pred, int coef) { unsigned var_counter::get_max_var(bool& has_var) { has_var = false; unsigned max_var = 0; + ptr_vector qs; while (!m_todo.empty()) { expr* e = m_todo.back(); m_todo.pop_back(); @@ -117,14 +118,7 @@ unsigned var_counter::get_max_var(bool& has_var) { m_visited.mark(e, true); switch(e->get_kind()) { case AST_QUANTIFIER: { - var_counter aux_counter; - quantifier* q = to_quantifier(e); - bool has_var1 = false; - unsigned max_v = aux_counter.get_max_var(has_var1); - if (max_v > max_var + q->get_num_decls()) { - max_var = max_v - q->get_num_decls(); - has_var = true; - } + qs.push_back(to_quantifier(e)); break; } case AST_VAR: { @@ -147,6 +141,20 @@ unsigned var_counter::get_max_var(bool& has_var) { } } m_visited.reset(); + + while (!qs.empty()) { + var_counter aux_counter; + quantifier* q = qs.back(); + qs.pop_back(); + aux_counter.m_todo.push_back(q->get_expr()); + bool has_var1 = false; + unsigned max_v = aux_counter.get_max_var(has_var1); + if (max_v >= max_var + q->get_num_decls()) { + max_var = max_v - q->get_num_decls(); + has_var = has_var || has_var1; + } + } + return max_var; } diff --git a/src/muz_qe/dl_context.cpp b/src/muz_qe/dl_context.cpp index 9f250742c..7da9808e7 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz_qe/dl_context.cpp @@ -652,6 +652,7 @@ namespace datalog { if (check_pred(e)) { std::ostringstream out; out << "recursive predicate " << mk_ismt2_pp(e, get_manager()) << " occurs nested in body"; + r->display(*this, out << "\n"); throw default_exception(out.str()); } diff --git a/src/muz_qe/dl_rule.cpp b/src/muz_qe/dl_rule.cpp index 70da4ed4b..455f2c244 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz_qe/dl_rule.cpp @@ -186,15 +186,20 @@ namespace datalog { } void rule_manager::mk_rule_core(expr* fml, proof* p, rule_set& rules, symbol const& name) { + DEBUG_CODE(ptr_vector sorts; + ::get_free_vars(fml, sorts); ); expr_ref_vector fmls(m); proof_ref_vector prs(m); m_hnf.reset(); m_hnf.set_name(name); + m_hnf(fml, p, fmls, prs); for (unsigned i = 0; i < m_hnf.get_fresh_predicates().size(); ++i) { m_ctx.register_predicate(m_hnf.get_fresh_predicates()[i], false); } for (unsigned i = 0; i < fmls.size(); ++i) { + DEBUG_CODE(ptr_vector sorts; + ::get_free_vars(fmls[i].get(), sorts); ); mk_horn_rule(fmls[i].get(), prs[i].get(), rules, name); } } @@ -265,7 +270,7 @@ namespace datalog { } else { head = ensure_app(fml); - } + } return index; } @@ -491,6 +496,12 @@ namespace datalog { app * * uninterp_tail = r->m_tail; //grows upwards app * * interp_tail = r->m_tail+n; //grows downwards + DEBUG_CODE(ptr_vector sorts; + ::get_free_vars(head, sorts); + for (unsigned i = 0; i < n; ++i) { + ::get_free_vars(tail[i], sorts); + }); + bool has_neg = false; for (unsigned i = 0; i < n; i++) { diff --git a/src/muz_qe/hnf.cpp b/src/muz_qe/hnf.cpp index 75a85061c..36316cfa6 100644 --- a/src/muz_qe/hnf.cpp +++ b/src/muz_qe/hnf.cpp @@ -128,7 +128,12 @@ public: } void set_name(symbol const& n) { - m_name = n; + if (n == symbol::null) { + m_name = symbol("P"); + } + else { + m_name = n; + } } func_decl_ref_vector const& get_fresh_predicates() { diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index ce1b30b88..d597500b2 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -105,14 +105,12 @@ namespace datalog { } } - lbool rel_context::saturate() { + lbool rel_context::saturate(scoped_query& sq) { m_context.ensure_closed(); bool time_limit = m_context.soft_timeout()!=0; unsigned remaining_time_limit = m_context.soft_timeout(); unsigned restart_time = m_context.initial_restart_timeout(); - - scoped_query scoped_query(m_context); - + instruction_block termination_code; lbool result; @@ -191,7 +189,7 @@ namespace datalog { else { restart_time = static_cast(new_restart_time); } - scoped_query.reset(); + sq.reset(); } m_context.record_transformed_rules(); TRACE("dl", display_profile(tout);); @@ -206,7 +204,7 @@ namespace datalog { } m_context.close(); reset_negated_tables(); - lbool res = saturate(); + lbool res = saturate(_scoped_query); switch(res) { case l_true: { @@ -215,7 +213,8 @@ namespace datalog { bool some_non_empty = num_rels == 0; bool is_approx = false; for (unsigned i = 0; i < num_rels; ++i) { - relation_base& rel = get_relation(rels[i]); + func_decl* q = m_context.get_rules().get_pred(rels[i]); + relation_base& rel = get_relation(q); if (!rel.empty()) { some_non_empty = true; } @@ -272,13 +271,14 @@ namespace datalog { if (m_context.magic_sets_for_queries()) { m_context.transform_rules(alloc(mk_magic_sets, m_context, query_pred)); + query_pred = m_context.get_rules().get_pred(query_pred); } + lbool res = saturate(_scoped_query); + query_pred = m_context.get_rules().get_pred(query_pred); - lbool res = saturate(); - - if (res != l_undef) { + if (res != l_undef) { m_last_result_relation = get_relation(query_pred).clone(); if (m_last_result_relation->empty()) { res = l_false; diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index 057d1c15f..0b73caaa6 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -109,7 +109,7 @@ namespace datalog { void display_profile(std::ostream& out); - lbool saturate(); + lbool saturate(scoped_query& sq); }; }; From 4db8db7484a9b7ad6feb46812382508a3f82317b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Aug 2013 12:40:16 -0700 Subject: [PATCH 240/281] extend tracing for rule transformations Signed-off-by: Nikolaj Bjorner --- src/muz_qe/dl_rule_transformer.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz_qe/dl_rule_transformer.cpp index 9055007b9..2df8b9453 100644 --- a/src/muz_qe/dl_rule_transformer.cpp +++ b/src/muz_qe/dl_rule_transformer.cpp @@ -22,6 +22,7 @@ Revision History: #include"dl_context.h" #include"dl_rule_transformer.h" +#include"stopwatch.h" namespace datalog { @@ -86,8 +87,16 @@ namespace datalog { for(; it!=end && !m_context.canceled(); ++it) { plugin & p = **it; + + IF_VERBOSE(1, verbose_stream() << "(transform " << typeid(p).name() << "...";); + stopwatch sw; + sw.start(); rule_set * new_rules1 = p(*new_rules); + sw.stop(); + double sec = sw.get_seconds(); + if (sec < 0.001) sec = 0.0; if (!new_rules1) { + IF_VERBOSE(1, verbose_stream() << "no-op " << sec << "s)\n";); continue; } if (p.can_destratify_negation() && @@ -96,6 +105,7 @@ namespace datalog { warning_msg("a rule transformation skipped " "because it destratified negation"); dealloc(new_rules1); + IF_VERBOSE(1, verbose_stream() << "no-op " << sec << "s)\n";); continue; } modified = true; @@ -103,6 +113,7 @@ namespace datalog { new_rules = new_rules1; new_rules->ensure_closed(); + IF_VERBOSE(1, verbose_stream() << new_rules->get_num_rules() << " rules " << sec << "s)\n";); TRACE("dl_rule_transf", tout << typeid(p).name()<<":\n"; new_rules->display(tout); From 2d6b3fa28434a8c16fdf8cfbdfcfd08dbaf4b197 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Aug 2013 19:45:21 -0700 Subject: [PATCH 241/281] wworking on generalizing post-image Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_farkas_learner.cpp | 24 +++++++-- src/muz_qe/pdr_farkas_learner.h | 18 +++++++ src/muz_qe/pdr_generalizers.cpp | 89 +++++++++++++++++++++++-------- src/muz_qe/pdr_generalizers.h | 6 +-- src/muz_qe/pdr_prop_solver.cpp | 9 +++- src/muz_qe/pdr_prop_solver.h | 3 ++ 6 files changed, 119 insertions(+), 30 deletions(-) diff --git a/src/muz_qe/pdr_farkas_learner.cpp b/src/muz_qe/pdr_farkas_learner.cpp index 71404ab12..8bc77ecc6 100644 --- a/src/muz_qe/pdr_farkas_learner.cpp +++ b/src/muz_qe/pdr_farkas_learner.cpp @@ -249,6 +249,7 @@ namespace pdr { farkas_learner::farkas_learner(smt_params& params, ast_manager& outer_mgr) : m_proof_params(get_proof_params(params)), m_pr(PROOF_MODE), + m_combine_farkas_coefficients(true), p2o(m_pr, outer_mgr), o2p(outer_mgr, m_pr) { @@ -412,11 +413,17 @@ namespace pdr { void farkas_learner::combine_constraints(unsigned n, app * const * lits, rational const * coeffs, expr_ref& res) { ast_manager& m = res.get_manager(); - constr res_c(m); - for(unsigned i = 0; i < n; ++i) { - res_c.add(coeffs[i], lits[i]); + if (m_combine_farkas_coefficients) { + constr res_c(m); + for(unsigned i = 0; i < n; ++i) { + res_c.add(coeffs[i], lits[i]); + } + res_c.get(res); + } + else { + bool_rewriter rw(m); + rw.mk_or(n, (expr*const*)(lits), res); } - res_c.get(res); } class farkas_learner::constant_replacer_cfg : public default_rewriter_cfg @@ -694,7 +701,7 @@ namespace pdr { tout << (b_pure?"B":"A") << " " << coef << " " << mk_pp(m.get_fact(prem), m) << "\n"; } tout << mk_pp(m.get_fact(p), m) << "\n"; - ); + ); // NB. Taking 'abs' of coefficients is a workaround. // The Farkas coefficient extraction in arith_core must be wrong. @@ -753,6 +760,13 @@ namespace pdr { simplify_lemmas(lemmas); } + void farkas_learner::get_consequences(proof* root, expr_set const& bs, expr_ref_vector& consequences) { + TRACE("farkas_learner", tout << "get consequences\n";); + m_combine_farkas_coefficients = false; + get_lemmas(root, bs, consequences); + m_combine_farkas_coefficients = true; + } + void farkas_learner::get_asserted(proof* p, expr_set const& bs, ast_mark& b_closed, obj_hashtable& lemma_set, expr_ref_vector& lemmas) { ast_manager& m = lemmas.get_manager(); ast_mark visited; diff --git a/src/muz_qe/pdr_farkas_learner.h b/src/muz_qe/pdr_farkas_learner.h index eb38455ab..b623c2035 100644 --- a/src/muz_qe/pdr_farkas_learner.h +++ b/src/muz_qe/pdr_farkas_learner.h @@ -43,6 +43,12 @@ class farkas_learner { ast_manager m_pr; scoped_ptr m_ctx; + // + // true: produce a combined constraint by applying Farkas coefficients. + // false: produce a conjunction of the negated literals from the theory lemmas. + // + bool m_combine_farkas_coefficients; + static smt_params get_proof_params(smt_params& orig_params); @@ -92,6 +98,18 @@ public: */ void get_lemmas(proof* root, expr_set const& bs, expr_ref_vector& lemmas); + /** + Traverse a proof and retrieve consequences of A that are used to establish ~B. + The assumption is that: + + A => \/ ~consequences[i] and \/ ~consequences[i] => ~B + + e.g., the second implication can be rewritten as: + + B => /\ consequences[i] + */ + void get_consequences(proof* root, expr_set const& bs, expr_ref_vector& consequences); + /** \brief Simplify lemmas using subsumption. */ diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index 55d8a05f8..f51df79a6 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -159,6 +159,7 @@ namespace pdr { } void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { + // method3(n, core, uses_level, new_cores); method1(n, core, uses_level, new_cores); } @@ -187,7 +188,7 @@ namespace pdr { new_cores.push_back(std::make_pair(core, uses_level)); return; } - add_variables(n, eqs); + add_variables(n, 2, eqs); if (!mk_convex(core, 0, conv1)) { new_cores.push_back(std::make_pair(core, uses_level)); IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core), m) << "\n";); @@ -257,7 +258,7 @@ namespace pdr { IF_VERBOSE(0, verbose_stream() << "unexpected result from satisfiability check\n";); return; } - add_variables(n, conv1); + add_variables(n, 2, conv1); model_ref mdl; ctx.get_model(mdl); @@ -267,7 +268,7 @@ namespace pdr { expr* left, *right; func_decl* fn0 = n.pt().sig(i); func_decl* fn1 = pm.o2n(fn0, 0); - if (m_left.find(fn1, left) && m_right.find(fn1, right)) { + if (m_vars[0].find(fn1, left) && m_vars[1].find(fn1, right)) { expr_ref val(m); mdl->eval(fn1, val); if (val) { @@ -306,34 +307,84 @@ namespace pdr { } } - void core_convex_hull_generalizer::add_variables(model_node& n, expr_ref_vector& eqs) { + /* + Extract the lemmas from the transition relation that were used to establish unsatisfiability. + Take convex closures of conbinations of these lemmas. + */ + void core_convex_hull_generalizer::method3(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { + TRACE("dl", tout << "method: generalize consequences of F(R)\n"; + for (unsigned i = 0; i < core.size(); ++i) { + tout << "B:" << mk_pp(core[i], m) << "\n"; + }); manager& pm = n.pt().get_pdr_manager(); - if (!m_left.contains(n.pt().head())) { - expr_ref left(m), right(m); - m_left.insert(n.pt().head(), 0); + bool uses_level1; + expr_ref_vector core1(m); + core1.append(core); + obj_hashtable bs; + for (unsigned i = 0; i < core.size(); ++i) { + bs.insert(core[i]); + } + expr_ref_vector consequences(m); + { + n.pt().get_solver().set_consequences(&consequences); + pred_transformer::scoped_farkas sf (n.pt(), true); + VERIFY(l_false == n.pt().is_reachable(n, &core1, uses_level1)); + n.pt().get_solver().set_consequences(0); + } + IF_VERBOSE(0, + verbose_stream() << "Consequences: " << consequences.size() << "\n"; + for (unsigned i = 0; i < consequences.size(); ++i) { + verbose_stream() << mk_pp(consequences[i].get(), m) << "\n"; + } + verbose_stream() << "core: " << core1.size() << "\n"; + for (unsigned i = 0; i < core1.size(); ++i) { + verbose_stream() << mk_pp(core1[i].get(), m) << "\n"; + }); + + // now create the convex closure of the consequences: + expr_ref_vector conv(m); + for (unsigned i = 0; i < consequences.size(); ++i) { + if (m_sigma.size() == i) { + m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); + } + conv.push_back(a.mk_ge(m_sigma[i].get(), a.mk_numeral(rational(0), a.mk_real()))); + ;; // mk_convex + } + } + + void core_convex_hull_generalizer::add_variables(model_node& n, unsigned num_vars, expr_ref_vector& eqs) { + manager& pm = n.pt().get_pdr_manager(); + if (m_vars.size() < num_vars) { + m_vars.resize(num_vars); + } + if (!m_vars[0].contains(n.pt().head())) { + expr_ref var(m); + m_vars[0].insert(n.pt().head(), 0); unsigned sz = n.pt().sig_size(); for (unsigned i = 0; i < sz; ++i) { func_decl* fn0 = n.pt().sig(i); sort* srt = fn0->get_range(); if (a.is_int_real(srt)) { func_decl* fn1 = pm.o2n(fn0, 0); - left = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); - right = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); - m_left.insert(fn1, left); - m_right.insert(fn1, right); - m_trail.push_back(left); - m_trail.push_back(right); + for (unsigned j = 0; j < num_vars; ++j) { + var = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); + m_vars[j].insert(fn1, var); + m_trail.push_back(var); + } } } } unsigned sz = n.pt().sig_size(); for (unsigned i = 0; i < sz; ++i) { - expr* left, *right; + expr* var; + ptr_vector vars; func_decl* fn0 = n.pt().sig(i); func_decl* fn1 = pm.o2n(fn0, 0); - if (m_left.find(fn1, left) && m_right.find(fn1, right)) { - eqs.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(left, right))); + for (unsigned j = 0; j < num_vars; ++j) { + VERIFY (m_vars[j].find(fn1, var)); + vars.push_back(var); } + eqs.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(num_vars, vars.c_ptr()))); } } @@ -412,11 +463,7 @@ namespace pdr { bool core_convex_hull_generalizer::translate(func_decl* f, unsigned index, expr_ref& result) { expr* tmp; - if (index == 0 && m_left.find(f, tmp)) { - result = tmp; - return true; - } - if (index == 1 && m_right.find(f, tmp)) { + if (m_vars[index].find(f, tmp)) { result = tmp; return true; } diff --git a/src/muz_qe/pdr_generalizers.h b/src/muz_qe/pdr_generalizers.h index ece1f51f1..9dcdf44c0 100644 --- a/src/muz_qe/pdr_generalizers.h +++ b/src/muz_qe/pdr_generalizers.h @@ -78,8 +78,7 @@ namespace pdr { arith_util a; expr_ref_vector m_sigma; expr_ref_vector m_trail; - obj_map m_left; - obj_map m_right; + vector > m_vars; obj_map m_models; bool m_is_closure; expr_ref mk_closure(expr* e); @@ -90,7 +89,8 @@ namespace pdr { bool translate(func_decl* fn, unsigned index, expr_ref& result); void method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); void method2(model_node& n, expr_ref_vector& core, bool& uses_level); - void add_variables(model_node& n, expr_ref_vector& eqs); + void method3(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); + void add_variables(model_node& n, unsigned num_vars, expr_ref_vector& eqs); public: core_convex_hull_generalizer(context& ctx, bool is_closure); virtual ~core_convex_hull_generalizer() {} diff --git a/src/muz_qe/pdr_prop_solver.cpp b/src/muz_qe/pdr_prop_solver.cpp index c7f0bfbc3..eb3c0ee96 100644 --- a/src/muz_qe/pdr_prop_solver.cpp +++ b/src/muz_qe/pdr_prop_solver.cpp @@ -236,9 +236,12 @@ namespace pdr { m_neg_level_atoms(m), m_proxies(m), m_core(0), + m_model(0), + m_consequences(0), m_subset_based_core(false), m_use_farkas(false), - m_in_level(false) + m_in_level(false), + m_current_level(0) { m_ctx->assert_expr(m_pm.get_background()); } @@ -413,6 +416,10 @@ namespace pdr { m_core->reset(); m_core->append(lemmas); + + if (m_consequences) { + fl.get_consequences(pr, bs, *m_consequences); + } } } diff --git a/src/muz_qe/pdr_prop_solver.h b/src/muz_qe/pdr_prop_solver.h index 5a6b09360..0c60a7124 100644 --- a/src/muz_qe/pdr_prop_solver.h +++ b/src/muz_qe/pdr_prop_solver.h @@ -48,6 +48,7 @@ namespace pdr { app_ref_vector m_proxies; // predicates for assumptions expr_ref_vector* m_core; model_ref* m_model; + expr_ref_vector* m_consequences; bool m_subset_based_core; bool m_assumes_level; bool m_use_farkas; @@ -84,6 +85,8 @@ namespace pdr { void set_core(expr_ref_vector* core) { m_core = core; } void set_model(model_ref* mdl) { m_model = mdl; } void set_subset_based_core(bool f) { m_subset_based_core = f; } + void set_consequences(expr_ref_vector* consequences) { m_consequences = consequences; } + bool assumes_level() const { return m_assumes_level; } void add_level(); From e5541bad17639c9318d0b8d5aeb8c29b6b45cdfc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 27 Aug 2013 21:11:45 -0700 Subject: [PATCH 242/281] working on convex lemma gneralization Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_generalizers.cpp | 108 +++++++++++++++++++++++--------- src/muz_qe/pdr_generalizers.h | 2 +- 2 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index f51df79a6..ed9e4d999 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -154,8 +154,6 @@ namespace pdr { m_sigma(m), m_trail(m), m_is_closure(is_closure) { - m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); - m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); } void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { @@ -182,29 +180,18 @@ namespace pdr { // void core_convex_hull_generalizer::method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { manager& pm = n.pt().get_pdr_manager(); - expr_ref_vector conv1(m), conv2(m), core1(m), core2(m), eqs(m); + expr_ref_vector conv1(m), conv2(m), core1(m), core2(m); unsigned orig_size = new_cores.size(); if (core.empty()) { new_cores.push_back(std::make_pair(core, uses_level)); return; } - add_variables(n, 2, eqs); + add_variables(n, 2, conv1); if (!mk_convex(core, 0, conv1)) { new_cores.push_back(std::make_pair(core, uses_level)); IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core), m) << "\n";); return; } - conv1.append(eqs); - if (m_is_closure) { - conv1.push_back(a.mk_ge(m_sigma[0].get(), a.mk_numeral(rational(0), a.mk_real()))); - conv1.push_back(a.mk_ge(m_sigma[1].get(), a.mk_numeral(rational(0), a.mk_real()))); - } - else { - // is interior: - conv1.push_back(a.mk_gt(m_sigma[0].get(), a.mk_numeral(rational(0), a.mk_real()))); - conv1.push_back(a.mk_gt(m_sigma[1].get(), a.mk_numeral(rational(0), a.mk_real()))); - } - conv1.push_back(m.mk_eq(a.mk_numeral(rational(1), a.mk_real()), a.mk_add(m_sigma[0].get(), m_sigma[1].get()))); expr_ref fml = n.pt().get_formulas(n.level(), false); expr_ref_vector fmls(m); datalog::flatten_and(fml, fmls); @@ -281,10 +268,6 @@ namespace pdr { m_trail.push_back(goal); m_models.insert(goal, new_model); } - conv1.push_back(a.mk_gt(m_sigma[0].get(), a.mk_numeral(rational(0), a.mk_real()))); - conv1.push_back(a.mk_gt(m_sigma[1].get(), a.mk_numeral(rational(0), a.mk_real()))); - conv1.push_back(m.mk_eq(a.mk_numeral(rational(1), a.mk_real()), a.mk_add(m_sigma[0].get(), m_sigma[1].get()))); - obj_map::iterator it = m_models.begin(), end = m_models.end(); for (; it != end; ++it) { if (it->m_key == goal) { @@ -342,21 +325,76 @@ namespace pdr { }); // now create the convex closure of the consequences: - expr_ref_vector conv(m); + expr_ref tmp(m), zero(m); + expr_ref_vector conv(m), es(m), enabled(m); + zero = a.mk_numeral(rational(0), a.mk_real()); + add_variables(n, consequences.size(), conv); for (unsigned i = 0; i < consequences.size(); ++i) { - if (m_sigma.size() == i) { - m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); + es.reset(); + tmp = m.mk_not(consequences[i].get()); + datalog::flatten_and(tmp, es); + if (!mk_convex(es, i, conv)) { + IF_VERBOSE(0, verbose_stream() << "Failed to create convex closure\n";); + return; } - conv.push_back(a.mk_ge(m_sigma[i].get(), a.mk_numeral(rational(0), a.mk_real()))); - ;; // mk_convex + es.reset(); + // + // enabled[i] = not (sigma_i = 0 and z_i1 = 0 and .. and z_im = 0) + // + es.push_back(m.mk_eq(m_sigma[i].get(), zero)); + for (unsigned j = 0; j < n.pt().sig_size(); ++j) { + func_decl* fn0 = n.pt().sig(j); + func_decl* fn1 = pm.o2n(fn0, 0); + expr* var; + VERIFY (m_vars[i].find(fn1, var)); + es.push_back(m.mk_eq(var, zero)); + } + + enabled.push_back(m.mk_not(m.mk_and(es.size(), es.c_ptr()))); } + + // the convex closure was created of all consequences. + // now determine a subset of enabled constraints. + smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); + for (unsigned i = 0; i < conv.size(); ++i) { + ctx.assert_expr(conv[i].get()); + } + for (unsigned i = 0; i < core.size(); ++i) { + ctx.assert_expr(core[i]); + } + vector transversal; + while (l_true == ctx.check()) { + model_ref md; + ctx.get_model(md); + expr_ref_vector lits(m); + unsigned_vector pos; + for (unsigned i = 0; i < consequences.size(); ++i) { + if (md->eval(enabled[i].get(), tmp, false)) { + if (m.is_true(tmp)) { + lits.push_back(tmp); + pos.push_back(i); + } + } + } + transversal.push_back(pos); + SASSERT(!lits.empty()); + tmp = m.mk_not(m.mk_and(lits.size(), lits.c_ptr())); + TRACE("pdr", tout << "add block: " << mk_pp(tmp, m) << "\n";); + ctx.assert_expr(tmp); + } + // + // we could no longer satisfy core using a partition. + // + } - void core_convex_hull_generalizer::add_variables(model_node& n, unsigned num_vars, expr_ref_vector& eqs) { + void core_convex_hull_generalizer::add_variables(model_node& n, unsigned num_vars, expr_ref_vector& fmls) { manager& pm = n.pt().get_pdr_manager(); - if (m_vars.size() < num_vars) { - m_vars.resize(num_vars); - } + while (m_vars.size() < num_vars) { + m_vars.resize(m_vars.size()+1); + m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); + } + if (!m_vars[0].contains(n.pt().head())) { expr_ref var(m); m_vars[0].insert(n.pt().head(), 0); @@ -384,8 +422,20 @@ namespace pdr { VERIFY (m_vars[j].find(fn1, var)); vars.push_back(var); } - eqs.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(num_vars, vars.c_ptr()))); + fmls.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(num_vars, vars.c_ptr()))); } + if (m_is_closure) { + for (unsigned i = 0; i < num_vars; ++i) { + fmls.push_back(a.mk_ge(m_sigma[i].get(), a.mk_numeral(rational(0), a.mk_real()))); + } + } + else { + // is interior: + for (unsigned i = 0; i < num_vars; ++i) { + fmls.push_back(a.mk_gt(m_sigma[i].get(), a.mk_numeral(rational(0), a.mk_real()))); + } + } + fmls.push_back(m.mk_eq(a.mk_numeral(rational(1), a.mk_real()), a.mk_add(num_vars, m_sigma.c_ptr()))); } expr_ref core_convex_hull_generalizer::mk_closure(expr* e) { diff --git a/src/muz_qe/pdr_generalizers.h b/src/muz_qe/pdr_generalizers.h index 9dcdf44c0..10aa5b978 100644 --- a/src/muz_qe/pdr_generalizers.h +++ b/src/muz_qe/pdr_generalizers.h @@ -90,7 +90,7 @@ namespace pdr { void method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); void method2(model_node& n, expr_ref_vector& core, bool& uses_level); void method3(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); - void add_variables(model_node& n, unsigned num_vars, expr_ref_vector& eqs); + void add_variables(model_node& n, unsigned num_vars, expr_ref_vector& fmls); public: core_convex_hull_generalizer(context& ctx, bool is_closure); virtual ~core_convex_hull_generalizer() {} From d795792304295ed08f37f57a2fa8529e9e3a782c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Aug 2013 08:48:18 -0700 Subject: [PATCH 243/281] add API for fixing tests Signed-off-by: Nikolaj Bjorner --- src/muz_qe/pdr_generalizers.cpp | 1 + src/muz_qe/rel_context.cpp | 5 +++++ src/muz_qe/rel_context.h | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz_qe/pdr_generalizers.cpp index ed9e4d999..8e15fa983 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz_qe/pdr_generalizers.cpp @@ -364,6 +364,7 @@ namespace pdr { } vector transversal; while (l_true == ctx.check()) { + IF_VERBOSE(0, ctx.display(verbose_stream());); model_ref md; ctx.get_model(md); expr_ref_vector lits(m); diff --git a/src/muz_qe/rel_context.cpp b/src/muz_qe/rel_context.cpp index d597500b2..75f68c7f1 100644 --- a/src/muz_qe/rel_context.cpp +++ b/src/muz_qe/rel_context.cpp @@ -105,6 +105,11 @@ namespace datalog { } } + lbool rel_context::saturate() { + scoped_query sq(m_context); + return saturate(sq); + } + lbool rel_context::saturate(scoped_query& sq) { m_context.ensure_closed(); bool time_limit = m_context.soft_timeout()!=0; diff --git a/src/muz_qe/rel_context.h b/src/muz_qe/rel_context.h index 0b73caaa6..20da827ce 100644 --- a/src/muz_qe/rel_context.h +++ b/src/muz_qe/rel_context.h @@ -48,6 +48,8 @@ namespace datalog { void reset_tables(); + lbool saturate(scoped_query& sq); + public: rel_context(context& ctx); @@ -109,7 +111,7 @@ namespace datalog { void display_profile(std::ostream& out); - lbool saturate(scoped_query& sq); + lbool saturate(); }; }; From 137339a2e17697e715d0ec3909176c5c13f3ab02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Aug 2013 12:08:47 -0700 Subject: [PATCH 244/281] split muz_qe into two directories Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 8 +- src/{muz_qe => muz}/README | 0 src/{muz_qe => muz}/aig_exporter.cpp | 0 src/{muz_qe => muz}/aig_exporter.h | 0 src/{muz_qe => muz}/arith_bounds_tactic.cpp | 0 src/{muz_qe => muz}/arith_bounds_tactic.h | 0 src/{muz_qe => muz}/clp_context.cpp | 0 src/{muz_qe => muz}/clp_context.h | 0 src/{muz_qe => muz}/datalog_parser.cpp | 0 src/{muz_qe => muz}/datalog_parser.h | 0 src/{muz_qe => muz}/dl_base.cpp | 0 src/{muz_qe => muz}/dl_base.h | 0 src/{muz_qe => muz}/dl_bmc_engine.cpp | 0 src/{muz_qe => muz}/dl_bmc_engine.h | 0 src/{muz_qe => muz}/dl_boogie_proof.cpp | 4 +- src/{muz_qe => muz}/dl_boogie_proof.h | 0 src/{muz_qe => muz}/dl_bound_relation.cpp | 0 src/{muz_qe => muz}/dl_bound_relation.h | 0 src/{muz_qe => muz}/dl_check_table.cpp | 0 src/{muz_qe => muz}/dl_check_table.h | 0 src/{muz_qe => muz}/dl_cmds.cpp | 0 src/{muz_qe => muz}/dl_cmds.h | 0 src/{muz_qe => muz}/dl_compiler.cpp | 0 src/{muz_qe => muz}/dl_compiler.h | 0 src/{muz_qe => muz}/dl_context.cpp | 12 +- src/{muz_qe => muz}/dl_context.h | 0 src/{muz_qe => muz}/dl_costs.cpp | 0 src/{muz_qe => muz}/dl_costs.h | 0 src/{muz_qe => muz}/dl_external_relation.cpp | 0 src/{muz_qe => muz}/dl_external_relation.h | 0 .../dl_finite_product_relation.cpp | 0 .../dl_finite_product_relation.h | 0 src/{muz_qe => muz}/dl_instruction.cpp | 0 src/{muz_qe => muz}/dl_instruction.h | 0 src/{muz_qe => muz}/dl_interval_relation.cpp | 0 src/{muz_qe => muz}/dl_interval_relation.h | 0 src/{muz_qe => muz}/dl_mk_array_blast.cpp | 6 +- src/{muz_qe => muz}/dl_mk_array_blast.h | 0 src/{muz_qe => muz}/dl_mk_backwards.cpp | 0 src/{muz_qe => muz}/dl_mk_backwards.h | 0 src/{muz_qe => muz}/dl_mk_bit_blast.cpp | 0 src/{muz_qe => muz}/dl_mk_bit_blast.h | 0 src/{muz_qe => muz}/dl_mk_coalesce.cpp | 0 src/{muz_qe => muz}/dl_mk_coalesce.h | 0 src/{muz_qe => muz}/dl_mk_coi_filter.cpp | 0 src/{muz_qe => muz}/dl_mk_coi_filter.h | 0 src/muz/dl_mk_different.h | 38 ++++++ src/{muz_qe => muz}/dl_mk_explanations.cpp | 0 src/{muz_qe => muz}/dl_mk_explanations.h | 0 src/{muz_qe => muz}/dl_mk_filter_rules.cpp | 0 src/{muz_qe => muz}/dl_mk_filter_rules.h | 0 .../dl_mk_interp_tail_simplifier.cpp | 2 +- .../dl_mk_interp_tail_simplifier.h | 0 src/{muz_qe => muz}/dl_mk_karr_invariants.cpp | 2 +- src/{muz_qe => muz}/dl_mk_karr_invariants.h | 0 src/{muz_qe => muz}/dl_mk_loop_counter.cpp | 0 src/{muz_qe => muz}/dl_mk_loop_counter.h | 0 src/{muz_qe => muz}/dl_mk_magic_sets.cpp | 0 src/{muz_qe => muz}/dl_mk_magic_sets.h | 0 src/{muz_qe => muz}/dl_mk_magic_symbolic.cpp | 0 src/{muz_qe => muz}/dl_mk_magic_symbolic.h | 0 src/{muz_qe => muz}/dl_mk_partial_equiv.cpp | 0 src/{muz_qe => muz}/dl_mk_partial_equiv.h | 0 .../dl_mk_quantifier_abstraction.cpp | 0 .../dl_mk_quantifier_abstraction.h | 0 .../dl_mk_quantifier_instantiation.cpp | 2 +- .../dl_mk_quantifier_instantiation.h | 0 src/{muz_qe => muz}/dl_mk_rule_inliner.cpp | 0 src/{muz_qe => muz}/dl_mk_rule_inliner.h | 0 src/{muz_qe => muz}/dl_mk_scale.cpp | 0 src/{muz_qe => muz}/dl_mk_scale.h | 0 .../dl_mk_similarity_compressor.cpp | 0 .../dl_mk_similarity_compressor.h | 0 src/{muz_qe => muz}/dl_mk_simple_joins.cpp | 0 src/{muz_qe => muz}/dl_mk_simple_joins.h | 0 src/{muz_qe => muz}/dl_mk_slice.cpp | 2 +- src/{muz_qe => muz}/dl_mk_slice.h | 0 .../dl_mk_subsumption_checker.cpp | 0 .../dl_mk_subsumption_checker.h | 0 .../dl_mk_unbound_compressor.cpp | 0 .../dl_mk_unbound_compressor.h | 0 src/{muz_qe => muz}/dl_mk_unfold.cpp | 0 src/{muz_qe => muz}/dl_mk_unfold.h | 0 src/{muz_qe => muz}/dl_product_relation.cpp | 0 src/{muz_qe => muz}/dl_product_relation.h | 0 src/{muz_qe => muz}/dl_relation_manager.cpp | 0 src/{muz_qe => muz}/dl_relation_manager.h | 0 src/{muz_qe => muz}/dl_rule.cpp | 4 +- src/{muz_qe => muz}/dl_rule.h | 0 src/{muz_qe => muz}/dl_rule_set.cpp | 0 src/{muz_qe => muz}/dl_rule_set.h | 0 .../dl_rule_subsumption_index.cpp | 0 .../dl_rule_subsumption_index.h | 0 src/{muz_qe => muz}/dl_rule_transformer.cpp | 0 src/{muz_qe => muz}/dl_rule_transformer.h | 0 src/{muz_qe => muz}/dl_sieve_relation.cpp | 0 src/{muz_qe => muz}/dl_sieve_relation.h | 0 src/{muz_qe => muz}/dl_sparse_table.cpp | 0 src/{muz_qe => muz}/dl_sparse_table.h | 0 src/{muz_qe => muz}/dl_table.cpp | 0 src/{muz_qe => muz}/dl_table.h | 0 src/{muz_qe => muz}/dl_table_plugin.h | 0 src/{muz_qe => muz}/dl_table_relation.cpp | 0 src/{muz_qe => muz}/dl_table_relation.h | 0 src/{muz_qe => muz}/dl_util.cpp | 112 ----------------- src/{muz_qe => muz}/dl_util.h | 13 +- src/{muz_qe => muz}/dl_vector_relation.h | 0 src/{muz_qe => muz}/equiv_proof_converter.cpp | 0 src/{muz_qe => muz}/equiv_proof_converter.h | 0 src/{muz_qe => muz}/fixedpoint_params.pyg | 0 src/{muz_qe => muz}/heap_trie.h | 0 src/{muz_qe => muz}/hilbert_basis.cpp | 0 src/{muz_qe => muz}/hilbert_basis.h | 0 src/{muz_qe => muz}/hnf.cpp | 2 +- src/{muz_qe => muz}/hnf.h | 0 .../horn_subsume_model_converter.cpp | 0 .../horn_subsume_model_converter.h | 0 src/{muz_qe => muz}/horn_tactic.cpp | 2 +- src/{muz_qe => muz}/horn_tactic.h | 0 src/{muz_qe => muz}/model2expr.cpp | 0 src/{muz_qe => muz}/model2expr.h | 0 src/{muz_qe => muz}/pdr_context.cpp | 11 +- src/{muz_qe => muz}/pdr_context.h | 0 src/{muz_qe => muz}/pdr_dl_interface.cpp | 0 src/{muz_qe => muz}/pdr_dl_interface.h | 0 src/{muz_qe => muz}/pdr_farkas_learner.cpp | 2 +- src/{muz_qe => muz}/pdr_farkas_learner.h | 0 src/{muz_qe => muz}/pdr_generalizers.cpp | 10 +- src/{muz_qe => muz}/pdr_generalizers.h | 0 src/{muz_qe => muz}/pdr_manager.cpp | 6 +- src/{muz_qe => muz}/pdr_manager.h | 0 src/{muz_qe => muz}/pdr_prop_solver.cpp | 2 +- src/{muz_qe => muz}/pdr_prop_solver.h | 0 src/{muz_qe => muz}/pdr_reachable_cache.cpp | 0 src/{muz_qe => muz}/pdr_reachable_cache.h | 0 .../pdr_smt_context_manager.cpp | 0 src/{muz_qe => muz}/pdr_smt_context_manager.h | 0 src/{muz_qe => muz}/pdr_sym_mux.cpp | 0 src/{muz_qe => muz}/pdr_sym_mux.h | 0 src/{muz_qe => muz}/pdr_util.cpp | 2 +- src/{muz_qe => muz}/pdr_util.h | 0 src/{muz_qe => muz}/proof_utils.cpp | 0 src/{muz_qe => muz}/proof_utils.h | 0 src/{muz_qe => muz}/rel_context.cpp | 0 src/{muz_qe => muz}/rel_context.h | 0 .../replace_proof_converter.cpp | 0 src/{muz_qe => muz}/replace_proof_converter.h | 0 src/{muz_qe => muz}/skip_list_base.h | 0 src/{muz_qe => muz}/tab_context.cpp | 6 +- src/{muz_qe => muz}/tab_context.h | 0 .../unit_subsumption_tactic.cpp | 0 src/{muz_qe => muz}/unit_subsumption_tactic.h | 0 src/{muz_qe => muz}/vsubst_tactic.cpp | 0 src/{muz_qe => muz}/vsubst_tactic.h | 0 src/{muz_qe => qe}/nlarith_util.cpp | 0 src/{muz_qe => qe}/nlarith_util.h | 0 src/{muz_qe => qe}/qe.cpp | 6 +- src/{muz_qe => qe}/qe.h | 0 src/{muz_qe => qe}/qe_arith_plugin.cpp | 0 src/{muz_qe => qe}/qe_array_plugin.cpp | 0 src/{muz_qe => qe}/qe_bool_plugin.cpp | 0 src/{muz_qe => qe}/qe_bv_plugin.cpp | 0 src/{muz_qe => qe}/qe_cmd.cpp | 0 src/{muz_qe => qe}/qe_cmd.h | 0 src/{muz_qe => qe}/qe_datatype_plugin.cpp | 0 src/{muz_qe => qe}/qe_dl_plugin.cpp | 0 src/{muz_qe => qe}/qe_lite.cpp | 9 +- src/{muz_qe => qe}/qe_lite.h | 0 src/{muz_qe => qe}/qe_sat_tactic.cpp | 0 src/{muz_qe => qe}/qe_sat_tactic.h | 0 src/{muz_qe => qe}/qe_tactic.cpp | 0 src/{muz_qe => qe}/qe_tactic.h | 0 src/qe/qe_util.cpp | 116 ++++++++++++++++++ src/qe/qe_util.h | 37 ++++++ 174 files changed, 242 insertions(+), 174 deletions(-) rename src/{muz_qe => muz}/README (100%) rename src/{muz_qe => muz}/aig_exporter.cpp (100%) mode change 100755 => 100644 rename src/{muz_qe => muz}/aig_exporter.h (100%) mode change 100755 => 100644 rename src/{muz_qe => muz}/arith_bounds_tactic.cpp (100%) rename src/{muz_qe => muz}/arith_bounds_tactic.h (100%) rename src/{muz_qe => muz}/clp_context.cpp (100%) rename src/{muz_qe => muz}/clp_context.h (100%) rename src/{muz_qe => muz}/datalog_parser.cpp (100%) rename src/{muz_qe => muz}/datalog_parser.h (100%) rename src/{muz_qe => muz}/dl_base.cpp (100%) rename src/{muz_qe => muz}/dl_base.h (100%) rename src/{muz_qe => muz}/dl_bmc_engine.cpp (100%) rename src/{muz_qe => muz}/dl_bmc_engine.h (100%) rename src/{muz_qe => muz}/dl_boogie_proof.cpp (99%) rename src/{muz_qe => muz}/dl_boogie_proof.h (100%) rename src/{muz_qe => muz}/dl_bound_relation.cpp (100%) rename src/{muz_qe => muz}/dl_bound_relation.h (100%) rename src/{muz_qe => muz}/dl_check_table.cpp (100%) rename src/{muz_qe => muz}/dl_check_table.h (100%) rename src/{muz_qe => muz}/dl_cmds.cpp (100%) rename src/{muz_qe => muz}/dl_cmds.h (100%) rename src/{muz_qe => muz}/dl_compiler.cpp (100%) rename src/{muz_qe => muz}/dl_compiler.h (100%) rename src/{muz_qe => muz}/dl_context.cpp (100%) rename src/{muz_qe => muz}/dl_context.h (100%) rename src/{muz_qe => muz}/dl_costs.cpp (100%) rename src/{muz_qe => muz}/dl_costs.h (100%) rename src/{muz_qe => muz}/dl_external_relation.cpp (100%) rename src/{muz_qe => muz}/dl_external_relation.h (100%) rename src/{muz_qe => muz}/dl_finite_product_relation.cpp (100%) rename src/{muz_qe => muz}/dl_finite_product_relation.h (100%) rename src/{muz_qe => muz}/dl_instruction.cpp (100%) rename src/{muz_qe => muz}/dl_instruction.h (100%) rename src/{muz_qe => muz}/dl_interval_relation.cpp (100%) rename src/{muz_qe => muz}/dl_interval_relation.h (100%) rename src/{muz_qe => muz}/dl_mk_array_blast.cpp (98%) rename src/{muz_qe => muz}/dl_mk_array_blast.h (100%) rename src/{muz_qe => muz}/dl_mk_backwards.cpp (100%) rename src/{muz_qe => muz}/dl_mk_backwards.h (100%) rename src/{muz_qe => muz}/dl_mk_bit_blast.cpp (100%) rename src/{muz_qe => muz}/dl_mk_bit_blast.h (100%) rename src/{muz_qe => muz}/dl_mk_coalesce.cpp (100%) rename src/{muz_qe => muz}/dl_mk_coalesce.h (100%) rename src/{muz_qe => muz}/dl_mk_coi_filter.cpp (100%) rename src/{muz_qe => muz}/dl_mk_coi_filter.h (100%) create mode 100644 src/muz/dl_mk_different.h rename src/{muz_qe => muz}/dl_mk_explanations.cpp (100%) rename src/{muz_qe => muz}/dl_mk_explanations.h (100%) rename src/{muz_qe => muz}/dl_mk_filter_rules.cpp (100%) rename src/{muz_qe => muz}/dl_mk_filter_rules.h (100%) rename src/{muz_qe => muz}/dl_mk_interp_tail_simplifier.cpp (99%) rename src/{muz_qe => muz}/dl_mk_interp_tail_simplifier.h (100%) rename src/{muz_qe => muz}/dl_mk_karr_invariants.cpp (99%) rename src/{muz_qe => muz}/dl_mk_karr_invariants.h (100%) rename src/{muz_qe => muz}/dl_mk_loop_counter.cpp (100%) rename src/{muz_qe => muz}/dl_mk_loop_counter.h (100%) rename src/{muz_qe => muz}/dl_mk_magic_sets.cpp (100%) rename src/{muz_qe => muz}/dl_mk_magic_sets.h (100%) rename src/{muz_qe => muz}/dl_mk_magic_symbolic.cpp (100%) rename src/{muz_qe => muz}/dl_mk_magic_symbolic.h (100%) rename src/{muz_qe => muz}/dl_mk_partial_equiv.cpp (100%) rename src/{muz_qe => muz}/dl_mk_partial_equiv.h (100%) rename src/{muz_qe => muz}/dl_mk_quantifier_abstraction.cpp (100%) rename src/{muz_qe => muz}/dl_mk_quantifier_abstraction.h (100%) rename src/{muz_qe => muz}/dl_mk_quantifier_instantiation.cpp (99%) rename src/{muz_qe => muz}/dl_mk_quantifier_instantiation.h (100%) rename src/{muz_qe => muz}/dl_mk_rule_inliner.cpp (100%) rename src/{muz_qe => muz}/dl_mk_rule_inliner.h (100%) rename src/{muz_qe => muz}/dl_mk_scale.cpp (100%) rename src/{muz_qe => muz}/dl_mk_scale.h (100%) rename src/{muz_qe => muz}/dl_mk_similarity_compressor.cpp (100%) rename src/{muz_qe => muz}/dl_mk_similarity_compressor.h (100%) rename src/{muz_qe => muz}/dl_mk_simple_joins.cpp (100%) rename src/{muz_qe => muz}/dl_mk_simple_joins.h (100%) rename src/{muz_qe => muz}/dl_mk_slice.cpp (99%) rename src/{muz_qe => muz}/dl_mk_slice.h (100%) rename src/{muz_qe => muz}/dl_mk_subsumption_checker.cpp (100%) rename src/{muz_qe => muz}/dl_mk_subsumption_checker.h (100%) rename src/{muz_qe => muz}/dl_mk_unbound_compressor.cpp (100%) rename src/{muz_qe => muz}/dl_mk_unbound_compressor.h (100%) rename src/{muz_qe => muz}/dl_mk_unfold.cpp (100%) rename src/{muz_qe => muz}/dl_mk_unfold.h (100%) rename src/{muz_qe => muz}/dl_product_relation.cpp (100%) rename src/{muz_qe => muz}/dl_product_relation.h (100%) rename src/{muz_qe => muz}/dl_relation_manager.cpp (100%) rename src/{muz_qe => muz}/dl_relation_manager.h (100%) rename src/{muz_qe => muz}/dl_rule.cpp (99%) rename src/{muz_qe => muz}/dl_rule.h (100%) rename src/{muz_qe => muz}/dl_rule_set.cpp (100%) rename src/{muz_qe => muz}/dl_rule_set.h (100%) rename src/{muz_qe => muz}/dl_rule_subsumption_index.cpp (100%) rename src/{muz_qe => muz}/dl_rule_subsumption_index.h (100%) rename src/{muz_qe => muz}/dl_rule_transformer.cpp (100%) rename src/{muz_qe => muz}/dl_rule_transformer.h (100%) rename src/{muz_qe => muz}/dl_sieve_relation.cpp (100%) rename src/{muz_qe => muz}/dl_sieve_relation.h (100%) rename src/{muz_qe => muz}/dl_sparse_table.cpp (100%) rename src/{muz_qe => muz}/dl_sparse_table.h (100%) rename src/{muz_qe => muz}/dl_table.cpp (100%) rename src/{muz_qe => muz}/dl_table.h (100%) rename src/{muz_qe => muz}/dl_table_plugin.h (100%) rename src/{muz_qe => muz}/dl_table_relation.cpp (100%) rename src/{muz_qe => muz}/dl_table_relation.h (100%) rename src/{muz_qe => muz}/dl_util.cpp (83%) rename src/{muz_qe => muz}/dl_util.h (98%) rename src/{muz_qe => muz}/dl_vector_relation.h (100%) rename src/{muz_qe => muz}/equiv_proof_converter.cpp (100%) rename src/{muz_qe => muz}/equiv_proof_converter.h (100%) rename src/{muz_qe => muz}/fixedpoint_params.pyg (100%) rename src/{muz_qe => muz}/heap_trie.h (100%) rename src/{muz_qe => muz}/hilbert_basis.cpp (100%) rename src/{muz_qe => muz}/hilbert_basis.h (100%) rename src/{muz_qe => muz}/hnf.cpp (99%) rename src/{muz_qe => muz}/hnf.h (100%) rename src/{muz_qe => muz}/horn_subsume_model_converter.cpp (100%) rename src/{muz_qe => muz}/horn_subsume_model_converter.h (100%) rename src/{muz_qe => muz}/horn_tactic.cpp (99%) rename src/{muz_qe => muz}/horn_tactic.h (100%) rename src/{muz_qe => muz}/model2expr.cpp (100%) rename src/{muz_qe => muz}/model2expr.h (100%) rename src/{muz_qe => muz}/pdr_context.cpp (99%) rename src/{muz_qe => muz}/pdr_context.h (100%) rename src/{muz_qe => muz}/pdr_dl_interface.cpp (100%) rename src/{muz_qe => muz}/pdr_dl_interface.h (100%) rename src/{muz_qe => muz}/pdr_farkas_learner.cpp (99%) rename src/{muz_qe => muz}/pdr_farkas_learner.h (100%) rename src/{muz_qe => muz}/pdr_generalizers.cpp (99%) rename src/{muz_qe => muz}/pdr_generalizers.h (100%) rename src/{muz_qe => muz}/pdr_manager.cpp (98%) rename src/{muz_qe => muz}/pdr_manager.h (100%) rename src/{muz_qe => muz}/pdr_prop_solver.cpp (99%) rename src/{muz_qe => muz}/pdr_prop_solver.h (100%) rename src/{muz_qe => muz}/pdr_reachable_cache.cpp (100%) rename src/{muz_qe => muz}/pdr_reachable_cache.h (100%) rename src/{muz_qe => muz}/pdr_smt_context_manager.cpp (100%) rename src/{muz_qe => muz}/pdr_smt_context_manager.h (100%) rename src/{muz_qe => muz}/pdr_sym_mux.cpp (100%) rename src/{muz_qe => muz}/pdr_sym_mux.h (100%) rename src/{muz_qe => muz}/pdr_util.cpp (99%) rename src/{muz_qe => muz}/pdr_util.h (100%) rename src/{muz_qe => muz}/proof_utils.cpp (100%) rename src/{muz_qe => muz}/proof_utils.h (100%) rename src/{muz_qe => muz}/rel_context.cpp (100%) rename src/{muz_qe => muz}/rel_context.h (100%) rename src/{muz_qe => muz}/replace_proof_converter.cpp (100%) rename src/{muz_qe => muz}/replace_proof_converter.h (100%) rename src/{muz_qe => muz}/skip_list_base.h (100%) rename src/{muz_qe => muz}/tab_context.cpp (99%) rename src/{muz_qe => muz}/tab_context.h (100%) rename src/{muz_qe => muz}/unit_subsumption_tactic.cpp (100%) rename src/{muz_qe => muz}/unit_subsumption_tactic.h (100%) rename src/{muz_qe => muz}/vsubst_tactic.cpp (100%) rename src/{muz_qe => muz}/vsubst_tactic.h (100%) rename src/{muz_qe => qe}/nlarith_util.cpp (100%) rename src/{muz_qe => qe}/nlarith_util.h (100%) rename src/{muz_qe => qe}/qe.cpp (99%) rename src/{muz_qe => qe}/qe.h (100%) rename src/{muz_qe => qe}/qe_arith_plugin.cpp (100%) rename src/{muz_qe => qe}/qe_array_plugin.cpp (100%) rename src/{muz_qe => qe}/qe_bool_plugin.cpp (100%) rename src/{muz_qe => qe}/qe_bv_plugin.cpp (100%) rename src/{muz_qe => qe}/qe_cmd.cpp (100%) rename src/{muz_qe => qe}/qe_cmd.h (100%) rename src/{muz_qe => qe}/qe_datatype_plugin.cpp (100%) rename src/{muz_qe => qe}/qe_dl_plugin.cpp (100%) rename src/{muz_qe => qe}/qe_lite.cpp (99%) rename src/{muz_qe => qe}/qe_lite.h (100%) rename src/{muz_qe => qe}/qe_sat_tactic.cpp (100%) rename src/{muz_qe => qe}/qe_sat_tactic.h (100%) rename src/{muz_qe => qe}/qe_tactic.cpp (100%) rename src/{muz_qe => qe}/qe_tactic.h (100%) create mode 100644 src/qe/qe_util.cpp create mode 100644 src/qe/qe_util.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index e6e7d5dc8..44ad9ccbc 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -53,11 +53,11 @@ def init_project_def(): add_lib('fpa', ['core_tactics', 'bv_tactics', 'sat_tactic'], 'tactic/fpa') add_lib('smt_tactic', ['smt'], 'smt/tactic') add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls') - # TODO: split muz_qe into muz, qe. Perhaps, we should also consider breaking muz into muz and pdr. - add_lib('muz_qe', ['smt', 'sat', 'smt2parser', 'aig_tactic']) - add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'muz_qe'], 'tactic/smtlogics') + add_lib('qe', ['smt','sat'], 'qe') + add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic','qe']) + add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'muz','qe'], 'tactic/smtlogics') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') - add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'muz_qe', 'sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') + add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'muz', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('smtparser', ['portfolio'], 'parsers/smt') API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h'] add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure'], diff --git a/src/muz_qe/README b/src/muz/README similarity index 100% rename from src/muz_qe/README rename to src/muz/README diff --git a/src/muz_qe/aig_exporter.cpp b/src/muz/aig_exporter.cpp old mode 100755 new mode 100644 similarity index 100% rename from src/muz_qe/aig_exporter.cpp rename to src/muz/aig_exporter.cpp diff --git a/src/muz_qe/aig_exporter.h b/src/muz/aig_exporter.h old mode 100755 new mode 100644 similarity index 100% rename from src/muz_qe/aig_exporter.h rename to src/muz/aig_exporter.h diff --git a/src/muz_qe/arith_bounds_tactic.cpp b/src/muz/arith_bounds_tactic.cpp similarity index 100% rename from src/muz_qe/arith_bounds_tactic.cpp rename to src/muz/arith_bounds_tactic.cpp diff --git a/src/muz_qe/arith_bounds_tactic.h b/src/muz/arith_bounds_tactic.h similarity index 100% rename from src/muz_qe/arith_bounds_tactic.h rename to src/muz/arith_bounds_tactic.h diff --git a/src/muz_qe/clp_context.cpp b/src/muz/clp_context.cpp similarity index 100% rename from src/muz_qe/clp_context.cpp rename to src/muz/clp_context.cpp diff --git a/src/muz_qe/clp_context.h b/src/muz/clp_context.h similarity index 100% rename from src/muz_qe/clp_context.h rename to src/muz/clp_context.h diff --git a/src/muz_qe/datalog_parser.cpp b/src/muz/datalog_parser.cpp similarity index 100% rename from src/muz_qe/datalog_parser.cpp rename to src/muz/datalog_parser.cpp diff --git a/src/muz_qe/datalog_parser.h b/src/muz/datalog_parser.h similarity index 100% rename from src/muz_qe/datalog_parser.h rename to src/muz/datalog_parser.h diff --git a/src/muz_qe/dl_base.cpp b/src/muz/dl_base.cpp similarity index 100% rename from src/muz_qe/dl_base.cpp rename to src/muz/dl_base.cpp diff --git a/src/muz_qe/dl_base.h b/src/muz/dl_base.h similarity index 100% rename from src/muz_qe/dl_base.h rename to src/muz/dl_base.h diff --git a/src/muz_qe/dl_bmc_engine.cpp b/src/muz/dl_bmc_engine.cpp similarity index 100% rename from src/muz_qe/dl_bmc_engine.cpp rename to src/muz/dl_bmc_engine.cpp diff --git a/src/muz_qe/dl_bmc_engine.h b/src/muz/dl_bmc_engine.h similarity index 100% rename from src/muz_qe/dl_bmc_engine.h rename to src/muz/dl_bmc_engine.h diff --git a/src/muz_qe/dl_boogie_proof.cpp b/src/muz/dl_boogie_proof.cpp similarity index 99% rename from src/muz_qe/dl_boogie_proof.cpp rename to src/muz/dl_boogie_proof.cpp index e14512973..d11e4a932 100644 --- a/src/muz_qe/dl_boogie_proof.cpp +++ b/src/muz/dl_boogie_proof.cpp @@ -49,7 +49,7 @@ Example from Boogie: #include "model_pp.h" #include "proof_utils.h" #include "ast_pp.h" -#include "dl_util.h" +#include "qe_util.h" namespace datalog { @@ -91,7 +91,7 @@ namespace datalog { if (!m.is_implies(premise, l1, l2)) { continue; } - datalog::flatten_and(l1, literals); + qe::flatten_and(l1, literals); positions2.reset(); premises2.reset(); premises2.push_back(premise); diff --git a/src/muz_qe/dl_boogie_proof.h b/src/muz/dl_boogie_proof.h similarity index 100% rename from src/muz_qe/dl_boogie_proof.h rename to src/muz/dl_boogie_proof.h diff --git a/src/muz_qe/dl_bound_relation.cpp b/src/muz/dl_bound_relation.cpp similarity index 100% rename from src/muz_qe/dl_bound_relation.cpp rename to src/muz/dl_bound_relation.cpp diff --git a/src/muz_qe/dl_bound_relation.h b/src/muz/dl_bound_relation.h similarity index 100% rename from src/muz_qe/dl_bound_relation.h rename to src/muz/dl_bound_relation.h diff --git a/src/muz_qe/dl_check_table.cpp b/src/muz/dl_check_table.cpp similarity index 100% rename from src/muz_qe/dl_check_table.cpp rename to src/muz/dl_check_table.cpp diff --git a/src/muz_qe/dl_check_table.h b/src/muz/dl_check_table.h similarity index 100% rename from src/muz_qe/dl_check_table.h rename to src/muz/dl_check_table.h diff --git a/src/muz_qe/dl_cmds.cpp b/src/muz/dl_cmds.cpp similarity index 100% rename from src/muz_qe/dl_cmds.cpp rename to src/muz/dl_cmds.cpp diff --git a/src/muz_qe/dl_cmds.h b/src/muz/dl_cmds.h similarity index 100% rename from src/muz_qe/dl_cmds.h rename to src/muz/dl_cmds.h diff --git a/src/muz_qe/dl_compiler.cpp b/src/muz/dl_compiler.cpp similarity index 100% rename from src/muz_qe/dl_compiler.cpp rename to src/muz/dl_compiler.cpp diff --git a/src/muz_qe/dl_compiler.h b/src/muz/dl_compiler.h similarity index 100% rename from src/muz_qe/dl_compiler.h rename to src/muz/dl_compiler.h diff --git a/src/muz_qe/dl_context.cpp b/src/muz/dl_context.cpp similarity index 100% rename from src/muz_qe/dl_context.cpp rename to src/muz/dl_context.cpp index 7da9808e7..f5bfb6b5e 100644 --- a/src/muz_qe/dl_context.cpp +++ b/src/muz/dl_context.cpp @@ -35,12 +35,6 @@ Revision History: #include"dl_mk_similarity_compressor.h" #include"dl_mk_unbound_compressor.h" #include"dl_mk_subsumption_checker.h" -#include"dl_compiler.h" -#include"dl_instruction.h" -#include"dl_context.h" -#include"for_each_expr.h" -#include"ast_smt_pp.h" -#include"ast_smt2_pp.h" #include"dl_mk_partial_equiv.h" #include"dl_mk_bit_blast.h" #include"dl_mk_array_blast.h" @@ -49,6 +43,12 @@ Revision History: #include"dl_mk_quantifier_abstraction.h" #include"dl_mk_quantifier_instantiation.h" #include"dl_mk_scale.h" +#include"dl_compiler.h" +#include"dl_instruction.h" +#include"dl_context.h" +#include"for_each_expr.h" +#include"ast_smt_pp.h" +#include"ast_smt2_pp.h" #include"datatype_decl_plugin.h" diff --git a/src/muz_qe/dl_context.h b/src/muz/dl_context.h similarity index 100% rename from src/muz_qe/dl_context.h rename to src/muz/dl_context.h diff --git a/src/muz_qe/dl_costs.cpp b/src/muz/dl_costs.cpp similarity index 100% rename from src/muz_qe/dl_costs.cpp rename to src/muz/dl_costs.cpp diff --git a/src/muz_qe/dl_costs.h b/src/muz/dl_costs.h similarity index 100% rename from src/muz_qe/dl_costs.h rename to src/muz/dl_costs.h diff --git a/src/muz_qe/dl_external_relation.cpp b/src/muz/dl_external_relation.cpp similarity index 100% rename from src/muz_qe/dl_external_relation.cpp rename to src/muz/dl_external_relation.cpp diff --git a/src/muz_qe/dl_external_relation.h b/src/muz/dl_external_relation.h similarity index 100% rename from src/muz_qe/dl_external_relation.h rename to src/muz/dl_external_relation.h diff --git a/src/muz_qe/dl_finite_product_relation.cpp b/src/muz/dl_finite_product_relation.cpp similarity index 100% rename from src/muz_qe/dl_finite_product_relation.cpp rename to src/muz/dl_finite_product_relation.cpp diff --git a/src/muz_qe/dl_finite_product_relation.h b/src/muz/dl_finite_product_relation.h similarity index 100% rename from src/muz_qe/dl_finite_product_relation.h rename to src/muz/dl_finite_product_relation.h diff --git a/src/muz_qe/dl_instruction.cpp b/src/muz/dl_instruction.cpp similarity index 100% rename from src/muz_qe/dl_instruction.cpp rename to src/muz/dl_instruction.cpp diff --git a/src/muz_qe/dl_instruction.h b/src/muz/dl_instruction.h similarity index 100% rename from src/muz_qe/dl_instruction.h rename to src/muz/dl_instruction.h diff --git a/src/muz_qe/dl_interval_relation.cpp b/src/muz/dl_interval_relation.cpp similarity index 100% rename from src/muz_qe/dl_interval_relation.cpp rename to src/muz/dl_interval_relation.cpp diff --git a/src/muz_qe/dl_interval_relation.h b/src/muz/dl_interval_relation.h similarity index 100% rename from src/muz_qe/dl_interval_relation.h rename to src/muz/dl_interval_relation.h diff --git a/src/muz_qe/dl_mk_array_blast.cpp b/src/muz/dl_mk_array_blast.cpp similarity index 98% rename from src/muz_qe/dl_mk_array_blast.cpp rename to src/muz/dl_mk_array_blast.cpp index 2bfb6807a..776a2da5b 100644 --- a/src/muz_qe/dl_mk_array_blast.cpp +++ b/src/muz/dl_mk_array_blast.cpp @@ -18,7 +18,7 @@ Revision History: --*/ #include "dl_mk_array_blast.h" - +#include "qe_util.h" namespace datalog { @@ -101,7 +101,7 @@ namespace datalog { bool mk_array_blast::ackermanize(rule const& r, expr_ref& body, expr_ref& head) { expr_ref_vector conjs(m); - flatten_and(body, conjs); + qe::flatten_and(body, conjs); m_defs.reset(); m_sub.reset(); m_next_var = 0; @@ -207,7 +207,7 @@ namespace datalog { for (unsigned i = utsz; i < tsz; ++i) { conjs.push_back(r.get_tail(i)); } - flatten_and(conjs); + qe::flatten_and(conjs); for (unsigned i = 0; i < conjs.size(); ++i) { expr* x, *y, *e = conjs[i].get(); diff --git a/src/muz_qe/dl_mk_array_blast.h b/src/muz/dl_mk_array_blast.h similarity index 100% rename from src/muz_qe/dl_mk_array_blast.h rename to src/muz/dl_mk_array_blast.h diff --git a/src/muz_qe/dl_mk_backwards.cpp b/src/muz/dl_mk_backwards.cpp similarity index 100% rename from src/muz_qe/dl_mk_backwards.cpp rename to src/muz/dl_mk_backwards.cpp diff --git a/src/muz_qe/dl_mk_backwards.h b/src/muz/dl_mk_backwards.h similarity index 100% rename from src/muz_qe/dl_mk_backwards.h rename to src/muz/dl_mk_backwards.h diff --git a/src/muz_qe/dl_mk_bit_blast.cpp b/src/muz/dl_mk_bit_blast.cpp similarity index 100% rename from src/muz_qe/dl_mk_bit_blast.cpp rename to src/muz/dl_mk_bit_blast.cpp diff --git a/src/muz_qe/dl_mk_bit_blast.h b/src/muz/dl_mk_bit_blast.h similarity index 100% rename from src/muz_qe/dl_mk_bit_blast.h rename to src/muz/dl_mk_bit_blast.h diff --git a/src/muz_qe/dl_mk_coalesce.cpp b/src/muz/dl_mk_coalesce.cpp similarity index 100% rename from src/muz_qe/dl_mk_coalesce.cpp rename to src/muz/dl_mk_coalesce.cpp diff --git a/src/muz_qe/dl_mk_coalesce.h b/src/muz/dl_mk_coalesce.h similarity index 100% rename from src/muz_qe/dl_mk_coalesce.h rename to src/muz/dl_mk_coalesce.h diff --git a/src/muz_qe/dl_mk_coi_filter.cpp b/src/muz/dl_mk_coi_filter.cpp similarity index 100% rename from src/muz_qe/dl_mk_coi_filter.cpp rename to src/muz/dl_mk_coi_filter.cpp diff --git a/src/muz_qe/dl_mk_coi_filter.h b/src/muz/dl_mk_coi_filter.h similarity index 100% rename from src/muz_qe/dl_mk_coi_filter.h rename to src/muz/dl_mk_coi_filter.h diff --git a/src/muz/dl_mk_different.h b/src/muz/dl_mk_different.h new file mode 100644 index 000000000..2def011f9 --- /dev/null +++ b/src/muz/dl_mk_different.h @@ -0,0 +1,38 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_different_symbolic.h + +Abstract: + + Create Horn clauses for different symbolic transformation. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-06-19 + +Revision History: + +--*/ +#ifndef _DL_MK_DIFFERENT_SYMBOLIC_H_ +#define _DL_MK_DIFFERENT_SYMBOLIC_H_ + +#include"dl_rule_transformer.h" + +namespace datalog { + + class mk_different_symbolic : public rule_transformer::plugin { + ast_manager& m; + context& m_ctx; + public: + mk_different_symbolic(context & ctx, unsigned priority = 33037); + ~mk_different_symbolic(); + rule_set * operator()(rule_set const & source); + }; + +}; + +#endif /* _DL_MK_DIFFERENT_SYMBOLIC_H_ */ + diff --git a/src/muz_qe/dl_mk_explanations.cpp b/src/muz/dl_mk_explanations.cpp similarity index 100% rename from src/muz_qe/dl_mk_explanations.cpp rename to src/muz/dl_mk_explanations.cpp diff --git a/src/muz_qe/dl_mk_explanations.h b/src/muz/dl_mk_explanations.h similarity index 100% rename from src/muz_qe/dl_mk_explanations.h rename to src/muz/dl_mk_explanations.h diff --git a/src/muz_qe/dl_mk_filter_rules.cpp b/src/muz/dl_mk_filter_rules.cpp similarity index 100% rename from src/muz_qe/dl_mk_filter_rules.cpp rename to src/muz/dl_mk_filter_rules.cpp diff --git a/src/muz_qe/dl_mk_filter_rules.h b/src/muz/dl_mk_filter_rules.h similarity index 100% rename from src/muz_qe/dl_mk_filter_rules.h rename to src/muz/dl_mk_filter_rules.h diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp b/src/muz/dl_mk_interp_tail_simplifier.cpp similarity index 99% rename from src/muz_qe/dl_mk_interp_tail_simplifier.cpp rename to src/muz/dl_mk_interp_tail_simplifier.cpp index afd586627..b01b4326c 100644 --- a/src/muz_qe/dl_mk_interp_tail_simplifier.cpp +++ b/src/muz/dl_mk_interp_tail_simplifier.cpp @@ -546,7 +546,7 @@ namespace datalog { if (modified) { m_conj.reset(); - flatten_and(simp_res, m_conj); + qe::flatten_and(simp_res, m_conj); for (unsigned i = 0; i < m_conj.size(); ++i) { expr* e = m_conj[i].get(); if (is_app(e)) { diff --git a/src/muz_qe/dl_mk_interp_tail_simplifier.h b/src/muz/dl_mk_interp_tail_simplifier.h similarity index 100% rename from src/muz_qe/dl_mk_interp_tail_simplifier.h rename to src/muz/dl_mk_interp_tail_simplifier.h diff --git a/src/muz_qe/dl_mk_karr_invariants.cpp b/src/muz/dl_mk_karr_invariants.cpp similarity index 99% rename from src/muz_qe/dl_mk_karr_invariants.cpp rename to src/muz/dl_mk_karr_invariants.cpp index e4e5a1ff8..11bc850bb 100644 --- a/src/muz_qe/dl_mk_karr_invariants.cpp +++ b/src/muz/dl_mk_karr_invariants.cpp @@ -430,7 +430,7 @@ namespace datalog { var* v, *w; rational n1, n2; expr_ref_vector conjs(m); - datalog::flatten_and(cond, conjs); + qe::flatten_and(cond, conjs); matrix& M = get_ineqs(); unsigned num_columns = get_signature().size(); diff --git a/src/muz_qe/dl_mk_karr_invariants.h b/src/muz/dl_mk_karr_invariants.h similarity index 100% rename from src/muz_qe/dl_mk_karr_invariants.h rename to src/muz/dl_mk_karr_invariants.h diff --git a/src/muz_qe/dl_mk_loop_counter.cpp b/src/muz/dl_mk_loop_counter.cpp similarity index 100% rename from src/muz_qe/dl_mk_loop_counter.cpp rename to src/muz/dl_mk_loop_counter.cpp diff --git a/src/muz_qe/dl_mk_loop_counter.h b/src/muz/dl_mk_loop_counter.h similarity index 100% rename from src/muz_qe/dl_mk_loop_counter.h rename to src/muz/dl_mk_loop_counter.h diff --git a/src/muz_qe/dl_mk_magic_sets.cpp b/src/muz/dl_mk_magic_sets.cpp similarity index 100% rename from src/muz_qe/dl_mk_magic_sets.cpp rename to src/muz/dl_mk_magic_sets.cpp diff --git a/src/muz_qe/dl_mk_magic_sets.h b/src/muz/dl_mk_magic_sets.h similarity index 100% rename from src/muz_qe/dl_mk_magic_sets.h rename to src/muz/dl_mk_magic_sets.h diff --git a/src/muz_qe/dl_mk_magic_symbolic.cpp b/src/muz/dl_mk_magic_symbolic.cpp similarity index 100% rename from src/muz_qe/dl_mk_magic_symbolic.cpp rename to src/muz/dl_mk_magic_symbolic.cpp diff --git a/src/muz_qe/dl_mk_magic_symbolic.h b/src/muz/dl_mk_magic_symbolic.h similarity index 100% rename from src/muz_qe/dl_mk_magic_symbolic.h rename to src/muz/dl_mk_magic_symbolic.h diff --git a/src/muz_qe/dl_mk_partial_equiv.cpp b/src/muz/dl_mk_partial_equiv.cpp similarity index 100% rename from src/muz_qe/dl_mk_partial_equiv.cpp rename to src/muz/dl_mk_partial_equiv.cpp diff --git a/src/muz_qe/dl_mk_partial_equiv.h b/src/muz/dl_mk_partial_equiv.h similarity index 100% rename from src/muz_qe/dl_mk_partial_equiv.h rename to src/muz/dl_mk_partial_equiv.h diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.cpp b/src/muz/dl_mk_quantifier_abstraction.cpp similarity index 100% rename from src/muz_qe/dl_mk_quantifier_abstraction.cpp rename to src/muz/dl_mk_quantifier_abstraction.cpp diff --git a/src/muz_qe/dl_mk_quantifier_abstraction.h b/src/muz/dl_mk_quantifier_abstraction.h similarity index 100% rename from src/muz_qe/dl_mk_quantifier_abstraction.h rename to src/muz/dl_mk_quantifier_abstraction.h diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.cpp b/src/muz/dl_mk_quantifier_instantiation.cpp similarity index 99% rename from src/muz_qe/dl_mk_quantifier_instantiation.cpp rename to src/muz/dl_mk_quantifier_instantiation.cpp index ddbddca01..b24e3e81c 100644 --- a/src/muz_qe/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/dl_mk_quantifier_instantiation.cpp @@ -48,7 +48,7 @@ namespace datalog { for (unsigned j = 0; j < tsz; ++j) { conjs.push_back(r.get_tail(j)); } - datalog::flatten_and(conjs); + qe::flatten_and(conjs); for (unsigned j = 0; j < conjs.size(); ++j) { expr* e = conjs[j].get(); quantifier* q; diff --git a/src/muz_qe/dl_mk_quantifier_instantiation.h b/src/muz/dl_mk_quantifier_instantiation.h similarity index 100% rename from src/muz_qe/dl_mk_quantifier_instantiation.h rename to src/muz/dl_mk_quantifier_instantiation.h diff --git a/src/muz_qe/dl_mk_rule_inliner.cpp b/src/muz/dl_mk_rule_inliner.cpp similarity index 100% rename from src/muz_qe/dl_mk_rule_inliner.cpp rename to src/muz/dl_mk_rule_inliner.cpp diff --git a/src/muz_qe/dl_mk_rule_inliner.h b/src/muz/dl_mk_rule_inliner.h similarity index 100% rename from src/muz_qe/dl_mk_rule_inliner.h rename to src/muz/dl_mk_rule_inliner.h diff --git a/src/muz_qe/dl_mk_scale.cpp b/src/muz/dl_mk_scale.cpp similarity index 100% rename from src/muz_qe/dl_mk_scale.cpp rename to src/muz/dl_mk_scale.cpp diff --git a/src/muz_qe/dl_mk_scale.h b/src/muz/dl_mk_scale.h similarity index 100% rename from src/muz_qe/dl_mk_scale.h rename to src/muz/dl_mk_scale.h diff --git a/src/muz_qe/dl_mk_similarity_compressor.cpp b/src/muz/dl_mk_similarity_compressor.cpp similarity index 100% rename from src/muz_qe/dl_mk_similarity_compressor.cpp rename to src/muz/dl_mk_similarity_compressor.cpp diff --git a/src/muz_qe/dl_mk_similarity_compressor.h b/src/muz/dl_mk_similarity_compressor.h similarity index 100% rename from src/muz_qe/dl_mk_similarity_compressor.h rename to src/muz/dl_mk_similarity_compressor.h diff --git a/src/muz_qe/dl_mk_simple_joins.cpp b/src/muz/dl_mk_simple_joins.cpp similarity index 100% rename from src/muz_qe/dl_mk_simple_joins.cpp rename to src/muz/dl_mk_simple_joins.cpp diff --git a/src/muz_qe/dl_mk_simple_joins.h b/src/muz/dl_mk_simple_joins.h similarity index 100% rename from src/muz_qe/dl_mk_simple_joins.h rename to src/muz/dl_mk_simple_joins.h diff --git a/src/muz_qe/dl_mk_slice.cpp b/src/muz/dl_mk_slice.cpp similarity index 99% rename from src/muz_qe/dl_mk_slice.cpp rename to src/muz/dl_mk_slice.cpp index 5b9d43acc..0df75324d 100644 --- a/src/muz_qe/dl_mk_slice.cpp +++ b/src/muz/dl_mk_slice.cpp @@ -619,7 +619,7 @@ namespace datalog { for (unsigned j = r.get_uninterpreted_tail_size(); j < r.get_tail_size(); ++j) { conjs.push_back(r.get_tail(j)); } - datalog::flatten_and(conjs); + qe::flatten_and(conjs); return conjs; } diff --git a/src/muz_qe/dl_mk_slice.h b/src/muz/dl_mk_slice.h similarity index 100% rename from src/muz_qe/dl_mk_slice.h rename to src/muz/dl_mk_slice.h diff --git a/src/muz_qe/dl_mk_subsumption_checker.cpp b/src/muz/dl_mk_subsumption_checker.cpp similarity index 100% rename from src/muz_qe/dl_mk_subsumption_checker.cpp rename to src/muz/dl_mk_subsumption_checker.cpp diff --git a/src/muz_qe/dl_mk_subsumption_checker.h b/src/muz/dl_mk_subsumption_checker.h similarity index 100% rename from src/muz_qe/dl_mk_subsumption_checker.h rename to src/muz/dl_mk_subsumption_checker.h diff --git a/src/muz_qe/dl_mk_unbound_compressor.cpp b/src/muz/dl_mk_unbound_compressor.cpp similarity index 100% rename from src/muz_qe/dl_mk_unbound_compressor.cpp rename to src/muz/dl_mk_unbound_compressor.cpp diff --git a/src/muz_qe/dl_mk_unbound_compressor.h b/src/muz/dl_mk_unbound_compressor.h similarity index 100% rename from src/muz_qe/dl_mk_unbound_compressor.h rename to src/muz/dl_mk_unbound_compressor.h diff --git a/src/muz_qe/dl_mk_unfold.cpp b/src/muz/dl_mk_unfold.cpp similarity index 100% rename from src/muz_qe/dl_mk_unfold.cpp rename to src/muz/dl_mk_unfold.cpp diff --git a/src/muz_qe/dl_mk_unfold.h b/src/muz/dl_mk_unfold.h similarity index 100% rename from src/muz_qe/dl_mk_unfold.h rename to src/muz/dl_mk_unfold.h diff --git a/src/muz_qe/dl_product_relation.cpp b/src/muz/dl_product_relation.cpp similarity index 100% rename from src/muz_qe/dl_product_relation.cpp rename to src/muz/dl_product_relation.cpp diff --git a/src/muz_qe/dl_product_relation.h b/src/muz/dl_product_relation.h similarity index 100% rename from src/muz_qe/dl_product_relation.h rename to src/muz/dl_product_relation.h diff --git a/src/muz_qe/dl_relation_manager.cpp b/src/muz/dl_relation_manager.cpp similarity index 100% rename from src/muz_qe/dl_relation_manager.cpp rename to src/muz/dl_relation_manager.cpp diff --git a/src/muz_qe/dl_relation_manager.h b/src/muz/dl_relation_manager.h similarity index 100% rename from src/muz_qe/dl_relation_manager.h rename to src/muz/dl_relation_manager.h diff --git a/src/muz_qe/dl_rule.cpp b/src/muz/dl_rule.cpp similarity index 99% rename from src/muz_qe/dl_rule.cpp rename to src/muz/dl_rule.cpp index 455f2c244..5ac580cb8 100644 --- a/src/muz_qe/dl_rule.cpp +++ b/src/muz/dl_rule.cpp @@ -263,7 +263,7 @@ namespace datalog { if (m.is_implies(fml, e1, e2)) { expr_ref_vector es(m); head = ensure_app(e2); - datalog::flatten_and(e1, es); + qe::flatten_and(e1, es); for (unsigned i = 0; i < es.size(); ++i) { body.push_back(ensure_app(es[i].get())); } @@ -380,7 +380,7 @@ namespace datalog { for (unsigned i = 0; i < body.size(); ++i) { r.push_back(body[i].get()); } - flatten_and(r); + qe::flatten_and(r); body.reset(); for (unsigned i = 0; i < r.size(); ++i) { body.push_back(ensure_app(r[i].get())); diff --git a/src/muz_qe/dl_rule.h b/src/muz/dl_rule.h similarity index 100% rename from src/muz_qe/dl_rule.h rename to src/muz/dl_rule.h diff --git a/src/muz_qe/dl_rule_set.cpp b/src/muz/dl_rule_set.cpp similarity index 100% rename from src/muz_qe/dl_rule_set.cpp rename to src/muz/dl_rule_set.cpp diff --git a/src/muz_qe/dl_rule_set.h b/src/muz/dl_rule_set.h similarity index 100% rename from src/muz_qe/dl_rule_set.h rename to src/muz/dl_rule_set.h diff --git a/src/muz_qe/dl_rule_subsumption_index.cpp b/src/muz/dl_rule_subsumption_index.cpp similarity index 100% rename from src/muz_qe/dl_rule_subsumption_index.cpp rename to src/muz/dl_rule_subsumption_index.cpp diff --git a/src/muz_qe/dl_rule_subsumption_index.h b/src/muz/dl_rule_subsumption_index.h similarity index 100% rename from src/muz_qe/dl_rule_subsumption_index.h rename to src/muz/dl_rule_subsumption_index.h diff --git a/src/muz_qe/dl_rule_transformer.cpp b/src/muz/dl_rule_transformer.cpp similarity index 100% rename from src/muz_qe/dl_rule_transformer.cpp rename to src/muz/dl_rule_transformer.cpp diff --git a/src/muz_qe/dl_rule_transformer.h b/src/muz/dl_rule_transformer.h similarity index 100% rename from src/muz_qe/dl_rule_transformer.h rename to src/muz/dl_rule_transformer.h diff --git a/src/muz_qe/dl_sieve_relation.cpp b/src/muz/dl_sieve_relation.cpp similarity index 100% rename from src/muz_qe/dl_sieve_relation.cpp rename to src/muz/dl_sieve_relation.cpp diff --git a/src/muz_qe/dl_sieve_relation.h b/src/muz/dl_sieve_relation.h similarity index 100% rename from src/muz_qe/dl_sieve_relation.h rename to src/muz/dl_sieve_relation.h diff --git a/src/muz_qe/dl_sparse_table.cpp b/src/muz/dl_sparse_table.cpp similarity index 100% rename from src/muz_qe/dl_sparse_table.cpp rename to src/muz/dl_sparse_table.cpp diff --git a/src/muz_qe/dl_sparse_table.h b/src/muz/dl_sparse_table.h similarity index 100% rename from src/muz_qe/dl_sparse_table.h rename to src/muz/dl_sparse_table.h diff --git a/src/muz_qe/dl_table.cpp b/src/muz/dl_table.cpp similarity index 100% rename from src/muz_qe/dl_table.cpp rename to src/muz/dl_table.cpp diff --git a/src/muz_qe/dl_table.h b/src/muz/dl_table.h similarity index 100% rename from src/muz_qe/dl_table.h rename to src/muz/dl_table.h diff --git a/src/muz_qe/dl_table_plugin.h b/src/muz/dl_table_plugin.h similarity index 100% rename from src/muz_qe/dl_table_plugin.h rename to src/muz/dl_table_plugin.h diff --git a/src/muz_qe/dl_table_relation.cpp b/src/muz/dl_table_relation.cpp similarity index 100% rename from src/muz_qe/dl_table_relation.cpp rename to src/muz/dl_table_relation.cpp diff --git a/src/muz_qe/dl_table_relation.h b/src/muz/dl_table_relation.h similarity index 100% rename from src/muz_qe/dl_table_relation.h rename to src/muz/dl_table_relation.h diff --git a/src/muz_qe/dl_util.cpp b/src/muz/dl_util.cpp similarity index 83% rename from src/muz_qe/dl_util.cpp rename to src/muz/dl_util.cpp index 1b1042345..0b88136e2 100644 --- a/src/muz_qe/dl_util.cpp +++ b/src/muz/dl_util.cpp @@ -40,118 +40,6 @@ namespace datalog { ptr->deallocate(); } - void flatten_and(expr_ref_vector& result) { - ast_manager& m = result.get_manager(); - expr* e1, *e2, *e3; - for (unsigned i = 0; i < result.size(); ++i) { - if (m.is_and(result[i].get())) { - app* a = to_app(result[i].get()); - unsigned num_args = a->get_num_args(); - for (unsigned j = 0; j < num_args; ++j) { - result.push_back(a->get_arg(j)); - } - result[i] = result.back(); - result.pop_back(); - --i; - } - else if (m.is_not(result[i].get(), e1) && m.is_not(e1, e2)) { - result[i] = e2; - --i; - } - else if (m.is_not(result[i].get(), e1) && m.is_or(e1)) { - app* a = to_app(e1); - unsigned num_args = a->get_num_args(); - for (unsigned j = 0; j < num_args; ++j) { - result.push_back(m.mk_not(a->get_arg(j))); - } - result[i] = result.back(); - result.pop_back(); - --i; - } - else if (m.is_not(result[i].get(), e1) && m.is_implies(e1,e2,e3)) { - result.push_back(e2); - result[i] = m.mk_not(e3); - --i; - } - else if (m.is_true(result[i].get()) || - (m.is_not(result[i].get(), e1) && - m.is_false(e1))) { - result[i] = result.back(); - result.pop_back(); - --i; - } - else if (m.is_false(result[i].get()) || - (m.is_not(result[i].get(), e1) && - m.is_true(e1))) { - result.reset(); - result.push_back(m.mk_false()); - return; - } - } - } - - void flatten_and(expr* fml, expr_ref_vector& result) { - SASSERT(result.get_manager().is_bool(fml)); - result.push_back(fml); - flatten_and(result); - } - - void flatten_or(expr_ref_vector& result) { - ast_manager& m = result.get_manager(); - expr* e1, *e2, *e3; - for (unsigned i = 0; i < result.size(); ++i) { - if (m.is_or(result[i].get())) { - app* a = to_app(result[i].get()); - unsigned num_args = a->get_num_args(); - for (unsigned j = 0; j < num_args; ++j) { - result.push_back(a->get_arg(j)); - } - result[i] = result.back(); - result.pop_back(); - --i; - } - else if (m.is_not(result[i].get(), e1) && m.is_not(e1, e2)) { - result[i] = e2; - --i; - } - else if (m.is_not(result[i].get(), e1) && m.is_and(e1)) { - app* a = to_app(e1); - unsigned num_args = a->get_num_args(); - for (unsigned j = 0; j < num_args; ++j) { - result.push_back(m.mk_not(a->get_arg(j))); - } - result[i] = result.back(); - result.pop_back(); - --i; - } - else if (m.is_implies(result[i].get(),e2,e3)) { - result.push_back(e3); - result[i] = m.mk_not(e2); - --i; - } - else if (m.is_false(result[i].get()) || - (m.is_not(result[i].get(), e1) && - m.is_true(e1))) { - result[i] = result.back(); - result.pop_back(); - --i; - } - else if (m.is_true(result[i].get()) || - (m.is_not(result[i].get(), e1) && - m.is_false(e1))) { - result.reset(); - result.push_back(m.mk_true()); - return; - } - } - } - - - void flatten_or(expr* fml, expr_ref_vector& result) { - SASSERT(result.get_manager().is_bool(fml)); - result.push_back(fml); - flatten_or(result); - } bool contains_var(expr * trm, unsigned var_idx) { ptr_vector vars; diff --git a/src/muz_qe/dl_util.h b/src/muz/dl_util.h similarity index 98% rename from src/muz_qe/dl_util.h rename to src/muz/dl_util.h index b92a33d1a..debb4d3e2 100644 --- a/src/muz_qe/dl_util.h +++ b/src/muz/dl_util.h @@ -30,6 +30,7 @@ Revision History: #include"ast_counter.h" #include"statistics.h" #include"lbool.h" +#include"qe_util.h" namespace datalog { @@ -107,18 +108,6 @@ namespace datalog { typedef u_map varidx2var_map; typedef obj_hashtable func_decl_set; //!< Rule dependencies. typedef vector string_vector; - - - /** - \brief Collect top-level conjunctions and disjunctions. - */ - void flatten_and(expr_ref_vector& result); - - void flatten_and(expr* fml, expr_ref_vector& result); - - void flatten_or(expr_ref_vector& result); - - void flatten_or(expr* fml, expr_ref_vector& result); bool contains_var(expr * trm, unsigned var_idx); diff --git a/src/muz_qe/dl_vector_relation.h b/src/muz/dl_vector_relation.h similarity index 100% rename from src/muz_qe/dl_vector_relation.h rename to src/muz/dl_vector_relation.h diff --git a/src/muz_qe/equiv_proof_converter.cpp b/src/muz/equiv_proof_converter.cpp similarity index 100% rename from src/muz_qe/equiv_proof_converter.cpp rename to src/muz/equiv_proof_converter.cpp diff --git a/src/muz_qe/equiv_proof_converter.h b/src/muz/equiv_proof_converter.h similarity index 100% rename from src/muz_qe/equiv_proof_converter.h rename to src/muz/equiv_proof_converter.h diff --git a/src/muz_qe/fixedpoint_params.pyg b/src/muz/fixedpoint_params.pyg similarity index 100% rename from src/muz_qe/fixedpoint_params.pyg rename to src/muz/fixedpoint_params.pyg diff --git a/src/muz_qe/heap_trie.h b/src/muz/heap_trie.h similarity index 100% rename from src/muz_qe/heap_trie.h rename to src/muz/heap_trie.h diff --git a/src/muz_qe/hilbert_basis.cpp b/src/muz/hilbert_basis.cpp similarity index 100% rename from src/muz_qe/hilbert_basis.cpp rename to src/muz/hilbert_basis.cpp diff --git a/src/muz_qe/hilbert_basis.h b/src/muz/hilbert_basis.h similarity index 100% rename from src/muz_qe/hilbert_basis.h rename to src/muz/hilbert_basis.h diff --git a/src/muz_qe/hnf.cpp b/src/muz/hnf.cpp similarity index 99% rename from src/muz_qe/hnf.cpp rename to src/muz/hnf.cpp index 36316cfa6..9d6f3c1ab 100644 --- a/src/muz_qe/hnf.cpp +++ b/src/muz/hnf.cpp @@ -214,7 +214,7 @@ private: m_body.push_back(e1); head = e2; } - datalog::flatten_and(m_body); + qe::flatten_and(m_body); if (premise) { p = m.mk_rewrite(fml0, mk_implies(m_body, head)); } diff --git a/src/muz_qe/hnf.h b/src/muz/hnf.h similarity index 100% rename from src/muz_qe/hnf.h rename to src/muz/hnf.h diff --git a/src/muz_qe/horn_subsume_model_converter.cpp b/src/muz/horn_subsume_model_converter.cpp similarity index 100% rename from src/muz_qe/horn_subsume_model_converter.cpp rename to src/muz/horn_subsume_model_converter.cpp diff --git a/src/muz_qe/horn_subsume_model_converter.h b/src/muz/horn_subsume_model_converter.h similarity index 100% rename from src/muz_qe/horn_subsume_model_converter.h rename to src/muz/horn_subsume_model_converter.h diff --git a/src/muz_qe/horn_tactic.cpp b/src/muz/horn_tactic.cpp similarity index 99% rename from src/muz_qe/horn_tactic.cpp rename to src/muz/horn_tactic.cpp index 1916839f4..07a0e2568 100644 --- a/src/muz_qe/horn_tactic.cpp +++ b/src/muz/horn_tactic.cpp @@ -141,7 +141,7 @@ class horn_tactic : public tactic { expr_ref_vector args(m), body(m); expr_ref head(m); expr* a = 0, *a1 = 0; - datalog::flatten_or(tmp, args); + qe::flatten_or(tmp, args); for (unsigned i = 0; i < args.size(); ++i) { a = args[i].get(); check_predicate(mark, a); diff --git a/src/muz_qe/horn_tactic.h b/src/muz/horn_tactic.h similarity index 100% rename from src/muz_qe/horn_tactic.h rename to src/muz/horn_tactic.h diff --git a/src/muz_qe/model2expr.cpp b/src/muz/model2expr.cpp similarity index 100% rename from src/muz_qe/model2expr.cpp rename to src/muz/model2expr.cpp diff --git a/src/muz_qe/model2expr.h b/src/muz/model2expr.h similarity index 100% rename from src/muz_qe/model2expr.h rename to src/muz/model2expr.h diff --git a/src/muz_qe/pdr_context.cpp b/src/muz/pdr_context.cpp similarity index 99% rename from src/muz_qe/pdr_context.cpp rename to src/muz/pdr_context.cpp index ff40be4f3..db85bc5a9 100644 --- a/src/muz_qe/pdr_context.cpp +++ b/src/muz/pdr_context.cpp @@ -45,6 +45,7 @@ Notes: #include "smt_value_sort.h" #include "proof_utils.h" #include "dl_boogie_proof.h" +#include "qe_util.h" namespace pdr { @@ -342,7 +343,7 @@ namespace pdr { void pred_transformer::add_property(expr* lemma, unsigned lvl) { expr_ref_vector lemmas(m); - datalog::flatten_and(lemma, lemmas); + qe::flatten_and(lemma, lemmas); for (unsigned i = 0; i < lemmas.size(); ++i) { expr* lemma_i = lemmas[i].get(); if (add_property1(lemma_i, lvl)) { @@ -587,7 +588,7 @@ namespace pdr { for (unsigned i = ut_size; i < t_size; ++i) { tail.push_back(rule.get_tail(i)); } - datalog::flatten_and(tail); + qe::flatten_and(tail); for (unsigned i = 0; i < tail.size(); ++i) { expr_ref tmp(m); var_subst(m, false)(tail[i].get(), var_reprs.size(), (expr*const*)var_reprs.c_ptr(), tmp); @@ -778,7 +779,7 @@ namespace pdr { ast_manager& m = pt().get_manager(); expr_ref_vector conjs(m); obj_map model; - datalog::flatten_and(state(), conjs); + qe::flatten_and(state(), conjs); for (unsigned i = 0; i < conjs.size(); ++i) { expr* e = conjs[i].get(), *e1, *e2; if (m.is_eq(e, e1, e2) || m.is_iff(e, e1, e2)) { @@ -1979,7 +1980,7 @@ namespace pdr { expr_ref_vector mdl(m), forms(m), Phi(m); forms.push_back(T); forms.push_back(phi); - datalog::flatten_and(forms); + qe::flatten_and(forms); ptr_vector forms1(forms.size(), forms.c_ptr()); if (use_model_generalizer) { Phi.append(mev.minimize_model(forms1, M)); @@ -2035,7 +2036,7 @@ namespace pdr { TRACE("pdr", tout << "Projected:\n" << mk_pp(phi1, m) << "\n";); } Phi.reset(); - datalog::flatten_and(phi1, Phi); + qe::flatten_and(phi1, Phi); unsigned_vector indices; vector child_states; child_states.resize(preds.size(), expr_ref_vector(m)); diff --git a/src/muz_qe/pdr_context.h b/src/muz/pdr_context.h similarity index 100% rename from src/muz_qe/pdr_context.h rename to src/muz/pdr_context.h diff --git a/src/muz_qe/pdr_dl_interface.cpp b/src/muz/pdr_dl_interface.cpp similarity index 100% rename from src/muz_qe/pdr_dl_interface.cpp rename to src/muz/pdr_dl_interface.cpp diff --git a/src/muz_qe/pdr_dl_interface.h b/src/muz/pdr_dl_interface.h similarity index 100% rename from src/muz_qe/pdr_dl_interface.h rename to src/muz/pdr_dl_interface.h diff --git a/src/muz_qe/pdr_farkas_learner.cpp b/src/muz/pdr_farkas_learner.cpp similarity index 99% rename from src/muz_qe/pdr_farkas_learner.cpp rename to src/muz/pdr_farkas_learner.cpp index 8bc77ecc6..6202c913d 100644 --- a/src/muz_qe/pdr_farkas_learner.cpp +++ b/src/muz/pdr_farkas_learner.cpp @@ -320,7 +320,7 @@ namespace pdr { expr_set bs; expr_ref_vector blist(m_pr); - datalog::flatten_and(B, blist); + qe::flatten_and(B, blist); for (unsigned i = 0; i < blist.size(); ++i) { bs.insert(blist[i].get()); } diff --git a/src/muz_qe/pdr_farkas_learner.h b/src/muz/pdr_farkas_learner.h similarity index 100% rename from src/muz_qe/pdr_farkas_learner.h rename to src/muz/pdr_farkas_learner.h diff --git a/src/muz_qe/pdr_generalizers.cpp b/src/muz/pdr_generalizers.cpp similarity index 99% rename from src/muz_qe/pdr_generalizers.cpp rename to src/muz/pdr_generalizers.cpp index 8e15fa983..93a1c1844 100644 --- a/src/muz_qe/pdr_generalizers.cpp +++ b/src/muz/pdr_generalizers.cpp @@ -137,7 +137,7 @@ namespace pdr { C = pm.mk_or(Bs); TRACE("pdr", tout << "prop:\n" << mk_pp(A,m) << "\ngen:" << mk_pp(B, m) << "\nto: " << mk_pp(C, m) << "\n";); core.reset(); - datalog::flatten_and(C, core); + qe::flatten_and(C, core); uses_level = true; } } @@ -157,7 +157,7 @@ namespace pdr { } void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { - // method3(n, core, uses_level, new_cores); + method3(n, core, uses_level, new_cores); method1(n, core, uses_level, new_cores); } @@ -194,11 +194,11 @@ namespace pdr { } expr_ref fml = n.pt().get_formulas(n.level(), false); expr_ref_vector fmls(m); - datalog::flatten_and(fml, fmls); + qe::flatten_and(fml, fmls); for (unsigned i = 0; i < fmls.size(); ++i) { fml = m.mk_not(fmls[i].get()); core2.reset(); - datalog::flatten_and(fml, core2); + qe::flatten_and(fml, core2); if (!mk_convex(core2, 1, conv2)) { IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core2), m) << "\n";); continue; @@ -332,7 +332,7 @@ namespace pdr { for (unsigned i = 0; i < consequences.size(); ++i) { es.reset(); tmp = m.mk_not(consequences[i].get()); - datalog::flatten_and(tmp, es); + qe::flatten_and(tmp, es); if (!mk_convex(es, i, conv)) { IF_VERBOSE(0, verbose_stream() << "Failed to create convex closure\n";); return; diff --git a/src/muz_qe/pdr_generalizers.h b/src/muz/pdr_generalizers.h similarity index 100% rename from src/muz_qe/pdr_generalizers.h rename to src/muz/pdr_generalizers.h diff --git a/src/muz_qe/pdr_manager.cpp b/src/muz/pdr_manager.cpp similarity index 98% rename from src/muz_qe/pdr_manager.cpp rename to src/muz/pdr_manager.cpp index 3e79e4f00..9eb10aba9 100644 --- a/src/muz_qe/pdr_manager.cpp +++ b/src/muz/pdr_manager.cpp @@ -56,7 +56,7 @@ namespace pdr { expr_ref inductive_property::fixup_clause(expr* fml) const { expr_ref_vector disjs(m); - datalog::flatten_or(fml, disjs); + qe::flatten_or(fml, disjs); expr_ref result(m); bool_rewriter(m).mk_or(disjs.size(), disjs.c_ptr(), result); return result; @@ -65,7 +65,7 @@ namespace pdr { expr_ref inductive_property::fixup_clauses(expr* fml) const { expr_ref_vector conjs(m); expr_ref result(m); - datalog::flatten_and(fml, conjs); + qe::flatten_and(fml, conjs); for (unsigned i = 0; i < conjs.size(); ++i) { conjs[i] = fixup_clause(conjs[i].get()); } @@ -238,7 +238,7 @@ namespace pdr { expr_ref manager::mk_not_and(expr_ref_vector const& conjs) { expr_ref result(m), e(m); expr_ref_vector es(conjs); - datalog::flatten_and(es); + qe::flatten_and(es); for (unsigned i = 0; i < es.size(); ++i) { m_brwr.mk_not(es[i].get(), e); es[i] = e; diff --git a/src/muz_qe/pdr_manager.h b/src/muz/pdr_manager.h similarity index 100% rename from src/muz_qe/pdr_manager.h rename to src/muz/pdr_manager.h diff --git a/src/muz_qe/pdr_prop_solver.cpp b/src/muz/pdr_prop_solver.cpp similarity index 99% rename from src/muz_qe/pdr_prop_solver.cpp rename to src/muz/pdr_prop_solver.cpp index eb3c0ee96..d9b22e04e 100644 --- a/src/muz_qe/pdr_prop_solver.cpp +++ b/src/muz/pdr_prop_solver.cpp @@ -76,7 +76,7 @@ namespace pdr { } void mk_safe(expr_ref_vector& conjs) { - datalog::flatten_and(conjs); + qe::flatten_and(conjs); expand_literals(conjs); for (unsigned i = 0; i < conjs.size(); ++i) { expr * lit = conjs[i].get(); diff --git a/src/muz_qe/pdr_prop_solver.h b/src/muz/pdr_prop_solver.h similarity index 100% rename from src/muz_qe/pdr_prop_solver.h rename to src/muz/pdr_prop_solver.h diff --git a/src/muz_qe/pdr_reachable_cache.cpp b/src/muz/pdr_reachable_cache.cpp similarity index 100% rename from src/muz_qe/pdr_reachable_cache.cpp rename to src/muz/pdr_reachable_cache.cpp diff --git a/src/muz_qe/pdr_reachable_cache.h b/src/muz/pdr_reachable_cache.h similarity index 100% rename from src/muz_qe/pdr_reachable_cache.h rename to src/muz/pdr_reachable_cache.h diff --git a/src/muz_qe/pdr_smt_context_manager.cpp b/src/muz/pdr_smt_context_manager.cpp similarity index 100% rename from src/muz_qe/pdr_smt_context_manager.cpp rename to src/muz/pdr_smt_context_manager.cpp diff --git a/src/muz_qe/pdr_smt_context_manager.h b/src/muz/pdr_smt_context_manager.h similarity index 100% rename from src/muz_qe/pdr_smt_context_manager.h rename to src/muz/pdr_smt_context_manager.h diff --git a/src/muz_qe/pdr_sym_mux.cpp b/src/muz/pdr_sym_mux.cpp similarity index 100% rename from src/muz_qe/pdr_sym_mux.cpp rename to src/muz/pdr_sym_mux.cpp diff --git a/src/muz_qe/pdr_sym_mux.h b/src/muz/pdr_sym_mux.h similarity index 100% rename from src/muz_qe/pdr_sym_mux.h rename to src/muz/pdr_sym_mux.h diff --git a/src/muz_qe/pdr_util.cpp b/src/muz/pdr_util.cpp similarity index 99% rename from src/muz_qe/pdr_util.cpp rename to src/muz/pdr_util.cpp index 3d93f8104..d23dc186e 100644 --- a/src/muz_qe/pdr_util.cpp +++ b/src/muz/pdr_util.cpp @@ -954,7 +954,7 @@ namespace pdr { void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) { ast_manager& m = fml.get_manager(); expr_ref_vector conjs(m); - datalog::flatten_and(fml, conjs); + qe::flatten_and(fml, conjs); obj_map diseqs; expr* n, *lhs, *rhs; for (unsigned i = 0; i < conjs.size(); ++i) { diff --git a/src/muz_qe/pdr_util.h b/src/muz/pdr_util.h similarity index 100% rename from src/muz_qe/pdr_util.h rename to src/muz/pdr_util.h diff --git a/src/muz_qe/proof_utils.cpp b/src/muz/proof_utils.cpp similarity index 100% rename from src/muz_qe/proof_utils.cpp rename to src/muz/proof_utils.cpp diff --git a/src/muz_qe/proof_utils.h b/src/muz/proof_utils.h similarity index 100% rename from src/muz_qe/proof_utils.h rename to src/muz/proof_utils.h diff --git a/src/muz_qe/rel_context.cpp b/src/muz/rel_context.cpp similarity index 100% rename from src/muz_qe/rel_context.cpp rename to src/muz/rel_context.cpp diff --git a/src/muz_qe/rel_context.h b/src/muz/rel_context.h similarity index 100% rename from src/muz_qe/rel_context.h rename to src/muz/rel_context.h diff --git a/src/muz_qe/replace_proof_converter.cpp b/src/muz/replace_proof_converter.cpp similarity index 100% rename from src/muz_qe/replace_proof_converter.cpp rename to src/muz/replace_proof_converter.cpp diff --git a/src/muz_qe/replace_proof_converter.h b/src/muz/replace_proof_converter.h similarity index 100% rename from src/muz_qe/replace_proof_converter.h rename to src/muz/replace_proof_converter.h diff --git a/src/muz_qe/skip_list_base.h b/src/muz/skip_list_base.h similarity index 100% rename from src/muz_qe/skip_list_base.h rename to src/muz/skip_list_base.h diff --git a/src/muz_qe/tab_context.cpp b/src/muz/tab_context.cpp similarity index 99% rename from src/muz_qe/tab_context.cpp rename to src/muz/tab_context.cpp index 4f4c14cc7..a56d16a0e 100644 --- a/src/muz_qe/tab_context.cpp +++ b/src/muz/tab_context.cpp @@ -208,7 +208,7 @@ namespace tb { fmls.push_back(m_predicates[i]); } fmls.push_back(m_constraint); - datalog::flatten_and(fmls); + qe::flatten_and(fmls); bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), fml); return fml; } @@ -337,7 +337,7 @@ namespace tb { expr_ref tmp(m); substitution subst(m); subst.reserve(1, get_num_vars()); - datalog::flatten_and(m_constraint, fmls); + qe::flatten_and(m_constraint, fmls); unsigned num_fmls = fmls.size(); for (unsigned i = 0; i < num_fmls; ++i) { if (get_subst(rw, subst, i, fmls)) { @@ -664,7 +664,7 @@ namespace tb { m_qe(m_empty_set, false, fmls); - datalog::flatten_and(fmls); + qe::flatten_and(fmls); for (unsigned i = 0; i < fmls.size(); ++i) { expr_ref n = normalize(fmls[i].get()); if (m_sat_lits.contains(n)) { diff --git a/src/muz_qe/tab_context.h b/src/muz/tab_context.h similarity index 100% rename from src/muz_qe/tab_context.h rename to src/muz/tab_context.h diff --git a/src/muz_qe/unit_subsumption_tactic.cpp b/src/muz/unit_subsumption_tactic.cpp similarity index 100% rename from src/muz_qe/unit_subsumption_tactic.cpp rename to src/muz/unit_subsumption_tactic.cpp diff --git a/src/muz_qe/unit_subsumption_tactic.h b/src/muz/unit_subsumption_tactic.h similarity index 100% rename from src/muz_qe/unit_subsumption_tactic.h rename to src/muz/unit_subsumption_tactic.h diff --git a/src/muz_qe/vsubst_tactic.cpp b/src/muz/vsubst_tactic.cpp similarity index 100% rename from src/muz_qe/vsubst_tactic.cpp rename to src/muz/vsubst_tactic.cpp diff --git a/src/muz_qe/vsubst_tactic.h b/src/muz/vsubst_tactic.h similarity index 100% rename from src/muz_qe/vsubst_tactic.h rename to src/muz/vsubst_tactic.h diff --git a/src/muz_qe/nlarith_util.cpp b/src/qe/nlarith_util.cpp similarity index 100% rename from src/muz_qe/nlarith_util.cpp rename to src/qe/nlarith_util.cpp diff --git a/src/muz_qe/nlarith_util.h b/src/qe/nlarith_util.h similarity index 100% rename from src/muz_qe/nlarith_util.h rename to src/qe/nlarith_util.h diff --git a/src/muz_qe/qe.cpp b/src/qe/qe.cpp similarity index 99% rename from src/muz_qe/qe.cpp rename to src/qe/qe.cpp index 894a935b5..d0aafb896 100644 --- a/src/muz_qe/qe.cpp +++ b/src/qe/qe.cpp @@ -36,7 +36,7 @@ Revision History: #include "expr_functors.h" #include "quant_hoist.h" #include "bool_rewriter.h" -#include "dl_util.h" +#include "qe_util.h" #include "th_rewriter.h" #include "smt_kernel.h" #include "model_evaluator.h" @@ -81,7 +81,7 @@ namespace qe { ptr_vector todo; ptr_vector conjs_closed, conjs_mixed, conjs_open; - datalog::flatten_and(fml, conjs); + qe::flatten_and(fml, conjs); for (unsigned i = 0; i < conjs.size(); ++i) { todo.push_back(conjs[i].get()); @@ -306,7 +306,7 @@ namespace qe { // conj_enum conj_enum::conj_enum(ast_manager& m, expr* e): m(m), m_conjs(m) { - datalog::flatten_and(e, m_conjs); + qe::flatten_and(e, m_conjs); } void conj_enum::extract_equalities(expr_ref_vector& eqs) { diff --git a/src/muz_qe/qe.h b/src/qe/qe.h similarity index 100% rename from src/muz_qe/qe.h rename to src/qe/qe.h diff --git a/src/muz_qe/qe_arith_plugin.cpp b/src/qe/qe_arith_plugin.cpp similarity index 100% rename from src/muz_qe/qe_arith_plugin.cpp rename to src/qe/qe_arith_plugin.cpp diff --git a/src/muz_qe/qe_array_plugin.cpp b/src/qe/qe_array_plugin.cpp similarity index 100% rename from src/muz_qe/qe_array_plugin.cpp rename to src/qe/qe_array_plugin.cpp diff --git a/src/muz_qe/qe_bool_plugin.cpp b/src/qe/qe_bool_plugin.cpp similarity index 100% rename from src/muz_qe/qe_bool_plugin.cpp rename to src/qe/qe_bool_plugin.cpp diff --git a/src/muz_qe/qe_bv_plugin.cpp b/src/qe/qe_bv_plugin.cpp similarity index 100% rename from src/muz_qe/qe_bv_plugin.cpp rename to src/qe/qe_bv_plugin.cpp diff --git a/src/muz_qe/qe_cmd.cpp b/src/qe/qe_cmd.cpp similarity index 100% rename from src/muz_qe/qe_cmd.cpp rename to src/qe/qe_cmd.cpp diff --git a/src/muz_qe/qe_cmd.h b/src/qe/qe_cmd.h similarity index 100% rename from src/muz_qe/qe_cmd.h rename to src/qe/qe_cmd.h diff --git a/src/muz_qe/qe_datatype_plugin.cpp b/src/qe/qe_datatype_plugin.cpp similarity index 100% rename from src/muz_qe/qe_datatype_plugin.cpp rename to src/qe/qe_datatype_plugin.cpp diff --git a/src/muz_qe/qe_dl_plugin.cpp b/src/qe/qe_dl_plugin.cpp similarity index 100% rename from src/muz_qe/qe_dl_plugin.cpp rename to src/qe/qe_dl_plugin.cpp diff --git a/src/muz_qe/qe_lite.cpp b/src/qe/qe_lite.cpp similarity index 99% rename from src/muz_qe/qe_lite.cpp rename to src/qe/qe_lite.cpp index 01537b574..130673527 100644 --- a/src/muz_qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -30,9 +30,8 @@ Revision History: #include "bool_rewriter.h" #include "var_subst.h" #include "uint_set.h" -#include "dl_util.h" +#include "qe_util.h" #include "th_rewriter.h" -#include "dl_util.h" #include "for_each_expr.h" #include "expr_safe_replace.h" #include "cooperate.h" @@ -696,7 +695,7 @@ namespace eq { m_subst(r, m_subst_map.size(), m_subst_map.c_ptr(), new_r); m_rewriter(new_r); conjs.reset(); - datalog::flatten_and(new_r, conjs); + qe::flatten_and(new_r, conjs); reduced = true; } } @@ -2387,7 +2386,7 @@ public: void operator()(uint_set const& index_set, bool index_of_bound, expr_ref& fml) { expr_ref_vector disjs(m); - datalog::flatten_or(fml, disjs); + qe::flatten_or(fml, disjs); for (unsigned i = 0; i < disjs.size(); ++i) { expr_ref_vector conjs(m); conjs.push_back(disjs[i].get()); @@ -2400,7 +2399,7 @@ public: void operator()(uint_set const& index_set, bool index_of_bound, expr_ref_vector& fmls) { - datalog::flatten_and(fmls); + qe::flatten_and(fmls); unsigned index; if (has_unique_non_ground(fmls, index)) { expr_ref fml(m); diff --git a/src/muz_qe/qe_lite.h b/src/qe/qe_lite.h similarity index 100% rename from src/muz_qe/qe_lite.h rename to src/qe/qe_lite.h diff --git a/src/muz_qe/qe_sat_tactic.cpp b/src/qe/qe_sat_tactic.cpp similarity index 100% rename from src/muz_qe/qe_sat_tactic.cpp rename to src/qe/qe_sat_tactic.cpp diff --git a/src/muz_qe/qe_sat_tactic.h b/src/qe/qe_sat_tactic.h similarity index 100% rename from src/muz_qe/qe_sat_tactic.h rename to src/qe/qe_sat_tactic.h diff --git a/src/muz_qe/qe_tactic.cpp b/src/qe/qe_tactic.cpp similarity index 100% rename from src/muz_qe/qe_tactic.cpp rename to src/qe/qe_tactic.cpp diff --git a/src/muz_qe/qe_tactic.h b/src/qe/qe_tactic.h similarity index 100% rename from src/muz_qe/qe_tactic.h rename to src/qe/qe_tactic.h diff --git a/src/qe/qe_util.cpp b/src/qe/qe_util.cpp new file mode 100644 index 000000000..629fe4b56 --- /dev/null +++ b/src/qe/qe_util.cpp @@ -0,0 +1,116 @@ +#include "qe_util.h" + +namespace qe { + void flatten_and(expr_ref_vector& result) { + ast_manager& m = result.get_manager(); + expr* e1, *e2, *e3; + for (unsigned i = 0; i < result.size(); ++i) { + if (m.is_and(result[i].get())) { + app* a = to_app(result[i].get()); + unsigned num_args = a->get_num_args(); + for (unsigned j = 0; j < num_args; ++j) { + result.push_back(a->get_arg(j)); + } + result[i] = result.back(); + result.pop_back(); + --i; + } + else if (m.is_not(result[i].get(), e1) && m.is_not(e1, e2)) { + result[i] = e2; + --i; + } + else if (m.is_not(result[i].get(), e1) && m.is_or(e1)) { + app* a = to_app(e1); + unsigned num_args = a->get_num_args(); + for (unsigned j = 0; j < num_args; ++j) { + result.push_back(m.mk_not(a->get_arg(j))); + } + result[i] = result.back(); + result.pop_back(); + --i; + } + else if (m.is_not(result[i].get(), e1) && m.is_implies(e1,e2,e3)) { + result.push_back(e2); + result[i] = m.mk_not(e3); + --i; + } + else if (m.is_true(result[i].get()) || + (m.is_not(result[i].get(), e1) && + m.is_false(e1))) { + result[i] = result.back(); + result.pop_back(); + --i; + } + else if (m.is_false(result[i].get()) || + (m.is_not(result[i].get(), e1) && + m.is_true(e1))) { + result.reset(); + result.push_back(m.mk_false()); + return; + } + } + } + + void flatten_and(expr* fml, expr_ref_vector& result) { + SASSERT(result.get_manager().is_bool(fml)); + result.push_back(fml); + flatten_and(result); + } + + void flatten_or(expr_ref_vector& result) { + ast_manager& m = result.get_manager(); + expr* e1, *e2, *e3; + for (unsigned i = 0; i < result.size(); ++i) { + if (m.is_or(result[i].get())) { + app* a = to_app(result[i].get()); + unsigned num_args = a->get_num_args(); + for (unsigned j = 0; j < num_args; ++j) { + result.push_back(a->get_arg(j)); + } + result[i] = result.back(); + result.pop_back(); + --i; + } + else if (m.is_not(result[i].get(), e1) && m.is_not(e1, e2)) { + result[i] = e2; + --i; + } + else if (m.is_not(result[i].get(), e1) && m.is_and(e1)) { + app* a = to_app(e1); + unsigned num_args = a->get_num_args(); + for (unsigned j = 0; j < num_args; ++j) { + result.push_back(m.mk_not(a->get_arg(j))); + } + result[i] = result.back(); + result.pop_back(); + --i; + } + else if (m.is_implies(result[i].get(),e2,e3)) { + result.push_back(e3); + result[i] = m.mk_not(e2); + --i; + } + else if (m.is_false(result[i].get()) || + (m.is_not(result[i].get(), e1) && + m.is_true(e1))) { + result[i] = result.back(); + result.pop_back(); + --i; + } + else if (m.is_true(result[i].get()) || + (m.is_not(result[i].get(), e1) && + m.is_false(e1))) { + result.reset(); + result.push_back(m.mk_true()); + return; + } + } + } + + + void flatten_or(expr* fml, expr_ref_vector& result) { + SASSERT(result.get_manager().is_bool(fml)); + result.push_back(fml); + flatten_or(result); + } +} diff --git a/src/qe/qe_util.h b/src/qe/qe_util.h new file mode 100644 index 000000000..7e1fe7f79 --- /dev/null +++ b/src/qe/qe_util.h @@ -0,0 +1,37 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + qe_util.h + +Abstract: + + Utilities for quantifiers. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-08-28 + +Revision History: + +--*/ +#ifndef _QE_UTIL_H_ +#define _QE_UTIL_H_ + +#include "ast.h" + +namespace qe { + /** + \brief Collect top-level conjunctions and disjunctions. + */ + void flatten_and(expr_ref_vector& result); + + void flatten_and(expr* fml, expr_ref_vector& result); + + void flatten_or(expr_ref_vector& result); + + void flatten_or(expr* fml, expr_ref_vector& result); + +} +#endif From 4597872be803dfd54062f2268ab15a311f4ba96a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Aug 2013 12:18:02 -0700 Subject: [PATCH 245/281] fix reset regression with mk_convex: Signed-off-by: Nikolaj Bjorner --- src/muz/pdr_generalizers.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/muz/pdr_generalizers.cpp b/src/muz/pdr_generalizers.cpp index 93a1c1844..883429315 100644 --- a/src/muz/pdr_generalizers.cpp +++ b/src/muz/pdr_generalizers.cpp @@ -157,7 +157,7 @@ namespace pdr { } void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { - method3(n, core, uses_level, new_cores); + // method3(n, core, uses_level, new_cores); method1(n, core, uses_level, new_cores); } @@ -180,18 +180,19 @@ namespace pdr { // void core_convex_hull_generalizer::method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { manager& pm = n.pt().get_pdr_manager(); - expr_ref_vector conv1(m), conv2(m), core1(m), core2(m); + expr_ref_vector conv1(m), conv2(m), core1(m), core2(m), fmls(m); unsigned orig_size = new_cores.size(); if (core.empty()) { new_cores.push_back(std::make_pair(core, uses_level)); return; } - add_variables(n, 2, conv1); + add_variables(n, 2, fmls); if (!mk_convex(core, 0, conv1)) { new_cores.push_back(std::make_pair(core, uses_level)); IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core), m) << "\n";); return; } + conv1.append(fmls); expr_ref fml = n.pt().get_formulas(n.level(), false); expr_ref_vector fmls(m); qe::flatten_and(fml, fmls); From 0d56499e2d96db8963f513e3a871c202b29ed70d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Aug 2013 21:20:24 -0700 Subject: [PATCH 246/281] re-organize muz_qe into separate units Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 13 +- src/api/api_datalog.cpp | 8 +- src/muz/{ => bmc}/dl_bmc_engine.cpp | 5 +- src/muz/{ => bmc}/dl_bmc_engine.h | 0 src/muz/{ => clp}/clp_context.cpp | 4 +- src/muz/{ => clp}/clp_context.h | 2 +- src/muz/dl_base.cpp | 459 ---- src/muz/dl_base.h | 1261 --------- src/muz/dl_bound_relation.cpp | 707 ----- src/muz/dl_bound_relation.h | 176 -- src/muz/dl_check_table.cpp | 439 --- src/muz/dl_check_table.h | 135 - src/muz/dl_cmds.h | 37 - src/muz/dl_context.cpp | 128 +- src/muz/dl_context.h | 100 +- src/muz/dl_engine_base.h | 82 + src/muz/dl_external_relation.cpp | 456 ---- src/muz/dl_external_relation.h | 154 -- src/muz/dl_finite_product_relation.cpp | 2377 ----------------- src/muz/dl_finite_product_relation.h | 366 --- src/muz/dl_interval_relation.cpp | 652 ----- src/muz/dl_interval_relation.h | 140 - src/muz/dl_mk_explanations.cpp | 880 ------ src/muz/dl_mk_explanations.h | 86 - src/muz/dl_mk_karr_invariants.cpp | 1114 -------- src/muz/dl_mk_karr_invariants.h | 138 - src/muz/dl_mk_partial_equiv.cpp | 154 -- src/muz/dl_mk_partial_equiv.h | 50 - src/muz/dl_mk_similarity_compressor.cpp | 545 ---- src/muz/dl_mk_similarity_compressor.h | 78 - src/muz/dl_mk_simple_joins.cpp | 741 ----- src/muz/dl_mk_simple_joins.h | 63 - src/muz/dl_product_relation.cpp | 1117 -------- src/muz/dl_product_relation.h | 190 -- src/muz/dl_relation_manager.cpp | 1702 ------------ src/muz/dl_relation_manager.h | 688 ----- src/muz/dl_sieve_relation.cpp | 666 ----- src/muz/dl_sieve_relation.h | 197 -- src/muz/dl_sparse_table.cpp | 1246 --------- src/muz/dl_sparse_table.h | 480 ---- src/muz/dl_table.cpp | 772 ------ src/muz/dl_table.h | 265 -- src/muz/dl_table_plugin.h | 193 -- src/muz/dl_table_relation.cpp | 490 ---- src/muz/dl_table_relation.h | 133 - src/muz/dl_util.cpp | 27 - src/muz/dl_util.h | 59 - src/muz/dl_vector_relation.h | 407 --- src/muz/{ => fp}/dl_cmds.cpp | 4 +- src/muz/fp/dl_register_engine.cpp | 51 + src/muz/fp/dl_register_engine.h | 36 + src/muz/{ => fp}/horn_tactic.cpp | 7 +- src/muz/{ => fp}/horn_tactic.h | 0 src/muz/{ => pdr}/pdr_context.cpp | 0 src/muz/{ => pdr}/pdr_context.h | 1 - src/muz/{ => pdr}/pdr_dl_interface.cpp | 4 +- src/muz/{ => pdr}/pdr_dl_interface.h | 1 + src/muz/{ => pdr}/pdr_farkas_learner.cpp | 0 src/muz/{ => pdr}/pdr_farkas_learner.h | 0 src/muz/{ => pdr}/pdr_generalizers.cpp | 2 +- src/muz/{ => pdr}/pdr_generalizers.h | 0 src/muz/{ => pdr}/pdr_manager.cpp | 0 src/muz/{ => pdr}/pdr_manager.h | 0 src/muz/{ => pdr}/pdr_prop_solver.cpp | 0 src/muz/{ => pdr}/pdr_prop_solver.h | 0 src/muz/{ => pdr}/pdr_reachable_cache.cpp | 0 src/muz/{ => pdr}/pdr_reachable_cache.h | 0 src/muz/{ => pdr}/pdr_smt_context_manager.cpp | 0 src/muz/{ => pdr}/pdr_smt_context_manager.h | 0 src/muz/{ => pdr}/pdr_sym_mux.cpp | 0 src/muz/{ => pdr}/pdr_sym_mux.h | 0 src/muz/{ => pdr}/pdr_util.cpp | 0 src/muz/{ => pdr}/pdr_util.h | 0 src/muz/{ => rel}/aig_exporter.cpp | 0 src/muz/{ => rel}/aig_exporter.h | 2 +- src/muz/{ => rel}/dl_compiler.cpp | 1 + src/muz/{ => rel}/dl_compiler.h | 0 src/muz/{ => rel}/dl_instruction.cpp | 11 +- src/muz/{ => rel}/dl_instruction.h | 9 +- src/muz/{ => rel}/rel_context.cpp | 64 +- src/muz/{ => rel}/rel_context.h | 53 +- src/muz/{ => tab}/tab_context.cpp | 0 src/muz/{ => tab}/tab_context.h | 2 +- .../{ => transforms}/dl_mk_array_blast.cpp | 0 src/muz/{ => transforms}/dl_mk_array_blast.h | 0 src/muz/{ => transforms}/dl_mk_backwards.cpp | 0 src/muz/{ => transforms}/dl_mk_backwards.h | 0 src/muz/{ => transforms}/dl_mk_bit_blast.cpp | 0 src/muz/{ => transforms}/dl_mk_bit_blast.h | 0 src/muz/{ => transforms}/dl_mk_coalesce.cpp | 0 src/muz/{ => transforms}/dl_mk_coalesce.h | 0 src/muz/{ => transforms}/dl_mk_coi_filter.cpp | 18 +- src/muz/{ => transforms}/dl_mk_coi_filter.h | 0 src/muz/{ => transforms}/dl_mk_different.h | 0 .../{ => transforms}/dl_mk_filter_rules.cpp | 0 src/muz/{ => transforms}/dl_mk_filter_rules.h | 0 .../dl_mk_interp_tail_simplifier.cpp | 0 .../dl_mk_interp_tail_simplifier.h | 0 src/muz/transforms/dl_mk_karr_invariants.cpp | 325 +++ src/muz/transforms/dl_mk_karr_invariants.h | 81 + .../{ => transforms}/dl_mk_loop_counter.cpp | 0 src/muz/{ => transforms}/dl_mk_loop_counter.h | 0 src/muz/{ => transforms}/dl_mk_magic_sets.cpp | 2 +- src/muz/{ => transforms}/dl_mk_magic_sets.h | 0 .../{ => transforms}/dl_mk_magic_symbolic.cpp | 0 .../{ => transforms}/dl_mk_magic_symbolic.h | 0 .../dl_mk_quantifier_abstraction.cpp | 0 .../dl_mk_quantifier_abstraction.h | 0 .../dl_mk_quantifier_instantiation.cpp | 0 .../dl_mk_quantifier_instantiation.h | 0 .../{ => transforms}/dl_mk_rule_inliner.cpp | 7 +- src/muz/{ => transforms}/dl_mk_rule_inliner.h | 6 +- src/muz/{ => transforms}/dl_mk_scale.cpp | 0 src/muz/{ => transforms}/dl_mk_scale.h | 0 src/muz/{ => transforms}/dl_mk_slice.cpp | 0 src/muz/{ => transforms}/dl_mk_slice.h | 0 .../dl_mk_subsumption_checker.cpp | 18 +- .../dl_mk_subsumption_checker.h | 0 .../dl_mk_unbound_compressor.cpp | 4 +- .../dl_mk_unbound_compressor.h | 2 +- src/muz/{ => transforms}/dl_mk_unfold.cpp | 0 src/muz/{ => transforms}/dl_mk_unfold.h | 0 src/muz/transforms/dl_transforms.cpp | 81 + src/muz/transforms/dl_transforms.h | 30 + src/shell/datalog_frontend.cpp | 9 +- src/test/datalog_parser.cpp | 8 +- src/test/dl_context.cpp | 8 +- src/test/dl_product_relation.cpp | 10 +- src/test/dl_query.cpp | 11 +- src/test/dl_relation.cpp | 8 +- src/test/dl_table.cpp | 5 +- 131 files changed, 994 insertions(+), 20069 deletions(-) rename src/muz/{ => bmc}/dl_bmc_engine.cpp (99%) rename src/muz/{ => bmc}/dl_bmc_engine.h (100%) rename src/muz/{ => clp}/clp_context.cpp (98%) rename src/muz/{ => clp}/clp_context.h (96%) delete mode 100644 src/muz/dl_base.cpp delete mode 100644 src/muz/dl_base.h delete mode 100644 src/muz/dl_bound_relation.cpp delete mode 100644 src/muz/dl_bound_relation.h delete mode 100644 src/muz/dl_check_table.cpp delete mode 100644 src/muz/dl_check_table.h delete mode 100644 src/muz/dl_cmds.h create mode 100644 src/muz/dl_engine_base.h delete mode 100644 src/muz/dl_external_relation.cpp delete mode 100644 src/muz/dl_external_relation.h delete mode 100644 src/muz/dl_finite_product_relation.cpp delete mode 100644 src/muz/dl_finite_product_relation.h delete mode 100644 src/muz/dl_interval_relation.cpp delete mode 100644 src/muz/dl_interval_relation.h delete mode 100644 src/muz/dl_mk_explanations.cpp delete mode 100644 src/muz/dl_mk_explanations.h delete mode 100644 src/muz/dl_mk_karr_invariants.cpp delete mode 100644 src/muz/dl_mk_karr_invariants.h delete mode 100644 src/muz/dl_mk_partial_equiv.cpp delete mode 100644 src/muz/dl_mk_partial_equiv.h delete mode 100644 src/muz/dl_mk_similarity_compressor.cpp delete mode 100644 src/muz/dl_mk_similarity_compressor.h delete mode 100644 src/muz/dl_mk_simple_joins.cpp delete mode 100644 src/muz/dl_mk_simple_joins.h delete mode 100644 src/muz/dl_product_relation.cpp delete mode 100644 src/muz/dl_product_relation.h delete mode 100644 src/muz/dl_relation_manager.cpp delete mode 100644 src/muz/dl_relation_manager.h delete mode 100644 src/muz/dl_sieve_relation.cpp delete mode 100644 src/muz/dl_sieve_relation.h delete mode 100644 src/muz/dl_sparse_table.cpp delete mode 100644 src/muz/dl_sparse_table.h delete mode 100644 src/muz/dl_table.cpp delete mode 100644 src/muz/dl_table.h delete mode 100644 src/muz/dl_table_plugin.h delete mode 100644 src/muz/dl_table_relation.cpp delete mode 100644 src/muz/dl_table_relation.h delete mode 100644 src/muz/dl_vector_relation.h rename src/muz/{ => fp}/dl_cmds.cpp (98%) create mode 100644 src/muz/fp/dl_register_engine.cpp create mode 100644 src/muz/fp/dl_register_engine.h rename src/muz/{ => fp}/horn_tactic.cpp (98%) rename src/muz/{ => fp}/horn_tactic.h (100%) rename src/muz/{ => pdr}/pdr_context.cpp (100%) rename src/muz/{ => pdr}/pdr_context.h (99%) rename src/muz/{ => pdr}/pdr_dl_interface.cpp (98%) rename src/muz/{ => pdr}/pdr_dl_interface.h (98%) rename src/muz/{ => pdr}/pdr_farkas_learner.cpp (100%) rename src/muz/{ => pdr}/pdr_farkas_learner.h (100%) rename src/muz/{ => pdr}/pdr_generalizers.cpp (99%) rename src/muz/{ => pdr}/pdr_generalizers.h (100%) rename src/muz/{ => pdr}/pdr_manager.cpp (100%) rename src/muz/{ => pdr}/pdr_manager.h (100%) rename src/muz/{ => pdr}/pdr_prop_solver.cpp (100%) rename src/muz/{ => pdr}/pdr_prop_solver.h (100%) rename src/muz/{ => pdr}/pdr_reachable_cache.cpp (100%) rename src/muz/{ => pdr}/pdr_reachable_cache.h (100%) rename src/muz/{ => pdr}/pdr_smt_context_manager.cpp (100%) rename src/muz/{ => pdr}/pdr_smt_context_manager.h (100%) rename src/muz/{ => pdr}/pdr_sym_mux.cpp (100%) rename src/muz/{ => pdr}/pdr_sym_mux.h (100%) rename src/muz/{ => pdr}/pdr_util.cpp (100%) rename src/muz/{ => pdr}/pdr_util.h (100%) rename src/muz/{ => rel}/aig_exporter.cpp (100%) rename src/muz/{ => rel}/aig_exporter.h (100%) rename src/muz/{ => rel}/dl_compiler.cpp (99%) rename src/muz/{ => rel}/dl_compiler.h (100%) rename src/muz/{ => rel}/dl_instruction.cpp (98%) rename src/muz/{ => rel}/dl_instruction.h (96%) rename src/muz/{ => rel}/rel_context.cpp (89%) rename src/muz/{ => rel}/rel_context.h (55%) rename src/muz/{ => tab}/tab_context.cpp (100%) rename src/muz/{ => tab}/tab_context.h (96%) rename src/muz/{ => transforms}/dl_mk_array_blast.cpp (100%) rename src/muz/{ => transforms}/dl_mk_array_blast.h (100%) rename src/muz/{ => transforms}/dl_mk_backwards.cpp (100%) rename src/muz/{ => transforms}/dl_mk_backwards.h (100%) rename src/muz/{ => transforms}/dl_mk_bit_blast.cpp (100%) rename src/muz/{ => transforms}/dl_mk_bit_blast.h (100%) rename src/muz/{ => transforms}/dl_mk_coalesce.cpp (100%) rename src/muz/{ => transforms}/dl_mk_coalesce.h (100%) rename src/muz/{ => transforms}/dl_mk_coi_filter.cpp (92%) rename src/muz/{ => transforms}/dl_mk_coi_filter.h (100%) rename src/muz/{ => transforms}/dl_mk_different.h (100%) rename src/muz/{ => transforms}/dl_mk_filter_rules.cpp (100%) rename src/muz/{ => transforms}/dl_mk_filter_rules.h (100%) rename src/muz/{ => transforms}/dl_mk_interp_tail_simplifier.cpp (100%) rename src/muz/{ => transforms}/dl_mk_interp_tail_simplifier.h (100%) create mode 100644 src/muz/transforms/dl_mk_karr_invariants.cpp create mode 100644 src/muz/transforms/dl_mk_karr_invariants.h rename src/muz/{ => transforms}/dl_mk_loop_counter.cpp (100%) rename src/muz/{ => transforms}/dl_mk_loop_counter.h (100%) rename src/muz/{ => transforms}/dl_mk_magic_sets.cpp (99%) rename src/muz/{ => transforms}/dl_mk_magic_sets.h (100%) rename src/muz/{ => transforms}/dl_mk_magic_symbolic.cpp (100%) rename src/muz/{ => transforms}/dl_mk_magic_symbolic.h (100%) rename src/muz/{ => transforms}/dl_mk_quantifier_abstraction.cpp (100%) rename src/muz/{ => transforms}/dl_mk_quantifier_abstraction.h (100%) rename src/muz/{ => transforms}/dl_mk_quantifier_instantiation.cpp (100%) rename src/muz/{ => transforms}/dl_mk_quantifier_instantiation.h (100%) rename src/muz/{ => transforms}/dl_mk_rule_inliner.cpp (99%) rename src/muz/{ => transforms}/dl_mk_rule_inliner.h (98%) rename src/muz/{ => transforms}/dl_mk_scale.cpp (100%) rename src/muz/{ => transforms}/dl_mk_scale.h (100%) rename src/muz/{ => transforms}/dl_mk_slice.cpp (100%) rename src/muz/{ => transforms}/dl_mk_slice.h (100%) rename src/muz/{ => transforms}/dl_mk_subsumption_checker.cpp (96%) rename src/muz/{ => transforms}/dl_mk_subsumption_checker.h (100%) rename src/muz/{ => transforms}/dl_mk_unbound_compressor.cpp (99%) rename src/muz/{ => transforms}/dl_mk_unbound_compressor.h (98%) rename src/muz/{ => transforms}/dl_mk_unfold.cpp (100%) rename src/muz/{ => transforms}/dl_mk_unfold.h (100%) create mode 100644 src/muz/transforms/dl_transforms.cpp create mode 100644 src/muz/transforms/dl_transforms.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 44ad9ccbc..a2b4ef9b2 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -54,10 +54,17 @@ def init_project_def(): add_lib('smt_tactic', ['smt'], 'smt/tactic') add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls') add_lib('qe', ['smt','sat'], 'qe') - add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic','qe']) - add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'muz','qe'], 'tactic/smtlogics') + add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe']) + add_lib('transforms', ['muz'], 'muz/transforms') + add_lib('rel', ['muz', 'transforms'], 'muz/rel') + add_lib('pdr', ['muz', 'transforms'], 'muz/pdr') + add_lib('clp', ['muz', 'transforms'], 'muz/clp') + add_lib('tab', ['muz', 'transforms'], 'muz/tab') + add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') + add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc'], 'muz/fp') + add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') - add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'muz', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') + add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'fp', 'muz', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('smtparser', ['portfolio'], 'parsers/smt') API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h'] add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure'], diff --git a/src/api/api_datalog.cpp b/src/api/api_datalog.cpp index 64b8b064e..ad6b5ad69 100644 --- a/src/api/api_datalog.cpp +++ b/src/api/api_datalog.cpp @@ -18,7 +18,6 @@ Revision History: #include"api_datalog.h" #include"api_context.h" #include"api_util.h" -#include"dl_context.h" #include"ast_pp.h" #include"api_ast_vector.h" #include"api_log_macros.h" @@ -30,8 +29,10 @@ Revision History: #include"cmd_context.h" #include"smt2parser.h" #include"dl_context.h" +#include"dl_register_engine.h" #include"dl_external_relation.h" #include"dl_decl_plugin.h" +#include"rel_context.h" namespace api { @@ -39,6 +40,7 @@ namespace api { void * m_state; reduce_app_callback_fptr m_reduce_app; reduce_assign_callback_fptr m_reduce_assign; + datalog::register_engine m_register_engine; datalog::context m_context; ast_ref_vector m_trail; public: @@ -46,7 +48,7 @@ namespace api { m_state(0), m_reduce_app(0), m_reduce_assign(0), - m_context(m, p), + m_context(m, m_register_engine, p), m_trail(m) {} virtual ~fixedpoint_context() {} @@ -59,7 +61,7 @@ namespace api { if (!m.has_plugin(name)) { m.register_plugin(name, alloc(datalog::dl_decl_plugin)); } - datalog::rel_context* rel = m_context.get_rel_context(); + datalog::rel_context_base* rel = m_context.get_rel_context(); if (rel) { datalog::relation_manager& r = rel->get_rmanager(); r.register_plugin(alloc(datalog::external_relation_plugin, *this, r)); diff --git a/src/muz/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp similarity index 99% rename from src/muz/dl_bmc_engine.cpp rename to src/muz/bmc/dl_bmc_engine.cpp index 65a60cdeb..72e40590e 100644 --- a/src/muz/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -23,13 +23,14 @@ Revision History: #include "dl_mk_slice.h" #include "smt_kernel.h" #include "datatype_decl_plugin.h" -#include "dl_mk_rule_inliner.h" #include "dl_decl_plugin.h" #include "bool_rewriter.h" #include "model_smt2_pp.h" #include "ast_smt_pp.h" #include "well_sorted.h" #include "rewriter_def.h" +#include "dl_transforms.h" +#include "dl_mk_rule_inliner.h" namespace datalog { @@ -1437,7 +1438,7 @@ namespace datalog { datalog::rule_set old_rules(m_ctx.get_rules()); rule_manager.mk_query(query, m_ctx.get_rules()); expr_ref bg_assertion = m_ctx.get_background_assertion(); - m_ctx.apply_default_transformation(); + apply_default_transformation(m_ctx); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); diff --git a/src/muz/dl_bmc_engine.h b/src/muz/bmc/dl_bmc_engine.h similarity index 100% rename from src/muz/dl_bmc_engine.h rename to src/muz/bmc/dl_bmc_engine.h diff --git a/src/muz/clp_context.cpp b/src/muz/clp/clp_context.cpp similarity index 98% rename from src/muz/clp_context.cpp rename to src/muz/clp/clp_context.cpp index 01299a2b7..5f3a09e2d 100644 --- a/src/muz/clp_context.cpp +++ b/src/muz/clp/clp_context.cpp @@ -22,6 +22,8 @@ Revision History: #include "unifier.h" #include "var_subst.h" #include "substitution.h" +#include "smt_kernel.h" +#include "dl_transforms.h" namespace datalog { @@ -67,7 +69,7 @@ namespace datalog { m_solver.reset(); m_goals.reset(); rm.mk_query(query, m_ctx.get_rules()); - m_ctx.apply_default_transformation(); + apply_default_transformation(m_ctx); func_decl* head_decl = m_ctx.get_rules().get_output_predicate(); rule_set& rules = m_ctx.get_rules(); rule_vector const& rv = rules.get_predicate_rules(head_decl); diff --git a/src/muz/clp_context.h b/src/muz/clp/clp_context.h similarity index 96% rename from src/muz/clp_context.h rename to src/muz/clp/clp_context.h index 5184b474d..6464ae634 100644 --- a/src/muz/clp_context.h +++ b/src/muz/clp/clp_context.h @@ -22,7 +22,7 @@ Revision History: #include "ast.h" #include "lbool.h" #include "statistics.h" -#include "dl_util.h" +#include "dl_engine_base.h" namespace datalog { class context; diff --git a/src/muz/dl_base.cpp b/src/muz/dl_base.cpp deleted file mode 100644 index 0f250d76c..000000000 --- a/src/muz/dl_base.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_base.cpp - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-14. - -Revision History: - ---*/ - - -#include"ast_pp.h" -#include"union_find.h" -#include"vector.h" -#include"dl_context.h" -#include"dl_base.h" -#include"bool_rewriter.h" -#include - - -namespace datalog { - - context & get_context_from_rel_manager(const relation_manager & rm) { - return rm.get_context(); - } - - ast_manager & get_ast_manager_from_rel_manager(const relation_manager & rm) { - return rm.get_context().get_manager(); - } - -#if DL_LEAK_HUNTING - void leak_guard_check(const symbol & s) { - } -#endif - - void relation_signature::output(ast_manager & m, std::ostream & out) const { - unsigned sz=size(); - out<<"("; - for(unsigned i=0; i reset_fn = - get_manager().mk_filter_interpreted_fn(static_cast(*this), bottom_ref); - if(!reset_fn) { - NOT_IMPLEMENTED_YET(); - } - (*reset_fn)(*this); - } - - - - void table_signature::from_join(const table_signature & s1, const table_signature & s2, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2, table_signature & result) { - result.reset(); - - unsigned s1sz=s1.size(); - unsigned s2sz=s2.size(); - unsigned s1first_func=s1sz-s1.functional_columns(); - unsigned s2first_func=s2sz-s2.functional_columns(); - for(unsigned i=0; i=col_cnt); - result.set_functional_columns(func_cnt-col_cnt); - } - } - - void table_signature::from_project_with_reduce(const table_signature & src, unsigned col_cnt, - const unsigned * removed_cols, table_signature & result) { - signature_base::from_project(src, col_cnt, removed_cols, result); - - unsigned remaining_fun = src.functional_columns(); - unsigned first_src_fun = src.first_functional(); - for(int i=col_cnt-1; i>=0; i--) { - if(removed_cols[i] remaining_in_equivalence_class; - remaining_in_equivalence_class.resize(join_sig_sz, 0); - bool merging_rows_can_happen = false; - - union_find_default_ctx uf_ctx; - union_find<> uf(uf_ctx); //the numbers in uf correspond to column indexes after the join - for(unsigned i=0; icols1[i]) ? cols1[i] : (first_func_ofs+cols1[i]-s1_first_func); - unsigned idx2 = (s2_first_func>cols2[i]) ? (second_ofs+cols2[i]) : (second_func_ofs+cols2[i]-s2_first_func); - uf.merge(idx1, idx2); - } - for(unsigned i=0; i=first_func_ofs) { - //removing functional columns won't make us merge rows - continue; - } - unsigned eq_class_idx = uf.find(rc); - if(remaining_in_equivalence_class[eq_class_idx]>1) { - remaining_in_equivalence_class[eq_class_idx]--; - } - else { - merging_rows_can_happen = true; - break; - } - } - - if(merging_rows_can_happen) { - //this one marks all columns as non-functional - from_project(aux, removed_col_cnt, removed_cols, result); - SASSERT(result.functional_columns()==0); - } - else { - //this one preserves columns to be functional - from_project_with_reduce(aux, removed_col_cnt, removed_cols, result); - } - } - - - - - // ----------------------------------- - // - // table_base - // - // ----------------------------------- - - //here we give generic implementation of table operations using iterators - - bool table_base::empty() const { - return begin()==end(); - } - - void table_base::remove_facts(unsigned fact_cnt, const table_fact * facts) { - for(unsigned i=0; i to_remove; - table_base::iterator it = begin(); - table_base::iterator iend = end(); - table_fact row; - for(; it!=iend; ++it) { - it->get_fact(row); - to_remove.push_back(row); - } - remove_facts(to_remove.size(), to_remove.c_ptr()); - } - - bool table_base::contains_fact(const table_fact & f) const { - iterator it = begin(); - iterator iend = end(); - - table_fact row; - - for(; it!=iend; ++it) { - it->get_fact(row); - if(vectors_equal(row, f)) { - return true; - } - } - return false; - } - - bool table_base::fetch_fact(table_fact & f) const { - if(get_signature().functional_columns()==0) { - return contains_fact(f); - } - else { - unsigned sig_sz = get_signature().size(); - unsigned non_func_cnt = sig_sz-get_signature().functional_columns(); - table_base::iterator it = begin(); - table_base::iterator iend = end(); - table_fact row; - for(; it!=iend; ++it) { - it->get_fact(row); - bool differs = false; - for(unsigned i=0; iget_fact(row); - res->add_new_fact(row); - } - return res; - } - - /** - \brief Default method for complementation. - - It assumes that the compiler creates only tables with - at most one column (0 or 1 columns). - Complementation of tables with more than one columns - is transformed into a cross product of complements and/or - difference. - - */ - table_base * table_base::complement(func_decl* p, const table_element * func_columns) const { - const table_signature & sig = get_signature(); - SASSERT(sig.functional_columns()==0 || func_columns!=0); - SASSERT(sig.first_functional() <= 1); - - table_base * res = get_plugin().mk_empty(sig); - - table_fact fact; - fact.resize(sig.first_functional()); - fact.append(sig.functional_columns(), func_columns); - - if (sig.first_functional() == 0) { - if (empty()) { - res->add_fact(fact); - } - return res; - } - - VERIFY(sig.first_functional() == 1); - - uint64 upper_bound = get_signature()[0]; - bool empty_table = empty(); - - if (upper_bound > (1 << 18)) { - std::ostringstream buffer; - buffer << "creating large table of size " << upper_bound; - if (p) buffer << " for relation " << p->get_name(); - warning_msg(buffer.str().c_str()); - } - - for(table_element i = 0; i < upper_bound; i++) { - fact[0] = i; - if(empty_table || !contains_fact(fact)) { - res->add_fact(fact); - } - } - return res; - } - - void table_base::display(std::ostream & out) const { - out << "table with signature "; - print_container(get_signature(), out); - out << ":\n"; - - iterator it = begin(); - iterator iend = end(); - for(; it!=iend; ++it) { - const row_interface & r = *it; - r.display(out); - } - - out << "\n"; - } - - - class table_base::row_interface::fact_row_iterator : public table_base::row_iterator_core { - const row_interface & m_parent; - unsigned m_index; - protected: - virtual bool is_finished() const { return m_index==m_parent.size(); } - public: - fact_row_iterator(const row_interface & row, bool finished) - : m_parent(row), m_index(finished ? row.size() : 0) {} - - virtual table_element operator*() { - SASSERT(!is_finished()); - return m_parent[m_index]; - } - - virtual void operator++() { - m_index++; - SASSERT(m_index<=m_parent.size()); - } - }; - - table_base::row_iterator table_base::row_interface::begin() const { - return row_iterator(alloc(fact_row_iterator, *this, false)); - } - table_base::row_iterator table_base::row_interface::end() const { - return row_iterator(alloc(fact_row_iterator, *this, true)); - } - - void table_base::row_interface::get_fact(table_fact & result) const { - result.reset(); - unsigned n=size(); - for(unsigned i=0; i - -Author: - - Krystof Hoder (t-khoder) 2010-09-23. - -Revision History: - ---*/ -#ifndef _DL_BASE_H_ -#define _DL_BASE_H_ - -#define DL_LEAK_HUNTING 0 - -#include - -#include"ast.h" -#include"map.h" -#include"vector.h" -#include"ref.h" -#include"dl_util.h" - -namespace datalog { - - class context; - class relation_manager; - - ast_manager & get_ast_manager_from_rel_manager(const relation_manager & rm); - context & get_context_from_rel_manager(const relation_manager & rm); - - typedef func_decl_set decl_set; - -#if DL_LEAK_HUNTING - void leak_guard_check(const symbol & s); -#endif - - - /** - Termplate class containing common infrastructure for relations and tables - */ - template - struct tr_infrastructure { - - typedef typename Traits::plugin plugin; - typedef typename Traits::base_object base_object; - typedef typename Traits::element element; - typedef typename Traits::fact fact; - typedef typename Traits::sort sort; - typedef typename Traits::signature_base_base signature_base_base; //this must be a vector-like type - typedef typename Traits::signature signature; //this must be a vector-like type - - /** - The client submits an initial class to be used as a base for signature. Then we excend it by - the common signature methods into a signature_base class which then the client inherits from - to obtain the actual signature class. - */ - class signature_base : public signature_base_base { - public: - bool operator==(const signature & o) const { - unsigned n=signature_base_base::size(); - if(n!=o.size()) { - return false; - } - return memcmp(this->c_ptr(), o.c_ptr(), n*sizeof(sort))==0; - /*for(unsigned i=0; i=2); - result=src; - - permutate_by_cycle(result, cycle_len, permutation_cycle); - } - - /** - \brief Into \c result assign signature \c src with reordered columns. - */ - static void from_permutation_rename(const signature & src, - const unsigned * permutation, signature & result) { - result.reset(); - unsigned n = src.size(); - for(unsigned i=0; i(0)); - } - }; - - /** - \brief Mutator for relations that propagate constraints as a consequence of - combination. - - - supports_attachment - is used to query the mutator if it allows communicating - constraints to relations of the kind of the relation. - - - attach - is used to associate downstream clients. - It assumes that the relation kind is supported (supports_kind returns true) - */ - class mutator_fn : public base_fn { - public: - virtual void operator()(base_object & t) = 0; - - virtual bool supports_attachment(base_object& other) { return false; } - - virtual void attach(base_object& other) { UNREACHABLE(); } - }; - - class intersection_filter_fn : public base_fn { - public: - virtual void operator()(base_object & t, const base_object & intersected_obj) = 0; - }; - - class default_join_project_fn; - - /** - \brief Plugin class providing factory functions for a table and operations on it. - - The functor factory functions (mk_*_fn) may return 0. It means that the plugin - is unable to perform the operation on relations/tables of the particular kind. - */ - class plugin_object { - friend class relation_manager; - friend class check_table_plugin; - - family_id m_kind; - symbol m_name; - relation_manager & m_manager; - protected: - plugin_object(symbol const& name, relation_manager & manager) - : m_kind(null_family_id), m_name(name), m_manager(manager) {} - - /** - \brief Check \c r is of the same kind as the plugin. - */ - bool check_kind(base_object const& r) const { return &r.get_plugin()==this; } - public: - virtual ~plugin_object() {} - - virtual void initialize(family_id fid) { m_kind = fid; } - - family_id get_kind() const { return m_kind; } - - symbol const& get_name() const { return m_name; } - - virtual void set_cancel(bool f) {} - - relation_manager & get_manager() const { return m_manager; } - ast_manager& get_ast_manager() const { return datalog::get_ast_manager_from_rel_manager(m_manager); } - context& get_context() const { return datalog::get_context_from_rel_manager(m_manager); } - - virtual bool can_handle_signature(const signature & s) = 0; - - virtual bool can_handle_signature(const signature & s, family_id kind) { - return can_handle_signature(s); - } - - /** - \brief Create empty table/relation with given signature and return pointer to it. - - Precondition: can_handle_signature(s)==true - */ - virtual base_object * mk_empty(const signature & s) = 0; - - /** - \brief Create empty table/relation with signature \c s and kind \c kind. - - Precondition: &orig.get_plugin()==this - */ - virtual base_object * mk_empty(const signature & s, family_id kind) { - SASSERT(kind==get_kind()); //if plugin uses multiple kinds, this function needs to be overriden - return mk_empty(s); - } - - /** - \brief Create empty table/relation of the same specification as \c orig and return pointer to it. - - Precondition: &orig.get_plugin()==this - */ - virtual base_object * mk_empty(const base_object & orig) { - return mk_empty(orig.get_signature(), orig.get_kind()); - } - - /** - \brief Create full table/relation with given signature and return pointer to it. - - Precondition: can_handle_signature(s)==true - */ - virtual base_object * mk_full(func_decl* p, const signature & s) { - base_object * aux = mk_empty(s); - base_object * res = aux->complement(p); - aux->deallocate(); - return res; - } - - virtual base_object * mk_full(func_decl* p, const signature & s, family_id kind) { - if (kind == get_kind() || kind == null_family_id) { - return mk_full(p, s); - } - base_object * aux = mk_empty(s, kind); - base_object * res = aux->complement(p); - aux->deallocate(); - return res; - } - - protected: - //see \c relation_manager for documentation of the operations - - virtual join_fn * mk_join_fn(const base_object & t1, const base_object & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { return 0; } - - virtual transformer_fn * mk_project_fn(const base_object & t, unsigned col_cnt, - const unsigned * removed_cols) { return 0; } - - virtual join_fn * mk_join_project_fn(const base_object & t1, const base_object & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols) { return 0; } - - virtual transformer_fn * mk_rename_fn(const base_object & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle) { return 0; } - - virtual transformer_fn * mk_permutation_rename_fn(const base_object & t, - const unsigned * permutation) { return 0; } - - public: - virtual union_fn * mk_union_fn(const base_object & tgt, const base_object & src, - const base_object * delta) { return 0; } - protected: - - virtual union_fn * mk_widen_fn(const base_object & tgt, const base_object & src, - const base_object * delta) { return 0; } - - virtual mutator_fn * mk_filter_identical_fn(const base_object & t, unsigned col_cnt, - const unsigned * identical_cols) { return 0; } - - virtual mutator_fn * mk_filter_equal_fn(const base_object & t, const element & value, - unsigned col) { return 0; } - - virtual mutator_fn * mk_filter_interpreted_fn(const base_object & t, app * condition) - { return 0; } - - virtual transformer_fn * mk_filter_interpreted_and_project_fn(const base_object & t, - app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) - { return 0; } - - virtual transformer_fn * mk_select_equal_and_project_fn(const base_object & t, - const element & value, unsigned col) { return 0; } - - virtual intersection_filter_fn * mk_filter_by_intersection_fn(const base_object & t, - const base_object & src, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * src_cols) - { return 0; } - - virtual intersection_filter_fn * mk_filter_by_negation_fn(const base_object & t, - const base_object & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols) - { return 0; } - }; - - class base_ancestor { - plugin & m_plugin; - signature m_signature; - family_id m_kind; -#if DL_LEAK_HUNTING - sort_ref m_leak_guard; -#endif - protected: - base_ancestor(plugin & p, const signature & s) - : m_plugin(p), m_signature(s), m_kind(p.get_kind()) -#if DL_LEAK_HUNTING - , m_leak_guard(p.get_ast_manager().mk_fresh_sort(p.get_name().bare_str()), p.get_ast_manager()) -#endif - { -#if DL_LEAK_HUNTING - leak_guard_check(m_leak_guard->get_name()); -#endif - } - -#if DL_LEAK_HUNTING - base_ancestor(const base_ancestor & o) - : m_plugin(o.m_plugin), - m_signature(o.m_signature), - m_kind(o.m_kind), - m_leak_guard(m_plugin.get_ast_manager().mk_fresh_sort(m_plugin.get_name().bare_str()), - m_plugin.get_ast_manager()) { - leak_guard_check(m_leak_guard->get_name()); - } -#endif - - virtual ~base_ancestor() {} - - void set_kind(family_id kind) { SASSERT(kind>=0); m_kind = kind; } - - /** - Since the destructor is protected, we cannot use the \c dealloc macro. - */ - void destroy() { - SASSERT(this); - this->~base_ancestor(); -#if _DEBUG - memory::deallocate(__FILE__, __LINE__, this); -#else - memory::deallocate(this); -#endif - } - public: - /** - Deallocate the current object. - - Pointers and references to the current object become invalid after a call to this function. - */ - virtual void deallocate() { - destroy(); - } - /** - It must hold that operations created for particular table/relation are able to operate on - tables/relations of the same signature and kind. In most cases it is sufficient to use the kind - of the plugin object. - - However, it there is some parameter that is not reflected in the signature, the plugin may need to - allocate different kind numbers to the tables is creates. - */ - family_id get_kind() const { return m_kind; } - const signature & get_signature() const { return m_signature; } - plugin & get_plugin() const { return m_plugin; } - relation_manager & get_manager() const { return get_plugin().get_manager(); } - - virtual bool empty() const = 0; - virtual void add_fact(const fact & f) = 0; - /** - \brief Like \c add_fact, only here the caller guarantees that the fact is not present in - the table yet. - */ - virtual void add_new_fact(const fact & f) { - add_fact(f); - } - virtual bool contains_fact(const fact & f) const = 0; - - virtual void reset() = 0; - - /** - \brief Return table/relation that contains the same data as the current one. - */ - virtual base_object * clone() const = 0; - - virtual bool can_swap(const base_object & o) const { return false; } - - virtual void swap(base_object & o) { - std::swap(m_kind, o.m_kind); -#if DL_LEAK_HUNTING - m_leak_guard = get_plugin().get_ast_manager().mk_fresh_sort(get_plugin().get_name().bare_str()); - o.m_leak_guard = get_plugin().get_ast_manager().mk_fresh_sort(get_plugin().get_name().bare_str()); - leak_guard_check(m_leak_guard->get_name()); - leak_guard_check(o.m_leak_guard->get_name()); -#endif - } - - virtual unsigned get_size_estimate_rows() const { return UINT_MAX; } - virtual unsigned get_size_estimate_bytes() const { return UINT_MAX; } - virtual bool knows_exact_size() const { return false; } - - virtual void display(std::ostream & out) const = 0; - }; - - - class convenient_join_fn : public join_fn { - signature m_result_sig; - protected: - unsigned_vector m_cols1; - unsigned_vector m_cols2; - - convenient_join_fn(const signature & o1_sig, const signature & o2_sig, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2) - : m_cols1(col_cnt, cols1), - m_cols2(col_cnt, cols2) { - signature::from_join(o1_sig, o2_sig, col_cnt, cols1, cols2, m_result_sig); - } - - const signature & get_result_signature() const { return m_result_sig; } - }; - - class convenient_join_project_fn : public join_fn { - signature m_result_sig; - protected: - unsigned_vector m_cols1; - unsigned_vector m_cols2; - //it is non-const because it needs to be modified in sparse_table version of the join_project operator - unsigned_vector m_removed_cols; - - convenient_join_project_fn(const signature & o1_sig, const signature & o2_sig, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols) - : m_cols1(joined_col_cnt, cols1), - m_cols2(joined_col_cnt, cols2), - m_removed_cols(removed_col_cnt, removed_cols) { - - signature::from_join_project(o1_sig, o2_sig, joined_col_cnt, cols1, cols2, - removed_col_cnt, removed_cols, m_result_sig); - } - - const signature & get_result_signature() const { return m_result_sig; } - }; - - class convenient_transformer_fn : public transformer_fn { - signature m_result_sig; - protected: - signature & get_result_signature() { return m_result_sig; } - const signature & get_result_signature() const { return m_result_sig; } - }; - - class convenient_project_fn : public convenient_transformer_fn { - protected: - unsigned_vector m_removed_cols; - - convenient_project_fn(const signature & orig_sig, unsigned col_cnt, const unsigned * removed_cols) - : m_removed_cols(col_cnt, removed_cols) { - signature::from_project(orig_sig, col_cnt, removed_cols, - convenient_transformer_fn::get_result_signature()); - } - }; - - class convenient_rename_fn : public convenient_transformer_fn { - protected: - const unsigned_vector m_cycle; - - convenient_rename_fn(const signature & orig_sig, unsigned cycle_len, - const unsigned * permutation_cycle) - : m_cycle(cycle_len, permutation_cycle) { - signature::from_rename(orig_sig, cycle_len, permutation_cycle, - convenient_transformer_fn::get_result_signature()); - } - }; - - class convenient_negation_filter_fn : public intersection_filter_fn { - protected: - unsigned m_joined_col_cnt; - const unsigned_vector m_cols1; - const unsigned_vector m_cols2; - bool m_all_neg_bound; //all columns are bound at least once - bool m_overlap; //one column in negated table is bound multiple times - svector m_bound; - - convenient_negation_filter_fn(const base_object & tgt, const base_object & neg_t, - unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) - : m_joined_col_cnt(joined_col_cnt), m_cols1(joined_col_cnt, t_cols), - m_cols2(joined_col_cnt, negated_cols) { - unsigned neg_sig_size = neg_t.get_signature().size(); - m_overlap = false; - m_bound.resize(neg_sig_size, false); - for(unsigned i=0; i - void make_neg_bindings(T & tgt_neg, const U & src) const { - SASSERT(m_all_neg_bound); - SASSERT(!m_overlap); - for(unsigned i=0; i - bool bindings_match(const T & tgt_neg, const U & src) const { - for(unsigned i=0; i renamer_vector; - - unsigned_vector m_permutation; //this is valid only before m_renamers_initialized becomes true - bool m_renamers_initialized; - renamer_vector m_renamers; - public: - default_permutation_rename_fn(const base_object & o, const unsigned * permutation) - : m_permutation(o.get_signature().size(), permutation), - m_renamers_initialized(false) {} - - ~default_permutation_rename_fn() { - dealloc_ptr_vector_content(m_renamers); - } - - base_object * operator()(const base_object & o) { - const base_object * res = &o; - scoped_rel res_scoped; - if(m_renamers_initialized) { - typename renamer_vector::iterator rit = m_renamers.begin(); - typename renamer_vector::iterator rend = m_renamers.end(); - for(; rit!=rend; ++rit) { - res_scoped = (**rit)(*res); - res = res_scoped.get(); - } - } - else { - SASSERT(m_renamers.empty()); - unsigned_vector cycle; - while(try_remove_cycle_from_permutation(m_permutation, cycle)) { - transformer_fn * renamer = o.get_manager().mk_rename_fn(*res, cycle); - SASSERT(renamer); - m_renamers.push_back(renamer); - cycle.reset(); - - res_scoped = (*renamer)(*res); - res = res_scoped.get(); - } - m_renamers_initialized = true; - } - if(res_scoped) { - SASSERT(res==res_scoped.get()); - //we don't want to delete the last one since we'll be returning it - return res_scoped.release(); - } - else { - SASSERT(res==&o); - return res->clone(); - } - } - - }; - - - }; - - - // ----------------------------------- - // - // relation_base - // - // ----------------------------------- - - class relation_signature; - class relation_plugin; - class relation_base; - - typedef sort * relation_sort; - typedef ptr_vector relation_signature_base0; - typedef ptr_hash relation_sort_hash; - - typedef app * relation_element; - typedef app_ref relation_element_ref; - - class relation_fact : public app_ref_vector { - public: - class el_proxy { - friend class relation_fact; - - relation_fact & m_parent; - unsigned m_idx; - - el_proxy(relation_fact & parent, unsigned idx) : m_parent(parent), m_idx(idx) {} - public: - operator relation_element() const { - return m_parent.get(m_idx); - } - relation_element operator->() const { - return m_parent.get(m_idx); - } - relation_element operator=(const relation_element & val) const { - m_parent.set(m_idx, val); - return m_parent.get(m_idx); - } - relation_element operator=(const el_proxy & val) { - m_parent.set(m_idx, val); - return m_parent.get(m_idx); - } - }; - - typedef const relation_element * iterator; - - relation_fact(ast_manager & m) : app_ref_vector(m) {} - relation_fact(ast_manager & m, unsigned sz) : app_ref_vector(m) { resize(sz); } - relation_fact(context & ctx); - - iterator begin() const { return c_ptr(); } - iterator end() const { return c_ptr()+size(); } - - relation_element operator[](unsigned i) const { return get(i); } - el_proxy operator[](unsigned i) { return el_proxy(*this, i); } - }; - - struct relation_traits { - typedef relation_plugin plugin; - typedef relation_base base_object; - typedef relation_element element; - typedef relation_fact fact; - typedef relation_sort sort; - typedef relation_signature_base0 signature_base_base; - typedef relation_signature signature; - }; - - typedef tr_infrastructure relation_infrastructure; - - typedef relation_infrastructure::base_fn base_relation_fn; - typedef relation_infrastructure::join_fn relation_join_fn; - typedef relation_infrastructure::transformer_fn relation_transformer_fn; - typedef relation_infrastructure::union_fn relation_union_fn; - typedef relation_infrastructure::mutator_fn relation_mutator_fn; - typedef relation_infrastructure::intersection_filter_fn relation_intersection_filter_fn; - - typedef relation_infrastructure::convenient_join_fn convenient_relation_join_fn; - typedef relation_infrastructure::convenient_join_project_fn convenient_relation_join_project_fn; - typedef relation_infrastructure::convenient_transformer_fn convenient_relation_transformer_fn; - typedef relation_infrastructure::convenient_project_fn convenient_relation_project_fn; - typedef relation_infrastructure::convenient_rename_fn convenient_relation_rename_fn; - typedef relation_infrastructure::convenient_negation_filter_fn convenient_relation_negation_filter_fn; - typedef relation_infrastructure::identity_transformer_fn identity_relation_transformer_fn; - typedef relation_infrastructure::identity_mutator_fn identity_relation_mutator_fn; - typedef relation_infrastructure::identity_intersection_filter_fn identity_relation_intersection_filter_fn; - typedef relation_infrastructure::default_permutation_rename_fn default_relation_permutation_rename_fn; - - class relation_signature : public relation_infrastructure::signature_base { - public: - bool operator!=(const relation_signature & o) const { - return !(*this==o); - } - - void output(ast_manager & m, std::ostream & out) const; - - struct hash { - unsigned operator()(relation_signature const& s) const { - return obj_vector_hash(s); - } - }; - - struct eq { - bool operator()(relation_signature const& s1, relation_signature const& s2) const { - return s1 == s2; - } - }; - }; - - class relation_plugin : public relation_infrastructure::plugin_object { - protected: - enum special_relation_type { - ST_ORDINARY, - ST_TABLE_RELATION, - ST_FINITE_PRODUCT_RELATION, - ST_PRODUCT_RELATION, - ST_SIEVE_RELATION - }; - private: - special_relation_type m_special_type; - protected: - relation_plugin(symbol const& name, relation_manager & manager, - special_relation_type special_type = ST_ORDINARY) - : plugin_object(name, manager), - m_special_type(special_type) {} - public: - bool from_table() const { return m_special_type==ST_TABLE_RELATION; } - bool is_finite_product_relation() const { return m_special_type==ST_FINITE_PRODUCT_RELATION; } - bool is_product_relation() const { return m_special_type==ST_PRODUCT_RELATION; } - bool is_sieve_relation() const { return m_special_type==ST_SIEVE_RELATION; } - - /** - \brief If true, the relation can contain only one or zero elements. - - Having this zero allows the finite_product_relation to perform some operations in a simpler way. - (KH: I started implementing finite_product_relation::inner_singleton_union_fn that takes advantage of - it, but it's not finished.) - */ - virtual bool is_singleton_relation() const { return false; } - }; - - class relation_base : public relation_infrastructure::base_ancestor { - protected: - relation_base(relation_plugin & plugin, const relation_signature & s) - : base_ancestor(plugin, s) {} - virtual ~relation_base() {} - public: - virtual relation_base * complement(func_decl* p) const = 0; - - virtual void reset(); - - virtual void display_tuples(func_decl & pred, std::ostream & out) const { - out << "Tuples in " << pred.get_name() << ": \n"; - display(out); - } - - virtual void to_formula(expr_ref& fml) const = 0; - - bool from_table() const { return get_plugin().from_table(); } - virtual bool is_precise() const { return true; } - }; - - typedef ptr_vector relation_vector; - - // ----------------------------------- - // - // table_base - // - // ----------------------------------- - - class table_signature; - class table_plugin; - class table_base; - - typedef uint64 table_sort; - typedef svector table_signature_base0; - typedef uint64_hash table_sort_hash; - - typedef uint64 table_element; - typedef svector table_fact; - typedef uint64_hash table_element_hash; - - struct table_traits { - typedef table_plugin plugin; - typedef table_base base_object; - typedef table_element element; - typedef table_fact fact; - typedef table_sort sort; - typedef table_signature_base0 signature_base_base; - typedef table_signature signature; - }; - - typedef tr_infrastructure table_infrastructure; - - typedef table_infrastructure::base_fn base_table_fn; - typedef table_infrastructure::join_fn table_join_fn; - typedef table_infrastructure::transformer_fn table_transformer_fn; - typedef table_infrastructure::union_fn table_union_fn; - typedef table_infrastructure::mutator_fn table_mutator_fn; - typedef table_infrastructure::intersection_filter_fn table_intersection_filter_fn; - - typedef table_infrastructure::convenient_join_fn convenient_table_join_fn; - typedef table_infrastructure::convenient_join_project_fn convenient_table_join_project_fn; - typedef table_infrastructure::convenient_transformer_fn convenient_table_transformer_fn; - typedef table_infrastructure::convenient_project_fn convenient_table_project_fn; - typedef table_infrastructure::convenient_rename_fn convenient_table_rename_fn; - typedef table_infrastructure::convenient_negation_filter_fn convenient_table_negation_filter_fn; - typedef table_infrastructure::identity_transformer_fn identity_table_transformer_fn; - typedef table_infrastructure::identity_mutator_fn identity_table_mutator_fn; - typedef table_infrastructure::identity_intersection_filter_fn identity_table_intersection_filter_fn; - typedef table_infrastructure::default_permutation_rename_fn default_table_permutation_rename_fn; - - class table_row_mutator_fn { - public: - /** - \brief The function is called for a particular table row. The \c func_columns contains - a pointer to an array of functional column values that can be modified. If the function - returns true, the modification will appear in the table; otherwise the row will be deleted. - - It is possible that one call to the function stands for multiple table rows that share - the same functional column values. - */ - virtual bool operator()(table_element * func_columns) = 0; - }; - - class table_row_pair_reduce_fn { - public: - /** - \brief The function is called for pair of table rows that became duplicit due to projection. - The values that are in the first array after return from the function will be used for the - resulting row. - - It is assumed that the function is idempotent: when the two functional sub-tuples are equal, - the result is assumed to be equal to them as well, so the function may not be evaluated for them. - */ - virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) = 0; - }; - - - class table_signature : public table_infrastructure::signature_base { - public: - struct hash { - unsigned operator()(table_signature const& s) const { - return svector_hash()(s); - } - }; - - struct eq { - bool operator()(table_signature const& s1, table_signature const& s2) const { - return s1 == s2; - } - }; - private: - unsigned m_functional_columns; - public: - table_signature() : m_functional_columns(0) {} - - void swap(table_signature & s) { - signature_base::swap(s); - std::swap(m_functional_columns, s.m_functional_columns); - } - - /** - \brief The returned value is the number of last columns that are functional. - - The uniqueness is enforced on non-functional columns. When projection causes two - facts to have equal non-functional parts, it is not defined which one of them is retained. - */ - unsigned functional_columns() const { return m_functional_columns; } - void set_functional_columns(unsigned val) { SASSERT(size()>=val); m_functional_columns = val; } - - /** - \brief Return index of the first functional column, or the size of the signature if there - are no functional columns. - */ - unsigned first_functional() const { return size()-m_functional_columns; } - - bool operator==(const table_signature & o) const { - return signature_base::operator==(o) && m_functional_columns==o.m_functional_columns; - } - bool operator!=(const table_signature & o) const { - return !(*this==o); - } - - /** - \brief return true iof the two signatures are equal when we ignore which columns are functional. - */ - bool equal_up_to_fn_mark(const table_signature & o) const { - return signature_base::operator==(o); - } - - - /** - \brief Into \c result assign signature of result of join of relations with signatures \c s1 - and \c s2. The result is - - (non-functional of s1)(non-functional of s2)(functional of s1)(functional of s2) - */ - static void from_join(const table_signature & s1, const table_signature & s2, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2, table_signature & result); - - static void from_join_project(const table_signature & s1, const table_signature & s2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols, table_signature & result); - - - /** - \brief Into \c result assign signature projected from \c src. - - The array of removed columns must be sorted in ascending order. - - If we remove at least one non-functional column, all the columns in the result are non-functional. - */ - static void from_project(const table_signature & src, unsigned col_cnt, - const unsigned * removed_cols, table_signature & result); - - static void from_project_with_reduce(const table_signature & src, unsigned col_cnt, - const unsigned * removed_cols, table_signature & result); - - /** - \brief Into \c result assign signature \c src with reordered columns. - - Permutations between functional and nonfunctional columns are not allowed. - */ - static void from_rename(const table_signature & src, unsigned cycle_len, - const unsigned * permutation_cycle, table_signature & result) { - signature_base::from_rename(src, cycle_len, permutation_cycle, result); - result.set_functional_columns(src.functional_columns()); -#if Z3DEBUG - unsigned first_src_fun = src.size()-src.functional_columns(); - bool in_func = permutation_cycle[0]>=first_src_fun; - for(unsigned i=1;i=first_src_fun)); - } -#endif - } - - /** - \brief Into \c result assign signature \c src with reordered columns. - - Permutations mixing functional and nonfunctional columns are not allowed. - */ - static void from_permutation_rename(const table_signature & src, - const unsigned * permutation, table_signature & result) { - signature_base::from_permutation_rename(src, permutation, result); - result.set_functional_columns(src.functional_columns()); -#if Z3DEBUG - unsigned sz = src.size(); - unsigned first_src_fun = sz-src.functional_columns(); - for(unsigned i=first_src_fun;i=first_src_fun); - } -#endif - } - - }; - - class table_plugin : public table_infrastructure::plugin_object { - friend class relation_manager; - protected: - table_plugin(symbol const& n, relation_manager & manager) : plugin_object(n, manager) {} - public: - - virtual bool can_handle_signature(const table_signature & s) { return s.functional_columns()==0; } - - protected: - /** - If the returned value is non-zero, the returned object must take ownership of \c mapper. - Otherwise \c mapper must remain unmodified. - */ - virtual table_mutator_fn * mk_map_fn(const table_base & t, table_row_mutator_fn * mapper) { return 0; } - - /** - If the returned value is non-zero, the returned object must take ownership of \c reducer. - Otherwise \c reducer must remain unmodified. - */ - virtual table_transformer_fn * mk_project_with_reduce_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols, table_row_pair_reduce_fn * reducer) { return 0; } - - }; - - class table_base : public table_infrastructure::base_ancestor { - protected: - table_base(table_plugin & plugin, const table_signature & s) - : base_ancestor(plugin, s) {} - virtual ~table_base() {} - public: - virtual table_base * clone() const; - virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const; - virtual bool empty() const; - - /** - \brief Return true if table contains fact that corresponds to \c f in all non-functional - columns. - */ - virtual bool contains_fact(const table_fact & f) const; - - /** - \brief If \c f (i.e. its non-functional part) is not present in the table, - add it and return true. Otherwise update \c f, so that the values of functional - columns correspond to the ones present in the table. - */ - virtual bool suggest_fact(table_fact & f); - - /** - \brief If \c f (i.e. its non-functional part) is not present in the table, - return false. Otherwise update \c f, so that the values of functional - columns correspond to the ones present in the table and return true. - */ - virtual bool fetch_fact(table_fact & f) const; - - /** - \brief Ensure fact \c f is present in the table (including the values of its functional columns). - */ - virtual void ensure_fact(const table_fact & f); - - virtual void remove_fact(const table_fact & fact) { - SASSERT(fact.size() == get_signature().size()); - remove_fact(fact.c_ptr()); } - - virtual void remove_fact(table_element const* fact) = 0; - virtual void remove_facts(unsigned fact_cnt, const table_fact * facts); - virtual void remove_facts(unsigned fact_cnt, const table_element * facts); - virtual void reset(); - - class row_interface; - - virtual void display(std::ostream & out) const; - - /** - \brief Convert table to a formula that encodes the table. - The columns correspond to bound variables indexed as - 0, .., sig.size()-1 - */ - virtual void to_formula(relation_signature const& sig, expr_ref& fml) const; - - protected: - - - class iterator_core { - unsigned m_ref_cnt; - public: - iterator_core() : m_ref_cnt(0) {} - virtual ~iterator_core() {} - - void inc_ref() { m_ref_cnt++; } - void dec_ref() { - SASSERT(m_ref_cnt>0); - m_ref_cnt--; - if(m_ref_cnt==0) { - dealloc(this); - } - } - - virtual bool is_finished() const = 0; - - virtual row_interface & operator*() = 0; - virtual void operator++() = 0; - virtual bool operator==(const iterator_core & it) { - //we worry about the equality operator only because of checking - //the equality with the end() iterator - if(is_finished() && it.is_finished()) { - return true; - } - return false; - } - private: - //private and undefined copy constructor and assignment operator - iterator_core(const iterator_core &); - iterator_core & operator=(const iterator_core &); - }; - - struct row_iterator_core { - unsigned m_ref_cnt; - public: - row_iterator_core() : m_ref_cnt(0) {} - virtual ~row_iterator_core() {} - - void inc_ref() { m_ref_cnt++; } - void dec_ref() { - SASSERT(m_ref_cnt>0); - m_ref_cnt--; - if(m_ref_cnt==0) { - dealloc(this); - } - } - - virtual bool is_finished() const = 0; - - virtual table_element operator*() = 0; - virtual void operator++() = 0; - virtual bool operator==(const row_iterator_core & it) { - //we worry about the equality operator only because of checking - //the equality with the end() iterator - if(is_finished() && it.is_finished()) { - return true; - } - return false; - } - private: - //private and undefined copy constructor and assignment operator - row_iterator_core(const row_iterator_core &); - row_iterator_core & operator=(const row_iterator_core &); - }; - - public: - class iterator { - friend class table_base; - - ref m_core; - - iterator(iterator_core * core) : m_core(core) {} - public: - /** - \brief Return reference to a row_interface object for the current row. - - The reference is valid only until the \c operator++() is called or - until the iterator is invalidated. - */ - row_interface & operator*() - { return *(*m_core); } - row_interface * operator->() - { return &(*(*m_core)); } - iterator & operator++() - { ++(*m_core); return *this; } - bool operator==(const iterator & it) - { return (*m_core)==(*it.m_core); } - bool operator!=(const iterator & it) - { return !operator==(it); } - }; - - class row_iterator { - friend class table_base; - friend class row_interface; - - ref m_core; - - row_iterator(row_iterator_core * core) : m_core(core) {} - public: - table_element operator*() - { return *(*m_core); } - row_iterator & operator++() - { ++(*m_core); return *this; } - bool operator==(const row_iterator & it) - { return (*m_core)==(*it.m_core); } - bool operator!=(const row_iterator & it) - { return !operator==(it); } - }; - - virtual iterator begin() const = 0; - virtual iterator end() const = 0; - - class row_interface { - class fact_row_iterator; - - const table_base & m_parent_table; - public: - typedef row_iterator iterator; - typedef row_iterator const_iterator; - - row_interface(const table_base & parent_table) : m_parent_table(parent_table) {} - virtual ~row_interface() {} - - virtual table_element operator[](unsigned col) const = 0; - - unsigned size() const { return m_parent_table.get_signature().size(); } - virtual void get_fact(table_fact & result) const; - virtual row_iterator begin() const; - virtual row_iterator end() const; - virtual void display(std::ostream & out) const; - }; - - protected: - - class caching_row_interface : public row_interface { - mutable table_fact m_current; - - bool populated() const { return !m_current.empty(); } - void ensure_populated() const { - if(!populated()) { - get_fact(m_current); - } - } - public: - caching_row_interface(const table_base & parent) : row_interface(parent) {} - - virtual void get_fact(table_fact & result) const = 0; - - virtual table_element operator[](unsigned col) const { - ensure_populated(); - return m_current[col]; - } - /** - \brief Resets the cache of the row object. - - Must be called when the row object begins to represent a different row in the table. - */ - void reset() { m_current.reset(); } - }; - - //This function is here to create iterator instances in classes that derive from table_base. - //We do not want to make the constructor of the iterator class public, and being private, the - //inheritor classes cannot see it directly. - static iterator mk_iterator(iterator_core * core) { - return iterator(core); - } - }; - - -}; - -#endif /* _DL_BASE_H_ */ - diff --git a/src/muz/dl_bound_relation.cpp b/src/muz/dl_bound_relation.cpp deleted file mode 100644 index 182046c1e..000000000 --- a/src/muz/dl_bound_relation.cpp +++ /dev/null @@ -1,707 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_bound_relation.cpp - -Abstract: - - Basic (strict upper) bound relation. - -Author: - - Nikolaj Bjorner (nbjorner) 2010-2-11 - -Revision History: - ---*/ - -#include "dl_bound_relation.h" -#include "debug.h" -#include "ast_pp.h" - -namespace datalog { - - bound_relation_plugin::bound_relation_plugin(relation_manager& m): - relation_plugin(bound_relation_plugin::get_name(), m), - m_arith(get_ast_manager()), - m_bsimp(get_ast_manager()) { - } - - bool bound_relation_plugin::can_handle_signature(const relation_signature & sig) { - for (unsigned i = 0; i < sig.size(); ++i) { - if (!m_arith.is_int(sig[i]) && !m_arith.is_real(sig[i])) { - return false; - } - } - return true; - } - - bound_relation& bound_relation_plugin::get(relation_base& r) { - return dynamic_cast(r); - } - - bound_relation const & bound_relation_plugin::get(relation_base const& r) { - return dynamic_cast(r); - } - - bound_relation* bound_relation_plugin::get(relation_base* r) { - return dynamic_cast(r); - } - - bool bound_relation_plugin::is_interval_relation(relation_base const& r) { - return symbol("interval_relation") == r.get_plugin().get_name(); - } - - interval_relation& bound_relation_plugin::get_interval_relation(relation_base& r) { - SASSERT(is_interval_relation(r)); - return dynamic_cast(r); - } - - interval_relation const& bound_relation_plugin::get_interval_relation(relation_base const& r) { - SASSERT(is_interval_relation(r)); - return dynamic_cast(r); - } - - relation_base * bound_relation_plugin::mk_empty(const relation_signature & s) { - return alloc(bound_relation, *this, s, true); - } - - relation_base * bound_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { - return alloc(bound_relation, *this, s, false); - } - - class bound_relation_plugin::join_fn : public convenient_relation_join_fn { - public: - join_fn(const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2) - : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2) { - } - - virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { - bound_relation const& r1 = get(_r1); - bound_relation const& r2 = get(_r2); - bound_relation_plugin& p = r1.get_plugin(); - bound_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); - result->mk_join(r1, r2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); - return result; - } - }; - - relation_join_fn * bound_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (!check_kind(r1) || !check_kind(r2)) { - return 0; - } - return alloc(join_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2); - } - - - class bound_relation_plugin::project_fn : public convenient_relation_project_fn { - public: - project_fn(const relation_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) - : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { - } - - virtual relation_base * operator()(const relation_base & _r) { - bound_relation const& r = get(_r); - bound_relation_plugin& p = r.get_plugin(); - bound_relation* result = get(p.mk_full(0, get_result_signature())); - result->mk_project(r, m_removed_cols.size(), m_removed_cols.c_ptr()); - return result; - } - }; - - relation_transformer_fn * bound_relation_plugin::mk_project_fn(const relation_base & r, - unsigned col_cnt, const unsigned * removed_cols) { - return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); - } - - class bound_relation_plugin::rename_fn : public convenient_relation_rename_fn { - public: - rename_fn(const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) - : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) { - } - - virtual relation_base * operator()(const relation_base & _r) { - bound_relation const& r = get(_r); - bound_relation_plugin& p = r.get_plugin(); - bound_relation* result = get(p.mk_full(0, get_result_signature())); - result->mk_rename(r, m_cycle.size(), m_cycle.c_ptr()); - return result; - } - }; - - relation_transformer_fn * bound_relation_plugin::mk_rename_fn(const relation_base & r, - unsigned cycle_len, const unsigned * permutation_cycle) { - if(check_kind(r)) { - return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle); - } - return 0; - } - - - class bound_relation_plugin::union_fn : public relation_union_fn { - bool m_is_widen; - public: - union_fn(bool is_widen) : - m_is_widen(is_widen) { - } - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { - TRACE("bound_relation", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); - get(_r).mk_union(get(_src), get(_delta), m_is_widen); - } - }; - - class bound_relation_plugin::union_fn_i : public relation_union_fn { - bool m_is_widen; - public: - union_fn_i(bool is_widen) : - m_is_widen(is_widen) { - } - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { - TRACE("bound_relation", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); - get(_r).mk_union_i(get_interval_relation(_src), get(_delta), m_is_widen); - TRACE("bound_relation", _r.display(tout << "dst':\n");); - } - }; - - - relation_union_fn * bound_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if (check_kind(tgt) && is_interval_relation(src) && (!delta || check_kind(*delta))) { - return alloc(union_fn_i, false); - } - if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) { - return alloc(union_fn, false); - } - return 0; - } - - relation_union_fn * bound_relation_plugin::mk_widen_fn( - const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if (check_kind(tgt) && is_interval_relation(src) && (!delta || check_kind(*delta))) { - return alloc(union_fn_i, true); - } - if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) { - return alloc(union_fn, true); - } - return 0; - } - - class bound_relation_plugin::filter_identical_fn : public relation_mutator_fn { - unsigned_vector m_cols; - public: - filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) - : m_cols(col_cnt, identical_cols) {} - - virtual void operator()(relation_base & r) { - for (unsigned i = 1; i < m_cols.size(); ++i) { - get(r).equate(m_cols[0], m_cols[i]); - } - } - }; - - relation_mutator_fn * bound_relation_plugin::mk_filter_identical_fn( - const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { - if(check_kind(t)) { - return alloc(filter_identical_fn, col_cnt, identical_cols); - } - return 0; - } - - class bound_relation_plugin::filter_equal_fn : public relation_mutator_fn { - public: - filter_equal_fn(relation_element const& value, unsigned col) {} - - virtual void operator()(relation_base & r) { } - }; - - relation_mutator_fn * bound_relation_plugin::mk_filter_equal_fn(const relation_base & r, - const relation_element & value, unsigned col) { - if (check_kind(r)) { - return alloc(filter_equal_fn, value, col); - } - return 0; - } - - class bound_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { - enum kind_t { NOT_APPLICABLE, EQ_VAR, EQ_SUB, LT_VAR, LE_VAR, K_FALSE }; - app_ref m_cond; - app_ref m_lt; - arith_util m_arith; - interval_relation* m_interval; - unsigned_vector m_vars; - kind_t m_kind; - - unsigned get_var(expr* a) { - SASSERT(is_var(a)); - return to_var(a)->get_idx(); - } - - // x = z - y - void mk_sub_eq(expr* x, expr* z, expr* y) { - SASSERT(is_var(x)); - SASSERT(is_var(z)); - SASSERT(is_var(y)); - m_vars.push_back(get_var(x)); - m_vars.push_back(get_var(z)); - m_vars.push_back(get_var(y)); - m_kind = EQ_SUB; - } - - void mk_lt(expr* l, expr* r) { - SASSERT(is_var(l)); - SASSERT(is_var(r)); - m_vars.push_back(get_var(l)); - m_vars.push_back(get_var(r)); - m_lt = m_arith.mk_lt(l, r); - m_kind = LT_VAR; - } - - - void mk_le(expr* l, expr* r) { - SASSERT(is_var(l)); - SASSERT(is_var(r)); - m_vars.push_back(get_var(l)); - m_vars.push_back(get_var(r)); - m_kind = LE_VAR; - } - - void mk_eq(expr* l, expr* r) { - m_vars.push_back(get_var(l)); - m_vars.push_back(get_var(r)); - m_kind = EQ_VAR; - } - - public: - - filter_interpreted_fn(ast_manager& m, app* cond) : - m_cond(cond, m), - m_lt(m), m_arith(m), m_interval(0), m_kind(NOT_APPLICABLE) { - expr* l, *r, *r1, *r2, *c2; - rational n1; - if ((m_arith.is_lt(cond, l, r) || m_arith.is_gt(cond, r, l)) && - is_var(l) && is_var(r)) { - mk_lt(l, r); - } - else if (m.is_not(cond, c2) && - (m_arith.is_ge(c2, l, r) || m_arith.is_le(c2, r, l)) && - is_var(l) && is_var(r)) { - mk_lt(l, r); - } - else if ((m_arith.is_le(cond, l, r) || m_arith.is_ge(cond, r, l)) && - is_var(l) && is_var(r)) { - mk_le(l, r); - } - else if (m.is_not(cond, c2) && - (m_arith.is_gt(c2, l, r) || m_arith.is_lt(c2, r, l)) && - is_var(l) && is_var(r)) { - mk_le(l, r); - } - else if (m.is_false(cond)) { - m_kind = K_FALSE; - } - else if (m.is_eq(cond, l, r) && is_var(l) && is_var(r)) { - mk_eq(l, r); - } - else if (m.is_eq(cond, l, r) && - m_arith.is_sub(r, r1, r2) && - is_var(l) && is_var(r1) && is_var(r2)) { - mk_sub_eq(l, r1, r2); - } - else if (m.is_eq(cond, l, r) && - m_arith.is_sub(l, r1, r2) && - is_var(r) && is_var(r1) && is_var(r2)) { - mk_sub_eq(r, r1, r2); - } - else if (m.is_eq(cond, l, r) && - m_arith.is_add(r, r1, r2) && - m_arith.is_numeral(r1, n1) && - n1.is_pos() && is_var(l) && is_var(r2)) { - mk_lt(r2, l); - } - else if (m.is_eq(cond, l, r) && - m_arith.is_add(r, r1, r2) && - m_arith.is_numeral(r2, n1) && - n1.is_pos() && is_var(l) && is_var(r1)) { - mk_lt(r1, l); - } - else { - - } - } - - // - // x = z - y - // x = y - // x < y - // x <= y - // x < y + z - // - - void operator()(relation_base& t) { - TRACE("dl", tout << mk_pp(m_cond, m_cond.get_manager()) << "\n"; t.display(tout);); - bound_relation& r = get(t); - switch(m_kind) { - case K_FALSE: - r.set_empty(); - break; - case NOT_APPLICABLE: - break; - case EQ_VAR: - r.equate(m_vars[0], m_vars[1]); - break; - case EQ_SUB: - // TBD - break; - case LT_VAR: - r.mk_lt(m_vars[0], m_vars[1]); - break; - case LE_VAR: - r.mk_le(m_vars[0], m_vars[1]); - break; - default: - UNREACHABLE(); - break; - } - TRACE("dl", t.display(tout << "result\n");); - } - - bool supports_attachment(relation_base& t) { - return is_interval_relation(t); - } - - void attach(relation_base& t) { - SASSERT(is_interval_relation(t)); - interval_relation& r = get_interval_relation(t); - m_interval = &r; - } - }; - - relation_mutator_fn * bound_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { - return alloc(filter_interpreted_fn, t.get_plugin().get_ast_manager(), condition); - } - - // ----------------------------- - // bound_relation - - void bound_relation_helper::mk_project_t(uint_set2& t, unsigned_vector const& renaming) { - if (t.lt.empty() && t.le.empty()) { - return; - } - uint_set::iterator it = t.lt.begin(), end = t.lt.end(); - unsigned_vector ltv, lev; - for (; it != end; ++it) { - ltv.push_back(renaming[*it]); - } - it = t.le.begin(), end = t.le.end(); - for (; it != end; ++it) { - lev.push_back(renaming[*it]); - } - TRACE("dl", - tout << "project: "; - for (unsigned i = 0; i < renaming.size(); ++i) - if (renaming[i] == UINT_MAX) tout << i << " "; - tout << ": "; - it = t.lt.begin(); end = t.lt.end(); - for (; it != end; ++it) tout << *it << " "; - tout << " le "; - it = t.le.begin(); end = t.le.end(); - for (; it != end; ++it) tout << *it << " "; - tout << " => "; - for (unsigned i = 0; i < ltv.size(); ++i) tout << ltv[i] << " "; - tout << " le "; - for (unsigned i = 0; i < lev.size(); ++i) tout << lev[i] << " "; - tout << "\n";); - t.lt.reset(); - for (unsigned i = 0; i < ltv.size(); ++i) { - t.lt.insert(ltv[i]); - } - t.le.reset(); - for (unsigned i = 0; i < lev.size(); ++i) { - t.le.insert(lev[i]); - } - } - - bound_relation::bound_relation(bound_relation_plugin& p, relation_signature const& s, bool is_empty): - vector_relation(p, s, is_empty, uint_set2()) - { - } - - - uint_set2 bound_relation::mk_intersect(uint_set2 const& t1, uint_set2 const& t2, bool& is_empty) const { - is_empty = false; - uint_set2 r(t1); - r.lt |= t2.lt; - r.le |= t2.le; - return r; - } - - uint_set2 bound_relation::mk_widen(uint_set2 const& t1, uint_set2 const& t2) const { - return mk_unite(t1, t2); - } - - uint_set2 bound_relation::mk_unite(uint_set2 const& t1, uint_set2 const& t2) const { - uint_set2 s1(t1); - s1.lt &= t2.lt; - s1.le &= t2.le; - return s1; - } - - uint_set2 bound_relation::mk_eq(union_find<> const& old_eqs, union_find<> const& new_eqs, uint_set2 const& t) const { - unsigned sz = old_eqs.get_num_vars(); - SASSERT(sz == new_eqs.get_num_vars()); - uint_set2 result; - for (unsigned i = 0; i < sz; ++i) { - if (t.lt.contains(i)) { - unsigned j = i; - do { - result.lt.insert(new_eqs.find(j)); - j = old_eqs.next(j); - } - while (j != i); - } - if (t.le.contains(i)) { - unsigned j = i; - do { - result.le.insert(new_eqs.find(j)); - j = old_eqs.next(j); - } - while (j != i); - } - } - return result; - } - - bool bound_relation::is_subset_of(uint_set2 const& t1, uint_set2 const& t2) const { - uint_set2 s1, s2; - normalize(t1, s1); - normalize(t2, s2); - return s1.lt.subset_of(s2.lt) && s1.le.subset_of(s2.le); - } - - void bound_relation::mk_rename_elem(uint_set2& t, unsigned col_cnt, unsigned const* cycle) { - // [ 0 -> 2 -> 3 -> 0] - if (col_cnt == 0) return; - unsigned col1, col2; - col1 = find(cycle[0]); - col2 = find(cycle[col_cnt-1]); - bool has_col2_lt = t.lt.contains(col2); - t.lt.remove(col2); - bool has_col2_le = t.le.contains(col2); - t.le.remove(col2); - for (unsigned i = 0; i + 1 < col_cnt; ++i) { - col1 = find(cycle[i]); - col2 = find(cycle[i+1]); - if (t.lt.contains(col1)) { - t.lt.remove(col1); - t.lt.insert(col2); - } - if (t.le.contains(col1)) { - t.le.remove(col1); - t.le.insert(col2); - } - } - if (has_col2_lt) { - col1 = find(cycle[0]); - t.lt.insert(col1); - } - if (has_col2_le) { - col1 = find(cycle[0]); - t.le.insert(col1); - } - } - - - bool bound_relation::is_full(uint_set2 const& t) const { - return t.lt.empty() && t.le.empty(); - } - - bool bound_relation::is_empty(unsigned index, uint_set2 const& t) const { - return t.lt.contains(find(index)) || t.le.contains(find(index)); - } - - void bound_relation::normalize(uint_set const& src, uint_set& dst) const { - uint_set::iterator it = src.begin(), end = src.end(); - for (; it != end; ++it) { - dst.insert(find(*it)); - } - } - void bound_relation::normalize(uint_set2 const& src, uint_set2& dst) const { - normalize(src.lt, dst.lt); - normalize(src.le, dst.le); - } - - - void bound_relation::mk_lt(unsigned i) { - uint_set2& dst = (*this)[i]; - while (!m_todo.empty()) { - unsigned j = m_todo.back().first; - bool strict = m_todo.back().second; - if (i == j && strict) { - m_todo.reset(); - m_empty = true; - return; - } - m_todo.pop_back(); - if (i == j) { - continue; - } - uint_set2& src = (*m_elems)[j]; - uint_set::iterator it = src.lt.begin(), end = src.lt.end(); - for(; it != end; ++it) { - m_todo.push_back(std::make_pair(*it, true)); - } - it = src.le.begin(), end = src.le.end(); - for(; it != end; ++it) { - m_todo.push_back(std::make_pair(*it, strict)); - } - if (strict) { - dst.lt.insert(j); - } - else { - dst.le.insert(j); - } - } - } - - void bound_relation::mk_lt(unsigned i, unsigned j) { - m_todo.reset(); - i = find(i); - m_todo.push_back(std::make_pair(find(j), true)); - mk_lt(i); - } - - void bound_relation::mk_le(unsigned i, unsigned j) { - m_todo.reset(); - i = find(i); - m_todo.push_back(std::make_pair(find(j), false)); - mk_lt(i); - } - - bool bound_relation::is_lt(unsigned i, unsigned j) const { - return (*this)[i].lt.contains(find(j)); - } - - void bound_relation::add_fact(const relation_fact & f) { - bound_relation r(get_plugin(), get_signature(), false); - for (unsigned i = 0; i < f.size(); ++i) { - scoped_ptr fe = get_plugin().mk_filter_equal_fn(r, f[i], i); - (*fe)(r); - } - mk_union(r, 0, false); - } - - bool bound_relation::contains_fact(const relation_fact & f) const { - if (empty()) { - return false; - } - // this is a very rough approximation. - return true; - } - - bound_relation * bound_relation::clone() const { - bound_relation* result = 0; - if (empty()) { - result = bound_relation_plugin::get(get_plugin().mk_empty(get_signature())); - } - else { - result = bound_relation_plugin::get(get_plugin().mk_full(0, get_signature())); - result->copy(*this); - } - return result; - } - - void bound_relation::mk_union_i(interval_relation const& src, bound_relation* delta, bool is_widen) { - unsigned size = get_signature().size(); - for (unsigned i = 0; i < size; ++i) { - if (find(i) != i) { - continue; - } - uint_set2& s = (*this)[i]; - ext_numeral const& lo = src[i].sup(); - if (lo.is_infinite()) { - s.lt.reset(); - s.le.reset(); - continue; - } - uint_set::iterator it = s.lt.begin(), end = s.lt.end(); - for(; it != end; ++it) { - ext_numeral const& hi = src[*it].inf(); - if (hi.is_infinite() || lo.to_rational() >= hi.to_rational()) { - s.lt.remove(*it); - } - } - it = s.le.begin(), end = s.le.end(); - for(; it != end; ++it) { - ext_numeral const& hi = src[*it].inf(); - if (hi.is_infinite() || lo.to_rational() > hi.to_rational()) { - s.le.remove(*it); - } - } - } - } - - bound_relation * bound_relation::complement(func_decl* p) const { - UNREACHABLE(); - return 0; - } - - void bound_relation::to_formula(expr_ref& fml) const { - ast_manager& m = get_plugin().get_ast_manager(); - arith_util& arith = get_plugin().m_arith; - basic_simplifier_plugin& bsimp = get_plugin().m_bsimp; - expr_ref_vector conjs(m); - relation_signature const& sig = get_signature(); - for (unsigned i = 0; i < sig.size(); ++i) { - if (i != find(i)) { - conjs.push_back(m.mk_eq(m.mk_var(i, sig[i]), m.mk_var(find(i), sig[find(i)]))); - continue; - } - uint_set2 const& upper = (*this)[i]; - uint_set::iterator it = upper.lt.begin(), end = upper.lt.end(); - for (; it != end; ++it) { - conjs.push_back(arith.mk_lt(m.mk_var(i, sig[i]), m.mk_var(*it, sig[*it]))); - } - it = upper.le.begin(), end = upper.le.end(); - for (; it != end; ++it) { - conjs.push_back(arith.mk_le(m.mk_var(i, sig[i]), m.mk_var(*it, sig[*it]))); - } - } - bsimp.mk_and(conjs.size(), conjs.c_ptr(), fml); - } - - - void bound_relation::display_index(unsigned i, uint_set2 const& src, std::ostream & out) const { - uint_set::iterator it = src.lt.begin(), end = src.lt.end(); - out << "#" << i; - if (!src.lt.empty()) { - out << " < "; - for(; it != end; ++it) { - out << *it << " "; - } - } - if (!src.le.empty()) { - it = src.le.begin(), end = src.le.end(); - out << " <= "; - for(; it != end; ++it) { - out << *it << " "; - } - } - if (src.lt.empty() && src.le.empty()) { - out << " < oo"; - } - out << "\n"; - } - - bound_relation_plugin& bound_relation::get_plugin() const { - return dynamic_cast(relation_base::get_plugin()); - } - - -}; - - diff --git a/src/muz/dl_bound_relation.h b/src/muz/dl_bound_relation.h deleted file mode 100644 index 04479b3b6..000000000 --- a/src/muz/dl_bound_relation.h +++ /dev/null @@ -1,176 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_bound_relation.h - -Abstract: - - Basic (strict upper) bound relation. - -Author: - - Nikolaj Bjorner (nbjorner) 2010-2-11 - -Revision History: - ---*/ -#ifndef _DL_BOUND_RELATION_H_ -#define _DL_BOUND_RELATION_H_ - -#include "dl_context.h" -#include "uint_set.h" -#include "dl_vector_relation.h" -#include "dl_interval_relation.h" -#include "arith_decl_plugin.h" -#include "basic_simplifier_plugin.h" - -namespace datalog { - - class bound_relation; - - class bound_relation_plugin : public relation_plugin { - friend class bound_relation; - class join_fn; - class project_fn; - class rename_fn; - class union_fn; - class union_fn_i; - class filter_equal_fn; - class filter_identical_fn; - class filter_interpreted_fn; - class filter_intersection_fn; - arith_util m_arith; - basic_simplifier_plugin m_bsimp; - public: - bound_relation_plugin(relation_manager& m); - virtual bool can_handle_signature(const relation_signature & s); - static symbol get_name() { return symbol("bound_relation"); } - virtual relation_base * mk_empty(const relation_signature & s); - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - - virtual relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols) { return 0; } - - -#if 0 - virtual intersection_filter_fn * mk_filter_by_intersection_fn( - const relation_base & t, - const relation_base & src, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * src_cols) { - return 0; - } -#endif - - static bound_relation* get(relation_base* r); - private: - static bound_relation& get(relation_base& r); - static bound_relation const & get(relation_base const& r); - - - static bool is_interval_relation(relation_base const& r); - static interval_relation& get_interval_relation(relation_base& r); - static interval_relation const& get_interval_relation(relation_base const& r); - }; - - struct uint_set2 { - uint_set lt; - uint_set le; - uint_set2(uint_set2 const& other):lt(other.lt), le(other.le) {} - uint_set2() {} - bool operator==(const uint_set2& other) const { - return other.lt == lt && other.le == le; - } - bool operator!=(const uint_set2& other) const { - return other.lt != lt || other.le != le; - } - }; - - inline std::ostream & operator<<(std::ostream & target, const uint_set2 & s) { - return target << s.lt << " " << s.le; - } - - - class bound_relation_helper { - public: - static void mk_project_t(uint_set2& t, unsigned_vector const& renaming); - }; - - class bound_relation : public vector_relation { - friend class bound_relation_plugin; - svector > m_todo; - - public: - bound_relation(bound_relation_plugin& p, relation_signature const& s, bool is_empty); - bound_relation& operator=(bound_relation const& other); - - virtual bool empty() const { return m_empty; } - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual bound_relation * clone() const; - virtual bound_relation * complement(func_decl* p) const; - virtual void to_formula(expr_ref& fml) const; - bound_relation_plugin& get_plugin() const; - - void mk_union_i(interval_relation const& src, bound_relation* delta, bool is_widen); - - void mk_lt(unsigned i, unsigned j); - - void mk_lt(unsigned i); - - void mk_le(unsigned i, unsigned j); - - bool is_lt(unsigned i, unsigned j) const; - - virtual bool is_precise() const { return false; } - - private: - typedef uint_set2 T; - virtual T mk_intersect(T const& t1, T const& t2, bool& is_empty) const; - - virtual T mk_widen(T const& t1, T const& t2) const; - - virtual T mk_unite(T const& t1, T const& t2) const; - - virtual T mk_eq(union_find<> const& old_eqs, union_find<> const& new_eqs, T const& t) const; - - virtual void mk_rename_elem(T& i, unsigned col_cnt, unsigned const* cycle); - - - virtual bool is_subset_of(T const& t1, T const& t2) const; - - virtual bool is_full(T const& t) const; - - virtual bool is_empty(unsigned idx, T const& t) const; - - virtual void display_index(unsigned idx, T const& t, std::ostream& out) const; - - void normalize(T const& src, T& dst) const; - - void normalize(uint_set const& src, uint_set& dst) const; - - - - }; - -}; - -#endif - diff --git a/src/muz/dl_check_table.cpp b/src/muz/dl_check_table.cpp deleted file mode 100644 index ea4003e5f..000000000 --- a/src/muz/dl_check_table.cpp +++ /dev/null @@ -1,439 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_check_table.cpp - -Abstract: - - - -Author: - - Nikolaj Bjorner (nbjorner) 2010-11-15 - - -Revision History: - ---*/ - - -#include "dl_check_table.h" -#include "dl_table.h" - - -namespace datalog { - - bool check_table_plugin::can_handle_signature(table_signature const& s) { - return m_tocheck.can_handle_signature(s) && m_checker.can_handle_signature(s); - } - - - check_table & check_table_plugin::get(table_base& r) { - return static_cast(r); - } - - check_table const & check_table_plugin::get(table_base const& r) { - return static_cast(r); - } - - table_base& check_table_plugin::checker(table_base& r) { return *get(r).m_checker; } - table_base const& check_table_plugin::checker(table_base const& r) { return *get(r).m_checker; } - table_base* check_table_plugin::checker(table_base* r) { return r?(get(*r).m_checker):0; } - table_base const* check_table_plugin::checker(table_base const* r) { return r?(get(*r).m_checker):0; } - table_base& check_table_plugin::tocheck(table_base& r) { return *get(r).m_tocheck; } - table_base const& check_table_plugin::tocheck(table_base const& r) { return *get(r).m_tocheck; } - table_base* check_table_plugin::tocheck(table_base* r) { return r?(get(*r).m_tocheck):0; } - table_base const* check_table_plugin::tocheck(table_base const* r) { return r?(get(*r).m_tocheck):0; } - - table_base * check_table_plugin::mk_empty(const table_signature & s) { - IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); - table_base* checker = m_checker.mk_empty(s); - table_base* tocheck = m_tocheck.mk_empty(s); - return alloc(check_table, *this, s, tocheck, checker); - } - - class check_table_plugin::join_fn : public table_join_fn { - scoped_ptr m_tocheck; - scoped_ptr m_checker; - public: - join_fn(check_table_plugin& p, - const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - m_tocheck = p.get_manager().mk_join_fn(tocheck(t1), tocheck(t2), col_cnt, cols1, cols2); - m_checker = p.get_manager().mk_join_fn(checker(t1), checker(t2), col_cnt, cols1, cols2); - } - - virtual table_base* operator()(const table_base & t1, const table_base & t2) { - IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); - table_base* ttocheck = (*m_tocheck)(tocheck(t1), tocheck(t2)); - table_base* tchecker = (*m_checker)(checker(t1), checker(t2)); - check_table* result = alloc(check_table, get(t1).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); - return result; - } - }; - - table_join_fn * check_table_plugin::mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (!check_kind(t1) || !check_kind(t2)) { - return 0; - } - return alloc(join_fn, *this, t1, t2, col_cnt, cols1, cols2); - } - - class check_table_plugin::join_project_fn : public table_join_fn { - scoped_ptr m_tocheck; - scoped_ptr m_checker; - public: - join_project_fn(check_table_plugin& p, const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols) { - m_tocheck = p.get_manager().mk_join_project_fn(tocheck(t1), tocheck(t2), col_cnt, cols1, cols2, removed_col_cnt, removed_cols); - m_checker = p.get_manager().mk_join_project_fn(checker(t1), checker(t2), col_cnt, cols1, cols2, removed_col_cnt, removed_cols); - } - - virtual table_base* operator()(const table_base & t1, const table_base & t2) { - table_base* ttocheck = (*m_tocheck)(tocheck(t1), tocheck(t2)); - table_base* tchecker = (*m_checker)(checker(t1), checker(t2)); - check_table* result = alloc(check_table, get(t1).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); - return result; - } - }; - - table_join_fn * check_table_plugin::mk_join_project_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols) { - if (!check_kind(t1) || !check_kind(t2)) { - return 0; - } - return alloc(join_project_fn, *this, t1, t2, col_cnt, cols1, cols2, removed_col_cnt, removed_cols); - } - - class check_table_plugin::union_fn : public table_union_fn { - scoped_ptr m_tocheck; - scoped_ptr m_checker; - public: - union_fn(check_table_plugin& p, table_base const& tgt, const table_base& src, table_base const* delta) { - m_tocheck = p.get_manager().mk_union_fn(tocheck(tgt), tocheck(src), tocheck(delta)); - m_checker = p.get_manager().mk_union_fn(checker(tgt), checker(src), checker(delta)); - } - - virtual void operator()(table_base& tgt, const table_base& src, table_base* delta) { - IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); - (*m_tocheck)(tocheck(tgt), tocheck(src), tocheck(delta)); - (*m_checker)(checker(tgt), checker(src), checker(delta)); - get(tgt).well_formed(); - if (delta) { - get(*delta).well_formed(); - } - } - }; - - table_union_fn * check_table_plugin::mk_union_fn(const table_base & tgt, const table_base & src, const table_base * delta) { - if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; - } - return alloc(union_fn, *this, tgt, src, delta); - - } - - class check_table_plugin::project_fn : public table_transformer_fn { - scoped_ptr m_checker; - scoped_ptr m_tocheck; - public: - project_fn(check_table_plugin& p, const table_base & t, unsigned col_cnt, const unsigned * removed_cols) { - m_checker = p.get_manager().mk_project_fn(checker(t), col_cnt, removed_cols); - m_tocheck = p.get_manager().mk_project_fn(tocheck(t), col_cnt, removed_cols); - } - - table_base* operator()(table_base const& src) { - table_base* tchecker = (*m_checker)(checker(src)); - table_base* ttocheck = (*m_tocheck)(tocheck(src)); - check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker); - return result; - } - }; - - table_transformer_fn * check_table_plugin::mk_project_fn(const table_base & t, unsigned col_cnt, const unsigned * removed_cols) { - if (!check_kind(t)) { - return 0; - } - return alloc(project_fn, *this, t, col_cnt, removed_cols); - } - - class check_table_plugin::select_equal_and_project_fn : public table_transformer_fn { - scoped_ptr m_checker; - scoped_ptr m_tocheck; - public: - select_equal_and_project_fn(check_table_plugin& p, const table_base & t, const table_element & value, unsigned col) { - m_checker = p.get_manager().mk_select_equal_and_project_fn(checker(t), value, col); - m_tocheck = p.get_manager().mk_select_equal_and_project_fn(tocheck(t), value, col); - } - - table_base* operator()(table_base const& src) { - table_base* tchecker = (*m_checker)(checker(src)); - table_base* ttocheck = (*m_tocheck)(tocheck(src)); - check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker); - return result; - } - }; - - table_transformer_fn * check_table_plugin::mk_select_equal_and_project_fn(const table_base & t, - const table_element & value, unsigned col) { - if (!check_kind(t)) { - return 0; - } - return alloc(select_equal_and_project_fn, *this, t, value, col); - } - - class check_table_plugin::rename_fn : public table_transformer_fn { - scoped_ptr m_checker; - scoped_ptr m_tocheck; - public: - rename_fn(check_table_plugin& p, const table_base & t, unsigned cycle_len, unsigned const* cycle) { - m_checker = p.get_manager().mk_rename_fn(checker(t), cycle_len, cycle); - m_tocheck = p.get_manager().mk_rename_fn(tocheck(t), cycle_len, cycle); - } - - table_base* operator()(table_base const& src) { - IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); - table_base* tchecker = (*m_checker)(checker(src)); - table_base* ttocheck = (*m_tocheck)(tocheck(src)); - check_table* result = alloc(check_table, get(src).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); - return result; - } - }; - - table_transformer_fn * check_table_plugin::mk_rename_fn(const table_base & t, unsigned len, const unsigned * cycle) { - if (!check_kind(t)) { - return 0; - } - return alloc(rename_fn, *this, t, len, cycle); - } - - class check_table_plugin::filter_identical_fn : public table_mutator_fn { - scoped_ptr m_checker; - scoped_ptr m_tocheck; - public: - filter_identical_fn(check_table_plugin& p, const table_base & t,unsigned cnt, unsigned const* cols) - { - m_checker = p.get_manager().mk_filter_identical_fn(checker(t), cnt, cols); - m_tocheck = p.get_manager().mk_filter_identical_fn(tocheck(t), cnt, cols); - } - - void operator()(table_base & t) { - (*m_checker)(checker(t)); - (*m_tocheck)(tocheck(t)); - get(t).well_formed(); - } - }; - - table_mutator_fn * check_table_plugin::mk_filter_identical_fn(const table_base & t, unsigned col_cnt, - const unsigned * identical_cols) { - if (check_kind(t)) { - return alloc(filter_identical_fn, *this, t, col_cnt, identical_cols); - } - return 0; - } - - class check_table_plugin::filter_equal_fn : public table_mutator_fn { - scoped_ptr m_checker; - scoped_ptr m_tocheck; - public: - filter_equal_fn(check_table_plugin& p, const table_base & t, const table_element & v, unsigned col) - { - m_checker = p.get_manager().mk_filter_equal_fn(checker(t), v, col); - m_tocheck = p.get_manager().mk_filter_equal_fn(tocheck(t), v, col); - } - - virtual void operator()(table_base& src) { - (*m_checker)(checker(src)); - (*m_tocheck)(tocheck(src)); - get(src).well_formed(); - } - }; - - table_mutator_fn * check_table_plugin::mk_filter_equal_fn(const table_base & t, const table_element & value, unsigned col) { - if (check_kind(t)) { - return alloc(filter_equal_fn, *this, t, value, col); - } - return 0; - } - - class check_table_plugin::filter_interpreted_fn : public table_mutator_fn { - scoped_ptr m_checker; - scoped_ptr m_tocheck; - public: - filter_interpreted_fn(check_table_plugin& p, const table_base & t, app * condition) - { - m_checker = p.get_manager().mk_filter_interpreted_fn(checker(t), condition); - m_tocheck = p.get_manager().mk_filter_interpreted_fn(tocheck(t), condition); - } - - virtual void operator()(table_base& src) { - (*m_checker)(checker(src)); - (*m_tocheck)(tocheck(src)); - get(src).well_formed(); - } - }; - - table_mutator_fn * check_table_plugin::mk_filter_interpreted_fn(const table_base & t, app * condition) { - if (check_kind(t)) { - return alloc(filter_interpreted_fn, *this, t, condition); - } - return 0; - } - - class check_table_plugin::filter_interpreted_and_project_fn : public table_transformer_fn { - scoped_ptr m_checker; - scoped_ptr m_tocheck; - public: - filter_interpreted_and_project_fn(check_table_plugin& p, const table_base & t, app * condition, - unsigned removed_col_cnt, const unsigned * removed_cols) - { - m_checker = p.get_manager().mk_filter_interpreted_and_project_fn(checker(t), condition, removed_col_cnt, removed_cols); - m_tocheck = p.get_manager().mk_filter_interpreted_and_project_fn(tocheck(t), condition, removed_col_cnt, removed_cols); - } - - table_base* operator()(table_base const& src) { - table_base* tchecker = (*m_checker)(checker(src)); - table_base* ttocheck = (*m_tocheck)(tocheck(src)); - check_table* result = alloc(check_table, get(src).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); - return result; - } - }; - - table_transformer_fn * check_table_plugin::mk_filter_interpreted_and_project_fn(const table_base & t, - app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { - if (check_kind(t)) { - return alloc(filter_interpreted_and_project_fn, *this, t, condition, removed_col_cnt, removed_cols); - } - return 0; - } - - class check_table_plugin::filter_by_negation_fn : public table_intersection_filter_fn { - scoped_ptr m_checker; - scoped_ptr m_tocheck; - public: - filter_by_negation_fn( - check_table_plugin& p, - const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols) { - m_checker = p.get_manager().mk_filter_by_negation_fn(checker(t), checker(negated_obj), joined_col_cnt, t_cols, negated_cols); - m_tocheck = p.get_manager().mk_filter_by_negation_fn(tocheck(t), tocheck(negated_obj), joined_col_cnt, t_cols, negated_cols); - } - - virtual void operator()(table_base& src, table_base const& negated_obj) { - IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); - (*m_checker)(checker(src), checker(negated_obj)); - (*m_tocheck)(tocheck(src), tocheck(negated_obj)); - get(src).well_formed(); - } - - }; - - table_intersection_filter_fn * check_table_plugin::mk_filter_by_negation_fn(const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols) { - if (check_kind(t) && check_kind(negated_obj)) { - return alloc(filter_by_negation_fn, *this, t, negated_obj, joined_col_cnt, t_cols, negated_cols); - } - return 0; - } - - // ------------------ - // check_table - - - check_table::check_table(check_table_plugin & p, const table_signature & sig): - table_base(p, sig) { - (well_formed()); - } - - check_table::check_table(check_table_plugin & p, const table_signature & sig, table_base* tocheck, table_base* checker): - table_base(p, sig), - m_checker(checker), - m_tocheck(tocheck) { - well_formed(); - } - - check_table::~check_table() { - m_tocheck->deallocate(); - m_checker->deallocate(); - } - - bool check_table::well_formed() const { - get_plugin().m_count++; - iterator it = m_tocheck->begin(), end = m_tocheck->end(); - for (; it != end; ++it) { - table_fact fact; - it->get_fact(fact); - if (!m_checker->contains_fact(fact)) { - m_tocheck->display(verbose_stream()); - m_checker->display(verbose_stream()); - verbose_stream() << get_plugin().m_count << "\n"; - UNREACHABLE(); - fatal_error(0); - return false; - } - } - iterator it2 = m_checker->begin(), end2 = m_checker->end(); - for (; it2 != end2; ++it2) { - table_fact fact; - it2->get_fact(fact); - if (!m_tocheck->contains_fact(fact)) { - m_tocheck->display(verbose_stream()); - m_checker->display(verbose_stream()); - verbose_stream() << get_plugin().m_count << "\n"; - UNREACHABLE(); - fatal_error(0); - return false; - } - } - return true; - } - - bool check_table::empty() const { - if (m_tocheck->empty() != m_checker->empty()) { - m_tocheck->display(verbose_stream()); - m_checker->display(verbose_stream()); - verbose_stream() << get_plugin().m_count << "\n"; - fatal_error(0); - } - return m_tocheck->empty(); - } - - - void check_table::add_fact(const table_fact & f) { - IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); - m_tocheck->add_fact(f); - m_checker->add_fact(f); - well_formed(); - } - - void check_table::remove_fact(const table_element* f) { - IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); - m_tocheck->remove_fact(f); - m_checker->remove_fact(f); - well_formed(); - } - - bool check_table::contains_fact(const table_fact & f) const { - return m_checker->contains_fact(f); - } - - table_base * check_table::clone() const { - IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); - check_table* result = alloc(check_table, get_plugin(), get_signature(), m_tocheck->clone(), m_checker->clone()); - return result; - } - - table_base * check_table::complement(func_decl* p, const table_element * func_columns) const { - check_table* result = alloc(check_table, get_plugin(), get_signature(), m_tocheck->complement(p, func_columns), m_checker->complement(p, func_columns)); - return result; - } - -}; - diff --git a/src/muz/dl_check_table.h b/src/muz/dl_check_table.h deleted file mode 100644 index e4f439590..000000000 --- a/src/muz/dl_check_table.h +++ /dev/null @@ -1,135 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_check_table.h - -Abstract: - - - -Author: - - Nikolaj Bjorner (nbjorner) 2010-11-15 - - -Revision History: - ---*/ - -#ifndef _DL_CHECK_TABLE_H_ -#define _DL_CHECK_TABLE_H_ - -#include "dl_base.h" -#include "dl_decl_plugin.h" -#include "dl_relation_manager.h" - -namespace datalog { - class check_table; - - class check_table_plugin : public table_plugin { - friend class check_table; - table_plugin& m_checker; - table_plugin& m_tocheck; - unsigned m_count; - protected: - class join_fn; - class join_project_fn; - class union_fn; - class transformer_fn; - class rename_fn; - class project_fn; - class select_equal_and_project_fn; - class filter_equal_fn; - class filter_identical_fn; - class filter_interpreted_fn; - class filter_interpreted_and_project_fn; - class filter_by_negation_fn; - - public: - check_table_plugin(relation_manager & manager, symbol const& checker, symbol const& tocheck) - : table_plugin(symbol("check"), manager), - m_checker(*manager.get_table_plugin(checker)), - m_tocheck(*manager.get_table_plugin(tocheck)), m_count(0) {} - - virtual table_base * mk_empty(const table_signature & s); - - virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols); - virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, - const table_base * delta); - virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t, - const table_element & value, unsigned col); - virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual table_mutator_fn * mk_filter_identical_fn(const table_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value, - unsigned col); - virtual table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition); - virtual table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, - app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); - virtual table_intersection_filter_fn * mk_filter_by_negation_fn( - const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); - - virtual bool can_handle_signature(table_signature const& s); - - private: - static check_table& get(table_base& r); - - static check_table const & get(table_base const& r); - - static table_base& checker(table_base& r); - static table_base const& checker(table_base const& r); - static table_base* checker(table_base* r); - static table_base const* checker(table_base const* r); - static table_base& tocheck(table_base& r); - static table_base const& tocheck(table_base const& r); - static table_base* tocheck(table_base* r); - static table_base const* tocheck(table_base const* r); - }; - - class check_table : public table_base { - friend class check_table_plugin; - - table_base* m_checker; - table_base* m_tocheck; - - check_table(check_table_plugin & p, const table_signature & sig); - check_table(check_table_plugin & p, const table_signature & sig, table_base* tocheck, table_base* checker); - - virtual ~check_table(); - - bool well_formed() const; - - public: - - check_table_plugin & get_plugin() const { - return static_cast(table_base::get_plugin()); - } - - virtual bool empty() const; - virtual void add_fact(const table_fact & f); - virtual void remove_fact(const table_element* fact); - virtual bool contains_fact(const table_fact & f) const; - virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const; - virtual table_base * clone() const; - - virtual iterator begin() const { SASSERT(well_formed()); return m_tocheck->begin(); } - virtual iterator end() const { return m_tocheck->end(); } - - virtual unsigned get_size_estimate_rows() const { return m_tocheck->get_size_estimate_rows(); } - virtual unsigned get_size_estimate_bytes() const { return m_tocheck->get_size_estimate_bytes(); } - }; - - }; - - #endif /* _DL_CHECK_TABLE_H_ */ diff --git a/src/muz/dl_cmds.h b/src/muz/dl_cmds.h deleted file mode 100644 index d71b319c4..000000000 --- a/src/muz/dl_cmds.h +++ /dev/null @@ -1,37 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - dl_cmds.h - -Abstract: - Datalog commands for SMT2 front-end. - -Author: - - Nikolaj Bjorner (nbjorner) 2012-11-17 - -Notes: - ---*/ -#ifndef _DL_CMDS_H_ -#define _DL_CMDS_H_ - -#include "ast.h" - -class cmd_context; - -struct dl_collected_cmds { - expr_ref_vector m_rules; - svector m_names; - expr_ref_vector m_queries; - func_decl_ref_vector m_rels; - dl_collected_cmds(ast_manager& m) : m_rules(m), m_queries(m), m_rels(m) {} -}; - -void install_dl_cmds(cmd_context & ctx); -void install_dl_collect_cmds(dl_collected_cmds& collected_cmds, cmd_context& ctx); - - -#endif diff --git a/src/muz/dl_context.cpp b/src/muz/dl_context.cpp index f5bfb6b5e..5e707e315 100644 --- a/src/muz/dl_context.cpp +++ b/src/muz/dl_context.cpp @@ -23,28 +23,6 @@ Revision History: #include"basic_simplifier_plugin.h" #include"arith_decl_plugin.h" #include"bv_decl_plugin.h" -#include"dl_table.h" -#include"dl_table_relation.h" -#include"dl_rule_transformer.h" -#include"dl_mk_coi_filter.h" -#include"dl_mk_explanations.h" -#include"dl_mk_filter_rules.h" -#include"dl_mk_interp_tail_simplifier.h" -#include"dl_mk_rule_inliner.h" -#include"dl_mk_simple_joins.h" -#include"dl_mk_similarity_compressor.h" -#include"dl_mk_unbound_compressor.h" -#include"dl_mk_subsumption_checker.h" -#include"dl_mk_partial_equiv.h" -#include"dl_mk_bit_blast.h" -#include"dl_mk_array_blast.h" -#include"dl_mk_karr_invariants.h" -#include"dl_mk_magic_symbolic.h" -#include"dl_mk_quantifier_abstraction.h" -#include"dl_mk_quantifier_instantiation.h" -#include"dl_mk_scale.h" -#include"dl_compiler.h" -#include"dl_instruction.h" #include"dl_context.h" #include"for_each_expr.h" #include"ast_smt_pp.h" @@ -217,8 +195,9 @@ namespace datalog { // // ----------------------------------- - context::context(ast_manager & m, smt_params& fp, params_ref const& pa): + context::context(ast_manager & m, register_engine_base& re, smt_params& fp, params_ref const& pa): m(m), + m_register_engine(re), m_fparams(fp), m_params_ref(pa), m_params(m_params_ref), @@ -248,6 +227,7 @@ namespace datalog { m_last_answer(m), m_engine_type(LAST_ENGINE), m_cancel(false) { + re.set_context(this); } context::~context() { @@ -780,29 +760,6 @@ namespace datalog { m_closed = false; } - void context::transform_rules() { - m_transf.reset(); - m_transf.register_plugin(alloc(mk_coi_filter, *this)); - m_transf.register_plugin(alloc(mk_filter_rules, *this)); - m_transf.register_plugin(alloc(mk_simple_joins, *this)); - if (unbound_compressor()) { - m_transf.register_plugin(alloc(mk_unbound_compressor, *this)); - } - if (similarity_compressor()) { - m_transf.register_plugin(alloc(mk_similarity_compressor, *this)); - } - m_transf.register_plugin(alloc(mk_partial_equivalence_transformer, *this)); - m_transf.register_plugin(alloc(mk_rule_inliner, *this)); - m_transf.register_plugin(alloc(mk_interp_tail_simplifier, *this)); - - if (get_params().bit_blast()) { - m_transf.register_plugin(alloc(mk_bit_blast, *this, 22000)); - m_transf.register_plugin(alloc(mk_interp_tail_simplifier, *this, 21000)); - } - - transform_rules(m_transf); - } - void context::transform_rules(rule_transformer::plugin* plugin) { rule_transformer transformer(*this); transformer.register_plugin(plugin); @@ -834,45 +791,6 @@ namespace datalog { } void context::apply_default_transformation() { - ensure_closed(); - m_transf.reset(); - m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this)); - m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this)); - - m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 35005)); - m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 35000)); - m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34990)); - m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34980)); - - //and another round of inlining - m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34975)); - m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34970)); - m_transf.register_plugin(alloc(datalog::mk_coi_filter, *this, 34960)); - m_transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, *this, 34950)); - - m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34940)); - m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34930)); - m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34920)); - m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34910)); - m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34900)); - m_transf.register_plugin(alloc(datalog::mk_rule_inliner, *this, 34890)); - m_transf.register_plugin(alloc(datalog::mk_subsumption_checker, *this, 34880)); - - - if (get_params().quantify_arrays()) { - m_transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, *this, 33000)); - m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 32500)); - } - m_transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, *this, 32000)); - - m_transf.register_plugin(alloc(datalog::mk_bit_blast, *this, 35000)); - m_transf.register_plugin(alloc(datalog::mk_array_blast, *this, 36000)); - m_transf.register_plugin(alloc(datalog::mk_karr_invariants, *this, 36010)); - if (get_params().magic()) { - m_transf.register_plugin(alloc(datalog::mk_magic_symbolic, *this, 36020)); - } - m_transf.register_plugin(alloc(datalog::mk_scale, *this, 36030)); - transform_rules(m_transf); } void context::collect_params(param_descrs& p) { @@ -1024,39 +942,18 @@ namespace datalog { void context::ensure_engine() { if (!m_engine.get()) { - switch (get_engine()) { - case PDR_ENGINE: - case QPDR_ENGINE: - m_engine = alloc(pdr::dl_interface, *this); - break; - case DATALOG_ENGINE: - m_rel = alloc(rel_context, *this); - m_engine = m_rel; - break; - case BMC_ENGINE: - case QBMC_ENGINE: - m_engine = alloc(bmc, *this); - break; - case TAB_ENGINE: - m_engine = alloc(tab, *this); - break; - case CLP_ENGINE: - m_engine = alloc(clp, *this); - break; - case LAST_ENGINE: - UNREACHABLE(); + m_engine = m_register_engine.mk_engine(get_engine()); + + // break abstraction. + if (get_engine() == DATALOG_ENGINE) { + m_rel = dynamic_cast(m_engine.get()); } - } + } } lbool context::rel_query(unsigned num_rels, func_decl * const* rels) { ensure_engine(); - if (m_rel) { - return m_rel->query(num_rels, rels); - } - else { - return l_undef; - } + return m_engine->query(num_rels, rels); } expr* context::get_answer_as_formula() { @@ -1073,6 +970,11 @@ namespace datalog { m_engine->display_certificate(out); } + void context::display(std::ostream & out) const { + display_rules(out); + if (m_rel) m_rel->display_facts(out); + } + void context::display_profile(std::ostream& out) const { out << "\n---------------\n"; out << "Original rules\n"; diff --git a/src/muz/dl_context.h b/src/muz/dl_context.h index a3c7e583c..97a371f5a 100644 --- a/src/muz/dl_context.h +++ b/src/muz/dl_context.h @@ -28,15 +28,9 @@ Revision History: #include"th_rewriter.h" #include"str_hashtable.h" #include"var_subst.h" -#include"dl_base.h" #include"dl_costs.h" #include"dl_decl_plugin.h" -#include"dl_relation_manager.h" #include"dl_rule_set.h" -#include"pdr_dl_interface.h" -#include"dl_bmc_engine.h" -#include"tab_context.h" -#include"rel_context.h" #include"lbool.h" #include"statistics.h" #include"params.h" @@ -47,7 +41,7 @@ Revision History: #include"dl_rule_transformer.h" #include"expr_abstract.h" #include"expr_functors.h" -#include"clp_context.h" +#include"dl_engine_base.h" namespace datalog { @@ -60,6 +54,84 @@ namespace datalog { CANCELED }; + class relation_manager; + + typedef sort * relation_sort; + typedef uint64 table_element; + typedef svector table_fact; + + typedef app * relation_element; + typedef app_ref relation_element_ref; + + class relation_fact : public app_ref_vector { + public: + class el_proxy { + friend class relation_fact; + + relation_fact & m_parent; + unsigned m_idx; + + el_proxy(relation_fact & parent, unsigned idx) : m_parent(parent), m_idx(idx) {} + public: + operator relation_element() const { + return m_parent.get(m_idx); + } + relation_element operator->() const { + return m_parent.get(m_idx); + } + relation_element operator=(const relation_element & val) const { + m_parent.set(m_idx, val); + return m_parent.get(m_idx); + } + relation_element operator=(const el_proxy & val) { + m_parent.set(m_idx, val); + return m_parent.get(m_idx); + } + }; + + typedef const relation_element * iterator; + + relation_fact(ast_manager & m) : app_ref_vector(m) {} + relation_fact(ast_manager & m, unsigned sz) : app_ref_vector(m) { resize(sz); } + relation_fact(context & ctx); + + iterator begin() const { return c_ptr(); } + iterator end() const { return c_ptr()+size(); } + + relation_element operator[](unsigned i) const { return get(i); } + el_proxy operator[](unsigned i) { return el_proxy(*this, i); } + }; + + // attempt to modularize context code. + class rel_context_base : public engine_base { + public: + rel_context_base(ast_manager& m, char const* name): engine_base(m, name) {} + virtual ~rel_context_base() {} + virtual relation_manager & get_rmanager() = 0; + virtual const relation_manager & get_rmanager() const = 0; + virtual relation_base & get_relation(func_decl * pred) = 0; + virtual relation_base * try_get_relation(func_decl * pred) const = 0; + virtual bool is_empty_relation(func_decl* pred) const = 0; + virtual expr_ref try_get_formula(func_decl * pred) const = 0; + virtual void display_output_facts(rule_set const& rules, std::ostream & out) const = 0; + virtual void display_facts(std::ostream & out) const = 0; + virtual void display_profile(std::ostream& out) = 0; + virtual void restrict_predicates(func_decl_set const& predicates) = 0; + virtual bool result_contains_fact(relation_fact const& f) = 0; + virtual void add_fact(func_decl* pred, relation_fact const& fact) = 0; + virtual void add_fact(func_decl* pred, table_fact const& fact) = 0; + virtual bool has_facts(func_decl * pred) const = 0; + virtual void store_relation(func_decl * pred, relation_base * rel) = 0; + virtual void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred) = 0; + virtual void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, + symbol const * relation_names) = 0; + virtual bool output_profile() const = 0; + virtual void collect_non_empty_predicates(func_decl_set& preds) = 0; + virtual void transform_rules() = 0; + virtual bool try_get_size(func_decl* pred, unsigned& rel_sz) const = 0; + virtual lbool saturate() = 0; + }; + class context { public: typedef unsigned finite_element; @@ -93,6 +165,7 @@ namespace datalog { ast_manager & m; + register_engine_base& m_register_engine; smt_params & m_fparams; params_ref m_params_ref; fixedpoint_params m_params; @@ -122,7 +195,7 @@ namespace datalog { model_converter_ref m_mc; proof_converter_ref m_pc; - rel_context* m_rel; + rel_context_base* m_rel; scoped_ptr m_engine; bool m_closed; @@ -143,7 +216,7 @@ namespace datalog { public: - context(ast_manager & m, smt_params& fp, params_ref const& p = params_ref()); + context(ast_manager & m, register_engine_base& re, smt_params& fp, params_ref const& p = params_ref()); ~context(); void reset(); @@ -160,6 +233,7 @@ namespace datalog { smt_params & get_fparams() const { return m_fparams; } fixedpoint_params const& get_params() const { return m_params; } DL_ENGINE get_engine() { configure_engine(); return m_engine_type; } + register_engine_base& get_register_engine() { return m_register_engine; } th_rewriter& get_rewriter() { return m_rewriter; } var_subst & get_var_subst() { return m_var_subst; } dl_decl_util & get_decl_util() { return m_decl_util; } @@ -355,7 +429,6 @@ namespace datalog { proof_converter_ref& get_proof_converter() { return m_pc; } void add_proof_converter(proof_converter* pc) { m_pc = concat(m_pc.get(), pc); } - void transform_rules(); void transform_rules(rule_transformer& transf); void transform_rules(rule_transformer::plugin* plugin); void replace_rules(rule_set const& rs); @@ -371,10 +444,7 @@ namespace datalog { m_rule_set.display(out); } - void display(std::ostream & out) const { - display_rules(out); - if (m_rel) m_rel->display_facts(out); - } + void display(std::ostream & out) const; void display_smt2(unsigned num_queries, expr* const* queries, std::ostream& out); @@ -459,7 +529,7 @@ namespace datalog { */ bool result_contains_fact(relation_fact const& f); - rel_context* get_rel_context() { ensure_engine(); return m_rel; } + rel_context_base* get_rel_context() { ensure_engine(); return m_rel; } private: diff --git a/src/muz/dl_engine_base.h b/src/muz/dl_engine_base.h new file mode 100644 index 000000000..52dc9acd4 --- /dev/null +++ b/src/muz/dl_engine_base.h @@ -0,0 +1,82 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_engine_base.h + +Abstract: + + Base class for Datalog engines. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-08-28 + +Revision History: + +--*/ +#ifndef _DL_ENGINE_BASE_H_ +#define _DL_ENGINE_BASE_H_ + +#include "model.h" + +namespace datalog { + enum DL_ENGINE { + DATALOG_ENGINE, + PDR_ENGINE, + QPDR_ENGINE, + BMC_ENGINE, + QBMC_ENGINE, + TAB_ENGINE, + CLP_ENGINE, + LAST_ENGINE + }; + + class engine_base { + ast_manager& m; + std::string m_name; + public: + engine_base(ast_manager& m, char const* name): m(m), m_name(name) {} + virtual ~engine_base() {} + + virtual expr_ref get_answer() = 0; + virtual lbool query(expr* q) = 0; + virtual lbool query(unsigned num_rels, func_decl*const* rels) { return l_undef; } + + virtual void reset_statistics() {} + virtual void display_profile(std::ostream& out) const {} + virtual void collect_statistics(statistics& st) const {} + virtual unsigned get_num_levels(func_decl* pred) { + throw default_exception(std::string("get_num_levels is not supported for ") + m_name); + } + virtual expr_ref get_cover_delta(int level, func_decl* pred) { + throw default_exception(std::string("operation is not supported for ") + m_name); + } + virtual void add_cover(int level, func_decl* pred, expr* property) { + throw default_exception(std::string("operation is not supported for ") + m_name); + } + virtual void display_certificate(std::ostream& out) const { + throw default_exception(std::string("certificates are not supported for ") + m_name); + } + virtual model_ref get_model() { + return model_ref(alloc(model, m)); + } + virtual proof_ref get_proof() { + return proof_ref(m.mk_asserted(m.mk_true()), m); + } + virtual void updt_params() {} + virtual void cancel() {} + virtual void cleanup() {} + }; + + class context; + + class register_engine_base { + public: + virtual engine_base* mk_engine(DL_ENGINE engine_type) = 0; + virtual void set_context(context* ctx) = 0; + }; +} + +#endif diff --git a/src/muz/dl_external_relation.cpp b/src/muz/dl_external_relation.cpp deleted file mode 100644 index f32509473..000000000 --- a/src/muz/dl_external_relation.cpp +++ /dev/null @@ -1,456 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_external_relation.cpp - -Abstract: - - - -Author: - - Nikolaj Bjorner (nbjorner) 2010-05-10 - -Revision History: - ---*/ - -#include "debug.h" -#include "ast_pp.h" -#include "dl_context.h" -#include "dl_external_relation.h" -#include "dl_decl_plugin.h" - -namespace datalog { - - external_relation::external_relation(external_relation_plugin & p, const relation_signature & s, expr* r) - : relation_base(p, s), - m_rel(r, p.get_ast_manager()), - m_select_fn(p.get_ast_manager()), - m_store_fn(p.get_ast_manager()), - m_is_empty_fn(p.get_ast_manager()) - { - } - - external_relation::~external_relation() { - } - - void external_relation::mk_accessor(decl_kind k, func_decl_ref& fn, const relation_fact& f, bool destructive, expr_ref& res) const { - ast_manager& m = m_rel.get_manager(); - family_id fid = get_plugin().get_family_id(); - ptr_vector args; - args.push_back(m_rel); - for (unsigned i = 0; i < f.size(); ++i) { - args.push_back(f[i]); - } - if (!fn.get()) { - fn = m.mk_func_decl(fid, k, 0, 0, args.size(), args.c_ptr()); - } - if (destructive) { - get_plugin().reduce_assign(fn, args.size(), args.c_ptr(), 1, args.c_ptr()); - res = m_rel; - } - else { - get_plugin().reduce(fn, args.size(), args.c_ptr(), res); - } - } - - bool external_relation::empty() const { - ast_manager& m = m_rel.get_manager(); - expr* r = m_rel.get(); - expr_ref res(m); - if (!m_is_empty_fn.get()) { - family_id fid = get_plugin().get_family_id(); - const_cast(m_is_empty_fn) = m.mk_func_decl(fid, OP_RA_IS_EMPTY, 0, 0, 1, &r); - } - get_plugin().reduce(m_is_empty_fn, 1, &r, res); - return m.is_true(res); - } - - void external_relation::add_fact(const relation_fact & f) { - mk_accessor(OP_RA_STORE, m_store_fn, f, true, m_rel); - } - - bool external_relation::contains_fact(const relation_fact & f) const { - ast_manager& m = get_plugin().get_ast_manager(); - expr_ref res(m); - mk_accessor(OP_RA_SELECT, const_cast(m_select_fn), f, false, res); - return !m.is_false(res); - } - - external_relation * external_relation::clone() const { - ast_manager& m = m_rel.get_manager(); - family_id fid = get_plugin().get_family_id(); - expr* rel = m_rel.get(); - expr_ref res(m.mk_fresh_const("T", m.get_sort(rel)), m); - expr* rel_out = res.get(); - func_decl_ref fn(m.mk_func_decl(fid, OP_RA_CLONE,0,0, 1, &rel), m); - get_plugin().reduce_assign(fn, 1, &rel, 1, &rel_out); - return alloc(external_relation, get_plugin(), get_signature(), res); - } - - external_relation * external_relation::complement(func_decl* p) const { - ast_manager& m = m_rel.get_manager(); - family_id fid = get_plugin().get_family_id(); - expr_ref res(m); - expr* rel = m_rel; - func_decl_ref fn(m.mk_func_decl(fid, OP_RA_COMPLEMENT,0,0, 1, &rel), m); - get_plugin().reduce(fn, 1, &rel, res); - return alloc(external_relation, get_plugin(), get_signature(), res); - } - - void external_relation::display(std::ostream & out) const { - out << mk_pp(m_rel, m_rel.get_manager()) << "\n"; - } - - void external_relation::display_tuples(func_decl & pred, std::ostream & out) const { - display(out); - } - - - external_relation_plugin & external_relation::get_plugin() const { - return static_cast(relation_base::get_plugin()); - } - - - // ----------------------------------- - // - // external_relation_plugin - // - // ----------------------------------- - - - external_relation_plugin::external_relation_plugin(external_relation_context& ctx, relation_manager & m) - : relation_plugin(external_relation_plugin::get_name(), m), m_ext(ctx) {} - - external_relation const & external_relation_plugin::get(relation_base const& r) { - return dynamic_cast(r); - } - - external_relation & external_relation_plugin::get(relation_base & r) { - return dynamic_cast(r); - } - - relation_base * external_relation_plugin::mk_empty(const relation_signature & s) { - ast_manager& m = get_ast_manager(); - sort* r_sort = get_relation_sort(s); - parameter param(r_sort); - family_id fid = get_family_id(); - expr_ref e(m.mk_fresh_const("T", r_sort), m); - expr* args[1] = { e.get() }; - func_decl_ref empty_decl(m.mk_func_decl(fid, OP_RA_EMPTY, 1, ¶m, 0, (sort*const*)0), m); - reduce_assign(empty_decl, 0, 0, 1, args); - return alloc(external_relation, *this, s, e); - } - - sort* external_relation_plugin::get_relation_sort(relation_signature const& sig) { - vector sorts; - ast_manager& m = get_ast_manager(); - family_id fid = get_family_id(); - for (unsigned i = 0; i < sig.size(); ++i) { - sorts.push_back(parameter(sig[i])); - } - return m.mk_sort(fid, DL_RELATION_SORT, sorts.size(), sorts.c_ptr()); - } - - sort* external_relation_plugin::get_column_sort(unsigned col, sort* s) { - SASSERT(s->get_num_parameters() > col); - SASSERT(s->get_parameter(col).is_ast()); - SASSERT(is_sort(s->get_parameter(col).get_ast())); - return to_sort(s->get_parameter(col).get_ast()); - } - - family_id external_relation_plugin::get_family_id() { - return m_ext.get_family_id(); - } - - - void external_relation_plugin::mk_filter_fn(sort* s, app* condition, func_decl_ref& f) { - ast_manager& m = get_ast_manager(); - family_id fid = get_family_id(); - parameter param(condition); - f = m.mk_func_decl(fid, OP_RA_FILTER, 1, ¶m, 1, &s); - } - - class external_relation_plugin::join_fn : public convenient_relation_join_fn { - external_relation_plugin& m_plugin; - func_decl_ref m_join_fn; - expr* m_args[2]; - public: - join_fn(external_relation_plugin& p, const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2) - : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2), - m_plugin(p), - m_join_fn(p.get_ast_manager()) { - ast_manager& m = p.get_ast_manager(); - family_id fid = p.get_family_id(); - vector params; - for (unsigned i = 0; i < col_cnt; ++i) { - params.push_back(parameter(cols1[i])); - params.push_back(parameter(cols2[i])); - } - sort* domain[2] = { p.get_relation_sort(o1_sig), p.get_relation_sort(o2_sig) }; - m_join_fn = m.mk_func_decl(fid, OP_RA_JOIN, params.size(), params.c_ptr(), 2, domain); - } - - virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { - expr_ref res(m_plugin.get_ast_manager()); - m_args[0] = get(r1).get_relation(); - m_args[1] = get(r2).get_relation(); - m_plugin.reduce(m_join_fn, 2, m_args, res); - return alloc(external_relation, m_plugin, get_result_signature(), res); - } - }; - - relation_join_fn * external_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (!check_kind(r1) || !check_kind(r2)) { - return 0; - } - return alloc(join_fn, *this, r1.get_signature(), r2.get_signature() , col_cnt, cols1, cols2); - } - - - class external_relation_plugin::project_fn : public convenient_relation_project_fn { - external_relation_plugin& m_plugin; - func_decl_ref m_project_fn; - public: - project_fn(external_relation_plugin& p, sort* relation_sort, - const relation_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) - : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols), - m_plugin(p), - m_project_fn(p.get_ast_manager()) { - vector params; - ast_manager& m = p.get_ast_manager(); - family_id fid = p.get_family_id(); - for (unsigned i = 0; i < removed_col_cnt; ++i) { - params.push_back(parameter(removed_cols[i])); - } - m_project_fn = m.mk_func_decl(fid, OP_RA_PROJECT, params.size(), params.c_ptr(), 1, &relation_sort); - } - - virtual relation_base * operator()(const relation_base & r) { - expr_ref res(m_plugin.get_ast_manager()); - expr* rel = get(r).get_relation(); - m_plugin.reduce(m_project_fn, 1, &rel, res); - return alloc(external_relation, m_plugin, get_result_signature(), to_app(res)); - } - }; - - relation_transformer_fn * external_relation_plugin::mk_project_fn(const relation_base & r, - unsigned col_cnt, const unsigned * removed_cols) { - return alloc(project_fn, *this, get(r).get_sort(), r.get_signature(), col_cnt, removed_cols); - } - - - class external_relation_plugin::rename_fn : public convenient_relation_rename_fn { - external_relation_plugin& m_plugin; - func_decl_ref m_rename_fn; - expr* m_args[2]; - public: - rename_fn(external_relation_plugin& p, sort* relation_sort, const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) - : convenient_relation_rename_fn(orig_sig, cycle_len, cycle), - m_plugin(p), - m_rename_fn(p.get_ast_manager()) { - - ast_manager& m = p.get_ast_manager(); - family_id fid = p.get_family_id(); - vector params; - for (unsigned i = 0; i < cycle_len; ++i) { - SASSERT(cycle[i] < orig_sig.size()); - params.push_back(parameter(cycle[i])); - } - m_rename_fn = m.mk_func_decl(fid, OP_RA_RENAME, params.size(), params.c_ptr(), 1, &relation_sort); - } - - virtual relation_base * operator()(const relation_base & r) { - expr* rel = get(r).get_relation(); - expr_ref res(m_plugin.get_ast_manager()); - m_args[0] = rel; - m_plugin.reduce(m_rename_fn, 1, &rel, res); - return alloc(external_relation, m_plugin, get_result_signature(), res); - } - }; - - relation_transformer_fn * external_relation_plugin::mk_rename_fn(const relation_base & r, - unsigned cycle_len, const unsigned * permutation_cycle) { - if(!check_kind(r)) { - return 0; - } - return alloc(rename_fn, *this, get(r).get_sort(), r.get_signature(), cycle_len, permutation_cycle); - } - - - class external_relation_plugin::union_fn : public relation_union_fn { - external_relation_plugin& m_plugin; - func_decl_ref m_union_fn; - expr* m_args[2]; - expr* m_outs[2]; - - public: - union_fn(external_relation_plugin& p, decl_kind k, sort* relation_sort): - m_plugin(p), - m_union_fn(p.get_ast_manager()) { - ast_manager& m = p.get_ast_manager(); - sort* domain[2] = { relation_sort, relation_sort }; - m_union_fn = m.mk_func_decl(p.get_family_id(), k, 0, 0, 2, domain); - } - - virtual void operator()(relation_base & r, const relation_base & src, relation_base * delta) { - ast_manager& m = m_plugin.get_ast_manager(); - expr_ref_vector res(m); - m_args[0] = get(r).get_relation(); - m_args[1] = get(src).get_relation(); - m_outs[0] = m_args[0]; - unsigned num_out = 1; - if (delta) { - m_outs[1] = get(*delta).get_relation(); - ++num_out; - } - m_plugin.reduce_assign(m_union_fn, 2, m_args, num_out, m_outs); - } - }; - - relation_union_fn * external_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; - } - return alloc(union_fn, *this, OP_RA_UNION, get(src).get_sort()); - } - - relation_union_fn * external_relation_plugin::mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; - } - return alloc(union_fn, *this, OP_RA_WIDEN, get(src).get_sort()); - } - - class external_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { - external_relation_plugin& m_plugin; - app_ref m_condition; - func_decl_ref m_filter_fn; - public: - filter_interpreted_fn(external_relation_plugin& p, sort* relation_sort, app * condition) - : 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)); - } - - virtual void operator()(relation_base & r) { - SASSERT(m_plugin.check_kind(r)); - expr* arg = get(r).get_relation(); - m_plugin.reduce_assign(m_filter_fn, 1, &arg, 1, &arg); - } - }; - - relation_mutator_fn * external_relation_plugin::mk_filter_interpreted_fn(const relation_base & r, app * condition) { - if(!check_kind(r)) { - return 0; - } - return alloc(filter_interpreted_fn, *this, get(r).get_sort(), condition); - } - - relation_mutator_fn * external_relation_plugin::mk_filter_equal_fn(const relation_base & r, - const relation_element & value, unsigned col) { - if(!check_kind(r)) { - return 0; - } - ast_manager& m = get_ast_manager(); - app_ref condition(m); - expr_ref var(m); - sort* relation_sort = get(r).get_sort(); - sort* column_sort = get_column_sort(col, relation_sort); - var = m.mk_var(col, column_sort); - condition = m.mk_eq(var, value); - return mk_filter_interpreted_fn(r, condition); - } - - class external_relation_plugin::filter_identical_fn : public relation_mutator_fn { - external_relation_plugin& m_plugin; - func_decl_ref_vector m_filter_fn; - public: - filter_identical_fn(external_relation_plugin& p, sort* relation_sort, - unsigned col_cnt, const unsigned * identical_cols) - : m_plugin(p), m_filter_fn(p.get_ast_manager()) { - ast_manager& m = p.get_ast_manager(); - func_decl_ref fn(m); - app_ref eq(m); - if (col_cnt <= 1) { - return; - } - unsigned col = identical_cols[0]; - sort* s = p.get_column_sort(col, relation_sort); - var* v0 = m.mk_var(col, s); - for (unsigned i = 1; i < col_cnt; ++i) { - col = identical_cols[i]; - s = p.get_column_sort(col, relation_sort); - eq = m.mk_eq(v0, m.mk_var(col, s)); - p.mk_filter_fn(relation_sort, eq.get(), fn); - m_filter_fn.push_back(fn); - } - } - - virtual void operator()(relation_base & r) { - expr* r0 = get(r).get_relation(); - for (unsigned i = 0; i < m_filter_fn.size(); ++i) { - m_plugin.reduce_assign(m_filter_fn[i].get(), 1, &r0, 1, &r0); - } - } - }; - - relation_mutator_fn * external_relation_plugin::mk_filter_identical_fn(const relation_base & r, - unsigned col_cnt, const unsigned * identical_cols) { - if (!check_kind(r)) { - return 0; - } - return alloc(filter_identical_fn, *this, get(r).get_sort(), col_cnt, identical_cols); - } - - - class external_relation_plugin::negation_filter_fn : public convenient_relation_negation_filter_fn { - external_relation_plugin& m_plugin; - func_decl_ref m_negated_filter_fn; - expr* m_args[2]; - public: - negation_filter_fn(external_relation_plugin& p, - const relation_base & tgt, const relation_base & neg_t, - unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) : - convenient_negation_filter_fn(tgt, neg_t, joined_col_cnt, t_cols, negated_cols), - m_plugin(p), - m_negated_filter_fn(p.get_ast_manager()) - { - ast_manager& m = p.get_ast_manager(); - family_id fid = p.get_family_id(); - vector params; - for (unsigned i = 0; i < joined_col_cnt; ++i) { - params.push_back(parameter(t_cols[i])); - params.push_back(parameter(negated_cols[i])); - } - sort* domain[2] = { get(tgt).get_sort(), get(neg_t).get_sort() }; - m_negated_filter_fn = m.mk_func_decl(fid, OP_RA_NEGATION_FILTER, params.size(), params.c_ptr(), 2, domain); - } - - void operator()(relation_base & t, const relation_base & negated_obj) { - m_args[0] = get(t).get_relation(); - m_args[1] = get(negated_obj).get_relation(); - m_plugin.reduce_assign(m_negated_filter_fn.get(), 2, m_args, 1, m_args); - } - }; - - relation_intersection_filter_fn * external_relation_plugin::mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols) { - if (!check_kind(t) || !check_kind(negated_obj)) { - return 0; - } - return alloc(negation_filter_fn, *this, t, negated_obj, joined_col_cnt, t_cols, negated_cols); - } - -}; diff --git a/src/muz/dl_external_relation.h b/src/muz/dl_external_relation.h deleted file mode 100644 index 03838ecc4..000000000 --- a/src/muz/dl_external_relation.h +++ /dev/null @@ -1,154 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_external_relation.h - -Abstract: - - - -Author: - - Nikolaj Bjorner (nbjorner) 2010-05-10 - -Revision History: - ---*/ -#ifndef _DL_EXTERNAL_RELATION_H_ -#define _DL_EXTERNAL_RELATION_H_ - -#include "dl_base.h" - -namespace datalog { - - class external_relation; - - class external_relation_context { - public: - virtual ~external_relation_context() {} - - virtual family_id get_family_id() const = 0; - - // reduce arguments. - virtual void reduce(func_decl* f, unsigned num_args, expr * const* args, expr_ref& result) = 0; - - // overwrite terms passed in outs vector with values computed by function. - virtual void reduce_assign(func_decl* f, unsigned num_args, expr * const* args, unsigned num_out, expr* const* outs) = 0; - }; - - class external_relation_plugin : public relation_plugin { - - friend class external_relation; - class join_fn; - class project_fn; - class rename_fn; - class union_fn; - class filter_identical_fn; - class filter_interpreted_fn; - class negation_filter_fn; - - external_relation_context& m_ext; - - public: - external_relation_plugin(external_relation_context& ctx, relation_manager & m); - - virtual bool can_handle_signature(const relation_signature & s) { return true; } - - static symbol get_name() { return symbol("external_relation"); } - - virtual relation_base * mk_empty(const relation_signature & s); - - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); - - private: - - static external_relation& get(relation_base& r); - static external_relation const & get(relation_base const& r); - - void reduce(func_decl* f, unsigned num_args, expr * const* args, expr_ref& result) { - m_ext.reduce(f, num_args, args, result); - } - - void reduce_assign(func_decl* f, unsigned num_args, expr * const* args, unsigned num_out, expr* const* outs) { - m_ext.reduce_assign(f, num_args, args, num_out, outs); - } - - sort* get_relation_sort(relation_signature const& sig); - - sort* get_column_sort(unsigned col, sort* relation_sort); - - void mk_filter_fn(sort* s, app* condition, func_decl_ref& f); - - family_id get_family_id(); - }; - - class external_relation : public relation_base { - friend class external_relation_plugin; - friend class external_relation_plugin::join_fn; - friend class external_relation_plugin::project_fn; - friend class external_relation_plugin::rename_fn; - friend class external_relation_plugin::union_fn; - friend class external_relation_plugin::filter_identical_fn; - friend class external_relation_plugin::filter_interpreted_fn; - friend class external_relation_plugin::negation_filter_fn; - - expr_ref m_rel; - func_decl_ref m_select_fn; - func_decl_ref m_store_fn; - func_decl_ref m_is_empty_fn; - - unsigned size() const { return get_signature().size(); } - - sort* get_sort() const { return m_rel.get_manager().get_sort(m_rel); } - - void mk_accessor(decl_kind k, func_decl_ref& fn, const relation_fact& f, bool destructive, expr_ref& res) const; - - external_relation(external_relation_plugin & p, const relation_signature & s, expr* r); - virtual ~external_relation(); - - public: - external_relation_plugin & get_plugin() const; - - virtual bool empty() const; - - virtual void add_fact(const relation_fact & f); - - virtual bool contains_fact(const relation_fact & f) const; - - virtual external_relation * clone() const; - - virtual external_relation * complement(func_decl*) const; - - virtual void display(std::ostream & out) const; - - virtual void display_tuples(func_decl & pred, std::ostream & out) const; - - expr* get_relation() const { return m_rel.get(); } - - virtual void to_formula(expr_ref& fml) const { fml = get_relation(); } - - }; - - -}; - -#endif diff --git a/src/muz/dl_finite_product_relation.cpp b/src/muz/dl_finite_product_relation.cpp deleted file mode 100644 index 86fef433b..000000000 --- a/src/muz/dl_finite_product_relation.cpp +++ /dev/null @@ -1,2377 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_finite_product_relation.cpp - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-14. - -Revision History: - ---*/ - - -#include -#include"dl_context.h" -#include"dl_relation_manager.h" -#include"dl_table_relation.h" -#include"dl_finite_product_relation.h" -#include"bool_rewriter.h" - -namespace datalog { - - //static variables - - const table_sort finite_product_relation::s_rel_idx_sort = INT_MAX; - - void universal_delete(finite_product_relation* ptr) { - ptr->deallocate(); - } - - - // ----------------------------------- - // - // finite_product_relation_plugin - // - // ----------------------------------- - - finite_product_relation & finite_product_relation_plugin::get(relation_base & r) { - SASSERT(r.get_plugin().is_finite_product_relation()); - return static_cast(r); - } - - const finite_product_relation & finite_product_relation_plugin::get(const relation_base & r) { - SASSERT(r.get_plugin().is_finite_product_relation()); - return static_cast(r); - } - - finite_product_relation * finite_product_relation_plugin::get(relation_base * r) { - SASSERT(!r || r->get_plugin().is_finite_product_relation()); - return static_cast(r); - } - - const finite_product_relation * finite_product_relation_plugin::get(const relation_base * r) { - SASSERT(!r || r->get_plugin().is_finite_product_relation()); - return static_cast(r); - } - - symbol finite_product_relation_plugin::get_name(relation_plugin & inner_plugin) { - std::string str = std::string("fpr_")+inner_plugin.get_name().bare_str(); - return symbol(str.c_str()); - } - - finite_product_relation_plugin & finite_product_relation_plugin::get_plugin(relation_manager & rmgr, - relation_plugin & inner) { - finite_product_relation_plugin * res; - if(!rmgr.try_get_finite_product_relation_plugin(inner, res)) { - res = alloc(finite_product_relation_plugin, inner, rmgr); - rmgr.register_plugin(res); - } - return *res; - } - - finite_product_relation_plugin::finite_product_relation_plugin(relation_plugin & inner_plugin, - relation_manager & manager) - : relation_plugin(get_name(inner_plugin), manager, ST_FINITE_PRODUCT_RELATION), - m_inner_plugin(inner_plugin), m_spec_store(*this) { - } - - void finite_product_relation_plugin::initialize(family_id fid) { - relation_plugin::initialize(fid); - m_spec_store.add_available_kind(get_kind()); - } - - family_id finite_product_relation_plugin::get_relation_kind(finite_product_relation & r, - const bool * table_columns) { - const relation_signature & sig = r.get_signature(); - svector table_cols_vect(sig.size(), table_columns); - return m_spec_store.get_relation_kind(sig, rel_spec(table_cols_vect)); - } - - void finite_product_relation_plugin::get_all_possible_table_columns(relation_manager & rmgr, - const relation_signature & s, svector & table_columns) { - SASSERT(table_columns.empty()); - unsigned s_sz = s.size(); - for(unsigned i=0; i table_columns; - get_all_possible_table_columns(s, table_columns); -#ifndef _EXTERNAL_RELEASE - unsigned s_sz = s.size(); - unsigned rel_col_cnt = 0; - for(unsigned i=0; icomplement_self(p); - return res; - } - - bool finite_product_relation_plugin::can_convert_to_table_relation(const finite_product_relation & r) { - return r.m_other_sig.empty(); - } - - table_relation * finite_product_relation_plugin::to_table_relation(const finite_product_relation & r) { - SASSERT(can_convert_to_table_relation(r)); - r.garbage_collect(true); - //now all rows in the table will correspond to rows in the resulting table_relation - - const table_base & t = r.get_table(); - - unsigned removed_col = t.get_signature().size()-1; - scoped_ptr project_fun = - get_manager().mk_project_fn(r.get_table(), 1, &removed_col); - - table_base * res_table = (*project_fun)(t); - SASSERT(res_table->get_signature().functional_columns()==0); - return static_cast(get_manager().mk_table_relation(r.get_signature(), res_table)); - } - - - bool finite_product_relation_plugin::can_be_converted(const relation_base & r) { - if(&r.get_plugin()==&get_inner_plugin()) { - //can be converted by mk_from_inner_relation - return true; - } - if(r.from_table()) { - //We can convert directly from table plugin only if the inner plugin can handle empty signatures. - - //TODO: If the inner plugin cannot handle empty signatures, we may try to move some of the - //table columns into the inner relation signature. - return get_inner_plugin().can_handle_signature(relation_signature()); - } - return false; - } - - finite_product_relation * finite_product_relation_plugin::mk_from_table_relation(const table_relation & r) { - func_decl* pred = 0; - const relation_signature & sig = r.get_signature(); - const table_base & t = r.get_table(); - table_plugin & tplugin = r.get_table().get_plugin(); - - relation_signature inner_sig; //empty signature for the inner relation - if(!get_inner_plugin().can_handle_signature(inner_sig)) { - return 0; - } - - table_signature idx_singleton_sig; - idx_singleton_sig.push_back(finite_product_relation::s_rel_idx_sort); - idx_singleton_sig.set_functional_columns(1); - - scoped_rel idx_singleton; - if(tplugin.can_handle_signature(idx_singleton_sig)) { - idx_singleton = tplugin.mk_empty(idx_singleton_sig); - } - else { - idx_singleton = get_manager().mk_empty_table(idx_singleton_sig); - } - table_fact idx_singleton_fact; - idx_singleton_fact.push_back(0); - idx_singleton->add_fact(idx_singleton_fact); - - scoped_ptr join_fun = get_manager().mk_join_fn(t, *idx_singleton, 0, 0, 0); - SASSERT(join_fun); - scoped_rel res_table = (*join_fun)(t, *idx_singleton); - - svector table_cols(sig.size(), true); - finite_product_relation * res = mk_empty(sig, table_cols.c_ptr()); - - //this one does not need to be deleted -- it will be taken over by \c res in the \c init function - relation_base * inner_rel = get_inner_plugin().mk_full(pred, inner_sig, get_inner_plugin().get_kind()); - - relation_vector rels; - rels.push_back(inner_rel); - - res->init(*res_table, rels, true); - return res; - } - - finite_product_relation * finite_product_relation_plugin::mk_from_inner_relation(const relation_base & r) { - SASSERT(&r.get_plugin()==&get_inner_plugin()); - const relation_signature & sig = r.get_signature(); - - table_signature idx_singleton_sig; - idx_singleton_sig.push_back(finite_product_relation::s_rel_idx_sort); - idx_singleton_sig.set_functional_columns(1); - - scoped_rel idx_singleton = get_manager().mk_empty_table(idx_singleton_sig); - table_fact idx_singleton_fact; - idx_singleton_fact.push_back(0); - idx_singleton->add_fact(idx_singleton_fact); - - svector table_cols(sig.size(), false); - finite_product_relation * res = mk_empty(sig, table_cols.c_ptr()); - - relation_vector rels; - rels.push_back(r.clone()); - - res->init(*idx_singleton, rels, true); - return res; - } - - class finite_product_relation_plugin::converting_join_fn : public convenient_relation_join_fn { - finite_product_relation_plugin & m_plugin; - scoped_ptr m_native_join; - - finite_product_relation * convert(const relation_base & r) { - SASSERT(&r.get_plugin()!=&m_plugin); - if(&r.get_plugin()==&m_plugin.get_inner_plugin()) { - return m_plugin.mk_from_inner_relation(r); - } - SASSERT(r.from_table()); - const table_relation & tr = static_cast(r); - finite_product_relation * res = m_plugin.mk_from_table_relation(tr); - SASSERT(res); - return res; - } - - public: - converting_join_fn(finite_product_relation_plugin & plugin, const relation_signature & sig1, - const relation_signature & sig2, unsigned col_cnt, const unsigned * cols1, - const unsigned * cols2) - : convenient_relation_join_fn(sig1, sig2, col_cnt, cols1, cols2), - m_plugin(plugin) {} - - virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { - scoped_rel r1_conv; - if(&r1.get_plugin()!=&m_plugin) { - r1_conv = convert(r1); - } - scoped_rel r2_conv; - if(&r2.get_plugin()!=&m_plugin) { - r2_conv = convert(r2); - } - - const finite_product_relation & fpr1 = r1_conv ? *r1_conv : get(r1); - const finite_product_relation & fpr2 = r2_conv ? *r2_conv : get(r2); - - SASSERT(&fpr1.get_plugin()==&m_plugin); - SASSERT(&fpr2.get_plugin()==&m_plugin); - - if(!m_native_join) { - m_native_join = m_plugin.get_manager().mk_join_fn(fpr1, fpr2, m_cols1, m_cols2, false); - } - return (*m_native_join)(fpr1, fpr2); - } - }; - - - class finite_product_relation_plugin::join_fn : public convenient_relation_join_fn { - scoped_ptr m_tjoin_fn; - scoped_ptr m_rjoin_fn; - - unsigned_vector m_t_joined_cols1; - unsigned_vector m_t_joined_cols2; - unsigned_vector m_r_joined_cols1; - unsigned_vector m_r_joined_cols2; - - //Column equalities betweet table and inner relations. - //The columns numbers correspont to the columns of the table/inner relation - //in the result of the join operation - unsigned_vector m_tr_table_joined_cols; - unsigned_vector m_tr_rel_joined_cols; - - scoped_ptr m_filter_tr_identities; - - scoped_ptr m_tjoined_second_rel_remover; - - //determines which columns of the result are table columns and which are in the inner relation - svector m_res_table_columns; - - public: - class join_maker : public table_row_mutator_fn { - join_fn & m_parent; - const finite_product_relation & m_r1; - const finite_product_relation & m_r2; - relation_vector & m_rjoins; - public: - join_maker(join_fn & parent, const finite_product_relation & r1, const finite_product_relation & r2, - relation_vector & rjoins) - : m_parent(parent), m_r1(r1), m_r2(r2), m_rjoins(rjoins) {} - - virtual bool operator()(table_element * func_columns) { - const relation_base & or1 = m_r1.get_inner_rel(func_columns[0]); - const relation_base & or2 = m_r2.get_inner_rel(func_columns[1]); - SASSERT(&or1); - SASSERT(&or2); - unsigned new_rel_num = m_rjoins.size(); - m_rjoins.push_back(m_parent.do_rjoin(or1, or2)); - func_columns[0]=new_rel_num; - return true; - } - }; - - join_fn(const finite_product_relation & r1, const finite_product_relation & r2, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2) - : convenient_relation_join_fn(r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2) { - unsigned second_table_after_join_ofs = r1.m_table2sig.size(); - unsigned second_inner_rel_after_join_ofs = r1.m_other2sig.size(); - for(unsigned i=0;i tjoined = (*m_tjoin_fn)(r1.get_table(), r2.get_table()); - - relation_vector joined_orelations; - - { - join_maker * mutator = alloc(join_maker, *this, r1, r2, joined_orelations); //dealocated in inner_join_mapper - scoped_ptr inner_join_mapper = rmgr.mk_map_fn(*tjoined, mutator); - (*inner_join_mapper)(*tjoined); - } - - - if(!m_tjoined_second_rel_remover) { - unsigned removed_col = tjoined->get_signature().size()-1; - m_tjoined_second_rel_remover = rmgr.mk_project_fn(*tjoined, 1, &removed_col); - } - //remove the second functional column from tjoined to get a table that corresponds - //to the table signature of the resulting relation - scoped_rel res_table = (*m_tjoined_second_rel_remover)(*tjoined); - - relation_plugin & res_oplugin = - joined_orelations.empty() ? r1.m_other_plugin : joined_orelations.back()->get_plugin(); - - //TODO: Maybe we might want to specify a particular relation kind, instead of just null_family_id. - //It would however need to be somehow inferred for the new signature. - - finite_product_relation * res = alloc(finite_product_relation, r1.get_plugin(), get_result_signature(), - m_res_table_columns.c_ptr(), res_table->get_plugin(), res_oplugin, null_family_id); - - res->init(*res_table, joined_orelations, true); - - if(m_tr_table_joined_cols.size()) { - //There were some shared variables between the table and the relation part. - //We enforce those equalities here. - if(!m_filter_tr_identities) { - m_filter_tr_identities = plugin.mk_filter_identical_pairs(*res, m_tr_table_joined_cols.size(), - m_tr_table_joined_cols.c_ptr(), m_tr_rel_joined_cols.c_ptr()); - SASSERT(m_filter_tr_identities); - } - (*m_filter_tr_identities)(*res); - } - return res; - } - }; - - - - - relation_join_fn * finite_product_relation_plugin::mk_join_fn(const relation_base & rb1, const relation_base & rb2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if(!check_kind(rb1) || !check_kind(rb2)) { - bool r1foreign = &rb1.get_plugin()!=this; - bool r2foreign = &rb2.get_plugin()!=this; - if( (!r1foreign || can_be_converted(rb1)) && (!r2foreign || can_be_converted(rb2))) { - return alloc(converting_join_fn, *this, rb1.get_signature(), rb2.get_signature(), col_cnt, cols1, - cols2); - } - return 0; - } - const finite_product_relation & r1 = get(rb1); - const finite_product_relation & r2 = get(rb2); - - return alloc(join_fn, r1, r2, col_cnt, cols1, cols2); - } - - - class finite_product_relation_plugin::project_fn : public convenient_relation_project_fn { - unsigned_vector m_removed_table_cols; - unsigned_vector m_removed_rel_cols; - - scoped_ptr m_rel_projector; - scoped_ptr m_inner_rel_union; - - //determines which columns of the result are table columns and which are in the inner relation - svector m_res_table_columns; - public: - project_fn(const finite_product_relation & r, unsigned col_cnt, const unsigned * removed_cols) - : convenient_relation_project_fn(r.get_signature(), col_cnt, removed_cols) { - SASSERT(col_cnt>0); - for(unsigned i=0; ii); - m_res_table_columns.push_back(r.is_table_column(i)); - } - } - - class project_reducer : public table_row_pair_reduce_fn { - project_fn & m_parent; - relation_vector & m_relations; - public: - - project_reducer(project_fn & parent, relation_vector & relations) - : m_parent(parent), m_relations(relations) {} - - virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) { - relation_base * tgt = m_relations[static_cast(func_columns[0])]->clone(); - relation_base & src = *m_relations[static_cast(merged_func_columns[0])]; - if(!m_parent.m_inner_rel_union) { - m_parent.m_inner_rel_union = tgt->get_manager().mk_union_fn(*tgt, src); - } - (*m_parent.m_inner_rel_union)(*tgt, src); - - unsigned new_idx = m_relations.size(); - m_relations.push_back(tgt); - func_columns[0] = new_idx; - } - }; - - virtual relation_base * operator()(const relation_base & rb) { - const finite_product_relation & r = get(rb); - finite_product_relation_plugin & plugin = r.get_plugin(); - const table_base & rtable = r.get_table(); - relation_manager & rmgr = plugin.get_manager(); - - r.garbage_collect(false); - relation_vector res_relations; - unsigned orig_rel_cnt = r.m_others.size(); - for(unsigned i=0; iclone() : 0); - } - SASSERT(res_relations.size()==orig_rel_cnt); - - bool shared_res_table = false; - const table_base * res_table; - - if(m_removed_table_cols.empty()) { - shared_res_table = true; - res_table = &rtable; - } - else { - project_reducer * preducer = alloc(project_reducer, *this, res_relations); - scoped_ptr tproject = - rmgr.mk_project_with_reduce_fn(rtable, m_removed_table_cols.size(), m_removed_table_cols.c_ptr(), preducer); - res_table = (*tproject)(rtable); - } - - relation_plugin * res_oplugin = 0; - - if(!m_removed_rel_cols.empty()) { - unsigned res_rel_cnt = res_relations.size(); - for(unsigned i=0; ideallocate(); - if(!res_oplugin) { - res_oplugin = &res_relations[i]->get_plugin(); - } - } - } - - if(!res_oplugin) { - res_oplugin = &r.m_other_plugin; - } - - //TODO: Maybe we might want to specify a particular relation kind, instead of just null_family_id. - //It would however need to be somehow inferred for the new signature. - - finite_product_relation * res = alloc(finite_product_relation, r.get_plugin(), get_result_signature(), - m_res_table_columns.c_ptr(), res_table->get_plugin(), *res_oplugin, null_family_id); - - res->init(*res_table, res_relations, false); - - if(!shared_res_table) { - const_cast(res_table)->deallocate(); - } - - return res; - } - }; - - relation_transformer_fn * finite_product_relation_plugin::mk_project_fn(const relation_base & rb, unsigned col_cnt, - const unsigned * removed_cols) { - if(&rb.get_plugin()!=this) { - return 0; - } - return alloc(project_fn, get(rb), col_cnt, removed_cols); - } - - - - class finite_product_relation_plugin::rename_fn : public convenient_relation_rename_fn { - scoped_ptr m_table_renamer; - scoped_ptr m_rel_renamer; - bool m_rel_identity; - - unsigned_vector m_rel_permutation; - - //determines which columns of the result are table columns and which are in the inner relation - svector m_res_table_columns; - public: - rename_fn(const finite_product_relation & r, unsigned cycle_len, const unsigned * permutation_cycle) - : convenient_relation_rename_fn(r.get_signature(), cycle_len, permutation_cycle) { - SASSERT(cycle_len>1); - - unsigned sig_sz = r.get_signature().size(); - unsigned_vector permutation; - add_sequence(0, sig_sz, permutation); - permutate_by_cycle(permutation, cycle_len, permutation_cycle); - - unsigned_vector table_permutation; - - bool table_identity = true; - m_rel_identity = true; - for(unsigned new_i=0; new_iclone() : 0); - } - - if(!m_rel_identity) { - unsigned res_rel_cnt = res_relations.size(); - for(unsigned i=0; i inner_rel = res_relations[i]; - if(!m_rel_renamer) { - m_rel_renamer = r.get_manager().mk_permutation_rename_fn(*inner_rel, m_rel_permutation); - } - - res_relations[i] = (*m_rel_renamer)(*inner_rel); - } - } - scoped_rel res_table_scoped; - const table_base * res_table = &rtable; - - if(m_table_renamer) { - res_table_scoped = (*m_table_renamer)(*res_table); - res_table = res_table_scoped.get(); - } - - //TODO: Maybe we might want to specify a particular relation kind, instead of just null_family_id. - //It would however need to be somehow inferred for the new signature. - - finite_product_relation * res = alloc(finite_product_relation, r.get_plugin(), get_result_signature(), - m_res_table_columns.c_ptr(), res_table->get_plugin(), r.m_other_plugin, null_family_id); - - res->init(*res_table, res_relations, false); - - return res; - } - }; - - relation_transformer_fn * finite_product_relation_plugin::mk_rename_fn(const relation_base & rb, - unsigned permutation_cycle_len, const unsigned * permutation_cycle) { - - if(&rb.get_plugin()!=this) { - return 0; - } - const finite_product_relation & r = get(rb); - return alloc(rename_fn, r, permutation_cycle_len, permutation_cycle); - } - - - class finite_product_relation_plugin::union_fn : public relation_union_fn { - bool m_use_delta; - unsigned_vector m_data_cols;//non-functional columns in the product-relation table (useful for creating operations) - scoped_ptr m_common_join; //result of the join contains (data columns), tgt_rel_idx, src_rel_idx - scoped_ptr m_rel_union; - scoped_ptr m_table_union; - scoped_ptr m_remove_overlaps; - scoped_ptr m_remove_src_column_from_overlap; - - //this one is populated only if we're doing union with delta - scoped_ptr m_delta_merging_union; - - scoped_ptr m_overlap_delta_table_builder; - public: - union_fn(const finite_product_relation & tgt, bool use_delta) : m_use_delta(use_delta) {} - - relation_union_fn & get_inner_rel_union_op(relation_base & r) { - if(!m_rel_union) { - m_rel_union = r.get_manager().mk_union_fn(r, r, m_use_delta ? &r : 0); - } - return *m_rel_union; - } - - class union_mapper : public table_row_mutator_fn { - union_fn & m_parent; - finite_product_relation & m_tgt; - const finite_product_relation & m_src; - table_base * m_delta_indexes; //table with signature (updated tgt rel index, delta_index in m_delta_rels) - relation_vector * m_delta_rels; - table_fact m_di_fact; //auxiliary fact for inserting into \c m_delta_indexes - public: - /** - If \c delta_indexes is 0, it means we are not collecting indexes. - */ - union_mapper(union_fn & parent, finite_product_relation & tgt, const finite_product_relation & src, - table_base * delta_indexes, relation_vector * delta_rels) - : m_parent(parent), - m_tgt(tgt), - m_src(src), - m_delta_indexes(delta_indexes), - m_delta_rels(delta_rels) {} - - virtual ~union_mapper() {} - - virtual bool operator()(table_element * func_columns) { - relation_base & otgt_orig = m_tgt.get_inner_rel(func_columns[0]); - const relation_base & osrc = m_src.get_inner_rel(func_columns[1]); - - relation_base * otgt = otgt_orig.clone(); - unsigned new_tgt_idx = m_tgt.get_next_rel_idx(); - m_tgt.set_inner_rel(new_tgt_idx, otgt); - if(m_delta_indexes) { - relation_base * odelta = otgt->get_plugin().mk_empty(otgt->get_signature()); - m_parent.get_inner_rel_union_op(*otgt)(*otgt, osrc, odelta); - - unsigned delta_idx = m_delta_rels->size(); - m_delta_rels->push_back(odelta); - m_di_fact.reset(); - m_di_fact.push_back(new_tgt_idx); - m_di_fact.push_back(delta_idx); - m_delta_indexes->add_fact(m_di_fact); - } - else { - m_parent.get_inner_rel_union_op(*otgt)(*otgt, osrc); - } - - func_columns[0]=new_tgt_idx; - return true; - } - }; - - /** - Makes a table whose last column has indexes to relations in \c src into a table - with indexes to relation \c tgt. - */ - class src_copying_mapper : public table_row_mutator_fn { - finite_product_relation & m_tgt; - const finite_product_relation & m_src; - public: - /** - If \c delta_indexes is 0, it means we are not collecting indexes. - */ - src_copying_mapper(finite_product_relation & tgt, const finite_product_relation & src) - : m_tgt(tgt), m_src(src) {} - - virtual bool operator()(table_element * func_columns) { - const relation_base & osrc = m_src.get_inner_rel(func_columns[0]); - unsigned new_tgt_idx = m_tgt.get_next_rel_idx(); - m_tgt.set_inner_rel(new_tgt_idx, osrc.clone()); - func_columns[0]=new_tgt_idx; - return true; - } - }; - - virtual void operator()(relation_base & tgtb, const relation_base & srcb, relation_base * deltab) { - finite_product_relation & tgt = get(tgtb); - const finite_product_relation & src0 = get(srcb); - finite_product_relation * delta = get(deltab); - - relation_manager & rmgr = tgt.get_manager(); - - scoped_rel src_aux_copy; //copy of src in case its specification needs to be modified - - if(!vectors_equal(tgt.m_table2sig, src0.m_table2sig) - || (delta && !vectors_equal(tgt.m_table2sig, delta->m_table2sig)) ) { - src_aux_copy = src0.clone(); - ptr_vector orig_rels; - orig_rels.push_back(src_aux_copy.get()); - orig_rels.push_back(&tgt); - if(delta) { - orig_rels.push_back(delta); - } - if(!finite_product_relation::try_unify_specifications(orig_rels)) { - throw default_exception("finite_product_relation union: cannot convert relations to common specification"); - } - } - - const finite_product_relation & src = src_aux_copy ? *src_aux_copy : src0; - - table_plugin & tplugin = tgt.get_table_plugin(); - - if(!m_common_join) { - unsigned data_cols_cnt = tgt.m_table_sig.size()-1; - for(unsigned i=0; i table_overlap = (*m_common_join)(tgt.get_table(), src.get_table()); - - scoped_rel delta_indexes; - relation_vector delta_rels; - if(m_use_delta) { - table_signature di_sig; - di_sig.push_back(finite_product_relation::s_rel_idx_sort); - di_sig.push_back(finite_product_relation::s_rel_idx_sort); - di_sig.set_functional_columns(1); - delta_indexes = tplugin.mk_empty(di_sig); - } - - { - union_mapper * umapper = alloc(union_mapper, *this, tgt, src, delta_indexes.get(), &delta_rels); - scoped_ptr mapping_fn = rmgr.mk_map_fn(*table_overlap, umapper); - (*mapping_fn)(*table_overlap); - } - - if(!m_remove_src_column_from_overlap) { - unsigned removed_cols[] = { table_overlap->get_signature().size()-1 }; - m_remove_src_column_from_overlap = rmgr.mk_project_fn(*table_overlap, 1, removed_cols); - } - //transform table_overlap into the signature of tgt.get_table(), so that the functional - //column contains indexes of the united relations - scoped_rel regular_overlap = (*m_remove_src_column_from_overlap)(*table_overlap); - - - if(!m_remove_overlaps) { - m_remove_overlaps = rmgr.mk_filter_by_negation_fn(tgt.get_table(), *regular_overlap, m_data_cols, - m_data_cols); - } - - //in tgt keep only the rows that are in tgt only - (*m_remove_overlaps)(tgt.get_table(), *regular_overlap); - - //add rows in which tgt and src overlapped - if(!m_table_union) { - m_table_union = rmgr.mk_union_fn(tgt.get_table(), tgt.get_table()); - } - (*m_table_union)(tgt.get_table(), *regular_overlap); - - scoped_rel src_only = src.get_table().clone(); - (*m_remove_overlaps)(*src_only, *regular_overlap); - - scoped_rel src_only2; //a copy of src_only for use in building the delta - if(m_use_delta) { - src_only2 = src_only->clone(); - } - - { - src_copying_mapper * cpmapper = alloc(src_copying_mapper, tgt, src); - scoped_ptr mapping_fn = rmgr.mk_map_fn(*src_only, cpmapper); - (*mapping_fn)(*src_only); - } - - //add rows that were only in src - (*m_table_union)(tgt.get_table(), *src_only); - - if(m_use_delta) { - bool extending_delta = !delta->empty(); - //current delta, we will add it to the deltab argument later if it was not given to us empty - finite_product_relation * cdelta; - if(extending_delta) { - cdelta = delta->get_plugin().mk_empty(*delta); - } - else { - cdelta = delta; - } - - if(!m_overlap_delta_table_builder) { - unsigned table_fn_col = regular_overlap->get_signature().size()-1; - unsigned first_col = 0; - unsigned removed_cols[] = { table_fn_col, table_fn_col+1 }; - m_overlap_delta_table_builder = rmgr.mk_join_project_fn(*regular_overlap, *delta_indexes, 1, - &table_fn_col, &first_col, 2, removed_cols); - } - - scoped_rel overlap_delta_table = - (*m_overlap_delta_table_builder)(*regular_overlap, *delta_indexes); - - cdelta->init(*overlap_delta_table, delta_rels, true); - - { - src_copying_mapper * cpmapper = alloc(src_copying_mapper, *cdelta, src); - scoped_ptr mapping_fn = rmgr.mk_map_fn(*src_only2, cpmapper); - (*mapping_fn)(*src_only2); - } - - //add rows that were only in src - (*m_table_union)(cdelta->get_table(), *src_only2); - - if(extending_delta) { - if(!m_delta_merging_union) { - m_delta_merging_union = rmgr.mk_union_fn(*delta, *cdelta); - } - (*m_delta_merging_union)(*delta, *cdelta); - cdelta->deallocate(); - } - } - } - }; - -#if 0 - /** - Union operation taking advantage of the fact that the inner relation of all the arguments - is a singleton relation. - */ - class finite_product_relation_plugin::inner_singleton_union_fn : public relation_union_fn { - - class offset_row_mapper : public table_row_mutator_fn { - public: - unsigned m_ofs; - virtual bool operator()(table_element * func_columns) { - func_columns[0] += m_ofs; - return true; - } - }; - - // [Leo]: gcc complained about the following class. - // It does not have a constructor and uses a reference - - class inner_relation_copier : public table_row_mutator_fn { - finite_product_relation & m_tgt; - const finite_product_relation & m_src; - finite_product_relation * m_delta; - unsigned m_tgt_ofs; - unsigned m_delta_ofs; - public: - virtual bool operator()(table_element * func_columns) { - unsigned src_idx = static_cast(func_columns[0]); - unsigned tgt_idx = src_idx + m_tgt_ofs; - unsigned delta_idx = m_delta ? (src_idx + m_delta_ofs) : 0; - SASSERT(!m_delta || m_tgt.m_others[tgt_idx]==m_delta->m_others[delta_idx]); - SASSERT(m_tgt.m_others[tgt_idx]==0 || m_tgt.m_others[tgt_idx]==m_src.m_others[src_idx]); - if(m_tgt.m_others[tgt_idx]==0) { - m_tgt.m_others[tgt_idx] = m_src.m_others[src_idx]->clone(); - if(m_delta) { - m_delta->m_others[delta_idx] = m_src.m_others[src_idx]->clone(); - } - } - return true; - } - }; - - scoped_ptr m_t_union_fun; - offset_row_mapper * m_offset_mapper_obj; //initialized together with m_offset_mapper_fun, and deallocated by it - scoped_ptr m_offset_mapper_fun; - - - - public: - virtual void operator()(relation_base & tgtb, const relation_base & srcb, relation_base * deltab) { - finite_product_relation & tgt = get(tgtb); - const finite_product_relation & src = get(srcb); - finite_product_relation * delta = get(deltab); - - finite_product_relation_plugin & plugin = tgt.get_plugin(); - relation_manager & rmgr = plugin.get_manager(); - - //we want only non-empty inner relations to remain - tgt.garbage_collect(true); - src.garbage_collect(true); - - table_base & tgt_table = tgt.get_table(); - const table_base & src_table = src.get_table(); - - scoped_rel offsetted_src = src_table.clone(); - - if(!m_offset_mapper_fun) { - m_offset_mapper_obj = alloc(offset_row_mapper); - m_offset_mapper_fun = rmgr.mk_map_fn(*offsetted_src, m_offset_mapper_obj); - } - unsigned src_rel_offset = tgt.m_others.size(); - m_offset_mapper_obj->m_ofs = src_rel_offset; - - (*m_offset_mapper_fun)(*offsetted_src); - - //if we need to generate a delta, we get collect it into an empty relation and then union - //it with the delta passed in as argument. - scoped_rel loc_delta = delta ? get(plugin.mk_empty(*delta)) : 0; - //even if we don't need to generate the delta for the caller, we still want to have a delta - //table to know which relations to copy. - scoped_rel loc_delta_table_scoped; - if(!loc_delta) { - loc_delta_table_scoped = tgt_table.get_plugin().mk_empty(tgt_table); - } - table_base * loc_delta_table = loc_delta ? &loc_delta->get_table() : loc_delta_table_scoped.get(); - - if(!m_t_union_fun) { - m_t_union_fun = rmgr.mk_union_fn(tgt_table, *offsetted_src, loc_delta_table); - } - (*m_t_union_fun)(tgt_table, *offsetted_src, loc_delta_table); - - - //TODO: copy the relations into tgt and (possibly) delta using inner_relation_copier - //TODO: unite the local delta with the delta passed in as an argument - NOT_IMPLEMENTED_YET(); - } - }; -#endif - - class finite_product_relation_plugin::converting_union_fn : public relation_union_fn { - scoped_ptr m_tr_union_fun; - public: - virtual void operator()(relation_base & tgtb, const relation_base & srcb, relation_base * deltab) { - SASSERT(srcb.get_plugin().is_finite_product_relation()); - const finite_product_relation & src = get(srcb); - finite_product_relation_plugin & plugin = src.get_plugin(); - scoped_rel tr_src = plugin.to_table_relation(src); - if(!m_tr_union_fun) { - m_tr_union_fun = plugin.get_manager().mk_union_fn(tgtb, *tr_src, deltab); - SASSERT(m_tr_union_fun); - } - (*m_tr_union_fun)(tgtb, *tr_src, deltab); - } - }; - - relation_union_fn * finite_product_relation_plugin::mk_union_fn(const relation_base & tgtb, const relation_base & srcb, - const relation_base * deltab) { - if(&srcb.get_plugin()!=this) { - return 0; - } - const finite_product_relation & src = get(srcb); - if(&tgtb.get_plugin()!=this || (deltab && &deltab->get_plugin()!=this) ) { - if(can_convert_to_table_relation(src)) { - return alloc(converting_union_fn); - } - return 0; - } - - const finite_product_relation * delta = get(deltab); - - return alloc(union_fn, get(tgtb), delta!=0); - } - - - class finite_product_relation_plugin::filter_identical_fn : public relation_mutator_fn { - //the table and relation columns that should be identical - //the column numbering is local to the table or inner relation - unsigned_vector m_table_cols; - unsigned_vector m_rel_cols; - - scoped_ptr m_table_filter; - scoped_ptr m_rel_filter; - scoped_ptr m_tr_filter; - public: - filter_identical_fn(const finite_product_relation & r, unsigned col_cnt, const unsigned * identical_cols) - : m_table_filter(0), m_rel_filter(0), m_tr_filter(0) { - finite_product_relation_plugin & plugin = r.get_plugin(); - for(unsigned i=0; i1) { - m_table_filter = r.get_manager().mk_filter_identical_fn(r.get_table(), m_table_cols.size(), - m_table_cols.c_ptr()); - SASSERT(m_table_filter); - } - if(!m_table_cols.empty() && !m_rel_cols.empty()) { - unsigned tr_filter_table_cols[] = { m_table_cols[0] }; - unsigned tr_filter_rel_cols[] = { m_rel_cols[0] }; - m_tr_filter = plugin.mk_filter_identical_pairs(r, 1, tr_filter_table_cols, tr_filter_rel_cols); - SASSERT(m_tr_filter); - } - } - - void ensure_rel_filter(const relation_base & orel) { - SASSERT(m_rel_cols.size()>1); - if(m_rel_filter) { - return; - } - m_rel_filter = orel.get_manager().mk_filter_identical_fn(orel, m_rel_cols.size(), m_rel_cols.c_ptr()); - SASSERT(m_rel_filter); - } - - virtual void operator()(relation_base & rb) { - finite_product_relation & r = get(rb); - - if(m_table_cols.size()>1) { - (*m_table_filter)(r.get_table()); - } - - if(m_rel_cols.size()>1) { - r.garbage_collect(true); - unsigned rel_cnt = r.m_others.size(); - for(unsigned rel_idx=0; rel_idx m_table_filter; - scoped_ptr m_rel_filter; - unsigned m_col; - app_ref m_value; - public: - filter_equal_fn(const finite_product_relation & r, const relation_element & value, unsigned col) - : m_col(col), m_value(value, r.get_context().get_manager()) { - if(r.is_table_column(col)) { - table_element tval; - r.get_manager().relation_to_table(r.get_signature()[col], value, tval); - m_table_filter = r.get_manager().mk_filter_equal_fn(r.get_table(), tval, r.m_sig2table[col]); - } - } - - virtual void operator()(relation_base & rb) { - finite_product_relation & r = get(rb); - - if(m_table_filter) { - (*m_table_filter)(r.get_table()); - return; - } - r.garbage_collect(false); - relation_vector & inner_rels = r.m_others; - unsigned rel_cnt = inner_rels.size(); - for(unsigned i=0; i m_table_filter; - scoped_ptr m_rel_filter; - app_ref m_cond; - - idx_set m_table_cond_columns; - idx_set m_rel_cond_columns; - - //like m_table_cond_columns and m_rel_cond_columns, only the indexes are local to the - //table/relation, not to the signature of the whole relation - idx_set m_table_local_cond_columns; - idx_set m_rel_local_cond_columns; - - /** - If equal to 0, it means the interpreted condition uses all table columns. Then the original - table is used instead of the result of the projection. - */ - scoped_ptr m_table_cond_columns_project; - /** - \brief Column indexes of the global relations to which correspond the data columns in the table - that is result of applying the \c m_table_cond_columns_project functor. - */ - unsigned_vector m_global_origins_of_projected_columns; - - scoped_ptr m_assembling_join_project; - - - /** - \brief Renaming that transforms the variable numbers pointing to the global relation into - variables that point to the inner relation variables. - - The elements that do not correspond to columns of the inner relation (but rather to the table - columns) is modified in \c operator() when evaluating the condition for all the relevant - combinations of table values. - */ - expr_ref_vector m_renaming_for_inner_rel; - public: - filter_interpreted_fn(const finite_product_relation & r, app * condition) - : m_manager(r.get_context().get_manager()), - m_subst(r.get_context().get_var_subst()), - m_cond(condition, m_manager), - m_renaming_for_inner_rel(m_manager) { - relation_manager & rmgr = r.get_manager(); - - rule_manager& rm = r.get_context().get_rule_manager(); - idx_set& cond_columns = rm.collect_vars(m_cond); - - unsigned sig_sz = r.get_signature().size(); - for(unsigned i=0; i tproj_scope; - const table_base * tproj; - if(m_table_cond_columns_project) { - tproj_scope = (*m_table_cond_columns_project)(rtable); - tproj = tproj_scope.get(); - } - else { - tproj = &rtable; - } - unsigned projected_data_cols = tproj->get_signature().size()-1; - SASSERT(m_table_cond_columns.num_elems()==projected_data_cols); - - table_signature filtered_sig = tproj->get_signature(); - filtered_sig.push_back(finite_product_relation::s_rel_idx_sort); - filtered_sig.set_functional_columns(1); - - relation_vector new_rels; - - scoped_rel filtered_table = tplugin.mk_empty(filtered_sig); - table_fact f; - unsigned renaming_ofs = m_renaming_for_inner_rel.size()-1; - table_base::iterator pit = tproj->begin(); - table_base::iterator pend = tproj->end(); - for(; pit!=pend; ++pit) { - pit->get_fact(f); - unsigned old_rel_idx = static_cast(f.back()); - const relation_base & old_rel = r.get_inner_rel(old_rel_idx); - - //put the table values into the substitution - for(unsigned i=0; i filter = rmgr.mk_filter_interpreted_fn(*new_rel, to_app(inner_cond)); - (*filter)(*new_rel); - - if(new_rel->empty()) { - new_rel->deallocate(); - continue; - } - - unsigned new_rel_idx = new_rels.size(); - new_rels.push_back(new_rel); - f.push_back(new_rel_idx); - filtered_table->add_fact(f); - } - - if(!m_assembling_join_project) { - unsigned_vector table_cond_columns_vect; - for(unsigned i=0; i new_table = (*m_assembling_join_project)(rtable, *filtered_table); - r.reset(); - r.init(*new_table, new_rels, true); - } - }; - - relation_mutator_fn * finite_product_relation_plugin::mk_filter_interpreted_fn(const relation_base & rb, - app * condition) { - if(&rb.get_plugin()!=this) { - return 0; - } - return alloc(filter_interpreted_fn, get(rb), condition); - } - - class finite_product_relation_plugin::negation_filter_fn : public relation_intersection_filter_fn { - - unsigned_vector m_r_cols; - unsigned_vector m_neg_cols; - - scoped_ptr m_table_neg_filter; - scoped_ptr m_table_neg_complement_selector; - scoped_ptr m_neg_intersection_join; - scoped_ptr m_table_intersection_join; - scoped_ptr m_table_overlap_union; - scoped_ptr m_table_subtract; - scoped_ptr m_inner_subtract; - scoped_ptr m_overlap_table_last_column_remover; - scoped_ptr m_r_table_union; - - bool m_table_overlaps_only; - - unsigned_vector m_r_shared_table_cols; - unsigned_vector m_neg_shared_table_cols; - - unsigned_vector m_r_shared_rel_cols; - unsigned_vector m_neg_shared_rel_cols; - public: - negation_filter_fn(const finite_product_relation & r, const finite_product_relation & neg, - unsigned joined_col_cnt, const unsigned * r_cols, const unsigned * neg_cols) - : m_r_cols(joined_col_cnt, r_cols), - m_neg_cols(joined_col_cnt, neg_cols), - m_table_overlaps_only(true) { - const table_signature & tsig = r.m_table_sig; - const table_base & rtable = r.get_table(); - relation_manager & rmgr = r.get_manager(); - - for(unsigned i=0; iget_signature().size() , all_rel_cols); - m_parent.m_inner_subtract = m_r.get_manager().mk_filter_by_negation_fn(*r_inner, - inters_inner, all_rel_cols, all_rel_cols); - } - (*m_parent.m_inner_subtract)(*r_inner, inters_inner); - - unsigned new_rel_num = m_r.get_next_rel_idx(); - m_r.set_inner_rel(new_rel_num, r_inner); - func_columns[0]=new_rel_num; - return true; - } - }; - - - virtual void operator()(relation_base & rb, const relation_base & negb) { - finite_product_relation & r = get(rb); - const finite_product_relation & neg = get(negb); - - if(m_table_overlaps_only) { - handle_only_tables_overlap_case(r, neg); - 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()); - - table_base & r_table = r.get_table(); - table_plugin & tplugin = r_table.get_plugin(); - relation_manager & rmgr = r.get_manager(); - - //we need to do this before we perform the \c m_table_subtract - //the sigrature of the \c table_overlap0 relation is - //(data_columns)(original rel idx)(subtracted rel idx) - scoped_rel table_overlap0 = (*m_table_intersection_join)(r_table, - intersection->get_table()); - - //the rows that don't appear in the table of the intersection are safe to stay - (*m_table_subtract)(r_table, intersection->get_table()); - - //now we will examine the rows that do appear in the intersection - - //There are no functional columns in the \c table_overlap0 relation (because of - //the project we did). We need to make both rel idx columns functional. - //We do not lose any rows, since the data columns by themselves are unique. - - table_signature table_overlap_sig(table_overlap0->get_signature()); - table_overlap_sig.set_functional_columns(2); - scoped_rel table_overlap = tplugin.mk_empty(table_overlap_sig); - - if(!m_table_overlap_union) { - m_table_overlap_union = rmgr.mk_union_fn(*table_overlap, *table_overlap0); - SASSERT(m_table_overlap_union); - } - (*m_table_overlap_union)(*table_overlap, *table_overlap0); - - { - rel_subtractor * mutator = alloc(rel_subtractor, *this, r, *intersection); - scoped_ptr mapper = rmgr.mk_map_fn(*table_overlap, mutator); - (*mapper)(*table_overlap); - } - - if(!m_overlap_table_last_column_remover) { - unsigned removed_col = table_overlap->get_signature().size()-1; - m_overlap_table_last_column_remover = rmgr.mk_project_fn(*table_overlap, 1, &removed_col); - } - scoped_rel final_overlapping_rows_table = - (*m_overlap_table_last_column_remover)(*table_overlap); - - if(!m_r_table_union) { - m_r_table_union = rmgr.mk_union_fn(r_table, *final_overlapping_rows_table); - } - - (*m_r_table_union)(r_table, *final_overlapping_rows_table); - } - }; - - relation_intersection_filter_fn * finite_product_relation_plugin::mk_filter_by_negation_fn(const relation_base & rb, - const relation_base & negb, unsigned joined_col_cnt, - const unsigned * r_cols, const unsigned * negated_cols) { - if(&rb.get_plugin()!=this || &negb.get_plugin()!=this) { - return 0; - } - - return alloc(negation_filter_fn, get(rb), get(negb), joined_col_cnt, r_cols, negated_cols); - } - - - class finite_product_relation_plugin::filter_identical_pairs_fn : public relation_mutator_fn { - scoped_ptr m_tproject_fn; //if zero, no columns need to be projected away - unsigned m_col_cnt; - unsigned_vector m_table_cols; - unsigned_vector m_rel_cols; - - scoped_ptr m_assembling_join_project; - scoped_ptr m_updating_union; - public: - filter_identical_pairs_fn(const finite_product_relation & r, unsigned col_cnt, const unsigned * table_cols, - const unsigned * rel_cols) : - m_col_cnt(col_cnt), - m_table_cols(col_cnt, table_cols), - m_rel_cols(col_cnt, rel_cols) { - SASSERT(col_cnt>0); - const table_signature & tsig = r.m_table_sig; - unsigned t_sz = tsig.size(); - - sort_two_arrays(col_cnt, m_table_cols.begin(), m_rel_cols.begin()); - SASSERT(m_table_cols.back() tproj; - if(m_tproject_fn) { - tproj = (*m_tproject_fn)(r.get_table()); - } - else { - tproj = r.get_table().clone(); - } - SASSERT(m_col_cnt+1==tproj->get_signature().size()); - - table_signature filtered_sig = tproj->get_signature(); - filtered_sig.push_back(finite_product_relation::s_rel_idx_sort); - filtered_sig.set_functional_columns(1); - - relation_vector new_rels; - scoped_rel filtered_table = tplugin.mk_empty(filtered_sig); - table_fact f; - table_base::iterator pit = tproj->begin(); - table_base::iterator pend = tproj->end(); - for(; pit!=pend; ++pit) { - pit->get_fact(f); - unsigned old_rel_idx = static_cast(f.back()); - const relation_base & old_rel = r.get_inner_rel(old_rel_idx); - relation_base * new_rel = old_rel.clone(); - for(unsigned i=0; i filter = rmgr.mk_filter_equal_fn(*new_rel, r_el, m_rel_cols[i]); - (*filter)(*new_rel); - } - - if(new_rel->empty()) { - new_rel->deallocate(); - continue; - } - - unsigned new_rel_idx = new_rels.size(); - new_rels.push_back(new_rel); - f.push_back(new_rel_idx); - filtered_table->add_fact(f); - } - - if(!m_assembling_join_project) { - m_assembling_join_project = mk_assembler_of_filter_result(rtable, *filtered_table, m_table_cols); - } - - scoped_rel new_table = (*m_assembling_join_project)(r.get_table(), *filtered_table); - - r.reset(); - r.init(*new_table, new_rels, true); - } - }; - - relation_mutator_fn * finite_product_relation_plugin::mk_filter_identical_pairs(const finite_product_relation & r, - unsigned col_cnt, const unsigned * table_cols, const unsigned * rel_cols) { - return alloc(filter_identical_pairs_fn, r, col_cnt, table_cols, rel_cols); - } - - table_join_fn * finite_product_relation_plugin::mk_assembler_of_filter_result(const table_base & relation_table, - const table_base & filtered_table, const unsigned_vector & selected_columns) { - - table_plugin & tplugin = relation_table.get_plugin(); - const table_signature & rtable_sig = relation_table.get_signature(); - unsigned rtable_sig_sz = rtable_sig.size(); - unsigned selected_col_cnt = selected_columns.size(); - SASSERT(selected_col_cnt+2==filtered_table.get_signature().size()); - SASSERT(rtable_sig.functional_columns()==1); - SASSERT(filtered_table.get_signature().functional_columns()==1); - - unsigned_vector rtable_joined_cols; - rtable_joined_cols.append(selected_col_cnt, selected_columns.c_ptr()); //filtered table cols - rtable_joined_cols.push_back(rtable_sig_sz-1); //unfiltered relation indexes - - unsigned_vector filtered_joined_cols; - add_sequence(0, selected_col_cnt, filtered_joined_cols); //filtered table cols - filtered_joined_cols.push_back(selected_col_cnt); //unfiltered relation indexes - SASSERT(rtable_joined_cols.size()==filtered_joined_cols.size()); - - //the signature after join: - //(all relation table columns)(all filtered relation table columns)(unfiltered rel idx non-func from 'filtered') - // (unfiltered rel idx func from 'rtable')(filtered rel idx) - unsigned_vector removed_cols; - unsigned filtered_nonfunc_ofs = rtable_sig_sz-1; - add_sequence(filtered_nonfunc_ofs, selected_col_cnt, removed_cols); //data columns from 'filtered' - unsigned idx_ofs = filtered_nonfunc_ofs+selected_col_cnt; - removed_cols.push_back(idx_ofs); //unfiltered relation indexes from 'filtered' - removed_cols.push_back(idx_ofs+1); //unfiltered relation indexes from rtable - - table_join_fn * res = tplugin.get_manager().mk_join_project_fn(relation_table, filtered_table, - rtable_joined_cols, filtered_joined_cols, removed_cols); - SASSERT(res); - return res; - } - - // ----------------------------------- - // - // finite_product_relation - // - // ----------------------------------- - - finite_product_relation::finite_product_relation(finite_product_relation_plugin & p, - const relation_signature & s, const bool * table_columns, table_plugin & tplugin, - relation_plugin & oplugin, family_id other_kind) - : relation_base(p, s), - m_other_plugin(oplugin), - m_other_kind(other_kind), - m_full_rel_idx(UINT_MAX) { - const relation_signature & rel_sig = get_signature(); - unsigned sz = rel_sig.size(); - m_sig2table.resize(sz, UINT_MAX); - m_sig2other.resize(sz, UINT_MAX); - for(unsigned i=0; iclone()), - m_others(r.m_others), - m_available_rel_indexes(r.m_available_rel_indexes), - m_full_rel_idx(r.m_full_rel_idx), - m_live_rel_collection_project(), - m_empty_rel_removal_filter() { - //m_others is now just a shallow copy, we need use clone of the relations that in it now - unsigned other_sz = m_others.size(); - for(unsigned i=0; ideallocate(); - relation_vector::iterator it = m_others.begin(); - relation_vector::iterator end = m_others.end(); - for(; it!=end; ++it) { - relation_base * rel= *it; - if(rel) { - rel->deallocate(); - } - } - } - - context & finite_product_relation::get_context() const { - return get_manager().get_context(); - } - - unsigned finite_product_relation::get_next_rel_idx() const { - unsigned res; - if(!m_available_rel_indexes.empty()) { - res = m_available_rel_indexes.back(); - m_available_rel_indexes.pop_back(); - } - else { - res = m_others.size(); - m_others.push_back(0); - } - SASSERT(m_others[res]==0); - return res; - } - - void finite_product_relation::recycle_rel_idx(unsigned idx) const { - SASSERT(m_others[idx]==0); - m_available_rel_indexes.push_back(idx); - } - - unsigned finite_product_relation::get_full_rel_idx() { - if(m_full_rel_idx==UINT_MAX) { - m_full_rel_idx = get_next_rel_idx(); - relation_base * full_other = mk_full_inner(0); - m_others[m_full_rel_idx] = full_other; - } - return m_full_rel_idx; - } - - void finite_product_relation::init(const table_base & table_vals, const relation_vector & others, bool contiguous) { - SASSERT(m_table_sig.equal_up_to_fn_mark(table_vals.get_signature())); - SASSERT(empty()); - if(!m_others.empty()) { - garbage_collect(false); - } - SASSERT(m_others.empty()); - - m_others = others; - scoped_ptr table_union = get_manager().mk_union_fn(get_table(), table_vals); - (*table_union)(get_table(), table_vals); - - if(!contiguous) { - unsigned rel_cnt = m_others.size(); - for(unsigned i=0; isuggest_fact(t_f)) { - SASSERT(t_f.back()==new_rel_idx); - new_rel = mk_empty_inner(); - } else { - new_rel = get_inner_rel(t_f.back()).clone(); - - t_f[t_f.size()-1]=new_rel_idx; - m_table->ensure_fact(t_f); - } - new_rel->add_fact(o_f); - set_inner_rel(new_rel_idx, new_rel); - } - - bool finite_product_relation::contains_fact(const relation_fact & f) const { - table_fact t_f; - extract_table_fact(f, t_f); - - if(!m_table->fetch_fact(t_f)) { - return false; - } - - relation_fact o_f(get_context()); - extract_other_fact(f, o_f); - - const relation_base & other = get_inner_rel(t_f.back()); - - return other.contains_fact(o_f); - } - - bool finite_product_relation::empty() const { - garbage_collect(true); - return m_table->empty(); - } - - finite_product_relation * finite_product_relation::clone() const { - return alloc(finite_product_relation, *this); - } - - void finite_product_relation::complement_self(func_decl* p) { - unsigned other_sz = m_others.size(); - for(unsigned i=0; icomplement(p); - std::swap(m_others[i],r); - r->deallocate(); - } - table_element full_rel_idx = get_full_rel_idx(); - scoped_rel complement_table = m_table->complement(p, &full_rel_idx); - - scoped_ptr u_fn = get_manager().mk_union_fn(*m_table, *complement_table, 0); - SASSERT(u_fn); - (*u_fn)(*m_table, *complement_table, 0); - } - - finite_product_relation * finite_product_relation::complement(func_decl* p) const { - finite_product_relation * res = clone(); - res->complement_self(p); - return res; - } - - class finite_product_relation::live_rel_collection_reducer : public table_row_pair_reduce_fn { - idx_set & m_accumulator; - public: - live_rel_collection_reducer(idx_set & accumulator) : m_accumulator(accumulator) {} - - virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) { - m_accumulator.insert(static_cast(merged_func_columns[0])); - } - }; - - void finite_product_relation::collect_live_relation_indexes(idx_set & res) const { - SASSERT(res.empty()); - unsigned table_data_col_cnt = m_table_sig.size()-1; - - if(table_data_col_cnt==0) { - if(!get_table().empty()) { - table_base::iterator iit = get_table().begin(); - table_base::iterator iend = get_table().end(); - - SASSERT(iit!=iend); - res.insert(static_cast((*iit)[0])); - SASSERT((++iit)==iend); - } - return; - } - - if(!m_live_rel_collection_project) { - buffer removed_cols; - removed_cols.resize(table_data_col_cnt); - for(unsigned i=0; i live_indexes_table = (*m_live_rel_collection_project)(get_table()); - res.swap(m_live_rel_collection_acc); - - SASSERT(live_indexes_table->get_signature().size()==1); - SASSERT(live_indexes_table->get_signature().functional_columns()==1); - if(!live_indexes_table->empty()) { - table_base::iterator iit = live_indexes_table->begin(); - table_base::iterator iend = live_indexes_table->end(); - - SASSERT(iit!=iend); - res.insert(static_cast((*iit)[0])); - SASSERT((++iit)==iend); - } - } - - void finite_product_relation::garbage_collect(bool remove_empty) const { - idx_set live_indexes; - collect_live_relation_indexes(live_indexes); - - scoped_rel empty_rel_indexes; //populated only if \c remove_empty==true - table_fact empty_rel_fact; - - unsigned rel_cnt = m_others.size(); -#if Z3DEBUG - unsigned encountered_live_indexes = 0; -#endif - for(unsigned rel_idx=0; rel_idxempty()) { - continue; - } - if(empty_rel_indexes==0) { - table_signature empty_rel_indexes_sig; - empty_rel_indexes_sig.push_back(s_rel_idx_sort); - empty_rel_indexes = get_table_plugin().mk_empty(empty_rel_indexes_sig); - } - empty_rel_fact.reset(); - empty_rel_fact.push_back(rel_idx); - empty_rel_indexes->add_fact(empty_rel_fact); - } - m_others[rel_idx]->deallocate(); - m_others[rel_idx] = 0; - if(rel_idx==m_full_rel_idx) { - m_full_rel_idx = UINT_MAX; - } - recycle_rel_idx(rel_idx); - } - SASSERT(encountered_live_indexes==live_indexes.num_elems()); - - if(m_available_rel_indexes.size()==m_others.size()) { - m_available_rel_indexes.reset(); - m_others.reset(); - } - - if(empty_rel_indexes) { - SASSERT(remove_empty); - - if(!m_empty_rel_removal_filter) { - unsigned t_joined_cols[] = { m_table_sig.size()-1 }; - unsigned ei_joined_cols[] = { 0 }; - m_empty_rel_removal_filter = get_manager().mk_filter_by_negation_fn(get_table(), *empty_rel_indexes, - 1, t_joined_cols, ei_joined_cols); - } - - (*m_empty_rel_removal_filter)(*m_table, *empty_rel_indexes); - } - } - - bool finite_product_relation::try_unify_specifications(ptr_vector & rels) { - if(rels.empty()) { - return true; - } - unsigned sig_sz = rels.back()->get_signature().size(); - svector table_cols(sig_sz, true); - - ptr_vector::iterator it = rels.begin(); - ptr_vector::iterator end = rels.end(); - for(; it!=end; ++it) { - finite_product_relation & rel = **it; - for(unsigned i=0; i pr_fun = get_manager().mk_project_fn(get_table(), to_project_away); - table_base * moved_cols_table = (*pr_fun)(get_table()); //gets destroyed inside moved_cols_trel - scoped_rel moved_cols_trel = - rmgr.get_table_relation_plugin(moved_cols_table->get_plugin()).mk_from_table(moved_cols_sig, moved_cols_table); - - svector moved_cols_table_flags(moved_cols_sig.size(), false); - - scoped_rel moved_cols_rel = get_plugin().mk_empty(moved_cols_sig, - moved_cols_table_flags.c_ptr()); - - scoped_ptr union_fun = - get_manager().mk_union_fn(*moved_cols_rel, *moved_cols_trel); - SASSERT(union_fun); //the table_relation should be able to be 'unioned into' any relation - - (*union_fun)(*moved_cols_rel, *moved_cols_trel); - - unsigned_vector all_moved_cols_indexes; - add_sequence(0, moved_cols_sig.size(), all_moved_cols_indexes); - - scoped_ptr join_fun = get_manager().mk_join_project_fn(*this, *moved_cols_rel, new_rel_columns, - all_moved_cols_indexes, new_rel_columns, false); - - scoped_rel unordered_rel = (*join_fun)(*this, *moved_cols_rel); - SASSERT(unordered_rel->get_signature().size()==sig_sz); //the signature size should be the same as original - - //now we need to reorder the columns in the \c new_rel to match the original table - unsigned_vector permutation; - unsigned moved_cols_cnt = new_rel_columns.size(); - unsigned next_replaced_idx = 0; - unsigned next_orig_idx = 0; - for(unsigned i=0; i perm_fun = get_manager().mk_rename_fn(*unordered_rel, cycle); - //the scoped_rel wrapper does the destruction of the old object - unordered_rel = (*perm_fun)(*unordered_rel); - cycle.reset(); - } - - finite_product_relation & new_rel = finite_product_relation_plugin::get(*unordered_rel); - - //Swap the content of the current object and new_rel. On exitting the function new_rel will be destroyed - //since it points to the content of scoped_rel unordered_rel. - swap(new_rel); - - return true; - } - - void finite_product_relation::display(std::ostream & out) const { - - garbage_collect(true); - - out << "finite_product_relation:\n"; - - out << " table:\n"; - get_table().display(out); - - unsigned other_sz = m_others.size(); - for(unsigned i=0; iget_fact(tfact); - - const table_relation & orel = static_cast(get_inner_rel(tfact[rel_idx_col])); - const table_base & otable = orel.get_table(); - table_base::iterator oit = otable.begin(); - table_base::iterator oend = otable.end(); - for(; oit!=oend; ++oit) { - oit->get_fact(ofact); - - out << "\t("; - for(unsigned i=0; iget_fact(fact); - conjs.reset(); - SASSERT(fact.size() == fact_sz); - unsigned rel_idx = static_cast(fact[fact_sz-1]); - m_others[rel_idx]->to_formula(tmp); - for (unsigned i = 0; i + 1 < fact_sz; ++i) { - conjs.push_back(m.mk_eq(m.mk_var(i, sig[i]), util.mk_numeral(fact[i], sig[i]))); - } - sh(tmp, fact_sz-1, tmp); - conjs.push_back(tmp); - disjs.push_back(m.mk_and(conjs.size(), conjs.c_ptr())); - } - bool_rewriter(m).mk_or(disjs.size(), disjs.c_ptr(), fml); - } - -}; - diff --git a/src/muz/dl_finite_product_relation.h b/src/muz/dl_finite_product_relation.h deleted file mode 100644 index d5181d122..000000000 --- a/src/muz/dl_finite_product_relation.h +++ /dev/null @@ -1,366 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_finite_product_relation.h - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-24. - -Revision History: - ---*/ -#ifndef _DL_FINITE_PRODUCT_RELATION_H_ -#define _DL_FINITE_PRODUCT_RELATION_H_ - - -#include "dl_base.h" -#include "dl_relation_manager.h" -#include "dl_table_relation.h" - -namespace datalog { - - class finite_product_relation; - - void universal_delete(finite_product_relation* ptr); - - - class finite_product_relation_plugin : public relation_plugin { - friend class finite_product_relation; - public: - struct rel_spec { - family_id m_inner_kind; //null_family_id means we don't care about the kind - svector m_table_cols; - - rel_spec() : m_inner_kind(null_family_id) {} - rel_spec(const svector& table_cols) - : m_inner_kind(null_family_id), m_table_cols(table_cols) {} - - bool operator==(const rel_spec & o) const { - return m_inner_kind==o.m_inner_kind && vectors_equal(m_table_cols, o.m_table_cols); - } - struct hash { - unsigned operator()(const rel_spec & o) const { - return o.m_inner_kind^svector_hash()(o.m_table_cols); - } - }; - }; - private: - - class join_fn; - class converting_join_fn; - class project_fn; - class rename_fn; - class union_fn; - class inner_singleton_union_fn; - class converting_union_fn; - class filter_identical_fn; - class filter_equal_fn; - class filter_interpreted_fn; - class negation_filter_fn; - class filter_identical_pairs_fn; - - relation_plugin & m_inner_plugin; - - rel_spec_store > m_spec_store; - - static symbol get_name(relation_plugin & inner_plugin); - family_id get_relation_kind(finite_product_relation & r, const bool * table_columns); - - static void get_all_possible_table_columns(relation_manager & rmgr, const relation_signature & s, - svector & table_columns); - void get_all_possible_table_columns(const relation_signature & s, svector & table_columns) { - get_all_possible_table_columns(get_manager(), s, table_columns); - } - - void split_signatures(const relation_signature & s, table_signature & table_sig, - relation_signature & remaining_sig); - void split_signatures(const relation_signature & s, const bool * table_columns, - table_signature & table_sig, relation_signature & remaining_sig); - public: - static finite_product_relation & get(relation_base & r); - static const finite_product_relation & get(const relation_base & r); - static finite_product_relation * get(relation_base * r); - static const finite_product_relation * get(const relation_base * r); - - static finite_product_relation_plugin & get_plugin(relation_manager & rmgr, relation_plugin & inner); - - finite_product_relation_plugin(relation_plugin & inner_plugin, relation_manager & manager); - - virtual void initialize(family_id fid); - - relation_plugin & get_inner_plugin() const { return m_inner_plugin; } - - virtual bool can_handle_signature(const relation_signature & s); - - virtual relation_base * mk_empty(const relation_signature & s); - /** - \c inner_kind==null_family_id means we don't care about the kind of the inner relation - */ - finite_product_relation * mk_empty(const relation_signature & s, const bool * table_columns, - family_id inner_kind=null_family_id); - finite_product_relation * mk_empty(const finite_product_relation & original); - virtual relation_base * mk_empty(const relation_base & original); - virtual relation_base * mk_empty(const relation_signature & s, family_id kind); - - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - - /** - \brief Return true if \c r can be converted to \c finite_product_relation_plugin either - by \c mk_from_table_relation or by \c mk_from_inner_relation. - */ - bool can_be_converted(const relation_base & r); - - /** - If the conversion cannot be performed, 0 is returned. - */ - finite_product_relation * mk_from_table_relation(const table_relation & r); - finite_product_relation * mk_from_inner_relation(const relation_base & r); - - bool can_convert_to_table_relation(const finite_product_relation & r); - table_relation * to_table_relation(const finite_product_relation & r); - - protected: - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); - - private: - /** - \brief Create a filter that enforces equality between pairs of table and relation columns - - The column numbers in arrays \c table_cols and \c rel_cols must be local to the table/inner relation. - */ - relation_mutator_fn * mk_filter_identical_pairs(const finite_product_relation & r, unsigned col_cnt, - const unsigned * table_cols, const unsigned * rel_cols); - - /** - \brief Create a join-project operation that creates a table according to \c relation_table - but with references to relations updated and removed according to the content of \c filtered_table. - \c selected_columns contains sorted indexes of data columns in \c relation_table that are also in - the \c filtered_table (so that the first column in \c filtered_table corresponds to - \c selected_columns[0] -th column in \c relation_table etc...) - - Signature of \c relation_table: - (data columns)(functional column with indexes of relation objects) - - Signature of \c filtered_table: - (selected data columns)(non-functional column with original relation object indexes) - (functional column with indexes of filtered relation objects) - - */ - static table_join_fn * mk_assembler_of_filter_result(const table_base & relation_table, - const table_base & filtered_table, const unsigned_vector & selected_columns); - - }; - - class finite_product_relation : public relation_base { - friend class finite_product_relation_plugin; - friend class finite_product_relation_plugin::join_fn; - friend class finite_product_relation_plugin::project_fn; - friend class finite_product_relation_plugin::union_fn; - friend class finite_product_relation_plugin::rename_fn; - friend class finite_product_relation_plugin::inner_singleton_union_fn; - friend class finite_product_relation_plugin::filter_equal_fn; - friend class finite_product_relation_plugin::filter_identical_pairs_fn; - - class live_rel_collection_reducer; - - - public: - /** - Size of this sort determines how many different relation objects can we refer to. - */ - static const table_sort s_rel_idx_sort; - - - /** - \brief The last column in the signature is a functional column with index of the - associated inner relation. The other columns correspond to the relation signature - according to \c m_table2sig. - - It holds that \c m_table_sig.size()-1==m_table2sig.size() - */ - - table_signature m_table_sig; - unsigned_vector m_table2sig; // (ordered list) - unsigned_vector m_sig2table; //index of corresponding table column or UINT_MAX - private: - relation_signature m_other_sig; - unsigned_vector m_other2sig; // (ordered list) - public: - unsigned_vector m_sig2other; //index of corresponding other relation column or UINT_MAX - private: - relation_plugin & m_other_plugin; - family_id m_other_kind; - - mutable table_base * m_table; - public: - mutable relation_vector m_others; - private: - mutable unsigned_vector m_available_rel_indexes; - - /** - \c UINT_MAX means uninitialized. - If we can get away with it, we want to have a single full relation to refer to. - */ - mutable unsigned m_full_rel_idx; - - mutable idx_set m_live_rel_collection_acc; - mutable scoped_ptr m_live_rel_collection_project; - - mutable scoped_ptr m_empty_rel_removal_filter; - - void recycle_rel_idx(unsigned idx) const; - - // creates a full relation if it does not exist. - unsigned get_full_rel_idx(); - - - - public: - relation_base & get_inner_rel(table_element idx) - { SASSERT(idx(idx)); } - relation_base & get_inner_rel(unsigned idx) { SASSERT(m_others[idx]); return *m_others[idx]; } - const relation_base & get_inner_rel(unsigned idx) const - { return const_cast(*this).get_inner_rel(idx); } - - unsigned get_next_rel_idx() const; - - /** - The relation takes ownership of the \c inner object. - */ - void set_inner_rel(table_element idx, relation_base * inner) - { SASSERT(idx(idx), inner); } - /** - The relation takes ownership of the \c inner object. - */ - void set_inner_rel(unsigned idx, relation_base * inner) { - SASSERT(!m_others[idx]); - SASSERT(inner); - m_others[idx] = inner; - } - table_base & get_table() { return *m_table; } - - table_plugin & get_table_plugin() const { return get_table().get_plugin(); } - - void garbage_collect(bool remove_empty) const; - - /** - \brief Initialize an empty relation with table \c table_vals and relations in \c others. - - The relation object takes ownership of relations inside the \c others vector. - - If \c contiguous is true, it can be assumed that there are no zero elements in the \c others array. - */ - void init(const table_base & table_vals, const relation_vector & others, bool contiguous); - - private: - - - /** - \brief Extract the values of table non-functional columns from the relation fact. - The value of the functional column which determines index of the inner relation is undefined. - */ - void extract_table_fact(const relation_fact rf, table_fact & tf) const; - /** - \brief Extract the values of the inner relation columns from the relation fact. - */ - void extract_other_fact(const relation_fact rf, relation_fact & of) const; - - relation_base * mk_empty_inner(); - relation_base * mk_full_inner(func_decl* pred); - - - void complement_self(func_decl* pred); - - void collect_live_relation_indexes(idx_set & res) const; - - - /** - \brief Try to modify relations in \c rels so that they have the same columns corresponding to the table - and the inner relation (so that the union can be perofrmed on theim in a straightforward way). - - Relations in \c rels must all have equal signature. - - Even if the function fails and false is returned, some relations may already be modified. They are - in a valid state, but with different specification. - */ - static bool try_unify_specifications(ptr_vector & rels); - - bool try_modify_specification(const bool * table_cols); - - virtual bool can_swap(const relation_base & r) const - { return &get_plugin()==&r.get_plugin(); } - - /** - \brief Swap content of the current relation with the content of \c r. - - Both relations must come from the same plugin and be of the same signature. - */ - virtual void swap(relation_base & r); - - /** - \brief Create a \c finite_product_relation object. - */ - finite_product_relation(finite_product_relation_plugin & p, const relation_signature & s, - const bool * table_columns, table_plugin & tplugin, relation_plugin & oplugin, family_id other_kind); - finite_product_relation(const finite_product_relation & r); - virtual ~finite_product_relation(); - public: - context & get_context() const; - finite_product_relation_plugin & get_plugin() const { - return static_cast(relation_base::get_plugin()); - } - - bool is_table_column(unsigned col_idx) const { return m_sig2table[col_idx]!=UINT_MAX; } - - const table_base & get_table() const { return *m_table; } - - const relation_base & get_inner_rel(table_element idx) const - { SASSERT(idx(idx)); } - - /** - The function calls garbage_collect, so the internal state may change when it is called. - */ - virtual bool empty() const; - void reset() { m_table->reset(); garbage_collect(false); } - - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - - virtual finite_product_relation * clone() const; - virtual finite_product_relation * complement(func_decl* p) const; - - virtual void display(std::ostream & out) const; - virtual void display_tuples(func_decl & pred, std::ostream & out) const; - - virtual unsigned get_size_estimate_rows() const { return m_table->get_size_estimate_rows(); } - virtual unsigned get_size_estimate_bytes() const { return m_table->get_size_estimate_bytes(); } - - virtual void to_formula(expr_ref& fml) const; - }; - -}; - -#endif /* _DL_FINITE_PRODUCT_RELATION_H_ */ - diff --git a/src/muz/dl_interval_relation.cpp b/src/muz/dl_interval_relation.cpp deleted file mode 100644 index adc8cb760..000000000 --- a/src/muz/dl_interval_relation.cpp +++ /dev/null @@ -1,652 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_interval_relation.cpp - -Abstract: - - Basic interval reatlion. - -Author: - - Nikolaj Bjorner (nbjorner) 2010-2-11 - -Revision History: - ---*/ - -#include "debug.h" -#include "optional.h" -#include "ast_pp.h" -#include "dl_interval_relation.h" -#include "bool_rewriter.h" - - -namespace datalog { - // ------------------------- - // interval_relation_plugin - - interval_relation_plugin::interval_relation_plugin(relation_manager& m): - relation_plugin(interval_relation_plugin::get_name(), m), - m_empty(m_dep), - m_arith(get_ast_manager()) { - } - - bool interval_relation_plugin::can_handle_signature(const relation_signature & sig) { - for (unsigned i = 0; i < sig.size(); ++i) { - if (!m_arith.is_int(sig[i]) && !m_arith.is_real(sig[i])) { - return false; - } - } - return true; - } - - - relation_base * interval_relation_plugin::mk_empty(const relation_signature & s) { - return alloc(interval_relation, *this, s, true); - } - - relation_base * interval_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { - return alloc(interval_relation, *this, s, false); - } - - class interval_relation_plugin::join_fn : public convenient_relation_join_fn { - public: - join_fn(const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2) - : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2){ - } - - virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { - interval_relation const& r1 = get(_r1); - interval_relation const& r2 = get(_r2); - interval_relation_plugin& p = r1.get_plugin(); - interval_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); - result->mk_join(r1, r2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); - return result; - } - }; - - relation_join_fn * interval_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (!check_kind(r1) || !check_kind(r2)) { - return 0; - } - return alloc(join_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2); - } - - - class interval_relation_plugin::project_fn : public convenient_relation_project_fn { - public: - project_fn(const relation_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) - : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { - } - - virtual relation_base * operator()(const relation_base & _r) { - interval_relation const& r = get(_r); - interval_relation_plugin& p = r.get_plugin(); - interval_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); - result->mk_project(r, m_removed_cols.size(), m_removed_cols.c_ptr()); - return result; - } - }; - - relation_transformer_fn * interval_relation_plugin::mk_project_fn(const relation_base & r, - unsigned col_cnt, const unsigned * removed_cols) { - return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); - } - - class interval_relation_plugin::rename_fn : public convenient_relation_rename_fn { - public: - rename_fn(const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) - : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) { - } - - virtual relation_base * operator()(const relation_base & _r) { - interval_relation const& r = get(_r); - interval_relation_plugin& p = r.get_plugin(); - interval_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); - result->mk_rename(r, m_cycle.size(), m_cycle.c_ptr()); - return result; - } - }; - - relation_transformer_fn * interval_relation_plugin::mk_rename_fn(const relation_base & r, - unsigned cycle_len, const unsigned * permutation_cycle) { - if(!check_kind(r)) { - return 0; - } - return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle); - } - - interval interval_relation_plugin::unite(interval const& src1, interval const& src2) { - bool l_open = src1.is_lower_open(); - bool r_open = src1.is_upper_open(); - ext_numeral low = src1.inf(); - ext_numeral high = src1.sup(); - if (src2.inf() < low || (src2.inf() == low && l_open)) { - low = src2.inf(); - l_open = src2.is_lower_open(); - } - if (src2.sup() > high || (src2.sup() == high && r_open)) { - high = src2.sup(); - r_open = src2.is_upper_open(); - } - return interval(dep(), low, l_open, 0, high, r_open, 0); - } - - interval interval_relation_plugin::widen(interval const& src1, interval const& src2) { - bool l_open = src1.is_lower_open(); - bool r_open = src1.is_upper_open(); - ext_numeral low = src1.inf(); - ext_numeral high = src1.sup(); - - if (src2.inf() < low || (low == src2.inf() && l_open && !src2.is_lower_open())) { - low = ext_numeral(false); - l_open = true; - } - if (high < src2.sup() || (src2.sup() == high && !r_open && src2.is_upper_open())) { - high = ext_numeral(true); - r_open = true; - } - return interval(dep(), low, l_open, 0, high, r_open, 0); - } - - interval interval_relation_plugin::meet(interval const& src1, interval const& src2, bool& isempty) { - isempty = false; - if (is_empty(0, src1) || is_infinite(src2)) { - return src1; - } - if (is_empty(0, src2) || is_infinite(src1)) { - return src2; - } - bool l_open = src1.is_lower_open(); - bool r_open = src1.is_upper_open(); - ext_numeral low = src1.inf(); - ext_numeral high = src1.sup(); - if (src2.inf() > low || (src2.inf() == low && !l_open)) { - low = src2.inf(); - l_open = src2.is_lower_open(); - } - if (src2.sup() < high || (src2.sup() == high && !r_open)) { - high = src2.sup(); - r_open = src2.is_upper_open(); - } - if (low > high || (low == high && (l_open || r_open))) { - isempty = true; - return interval(dep()); - } - else { - return interval(dep(), low, l_open, 0, high, r_open, 0); - } - } - - bool interval_relation_plugin::is_infinite(interval const& i) { - return i.plus_infinity() && i.minus_infinity(); - } - - bool interval_relation_plugin::is_empty(unsigned, interval const& i) { - return i.sup() < i.inf(); - } - - class interval_relation_plugin::union_fn : public relation_union_fn { - bool m_is_widen; - public: - union_fn(bool is_widen) : - m_is_widen(is_widen) { - } - - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { - - TRACE("interval_relation", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); - - interval_relation& r = get(_r); - interval_relation const& src = get(_src); - if (_delta) { - interval_relation& d = get(*_delta); - r.mk_union(src, &d, m_is_widen); - } - else { - r.mk_union(src, 0, m_is_widen); - } - } - }; - - relation_union_fn * interval_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; - } - return alloc(union_fn, false); - } - - relation_union_fn * interval_relation_plugin::mk_widen_fn( - const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; - } - return alloc(union_fn, true); - } - - class interval_relation_plugin::filter_identical_fn : public relation_mutator_fn { - unsigned_vector m_identical_cols; - public: - filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) - : m_identical_cols(col_cnt, identical_cols) {} - - virtual void operator()(relation_base & r) { - interval_relation & pr = get(r); - for (unsigned i = 1; i < m_identical_cols.size(); ++i) { - unsigned c1 = m_identical_cols[0]; - unsigned c2 = m_identical_cols[i]; - pr.equate(c1, c2); - } - } - }; - - relation_mutator_fn * interval_relation_plugin::mk_filter_identical_fn( - const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { - if(!check_kind(t)) { - return 0; - } - return alloc(filter_identical_fn, col_cnt, identical_cols); - } - - - class interval_relation_plugin::filter_equal_fn : public relation_mutator_fn { - unsigned m_col; - rational m_value; - public: - filter_equal_fn(relation_manager & m, const relation_element & value, unsigned col) - : m_col(col) { - arith_util arith(m.get_context().get_manager()); - VERIFY(arith.is_numeral(value, m_value)); - } - - virtual void operator()(relation_base & _r) { - interval_relation & r = get(_r); - interval_relation_plugin & p = r.get_plugin(); - r.mk_intersect(m_col, interval(p.dep(), m_value)); - TRACE("interval_relation", tout << m_value << "\n"; r.display(tout);); - } - }; - - relation_mutator_fn * interval_relation_plugin::mk_filter_equal_fn(const relation_base & r, - const relation_element & value, unsigned col) { - if(check_kind(r)) { - return alloc(filter_equal_fn, get_manager(), value, col); - } - return 0; - } - - - class interval_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { - app_ref m_cond; - public: - filter_interpreted_fn(interval_relation const& t, app* cond): - m_cond(cond, t.get_plugin().get_ast_manager()) { - } - - void operator()(relation_base& t) { - get(t).filter_interpreted(m_cond); - TRACE("interval_relation", tout << mk_pp(m_cond, m_cond.get_manager()) << "\n"; t.display(tout);); - } - }; - - relation_mutator_fn * interval_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { - if (check_kind(t)) { - return alloc(filter_interpreted_fn, get(t), condition); - } - return 0; - } - - interval_relation& interval_relation_plugin::get(relation_base& r) { - return dynamic_cast(r); - } - - interval_relation const & interval_relation_plugin::get(relation_base const& r) { - return dynamic_cast(r); - } - - // ----------------------- - // interval_relation - - interval_relation::interval_relation(interval_relation_plugin& p, relation_signature const& s, bool is_empty): - vector_relation(p, s, is_empty, interval(p.dep())) - { - TRACE("interval_relation", tout << s.size() << "\n";); - } - - void interval_relation::add_fact(const relation_fact & f) { - interval_relation r(get_plugin(), get_signature(), false); - ast_manager& m = get_plugin().get_ast_manager(); - for (unsigned i = 0; i < f.size(); ++i) { - app_ref eq(m); - expr* e = f[i]; - eq = m.mk_eq(m.mk_var(i, m.get_sort(e)), e); - r.filter_interpreted(eq.get()); - } - mk_union(r, 0, false); - } - - bool interval_relation::contains_fact(const relation_fact & f) const { - SASSERT(f.size() == get_signature().size()); - interval_relation_plugin& p = get_plugin(); - - for (unsigned i = 0; i < f.size(); ++i) { - if (f[i] != f[find(i)]) { - return false; - } - interval const& iv = (*this)[i]; - if (p.is_infinite(iv)) { - continue; - } - rational v; - if (p.m_arith.is_numeral(f[i], v)) { - if (!iv.contains(v)) { - return false; - } - } - else { - // TBD: may or must? - } - } - return true; - } - - interval_relation * interval_relation::clone() const { - interval_relation* result = alloc(interval_relation, get_plugin(), get_signature(), empty()); - result->copy(*this); - return result; - } - - interval_relation * interval_relation::complement(func_decl*) const { - UNREACHABLE(); - return 0; - } - - void interval_relation::to_formula(expr_ref& fml) const { - ast_manager& m = get_plugin().get_ast_manager(); - arith_util& arith = get_plugin().m_arith; - expr_ref_vector conjs(m); - relation_signature const& sig = get_signature(); - for (unsigned i = 0; i < sig.size(); ++i) { - if (i != find(i)) { - conjs.push_back(m.mk_eq(m.mk_var(i, sig[i]), - m.mk_var(find(i), sig[find(i)]))); - continue; - } - interval const& iv = (*this)[i]; - sort* ty = sig[i]; - expr_ref var(m.mk_var(i, ty), m); - if (!iv.minus_infinity()) { - expr* lo = arith.mk_numeral(iv.get_lower_value(), ty); - if (iv.is_lower_open()) { - conjs.push_back(arith.mk_lt(lo, var)); - } - else { - conjs.push_back(arith.mk_le(lo, var)); - } - } - if (!iv.plus_infinity()) { - expr* hi = arith.mk_numeral(iv.get_upper_value(), ty); - if (iv.is_upper_open()) { - conjs.push_back(arith.mk_lt(var, hi)); - } - else { - conjs.push_back(arith.mk_le(var, hi)); - } - } - } - bool_rewriter br(m); - br.mk_and(conjs.size(), conjs.c_ptr(), fml); - } - - - void interval_relation::display_index(unsigned i, interval const& j, std::ostream & out) const { - out << i << " in " << j << "\n"; - } - - interval_relation_plugin& interval_relation::get_plugin() const { - return static_cast(relation_base::get_plugin()); - } - - void interval_relation::mk_intersect(unsigned idx, interval const& i) { - bool isempty; - (*this)[idx] = mk_intersect((*this)[idx], i, isempty); - if (isempty || is_empty(idx, (*this)[idx])) { - set_empty(); - } - } - - void interval_relation::mk_rename_elem(interval& i, unsigned, unsigned const* ) { - - } - - void interval_relation::filter_interpreted(app* cond) { - interval_relation_plugin& p = get_plugin(); - rational k; - unsigned x, y; - if (p.is_lt(cond, x, k, y)) { - // 0 < x - y + k - if (x == UINT_MAX) { - // y < k - mk_intersect(y, interval(p.dep(), k, true, false, 0)); - return; - } - if (y == UINT_MAX) { - // -k < x - mk_intersect(x, interval(p.dep(), -k, true, true, 0)); - return; - } - // y < x + k - ext_numeral x_hi = (*this)[x].sup(); - ext_numeral y_lo = (*this)[y].inf(); - if (!x_hi.is_infinite()) { - mk_intersect(y, interval(p.dep(), k + x_hi.to_rational(), true, false, 0)); - } - if (!y_lo.is_infinite()) { - mk_intersect(x, interval(p.dep(), y_lo.to_rational() - k, true, true, 0)); - } - return; - } - bool is_int = false; - if (p.is_le(cond, x, k, y, is_int)) { - // 0 <= x - y + k - if (x == UINT_MAX) { - // y <= k - mk_intersect(y, interval(p.dep(), k, false, false, 0)); - return; - } - if (y == UINT_MAX) { - // -k <= x - mk_intersect(x, interval(p.dep(), -k, false, true, 0)); - return; - } - ext_numeral x_hi = (*this)[x].sup(); - ext_numeral y_lo = (*this)[y].inf(); - if (!x_hi.is_infinite()) { - mk_intersect(y, interval(p.dep(), k + x_hi.to_rational(), false, false, 0)); - } - if (!y_lo.is_infinite()) { - mk_intersect(x, interval(p.dep(), y_lo.to_rational() - k, false, true, 0)); - } - return; - } - if (p.is_eq(cond, x, k, y)) { - // y = x + k - if (x == UINT_MAX) { - SASSERT(y != UINT_MAX); - mk_intersect(y, interval(p.dep(), k)); - return; - } - if (y == UINT_MAX) { - // x = - k - SASSERT(x != UINT_MAX); - mk_intersect(x, interval(p.dep(), -k)); - return; - } - interval x_i = (*this)[x]; - interval y_i = (*this)[y]; - x_i += interval(p.dep(), k); - y_i -= interval(p.dep(), k); - mk_intersect(x, y_i); - mk_intersect(y, x_i); - } - if (get_plugin().get_ast_manager().is_false(cond)) { - set_empty(); - } - } - - bool interval_relation_plugin::is_linear(expr* e, unsigned& neg, unsigned& pos, rational& k, bool is_pos) const { -#define SET_VAR(_idx_) \ - if (is_pos &&pos == UINT_MAX) { \ - pos = _idx_; \ - return true; \ - } \ - if (!is_pos && neg == UINT_MAX) { \ - neg = _idx_; \ - return true; \ - } \ - else { \ - return false; \ - } - - if (is_var(e)) { - SET_VAR(to_var(e)->get_idx()); - } - if (!is_app(e)) { - return false; - } - app* a = to_app(e); - - if (m_arith.is_add(e)) { - for (unsigned i = 0; i < a->get_num_args(); ++i) { - if (!is_linear(a->get_arg(i), neg, pos, k, is_pos)) return false; - } - return true; - } - if (m_arith.is_sub(e)) { - SASSERT(a->get_num_args() == 2); - return - is_linear(a->get_arg(0), neg, pos, k, is_pos) && - is_linear(a->get_arg(1), neg, pos, k, !is_pos); - } - rational k1; - SASSERT(!m_arith.is_mul(e) || a->get_num_args() == 2); - if (m_arith.is_mul(e) && - m_arith.is_numeral(a->get_arg(0), k1) && - k1.is_minus_one() && - is_var(a->get_arg(1))) { - SET_VAR(to_var(a->get_arg(1))->get_idx()); - } - - if (m_arith.is_numeral(e, k1)) { - if (is_pos) { - k += k1; - } - else { - k -= k1; - } - return true; - } - return false; - } - - // 0 <= x - y + k - bool interval_relation_plugin::is_le(app* cond, unsigned& x, rational& k, unsigned& y, bool& is_int) const { - ast_manager& m = get_ast_manager(); - k.reset(); - x = UINT_MAX; - y = UINT_MAX; - - if (m_arith.is_le(cond)) { - is_int = m_arith.is_int(cond->get_arg(0)); - if (!is_linear(cond->get_arg(0), y, x, k, false)) return false; - if (!is_linear(cond->get_arg(1), y, x, k, true)) return false; - return (x != UINT_MAX || y != UINT_MAX); - } - if (m_arith.is_ge(cond)) { - is_int = m_arith.is_int(cond->get_arg(0)); - if (!is_linear(cond->get_arg(0), y, x, k, true)) return false; - if (!is_linear(cond->get_arg(1), y, x, k, false)) return false; - return (x != UINT_MAX || y != UINT_MAX); - } - if (m_arith.is_lt(cond) && m_arith.is_int(cond->get_arg(0))) { - is_int = true; - if (!is_linear(cond->get_arg(0), y, x, k, false)) return false; - if (!is_linear(cond->get_arg(1), y, x, k, true)) return false; - k -= rational::one(); - return (x != UINT_MAX || y != UINT_MAX); - } - if (m_arith.is_gt(cond) && m_arith.is_int(cond->get_arg(0))) { - is_int = true; - if (!is_linear(cond->get_arg(0), y, x, k, true)) return false; - if (!is_linear(cond->get_arg(1), y, x, k, false)) return false; - k += rational::one(); - return (x != UINT_MAX || y != UINT_MAX); - } - if (m.is_not(cond) && is_app(cond->get_arg(0))) { - // not (0 <= x - y + k) - // <=> - // 0 > x - y + k - // <=> - // 0 <= y - x - k - 1 - if (is_le(to_app(cond->get_arg(0)), x, k, y, is_int) && is_int) { - k.neg(); - k -= rational::one(); - std::swap(x, y); - return true; - } - // not (0 < x - y + k) - // <=> - // 0 >= x - y + k - // <=> - // 0 <= y - x - k - if (is_lt(to_app(cond->get_arg(0)), x, k, y)) { - is_int = false; - k.neg(); - std::swap(x, y); - return true; - } - } - return false; - } - - // 0 < x - y + k - bool interval_relation_plugin::is_lt(app* cond, unsigned& x, rational& k, unsigned& y) const { - k.reset(); - x = UINT_MAX; - y = UINT_MAX; - if (m_arith.is_lt(cond) && m_arith.is_real(cond->get_arg(0))) { - if (!is_linear(cond->get_arg(0), y, x, k, false)) return false; - if (!is_linear(cond->get_arg(1), y, x, k, true)) return false; - return (x != UINT_MAX || y != UINT_MAX); - } - if (m_arith.is_gt(cond) && m_arith.is_real(cond->get_arg(0))) { - if (!is_linear(cond->get_arg(0), y, x, k, true)) return false; - if (!is_linear(cond->get_arg(1), y, x, k, false)) return false; - return (x != UINT_MAX || y != UINT_MAX); - } - return false; - } - - // 0 = x - y + k - bool interval_relation_plugin::is_eq(app* cond, unsigned& x, rational& k, unsigned& y) const { - ast_manager& m = get_ast_manager(); - k.reset(); - x = UINT_MAX; - y = UINT_MAX; - if (m.is_eq(cond)) { - if (!is_linear(cond->get_arg(0), y, x, k, false)) return false; - if (!is_linear(cond->get_arg(1), y, x, k, true)) return false; - return (x != UINT_MAX || y != UINT_MAX); - } - return false; - } - -}; - diff --git a/src/muz/dl_interval_relation.h b/src/muz/dl_interval_relation.h deleted file mode 100644 index 685ef5c86..000000000 --- a/src/muz/dl_interval_relation.h +++ /dev/null @@ -1,140 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_interval_relation.h - -Abstract: - - Basic interval reatlion. - -Author: - - Nikolaj Bjorner (nbjorner) 2010-2-11 - -Revision History: - ---*/ -#ifndef _DL_INTERVAL_RELATION_H_ -#define _DL_INTERVAL_RELATION_H_ - - -#include "dl_context.h" -#include "old_interval.h" -#include "dl_vector_relation.h" -#include "arith_decl_plugin.h" -#include "basic_simplifier_plugin.h" - -namespace datalog { - - class interval_relation; - - class interval_relation_plugin : public relation_plugin { - v_dependency_manager m_dep; - interval m_empty; - arith_util m_arith; - - class join_fn; - class project_fn; - class rename_fn; - class union_fn; - class filter_equal_fn; - class filter_identical_fn; - class filter_interpreted_fn; - friend class interval_relation; - - interval unite(interval const& src1, interval const& src2); - interval widen(interval const& src1, interval const& src2); - interval meet(interval const& src1, interval const& src2, bool& is_empty); - - v_dependency_manager & dep() const { return const_cast(m_dep); } - - public: - interval_relation_plugin(relation_manager& m); - virtual bool can_handle_signature(const relation_signature & s); - static symbol get_name() { return symbol("interval_relation"); } - virtual relation_base * mk_empty(const relation_signature & s); - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - - static bool is_empty(unsigned idx, interval const& i); - static bool is_infinite(interval const& i); - - private: - static interval_relation& get(relation_base& r); - static interval_relation const & get(relation_base const& r); - - bool is_linear(expr* e, unsigned& pos, unsigned& neg, rational& k, bool is_pos) const; - - // x + k <= y - bool is_le(app* cond, unsigned& x, rational& k, unsigned& y, bool& is_int) const; - // x + k < y - bool is_lt(app* cond, unsigned& x, rational& k, unsigned& y) const; - // x + k = y - bool is_eq(app* cond, unsigned& x, rational& k, unsigned& y) const; - }; - - - class interval_relation : public vector_relation { - friend class interval_relation_plugin; - friend class interval_relation_plugin::filter_equal_fn; - public: - interval_relation(interval_relation_plugin& p, relation_signature const& s, bool is_empty); - - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual interval_relation * clone() const; - virtual interval_relation * complement(func_decl*) const; - virtual void to_formula(expr_ref& fml) const; - interval_relation_plugin& get_plugin() const; - - void filter_interpreted(app* cond); - virtual bool is_precise() const { return false; } - - private: - - virtual interval mk_intersect(interval const& t1, interval const& t2, bool& is_empty) const { - return get_plugin().meet(t1, t2, is_empty); - } - - virtual interval mk_unite(interval const& t1, interval const& t2) const { return get_plugin().unite(t1,t2); } - - virtual interval mk_widen(interval const& t1, interval const& t2) const { return get_plugin().widen(t1,t2); } - - virtual bool is_subset_of(interval const& t1, interval const& t2) const { NOT_IMPLEMENTED_YET(); return false; } - - virtual bool is_full(interval const& t) const { - return interval_relation_plugin::is_infinite(t); - } - - virtual bool is_empty(unsigned idx, interval const& t) const { - return interval_relation_plugin::is_empty(idx, t); - } - - virtual void mk_rename_elem(interval& i, unsigned col_cnt, unsigned const* cycle); - - virtual void display_index(unsigned idx, interval const & i, std::ostream& out) const; - - void mk_intersect(unsigned idx, interval const& i); - - }; - -}; - -#endif - diff --git a/src/muz/dl_mk_explanations.cpp b/src/muz/dl_mk_explanations.cpp deleted file mode 100644 index 253bbbec7..000000000 --- a/src/muz/dl_mk_explanations.cpp +++ /dev/null @@ -1,880 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_mk_explanations.cpp - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-11-08. - -Revision History: - ---*/ - - -#include -#include"ast_pp.h" -#include "ast_smt_pp.h" -#include"dl_finite_product_relation.h" -#include"dl_product_relation.h" -#include"dl_sieve_relation.h" - -#include"dl_mk_explanations.h" - -namespace datalog { - - // ----------------------------------- - // - // explanation_relation_plugin declaration - // - // ----------------------------------- - - class explanation_relation; - - class explanation_relation_plugin : public relation_plugin { - friend class explanation_relation; - - class join_fn; - class project_fn; - class rename_fn; - class union_fn; - class foreign_union_fn; - class assignment_filter_fn; - class negation_filter_fn; - class intersection_filter_fn; - - bool m_relation_level_explanations; - - func_decl_ref m_union_decl; - - vector > m_pool; - - - app * mk_union(app * a1, app * a2) { - return get_ast_manager().mk_app(m_union_decl, a1, a2); - } - - public: - static symbol get_name(bool relation_level) { - return symbol(relation_level ? "relation_explanation" : "fact_explanation"); - } - - explanation_relation_plugin(bool relation_level, relation_manager & manager) - : relation_plugin(get_name(relation_level), manager), - m_relation_level_explanations(relation_level), - m_union_decl(mk_explanations::get_union_decl(get_context()), get_ast_manager()) {} - - ~explanation_relation_plugin() { - for (unsigned i = 0; i < m_pool.size(); ++i) { - for (unsigned j = 0; j < m_pool[i].size(); ++j) { - dealloc(m_pool[i][j]); - } - } - } - - virtual bool can_handle_signature(const relation_signature & s) { - unsigned n=s.size(); - for (unsigned i=0; i(relation_base::get_plugin()); - } - - virtual void to_formula(expr_ref& fml) const { - ast_manager& m = fml.get_manager(); - fml = m.mk_eq(m.mk_var(0, m.get_sort(m_data[0])), m_data[0]); - } - - bool is_undefined(unsigned col_idx) const { - return m_data[col_idx]==0; - } - bool no_undefined() const { - if (empty()) { - return true; - } - unsigned n = get_signature().size(); - for (unsigned i=0; i(get_plugin().mk_empty(get_signature())); - res->m_empty = m_empty; - SASSERT(res->m_data.empty()); - res->m_data.append(m_data); - return res; - } - - virtual relation_base * complement(func_decl* pred) const { - explanation_relation * res = static_cast(get_plugin().mk_empty(get_signature())); - if (empty()) { - res->set_undefined(); - } - return res; - } - - void display_explanation(app * expl, std::ostream & out) const { - if (expl) { - //TODO: some nice explanation output - ast_smt_pp pp(get_plugin().get_ast_manager()); - pp.display_expr_smt2(out, expl); - } - else { - out << ""; - } - } - - virtual void display(std::ostream & out) const { - if (empty()) { - out << "\n"; - return; - } - unsigned sz = get_signature().size(); - for (unsigned i=0; i s.size() && !m_pool[s.size()].empty()) { - explanation_relation* r = m_pool[s.size()].back(); - m_pool[s.size()].pop_back(); - r->m_empty = true; - r->m_data.reset(); - return r; - } - return alloc(explanation_relation, *this, s); - } - - void explanation_relation_plugin::recycle(explanation_relation* r) { - relation_signature const& sig = r->get_signature(); - if (m_pool.size() <= sig.size()) { - m_pool.resize(sig.size()+1); - } - m_pool[sig.size()].push_back(r); - } - - - class explanation_relation_plugin::join_fn : public convenient_relation_join_fn { - public: - join_fn(const relation_signature & sig1, const relation_signature & sig2) - : convenient_relation_join_fn(sig1, sig2, 0, 0, 0) {} - - virtual relation_base * operator()(const relation_base & r1_0, const relation_base & r2_0) { - const explanation_relation & r1 = static_cast(r1_0); - const explanation_relation & r2 = static_cast(r2_0); - explanation_relation_plugin & plugin = r1.get_plugin(); - - explanation_relation * res = static_cast(plugin.mk_empty(get_result_signature())); - if (!r1.empty() && !r2.empty()) { - res->m_empty = false; - SASSERT(res->m_data.empty()); - res->m_data.append(r1.m_data); - res->m_data.append(r2.m_data); - } - return res; - } - }; - - relation_join_fn * explanation_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (&r1.get_plugin()!=this || &r2.get_plugin()!=this) { - return 0; - } - if (col_cnt!=0) { - return 0; - } - return alloc(join_fn, r1.get_signature(), r2.get_signature()); - } - - - class explanation_relation_plugin::project_fn : public convenient_relation_project_fn { - public: - project_fn(const relation_signature & sig, unsigned col_cnt, const unsigned * removed_cols) - : convenient_relation_project_fn(sig, col_cnt, removed_cols) {} - - virtual relation_base * operator()(const relation_base & r0) { - const explanation_relation & r = static_cast(r0); - explanation_relation_plugin & plugin = r.get_plugin(); - - explanation_relation * res = static_cast(plugin.mk_empty(get_result_signature())); - if (!r.empty()) { - relation_fact proj_data = r.m_data; - project_out_vector_columns(proj_data, m_removed_cols); - res->assign_data(proj_data); - } - return res; - } - }; - - relation_transformer_fn * explanation_relation_plugin::mk_project_fn(const relation_base & r, unsigned col_cnt, - const unsigned * removed_cols) { - if (&r.get_plugin()!=this) { - return 0; - } - return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); - } - - - class explanation_relation_plugin::rename_fn : public convenient_relation_rename_fn { - public: - rename_fn(const relation_signature & sig, unsigned permutation_cycle_len, const unsigned * permutation_cycle) - : convenient_relation_rename_fn(sig, permutation_cycle_len, permutation_cycle) {} - - virtual relation_base * operator()(const relation_base & r0) { - const explanation_relation & r = static_cast(r0); - explanation_relation_plugin & plugin = r.get_plugin(); - - explanation_relation * res = static_cast(plugin.mk_empty(get_result_signature())); - if (!r.empty()) { - relation_fact permutated_data = r.m_data; - permutate_by_cycle(permutated_data, m_cycle); - res->assign_data(permutated_data); - } - return res; - } - }; - - relation_transformer_fn * explanation_relation_plugin::mk_rename_fn(const relation_base & r, - unsigned permutation_cycle_len, const unsigned * permutation_cycle) { - return alloc(rename_fn, r.get_signature(), permutation_cycle_len, permutation_cycle); - } - - - class explanation_relation_plugin::union_fn : public relation_union_fn { - scoped_ptr m_delta_union_fun; - public: - virtual void operator()(relation_base & tgt0, const relation_base & src0, relation_base * delta0) { - explanation_relation & tgt = static_cast(tgt0); - const explanation_relation & src = static_cast(src0); - explanation_relation * delta = delta0 ? static_cast(delta0) : 0; - explanation_relation_plugin & plugin = tgt.get_plugin(); - - if (!src.no_undefined() || !tgt.no_undefined() || (delta && !delta->no_undefined())) { - UNREACHABLE(); - } - if (src.empty()) { - return; - } - if (plugin.m_relation_level_explanations) { - tgt.unite_with_data(src.m_data); - if (delta) { - if (!m_delta_union_fun) { - m_delta_union_fun = plugin.get_manager().mk_union_fn(*delta, src); - SASSERT(m_delta_union_fun); - } - (*m_delta_union_fun)(*delta, src); - } - } - else { - if (tgt.empty()) { - tgt.assign_data(src.m_data); - if (delta && delta->empty()) { - delta->assign_data(src.m_data); - } - } - } - } - }; - - class explanation_relation_plugin::foreign_union_fn : public relation_union_fn { - scoped_ptr m_delta_union_fun; - public: - virtual void operator()(relation_base & tgt0, const relation_base & src, relation_base * delta0) { - explanation_relation & tgt = static_cast(tgt0); - explanation_relation * delta = delta0 ? static_cast(delta0) : 0; - - if (src.empty()) { - return; - } - tgt.set_undefined(); - if (delta) { - delta->set_undefined(); - } - } - }; - - relation_union_fn * explanation_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if (!check_kind(tgt) || (delta && !check_kind(*delta))) { - return 0; - } - if (!check_kind(src)) { - //this is to handle the product relation - return alloc(foreign_union_fn); - } - return alloc(union_fn); - } - - class explanation_relation_plugin::assignment_filter_fn : public relation_mutator_fn { - ast_manager & m_manager; - var_subst & m_subst; - unsigned m_col_idx; - app_ref m_new_rule; - public: - assignment_filter_fn(context & ctx, unsigned col_idx, app_ref new_rule) - : m_manager(ctx.get_manager()), - m_subst(ctx.get_var_subst()), - m_col_idx(col_idx), - m_new_rule(new_rule) {} - - virtual void operator()(relation_base & r0) { - explanation_relation & r = static_cast(r0); - - if (!r.is_undefined(m_col_idx)) { - UNREACHABLE(); - } - - unsigned sz = r.get_signature().size(); - ptr_vector subst_arg; - subst_arg.resize(sz, 0); - unsigned ofs = sz-1; - for (unsigned i=0; iget_arg(0); - expr * arg2 = cond->get_arg(1); - - if (is_var(arg2)) { - std::swap(arg1, arg2); - } - - if (!is_var(arg1) || !is_app(arg2)) { - return 0; - } - var * col_var = to_var(arg1); - app * new_rule = to_app(arg2); - if (!get_context().get_decl_util().is_rule_sort(col_var->get_sort())) { - return 0; - } - unsigned col_idx = col_var->get_idx(); - - return alloc(assignment_filter_fn, get_context(), col_idx, app_ref(new_rule, get_ast_manager())); - } - - - class explanation_relation_plugin::negation_filter_fn : public relation_intersection_filter_fn { - public: - virtual void operator()(relation_base & r, const relation_base & neg) { - if (!neg.empty()) { - r.reset(); - } - } - }; - - relation_intersection_filter_fn * explanation_relation_plugin::mk_filter_by_negation_fn(const relation_base & r, - const relation_base & neg, unsigned joined_col_cnt, const unsigned * t_cols, - const unsigned * negated_cols) { - if (&r.get_plugin()!=this || &neg.get_plugin()!=this) { - return 0; - } - return alloc(negation_filter_fn); - } - - class explanation_relation_plugin::intersection_filter_fn : public relation_intersection_filter_fn { - func_decl_ref m_union_decl; - public: - intersection_filter_fn(explanation_relation_plugin & plugin) - : m_union_decl(plugin.m_union_decl) {} - - virtual void operator()(relation_base & tgt0, const relation_base & src0) { - explanation_relation & tgt = static_cast(tgt0); - const explanation_relation & src = static_cast(src0); - - if (src.empty()) { - tgt.reset(); - return; - } - if (tgt.empty()) { - return; - } - unsigned sz = tgt.get_signature().size(); - for (unsigned i=0; iget_decl()==m_union_decl.get()) { - if (curr_tgt->get_arg(0)==curr_src || curr_tgt->get_arg(1)==curr_src) { - tgt.m_data.set(i, curr_src); - continue; - } - } - //the intersection is imprecise because we do nothing here, but it is good enough for - //the purpose of explanations - } - } - }; - - relation_intersection_filter_fn * explanation_relation_plugin::mk_filter_by_intersection_fn( - const relation_base & tgt, const relation_base & src, unsigned joined_col_cnt, - const unsigned * tgt_cols, const unsigned * src_cols) { - if (&tgt.get_plugin()!=this || &src.get_plugin()!=this) { - return 0; - } - //this checks the join is one to one on all columns - if (tgt.get_signature()!=src.get_signature() - || joined_col_cnt!=tgt.get_signature().size() - || !containers_equal(tgt_cols, tgt_cols+joined_col_cnt, src_cols, src_cols+joined_col_cnt)) { - return 0; - } - counter ctr; - ctr.count(joined_col_cnt, tgt_cols); - if (ctr.get_max_counter_value()>1 || (joined_col_cnt && ctr.get_max_positive()!=joined_col_cnt-1)) { - return 0; - } - return alloc(intersection_filter_fn, *this); - } - - - // ----------------------------------- - // - // mk_explanations - // - // ----------------------------------- - - - mk_explanations::mk_explanations(context & ctx) - : plugin(50000), - m_manager(ctx.get_manager()), - m_context(ctx), - m_decl_util(ctx.get_decl_util()), - m_relation_level(ctx.explanations_on_relation_level()), - m_pinned(m_manager) { - m_e_sort = m_decl_util.mk_rule_sort(); - m_pinned.push_back(m_e_sort); - - relation_manager & rmgr = ctx.get_rel_context()->get_rmanager(); - symbol er_symbol = explanation_relation_plugin::get_name(m_relation_level); - m_er_plugin = static_cast(rmgr.get_relation_plugin(er_symbol)); - if (!m_er_plugin) { - m_er_plugin = alloc(explanation_relation_plugin, m_relation_level, rmgr); - rmgr.register_plugin(m_er_plugin); - if (!m_relation_level) { - DEBUG_CODE( - finite_product_relation_plugin * dummy; - SASSERT(!rmgr.try_get_finite_product_relation_plugin(*m_er_plugin, dummy)); - ); - rmgr.register_plugin(alloc(finite_product_relation_plugin, *m_er_plugin, rmgr)); - } - } - DEBUG_CODE( - if (!m_relation_level) { - finite_product_relation_plugin * dummy; - SASSERT(rmgr.try_get_finite_product_relation_plugin(*m_er_plugin, dummy)); - } - ); - } - - func_decl * mk_explanations::get_union_decl(context & ctx) { - ast_manager & m = ctx.get_manager(); - sort_ref s(ctx.get_decl_util().mk_rule_sort(), m); - //can it happen that the function name would collide with some other symbol? - //if functions can be overloaded by their ranges, it should be fine. - return m.mk_func_decl(symbol("e_union"), s, s, s); - } - - void mk_explanations::assign_rel_level_kind(func_decl * e_decl, func_decl * orig) { - SASSERT(m_relation_level); - - relation_manager & rmgr = m_context.get_rel_context()->get_rmanager(); - unsigned sz = e_decl->get_arity(); - relation_signature sig; - rmgr.from_predicate(e_decl, sig); - - svector inner_sieve(sz-1, true); - inner_sieve.push_back(false); - - svector expl_sieve(sz-1, false); - expl_sieve.push_back(true); - - sieve_relation_plugin & sieve_plugin = sieve_relation_plugin::get_plugin(rmgr); - - family_id inner_kind = rmgr.get_requested_predicate_kind(orig); //may be null_family_id - family_id inner_sieve_kind = sieve_plugin.get_relation_kind(sig, inner_sieve, inner_kind); - family_id expl_kind = m_er_plugin->get_kind(); - family_id expl_sieve_kind = sieve_plugin.get_relation_kind(sig, expl_sieve, expl_kind); - - product_relation_plugin::rel_spec product_spec; - product_spec.push_back(inner_sieve_kind); - product_spec.push_back(expl_sieve_kind); - - family_id pred_kind = - product_relation_plugin::get_plugin(rmgr).get_relation_kind(sig, product_spec); - - rmgr.set_predicate_kind(e_decl, pred_kind); - } - - func_decl * mk_explanations::get_e_decl(func_decl * orig_decl) { - decl_map::obj_map_entry * e = m_e_decl_map.insert_if_not_there2(orig_decl, 0); - if (e->get_data().m_value==0) { - relation_signature e_domain; - e_domain.append(orig_decl->get_arity(), orig_decl->get_domain()); - e_domain.push_back(m_e_sort); - func_decl * new_decl = m_context.mk_fresh_head_predicate(orig_decl->get_name(), symbol("expl"), - e_domain.size(), e_domain.c_ptr(), orig_decl); - m_pinned.push_back(new_decl); - e->get_data().m_value = new_decl; - - if (m_relation_level) { - assign_rel_level_kind(new_decl, orig_decl); - } - } - return e->get_data().m_value; - } - - app * mk_explanations::get_e_lit(app * lit, unsigned e_var_idx) { - expr_ref_vector args(m_manager); - func_decl * e_decl = get_e_decl(lit->get_decl()); - args.append(lit->get_num_args(), lit->get_args()); - args.push_back(m_manager.mk_var(e_var_idx, m_e_sort)); - return m_manager.mk_app(e_decl, args.c_ptr()); - } - - symbol mk_explanations::get_rule_symbol(rule * r) { - if (r->name() == symbol::null) { - std::stringstream sstm; - r->display(m_context, sstm); - std::string res = sstm.str(); - res = res.substr(0, res.find_last_not_of('\n')+1); - return symbol(res.c_str()); - } - else { - return r->name(); - } - } - - rule * mk_explanations::get_e_rule(rule * r) { - rule_counter ctr; - ctr.count_rule_vars(m_manager, r); - unsigned max_var; - unsigned next_var = ctr.get_max_positive(max_var) ? (max_var+1) : 0; - unsigned head_var = next_var++; - app_ref e_head(get_e_lit(r->get_head(), head_var), m_manager); - - app_ref_vector e_tail(m_manager); - svector neg_flags; - unsigned pos_tail_sz = r->get_positive_tail_size(); - for (unsigned i=0; iget_tail(i), e_var)); - neg_flags.push_back(false); - } - unsigned tail_sz = r->get_tail_size(); - for (unsigned i=pos_tail_sz; iget_tail(i)); - neg_flags.push_back(r->is_neg_tail(i)); - } - - symbol rule_repr = get_rule_symbol(r); - - expr_ref_vector rule_expr_args(m_manager); - for (unsigned tail_idx=0; tail_idxget_arg(tail->get_num_args()-1)); - } - else { - //this adds argument values and the explanation term - //(values will be substituted for variables at runtime by the finite_product_relation) - rule_expr_args.append(tail->get_num_args(), tail->get_args()); - } - } - //rule_expr contains rule function with string representation of the rule as symbol and - //for each positive uninterpreted tail it contains its argument values and its explanation term - expr * rule_expr = m_decl_util.mk_rule(rule_repr, rule_expr_args.size(), rule_expr_args.c_ptr()); - - app_ref e_record(m_manager.mk_eq(m_manager.mk_var(head_var, m_e_sort), rule_expr), m_manager); - e_tail.push_back(e_record); - neg_flags.push_back(false); - SASSERT(e_tail.size()==neg_flags.size()); - - return m_context.get_rule_manager().mk(e_head, e_tail.size(), e_tail.c_ptr(), neg_flags.c_ptr()); - } - - void mk_explanations::transform_rules(const rule_set & src, rule_set & dst) { - rule_set::iterator rit = src.begin(); - rule_set::iterator rend = src.end(); - for (; rit!=rend; ++rit) { - rule * e_rule = get_e_rule(*rit); - dst.add_rule(e_rule); - } - - //add rules that will (for output predicates) copy facts from explained relations back to - //the original ones - expr_ref_vector lit_args(m_manager); - decl_set::iterator pit = src.get_output_predicates().begin(); - decl_set::iterator pend = src.get_output_predicates().end(); - for (; pit != pend; ++pit) { - func_decl * orig_decl = *pit; - - lit_args.reset(); - unsigned arity = orig_decl->get_arity(); - for (unsigned i=0; iget_domain(i))); - } - app_ref orig_lit(m_manager.mk_app(orig_decl, lit_args.c_ptr()), m_manager); - app_ref e_lit(get_e_lit(orig_lit, arity), m_manager); - app * tail[] = { e_lit.get() }; - dst.add_rule(m_context.get_rule_manager().mk(orig_lit, 1, tail, 0)); - } - } - - void mk_explanations::translate_rel_level_relation(relation_manager & rmgr, relation_base & orig, - relation_base & e_rel) { - SASSERT(m_e_fact_relation); - SASSERT(e_rel.get_plugin().is_product_relation()); - - product_relation & prod_rel = static_cast(e_rel); - SASSERT(prod_rel.size()==2); - SASSERT(prod_rel[0].get_plugin().is_sieve_relation()); - SASSERT(prod_rel[1].get_plugin().is_sieve_relation()); - sieve_relation * srels[] = { - static_cast(&prod_rel[0]), - static_cast(&prod_rel[1]) }; - if (&srels[0]->get_inner().get_plugin()==m_er_plugin) { - std::swap(srels[0], srels[1]); - } - SASSERT(&srels[0]->get_inner().get_plugin()==&orig.get_plugin()); - SASSERT(&srels[1]->get_inner().get_plugin()==m_er_plugin); - - relation_base & new_orig = srels[0]->get_inner(); - explanation_relation & expl_rel = static_cast(srels[1]->get_inner()); - - { - scoped_ptr orig_union_fun = rmgr.mk_union_fn(new_orig, orig); - SASSERT(orig_union_fun); - (*orig_union_fun)(new_orig, orig); - } - - { - scoped_ptr expl_union_fun = rmgr.mk_union_fn(expl_rel, *m_e_fact_relation); - SASSERT(expl_union_fun); - (*expl_union_fun)(expl_rel, *m_e_fact_relation); - } - } - - void mk_explanations::transform_facts(relation_manager & rmgr, rule_set const& src, rule_set& dst) { - - if (!m_e_fact_relation) { - relation_signature expl_singleton_sig; - expl_singleton_sig.push_back(m_e_sort); - - relation_base * expl_singleton = rmgr.mk_empty_relation(expl_singleton_sig, m_er_plugin->get_kind()); - relation_fact es_fact(m_manager); - es_fact.push_back(m_decl_util.mk_fact(symbol("fact"))); - expl_singleton->add_fact(es_fact); - - SASSERT(&expl_singleton->get_plugin()==m_er_plugin); - m_e_fact_relation = static_cast(expl_singleton); - } - func_decl_set const& predicates = m_context.get_predicates(); - decl_set::iterator it = predicates.begin(); - decl_set::iterator end = predicates.end(); - for (; it!=end; ++it) { - func_decl * orig_decl = *it; - func_decl * e_decl = get_e_decl(orig_decl); - - if (!rmgr.try_get_relation(orig_decl) && - !src.contains(orig_decl)) { - // there are no facts or rules for this predicate - continue; - } - - dst.inherit_predicate(src, orig_decl, e_decl); - - relation_base & orig_rel = rmgr.get_relation(orig_decl); - relation_base & e_rel = rmgr.get_relation(e_decl); - SASSERT(e_rel.empty()); //the e_rel should be a new relation - - if (m_relation_level) { - translate_rel_level_relation(rmgr, orig_rel, e_rel); - } - else { - scoped_ptr product_fun = rmgr.mk_join_fn(orig_rel, *m_e_fact_relation, 0, 0, 0); - SASSERT(product_fun); - scoped_rel aux_extended_rel = (*product_fun)(orig_rel, *m_e_fact_relation); - scoped_ptr union_fun = rmgr.mk_union_fn(e_rel, *aux_extended_rel); - SASSERT(union_fun); - (*union_fun)(e_rel, *aux_extended_rel); - } - } - } - - rule_set * mk_explanations::operator()(rule_set const & source) { - - if (source.empty()) { - return 0; - } - if (!m_context.generate_explanations()) { - return 0; - } - rule_set * res = alloc(rule_set, m_context); - transform_facts(m_context.get_rel_context()->get_rmanager(), source, *res); - transform_rules(source, *res); - return res; - } - -}; - diff --git a/src/muz/dl_mk_explanations.h b/src/muz/dl_mk_explanations.h deleted file mode 100644 index 9e4d705c3..000000000 --- a/src/muz/dl_mk_explanations.h +++ /dev/null @@ -1,86 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_mk_explanations.h - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-11-08. - -Revision History: - ---*/ - -#ifndef _DL_MK_EXPLANATIONS_H_ -#define _DL_MK_EXPLANATIONS_H_ - -#include "dl_context.h" -#include "dl_rule_transformer.h" - -namespace datalog { - - class explanation_relation; - class explanation_relation_plugin; - - class mk_explanations : public rule_transformer::plugin { - - typedef obj_map decl_map; - - ast_manager & m_manager; - context & m_context; - dl_decl_util & m_decl_util; - bool m_relation_level; - ast_ref_vector m_pinned; - explanation_relation_plugin * m_er_plugin; - sort * m_e_sort; - scoped_rel m_e_fact_relation; - - decl_map m_e_decl_map; - - symbol get_rule_symbol(rule * r); - - app * get_e_lit(app * lit, unsigned e_var_idx); - rule * get_e_rule(rule * r); - - /** - If \c m_relation_level is true, ensure \c e_decl predicate will be represented by - the right relation object. \c orig is the predicate corresponding to \c e_decl without - the explanation column. - */ - void assign_rel_level_kind(func_decl * e_decl, func_decl * orig); - void translate_rel_level_relation(relation_manager & rmgr, relation_base & orig, relation_base & e_rel); - - void transform_rules(const rule_set & src, rule_set & dst); - - void transform_facts(relation_manager & rmgr, rule_set const& src, rule_set& dst); - public: - /** - If relation_level is true, the explanation will not be stored for each fact, - but we will rather store history of the whole relation. - */ - mk_explanations(context & ctx); - - /** - \brief Return explanation predicate that corresponds to \c orig_decl. - */ - func_decl * get_e_decl(func_decl * orig_decl); - - static func_decl * get_union_decl(context & ctx); - func_decl * get_union_decl() const { - return get_union_decl(m_context); - } - - rule_set * operator()(rule_set const & source); - - static expr* get_explanation(relation_base const& r); - }; -}; - -#endif /* _DL_MK_EXPLANATIONS_H_ */ - diff --git a/src/muz/dl_mk_karr_invariants.cpp b/src/muz/dl_mk_karr_invariants.cpp deleted file mode 100644 index 11bc850bb..000000000 --- a/src/muz/dl_mk_karr_invariants.cpp +++ /dev/null @@ -1,1114 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - dl_mk_karr_invariants.cpp - -Abstract: - - Extract integer linear invariants. - - The linear invariants are extracted according to Karr's method. - A short description is in - Nikolaj Bjorner, Anca Browne and Zohar Manna. Automatic Generation - of Invariants and Intermediate Assertions, in CP 95. - - The algorithm is here adapted to Horn clauses. - The idea is to maintain two data-structures for each recursive relation. - We call them R and RD - - R - set of linear congruences that are true of R. - - RD - the dual basis of of solutions for R. - - RD is updated by accumulating basis vectors for solutions - to R (the homogeneous dual of R) - R is updated from the inhomogeneous dual of RD. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-03-09 - -Revision History: - ---*/ - -#include"dl_mk_karr_invariants.h" -#include"expr_safe_replace.h" -#include"bool_rewriter.h" -#include"dl_mk_backwards.h" -#include"dl_mk_loop_counter.h" -#include "for_each_expr.h" - -namespace datalog { - - - mk_karr_invariants::mk_karr_invariants(context & ctx, unsigned priority): - rule_transformer::plugin(priority, false), - m_ctx(ctx), - m(ctx.get_manager()), - rm(ctx.get_rule_manager()), - m_inner_ctx(m, ctx.get_fparams()), - a(m), - m_pinned(m), - m_cancel(false) { - params_ref params; - params.set_sym("default_relation", symbol("karr_relation")); - params.set_sym("engine", symbol("datalog")); - params.set_bool("karr", false); - m_inner_ctx.updt_params(params); - } - - mk_karr_invariants::~mk_karr_invariants() { } - - matrix& matrix::operator=(matrix const& other) { - reset(); - append(other); - return *this; - } - - void matrix::display_row( - std::ostream& out, vector const& row, rational const& b, bool is_eq) { - for (unsigned j = 0; j < row.size(); ++j) { - out << row[j] << " "; - } - out << (is_eq?" = ":" >= ") << -b << "\n"; - } - - void matrix::display_ineq( - std::ostream& out, vector const& row, rational const& b, bool is_eq) { - bool first = true; - for (unsigned j = 0; j < row.size(); ++j) { - if (!row[j].is_zero()) { - if (!first && row[j].is_pos()) { - out << "+ "; - } - if (row[j].is_minus_one()) { - out << "- "; - } - if (row[j] > rational(1) || row[j] < rational(-1)) { - out << row[j] << "*"; - } - out << "x" << j << " "; - first = false; - } - } - out << (is_eq?"= ":">= ") << -b << "\n"; - } - - void matrix::display(std::ostream& out) const { - for (unsigned i = 0; i < A.size(); ++i) { - display_row(out, A[i], b[i], eq[i]); - } - } - - - class mk_karr_invariants::add_invariant_model_converter : public model_converter { - ast_manager& m; - arith_util a; - func_decl_ref_vector m_funcs; - expr_ref_vector m_invs; - public: - - add_invariant_model_converter(ast_manager& m): m(m), a(m), m_funcs(m), m_invs(m) {} - - virtual ~add_invariant_model_converter() { } - - void add(func_decl* p, expr* inv) { - if (!m.is_true(inv)) { - m_funcs.push_back(p); - m_invs.push_back(inv); - } - } - - virtual void operator()(model_ref & mr) { - for (unsigned i = 0; i < m_funcs.size(); ++i) { - func_decl* p = m_funcs[i].get(); - func_interp* f = mr->get_func_interp(p); - expr_ref body(m); - unsigned arity = p->get_arity(); - SASSERT(0 < arity); - if (f) { - SASSERT(f->num_entries() == 0); - if (!f->is_partial()) { - bool_rewriter(m).mk_and(f->get_else(), m_invs[i].get(), body); - } - } - else { - f = alloc(func_interp, m, arity); - mr->register_decl(p, f); - body = m.mk_false(); // fragile: assume that relation was pruned by being infeasible. - } - f->set_else(body); - } - } - - virtual model_converter * translate(ast_translation & translator) { - add_invariant_model_converter* mc = alloc(add_invariant_model_converter, m); - for (unsigned i = 0; i < m_funcs.size(); ++i) { - mc->add(translator(m_funcs[i].get()), m_invs[i].get()); - } - return mc; - } - - private: - void mk_body(matrix const& M, expr_ref& body) { - expr_ref_vector conj(m); - for (unsigned i = 0; i < M.size(); ++i) { - mk_body(M.A[i], M.b[i], M.eq[i], conj); - } - bool_rewriter(m).mk_and(conj.size(), conj.c_ptr(), body); - } - - void mk_body(vector const& row, rational const& b, bool is_eq, expr_ref_vector& conj) { - expr_ref_vector sum(m); - expr_ref zero(m), lhs(m); - zero = a.mk_numeral(rational(0), true); - - for (unsigned i = 0; i < row.size(); ++i) { - if (row[i].is_zero()) { - continue; - } - var* var = m.mk_var(i, a.mk_int()); - if (row[i].is_one()) { - sum.push_back(var); - } - else { - sum.push_back(a.mk_mul(a.mk_numeral(row[i], true), var)); - } - } - if (!b.is_zero()) { - sum.push_back(a.mk_numeral(b, true)); - } - lhs = a.mk_add(sum.size(), sum.c_ptr()); - if (is_eq) { - conj.push_back(m.mk_eq(lhs, zero)); - } - else { - conj.push_back(a.mk_ge(lhs, zero)); - } - } - }; - - void mk_karr_invariants::cancel() { - m_cancel = true; - m_inner_ctx.cancel(); - } - - rule_set * mk_karr_invariants::operator()(rule_set const & source) { - if (!m_ctx.get_params().karr()) { - return 0; - } - rule_set::iterator it = source.begin(), end = source.end(); - for (; it != end; ++it) { - rule const& r = **it; - if (r.has_negation()) { - return 0; - } - } - mk_loop_counter lc(m_ctx); - mk_backwards bwd(m_ctx); - - scoped_ptr src_loop = lc(source); - TRACE("dl", src_loop->display(tout << "source loop\n");); - - get_invariants(*src_loop); - - if (m_cancel) { - return 0; - } - - // figure out whether to update same rules as used for saturation. - scoped_ptr rev_source = bwd(*src_loop); - get_invariants(*rev_source); - scoped_ptr src_annot = update_rules(*src_loop); - rule_set* rules = lc.revert(*src_annot); - rules->inherit_predicates(source); - TRACE("dl", rules->display(tout);); - m_pinned.reset(); - m_fun2inv.reset(); - return rules; - } - - void mk_karr_invariants::get_invariants(rule_set const& src) { - m_inner_ctx.reset(); - rel_context& rctx = *m_inner_ctx.get_rel_context(); - ptr_vector heads; - func_decl_set const& predicates = m_ctx.get_predicates(); - for (func_decl_set::iterator fit = predicates.begin(); fit != predicates.end(); ++fit) { - m_inner_ctx.register_predicate(*fit, false); - } - m_inner_ctx.ensure_opened(); - m_inner_ctx.replace_rules(src); - m_inner_ctx.close(); - rule_set::decl2rules::iterator dit = src.begin_grouped_rules(); - rule_set::decl2rules::iterator dend = src.end_grouped_rules(); - for (; dit != dend; ++dit) { - heads.push_back(dit->m_key); - } - m_inner_ctx.rel_query(heads.size(), heads.c_ptr()); - - // retrieve invariants. - dit = src.begin_grouped_rules(); - for (; dit != dend; ++dit) { - func_decl* p = dit->m_key; - relation_base* rb = rctx.try_get_relation(p); - if (rb) { - expr_ref fml(m); - rb->to_formula(fml); - if (m.is_true(fml)) { - continue; - } - expr* inv = 0; - if (m_fun2inv.find(p, inv)) { - fml = m.mk_and(inv, fml); - } - m_pinned.push_back(fml); - m_fun2inv.insert(p, fml); - } - } - } - - rule_set* mk_karr_invariants::update_rules(rule_set const& src) { - scoped_ptr dst = alloc(rule_set, m_ctx); - rule_set::iterator it = src.begin(), end = src.end(); - for (; it != end; ++it) { - update_body(*dst, **it); - } - if (m_ctx.get_model_converter()) { - add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m); - rule_set::decl2rules::iterator git = src.begin_grouped_rules(); - rule_set::decl2rules::iterator gend = src.end_grouped_rules(); - for (; git != gend; ++git) { - func_decl* p = git->m_key; - expr* fml = 0; - if (m_fun2inv.find(p, fml)) { - kmc->add(p, fml); - } - } - m_ctx.add_model_converter(kmc); - } - - dst->inherit_predicates(src); - return dst.detach(); - } - - void mk_karr_invariants::update_body(rule_set& rules, rule& r) { - unsigned utsz = r.get_uninterpreted_tail_size(); - unsigned tsz = r.get_tail_size(); - app_ref_vector tail(m); - expr_ref fml(m); - for (unsigned i = 0; i < tsz; ++i) { - tail.push_back(r.get_tail(i)); - } - for (unsigned i = 0; i < utsz; ++i) { - func_decl* q = r.get_decl(i); - expr* fml = 0; - if (m_fun2inv.find(q, fml)) { - expr_safe_replace rep(m); - for (unsigned j = 0; j < q->get_arity(); ++j) { - rep.insert(m.mk_var(j, q->get_domain(j)), - r.get_tail(i)->get_arg(j)); - } - expr_ref tmp(fml, m); - rep(tmp); - tail.push_back(to_app(tmp)); - } - } - rule* new_rule = &r; - if (tail.size() != tsz) { - new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name()); - } - rules.add_rule(new_rule); - rm.mk_rule_rewrite_proof(r, *new_rule); // should be weakening rule. - } - - - - class karr_relation : public relation_base { - friend class karr_relation_plugin; - friend class karr_relation_plugin::filter_equal_fn; - - karr_relation_plugin& m_plugin; - ast_manager& m; - mutable arith_util a; - func_decl_ref m_fn; - mutable bool m_empty; - mutable matrix m_ineqs; - mutable bool m_ineqs_valid; - mutable matrix m_basis; - mutable bool m_basis_valid; - - public: - karr_relation(karr_relation_plugin& p, func_decl* f, relation_signature const& s, bool is_empty): - relation_base(p, s), - m_plugin(p), - m(p.get_ast_manager()), - a(m), - m_fn(f, m), - m_empty(is_empty), - m_ineqs_valid(!is_empty), - m_basis_valid(false) - { - } - - virtual bool empty() const { - return m_empty; - } - - virtual bool is_precise() const { return false; } - - virtual void add_fact(const relation_fact & f) { - SASSERT(m_empty); - SASSERT(!m_basis_valid); - m_empty = false; - m_ineqs_valid = true; - for (unsigned i = 0; i < f.size(); ++i) { - rational n; - if (a.is_numeral(f[i], n) && n.is_int()) { - vector row; - row.resize(f.size()); - row[i] = rational(1); - m_ineqs.A.push_back(row); - m_ineqs.b.push_back(-n); - m_ineqs.eq.push_back(true); - } - } - } - - virtual bool contains_fact(const relation_fact & f) const { - UNREACHABLE(); - return false; - } - - virtual void display(std::ostream & out) const { - if (m_fn) { - out << m_fn->get_name() << "\n"; - } - if (empty()) { - out << "empty\n"; - } - else { - if (m_ineqs_valid) { - m_ineqs.display(out << "ineqs:\n"); - } - if (m_basis_valid) { - m_basis.display(out << "basis:\n"); - } - } - } - - virtual karr_relation * clone() const { - karr_relation* result = alloc(karr_relation, m_plugin, m_fn, get_signature(), m_empty); - result->copy(*this); - return result; - } - - virtual karr_relation * complement(func_decl*) const { - UNREACHABLE(); - return 0; - } - - virtual void to_formula(expr_ref& fml) const { - if (empty()) { - fml = m.mk_false(); - } - else { - matrix const& M = get_ineqs(); - expr_ref_vector conj(m); - for (unsigned i = 0; i < M.size(); ++i) { - to_formula(M.A[i], M.b[i], M.eq[i], conj); - } - bool_rewriter(m).mk_and(conj.size(), conj.c_ptr(), fml); - } - } - - karr_relation_plugin& get_plugin() const { return m_plugin; } - - void filter_interpreted(app* cond) { - rational one(1), mone(-1); - expr* e1, *e2, *en; - var* v, *w; - rational n1, n2; - expr_ref_vector conjs(m); - qe::flatten_and(cond, conjs); - matrix& M = get_ineqs(); - unsigned num_columns = get_signature().size(); - - for (unsigned i = 0; i < conjs.size(); ++i) { - expr* e = conjs[i].get(); - rational b(0); - vector row; - row.resize(num_columns, rational(0)); - bool processed = true; - if (m.is_eq(e, e1, e2) && is_linear(e1, row, b, one) && is_linear(e2, row, b, mone)) { - M.A.push_back(row); - M.b.push_back(b); - M.eq.push_back(true); - } - else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b); - M.eq.push_back(false); - } - else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b - rational(1)); - M.eq.push_back(false); - } - else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b); - M.eq.push_back(false); - } - else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && - is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { - M.A.push_back(row); - M.b.push_back(b - rational(1)); - M.eq.push_back(false); - } - else if (m.is_or(e, e1, e2) && is_eq(e1, v, n1) && is_eq(e2, w, n2) && v == w) { - if (n1 > n2) { - std::swap(n1, n2); - } - SASSERT(n1 <= n2); - row[v->get_idx()] = rational(1); - // v - n1 >= 0 - M.A.push_back(row); - M.b.push_back(-n1); - M.eq.push_back(false); - // -v + n2 >= 0 - row[v->get_idx()] = rational(-1); - M.A.push_back(row); - M.b.push_back(n2); - M.eq.push_back(false); - } - else { - processed = false; - } - TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n"; - if (processed) matrix::display_ineq(tout, row, M.b.back(), M.eq.back()); - ); - } - TRACE("dl", display(tout);); - } - - void mk_join(karr_relation const& r1, karr_relation const& r2, - unsigned col_cnt, unsigned const* cols1, unsigned const* cols2) { - if (r1.empty() || r2.empty()) { - m_empty = true; - return; - } - matrix const& M1 = r1.get_ineqs(); - matrix const& M2 = r2.get_ineqs(); - unsigned sig1_size = r1.get_signature().size(); - unsigned sig_size = get_signature().size(); - m_ineqs.reset(); - for (unsigned i = 0; i < M1.size(); ++i) { - vector row; - row.append(M1.A[i]); - row.resize(sig_size); - m_ineqs.A.push_back(row); - m_ineqs.b.push_back(M1.b[i]); - m_ineqs.eq.push_back(M1.eq[i]); - } - for (unsigned i = 0; i < M2.size(); ++i) { - vector row; - row.resize(sig_size); - for (unsigned j = 0; j < M2.A[i].size(); ++j) { - row[sig1_size + j] = M2.A[i][j]; - } - m_ineqs.A.push_back(row); - m_ineqs.b.push_back(M2.b[i]); - m_ineqs.eq.push_back(M2.eq[i]); - } - for (unsigned i = 0; i < col_cnt; ++i) { - vector row; - row.resize(sig_size); - row[cols1[i]] = rational(1); - row[sig1_size + cols2[i]] = rational(-1); - m_ineqs.A.push_back(row); - m_ineqs.b.push_back(rational(0)); - m_ineqs.eq.push_back(true); - } - m_ineqs_valid = true; - m_basis_valid = false; - m_empty = false; - if (r1.m_fn) { - m_fn = r1.m_fn; - } - if (r2.m_fn) { - m_fn = r2.m_fn; - } - } - - void mk_project(karr_relation const& r, unsigned cnt, unsigned const* cols) { - if (r.m_empty) { - m_empty = true; - return; - } - matrix const& M = r.get_basis(); - m_basis.reset(); - for (unsigned i = 0; i < M.size(); ++i) { - vector row; - unsigned k = 0; - for (unsigned j = 0; j < M.A[i].size(); ++j) { - if (k < cnt && j == cols[k]) { - ++k; - } - else { - row.push_back(M.A[i][j]); - } - } - SASSERT(row.size() + cnt == M.A[i].size()); - SASSERT(M.eq[i]); - m_basis.A.push_back(row); - m_basis.b.push_back(M.b[i]); - m_basis.eq.push_back(true); - } - m_basis_valid = true; - m_ineqs_valid = false; - m_empty = false; - m_fn = r.m_fn; - - TRACE("dl", - for (unsigned i = 0; i < cnt; ++i) { - tout << cols[i] << " "; - } - tout << "\n"; - r.display(tout); - display(tout);); - } - - void mk_rename(const karr_relation & r, unsigned col_cnt, const unsigned * cols) { - if (r.empty()) { - m_empty = true; - return; - } - m_ineqs.reset(); - m_basis.reset(); - m_ineqs_valid = r.m_ineqs_valid; - m_basis_valid = r.m_basis_valid; - if (m_ineqs_valid) { - m_ineqs.append(r.m_ineqs); - mk_rename(m_ineqs, col_cnt, cols); - } - if (m_basis_valid) { - m_basis.append(r.m_basis); - mk_rename(m_basis, col_cnt, cols); - } - m_fn = r.m_fn; - TRACE("dl", r.display(tout); display(tout);); - } - - void mk_union(karr_relation const& src, karr_relation* delta) { - if (src.empty()) { - if (delta) { - delta->m_empty = true; - } - return; - } - matrix const& M = src.get_basis(); - if (empty()) { - m_basis = M; - m_basis_valid = true; - m_empty = false; - m_ineqs_valid = false; - if (delta) { - delta->copy(*this); - } - return; - } - matrix& N = get_basis(); - unsigned N_size = N.size(); - for (unsigned i = 0; i < M.size(); ++i) { - bool found = false; - for (unsigned j = 0; !found && j < N_size; ++j) { - found = - same_row(M.A[i], N.A[j]) && - M.b[i] == N.b[j] && - M.eq[i] == N.eq[j]; - } - if (!found) { - N.A.push_back(M.A[i]); - N.b.push_back(M.b[i]); - N.eq.push_back(M.eq[i]); - } - } - m_ineqs_valid = false; - if (N_size != N.size()) { - if (delta) { - delta->copy(*this); - } - } - } - - matrix const& get_basis() const { - init_basis(); - return m_basis; - } - - matrix& get_basis() { - init_basis(); - return m_basis; - } - - matrix const& get_ineqs() const { - init_ineqs(); - return m_ineqs; - } - - matrix & get_ineqs() { - init_ineqs(); - return m_ineqs; - } - - private: - - void copy(karr_relation const& other) { - m_ineqs = other.m_ineqs; - m_basis = other.m_basis; - m_basis_valid = other.m_basis_valid; - m_ineqs_valid = other.m_ineqs_valid; - m_empty = other.m_empty; - } - - bool same_row(vector const& r1, vector const& r2) const { - SASSERT(r1.size() == r2.size()); - for (unsigned i = 0; i < r1.size(); ++i) { - if (r1[i] != r2[i]) { - return false; - } - } - return true; - } - - void mk_rename(matrix& M, unsigned col_cnt, unsigned const* cols) { - for (unsigned j = 0; j < M.size(); ++j) { - vector & row = M.A[j]; - rational tmp = row[cols[0]]; - for (unsigned i = 0; i + 1 < col_cnt; ++i) { - row[cols[i]] = row[cols[i+1]]; - } - row[cols[col_cnt-1]] = tmp; - } - } - - bool is_eq(expr* e, var*& v, rational& n) { - expr* e1, *e2; - if (!m.is_eq(e, e1, e2)) { - return false; - } - if (!is_var(e1)) { - std::swap(e1, e2); - } - if (!is_var(e1)) { - return false; - } - v = to_var(e1); - if (!a.is_numeral(e2, n)) { - return false; - } - return true; - } - - bool is_linear(expr* e, vector& row, rational& b, rational const& mul) { - if (!a.is_int(e)) { - return false; - } - if (is_var(e)) { - row[to_var(e)->get_idx()] += mul; - return true; - } - if (!is_app(e)) { - return false; - } - rational n; - if (a.is_numeral(e, n)) { - b += mul*n; - return true; - } - if (a.is_add(e)) { - for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { - if (!is_linear(to_app(e)->get_arg(i), row, b, mul)) { - return false; - } - } - return true; - } - expr* e1, *e2; - if (a.is_sub(e, e1, e2)) { - return is_linear(e1, row, b, mul) && is_linear(e2, row, b, -mul); - } - if (a.is_mul(e, e1, e2) && a.is_numeral(e1, n)) { - return is_linear(e2, row, b, mul*n); - } - if (a.is_mul(e, e1, e2) && a.is_numeral(e2, n)) { - return is_linear(e1, row, b, mul*n); - } - if (a.is_uminus(e, e1)) { - return is_linear(e1, row, b, -mul); - } - return false; - } - - void init_ineqs() const { - if (!m_ineqs_valid) { - SASSERT(m_basis_valid); - m_plugin.dualizeH(m_ineqs, m_basis); - m_ineqs_valid = true; - } - } - - void init_basis() const { - if (!m_basis_valid) { - SASSERT(m_ineqs_valid); - if (m_plugin.dualizeI(m_basis, m_ineqs)) { - m_basis_valid = true; - } - else { - m_empty = true; - } - } - } - - void to_formula(vector const& row, rational const& b, bool is_eq, expr_ref_vector& conj) const { - expr_ref_vector sum(m); - expr_ref zero(m), lhs(m); - zero = a.mk_numeral(rational(0), true); - - for (unsigned i = 0; i < row.size(); ++i) { - if (row[i].is_zero()) { - continue; - } - var* var = m.mk_var(i, a.mk_int()); - if (row[i].is_one()) { - sum.push_back(var); - } - else { - sum.push_back(a.mk_mul(a.mk_numeral(row[i], true), var)); - } - } - if (!b.is_zero()) { - sum.push_back(a.mk_numeral(b, true)); - } - lhs = a.mk_add(sum.size(), sum.c_ptr()); - if (is_eq) { - conj.push_back(m.mk_eq(lhs, zero)); - } - else { - conj.push_back(a.mk_ge(lhs, zero)); - } - } - }; - - - karr_relation& karr_relation_plugin::get(relation_base& r) { - return dynamic_cast(r); - } - - karr_relation const & karr_relation_plugin::get(relation_base const& r) { - return dynamic_cast(r); - } - - void karr_relation_plugin::set_cancel(bool f) { - m_hb.set_cancel(f); - } - - relation_base * karr_relation_plugin::mk_empty(const relation_signature & s) { - return alloc(karr_relation, *this, 0, s, true); - } - - relation_base * karr_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { - return alloc(karr_relation, *this, p, s, false); - } - - class karr_relation_plugin::join_fn : public convenient_relation_join_fn { - public: - join_fn(const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2) - : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2){ - } - - virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { - karr_relation const& r1 = get(_r1); - karr_relation const& r2 = get(_r2); - karr_relation_plugin& p = r1.get_plugin(); - karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); - result->mk_join(r1, r2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); - return result; - } - }; - - relation_join_fn * karr_relation_plugin::mk_join_fn( - const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (!check_kind(t1) || !check_kind(t2)) { - return 0; - } - return alloc(join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); - } - - - class karr_relation_plugin::project_fn : public convenient_relation_project_fn { - public: - project_fn(const relation_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) - : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { - } - - virtual relation_base * operator()(const relation_base & _r) { - karr_relation const& r = get(_r); - karr_relation_plugin& p = r.get_plugin(); - karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); - result->mk_project(r, m_removed_cols.size(), m_removed_cols.c_ptr()); - return result; - } - }; - - relation_transformer_fn * karr_relation_plugin::mk_project_fn(const relation_base & r, - unsigned col_cnt, const unsigned * removed_cols) { - return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); - } - - class karr_relation_plugin::rename_fn : public convenient_relation_rename_fn { - public: - rename_fn(karr_relation_plugin& p, const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) - : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) {} - - virtual relation_base * operator()(const relation_base & _r) { - karr_relation const& r = get(_r); - karr_relation_plugin& p = r.get_plugin(); - karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); - result->mk_rename(r, m_cycle.size(), m_cycle.c_ptr()); - return result; - } - }; - - relation_transformer_fn * karr_relation_plugin::mk_rename_fn(const relation_base & r, - unsigned cycle_len, const unsigned * permutation_cycle) { - if (!check_kind(r)) { - return 0; - } - return alloc(rename_fn, *this, r.get_signature(), cycle_len, permutation_cycle); - } - - bool karr_relation_plugin::dualizeI(matrix& dst, matrix const& src) { - dst.reset(); - m_hb.reset(); - for (unsigned i = 0; i < src.size(); ++i) { - if (src.eq[i]) { - m_hb.add_eq(src.A[i], -src.b[i]); - } - else { - m_hb.add_ge(src.A[i], -src.b[i]); - } - } - for (unsigned i = 0; !src.A.empty() && i < src.A[0].size(); ++i) { - m_hb.set_is_int(i); - } - lbool is_sat = l_undef; - - try { - is_sat = m_hb.saturate(); - } - catch (...) { - is_sat = l_undef; - } - TRACE("dl_verbose", m_hb.display(tout);); - if (is_sat == l_false) { - return false; - } - if (is_sat == l_undef) { - return true; - } - unsigned basis_size = m_hb.get_basis_size(); - bool first_initial = true; - for (unsigned i = 0; i < basis_size; ++i) { - bool is_initial; - vector soln; - m_hb.get_basis_solution(i, soln, is_initial); - if (is_initial && first_initial) { - dst.A.push_back(soln); - dst.b.push_back(rational(1)); - dst.eq.push_back(true); - first_initial = false; - } - else if (!is_initial) { - dst.A.push_back(soln); - dst.b.push_back(rational(0)); - dst.eq.push_back(true); - } - } - return true; - } - - void karr_relation_plugin::dualizeH(matrix& dst, matrix const& src) { - dst.reset(); - if (src.size() == 0) { - return; - } - m_hb.reset(); - for (unsigned i = 0; i < src.size(); ++i) { - vector v(src.A[i]); - v.push_back(src.b[i]); - if (src.eq[i]) { - m_hb.add_eq(v, rational(0)); - } - else { - m_hb.add_ge(v, rational(0)); - } - } - for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) { - m_hb.set_is_int(i); - } - lbool is_sat = l_undef; - try { - is_sat = m_hb.saturate(); - } - catch (...) { - is_sat = l_undef; - } - if (is_sat != l_true) { - return; - } - TRACE("dl_verbose", m_hb.display(tout);); - SASSERT(is_sat == l_true); - unsigned basis_size = m_hb.get_basis_size(); - for (unsigned i = 0; i < basis_size; ++i) { - bool is_initial; - vector soln; - m_hb.get_basis_solution(i, soln, is_initial); - if (!is_initial) { - dst.b.push_back(soln.back()); - dst.eq.push_back(true); - soln.pop_back(); - dst.A.push_back(soln); - } - } - } - - - class karr_relation_plugin::union_fn : public relation_union_fn { - public: - union_fn() {} - - virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { - - karr_relation& r = get(_r); - karr_relation const& src = get(_src); - TRACE("dl", r.display(tout << "dst:\n"); src.display(tout << "src:\n");); - - if (_delta) { - karr_relation& d = get(*_delta); - r.mk_union(src, &d); - } - else { - r.mk_union(src, 0); - } - TRACE("dl", r.display(tout << "result:\n");); - } - }; - - relation_union_fn * karr_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { - return 0; - } - return alloc(union_fn); - } - - class karr_relation_plugin::filter_identical_fn : public relation_mutator_fn { - unsigned_vector m_identical_cols; - public: - filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) - : m_identical_cols(col_cnt, identical_cols) {} - - virtual void operator()(relation_base & _r) { - karr_relation & r = get(_r); - TRACE("dl", r.display(tout << "src:\n");); - r.get_ineqs(); - for (unsigned i = 1; i < m_identical_cols.size(); ++i) { - unsigned c1 = m_identical_cols[0]; - unsigned c2 = m_identical_cols[i]; - vector row; - row.resize(r.get_signature().size()); - row[c1] = rational(1); - row[c2] = rational(-1); - r.m_ineqs.A.push_back(row); - r.m_ineqs.b.push_back(rational(0)); - r.m_ineqs.eq.push_back(true); - r.m_basis_valid = false; - } - TRACE("dl", r.display(tout << "result:\n");); - } - }; - - relation_mutator_fn * karr_relation_plugin::mk_filter_identical_fn( - const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { - if(!check_kind(t)) { - return 0; - } - return alloc(filter_identical_fn, col_cnt, identical_cols); - } - - - class karr_relation_plugin::filter_equal_fn : public relation_mutator_fn { - unsigned m_col; - rational m_value; - bool m_valid; - public: - filter_equal_fn(relation_manager & m, const relation_element & value, unsigned col) - : m_col(col) { - arith_util arith(m.get_context().get_manager()); - m_valid = arith.is_numeral(value, m_value) && m_value.is_int(); - } - - virtual void operator()(relation_base & _r) { - karr_relation & r = get(_r); - if (m_valid) { - r.get_ineqs(); - vector row; - row.resize(r.get_signature().size()); - row[m_col] = rational(1); - r.m_ineqs.A.push_back(row); - r.m_ineqs.b.push_back(rational(-1)); - r.m_ineqs.eq.push_back(true); - r.m_basis_valid = false; - } - TRACE("dl", tout << m_value << "\n"; r.display(tout);); - } - }; - - relation_mutator_fn * karr_relation_plugin::mk_filter_equal_fn(const relation_base & r, - const relation_element & value, unsigned col) { - if (check_kind(r)) { - return alloc(filter_equal_fn, get_manager(), value, col); - } - return 0; - } - - - class karr_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { - app_ref m_cond; - public: - filter_interpreted_fn(karr_relation const& t, app* cond): - m_cond(cond, t.get_plugin().get_ast_manager()) { - } - - void operator()(relation_base& t) { - get(t).filter_interpreted(m_cond); - TRACE("dl", tout << mk_pp(m_cond, m_cond.get_manager()) << "\n"; t.display(tout);); - } - }; - - relation_mutator_fn * karr_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { - if (check_kind(t)) { - return alloc(filter_interpreted_fn, get(t), condition); - } - return 0; - } - -}; - diff --git a/src/muz/dl_mk_karr_invariants.h b/src/muz/dl_mk_karr_invariants.h deleted file mode 100644 index a86f726ef..000000000 --- a/src/muz/dl_mk_karr_invariants.h +++ /dev/null @@ -1,138 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - dl_mk_karr_invariants.h - -Abstract: - - Extract integer linear invariants. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-03-08 - -Revision History: - ---*/ -#ifndef _DL_MK_KARR_INVARIANTS_H_ -#define _DL_MK_KARR_INVARIANTS_H_ - -#include"dl_context.h" -#include"dl_rule_set.h" -#include"dl_rule_transformer.h" -#include"arith_decl_plugin.h" -#include"hilbert_basis.h" - -namespace datalog { - - /** - \brief Rule transformer that strengthens bodies with invariants. - */ - - struct matrix { - vector > A; - vector b; - svector eq; - unsigned size() const { return A.size(); } - void reset() { A.reset(); b.reset(); eq.reset(); } - matrix& operator=(matrix const& other); - void append(matrix const& other) { A.append(other.A); b.append(other.b); eq.append(other.eq); } - void display(std::ostream& out) const; - static void display_row( - std::ostream& out, vector const& row, rational const& b, bool is_eq); - static void display_ineq( - std::ostream& out, vector const& row, rational const& b, bool is_eq); - }; - - class mk_karr_invariants : public rule_transformer::plugin { - - class add_invariant_model_converter; - - context& m_ctx; - ast_manager& m; - rule_manager& rm; - context m_inner_ctx; - arith_util a; - obj_map m_fun2inv; - ast_ref_vector m_pinned; - volatile bool m_cancel; - - void get_invariants(rule_set const& src); - - void update_body(rule_set& result, rule& r); - rule_set* update_rules(rule_set const& src); - public: - mk_karr_invariants(context & ctx, unsigned priority); - - virtual ~mk_karr_invariants(); - - virtual void cancel(); - - rule_set * operator()(rule_set const & source); - - }; - - class karr_relation; - - class karr_relation_plugin : public relation_plugin { - arith_util a; - hilbert_basis m_hb; - - class join_fn; - class project_fn; - class rename_fn; - class union_fn; - class filter_equal_fn; - class filter_identical_fn; - class filter_interpreted_fn; - friend class karr_relation; - public: - karr_relation_plugin(relation_manager& rm): - relation_plugin(karr_relation_plugin::get_name(), rm), - a(get_ast_manager()) - {} - - virtual bool can_handle_signature(const relation_signature & sig) { - return true; - } - - static symbol get_name() { return symbol("karr_relation"); } - - virtual void set_cancel(bool f); - - virtual relation_base * mk_empty(const relation_signature & s); - - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - - static karr_relation& get(relation_base& r); - static karr_relation const & get(relation_base const& r); - - virtual relation_join_fn * mk_join_fn( - const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - - private: - bool dualizeI(matrix& dst, matrix const& src); - void dualizeH(matrix& dst, matrix const& src); - - - }; - - -}; - -#endif /* _DL_MK_KARR_INVARIANTS_H_ */ - diff --git a/src/muz/dl_mk_partial_equiv.cpp b/src/muz/dl_mk_partial_equiv.cpp deleted file mode 100644 index 4d1a1e860..000000000 --- a/src/muz/dl_mk_partial_equiv.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - dl_mk_partial_equiv.cpp - -Abstract: - - Rule transformer which identifies predicates that are partial equivalence relations. - -Author: - - Nikolaj Bjorner (nbjorner) 2012-05-14 - -Revision History: - ---*/ - -#include "dl_mk_partial_equiv.h" -#include "ast_pp.h" - -namespace datalog { - - bool mk_partial_equivalence_transformer::is_symmetry(rule const* r) { - func_decl* p = r->get_decl(); - return - p->get_arity() == 2 && - p->get_domain(0) == p->get_domain(1) && - r->get_tail_size() == 1 && - r->get_tail(0)->get_decl() == p && - r->get_head()->get_arg(0) == r->get_tail(0)->get_arg(1) && - r->get_head()->get_arg(1) == r->get_tail(0)->get_arg(0) && - is_var(r->get_head()->get_arg(0)) && - is_var(r->get_head()->get_arg(1)) && - r->get_head()->get_arg(0) != r->get_head()->get_arg(1); - } - - - bool mk_partial_equivalence_transformer::is_transitivity(rule const* r) { - func_decl* p = r->get_decl(); - if (p->get_arity() != 2 || - p->get_domain(0) != p->get_domain(1) || - r->get_tail_size() != 2 || - r->get_tail(0)->get_decl() != p || - r->get_tail(1)->get_decl() != p) { - return false; - } - app* h = r->get_head(); - app* a = r->get_tail(0); - app* b = r->get_tail(1); - expr* x1 = h->get_arg(0); - expr* x2 = h->get_arg(1); - expr* a1 = a->get_arg(0); - expr* a2 = a->get_arg(1); - expr* b1 = b->get_arg(0); - expr* b2 = b->get_arg(1); - - if (!(is_var(x1) && is_var(x2) && is_var(a1) && is_var(a2) && is_var(b1) && is_var(b2))) { - return false; - } - if (x1 == x2 || a1 == a2 || b1 == b2) { - return false; - } - if (a2 == b1) { - if (x1 == b2 && x2 == a1) { - return true; - } - if (x1 == a1 && x2 == b2) { - return true; - } - return false; - } - if (a1 == b2) { - if (x1 == b1 && x2 == a2) { - return true; - } - if (x1 == a2 && x2 == b1) { - return true; - } - return false; - } - - return false; -; - } - - - rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source) { - // TODO mc - - if (source.get_num_rules() == 0) { - return 0; - } - - if (m_context.get_engine() != DATALOG_ENGINE) { - return 0; - } - - relation_manager & rm = m_context.get_rel_context()->get_rmanager(); - rule_set::decl2rules::iterator it = source.begin_grouped_rules(); - rule_set::decl2rules::iterator end = source.end_grouped_rules(); - - rule_set* res = alloc(rule_set, m_context); - - for (; it != end; ++it) { - func_decl* p = it->m_key; - rule_vector const& rv = *(it->m_value); - bool has_symmetry = false; - bool has_transitivity = false; - unsigned i_symmetry, i_transitivity; - family_id kind = rm.get_requested_predicate_kind(p); - for (unsigned i = 0; i < rv.size(); ++i) { - - if (kind != null_family_id) { - res->add_rule(rv[i]); - } - else if (is_symmetry(rv[i])) { - i_symmetry = i; - has_symmetry = true; - } - else if (is_transitivity(rv[i])) { - i_transitivity = i; - has_transitivity = true; - } - else { - res->add_rule(rv[i]); - } - } - if (has_symmetry && !has_transitivity) { - res->add_rule(rv[i_symmetry]); - } - else if (!has_symmetry && has_transitivity) { - res->add_rule(rv[i_transitivity]); - } - else if (has_symmetry && has_transitivity) { - TRACE("dl", tout << "updating predicate " << mk_pp(p, m) << " to partial equivalence\n";); - SASSERT(kind == null_family_id); - rm.set_predicate_kind(p, rm.get_table_plugin(symbol("equivalence"))->get_kind()); - } - } - - if (res->get_num_rules() == source.get_num_rules()) { - dealloc(res); - return 0; - } - res->inherit_predicates(source); - - return res; - } - -}; - - diff --git a/src/muz/dl_mk_partial_equiv.h b/src/muz/dl_mk_partial_equiv.h deleted file mode 100644 index 54a70b3c0..000000000 --- a/src/muz/dl_mk_partial_equiv.h +++ /dev/null @@ -1,50 +0,0 @@ -/*++ -Copyright (c) 2012 Microsoft Corporation - -Module Name: - - dl_mk_partial_equiv.h - -Abstract: - - Rule transformer which identifies predicates that are partial equivalence relations. - -Author: - - Nikolaj Bjorner (nbjorner) 2012-05-14 - -Revision History: - ---*/ - - -#ifndef _DL_MK_PARTIAL_EQUIVALENCE_TRANSFORMER_H_ -#define _DL_MK_PARTIAL_EQUIVALENCE_TRANSFORMER_H_ - -#include "dl_context.h" -#include "dl_rule_transformer.h" - -namespace datalog { - - class mk_partial_equivalence_transformer : public rule_transformer::plugin { - ast_manager & m; - context & m_context; - public: - mk_partial_equivalence_transformer(context & ctx, unsigned priority=45000) - : plugin(priority), - m(ctx.get_manager()), - m_context(ctx) {} - - rule_set * operator()(rule_set const & source); - - private: - - bool is_symmetry(rule const* r); - bool is_transitivity(rule const* r); - }; - -}; - -#endif /* _DL_MK_PARTIAL_EQUIV_TRANSFORMER_H_ */ - - diff --git a/src/muz/dl_mk_similarity_compressor.cpp b/src/muz/dl_mk_similarity_compressor.cpp deleted file mode 100644 index d4f410130..000000000 --- a/src/muz/dl_mk_similarity_compressor.cpp +++ /dev/null @@ -1,545 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_mk_similarity_compressor.cpp - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-10-22. - -Revision History: - ---*/ - -#include -#include -#include"dl_mk_similarity_compressor.h" - -namespace datalog { - - mk_similarity_compressor::mk_similarity_compressor(context & ctx) : - plugin(5000), - m_context(ctx), - m_manager(ctx.get_manager()), - m_threshold_count(ctx.similarity_compressor_threshold()), - m_result_rules(ctx.get_rule_manager()), - m_modified(false), - m_pinned(m_manager) { - SASSERT(m_threshold_count>1); - } - - void mk_similarity_compressor::reset() { - m_rules.reset(); - m_result_rules.reset(); - m_pinned.reset(); - } - - /** - Allows to traverse head and positive tails in a single for loop starting from -1 - */ - static app * get_by_tail_index(rule * r, int idx) { - if (idx < 0) { - return r->get_head(); - } - SASSERT(idx < static_cast(r->get_positive_tail_size())); - return r->get_tail(idx); - } - - template - static int aux_compare(T a, T b) { - return (a>b) ? 1 : ( (a==b) ? 0 : -1); - } - - template - static int aux_compare(T* a, T* b); - - static int compare_var_args(app* t1, app* t2) { - SASSERT(t1->get_num_args()==t2->get_num_args()); - int res; - unsigned n = t1->get_num_args(); - for (unsigned i = 0; i < n; i++) { - expr * a1 = t1->get_arg(i); - expr * a2 = t2->get_arg(i); - res = aux_compare(is_var(a1), is_var(a2)); - if (res != 0) { - return res; - } - if (is_var(a1)) { - res = aux_compare(to_var(a1)->get_idx(), to_var(a2)->get_idx()); - if (res != 0) { - return res; - } - } - } - return 0; - } - - static int compare_args(app* t1, app* t2, int & skip_countdown) { - SASSERT(t1->get_num_args()==t2->get_num_args()); - int res; - unsigned n = t1->get_num_args(); - for (unsigned i=0; iget_arg(i))) { - SASSERT(t1->get_arg(i) == t2->get_arg(i)); - continue; - } - if ((skip_countdown--) == 0) { - continue; - } - res = aux_compare(t1->get_arg(i)->get_id(), t2->get_arg(i)->get_id()); - if (res!=0) { return res; } - } - return 0; - } - - /** - \brief Return 0 if r1 and r2 could be similar. If the rough similarity - equaivelance class of r1 is greater than the one of r2, return 1; otherwise return -1. - - Two rules are in the same rough similarity class if they differ only in constant arguments - of positive uninterpreted predicates. - */ - static int rough_compare(rule * r1, rule * r2) { - int res = aux_compare(r1->get_tail_size(), r2->get_tail_size()); - if (res!=0) { return res; } - res = aux_compare(r1->get_uninterpreted_tail_size(), r2->get_uninterpreted_tail_size()); - if (res!=0) { return res; } - res = aux_compare(r1->get_positive_tail_size(), r2->get_positive_tail_size()); - if (res!=0) { return res; } - - int pos_tail_sz = r1->get_positive_tail_size(); - for (int i=-1; iget_decl()->get_id(), t2->get_decl()->get_id()); - if (res!=0) { return res; } - res = compare_var_args(t1, t2); - if (res!=0) { return res; } - } - - unsigned tail_sz = r1->get_tail_size(); - for (unsigned i=pos_tail_sz; iget_tail(i)->get_id(), r2->get_tail(i)->get_id()); - if (res!=0) { return res; } - } - - return 0; - } - - /** - \c r1 and \c r2 must be equal according to the \c rough_compare function for this function - to be called. - */ - static int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) { - SASSERT(rough_compare(r1, r2)==0); - int pos_tail_sz = r1->get_positive_tail_size(); - for (int i=-1; i info_vector; - - static void collect_const_indexes(app * t, int tail_index, info_vector & res) { - unsigned n = t->get_num_args(); - for (unsigned i=0; iget_arg(i))) { - continue; - } - res.push_back(const_info(tail_index, i)); - } - } - - static void collect_const_indexes(rule * r, info_vector & res) { - collect_const_indexes(r->get_head(), -1, res); - unsigned pos_tail_sz = r->get_positive_tail_size(); - for (unsigned i=0; iget_tail(i), i, res); - } - } - - template - static void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) { - unsigned const_cnt = const_infos.size(); - tgt.reset(); - for (unsigned i=0; iget_arg(inf.arg_index()))); - SASSERT(tgt.back()->get_num_args()==0); - } - } - template - static void collect_orphan_sorts(rule * r, const info_vector & const_infos, T & tgt) { - unsigned const_cnt = const_infos.size(); - tgt.reset(); - for (unsigned i=0; iget_decl()->get_domain(inf.arg_index())); - } - } - - /** - \brief From the \c tail_indexes and \c arg_indexes remove elements corresponding to constants - that are the same in rules \c *first ... \c *(after_last-1). - */ - static void remove_stable_constants(rule_vector::iterator first, rule_vector::iterator after_last, - info_vector & const_infos) { - SASSERT(after_last-first>1); - unsigned const_cnt = const_infos.size(); - ptr_vector vals; - rule * r = *(first++); - collect_orphan_consts(r, const_infos, vals); - SASSERT(vals.size()==const_cnt); - rule_vector::iterator it = first; - for (; it!=after_last; ++it) { - for (unsigned i=0; iget_arg(const_infos[i].arg_index())); - if (vals[i]!=val) { - vals[i] = 0; - } - } - } - unsigned removed_cnt = 0; - for (unsigned i=0; i vals; - ptr_vector sorts; - rule * r = *(first++); - collect_orphan_consts(r, const_infos, vals); - collect_orphan_sorts(r, const_infos, sorts); - SASSERT(vals.size()==const_cnt); - vector possible_parents(const_cnt); - for (unsigned i=1; iget_head()->get_num_args() - count_variable_arguments(r->get_head()); - unsigned pos_tail_sz = r->get_positive_tail_size(); - for (unsigned i=0; iget_tail(i)->get_num_args() - count_variable_arguments(r->get_tail(i)); - } - return res; - } - - static bool initial_comparator(rule * r1, rule * r2) { - int res = rough_compare(r1, r2); - if (res!=0) { return res>0; } - return total_compare(r1, r2)>0; - } - - class arg_ignoring_comparator { - unsigned m_ignored_index; - public: - arg_ignoring_comparator(unsigned ignored_index) : m_ignored_index(ignored_index) {} - bool operator()(rule * r1, rule * r2) const { - return total_compare(r1, r2, m_ignored_index)>0; - } - bool eq(rule * r1, rule * r2) const { - return total_compare(r1, r2, m_ignored_index)==0; - } - }; - - void mk_similarity_compressor::merge_class(rule_vector::iterator first, - rule_vector::iterator after_last) { - SASSERT(after_last-first>1); - info_vector const_infos; - rule * r = *first; //an arbitrary representative of the class - collect_const_indexes(r, const_infos); - remove_stable_constants(first, after_last, const_infos); - - unsigned const_cnt = const_infos.size(); - SASSERT(const_cnt>0); - - detect_equal_constants(first, after_last, const_infos); - - - //The aux relation contains column for each constant which does not have an earlier constant - //that it is equal to (i.e. only has no parent) - ptr_vector aux_domain; - collect_orphan_sorts(r, const_infos, aux_domain); - - func_decl* head_pred = r->get_decl(); - symbol const& name_prefix = head_pred->get_name(); - std::string name_suffix = "sc_" + to_string(const_cnt); - func_decl * aux_pred = m_context.mk_fresh_head_predicate(name_prefix, symbol(name_suffix.c_str()), - aux_domain.size(), aux_domain.c_ptr(), head_pred); - m_pinned.push_back(aux_pred); - - relation_fact val_fact(m_manager, const_cnt); - rule_vector::iterator it = first; - for (; it!=after_last; ++it) { - collect_orphan_consts(*it, const_infos, val_fact); - m_context.add_fact(aux_pred, val_fact); - } - m_context.get_rel_context()->get_rmanager().mark_saturated(aux_pred); - - app * new_head = r->get_head(); - ptr_vector new_tail; - svector new_negs; - unsigned tail_sz = r->get_tail_size(); - for (unsigned i=0; iget_tail(i)); - new_negs.push_back(r->is_neg_tail(i)); - } - - rule_counter ctr; - ctr.count_rule_vars(m_manager, r); - unsigned max_var_idx, new_var_idx_base; - if (ctr.get_max_positive(max_var_idx)) { - new_var_idx_base = max_var_idx+1; - } - else { - new_var_idx_base = 0; - } - - ptr_vector const_vars; //variables at indexes of their corresponding constants - expr_ref_vector aux_vars(m_manager); //variables as arguments for the auxiliary predicate - - unsigned aux_column_index = 0; - - for (unsigned i=0; i mod_args(mod_tail->get_num_args(), mod_tail->get_args()); - - for (; iget_decl(), mod_args.c_ptr()); - m_pinned.push_back(upd_tail); - mod_tail = upd_tail; - } - - app_ref aux_tail(m_manager.mk_app(aux_pred, aux_vars.c_ptr()), m_manager); - new_tail.push_back(aux_tail); - new_negs.push_back(false); - - rule * new_rule = m_context.get_rule_manager().mk(new_head, new_tail.size(), new_tail.c_ptr(), - new_negs.c_ptr()); - m_result_rules.push_back(new_rule); - - //TODO: allow for a rule to have multiple parent objects - new_rule->set_accounting_parent_object(m_context, r); - m_modified = true; - } - - void mk_similarity_compressor::process_class(rule_set const& source, rule_vector::iterator first, - rule_vector::iterator after_last) { - SASSERT(first!=after_last); - //remove duplicates - { - rule_vector::iterator it = first; - rule_vector::iterator prev = it; - ++it; - while(it!=after_last) { - if (it!=after_last && total_compare(*prev, *it)==0) { - --after_last; - std::swap(*it, *after_last); - m_modified = true; - } - else { - prev = it; - ++it; - } - } - } - SASSERT(first!=after_last); - - unsigned const_cnt = get_constant_count(*first); -#if 0 - for (unsigned ignored_index=0; ignored_indexm_threshold_count) { - merge_class(grp_begin, it); - //group was processed, so we remove it from the class - if (it==after_last) { - after_last=grp_begin; - it=after_last; - } - else { - while(it!=grp_begin) { - std::swap(*--it, *--after_last); - } - } - } - grp_begin = it; - grp_size = 0; - } - } - } -#endif - //TODO: compress also rules with pairs (or tuples) of equal constants - -#if 1 - if (const_cnt>0 && !source.is_output_predicate((*first)->get_decl())) { - unsigned rule_cnt = static_cast(after_last-first); - if (rule_cnt>m_threshold_count) { - merge_class(first, after_last); - return; - } - } -#endif - - //put rules which weren't merged into result - rule_vector::iterator it = first; - for (; it!=after_last; ++it) { - m_result_rules.push_back(*it); - } - } - - rule_set * mk_similarity_compressor::operator()(rule_set const & source) { - // TODO mc - m_modified = false; - unsigned init_rule_cnt = source.get_num_rules(); - SASSERT(m_rules.empty()); - for (unsigned i=0; i(0); - if (m_modified) { - result = alloc(rule_set, m_context); - unsigned fin_rule_cnt = m_result_rules.size(); - for (unsigned i=0; iadd_rule(m_result_rules.get(i)); - } - result->inherit_predicates(source); - } - reset(); - return result; - } -}; diff --git a/src/muz/dl_mk_similarity_compressor.h b/src/muz/dl_mk_similarity_compressor.h deleted file mode 100644 index 34b76e7e1..000000000 --- a/src/muz/dl_mk_similarity_compressor.h +++ /dev/null @@ -1,78 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_mk_similarity_compressor.h - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-10-22. - -Revision History: - ---*/ -#ifndef _DL_MK_SIMILARITY_COMPRESSOR_H_ -#define _DL_MK_SIMILARITY_COMPRESSOR_H_ - -#include - -#include"map.h" -#include"obj_pair_hashtable.h" - -#include"dl_context.h" -#include"dl_rule_set.h" -#include"dl_rule_transformer.h" - -namespace datalog { - - /** - \brief Functor for merging groups of similar rules. - - A rule sequence - - P("1",x):-Q(x). - ... - P("N",x):-Q(x). - - will be replaced by - - P(y,x):-Q(x), Aux(y). - - and a set of facts - - Aux("1"). - ... - Aux("N"). - - Similar transformation is performed when the varying constant appears in the positive tail. - */ - class mk_similarity_compressor : public rule_transformer::plugin { - - context & m_context; - ast_manager & m_manager; - /** number of similar rules necessary for a group to be introduced */ - unsigned m_threshold_count; - rule_vector m_rules; - rule_ref_vector m_result_rules; - bool m_modified; - ast_ref_vector m_pinned; - - void merge_class(rule_vector::iterator first, rule_vector::iterator after_last); - void process_class(rule_set const& source, rule_vector::iterator first, rule_vector::iterator after_last); - - void reset(); - public: - mk_similarity_compressor(context & ctx); - - rule_set * operator()(rule_set const & source); - }; - -}; - -#endif /* _DL_MK_SIMILARITY_COMPRESSOR_H_ */ - diff --git a/src/muz/dl_mk_simple_joins.cpp b/src/muz/dl_mk_simple_joins.cpp deleted file mode 100644 index 300ed0879..000000000 --- a/src/muz/dl_mk_simple_joins.cpp +++ /dev/null @@ -1,741 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_mk_simple_joins.cpp - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2010-05-20. - -Revision History: - ---*/ - -#include -#include -#include -#include"dl_mk_simple_joins.h" -#include"ast_pp.h" -#include"trace.h" - - -namespace datalog { - - mk_simple_joins::mk_simple_joins(context & ctx): - plugin(1000), - m_context(ctx), - rm(ctx.get_rule_manager()) { - } - - class join_planner { - typedef float cost; - - class pair_info { - cost m_total_cost; - /** - \brief Number of rules longer than two that contain this pair. - - This number is being updated by \c add_rule and \remove rule. Even though between - adding a rule and removing it, the length of a rule can decrease without this pair - being notified about it, it will surely see the decrease from length 3 to 2 which - the threshold for rule being counted in this counter. - */ - unsigned m_consumers; - bool m_stratified; - unsigned m_src_stratum; - public: - var_idx_set m_all_nonlocal_vars; - rule_vector m_rules; - - pair_info() : m_consumers(0), m_stratified(true), m_src_stratum(0) {} - - bool can_be_joined() const { - return m_consumers>0; - } - - cost get_cost() const { - /*if(m_instantiated) { - return std::numeric_limits::min(); - }*/ - SASSERT(m_consumers>0); - cost amortized = m_total_cost/m_consumers; - if(m_stratified) { - return amortized * ( (amortized>0) ? (1/16.0f) : 16.0f); - } - else { - return amortized; - } - } - - /** - \brief Add rule \c r among rules interested in current predicate pair. - - The \c pl.m_rule_content entry of the rule has to be properly filled in - by the time of a call to this function - */ - void add_rule(join_planner & pl, app * t1, app * t2, rule * r, - const var_idx_set & non_local_vars_normalized) { - if(m_rules.empty()) { - m_total_cost = pl.compute_cost(t1, t2); - m_src_stratum = std::max(pl.get_stratum(t1->get_decl()), pl.get_stratum(t2->get_decl())); - } - m_rules.push_back(r); - if(pl.m_rules_content.find_core(r)->get_data().m_value.size()>2) { - m_consumers++; - } - if(m_stratified) { - unsigned head_stratum = pl.get_stratum(r->get_decl()); - SASSERT(head_stratum>=m_src_stratum); - if(head_stratum==m_src_stratum) { - m_stratified = false; - } - } - idx_set_union(m_all_nonlocal_vars, non_local_vars_normalized); - } - /** - \brief Remove rule from the pair record. Return true if no rules remain - in the pair, and so it should be removed. - */ - bool remove_rule(rule * r, unsigned original_length) { - TRUSTME( remove_from_vector(m_rules, r) ); - if(original_length>2) { - SASSERT(m_consumers>0); - m_consumers--; - } - SASSERT(!m_rules.empty() || m_consumers==0); - return m_rules.empty(); - } - private: - pair_info & operator=(const pair_info &); //to avoid the implicit one - }; - typedef std::pair app_pair; - typedef map, obj_ptr_hash >, default_eq > cost_map; - typedef map, ptr_hash, ptr_eq > rule_pred_map; - - context & m_context; - ast_manager & m; - rule_manager & rm; - var_subst & m_var_subst; - rule_set & m_rs_aux_copy; //reference to a rule_set that will allow to ask for stratum levels - - cost_map m_costs; - ptr_vector m_interpreted; - rule_pred_map m_rules_content; - rule_ref_vector m_introduced_rules; - ptr_hashtable, ptr_eq > m_modified_rules; - - ast_ref_vector m_pinned; - mutable ptr_vector m_vars; - - public: - join_planner(context & ctx, rule_set & rs_aux_copy) - : m_context(ctx), m(ctx.get_manager()), - rm(ctx.get_rule_manager()), - m_var_subst(ctx.get_var_subst()), - m_rs_aux_copy(rs_aux_copy), - m_introduced_rules(ctx.get_rule_manager()), - m_pinned(ctx.get_manager()) - { - } - - ~join_planner() - { - cost_map::iterator it = m_costs.begin(); - cost_map::iterator end = m_costs.end(); - for (; it != end; ++it) { - dealloc(it->m_value); - } - m_costs.reset(); - } - private: - - void get_normalizer(app * t, unsigned & next_var, expr_ref_vector & result) const { - SASSERT(result.size()>0); - unsigned res_ofs = result.size()-1; - unsigned n=t->get_num_args(); - for(unsigned i=0; iget_arg(i))); - var * v = to_var(t->get_arg(i)); - unsigned var_idx = v->get_idx(); - if(result[res_ofs-var_idx]==0) { - result[res_ofs-var_idx]=m.mk_var(next_var, v->get_sort()); - next_var++; - } - } - } - - void get_normalizer(app * t1, app * t2, expr_ref_vector & result) const { - SASSERT(result.empty()); - if(t1->get_num_args()==0 && t2->get_num_args()==0) { - return; //nothing to normalize - } - SASSERT(!t1->is_ground() || !t2->is_ground()); - - unsigned max_var_idx = 0; - { - var_idx_set& orig_var_set = rm.collect_vars(t1, t2); - var_idx_set::iterator ovit = orig_var_set.begin(); - var_idx_set::iterator ovend = orig_var_set.end(); - for(; ovit!=ovend; ++ovit) { - unsigned var_idx = *ovit; - if(var_idx>max_var_idx) { - max_var_idx = var_idx; - } - } - } - - if(t1->get_decl()!=t2->get_decl()) { - if(t1->get_decl()->get_id()get_decl()->get_id()) { - std::swap(t1, t2); - } - } - else { - int_vector norm1(max_var_idx+1, -1); - int_vector norm2(max_var_idx+1, -1); - unsigned n=t1->get_num_args(); - SASSERT(n==t2->get_num_args()); - for(unsigned i=0; iget_arg(i)); - var * v2 = to_var(t2->get_arg(i)); - if(v1->get_sort()!=v2->get_sort()) { - //different sorts mean we can distinguish the two terms - if(v1->get_sort()->get_id()get_sort()->get_id()) { - std::swap(t1, t2); - } - break; - } - unsigned v1_idx = v1->get_idx(); - unsigned v2_idx = v2->get_idx(); - //since the rules already went through the mk_filter_rules transformer, - //variables must be linear - SASSERT(norm1[v1_idx]==-1); - SASSERT(norm2[v2_idx]==-1); - - if(norm2[v1_idx]!=norm1[v2_idx]) { - //now we can distinguish the two terms - if(norm2[v1_idx](0)); - unsigned next_var = 0; - get_normalizer(t1, next_var, result); - get_normalizer(t2, next_var, result); - } - - app_pair get_key(app * t1, app * t2) { - expr_ref_vector norm_subst(m); - get_normalizer(t1, t2, norm_subst); - expr_ref t1n_ref(m); - expr_ref t2n_ref(m); - m_var_subst(t1, norm_subst.size(), norm_subst.c_ptr(), t1n_ref); - m_var_subst(t2, norm_subst.size(), norm_subst.c_ptr(), t2n_ref); - app * t1n = to_app(t1n_ref); - app * t2n = to_app(t2n_ref); - if(t1n>t2n) { - std::swap(t1n, t2n); - } - m_pinned.push_back(t1n); - m_pinned.push_back(t2n); - - /* - IF_VERBOSE(0, - print_renaming(norm_subst, verbose_stream()); - display_predicate(m_context, t1, verbose_stream()); - display_predicate(m_context, t2, verbose_stream()); - display_predicate(m_context, t1n, verbose_stream()); - display_predicate(m_context, t2n, verbose_stream());); - */ - return app_pair(t1n, t2n); - } - - /** - \brief Add rule \c r among rules interested in predicate pair \c t1, \c t2. - - The \c m_rule_content entry of the rule \c r has to be properly filled in - by the time of a call to this function - */ - void register_pair(app * t1, app * t2, rule * r, const var_idx_set & non_local_vars) { - TRACE("dl", tout << mk_pp(t1, m) << " " << mk_pp(t2, m) << "\n"; - r->display(m_context, tout); tout << "\n";); - SASSERT(t1!=t2); - cost_map::entry * e = m_costs.insert_if_not_there2(get_key(t1, t2), 0); - pair_info * & ptr_inf = e->get_data().m_value; - if(ptr_inf==0) { - ptr_inf = alloc(pair_info); - } - pair_info & inf = *ptr_inf; - - expr_ref_vector normalizer(m); - get_normalizer(t1, t2, normalizer); - unsigned norm_ofs = normalizer.size()-1; - var_idx_set normalized_vars; - var_idx_set::iterator vit = non_local_vars.begin(); - var_idx_set::iterator vend = non_local_vars.end(); - for(; vit!=vend; ++vit) { - unsigned norm_var = to_var(normalizer.get(norm_ofs-*vit))->get_idx(); - normalized_vars.insert(norm_var); - } - - inf.add_rule(*this, t1, t2, r, normalized_vars); - } - - pair_info & get_pair(app_pair key) const { - cost_map::entry * e = m_costs.find_core(key); - SASSERT(e); - return *e->get_data().m_value; - } - - void remove_rule_from_pair(app_pair key, rule * r, unsigned original_len) { - pair_info * ptr = &get_pair(key); - if(ptr->remove_rule(r, original_len)) { - SASSERT(ptr->m_rules.empty()); - m_costs.remove(key); - dealloc(ptr); - } - } - - void register_rule(rule * r) { - rule_counter counter; - counter.count_rule_vars(m, r, 1); - - ptr_vector & rule_content = - m_rules_content.insert_if_not_there2(r, ptr_vector())->get_data().m_value; - SASSERT(rule_content.empty()); - - unsigned pos_tail_size=r->get_positive_tail_size(); - for(unsigned i=0; iget_tail(i)); - } - for(unsigned i=0; iget_tail(i); - var_idx_set t1_vars = rm.collect_vars(t1); - counter.count_vars(m, t1, -1); //temporarily remove t1 variables from counter - for(unsigned j=i+1; jget_tail(j); - counter.count_vars(m, t2, -1); //temporarily remove t2 variables from counter - var_idx_set scope_vars = rm.collect_vars(t2); - scope_vars |= t1_vars; - var_idx_set non_local_vars; - counter.collect_positive(non_local_vars); - counter.count_vars(m, t2, 1); //restore t2 variables in counter - set_intersection(non_local_vars, scope_vars); - register_pair(t1, t2, r, non_local_vars); - } - counter.count_vars(m, t1, 1); //restore t1 variables in counter - } - } - - bool extract_argument_info(unsigned var_idx, app * t, expr_ref_vector & args, - ptr_vector & domain) { - unsigned n=t->get_num_args(); - for(unsigned i=0; iget_arg(i)); - if(v->get_idx()==var_idx) { - args.push_back(v); - domain.push_back(m.get_sort(v)); - return true; - } - } - return false; - } - - void join_pair(app_pair pair_key) { - app * t1 = pair_key.first; - app * t2 = pair_key.second; - pair_info & inf = get_pair(pair_key); - SASSERT(!inf.m_rules.empty()); - var_idx_set & output_vars = inf.m_all_nonlocal_vars; - expr_ref_vector args(m); - ptr_vector domain; - - unsigned arity = output_vars.num_elems(); - idx_set::iterator ovit=output_vars.begin(); - idx_set::iterator ovend=output_vars.end(); - //TODO: improve quadratic complexity - for(;ovit!=ovend;++ovit) { - unsigned var_idx=*ovit; - - bool found=extract_argument_info(var_idx, t1, args, domain); - if(!found) { - found=extract_argument_info(var_idx, t2, args, domain); - } - SASSERT(found); - } - - SASSERT(args.size()==arity); - SASSERT(domain.size()==arity); - - rule * one_parent = inf.m_rules.back(); - - func_decl* parent_head = one_parent->get_decl(); - const char * one_parent_name = parent_head->get_name().bare_str(); - std::string parent_name; - if(inf.m_rules.size()>1) { - parent_name = one_parent_name + std::string("_and_") + to_string(inf.m_rules.size()-1); - } - else { - parent_name = one_parent_name; - } - - func_decl * decl = m_context.mk_fresh_head_predicate( - symbol(parent_name.c_str()), symbol("split"), - arity, domain.c_ptr(), parent_head); - - app_ref head(m.mk_app(decl, arity, args.c_ptr()), m); - - app * tail[] = {t1, t2}; - - rule * new_rule = m_context.get_rule_manager().mk(head, 2, tail, 0); - - //TODO: update accounting so that it can handle multiple parents - new_rule->set_accounting_parent_object(m_context, one_parent); - - m_introduced_rules.push_back(new_rule); - - //here we copy the inf.m_rules vector because inf.m_rules will get changed - //in the iteration. Also we use hashtable instead of vector because we do - //not want to process one rule twice. - typedef ptr_hashtable, default_eq > rule_hashtable; - rule_hashtable relevant_rules; - insert_into_set(relevant_rules, inf.m_rules); - rule_hashtable::iterator rit = relevant_rules.begin(); - rule_hashtable::iterator rend = relevant_rules.end(); - for(; rit!=rend; ++rit) { - apply_binary_rule(*rit, pair_key, head); - } - - // SASSERT(!m_costs.contains(pair_key)); - } - - void replace_edges(rule * r, const ptr_vector & removed_tails, - const ptr_vector & added_tails0, const ptr_vector & rule_content) { - SASSERT(removed_tails.size()>=added_tails0.size()); - unsigned len = rule_content.size(); - unsigned original_len = len+removed_tails.size()-added_tails0.size(); - ptr_vector added_tails(added_tails0); //we need a copy since we'll be modifying it - - unsigned rt_sz = removed_tails.size(); - //remove edges between removed tails - for(unsigned i=0; iget_head(); - - var_counter counter; - counter.count_vars(m, head, 1); - - unsigned tail_size=r->get_tail_size(); - unsigned pos_tail_size=r->get_positive_tail_size(); - - for(unsigned i=pos_tail_size; iget_tail(i), 1); - } - for(unsigned i=0; i & rule_content = m_rules_content.find_core(r)->get_data().m_value; - unsigned len = rule_content.size(); - if(len==1) { - return; - } - - func_decl * t1_pred = t1->get_decl(); - func_decl * t2_pred = t2->get_decl(); - ptr_vector removed_tails; - ptr_vector added_tails; - for(unsigned i1=0; i1get_decl()!=t1_pred) { - continue; - } - unsigned i2start = (t1_pred==t2_pred) ? (i1+1) : 0; - for(unsigned i2=i2start; i2get_decl()!=t2_pred) { - continue; - } - if(get_key(rt1, rt2)!=pair_key) { - continue; - } - expr_ref_vector normalizer(m); - get_normalizer(rt1, rt2, normalizer); - expr_ref_vector denormalizer(m); - reverse_renaming(m, normalizer, denormalizer); - expr_ref new_transf(m); - m_var_subst(t_new, denormalizer.size(), denormalizer.c_ptr(), new_transf); - app * new_lit = to_app(new_transf); - - m_pinned.push_back(new_lit); - rule_content[i1]=new_lit; - rule_content[i2]=rule_content.back(); - rule_content.pop_back(); - len--; //here the bound of both loops changes!!! - removed_tails.push_back(rt1); - removed_tails.push_back(rt2); - added_tails.push_back(new_lit); - //this exits the inner loop, the outer one continues in case there will - //be other matches - break; - } - } - SASSERT(!removed_tails.empty()); - SASSERT(!added_tails.empty()); - m_modified_rules.insert(r); - replace_edges(r, removed_tails, added_tails, rule_content); - } - - cost get_domain_size(func_decl * pred, unsigned arg_index) const { - relation_sort sort = pred->get_domain(arg_index); - return static_cast(m_context.get_sort_size_estimate(sort)); - //unsigned sz; - //if(!m_context.get_sort_size(sort, sz)) { - // sz=UINT_MAX; - //} - //return static_cast(sz); - } - - unsigned get_stratum(func_decl * pred) const { - return m_rs_aux_copy.get_predicate_strat(pred); - } - - cost estimate_size(app * t) const { - func_decl * pred = t->get_decl(); - unsigned n=pred->get_arity(); - rel_context* rel = m_context.get_rel_context(); - if (!rel) { - return cost(1); - } - relation_manager& rm = rel->get_rmanager(); - if( (m_context.saturation_was_run() && rm.try_get_relation(pred)) - || rm.is_saturated(pred)) { - SASSERT(rm.try_get_relation(pred)); //if it is saturated, it should exist - unsigned rel_size_int = rel->get_relation(pred).get_size_estimate_rows(); - if(rel_size_int!=0) { - cost rel_size = static_cast(rel_size_int); - cost curr_size = rel_size; - for(unsigned i=0; iget_arg(i))) { - curr_size /= get_domain_size(pred, i); - } - } - return curr_size; - } - } - cost res = 1; - for(unsigned i=0; iget_arg(i))) { - res *= get_domain_size(pred, i); - } - } - return res; - } - - cost compute_cost(app * t1, app * t2) const { - func_decl * t1_pred = t1->get_decl(); - func_decl * t2_pred = t2->get_decl(); - cost inters_size = 1; - variable_intersection vi(m_context.get_manager()); - vi.populate(t1, t2); - unsigned n = vi.size(); - for(unsigned i=0; i0) { - res /= 2; - } - else { - res *= 2; - } - } - }*/ - - TRACE("report_costs", - display_predicate(m_context, t1, tout); - display_predicate(m_context, t2, tout); - tout << res << "\n";); - return res; - } - - - bool pick_best_pair(app_pair & p) { - app_pair best; - bool found = false; - cost best_cost; - - cost_map::iterator it = m_costs.begin(); - cost_map::iterator end = m_costs.end(); - for(; it!=end; ++it) { - app_pair key = it->m_key; - pair_info & inf = *it->m_value; - if(!inf.can_be_joined()) { - continue; - } - cost c = inf.get_cost(); - if(!found || cm_key; - ptr_vector content = rcit->m_value; - SASSERT(content.size()<=2); - if(content.size()==orig_r->get_positive_tail_size()) { - //rule did not change - result->add_rule(orig_r); - continue; - } - - ptr_vector tail(content); - svector negs(tail.size(), false); - unsigned or_len = orig_r->get_tail_size(); - for(unsigned i=orig_r->get_positive_tail_size(); iget_tail(i)); - negs.push_back(orig_r->is_neg_tail(i)); - } - - rule * new_rule = m_context.get_rule_manager().mk(orig_r->get_head(), tail.size(), tail.c_ptr(), - negs.c_ptr()); - - new_rule->set_accounting_parent_object(m_context, orig_r); - m_context.get_rule_manager().mk_rule_rewrite_proof(*orig_r, *new_rule); - result->add_rule(new_rule); - } - while (!m_introduced_rules.empty()) { - result->add_rule(m_introduced_rules.back()); - m_context.get_rule_manager().mk_rule_asserted_proof(*m_introduced_rules.back()); - m_introduced_rules.pop_back(); - } - result->inherit_predicates(source); - return result; - } - }; - - rule_set * mk_simple_joins::operator()(rule_set const & source) { - rule_set rs_aux_copy(m_context); - rs_aux_copy.replace_rules(source); - if(!rs_aux_copy.is_closed()) { - rs_aux_copy.close(); - } - - join_planner planner(m_context, rs_aux_copy); - - return planner.run(source); - } - - -}; - diff --git a/src/muz/dl_mk_simple_joins.h b/src/muz/dl_mk_simple_joins.h deleted file mode 100644 index 36eb08dd5..000000000 --- a/src/muz/dl_mk_simple_joins.h +++ /dev/null @@ -1,63 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_mk_simple_joins.h - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2010-05-20. - -Revision History: - ---*/ -#ifndef _DL_MK_SIMPLE_JOINS_H_ -#define _DL_MK_SIMPLE_JOINS_H_ - -#include"map.h" -#include"obj_pair_hashtable.h" - -#include"dl_context.h" -#include"dl_rule_set.h" -#include"dl_rule_transformer.h" - -namespace datalog { - - /** - \brief Functor for creating rules that contain simple joins. - A simple join is the join of two tables. - - After applying this transformation, every rule has at most one join. - So, the rules will have the form - - HEAD :- TAIL. - HEAD :- TAIL_1, TAIL_2. - - We also assume a rule may contain interpreted expressions that work as filtering conditions. - So, we may also have: - - HEAD :- TAIL, C_1, ..., C_n. - HEAD :- TAIL_1, TAIL_2, C_1, ..., C_n. - - Where the C_i's are interpreted expressions. - - We say that a rule containing C_i's is a rule with a "big tail". - */ - class mk_simple_joins : public rule_transformer::plugin { - context & m_context; - rule_manager & rm; - public: - mk_simple_joins(context & ctx); - - rule_set * operator()(rule_set const & source); - }; - -}; - -#endif /* _DL_MK_SIMPLE_JOINS_H_ */ - diff --git a/src/muz/dl_product_relation.cpp b/src/muz/dl_product_relation.cpp deleted file mode 100644 index 48cd666e6..000000000 --- a/src/muz/dl_product_relation.cpp +++ /dev/null @@ -1,1117 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_product_relation.cpp - -Abstract: - - A Relation combinator. - -Author: - - Nikolaj Bjorner (nbjorner) 2010-4-11 - -Revision History: - -Notes: - - join = - more refined version lets augment the product - relation as a consequence of join. - join Q = - join = - - - u = - more refined version: - < (R u R') n (R u S') n (R' u S), (S u S') n (S u R') n (S' u R)> - - - proj = < proj R, proj S> - - & phi = - attach S to [R & phi] whenever R & phi can propagate to S - - - [rename] = - - - ---*/ - - -#include "dl_sieve_relation.h" -#include "dl_table_relation.h" -#include "dl_product_relation.h" -#include "bool_rewriter.h" -#include "ast_pp.h" - -namespace datalog { - - // ----------------------------------- - // - // product_relation_plugin - // - // ----------------------------------- - - product_relation_plugin & product_relation_plugin::get_plugin(relation_manager & rmgr) { - product_relation_plugin * res = - static_cast(rmgr.get_relation_plugin(get_name())); - if(!res) { - res = alloc(product_relation_plugin, rmgr); - rmgr.register_plugin(res); - } - return *res; - } - - product_relation_plugin::product_relation_plugin(relation_manager& m): - relation_plugin(product_relation_plugin::get_name(), m, ST_PRODUCT_RELATION), - m_spec_store(*this) { - } - - void product_relation_plugin::initialize(family_id fid) { - relation_plugin::initialize(fid); - m_spec_store.add_available_kind(get_kind()); - } - - family_id product_relation_plugin::get_relation_kind(const relation_signature & sig, const rel_spec & spec) { - return m_spec_store.get_relation_kind(sig, spec); - } - - family_id product_relation_plugin::get_relation_kind(const product_relation & r) { - return get_relation_kind(r.get_signature(), r.m_spec); - } - - bool product_relation_plugin::can_handle_signature(const relation_signature & s) { - return m_spec_store.contains_signature(s); - } - - bool product_relation_plugin::can_handle_signature(const relation_signature & s, family_id k) { - return true; - } - - product_relation& product_relation_plugin::get(relation_base& r) { - return dynamic_cast(r); - } - - product_relation const & product_relation_plugin::get(relation_base const& r) { - return dynamic_cast(r); - } - - product_relation* product_relation_plugin::get(relation_base* r) { - return dynamic_cast(r); - } - - product_relation const* product_relation_plugin::get(relation_base const* r) { - return dynamic_cast(r); - } - - bool product_relation_plugin::is_product_relation(relation_base const& r) { - return r.get_plugin().get_name() == product_relation_plugin::get_name(); - } - - bool product_relation_plugin::are_aligned(const product_relation& r1, const product_relation& r2) { - unsigned sz = r1.size(); - if(sz!=r2.size()) { - return false; - } - for(unsigned i=0; i & rels, - rel_spec & res) { - vector specs; - ptr_vector::const_iterator rit = rels.begin(); - ptr_vector::const_iterator rend = rels.end(); - for(; rit!=rend; ++rit) { - specs.push_back((*rit)->m_spec); - } - - vector::iterator sit = specs.begin(); - vector::iterator send = specs.end(); - for(; sit!=send; ++sit) { - rel_spec & s = *sit; - std::sort(s.begin(), s.end()); - } - - res.reset(); - for(;;) { - family_id next = -1; - - sit = specs.begin(); - for(; sit!=send; ++sit) { - rel_spec & s = *sit; - if(!s.empty() && s.back()>next) { - next = s.back(); - } - } - if(next==-1) { - //we're done - break; - } - res.push_back(next); - sit = specs.begin(); - for(; sit!=send; ++sit) { - rel_spec & s = *sit; - if(!s.empty() && s.back()==next) { - s.pop_back(); - } - } - } - } - - - relation_base * product_relation_plugin::mk_empty(const relation_signature & s) { - return alloc(product_relation,*this, s); - } - - relation_base * product_relation_plugin::mk_empty(const relation_signature & s, family_id kind) { - rel_spec spec; - m_spec_store.get_relation_spec(s, kind, spec); - relation_vector inner_rels; - unsigned rel_cnt = spec.size(); - for(unsigned i=0; i m_joins; - ptr_vector m_full; - unsigned_vector m_offset1; - svector m_kind1; - unsigned_vector m_offset2; - svector m_kind2; - - const relation_base & get_nonsieve_relation(const relation_base & r) { - relation_plugin & rp = r.get_plugin(); - if(rp.is_sieve_relation()) { - return static_cast(r).get_inner(); - } - else { - return r; - } - } - - relation_plugin & get_nonsieve_plugin(const relation_base & r) { - return get_nonsieve_relation(r).get_plugin(); - } - - family_id get_nonsieve_kind(const relation_base & r) { - return get_nonsieve_relation(r).get_kind(); - } - - /** - A tableish relatio is either a table_relation or a sieve_relation with a table_relation inside. - */ - bool is_tableish_relation(const relation_base & r) { - return get_nonsieve_plugin(r).from_table(); - } - - relation_base * get_full_tableish_relation(const relation_signature & sig, func_decl* p, family_id kind) { - relation_manager& rmgr = m_plugin.get_manager(); - table_signature tsig; - if(rmgr.relation_signature_to_table(sig, tsig)) { - return rmgr.mk_table_relation(sig, rmgr.get_appropriate_plugin(tsig).mk_full(p, tsig, kind)); - } - unsigned sz = sig.size(); - tsig.reset(); - for(unsigned i=0; i relations; - unsigned sz = m_joins.size(); - relation_base* result = 0; - for (unsigned i = 0; i < sz; ++i) { - relation_base const& r1 = (m_kind1[i] == T_FULL)?(*m_full[m_offset1[i]]):access(m_offset1[i], _r1); - relation_base const& r2 = (m_kind2[i] == T_FULL)?(*m_full[m_offset2[i]]):access(m_offset2[i], _r2); - relations.push_back((*m_joins[i])(r1, r2)); - } - result = alloc(product_relation, m_plugin, get_result_signature(), sz, relations.c_ptr()); - TRACE("dl",result->display(tout);); - return result; - } - }; - - relation_join_fn * product_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (is_product_relation(r1) && is_product_relation(r2)) { - return alloc(join_fn, *this, get(r1), get(r2), col_cnt, cols1, cols2); - } - if (is_product_relation(r1)) { - return alloc(join_fn, *this, get(r1), r2, col_cnt, cols1, cols2); - } - if (is_product_relation(r2)) { - return alloc(join_fn, *this, r1, get(r2), col_cnt, cols1, cols2); - } - if (r1.get_kind() != r2.get_kind()) { - return alloc(join_fn, *this, r1, r2, col_cnt, cols1, cols2); - } - return 0; - } - - - class product_relation_plugin::transform_fn : public relation_transformer_fn { - relation_signature m_sig; - ptr_vector m_transforms; - public: - transform_fn(relation_signature s, unsigned num_trans, relation_transformer_fn** trans): - m_sig(s), - m_transforms(num_trans, trans) {} - - ~transform_fn() { dealloc_ptr_vector_content(m_transforms); } - - virtual relation_base * operator()(const relation_base & _r) { - product_relation const& r = get(_r); - product_relation_plugin& p = r.get_plugin(); - SASSERT(m_transforms.size() == r.size()); - ptr_vector relations; - for (unsigned i = 0; i < r.size(); ++i) { - relations.push_back((*m_transforms[i])(r[i])); - } - relation_base* result = alloc(product_relation, p, m_sig, relations.size(), relations.c_ptr()); - TRACE("dl", _r.display(tout); result->display(tout);); - return result; - } - }; - - relation_transformer_fn * product_relation_plugin::mk_project_fn(const relation_base & _r, - unsigned col_cnt, const unsigned * removed_cols) { - if (is_product_relation(_r)) { - product_relation const& r = get(_r); - ptr_vector projs; - for (unsigned i = 0; i < r.size(); ++i) { - projs.push_back(get_manager().mk_project_fn(r[i], col_cnt, removed_cols)); - } - relation_signature s; - relation_signature::from_project(r.get_signature(), col_cnt, removed_cols, s); - return alloc(transform_fn, s, projs.size(), projs.c_ptr()); - } - return 0; - } - - relation_transformer_fn * product_relation_plugin::mk_rename_fn(const relation_base & _r, - unsigned cycle_len, const unsigned * permutation_cycle) { - if(is_product_relation(_r)) { - ptr_vector trans; - product_relation const& r = get(_r); - for (unsigned i = 0; i < r.size(); ++i) { - trans.push_back(get_manager().mk_rename_fn(r[i], cycle_len, permutation_cycle)); - } - relation_signature s; - relation_signature::from_rename(r.get_signature(), cycle_len, permutation_cycle, s); - return alloc(transform_fn, s, trans.size(), trans.c_ptr()); - } - return 0; - } - - class product_relation_plugin::aligned_union_fn : public relation_union_fn { - relation_manager & m_rmgr; - bool m_is_widen; - - //m_union[i][j] is union between i-th and j-th relation. - //It can be zero which means that particular union should be skipped. - vector > m_unions; - - void mk_union_fn(unsigned i, unsigned j, relation_base const& r1, relation_base const& r2, - const relation_base* delta) { - relation_manager& rmgr = r1.get_manager(); - relation_union_fn* u = 0; - if (m_is_widen) { - u = rmgr.mk_widen_fn(r1, r2, delta); - } - else { - u = rmgr.mk_union_fn(r1, r2, delta); - } - m_unions.back().push_back(u); - } - - void init(const relation_vector & tgts, const relation_vector & srcs, const relation_vector * deltas) { - SASSERT(tgts.size()==srcs.size()); - unsigned num = tgts.size(); - for (unsigned i = 0; i < num; ++i) { - relation_base& r1 = *tgts[i]; - relation_base* delta = deltas ? (*deltas)[i] : 0; - m_unions.push_back(ptr_vector()); - for (unsigned j = 0; j < num; ++j) { - relation_base& r2 = *srcs[j]; - mk_union_fn(i, j, r1, r2, delta); - } - } - } - - bool can_do_inner_union(unsigned tgt_idx, unsigned src_idx) { - return m_unions[tgt_idx][src_idx]!=0; - } - - void do_inner_union(unsigned tgt_idx, unsigned src_idx, relation_base& tgt, - relation_base& src, relation_base * delta) { - SASSERT(m_unions[tgt_idx][src_idx]); - (*m_unions[tgt_idx][src_idx])(tgt, src, delta); - } - - /** - If tgt is zero, it is assumed to be a full relation. - */ - void do_destructive_intersection(scoped_rel& tgt, scoped_rel& src) { - if(!src) { - return; - } - if(!tgt) { - tgt=src.release(); - return; - } - do_intersection(*tgt, *src); - src = 0; - } - - void do_intersection(relation_base& tgt, relation_base& src) { - scoped_ptr intersect_fun = - m_rmgr.mk_filter_by_intersection_fn(tgt, src); - if(!intersect_fun) { - warning_msg("intersection does not exist"); - return; - } - (*intersect_fun)(tgt, src); - } - void do_delta_union(unsigned rel_idx, relation_base& tgt, relation_base& src) { - scoped_ptr union_fun = m_rmgr.mk_union_fn(tgt, src); - SASSERT(union_fun); - (*union_fun)(tgt, src); - } - public: - aligned_union_fn(product_relation const& tgt, product_relation const& src, product_relation const* delta, - bool is_widen) : - m_rmgr(tgt.get_manager()), - m_is_widen(is_widen) { - SASSERT(vectors_equal(tgt.m_spec, src.m_spec)); - SASSERT(!delta || vectors_equal(tgt.m_spec, delta->m_spec)); - init(tgt.m_relations, src.m_relations, delta ? &delta->m_relations : 0); - } - - ~aligned_union_fn() { - unsigned sz = m_unions.size(); - for(unsigned i=0; i side_results; - ptr_vector side_deltas; - - for (unsigned i = 0; i < num; ++i) { - relation_base& itgt = tgt[i]; - relation_base* idelta = delta ? &(*delta)[i] : 0; - - scoped_rel fresh_delta = idelta ? idelta->get_plugin().mk_empty(*idelta) : 0; - scoped_rel side_result; - scoped_rel side_delta; - - //compute the side unions with which we will intersect the result of the basic one - for (unsigned j = 0; j < num; ++j) { - if (i == j) { - continue; //this is the basic union which we will perform later - } - if (can_do_inner_union(i, j)) { - TRACE("dl", itgt.display(tout << "tgt:\n"); src[j].display(tout << "src:\n");); - // union[i][j] - scoped_rel one_side_union = itgt.clone(); - scoped_rel one_side_delta = fresh_delta ? fresh_delta->clone() : 0; - TRACE("dl", one_side_union->display(tout << "union 1:\n"); src[j].display(tout);); - do_inner_union(i, j, *one_side_union, src[j], one_side_delta.get()); - TRACE("dl", one_side_union->display(tout << "union:\n");); - do_destructive_intersection(side_result, one_side_union); - TRACE("dl", - side_result->display(tout << "inner-union: " << i << " " << j << "\n"); - itgt.display(tout << "tgt:\n");); - if (one_side_delta) { - do_destructive_intersection(side_delta, one_side_delta); - } - - // union[j][i] - one_side_union = src[i].clone(); - one_side_delta = fresh_delta ? fresh_delta->clone() : 0; - TRACE("dl", one_side_union->display(tout << "union 2:\n"); tgt[j].display(tout);); - do_inner_union(i, j, *one_side_union, tgt[j], one_side_delta.get()); - TRACE("dl", one_side_union->display(tout << "union:\n");); - do_destructive_intersection(side_result, one_side_union); - TRACE("dl", - side_result->display(tout << "inner-union: " << i << " " << j << "\n"); - itgt.display(tout << "tgt:\n");); - if (one_side_delta) { - do_destructive_intersection(side_delta, one_side_delta); - } - } - } - side_results.push_back(side_result.release()); - side_deltas.push_back(side_delta.release()); - } - for (unsigned i = 0; i < num; ++i) { - relation_base& itgt = tgt[i]; - relation_base* idelta = delta ? &(*delta)[i] : 0; - scoped_rel fresh_delta = idelta ? idelta->get_plugin().mk_empty(*idelta) : 0; - scoped_rel side_result(side_results[i]); - scoped_rel side_delta(side_deltas[i]); - - // perform the basic union - // assume a relation can always perform union with the relation of the same type - VERIFY(can_do_inner_union(i,i)); - do_inner_union(i, i, itgt, src[i], fresh_delta.get()); - - if (side_result) { - do_intersection(itgt, *side_result); - TRACE("dl", side_result->display(tout << "inner-union-end: " << i << "\n");); - } - if (fresh_delta) { - do_destructive_intersection(fresh_delta,side_delta); - SASSERT(idelta); - do_delta_union(i, *idelta, *fresh_delta); - } - } - if (num == 0) { - //we need to handle product relation of no relations separately - if (!src.m_default_empty && tgt.m_default_empty) { - tgt.m_default_empty = false; - if (delta) { - delta->m_default_empty = false; - } - } - } - TRACE("dl", _tgt.display(tout << "dst':\n"); - if (_delta) _delta->display(tout << "delta:\n"); ;); - } - }; - - class product_relation_plugin::unaligned_union_fn : public relation_union_fn { - bool m_is_widen; - rel_spec m_common_spec; - scoped_ptr m_aligned_union_fun; - public: - unaligned_union_fn(product_relation const& tgt, product_relation const& src, - product_relation const* delta, bool is_widen) : m_is_widen(is_widen) { - ptr_vector rels; - rels.push_back(&tgt); - rels.push_back(&src); - if(delta) { - rels.push_back(delta); - } - get_common_spec(rels, m_common_spec); - } - - - virtual void operator()(relation_base& _tgt, const relation_base& _src, relation_base* _delta) { - TRACE("dl", _tgt.display(tout << "dst:\n"); _src.display(tout << "src:\n");); - product_relation& tgt = get(_tgt); - product_relation const& src0 = get(_src); - product_relation* delta = _delta ? get(_delta) : 0; - - tgt.convert_spec(m_common_spec); - if(delta) { - delta->convert_spec(m_common_spec); - } - scoped_rel src_scoped; - if(src0.get_kind()!=tgt.get_kind()) { - src_scoped = src0.clone(); - src_scoped->convert_spec(m_common_spec); - } - product_relation const& src = src_scoped ? *src_scoped : src0; - - if(!m_aligned_union_fun) { - m_aligned_union_fun = alloc(aligned_union_fn, tgt, src, delta, m_is_widen); - SASSERT(m_aligned_union_fun); - } - (*m_aligned_union_fun)(tgt, src, delta); - TRACE("dl", _tgt.display(tout << "dst':\n"); - if (_delta) _delta->display(tout << "delta:\n");); - } - }; - - class product_relation_plugin::single_non_transparent_src_union_fn : public relation_union_fn { - unsigned m_single_rel_idx; - scoped_ptr m_inner_union_fun; - public: - single_non_transparent_src_union_fn(unsigned single_rel_idx, relation_union_fn* inner_union_fun) - : m_single_rel_idx(single_rel_idx), - m_inner_union_fun(inner_union_fun) {} - - virtual void operator()(relation_base& tgt, const relation_base& _src, relation_base* delta) { - product_relation const& src = get(_src); - (*m_inner_union_fun)(tgt, src[m_single_rel_idx], delta); - } - }; - - relation_union_fn * product_relation_plugin::mk_union_w_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta, bool is_widen) { - if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) { - if(are_aligned(get(tgt), get(src)) && (!delta || are_aligned(get(tgt), *get(delta)))) { - return alloc(aligned_union_fn, get(tgt), get(src), get(delta), is_widen); - } - return alloc(unaligned_union_fn, get(tgt), get(src), get(delta), is_widen); - } - if(check_kind(src)) { - const product_relation & p_src = get(src); - unsigned single_idx; - if(p_src.try_get_single_non_transparent(single_idx)) { - relation_union_fn * inner; - if(is_widen) { - inner = get_manager().mk_widen_fn(tgt, p_src[single_idx], delta); - } - else { - inner = get_manager().mk_union_fn(tgt, p_src[single_idx], delta); - } - if(inner) { - return alloc(single_non_transparent_src_union_fn, single_idx, inner); - } - } - } - return 0; - } - - relation_union_fn * product_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - return mk_union_w_fn(tgt, src, delta, false); - } - - relation_union_fn * product_relation_plugin::mk_widen_fn( - const relation_base & tgt, const relation_base & src, const relation_base * delta) { - return mk_union_w_fn(tgt, src, delta, true); - } - - class product_relation_plugin::mutator_fn : public relation_mutator_fn { - ptr_vector m_mutators; - public: - mutator_fn(unsigned sz, relation_mutator_fn** muts): - m_mutators(sz, muts) {} - - ~mutator_fn() { dealloc_ptr_vector_content(m_mutators); } - - virtual void operator()(relation_base & _r) { - TRACE("dl", _r.display(tout);); - product_relation& r = get(_r); - SASSERT(m_mutators.size() == r.size()); - for (unsigned i = 0; i < r.size(); ++i) { - relation_mutator_fn* m = m_mutators[i]; - if (m) { - (*m)(r[i]); - } - } - TRACE("dl", _r.display(tout);); - } - }; - - - relation_mutator_fn * product_relation_plugin::mk_filter_identical_fn( - const relation_base & _t, unsigned col_cnt, const unsigned * identical_cols) { - - if(is_product_relation(_t)) { - bool found = false; - product_relation const& r = get(_t); - ptr_vector mutators; - for (unsigned i = 0; i < r.size(); ++i) { - relation_mutator_fn* m = get_manager().mk_filter_identical_fn(r[i], col_cnt, identical_cols); - mutators.push_back(m); - if (m) found = true; - } - if (found) { - return alloc(mutator_fn, mutators.size(), mutators.c_ptr()); - } - } - return 0; - } - - relation_mutator_fn * product_relation_plugin::mk_filter_equal_fn(const relation_base & _t, - const relation_element & value, unsigned col) { - if(is_product_relation(_t)) { - product_relation const& r = get(_t); - ptr_vector mutators; - bool found = false; - for (unsigned i = 0; i < r.size(); ++i) { - relation_mutator_fn* m = get_manager().mk_filter_equal_fn(r[i], value, col); - mutators.push_back(m); - if (m) found = true; - } - if (found) { - return alloc(mutator_fn, mutators.size(), mutators.c_ptr()); - } - } - return 0; - } - - class product_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { - ptr_vector m_mutators; - svector > m_attach; - public: - - filter_interpreted_fn(product_relation const& r, app* cond) { - for (unsigned i = 0; i < r.size(); ++i) { - m_mutators.push_back(r.get_manager().mk_filter_interpreted_fn(r[i], cond)); - } - for (unsigned i = 0; i < r.size(); ++i) { - relation_mutator_fn& m1 = *(m_mutators[i]); - for (unsigned j = i + 1; j < r.size(); ++j) { - relation_mutator_fn& m2 = *(m_mutators[j]); - if (m1.supports_attachment(r[j])) { - m_attach.push_back(std::make_pair(i,j)); - } - if (m2.supports_attachment(r[i])) { - m_attach.push_back(std::make_pair(j,i)); - } - } - } - } - - ~filter_interpreted_fn() { dealloc_ptr_vector_content(m_mutators); } - - void operator()(relation_base& _r) { - TRACE("dl", _r.display(tout);); - product_relation const& r = get(_r); - for (unsigned i = 0; i < m_attach.size(); ++i) { - m_mutators[m_attach[i].first]->attach(r[m_attach[i].second]); - } - for (unsigned i = 0; i < m_mutators.size(); ++i) { - (*m_mutators[i])(r[i]); - } - TRACE("dl", _r.display(tout);); - } - }; - - relation_mutator_fn * product_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { - return alloc(filter_interpreted_fn, get(t), condition); - } - - - // ----------------------------------- - // - // product_relation - // - // ----------------------------------- - - product_relation::product_relation(product_relation_plugin& p, relation_signature const& s): - relation_base(p, s), - m_default_empty(true) { - ensure_correct_kind(); - } - - product_relation::product_relation(product_relation_plugin& p, relation_signature const& s, unsigned num_relations, relation_base** relations) : - relation_base(p, s), - m_default_empty(true) { - for (unsigned i = 0; i < num_relations; ++i) { - SASSERT(relations[i]->get_signature()==s); - m_relations.push_back(relations[i]); - } - ensure_correct_kind(); - } - - product_relation::~product_relation() { - unsigned num_relations = m_relations.size(); - for (unsigned i = 0; i < num_relations; ++i) { - m_relations[i]->deallocate(); - } - } - - product_relation_plugin& product_relation::get_plugin() const { - return dynamic_cast(relation_base::get_plugin()); - } - - void product_relation::ensure_correct_kind() { - unsigned rel_cnt = m_relations.size(); - //the rel_cnt==0 part makes us to update the kind also when the relation is newly created - bool spec_changed = rel_cnt!=m_spec.size() || rel_cnt==0; - if(spec_changed) { - m_spec.resize(rel_cnt); - } - for(unsigned i=0;iget_kind(); - if(spec_changed || m_spec[i]!=rkind) { - spec_changed = true; - m_spec[i]=rkind; - } - } - if(spec_changed) { - family_id new_kind = get_plugin().get_relation_kind(*this); - set_kind(new_kind); - } - } - - void product_relation::convert_spec(const rel_spec & spec) { - - func_decl* p = 0; - const relation_signature & sig = get_signature(); - family_id new_kind = get_plugin().get_relation_kind(sig, spec); - if(new_kind==get_kind()) { - return; - } - - unsigned old_sz = size(); - unsigned new_sz = spec.size(); - unsigned old_remain = old_sz; - relation_vector new_rels; - - //the loop is quadratic with the number of relations, maybe we want to fix it - for(unsigned i=0; iget_kind()==ikind) { - irel = m_relations[j]; - m_relations[j] = 0; - old_remain--; - break; - } - } - if(!irel) { - if(old_sz==0 && m_default_empty) { - //The relation didn't contain any inner relations but it was empty, - //so we make the newly added relations empty as well. - irel = get_manager().mk_empty_relation(sig, new_kind); - } - else { - irel = get_manager().mk_full_relation(sig, p, new_kind); - } - } - new_rels.push_back(irel); - } - SASSERT(old_remain==0); //the new specification must be a superset of the old one - m_relations = new_rels; - - set_kind(new_kind); - DEBUG_CODE( - ensure_correct_kind(); - SASSERT(get_kind()==new_kind); - ); - } - - bool product_relation::try_get_single_non_transparent(unsigned & idx) const { - unsigned sz = size(); - bool found = false; - unsigned candidate; - for(unsigned i=0; i relations; - for (unsigned i = 0; i < size(); ++i) { - relations.push_back((*this)[i].clone()); - } - product_relation_plugin& p = get_plugin(); - return alloc(product_relation, p, get_signature(), relations.size(), relations.c_ptr()); - } - - product_relation * product_relation::complement(func_decl*) const { - if(m_relations.empty()) { - product_relation * res = clone(); - res->m_default_empty = !m_default_empty; - return res; - } - UNREACHABLE(); - return 0; - } - - bool product_relation::empty() const { - if(m_relations.empty()) { - return m_default_empty; - } - for (unsigned i = 0; i < m_relations.size(); ++i) { - if (m_relations[i]->empty()) { - return true; - } - } - return false; - } - - void product_relation::to_formula(expr_ref& fml) const { - ast_manager& m = fml.get_manager(); - expr_ref_vector conjs(m); - expr_ref tmp(m); - for (unsigned i = 0; i < m_relations.size(); ++i) { - m_relations[i]->to_formula(tmp); - conjs.push_back(tmp); - } - bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), fml); - } - - void product_relation::display(std::ostream & out) const { - out<<"Product of the following relations:\n"; - for (unsigned i = 0; i < m_relations.size(); ++i) { - m_relations[i]->display(out); - } - } - -}; - - - diff --git a/src/muz/dl_product_relation.h b/src/muz/dl_product_relation.h deleted file mode 100644 index bf37a59d0..000000000 --- a/src/muz/dl_product_relation.h +++ /dev/null @@ -1,190 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_product_relation.h - -Abstract: - - A Relation relation combinator. - -Author: - - Nikolaj Bjorner (nbjorner) 2010-4-11 - -Revision History: - ---*/ -#ifndef _DL_PRODUCT_RELATION_H_ -#define _DL_PRODUCT_RELATION_H_ - - -#include "dl_context.h" - -namespace datalog { - - class product_relation; - - class product_relation_plugin : public relation_plugin { - friend class product_relation; - public: - typedef svector rel_spec; - private: - class join_fn; - class transform_fn; - class mutator_fn; - class aligned_union_fn; - class unaligned_union_fn; - class single_non_transparent_src_union_fn; - class filter_equal_fn; - class filter_identical_fn; - class filter_interpreted_fn; - struct fid_hash { - typedef family_id data; - unsigned operator()(data x) const { return static_cast(x); } - }; - - rel_spec_store > m_spec_store; - - family_id get_relation_kind(const product_relation & r); - - bool is_product_relation(relation_base * r) { return r->get_plugin().is_product_relation(); } - - public: - static product_relation_plugin& get_plugin(relation_manager & rmgr); - - product_relation_plugin(relation_manager& m); - - virtual void initialize(family_id fid); - - virtual bool can_handle_signature(const relation_signature & s); - virtual bool can_handle_signature(const relation_signature & s, family_id kind); - - static symbol get_name() { return symbol("product_relation"); } - - family_id get_relation_kind(const relation_signature & sig, const rel_spec & spec); - - virtual relation_base * mk_empty(const relation_signature & s); - virtual relation_base * mk_empty(const relation_signature & s, family_id kind); - - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - virtual relation_base * mk_full(func_decl* p, const relation_signature & s, family_id kind); - - protected: - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - - static bool is_product_relation(relation_base const& r); - - private: - static product_relation& get(relation_base& r); - static product_relation const & get(relation_base const& r); - static product_relation* get(relation_base* r); - static product_relation const* get(relation_base const* r); - - relation_union_fn * mk_union_w_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta, bool is_widen); - - bool are_aligned(const product_relation& r1, const product_relation& r2); - static void get_common_spec(const ptr_vector & rels, rel_spec & res); - }; - - - class product_relation : public relation_base { - friend class product_relation_plugin; - - friend class product_relation_plugin::join_fn; - friend class product_relation_plugin::transform_fn; - friend class product_relation_plugin::mutator_fn; - friend class product_relation_plugin::aligned_union_fn; - friend class product_relation_plugin::unaligned_union_fn; - friend class product_relation_plugin::single_non_transparent_src_union_fn; - friend class product_relation_plugin::filter_equal_fn; - friend class product_relation_plugin::filter_identical_fn; - friend class product_relation_plugin::filter_interpreted_fn; - - - - typedef product_relation_plugin::rel_spec rel_spec; - - /** - If m_relations is empty, value of this determines whether the relation is empty or full. - */ - bool m_default_empty; - - /** - There must not be two relations of the same kind - */ - ptr_vector m_relations; - - /** - Array of kinds of inner relations. - - If two product relations have equal signature and specification, their - m_relations arrays contain corresponding relations at the same indexes. - - The value returned by get_kind() depends uniquely on the specification. - */ - rel_spec m_spec; - - /** - \brief Ensure the kind assigned to this relation reflects the types of inner relations. - */ - void ensure_correct_kind(); - /** - The current specification must be a subset of the new one. - */ - void convert_spec(const rel_spec & spec); - public: - product_relation(product_relation_plugin& p, relation_signature const& s); - product_relation(product_relation_plugin& p, relation_signature const& s, unsigned num_relations, relation_base** relations); - - ~product_relation(); - - virtual bool empty() const; - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual product_relation * clone() const; - virtual product_relation * complement(func_decl* p) const; - virtual void display(std::ostream & out) const; - virtual void to_formula(expr_ref& fml) const; - product_relation_plugin& get_plugin() const; - - unsigned size() const { return m_relations.size(); } - relation_base& operator[](unsigned i) const { return *m_relations[i]; } - - /** - If all relations except one are sieve_relations with no inner columns, - return true and into \c idx assign index of that relation. Otherwise return - false. - */ - bool try_get_single_non_transparent(unsigned & idx) const; - - virtual bool is_precise() const { - for (unsigned i = 0; i < m_relations.size(); ++i) { - if (!m_relations[i]->is_precise()) { - return false; - } - } - return true; - } - }; - -}; - -#endif - diff --git a/src/muz/dl_relation_manager.cpp b/src/muz/dl_relation_manager.cpp deleted file mode 100644 index 457ef28c0..000000000 --- a/src/muz/dl_relation_manager.cpp +++ /dev/null @@ -1,1702 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_relation_manager.cpp - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-14. - -Revision History: - ---*/ - - -#include -#include"ast_pp.h" -#include"dl_check_table.h" -#include"dl_context.h" -#include"dl_finite_product_relation.h" -#include"dl_product_relation.h" -#include"dl_sieve_relation.h" -#include"dl_table_relation.h" -#include"dl_relation_manager.h" - -namespace datalog { - - relation_manager::~relation_manager() { - reset(); - } - - - void relation_manager::reset_relations() { - relation_map::iterator it=m_relations.begin(); - relation_map::iterator end=m_relations.end(); - for(;it!=end;++it) { - func_decl * pred = it->m_key; - get_context().get_manager().dec_ref(pred); //inc_ref in get_relation - relation_base * r=(*it).m_value; - r->deallocate(); - } - m_relations.reset(); - } - - void relation_manager::reset() { - reset_relations(); - - m_favourite_table_plugin = static_cast(0); - m_favourite_relation_plugin = static_cast(0); - dealloc_ptr_vector_content(m_table_plugins); - m_table_plugins.reset(); - dealloc_ptr_vector_content(m_relation_plugins); - m_relation_plugins.reset(); - m_next_table_fid = 0; - m_next_relation_fid = 0; - } - - dl_decl_util & relation_manager::get_decl_util() const { - return get_context().get_decl_util(); - } - - family_id relation_manager::get_next_relation_fid(relation_plugin & claimer) { - unsigned res = m_next_relation_fid++; - m_kind2plugin.insert(res, &claimer); - return res; - } - - void relation_manager::set_predicate_kind(func_decl * pred, family_id kind) { - SASSERT(!m_relations.contains(pred)); - m_pred_kinds.insert(pred, kind); - } - - family_id relation_manager::get_requested_predicate_kind(func_decl * pred) { - family_id res; - if(m_pred_kinds.find(pred, res)) { - return res; - } - else { - return null_family_id; - } - } - - relation_base & relation_manager::get_relation(func_decl * pred) { - relation_base * res = try_get_relation(pred); - if(!res) { - relation_signature sig; - from_predicate(pred, sig); - family_id rel_kind = get_requested_predicate_kind(pred); - res = mk_empty_relation(sig, rel_kind); - store_relation(pred, res); - } - return *res; - } - - relation_base * relation_manager::try_get_relation(func_decl * pred) const { - relation_base * res = 0; - if(!m_relations.find(pred, res)) { - return 0; - } - SASSERT(res); - return res; - } - - void relation_manager::store_relation(func_decl * pred, relation_base * rel) { - SASSERT(rel); - relation_map::entry * e = m_relations.insert_if_not_there2(pred, 0); - if (e->get_data().m_value) { - e->get_data().m_value->deallocate(); - } - else { - get_context().get_manager().inc_ref(pred); //dec_ref in reset - } - e->get_data().m_value = rel; - } - - void relation_manager::collect_non_empty_predicates(decl_set & res) const { - relation_map::iterator it = m_relations.begin(); - relation_map::iterator end = m_relations.end(); - for(; it!=end; ++it) { - if(!it->m_value->empty()) { - res.insert(it->m_key); - } - } - } - - void relation_manager::restrict_predicates(const decl_set & preds) { - typedef ptr_vector fd_vector; - fd_vector to_remove; - - relation_map::iterator rit = m_relations.begin(); - relation_map::iterator rend = m_relations.end(); - for(; rit!=rend; ++rit) { - func_decl * pred = rit->m_key; - if (!preds.contains(pred)) { - to_remove.insert(pred); - } - } - - fd_vector::iterator pit = to_remove.begin(); - fd_vector::iterator pend = to_remove.end(); - for(; pit!=pend; ++pit) { - func_decl * pred = *pit; - relation_base * rel; - VERIFY( m_relations.find(pred, rel) ); - rel->deallocate(); - m_relations.remove(pred); - get_context().get_manager().dec_ref(pred); - } - - set_intersection(m_saturated_rels, preds); - } - - void relation_manager::register_plugin(table_plugin * plugin) { - plugin->initialize(get_next_table_fid()); - m_table_plugins.push_back(plugin); - - if(plugin->get_name()==get_context().default_table()) { - m_favourite_table_plugin = plugin; - } - - table_relation_plugin * tr_plugin = alloc(table_relation_plugin, *plugin, *this); - register_relation_plugin_impl(tr_plugin); - m_table_relation_plugins.insert(plugin, tr_plugin); - - symbol checker_name = get_context().default_table_checker(); - if(get_context().default_table_checked() && get_table_plugin(checker_name)) { - if( m_favourite_table_plugin && - (plugin==m_favourite_table_plugin || plugin->get_name()==checker_name) ) { - symbol checked_name = get_context().default_table(); - //the plugins we need to create the checking plugin were just added - SASSERT(m_favourite_table_plugin->get_name()==get_context().default_table()); - table_plugin * checking_plugin = alloc(check_table_plugin, *this, checker_name, checked_name); - register_plugin(checking_plugin); - m_favourite_table_plugin = checking_plugin; - } - if(m_favourite_relation_plugin && m_favourite_relation_plugin->from_table()) { - table_relation_plugin * fav_rel_plugin = - static_cast(m_favourite_relation_plugin); - if(&fav_rel_plugin->get_table_plugin()==plugin || plugin->get_name()==checker_name) { - //the plugins we need to create the checking table_relation_plugin were just added - SASSERT(m_favourite_relation_plugin->get_name() == - get_context().default_relation()); - symbol checked_name = fav_rel_plugin->get_table_plugin().get_name(); - table_plugin * checking_plugin = alloc(check_table_plugin, *this, checker_name, checked_name); - register_plugin(checking_plugin); - - table_relation_plugin * checking_tr_plugin = - alloc(table_relation_plugin, *checking_plugin, *this); - register_relation_plugin_impl(checking_tr_plugin); - m_table_relation_plugins.insert(checking_plugin, checking_tr_plugin); - m_favourite_relation_plugin = checking_tr_plugin; - } - } - } - - } - - void relation_manager::register_relation_plugin_impl(relation_plugin * plugin) { - m_relation_plugins.push_back(plugin); - plugin->initialize(get_next_relation_fid(*plugin)); - if (plugin->get_name() == get_context().default_relation()) { - m_favourite_relation_plugin = plugin; - } - if(plugin->is_finite_product_relation()) { - finite_product_relation_plugin * fprp = static_cast(plugin); - relation_plugin * inner = &fprp->get_inner_plugin(); - m_finite_product_relation_plugins.insert(inner, fprp); - } - } - - relation_plugin * relation_manager::try_get_appropriate_plugin(const relation_signature & s) { - if(m_favourite_relation_plugin && m_favourite_relation_plugin->can_handle_signature(s)) { - return m_favourite_relation_plugin; - } - relation_plugin_vector::iterator rpit = m_relation_plugins.begin(); - relation_plugin_vector::iterator rpend = m_relation_plugins.end(); - for(; rpit!=rpend; ++rpit) { - if((*rpit)->can_handle_signature(s)) { - return *rpit; - } - } - return 0; - } - - relation_plugin & relation_manager::get_appropriate_plugin(const relation_signature & s) { - relation_plugin * res = try_get_appropriate_plugin(s); - if (!res) { - throw default_exception("no suitable plugin found for given relation signature"); - } - return *res; - } - - table_plugin * relation_manager::try_get_appropriate_plugin(const table_signature & t) { - if (m_favourite_table_plugin && m_favourite_table_plugin->can_handle_signature(t)) { - return m_favourite_table_plugin; - } - table_plugin_vector::iterator tpit = m_table_plugins.begin(); - table_plugin_vector::iterator tpend = m_table_plugins.end(); - for(; tpit!=tpend; ++tpit) { - if((*tpit)->can_handle_signature(t)) { - return *tpit; - } - } - return 0; - } - - table_plugin & relation_manager::get_appropriate_plugin(const table_signature & t) { - table_plugin * res = try_get_appropriate_plugin(t); - if(!res) { - throw default_exception("no suitable plugin found for given table signature"); - } - return *res; - } - - relation_plugin * relation_manager::get_relation_plugin(symbol const& s) { - relation_plugin_vector::iterator rpit = m_relation_plugins.begin(); - relation_plugin_vector::iterator rpend = m_relation_plugins.end(); - for(; rpit!=rpend; ++rpit) { - if((*rpit)->get_name()==s) { - return *rpit; - } - } - return 0; - } - - relation_plugin & relation_manager::get_relation_plugin(family_id kind) { - SASSERT(kind>=0); - SASSERT(kindget_name()==k) { - return *tpit; - } - } - return 0; - } - - table_relation_plugin & relation_manager::get_table_relation_plugin(table_plugin & tp) { - table_relation_plugin * res; - VERIFY( m_table_relation_plugins.find(&tp, res) ); - return *res; - } - - bool relation_manager::try_get_finite_product_relation_plugin(const relation_plugin & inner, - finite_product_relation_plugin * & res) { - return m_finite_product_relation_plugins.find(&inner, res); - } - - table_base * relation_manager::mk_empty_table(const table_signature & s) { - return get_appropriate_plugin(s).mk_empty(s); - } - - - bool relation_manager::is_non_explanation(relation_signature const& s) const { - dl_decl_util & decl_util = get_context().get_decl_util(); - unsigned n = s.size(); - for(unsigned i = 0; i < n; i++) { - if(decl_util.is_rule_sort(s[i])) { - return false; - } - } - return true; - } - - relation_base * relation_manager::mk_empty_relation(const relation_signature & s, func_decl* pred) { - return mk_empty_relation(s, get_requested_predicate_kind(pred)); - } - - relation_base * relation_manager::mk_empty_relation(const relation_signature & s, family_id kind) { - if (kind != null_family_id) { - relation_plugin & plugin = get_relation_plugin(kind); - if (plugin.can_handle_signature(s, kind)) - return plugin.mk_empty(s, kind); - } - relation_base * res; - relation_plugin* p = m_favourite_relation_plugin; - - if (p && p->can_handle_signature(s)) { - return p->mk_empty(s); - } - - if (mk_empty_table_relation(s, res)) { - return res; - } - - for (unsigned i = 0; i < m_relation_plugins.size(); ++i) { - p = m_relation_plugins[i]; - if (p->can_handle_signature(s)) { - return p->mk_empty(s); - } - } - - //If there is no plugin to handle the signature, we just create an empty product relation and - //stuff will be added to it by later operations. - return product_relation_plugin::get_plugin(*this).mk_empty(s); - } - - - relation_base * relation_manager::mk_table_relation(const relation_signature & s, table_base * table) { - SASSERT(s.size()==table->get_signature().size()); - return get_table_relation_plugin(table->get_plugin()).mk_from_table(s, table); - } - - bool relation_manager::mk_empty_table_relation(const relation_signature & s, relation_base * & result) { - table_signature tsig; - if(!relation_signature_to_table(s, tsig)) { - return false; - } - table_base * table = mk_empty_table(tsig); - result = mk_table_relation(s, table); - return true; - } - - - relation_base * relation_manager::mk_full_relation(const relation_signature & s, func_decl* p, family_id kind) { - if (kind != null_family_id) { - relation_plugin & plugin = get_relation_plugin(kind); - if (plugin.can_handle_signature(s, kind)) { - return plugin.mk_full(p, s, kind); - } - } - return get_appropriate_plugin(s).mk_full(p, s, null_family_id); - } - - relation_base * relation_manager::mk_full_relation(const relation_signature & s, func_decl* pred) { - family_id kind = get_requested_predicate_kind(pred); - return mk_full_relation(s, pred, kind); - } - - void relation_manager::relation_to_table(const relation_sort & sort, const relation_element & from, - table_element & to) { - SASSERT(from->get_num_args()==0); - VERIFY(get_context().get_decl_util().is_numeral_ext(from, to)); - } - - void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from, - relation_element & to) { - to = get_decl_util().mk_numeral(from, sort); - } - - void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from, - relation_element_ref & to) { - relation_element rel_el; - table_to_relation(sort, from, rel_el); - to = rel_el; - } - - void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from, - const relation_fact::el_proxy & to) { - relation_element rel_el; - table_to_relation(sort, from, rel_el); - to = rel_el; - } - - bool relation_manager::relation_sort_to_table(const relation_sort & from, table_sort & to) { - return get_context().get_decl_util().try_get_size(from, to); - } - - void relation_manager::from_predicate(func_decl * pred, unsigned arg_index, relation_sort & result) { - result = pred->get_domain(arg_index); - } - - void relation_manager::from_predicate(func_decl * pred, relation_signature & result) { - result.reset(); - unsigned arg_num=pred->get_arity(); - for(unsigned i=0;iset_cancel(f); - } - } - - std::string relation_manager::to_nice_string(const relation_element & el) const { - uint64 val; - std::stringstream stm; - if(get_context().get_decl_util().is_numeral_ext(el, val)) { - stm << val; - } - else { - stm << mk_pp(el, get_context().get_manager()); - } - return stm.str(); - } - - std::string relation_manager::to_nice_string(const relation_sort & s, const relation_element & el) const { - std::stringstream stm; - uint64 val; - if(get_context().get_decl_util().is_numeral_ext(el, val)) { - get_context().print_constant_name(s, val, stm); - } - else { - stm << mk_pp(el, get_context().get_manager()); - } - return stm.str(); - } - - std::string relation_manager::to_nice_string(const relation_sort & s) const { - return std::string(s->get_name().bare_str()); - } - - std::string relation_manager::to_nice_string(const relation_signature & s) const { - std::string res("["); - bool first = true; - relation_signature::const_iterator it = s.begin(); - relation_signature::const_iterator end = s.end(); - for(; it!=end; ++it) { - if(first) { - first = false; - } - else { - res+=','; - } - res+=to_nice_string(*it); - } - res+=']'; - - return res; - } - - void relation_manager::display(std::ostream & out) const { - relation_map::iterator it=m_relations.begin(); - relation_map::iterator end=m_relations.end(); - for(;it!=end;++it) { - out << "Table " << it->m_key->get_name() << "\n"; - it->m_value->display(out); - } - } - - void relation_manager::display_relation_sizes(std::ostream & out) const { - relation_map::iterator it=m_relations.begin(); - relation_map::iterator end=m_relations.end(); - for(;it!=end;++it) { - out << "Relation " << it->m_key->get_name() << " has size " - << it->m_value->get_size_estimate_rows() << "\n"; - } - } - - void relation_manager::display_output_tables(rule_set const& rules, std::ostream & out) const { - const decl_set & output_preds = rules.get_output_predicates(); - decl_set::iterator it=output_preds.begin(); - decl_set::iterator end=output_preds.end(); - for(; it!=end; ++it) { - func_decl * pred = *it; - relation_base * rel = try_get_relation(pred); - if(!rel) { - out << "Tuples in " << pred->get_name() << ": \n"; - continue; - } - rel->display_tuples(*pred, out); - } - } - - - // ----------------------------------- - // - // relation operations - // - // ----------------------------------- - - class relation_manager::empty_signature_relation_join_fn : public relation_join_fn { - public: - virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { - TRACE("dl", tout << r1.get_plugin().get_name() << " " << r2.get_plugin().get_name() << "\n";); - if(r1.get_signature().empty()) { - if(r1.empty()) { - return r2.get_manager().mk_empty_relation(r2.get_signature(), r2.get_kind()); - } - else { - return r2.clone(); - } - } - else { - SASSERT(r2.get_signature().empty()); - if(r2.empty()) { - return r1.get_manager().mk_empty_relation(r1.get_signature(), r1.get_kind()); - } - else { - return r1.clone(); - } - } - } - }; - - relation_join_fn * relation_manager::mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, bool allow_product_relation) { - relation_plugin * p1 = &t1.get_plugin(); - relation_plugin * p2 = &t2.get_plugin(); - - relation_join_fn * res = p1->mk_join_fn(t1, t2, col_cnt, cols1, cols2); - if(!res && p1!=p2) { - res = p2->mk_join_fn(t1, t2, col_cnt, cols1, cols2); - } - - if(!res && (t1.get_signature().empty() || t2.get_signature().empty())) { - res = alloc(empty_signature_relation_join_fn); - } - - finite_product_relation_plugin * fprp; - if(!res && p1->from_table() && try_get_finite_product_relation_plugin(*p2, fprp)) { - //we downcast here to relation_plugin so that we don't have to declare - //relation_manager as a friend class of finite_product_relation_plugin - res = static_cast(fprp)->mk_join_fn(t1, t2, col_cnt, cols1, cols2); - } - if(!res && p2->from_table() && try_get_finite_product_relation_plugin(*p1, fprp)) { - res = static_cast(fprp)->mk_join_fn(t1, t2, col_cnt, cols1, cols2); - } - - if(!res && allow_product_relation) { - relation_plugin & product_plugin = product_relation_plugin::get_plugin(*this); - res = product_plugin.mk_join_fn(t1, t2, col_cnt, cols1, cols2); - } - - return res; - } - - relation_transformer_fn * relation_manager::mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols) { - return t.get_plugin().mk_project_fn(t, col_cnt, removed_cols); - } - - class relation_manager::default_relation_filter_interpreted_and_project_fn : public relation_transformer_fn { - scoped_ptr m_filter; - scoped_ptr m_project; - unsigned_vector m_removed_cols; - public: - /** - This constructor should be used only if we know that the projection operation - exists for the result of the join. - */ - default_relation_filter_interpreted_and_project_fn( - relation_mutator_fn* filter, - unsigned removed_col_cnt, - const unsigned * removed_cols) - : m_filter(filter), - m_project(0), - m_removed_cols(removed_col_cnt, removed_cols) {} - - virtual relation_base * operator()(const relation_base & t) { - scoped_rel t1 = t.clone(); - (*m_filter)(*t1); - if( !m_project) { - relation_manager & rmgr = t1->get_plugin().get_manager(); - m_project = rmgr.mk_project_fn(*t1, m_removed_cols.size(), m_removed_cols.c_ptr()); - if (!m_project) { - throw default_exception("projection does not exist"); - } - } - return (*m_project)(*t1); - } - }; - - relation_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn( - const relation_base & t, app * condition, - unsigned removed_col_cnt, const unsigned * removed_cols) { - - relation_transformer_fn* res = - t.get_plugin().mk_filter_interpreted_and_project_fn( - t, - condition, - removed_col_cnt, - removed_cols); - - if (!res) { - relation_mutator_fn* filter_fn = mk_filter_interpreted_fn(t, condition); - if (filter_fn) { - res = alloc(default_relation_filter_interpreted_and_project_fn, - filter_fn, - removed_col_cnt, - removed_cols); - } - } - return res; - } - - - class relation_manager::default_relation_join_project_fn : public relation_join_fn { - scoped_ptr m_join; - scoped_ptr m_project; - - unsigned_vector m_removed_cols; - public: - /** - This constructor should be used only if we know that the projection operation - exists for the result of the join. - */ - default_relation_join_project_fn(join_fn * join, unsigned removed_col_cnt, - const unsigned * removed_cols) - : m_join(join), m_project(0), m_removed_cols(removed_col_cnt, removed_cols) {} - - virtual relation_base * operator()(const relation_base & t1, const relation_base & t2) { - scoped_rel aux = (*m_join)(t1, t2); - if(!m_project) { - relation_manager & rmgr = aux->get_plugin().get_manager(); - m_project = rmgr.mk_project_fn(*aux, m_removed_cols.size(), m_removed_cols.c_ptr()); - if(!m_project) { - throw default_exception("projection does not exist"); - } - } - relation_base * res = (*m_project)(*aux); - return res; - } - }; - - - relation_join_fn * relation_manager::mk_join_project_fn(const relation_base & t1, const relation_base & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols, bool allow_product_relation_join) { - relation_join_fn * res = t1.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, - removed_col_cnt, removed_cols); - if(!res && &t1.get_plugin()!=&t2.get_plugin()) { - res = t2.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt, - removed_cols); - } - if(!res) { - relation_join_fn * join = mk_join_fn(t1, t2, joined_col_cnt, cols1, cols2, allow_product_relation_join); - if(join) { - res = alloc(default_relation_join_project_fn, join, removed_col_cnt, removed_cols); - } - } - return res; - - } - - relation_transformer_fn * relation_manager::mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle) { - return t.get_plugin().mk_rename_fn(t, permutation_cycle_len, permutation_cycle); - } - - relation_transformer_fn * relation_manager::mk_permutation_rename_fn(const relation_base & t, - const unsigned * permutation) { - relation_transformer_fn * res = t.get_plugin().mk_permutation_rename_fn(t, permutation); - if(!res) { - res = alloc(default_relation_permutation_rename_fn, t, permutation); - } - return res; - } - - - relation_union_fn * relation_manager::mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - relation_union_fn * res = tgt.get_plugin().mk_union_fn(tgt, src, delta); - if(!res && &tgt.get_plugin()!=&src.get_plugin()) { - res = src.get_plugin().mk_union_fn(tgt, src, delta); - } - if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { - res = delta->get_plugin().mk_union_fn(tgt, src, delta); - } - return res; - } - - relation_union_fn * relation_manager::mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - relation_union_fn * res = tgt.get_plugin().mk_widen_fn(tgt, src, delta); - if(!res && &tgt.get_plugin()!=&src.get_plugin()) { - res = src.get_plugin().mk_widen_fn(tgt, src, delta); - } - if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { - res = delta->get_plugin().mk_widen_fn(tgt, src, delta); - } - if(!res) { - res = mk_union_fn(tgt, src, delta); - } - return res; - } - - relation_mutator_fn * relation_manager::mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols) { - return t.get_plugin().mk_filter_identical_fn(t, col_cnt, identical_cols); - } - - relation_mutator_fn * relation_manager::mk_filter_equal_fn(const relation_base & t, - const relation_element & value, unsigned col) { - - return t.get_plugin().mk_filter_equal_fn(t, value, col); - } - - relation_mutator_fn * relation_manager::mk_filter_interpreted_fn(const relation_base & t, app * condition) { - return t.get_plugin().mk_filter_interpreted_fn(t, condition); - } - - class relation_manager::default_relation_select_equal_and_project_fn : public relation_transformer_fn { - scoped_ptr m_filter; - scoped_ptr m_project; - public: - default_relation_select_equal_and_project_fn(relation_mutator_fn * filter, relation_transformer_fn * project) - : m_filter(filter), m_project(project) {} - - virtual relation_base * operator()(const relation_base & t1) { - TRACE("dl", tout << t1.get_plugin().get_name() << "\n";); - scoped_rel aux = t1.clone(); - (*m_filter)(*aux); - relation_base * res = (*m_project)(*aux); - return res; - } - }; - - relation_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const relation_base & t, - const relation_element & value, unsigned col) { - relation_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col); - if(!res) { - relation_mutator_fn * selector = mk_filter_equal_fn(t, value, col); - if(selector) { - relation_transformer_fn * projector = mk_project_fn(t, 1, &col); - if(projector) { - res = alloc(default_relation_select_equal_and_project_fn, selector, projector); - } - else { - dealloc(selector); - } - } - } - return res; - } - - - class relation_manager::default_relation_intersection_filter_fn : public relation_intersection_filter_fn { - scoped_ptr m_join_fun; - scoped_ptr m_union_fun; - public: - - default_relation_intersection_filter_fn(relation_join_fn * join_fun, relation_union_fn * union_fun) - : m_join_fun(join_fun), m_union_fun(union_fun) {} - - virtual void operator()(relation_base & tgt, const relation_base & intersected_obj) { - scoped_rel filtered_rel = (*m_join_fun)(tgt, intersected_obj); - TRACE("dl", - tgt.display(tout << "tgt:\n"); - intersected_obj.display(tout << "intersected:\n"); - filtered_rel->display(tout << "filtered:\n"); - ); - if(!m_union_fun) { - SASSERT(tgt.can_swap(*filtered_rel)); - tgt.swap(*filtered_rel); - } - tgt.reset(); - TRACE("dl", tgt.display(tout << "target reset:\n"); ); - (*m_union_fun)(tgt, *filtered_rel); - TRACE("dl", tgt.display(tout << "intersected target:\n"); ); - } - - }; - - relation_intersection_filter_fn * relation_manager::try_mk_default_filter_by_intersection_fn( - const relation_base & tgt, const relation_base & src, unsigned joined_col_cnt, - const unsigned * tgt_cols, const unsigned * src_cols) { - TRACE("dl_verbose", tout << tgt.get_plugin().get_name() << "\n";); - unsigned_vector join_removed_cols; - add_sequence(tgt.get_signature().size(), src.get_signature().size(), join_removed_cols); - scoped_rel join_fun = mk_join_project_fn(tgt, src, joined_col_cnt, tgt_cols, src_cols, - join_removed_cols.size(), join_removed_cols.c_ptr(), false); - if(!join_fun) { - return 0; - } - //we perform the join operation here to see what the result is - scoped_rel join_res = (*join_fun)(tgt, src); - if(tgt.can_swap(*join_res)) { - return alloc(default_relation_intersection_filter_fn, join_fun.release(), 0); - } - if(join_res->get_plugin().is_product_relation()) { - //we cannot have the product relation here, since it uses the intersection operation - //for unions and therefore we would get into an infinite recursion - return 0; - } - scoped_rel union_fun = mk_union_fn(tgt, *join_res); - if(!union_fun) { - return 0; - } - return alloc(default_relation_intersection_filter_fn, join_fun.release(), union_fun.release()); - } - - - relation_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const relation_base & t, - const relation_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) { - TRACE("dl_verbose", tout << t.get_plugin().get_name() << "\n";); - relation_intersection_filter_fn * res = t.get_plugin().mk_filter_by_intersection_fn(t, src, joined_col_cnt, - t_cols, src_cols); - if(!res && &t.get_plugin()!=&src.get_plugin()) { - res = src.get_plugin().mk_filter_by_intersection_fn(t, src, joined_col_cnt, t_cols, src_cols); - } - if(!res) { - res = try_mk_default_filter_by_intersection_fn(t, src, joined_col_cnt, t_cols, src_cols); - } - return res; - } - - relation_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const relation_base & tgt, - const relation_base & src) { - TRACE("dl_verbose", tout << tgt.get_plugin().get_name() << "\n";); - SASSERT(tgt.get_signature()==src.get_signature()); - unsigned sz = tgt.get_signature().size(); - unsigned_vector cols; - add_sequence(0, sz, cols); - return mk_filter_by_intersection_fn(tgt, src, cols, cols); - } - - - relation_intersection_filter_fn * relation_manager::mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols) { - TRACE("dl", tout << t.get_plugin().get_name() << "\n";); - relation_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, - t_cols, negated_cols); - if(!res && &t.get_plugin()!=&negated_obj.get_plugin()) { - res = negated_obj.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, t_cols, - negated_cols); - } - return res; - } - - - - - - // ----------------------------------- - // - // table operations - // - // ----------------------------------- - - class relation_manager::default_table_join_fn : public convenient_table_join_fn { - unsigned m_col_cnt; - public: - default_table_join_fn(const table_signature & t1_sig, const table_signature & t2_sig, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2) - : convenient_table_join_fn(t1_sig, t2_sig, col_cnt, cols1, cols2), m_col_cnt(col_cnt) {} - - virtual table_base * operator()(const table_base & t1, const table_base & t2) { - table_plugin * plugin = &t1.get_plugin(); - - const table_signature & res_sign = get_result_signature(); - if (!plugin->can_handle_signature(res_sign)) { - plugin = &t2.get_plugin(); - if (!plugin->can_handle_signature(res_sign)) { - plugin = &t1.get_manager().get_appropriate_plugin(res_sign); - } - } - SASSERT(plugin->can_handle_signature(res_sign)); - table_base * res = plugin->mk_empty(res_sign); - - unsigned t1cols = t1.get_signature().size(); - unsigned t2cols = t2.get_signature().size(); - unsigned t1first_func = t1.get_signature().first_functional(); - unsigned t2first_func = t2.get_signature().first_functional(); - - table_base::iterator els1it = t1.begin(); - table_base::iterator els1end = t1.end(); - table_base::iterator els2end = t2.end(); - - table_fact acc; - - for(; els1it!=els1end; ++els1it) { - const table_base::row_interface & row1 = *els1it; - - table_base::iterator els2it = t2.begin(); - for(; els2it!=els2end; ++els2it) { - const table_base::row_interface & row2 = *els2it; - - bool match=true; - for(unsigned i=0; iadd_fact(acc); - } - } - return res; - } - }; - - table_join_fn * relation_manager::mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - table_join_fn * res = t1.get_plugin().mk_join_fn(t1, t2, col_cnt, cols1, cols2); - if(!res && &t1.get_plugin()!=&t2.get_plugin()) { - res = t2.get_plugin().mk_join_fn(t1, t2, col_cnt, cols1, cols2); - } - if(!res) { - table_signature sig; - table_signature::from_join(t1.get_signature(), t2.get_signature(), - col_cnt, cols1, cols2, sig); - res = alloc(default_table_join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); - } - return res; - } - - - class relation_manager::auxiliary_table_transformer_fn { - table_fact m_row; - public: - virtual ~auxiliary_table_transformer_fn() {} - virtual const table_signature & get_result_signature() const = 0; - virtual void modify_fact(table_fact & f) const = 0; - - table_base * operator()(const table_base & t) { - table_plugin & plugin = t.get_plugin(); - const table_signature & res_sign = get_result_signature(); - SASSERT(plugin.can_handle_signature(res_sign)); - table_base * res = plugin.mk_empty(res_sign); - - table_base::iterator it = t.begin(); - table_base::iterator end = t.end(); - - for(; it!=end; ++it) { - it->get_fact(m_row); - modify_fact(m_row); - res->add_fact(m_row); - } - return res; - } - }; - - class relation_manager::default_table_project_fn - : public convenient_table_project_fn, auxiliary_table_transformer_fn { - public: - default_table_project_fn(const table_signature & orig_sig, unsigned removed_col_cnt, - const unsigned * removed_cols) - : convenient_table_project_fn(orig_sig, removed_col_cnt, removed_cols) { - SASSERT(removed_col_cnt>0); - } - - virtual const table_signature & get_result_signature() const { - return convenient_table_project_fn::get_result_signature(); - } - - virtual void modify_fact(table_fact & f) const { - project_out_vector_columns(f, m_removed_cols); - } - - virtual table_base * operator()(const table_base & t) { - return auxiliary_table_transformer_fn::operator()(t); - } - }; - - class relation_manager::null_signature_table_project_fn : public table_transformer_fn { - const table_signature m_empty_sig; - public: - null_signature_table_project_fn() : m_empty_sig() {} - virtual table_base * operator()(const table_base & t) { - relation_manager & m = t.get_plugin().get_manager(); - table_base * res = m.mk_empty_table(m_empty_sig); - if(!t.empty()) { - table_fact el; - res->add_fact(el); - } - return res; - } - }; - - - - table_transformer_fn * relation_manager::mk_project_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols) { - table_transformer_fn * res = t.get_plugin().mk_project_fn(t, col_cnt, removed_cols); - if(!res && col_cnt==t.get_signature().size()) { - //all columns are projected out - res = alloc(null_signature_table_project_fn); - } - if(!res) { - res = alloc(default_table_project_fn, t.get_signature(), col_cnt, removed_cols); - } - return res; - } - - - class relation_manager::default_table_join_project_fn : public convenient_table_join_project_fn { - scoped_ptr m_join; - scoped_ptr m_project; - - unsigned_vector m_removed_cols; - public: - default_table_join_project_fn(join_fn * join, const table_base & t1, const table_base & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols) - : convenient_table_join_project_fn(t1.get_signature(), t2.get_signature(), joined_col_cnt, cols1, - cols2, removed_col_cnt, removed_cols), - m_join(join), - m_removed_cols(removed_col_cnt, removed_cols) {} - - class unreachable_reducer : public table_row_pair_reduce_fn { - virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) { - //we do project_with_reduce only if we are sure there will be no reductions - //(see code of the table_signature::from_join_project function) - UNREACHABLE(); - } - }; - - virtual table_base * operator()(const table_base & t1, const table_base & t2) { - table_base * aux = (*m_join)(t1, t2); - if(m_project==0) { - relation_manager & rmgr = aux->get_plugin().get_manager(); - if(get_result_signature().functional_columns()!=0) { - //to preserve functional columns we need to do the project_with_reduction - unreachable_reducer * reducer = alloc(unreachable_reducer); - m_project = rmgr.mk_project_with_reduce_fn(*aux, m_removed_cols.size(), m_removed_cols.c_ptr(), reducer); - } - else { - m_project = rmgr.mk_project_fn(*aux, m_removed_cols); - } - if(!m_project) { - throw default_exception("projection for table does not exist"); - } - } - table_base * res = (*m_project)(*aux); - aux->deallocate(); - return res; - } - }; - - table_join_fn * relation_manager::mk_join_project_fn(const table_base & t1, const table_base & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols) { - table_join_fn * res = t1.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, - removed_col_cnt, removed_cols); - if(!res && &t1.get_plugin()!=&t2.get_plugin()) { - res = t2.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt, - removed_cols); - } - if(!res) { - table_join_fn * join = mk_join_fn(t1, t2, joined_col_cnt, cols1, cols2); - if(join) { - res = alloc(default_table_join_project_fn, join, t1, t2, joined_col_cnt, cols1, cols2, - removed_col_cnt, removed_cols); - } - } - return res; - - } - - class relation_manager::default_table_rename_fn - : public convenient_table_rename_fn, auxiliary_table_transformer_fn { - public: - default_table_rename_fn(const table_signature & orig_sig, unsigned permutation_cycle_len, - const unsigned * permutation_cycle) - : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle) { - SASSERT(permutation_cycle_len>=2); - } - - virtual const table_signature & get_result_signature() const { - return convenient_table_rename_fn::get_result_signature(); - } - - virtual void modify_fact(table_fact & f) const { - permutate_by_cycle(f, m_cycle); - } - - virtual table_base * operator()(const table_base & t) { - return auxiliary_table_transformer_fn::operator()(t); - } - - }; - - table_transformer_fn * relation_manager::mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle) { - table_transformer_fn * res = t.get_plugin().mk_rename_fn(t, permutation_cycle_len, permutation_cycle); - if(!res) { - res = alloc(default_table_rename_fn, t.get_signature(), permutation_cycle_len, permutation_cycle); - } - return res; - } - - table_transformer_fn * relation_manager::mk_permutation_rename_fn(const table_base & t, - const unsigned * permutation) { - table_transformer_fn * res = t.get_plugin().mk_permutation_rename_fn(t, permutation); - if(!res) { - res = alloc(default_table_permutation_rename_fn, t, permutation); - } - return res; - } - - - class relation_manager::default_table_union_fn : public table_union_fn { - table_fact m_row; - public: - virtual void operator()(table_base & tgt, const table_base & src, table_base * delta) { - table_base::iterator it = src.begin(); - table_base::iterator iend = src.end(); - - for(; it!=iend; ++it) { - it->get_fact(m_row); - - if(delta) { - if(!tgt.contains_fact(m_row)) { - tgt.add_new_fact(m_row); - delta->add_fact(m_row); - } - } - else { - //if there's no delta, we don't need to know whether we are actually adding a new fact - tgt.add_fact(m_row); - } - } - } - }; - - table_union_fn * relation_manager::mk_union_fn(const table_base & tgt, const table_base & src, - const table_base * delta) { - table_union_fn * res = tgt.get_plugin().mk_union_fn(tgt, src, delta); - if(!res && &tgt.get_plugin()!=&src.get_plugin()) { - res = src.get_plugin().mk_union_fn(tgt, src, delta); - } - if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { - res = delta->get_plugin().mk_union_fn(tgt, src, delta); - } - if(!res) { - res = alloc(default_table_union_fn); - } - return res; - } - - table_union_fn * relation_manager::mk_widen_fn(const table_base & tgt, const table_base & src, - const table_base * delta) { - table_union_fn * res = tgt.get_plugin().mk_widen_fn(tgt, src, delta); - if(!res && &tgt.get_plugin()!=&src.get_plugin()) { - res = src.get_plugin().mk_widen_fn(tgt, src, delta); - } - if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { - res = delta->get_plugin().mk_widen_fn(tgt, src, delta); - } - if(!res) { - res = mk_union_fn(tgt, src, delta); - } - return res; - } - - - /** - An auixiliary class for functors that perform filtering. It performs the table traversal - and only asks for each individual row whether it should be removed. - - When using this class in multiple inheritance, this class should not be inherited publicly - and should be mentioned as last. This should ensure that deteletion of the object will - go well when initiated from a pointer to the first ancestor. - */ - class relation_manager::auxiliary_table_filter_fn { - table_fact m_row; - svector m_to_remove; - public: - virtual ~auxiliary_table_filter_fn() {} - virtual bool should_remove(const table_fact & f) const = 0; - - void operator()(table_base & r) { - m_to_remove.reset(); - unsigned sz = 0; - table_base::iterator it = r.begin(); - table_base::iterator iend = r.end(); - for(; it!=iend; ++it) { - it->get_fact(m_row); - if(should_remove(m_row)) { - m_to_remove.append(m_row.size(), m_row.c_ptr()); - ++sz; - } - } - r.remove_facts(sz, m_to_remove.c_ptr()); - } - }; - - class relation_manager::default_table_filter_identical_fn : public table_mutator_fn, auxiliary_table_filter_fn { - const unsigned m_col_cnt; - const unsigned_vector m_identical_cols; - public: - default_table_filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) - : m_col_cnt(col_cnt), - m_identical_cols(col_cnt, identical_cols) { - SASSERT(col_cnt>=2); - } - - virtual bool should_remove(const table_fact & f) const { - table_element val=f[m_identical_cols[0]]; - for(unsigned i=1; iget_arg(0); - if (!m.is_eq(condition)) { - return 0; - } - expr* x = to_app(condition)->get_arg(0); - expr* y = to_app(condition)->get_arg(1); - if (!is_var(x)) { - std::swap(x, y); - } - if (!is_var(x)) { - return 0; - } - dl_decl_util decl_util(m); - uint64 value = 0; - if (!decl_util.is_numeral_ext(y, value)) { - return 0; - } - return alloc(default_table_filter_not_equal_fn, ctx, to_var(x)->get_idx(), value); - } - }; - - - - class relation_manager::default_table_filter_interpreted_fn - : public table_mutator_fn, auxiliary_table_filter_fn { - ast_manager & m_ast_manager; - var_subst & m_vs; - dl_decl_util & m_decl_util; - th_rewriter & m_simp; - app_ref m_condition; - ptr_vector m_var_sorts; - expr_ref_vector m_args; - public: - default_table_filter_interpreted_fn(context & ctx, unsigned col_cnt, app* condition) - : m_ast_manager(ctx.get_manager()), - m_vs(ctx.get_var_subst()), - m_decl_util(ctx.get_decl_util()), - m_simp(ctx.get_rewriter()), - m_condition(condition, ctx.get_manager()), - m_args(ctx.get_manager()) { - m_var_sorts.resize(col_cnt); - get_free_vars(m_condition, m_var_sorts); - } - - virtual bool should_remove(const table_fact & f) const { - expr_ref_vector& args = const_cast(m_args); - - args.reset(); - //arguments need to be in reverse order for the substitution - unsigned col_cnt = f.size(); - for(int i=col_cnt-1;i>=0;i--) { - sort * var_sort = m_var_sorts[i]; - if(!var_sort) { - args.push_back(0); - continue; //this variable does not occur in the condition; - } - - table_element el = f[i]; - args.push_back(m_decl_util.mk_numeral(el, var_sort)); - } - - expr_ref ground(m_ast_manager); - m_vs(m_condition.get(), args.size(), args.c_ptr(), ground); - m_simp(ground); - - return m_ast_manager.is_false(ground); - } - - virtual void operator()(table_base & t) { - auxiliary_table_filter_fn::operator()(t); - } - }; - - table_mutator_fn * relation_manager::mk_filter_interpreted_fn(const table_base & t, app * condition) { - context & ctx = get_context(); - table_mutator_fn * res = t.get_plugin().mk_filter_interpreted_fn(t, condition); - if (!res) { - res = default_table_filter_not_equal_fn::mk(ctx, condition); - } - if(!res) { - res = alloc(default_table_filter_interpreted_fn, ctx, t.get_signature().size(), condition); - } - return res; - } - - - class relation_manager::default_table_filter_interpreted_and_project_fn - : public table_transformer_fn { - scoped_ptr m_filter; - scoped_ptr m_project; - app_ref m_condition; - unsigned_vector m_removed_cols; - public: - default_table_filter_interpreted_and_project_fn(context & ctx, table_mutator_fn * filter, - app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) - : m_filter(filter), m_condition(condition, ctx.get_manager()), - m_removed_cols(removed_col_cnt, removed_cols) {} - - virtual table_base* operator()(const table_base & tb) { - table_base *t2 = tb.clone(); - (*m_filter)(*t2); - if (!m_project) { - relation_manager & rmgr = t2->get_plugin().get_manager(); - m_project = rmgr.mk_project_fn(*t2, m_removed_cols.size(), m_removed_cols.c_ptr()); - if (!m_project) { - throw default_exception("projection does not exist"); - } - } - return (*m_project)(*t2); - } - }; - - table_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn(const table_base & t, - app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { - table_transformer_fn * res = t.get_plugin().mk_filter_interpreted_and_project_fn(t, condition, removed_col_cnt, removed_cols); - if (res) - return res; - - table_mutator_fn * filter = mk_filter_interpreted_fn(t, condition); - SASSERT(filter); - res = alloc(default_table_filter_interpreted_and_project_fn, get_context(), filter, condition, removed_col_cnt, removed_cols); - return res; - } - - - table_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const table_base & t, - const table_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) { - table_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, src, joined_col_cnt, - t_cols, src_cols); - if(!res && &t.get_plugin()!=&src.get_plugin()) { - res = src.get_plugin().mk_filter_by_negation_fn(t, src, joined_col_cnt, t_cols, src_cols); - } - return res; - } - - - - class relation_manager::default_table_negation_filter_fn : public convenient_table_negation_filter_fn, - auxiliary_table_filter_fn { - const table_base * m_negated_table; - mutable table_fact m_aux_fact; - public: - default_table_negation_filter_fn(const table_base & tgt, const table_base & neg_t, - unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) - : convenient_table_negation_filter_fn(tgt, neg_t, joined_col_cnt, t_cols, negated_cols), - m_negated_table(0) { - m_aux_fact.resize(neg_t.get_signature().size()); - } - - virtual bool should_remove(const table_fact & f) const { - if(!m_all_neg_bound || m_overlap) { - table_base::iterator nit = m_negated_table->begin(); - table_base::iterator nend = m_negated_table->end(); - for(; nit!=nend; ++nit) { - const table_base::row_interface & nrow = *nit; - if(bindings_match(nrow, f)) { - return true; - } - } - return false; - } - else { - make_neg_bindings(m_aux_fact, f); - return m_negated_table->contains_fact(m_aux_fact); - } - } - - virtual void operator()(table_base & tgt, const table_base & negated_table) { - SASSERT(m_negated_table==0); - flet flet_neg_table(m_negated_table, &negated_table); - auxiliary_table_filter_fn::operator()(tgt); - } - - }; - - table_intersection_filter_fn * relation_manager::mk_filter_by_negation_fn(const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols) { - table_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, - t_cols, negated_cols); - if(!res && &t.get_plugin()!=&negated_obj.get_plugin()) { - res = negated_obj.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, t_cols, - negated_cols); - } - if(!res) { - res = alloc(default_table_negation_filter_fn, t, negated_obj, joined_col_cnt, t_cols, negated_cols); - } - return res; - } - - - class relation_manager::default_table_select_equal_and_project_fn : public table_transformer_fn { - scoped_ptr m_filter; - scoped_ptr m_project; - public: - default_table_select_equal_and_project_fn(table_mutator_fn * filter, table_transformer_fn * project) - : m_filter(filter), m_project(project) {} - - virtual table_base * operator()(const table_base & t1) { - TRACE("dl", tout << t1.get_plugin().get_name() << "\n";); - scoped_rel aux = t1.clone(); - (*m_filter)(*aux); - table_base * res = (*m_project)(*aux); - return res; - } - }; - - table_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const table_base & t, - const table_element & value, unsigned col) { - table_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col); - if(!res) { - table_mutator_fn * selector = mk_filter_equal_fn(t, value, col); - SASSERT(selector); - table_transformer_fn * projector = mk_project_fn(t, 1, &col); - SASSERT(projector); - res = alloc(default_table_select_equal_and_project_fn, selector, projector); - } - return res; - } - - - class relation_manager::default_table_map_fn : public table_mutator_fn { - scoped_ptr m_mapper; - unsigned m_first_functional; - scoped_rel m_aux_table; - scoped_ptr m_union_fn; - table_fact m_curr_fact; - public: - default_table_map_fn(const table_base & t, table_row_mutator_fn * mapper) - : m_mapper(mapper), m_first_functional(t.get_signature().first_functional()) { - SASSERT(t.get_signature().functional_columns()>0); - table_plugin & plugin = t.get_plugin(); - m_aux_table = plugin.mk_empty(t.get_signature()); - m_union_fn = plugin.mk_union_fn(t, *m_aux_table, static_cast(0)); - } - - virtual void operator()(table_base & t) { - SASSERT(t.get_signature()==m_aux_table->get_signature()); - if(!m_aux_table->empty()) { - m_aux_table->reset(); - } - - - table_base::iterator it = t.begin(); - table_base::iterator iend = t.end(); - for(; it!=iend; ++it) { - it->get_fact(m_curr_fact); - if((*m_mapper)(m_curr_fact.c_ptr()+m_first_functional)) { - m_aux_table->add_fact(m_curr_fact); - } - } - - t.reset(); - (*m_union_fn)(t, *m_aux_table, static_cast(0)); - } - }; - - table_mutator_fn * relation_manager::mk_map_fn(const table_base & t, table_row_mutator_fn * mapper) { - SASSERT(t.get_signature().functional_columns()>0); - table_mutator_fn * res = t.get_plugin().mk_map_fn(t, mapper); - if(!res) { - res = alloc(default_table_map_fn, t, mapper); - } - return res; - } - - - class relation_manager::default_table_project_with_reduce_fn : public convenient_table_transformer_fn { - unsigned_vector m_removed_cols; - const unsigned m_inp_col_cnt; - const unsigned m_removed_col_cnt; - const unsigned m_result_col_cnt; - scoped_ptr m_reducer; - unsigned m_res_first_functional; - table_fact m_row; - table_fact m_former_row; - public: - default_table_project_with_reduce_fn(const table_signature & orig_sig, unsigned removed_col_cnt, - const unsigned * removed_cols, table_row_pair_reduce_fn * reducer) - : m_removed_cols(removed_col_cnt, removed_cols), - m_inp_col_cnt(orig_sig.size()), - m_removed_col_cnt(removed_col_cnt), - m_result_col_cnt(orig_sig.size()-removed_col_cnt), - m_reducer(reducer) { - SASSERT(removed_col_cnt>0); - table_signature::from_project_with_reduce(orig_sig, removed_col_cnt, removed_cols, - get_result_signature()); - m_res_first_functional = get_result_signature().first_functional(); - m_row.resize(get_result_signature().size()); - m_former_row.resize(get_result_signature().size()); - } - - virtual void modify_fact(table_fact & f) const { - unsigned ofs=1; - unsigned r_i=1; - for(unsigned i=m_removed_cols[0]+1; isuggest_fact(m_former_row)) { - (*m_reducer)(m_former_row.c_ptr()+m_res_first_functional, m_row.c_ptr()+m_res_first_functional); - res->ensure_fact(m_former_row); - } - } - return res; - } - }; - - table_transformer_fn * relation_manager::mk_project_with_reduce_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols, table_row_pair_reduce_fn * reducer) { - SASSERT(t.get_signature().functional_columns()>0); - table_transformer_fn * res = t.get_plugin().mk_project_with_reduce_fn(t, col_cnt, removed_cols, reducer); - if(!res) { - res = alloc(default_table_project_with_reduce_fn, t.get_signature(), col_cnt, removed_cols, reducer); - } - return res; - } - -}; - diff --git a/src/muz/dl_relation_manager.h b/src/muz/dl_relation_manager.h deleted file mode 100644 index 9f12b4bb6..000000000 --- a/src/muz/dl_relation_manager.h +++ /dev/null @@ -1,688 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_relation_manager.h - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-24. - -Revision History: - ---*/ -#ifndef _DL_RELATION_MANAGER_H_ -#define _DL_RELATION_MANAGER_H_ - - -#include"map.h" -#include"vector.h" -#include"dl_base.h" - -namespace datalog { - - class context; - class dl_decl_util; - class table_relation; - class table_relation_plugin; - class finite_product_relation; - class finite_product_relation_plugin; - class sieve_relation; - class sieve_relation_plugin; - class rule_set; - - - class relation_manager { - class empty_signature_relation_join_fn; - class default_relation_join_project_fn; - class default_relation_select_equal_and_project_fn; - class default_relation_intersection_filter_fn; - class default_relation_filter_interpreted_and_project_fn; - - class auxiliary_table_transformer_fn; - class auxiliary_table_filter_fn; - - class default_table_join_fn; - class default_table_project_fn; - class null_signature_table_project_fn; - class default_table_join_project_fn; - class default_table_rename_fn; - class default_table_union_fn; - class default_table_filter_equal_fn; - class default_table_filter_identical_fn; - class default_table_filter_interpreted_fn; - class default_table_filter_interpreted_and_project_fn; - class default_table_negation_filter_fn; - class default_table_filter_not_equal_fn; - class default_table_select_equal_and_project_fn; - class default_table_map_fn; - class default_table_project_with_reduce_fn; - - typedef obj_map decl2kind_map; - - typedef u_map kind2plugin_map; - - typedef map, - ptr_eq > tp2trp_map; - typedef map, - ptr_eq > rp2fprp_map; - - typedef map, ptr_eq > relation_map; - typedef ptr_vector table_plugin_vector; - typedef ptr_vector relation_plugin_vector; - - context & m_context; - table_plugin_vector m_table_plugins; - relation_plugin_vector m_relation_plugins; - //table_relation_plugins corresponding to table_plugins - tp2trp_map m_table_relation_plugins; - rp2fprp_map m_finite_product_relation_plugins; - - kind2plugin_map m_kind2plugin; - - table_plugin * m_favourite_table_plugin; - - relation_plugin * m_favourite_relation_plugin; - - relation_map m_relations; - - decl_set m_saturated_rels; - - family_id m_next_table_fid; - family_id m_next_relation_fid; - - /** - Map specifying what kind of relation should be used to represent particular predicate. - */ - decl2kind_map m_pred_kinds; - - void register_relation_plugin_impl(relation_plugin * plugin); - - relation_manager(const relation_manager &); //private and undefined copy constructor - relation_manager & operator=(const relation_manager &); //private and undefined operator= - public: - relation_manager(context & ctx) : - m_context(ctx), - m_favourite_table_plugin(0), - m_favourite_relation_plugin(0), - m_next_table_fid(0), - m_next_relation_fid(0) {} - - virtual ~relation_manager(); - - void reset(); - void reset_relations(); - - context & get_context() const { return m_context; } - dl_decl_util & get_decl_util() const; - - family_id get_next_table_fid() { return m_next_table_fid++; } - family_id get_next_relation_fid(relation_plugin & claimer); - - - /** - Set what kind of relation is going to be used to represent the predicate \c pred. - - This function can be called only before the relation object for \c pred is created - (i.e. before the \c get_relation function is called with \c pred as argument for the - first time). - */ - void set_predicate_kind(func_decl * pred, family_id kind); - /** - Return the relation kind that was requested to represent the predicate \c pred by - \c set_predicate_kind. If there was no such request, return \c null_family_id. - */ - family_id get_requested_predicate_kind(func_decl * pred); - relation_base & get_relation(func_decl * pred); - relation_base * try_get_relation(func_decl * pred) const; - /** - \brief Store the relation \c rel under the predicate \c pred. The \c relation_manager - takes over the relation object. - */ - void store_relation(func_decl * pred, relation_base * rel); - - bool is_saturated(func_decl * pred) const { return m_saturated_rels.contains(pred); } - void mark_saturated(func_decl * pred) { m_saturated_rels.insert(pred); } - void reset_saturated_marks() { - if(!m_saturated_rels.empty()) { - m_saturated_rels.reset(); - } - } - - void collect_non_empty_predicates(decl_set & res) const; - void restrict_predicates(const decl_set & preds); - - void register_plugin(table_plugin * plugin); - /** - table_relation_plugins should not be passed to this function since they are - created automatically when registering a table plugin. - */ - void register_plugin(relation_plugin * plugin) { - SASSERT(!plugin->from_table()); - register_relation_plugin_impl(plugin); - } - - table_plugin & get_appropriate_plugin(const table_signature & t); - relation_plugin & get_appropriate_plugin(const relation_signature & t); - table_plugin * try_get_appropriate_plugin(const table_signature & t); - relation_plugin * try_get_appropriate_plugin(const relation_signature & t); - - table_plugin * get_table_plugin(symbol const& s); - relation_plugin * get_relation_plugin(symbol const& s); - relation_plugin & get_relation_plugin(family_id kind); - table_relation_plugin & get_table_relation_plugin(table_plugin & tp); - bool try_get_finite_product_relation_plugin(const relation_plugin & inner, - finite_product_relation_plugin * & res); - - table_base * mk_empty_table(const table_signature & s); - relation_base * mk_implicit_relation(const relation_signature & s, app * expr); - - relation_base * mk_empty_relation(const relation_signature & s, family_id kind); - relation_base * mk_empty_relation(const relation_signature & s, func_decl* pred); - - relation_base * mk_full_relation(const relation_signature & s, func_decl* pred, family_id kind); - relation_base * mk_full_relation(const relation_signature & s, func_decl* pred); - - relation_base * mk_table_relation(const relation_signature & s, table_base * table); - bool mk_empty_table_relation(const relation_signature & s, relation_base * & result); - - bool is_non_explanation(relation_signature const& s) const; - - - /** - \brief Convert relation value to table one. - - This function can be called only for the relation sorts that have a table counterpart. - */ - void relation_to_table(const relation_sort & sort, const relation_element & from, table_element & to); - - void table_to_relation(const relation_sort & sort, const table_element & from, relation_element & to); - void table_to_relation(const relation_sort & sort, const table_element & from, - const relation_fact::el_proxy & to); - void table_to_relation(const relation_sort & sort, const table_element & from, - relation_element_ref & to); - - bool relation_sort_to_table(const relation_sort & from, table_sort & to); - void from_predicate(func_decl * pred, unsigned arg_index, relation_sort & result); - void from_predicate(func_decl * pred, relation_signature & result); - - /** - \brief Convert relation signature to table signature and return true if successful. If false - is returned, the value of \c to is undefined. - */ - bool relation_signature_to_table(const relation_signature & from, table_signature & to); - - void relation_fact_to_table(const relation_signature & s, const relation_fact & from, - table_fact & to); - void table_fact_to_relation(const relation_signature & s, const table_fact & from, - relation_fact & to); - - - void set_cancel(bool f); - - - // ----------------------------------- - // - // relation operations - // - // ----------------------------------- - - //TODO: If multiple operation implementations are available, we may want to do something to - //select the best one here. - - /** - If \c allow_product_relation is true, we will create a join that builds a product relation, - if there is no other way to do the join. If \c allow_product_relation is false, we will return - zero in that case. - */ - relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, bool allow_product_relation=true); - - relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - const unsigned_vector & cols1, const unsigned_vector & cols2, bool allow_product_relation=true) { - SASSERT(cols1.size()==cols2.size()); - return mk_join_fn(t1, t2, cols1.size(), cols1.c_ptr(), cols2.c_ptr(), allow_product_relation); - } - - /** - \brief Return functor that transforms a table into one that lacks columns listed in - \c removed_cols array. - - The \c removed_cols cotains columns of table \c t in strictly ascending order. - */ - relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - - relation_transformer_fn * mk_project_fn(const relation_base & t, const unsigned_vector & removed_cols) { - return mk_project_fn(t, removed_cols.size(), removed_cols.c_ptr()); - } - - /** - \brief Return an operation that is a composition of a join an a project operation. - */ - relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols, bool allow_product_relation_join=true); - - relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, - const unsigned_vector & cols1, const unsigned_vector & cols2, - const unsigned_vector & removed_cols, bool allow_product_relation_join=true) { - return mk_join_project_fn(t1, t2, cols1.size(), cols1.c_ptr(), cols2.c_ptr(), removed_cols.size(), - removed_cols.c_ptr(), allow_product_relation_join); - } - - relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - relation_transformer_fn * mk_rename_fn(const relation_base & t, const unsigned_vector & permutation_cycle) { - return mk_rename_fn(t, permutation_cycle.size(), permutation_cycle.c_ptr()); - } - - /** - Like \c mk_rename_fn, only the permutation is not specified by cycle, but by a permutated array - of column number. - */ - relation_transformer_fn * mk_permutation_rename_fn(const relation_base & t, - const unsigned * permutation); - relation_transformer_fn * mk_permutation_rename_fn(const relation_base & t, - const unsigned_vector permutation) { - SASSERT(t.get_signature().size()==permutation.size()); - return mk_permutation_rename_fn(t, permutation.c_ptr()); - } - - - /** - The post-condition for an ideal union operation is be - - Union(tgt, src, delta): - tgt_1==tgt_0 \union src - delta_1== delta_0 \union ( tgt_1 \setminus tgt_0 ) - - A required post-condition is - - Union(tgt, src, delta): - tgt_1==tgt_0 \union src - tgt_1==tgt_0 => delta_1==delta_0 - delta_0 \subset delta_1 - delta_1 \subset (delta_0 \union tgt_1) - ( tgt_1 \setminus tgt_0 ) \subset delta_1 - - So that a sufficient implementation is - - Union(tgt, src, delta) { - oldTgt:=tgt.clone(); - tgt:=tgt \union src - if(tgt!=oldTgt) { - delta:=delta \union src //also ?delta \union tgt? would work - } - } - - If rules are compiled with all_or_nothing_deltas parameter set to true, a sufficient - post-condition is - Union(tgt, src, delta): - tgt_1==tgt_0 \union src - (tgt_1==tgt_0 || delta_0 is non-empty) <=> delta_1 is non-empty - */ - relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - - relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src) { - return mk_union_fn(tgt, src, static_cast(0)); - } - - /** - Similar to union, but this one should be used inside loops to allow for abstract - domain convergence. - */ - relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - - relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, const unsigned_vector identical_cols) { - return mk_filter_identical_fn(t, identical_cols.size(), identical_cols.c_ptr()); - } - - relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - - relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - - relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t, app * condition, - unsigned removed_col_cnt, const unsigned * removed_cols); - - /** - \brief Operations that returns all rows of \c t for which is column \c col equal to \c value - with the column \c col removed. - - This operation can often be efficiently implemented and is useful for evaluating rules - of the form - - F(x):-P("c",x). - */ - relation_transformer_fn * mk_select_equal_and_project_fn(const relation_base & t, - const relation_element & value, unsigned col); - - - relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & tgt, - const relation_base & src, unsigned joined_col_cnt, - const unsigned * tgt_cols, const unsigned * src_cols); - relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & tgt, - const relation_base & src, const unsigned_vector & tgt_cols, const unsigned_vector & src_cols) { - SASSERT(tgt_cols.size()==src_cols.size()); - return mk_filter_by_intersection_fn(tgt, src, tgt_cols.size(), tgt_cols.c_ptr(), src_cols.c_ptr()); - } - relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & tgt, - const relation_base & src); - - /** - The filter_by_negation postcondition: - filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, - corresponding columns in neg: d1,...,dN): - tgt_1:={x: x\in tgt_0 && ! \exists y: ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) } - */ - relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); - relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, const unsigned_vector & t_cols, - const unsigned_vector & negated_cols) { - SASSERT(t_cols.size()==negated_cols.size()); - return mk_filter_by_negation_fn(t, negated_obj, t_cols.size(), t_cols.c_ptr(), negated_cols.c_ptr()); - } - - - // ----------------------------------- - // - // table operations - // - // ----------------------------------- - - - table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - - table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - const unsigned_vector & cols1, const unsigned_vector & cols2) { - SASSERT(cols1.size()==cols2.size()); - return mk_join_fn(t1, t2, cols1.size(), cols1.c_ptr(), cols2.c_ptr()); - } - - /** - \brief Return functor that transforms a table into one that lacks columns listed in - \c removed_cols array. - - The \c removed_cols cotains columns of table \c t in strictly ascending order. - - If a project operation removes a non-functional column, all functional columns become - non-functional (so that none of the values in functional columns are lost) - */ - table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols); - - table_transformer_fn * mk_project_fn(const table_base & t, const unsigned_vector & removed_cols) { - return mk_project_fn(t, removed_cols.size(), removed_cols.c_ptr()); - } - - /** - \brief Return an operation that is a composition of a join an a project operation. - - This operation is equivalent to the two operations performed separately, unless functional - columns are involved. - - The ordinary project would make all of the functional columns into non-functional if any - non-functional column was removed. In function, however, we group columns into equivalence - classes (according to the equalities in \c cols1 and \c cols2) and make everything non-functional - only if some equivalence class of non-functional columns would have no non-functional columns - remain after the removal. - - This behavior is implemented in the \c table_signature::from_join_project function. - */ - table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols); - - table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, - const unsigned_vector & cols1, const unsigned_vector & cols2, - const unsigned_vector & removed_cols) { - return mk_join_project_fn(t1, t2, cols1.size(), cols1.c_ptr(), cols2.c_ptr(), removed_cols.size(), - removed_cols.c_ptr()); - } - - table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - table_transformer_fn * mk_rename_fn(const table_base & t, const unsigned_vector & permutation_cycle) { - return mk_rename_fn(t, permutation_cycle.size(), permutation_cycle.c_ptr()); - } - - /** - Like \c mk_rename_fn, only the permutation is not specified by cycle, but by a permutated array - of column number. - */ - table_transformer_fn * mk_permutation_rename_fn(const table_base & t, const unsigned * permutation); - table_transformer_fn * mk_permutation_rename_fn(const table_base & t, const unsigned_vector permutation) { - SASSERT(t.get_signature().size()==permutation.size()); - return mk_permutation_rename_fn(t, permutation.c_ptr()); - } - - - /** - The post-condition for an ideal union operation is be - - Union(tgt, src, delta): - tgt_1==tgt_0 \union src - delta_1== delta_0 \union ( tgt_1 \setminus tgt_0 ) - - A required post-condition is - - Union(tgt, src, delta): - tgt_1==tgt_0 \union src - tgt_1==tgt_0 => delta_1==delta_0 - delta_0 \subset delta_1 - delta_1 \subset (delta_0 \union tgt_1) - ( tgt_1 \setminus tgt_0 ) \subset delta_1 - - So that a sufficient implementation is - - Union(tgt, src, delta) { - oldTgt:=tgt.clone(); - tgt:=tgt \union src - if(tgt!=oldTgt) { - delta:=delta \union src //also ?delta \union tgt? would work - } - } - - If rules are compiled with all_or_nothing_deltas parameter set to true, a sufficient - post-condition is - Union(tgt, src, delta): - tgt_1==tgt_0 \union src - (tgt_1==tgt_0 || delta_0 is non-empty) <=> delta_1 is non-empty - */ - table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, - const table_base * delta); - - table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src) { - return mk_union_fn(tgt, src, static_cast(0)); - } - - /** - Similar to union, but this one should be used inside loops to allow for abstract - domain convergence. - */ - table_union_fn * mk_widen_fn(const table_base & tgt, const table_base & src, - const table_base * delta); - - table_mutator_fn * mk_filter_identical_fn(const table_base & t, unsigned col_cnt, - const unsigned * identical_cols); - table_mutator_fn * mk_filter_identical_fn(const table_base & t, const unsigned_vector identical_cols) { - return mk_filter_identical_fn(t, identical_cols.size(), identical_cols.c_ptr()); - } - - table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value, - unsigned col); - - table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition); - - table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, app * condition, - unsigned removed_col_cnt, const unsigned * removed_cols); - - /** - \brief Operations that returns all rows of \c t for which is column \c col equal to \c value - with the column \c col removed. - - This operation can often be efficiently implemented and is useful for evaluating rules - of the form - - F(x):-P("c",x). - */ - table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t, - const table_element & value, unsigned col); - - table_intersection_filter_fn * mk_filter_by_intersection_fn(const table_base & t, - const table_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols); - table_intersection_filter_fn * mk_filter_by_intersection_fn(const table_base & t, - const table_base & src, const unsigned_vector & t_cols, const unsigned_vector & src_cols) { - SASSERT(t_cols.size()==src_cols.size()); - return mk_filter_by_intersection_fn(t, src, t_cols.size(), t_cols.c_ptr(), src_cols.c_ptr()); - } - - /** - The filter_by_negation postcondition: - filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, - corresponding columns in neg: d1,...,dN): - tgt_1:={x: x\in tgt_0 && ! \exists y: ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) } - */ - table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, const table_base & negated_obj, - unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols); - table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, const table_base & negated_obj, - const unsigned_vector & t_cols, const unsigned_vector & negated_cols) { - SASSERT(t_cols.size()==negated_cols.size()); - return mk_filter_by_negation_fn(t, negated_obj, t_cols.size(), t_cols.c_ptr(), negated_cols.c_ptr()); - } - - /** - \c t must contain at least one functional column. - - Created object takes ownership of the \c mapper object. - */ - virtual table_mutator_fn * mk_map_fn(const table_base & t, table_row_mutator_fn * mapper); - - /** - \c t must contain at least one functional column. - - Created object takes ownership of the \c mapper object. - */ - virtual table_transformer_fn * mk_project_with_reduce_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols, table_row_pair_reduce_fn * reducer); - - - - - // ----------------------------------- - // - // output functions - // - // ----------------------------------- - - - std::string to_nice_string(const relation_element & el) const; - /** - This one may give a nicer representation of \c el than the - \c to_nice_string(const relation_element & el) function, by unsing the information about the sort - of the element. - */ - std::string to_nice_string(const relation_sort & s, const relation_element & el) const; - std::string to_nice_string(const relation_sort & s) const; - std::string to_nice_string(const relation_signature & s) const; - - void display(std::ostream & out) const; - void display_relation_sizes(std::ostream & out) const; - void display_output_tables(rule_set const& rules, std::ostream & out) const; - - private: - relation_intersection_filter_fn * try_mk_default_filter_by_intersection_fn(const relation_base & t, - const relation_base & src, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * src_cols); - - }; - - /** - This is a helper class for relation_plugins whose relations can be of various kinds. - */ - template > - class rel_spec_store { - typedef relation_signature::hash r_hash; - typedef relation_signature::eq r_eq; - - typedef map family_id_idx_store; - typedef map sig2store; - - typedef u_map family_id2spec; - typedef map sig2spec_store; - - relation_plugin & m_parent; - svector m_allocated_kinds; - sig2store m_kind_assignment; - sig2spec_store m_kind_specs; - - - relation_manager & get_manager() { return m_parent.get_manager(); } - - void add_new_kind() { - add_available_kind(get_manager().get_next_relation_fid(m_parent)); - } - - public: - rel_spec_store(relation_plugin & parent) : m_parent(parent) {} - - ~rel_spec_store() { - reset_dealloc_values(m_kind_assignment); - reset_dealloc_values(m_kind_specs); - } - - void add_available_kind(family_id k) { - m_allocated_kinds.push_back(k); - } - - bool contains_signature(relation_signature const& sig) const { - return m_kind_assignment.contains(sig); - } - - family_id get_relation_kind(const relation_signature & sig, const Spec & spec) { - typename sig2store::entry * e = m_kind_assignment.find_core(sig); - if(!e) { - e = m_kind_assignment.insert_if_not_there2(sig, alloc(family_id_idx_store)); - m_kind_specs.insert(sig, alloc(family_id2spec)); - } - family_id_idx_store & ids = *e->get_data().m_value; - - unsigned res_idx; - if(!ids.find(spec, res_idx)) { - res_idx = ids.size(); - if(res_idx==m_allocated_kinds.size()) { - add_new_kind(); - } - SASSERT(res_idxinsert(m_allocated_kinds[res_idx], spec); - } - return m_allocated_kinds[res_idx]; - } - - void get_relation_spec(const relation_signature & sig, family_id kind, Spec & spec) { - family_id2spec * idspecs = m_kind_specs.find(sig); - spec = idspecs->find(kind); - } - - }; - -}; - -#endif /* _DL_RELATION_MANAGER_H_ */ - diff --git a/src/muz/dl_sieve_relation.cpp b/src/muz/dl_sieve_relation.cpp deleted file mode 100644 index 9f9419089..000000000 --- a/src/muz/dl_sieve_relation.cpp +++ /dev/null @@ -1,666 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_mk_explanations.cpp - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-11-08. - -Revision History: - ---*/ - -#include -#include"ast_pp.h" -#include"dl_sieve_relation.h" - -namespace datalog { - - // ----------------------------------- - // - // sieve_relation - // - // ----------------------------------- - - sieve_relation::sieve_relation(sieve_relation_plugin & p, const relation_signature & s, - const bool * inner_columns, relation_base * inner) - : relation_base(p, s), m_inner_cols(s.size(), inner_columns), m_inner(inner) { - unsigned n = s.size(); - for(unsigned i=0; i 0; ) { - --i; - unsigned idx = m_inner2sig[i]; - s.push_back(m.mk_var(idx, sig[i])); - } - get_inner().to_formula(tmp); - get_plugin().get_context().get_var_subst()(tmp, sz, s.c_ptr(), fml); - } - - - void sieve_relation::display(std::ostream & out) const { - out << "Sieve relation "; - print_container(m_inner_cols, out); - out <<"\n"; - get_inner().display(out); - } - - - // ----------------------------------- - // - // sieve_relation_plugin - // - // ----------------------------------- - - sieve_relation_plugin & sieve_relation_plugin::get_plugin(relation_manager & rmgr) { - sieve_relation_plugin * res = static_cast(rmgr.get_relation_plugin(get_name())); - if(!res) { - res = alloc(sieve_relation_plugin, rmgr); - rmgr.register_plugin(res); - } - return *res; - } - - sieve_relation& sieve_relation_plugin::get(relation_base& r) { - return dynamic_cast(r); - } - - sieve_relation const & sieve_relation_plugin::get(relation_base const& r) { - return dynamic_cast(r); - } - - sieve_relation* sieve_relation_plugin::get(relation_base* r) { - return dynamic_cast(r); - } - - sieve_relation const* sieve_relation_plugin::get(relation_base const* r) { - return dynamic_cast(r); - } - - sieve_relation_plugin::sieve_relation_plugin(relation_manager & manager) - : relation_plugin(get_name(), manager, ST_SIEVE_RELATION), - m_spec_store(*this) {} - - void sieve_relation_plugin::initialize(family_id fid) { - relation_plugin::initialize(fid); - m_spec_store.add_available_kind(get_kind()); - } - - family_id sieve_relation_plugin::get_relation_kind(const relation_signature & sig, - const bool * inner_columns, family_id inner_kind) { - rel_spec spec(sig.size(), inner_columns, inner_kind); - return m_spec_store.get_relation_kind(sig, spec); - } - - family_id sieve_relation_plugin::get_relation_kind(sieve_relation & r, const bool * inner_columns) { - const relation_signature & sig = r.get_signature(); - return get_relation_kind(sig, inner_columns, r.get_inner().get_kind()); - } - - void sieve_relation_plugin::extract_inner_columns(const relation_signature & s, relation_plugin & inner, - svector & inner_columns) { - SASSERT(inner_columns.size()==s.size()); - unsigned n = s.size(); - relation_signature inner_sig_singleton; - for(unsigned i=0; i & inner_columns, relation_signature & inner_sig) { - SASSERT(inner_columns.size()==s.size()); - inner_sig.reset(); - unsigned n = s.size(); - for(unsigned i=0; i inner_cols(s.size()); - extract_inner_columns(s, inner_cols.c_ptr()); - collect_inner_signature(s, inner_cols, inner_sig); -#endif - } - - bool sieve_relation_plugin::can_handle_signature(const relation_signature & s) { - //we do not want this plugin to handle anything by default - return false; -#if 0 - relation_signature inner_sig; - extract_inner_signature(s, inner_sig); - SASSERT(inner_sig.size()<=s.size()); - return !inner_sig.empty() && inner_sig.size()!=s.size(); -#endif - } - - sieve_relation * sieve_relation_plugin::mk_from_inner(const relation_signature & s, const bool * inner_columns, - relation_base * inner_rel) { - SASSERT(!inner_rel->get_plugin().is_sieve_relation()); //it does not make sense to make a sieve of a sieve - return alloc(sieve_relation, *this, s, inner_columns, inner_rel); - } - - sieve_relation * sieve_relation_plugin::mk_empty(const sieve_relation & original) { - return static_cast(mk_empty(original.get_signature(), original.get_kind())); - } - - relation_base * sieve_relation_plugin::mk_empty(const relation_base & original) { - return mk_empty(static_cast(original)); - } - - relation_base * sieve_relation_plugin::mk_empty(const relation_signature & s, family_id kind) { - rel_spec spec; - m_spec_store.get_relation_spec(s, kind, spec); - relation_signature inner_sig; - collect_inner_signature(s, spec.m_inner_cols, inner_sig); - relation_base * inner = get_manager().mk_empty_relation(inner_sig, spec.m_inner_kind); - return mk_from_inner(s, spec.m_inner_cols.c_ptr(), inner); - } - - - relation_base * sieve_relation_plugin::mk_empty(const relation_signature & s) { - UNREACHABLE(); - return 0; -#if 0 - svector inner_cols(s.size()); - extract_inner_columns(s, inner_cols.c_ptr()); - return mk_empty(s, inner_cols.c_ptr()); -#endif - } - - sieve_relation * sieve_relation_plugin::mk_empty(const relation_signature & s, relation_plugin & inner_plugin) { - SASSERT(!inner_plugin.is_sieve_relation()); //it does not make sense to make a sieve of a sieve - svector inner_cols(s.size()); - extract_inner_columns(s, inner_plugin, inner_cols); - relation_signature inner_sig; - collect_inner_signature(s, inner_cols, inner_sig); - relation_base * inner_rel = inner_plugin.mk_empty(inner_sig); - return mk_from_inner(s, inner_cols, inner_rel); - } - - relation_base * sieve_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { - relation_signature empty_sig; - relation_plugin& plugin = get_manager().get_appropriate_plugin(s); - relation_base * inner = plugin.mk_full(p, empty_sig, null_family_id); - svector inner_cols; - inner_cols.resize(s.size(), false); - return mk_from_inner(s, inner_cols, inner); - } - - sieve_relation * sieve_relation_plugin::mk_full(func_decl* p, const relation_signature & s, relation_plugin & inner_plugin) { - SASSERT(!inner_plugin.is_sieve_relation()); //it does not make sense to make a sieve of a sieve - svector inner_cols(s.size()); - extract_inner_columns(s, inner_plugin, inner_cols); - relation_signature inner_sig; - collect_inner_signature(s, inner_cols, inner_sig); - relation_base * inner_rel = inner_plugin.mk_full(p, inner_sig, null_family_id); - return mk_from_inner(s, inner_cols, inner_rel); - } - - class sieve_relation_plugin::join_fn : public convenient_relation_join_fn { - sieve_relation_plugin & m_plugin; - unsigned_vector m_inner_cols_1; - unsigned_vector m_inner_cols_2; - svector m_result_inner_cols; - - scoped_ptr m_inner_join_fun; - public: - join_fn(sieve_relation_plugin & p, const relation_base & r1, const relation_base & r2, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2, relation_join_fn * inner_join_fun) - : convenient_relation_join_fn(r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2), - m_plugin(p), - m_inner_join_fun(inner_join_fun) { - bool r1_sieved = r1.get_plugin().is_sieve_relation(); - bool r2_sieved = r2.get_plugin().is_sieve_relation(); - const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : 0; - const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : 0; - if(r1_sieved) { - m_result_inner_cols.append(sr1->m_inner_cols); - } - else { - m_result_inner_cols.resize(r1.get_signature().size(), true); - } - if(r2_sieved) { - m_result_inner_cols.append(sr2->m_inner_cols); - } - else { - m_result_inner_cols.resize(m_result_inner_cols.size() + r2.get_signature().size(), true); - } - } - - virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { - bool r1_sieved = r1.get_plugin().is_sieve_relation(); - bool r2_sieved = r2.get_plugin().is_sieve_relation(); - SASSERT(r1_sieved || r2_sieved); - const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : 0; - const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : 0; - const relation_base & inner1 = r1_sieved ? sr1->get_inner() : r1; - const relation_base & inner2 = r2_sieved ? sr2->get_inner() : r2; - - relation_base * inner_res = (*m_inner_join_fun)(inner1, inner2); - - return m_plugin.mk_from_inner(get_result_signature(), m_result_inner_cols.c_ptr(), inner_res); - } - }; - - relation_join_fn * sieve_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if( &r1.get_plugin()!=this && &r2.get_plugin()!=this ) { - //we create just operations that involve the current plugin - return 0; - } - bool r1_sieved = r1.get_plugin().is_sieve_relation(); - bool r2_sieved = r2.get_plugin().is_sieve_relation(); - const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : 0; - const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : 0; - const relation_base & inner1 = r1_sieved ? sr1->get_inner() : r1; - const relation_base & inner2 = r2_sieved ? sr2->get_inner() : r2; - - unsigned_vector inner_cols1; - unsigned_vector inner_cols2; - - for(unsigned i=0; iis_inner_col(cols1[i])) { - continue; - } - if(r2_sieved && !sr2->is_inner_col(cols2[i])) { - continue; - } - inner_cols1.push_back( r1_sieved ? sr1->get_inner_col(cols1[i]) : cols1[i] ); - inner_cols2.push_back( r2_sieved ? sr2->get_inner_col(cols2[i]) : cols2[i] ); - } - - relation_join_fn * inner_join_fun = get_manager().mk_join_fn(inner1, inner2, inner_cols1, inner_cols2, false); - if(!inner_join_fun) { - return 0; - } - return alloc(join_fn, *this, r1, r2, col_cnt, cols1, cols2, inner_join_fun); - } - - - class sieve_relation_plugin::transformer_fn : public convenient_relation_transformer_fn { - svector m_result_inner_cols; - - scoped_ptr m_inner_fun; - public: - transformer_fn(relation_transformer_fn * inner_fun, const relation_signature & result_sig, - const bool * result_inner_cols) - : m_result_inner_cols(result_sig.size(), result_inner_cols), m_inner_fun(inner_fun) { - get_result_signature() = result_sig; - } - - virtual relation_base * operator()(const relation_base & r0) { - SASSERT(r0.get_plugin().is_sieve_relation()); - const sieve_relation & r = static_cast(r0); - sieve_relation_plugin & plugin = r.get_plugin(); - - relation_base * inner_res = (*m_inner_fun)(r.get_inner()); - - return plugin.mk_from_inner(get_result_signature(), m_result_inner_cols.c_ptr(), inner_res); - } - }; - - relation_transformer_fn * sieve_relation_plugin::mk_project_fn(const relation_base & r0, unsigned col_cnt, - const unsigned * removed_cols) { - if(&r0.get_plugin()!=this) { - return 0; - } - const sieve_relation & r = static_cast(r0); - unsigned_vector inner_removed_cols; - - for(unsigned i=0; i result_inner_cols = r.m_inner_cols; - project_out_vector_columns(result_inner_cols, col_cnt, removed_cols); - - relation_signature result_sig; - relation_signature::from_project(r.get_signature(), col_cnt, removed_cols, result_sig); - - relation_transformer_fn * inner_fun; - if(inner_removed_cols.empty()) { - inner_fun = alloc(identity_relation_transformer_fn); - } - else { - inner_fun = get_manager().mk_project_fn(r.get_inner(), inner_removed_cols); - } - - if(!inner_fun) { - return 0; - } - return alloc(transformer_fn, inner_fun, result_sig, result_inner_cols.c_ptr()); - } - - relation_transformer_fn * sieve_relation_plugin::mk_rename_fn(const relation_base & r0, - unsigned cycle_len, const unsigned * permutation_cycle) { - if(&r0.get_plugin()!=this) { - return 0; - } - const sieve_relation & r = static_cast(r0); - - unsigned sig_sz = r.get_signature().size(); - unsigned_vector permutation; - add_sequence(0, sig_sz, permutation); - permutate_by_cycle(permutation, cycle_len, permutation_cycle); - - bool inner_identity; - unsigned_vector inner_permutation; - collect_sub_permutation(permutation, r.m_sig2inner, inner_permutation, inner_identity); - - svector result_inner_cols = r.m_inner_cols; - permutate_by_cycle(result_inner_cols, cycle_len, permutation_cycle); - - relation_signature result_sig; - relation_signature::from_rename(r.get_signature(), cycle_len, permutation_cycle, result_sig); - - relation_transformer_fn * inner_fun = - get_manager().mk_permutation_rename_fn(r.get_inner(), inner_permutation); - if(!inner_fun) { - return 0; - } - return alloc(transformer_fn, inner_fun, result_sig, result_inner_cols.c_ptr()); - } - - - class sieve_relation_plugin::union_fn : public relation_union_fn { - scoped_ptr m_union_fun; - public: - union_fn(relation_union_fn * union_fun) : m_union_fun(union_fun) {} - - virtual void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) { - bool tgt_sieved = tgt.get_plugin().is_sieve_relation(); - bool src_sieved = src.get_plugin().is_sieve_relation(); - bool delta_sieved = delta && delta->get_plugin().is_sieve_relation(); - sieve_relation * stgt = tgt_sieved ? static_cast(&tgt) : 0; - const sieve_relation * ssrc = src_sieved ? static_cast(&src) : 0; - sieve_relation * sdelta = delta_sieved ? static_cast(delta) : 0; - relation_base & itgt = tgt_sieved ? stgt->get_inner() : tgt; - const relation_base & isrc = src_sieved ? ssrc->get_inner() : src; - relation_base * idelta = delta_sieved ? &sdelta->get_inner() : delta; - - (*m_union_fun)(itgt, isrc, idelta); - } - }; - - relation_union_fn * sieve_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if(&tgt.get_plugin()!=this && &src.get_plugin()!=this && (delta && &delta->get_plugin()!=this)) { - //we create the operation only if it involves this plugin - return 0; - } - - bool tgt_sieved = tgt.get_plugin().is_sieve_relation(); - bool src_sieved = src.get_plugin().is_sieve_relation(); - bool delta_sieved = delta && delta->get_plugin().is_sieve_relation(); - const sieve_relation * stgt = tgt_sieved ? static_cast(&tgt) : 0; - const sieve_relation * ssrc = src_sieved ? static_cast(&src) : 0; - const sieve_relation * sdelta = delta_sieved ? static_cast(delta) : 0; - const relation_base & itgt = tgt_sieved ? stgt->get_inner() : tgt; - const relation_base & isrc = src_sieved ? ssrc->get_inner() : src; - const relation_base * idelta = delta_sieved ? &sdelta->get_inner() : delta; - - //Now we require that the sieved and inner columns must match on all relations. - //We may want to allow for some cases of misalignment even though it could introcude imprecision - if( tgt_sieved && src_sieved && (!delta || delta_sieved) ) { - if( !vectors_equal(stgt->m_inner_cols, ssrc->m_inner_cols) - || (delta && !vectors_equal(stgt->m_inner_cols, sdelta->m_inner_cols)) ) { - return 0; - } - } - else { - if( (stgt && !stgt->no_sieved_columns()) - || (ssrc && !ssrc->no_sieved_columns()) - || (sdelta && !sdelta->no_sieved_columns()) ) { - //We have an unsieved relation and then some relation with some sieved columns, - //which means there is an misalignment. - return 0; - } - } - - relation_union_fn * union_fun = get_manager().mk_union_fn(itgt, isrc, idelta); - if(!union_fun) { - return 0; - } - - return alloc(union_fn, union_fun); - } - - - class sieve_relation_plugin::filter_fn : public relation_mutator_fn { - scoped_ptr m_inner_fun; - public: - filter_fn(relation_mutator_fn * inner_fun) - : m_inner_fun(inner_fun) {} - - virtual void operator()(relation_base & r0) { - SASSERT(r0.get_plugin().is_sieve_relation()); - sieve_relation & r = static_cast(r0); - - (*m_inner_fun)(r.get_inner()); - } - }; - - relation_mutator_fn * sieve_relation_plugin::mk_filter_identical_fn(const relation_base & r0, - unsigned col_cnt, const unsigned * identical_cols) { - if(&r0.get_plugin()!=this) { - return 0; - } - const sieve_relation & r = static_cast(r0); - unsigned_vector inner_icols; - - //we ignore the columns which do not belong to the inner relation (which introduces imprecision) - for(unsigned i=0; i(r0); - if(!r.is_inner_col(col)) { - //if the column which do not belong to the inner relation, we do nothing (which introduces imprecision) - return alloc(identity_relation_mutator_fn); - } - unsigned inner_col = r.get_inner_col(col); - - relation_mutator_fn * inner_fun = get_manager().mk_filter_equal_fn(r.get_inner(), value, inner_col); - if(!inner_fun) { - return 0; - } - return alloc(filter_fn, inner_fun); - } - - relation_mutator_fn * sieve_relation_plugin::mk_filter_interpreted_fn(const relation_base & rb, - app * condition) { - if(&rb.get_plugin()!=this) { - return 0; - } - ast_manager & m = get_ast_manager(); - const sieve_relation & r = static_cast(rb); - const relation_signature sig = r.get_signature(); - unsigned sz = sig.size(); - - var_idx_set& cond_vars = get_context().get_rule_manager().collect_vars(condition); - expr_ref_vector subst_vect(m); - subst_vect.resize(sz); - unsigned subst_ofs = sz-1; - for(unsigned i=0; i m_inner_fun; - public: - negation_filter_fn(relation_intersection_filter_fn * inner_fun) - : m_inner_fun(inner_fun) {} - - virtual void operator()(relation_base & r, const relation_base & neg) { - bool r_sieved = r.get_plugin().is_sieve_relation(); - bool neg_sieved = neg.get_plugin().is_sieve_relation(); - SASSERT(r_sieved || neg_sieved); - sieve_relation * sr = r_sieved ? static_cast(&r) : 0; - const sieve_relation * sneg = neg_sieved ? static_cast(&neg) : 0; - relation_base & inner_r = r_sieved ? sr->get_inner() : r; - const relation_base & inner_neg = neg_sieved ? sneg->get_inner() : neg; - - (*m_inner_fun)(inner_r, inner_neg); - } - }; - - relation_intersection_filter_fn * sieve_relation_plugin::mk_filter_by_negation_fn(const relation_base & r, - const relation_base & neg, unsigned col_cnt, const unsigned * r_cols, - const unsigned * neg_cols) { - if(&r.get_plugin()!=this && &neg.get_plugin()!=this) { - //we create just operations that involve the current plugin - return 0; - } - bool r_sieved = r.get_plugin().is_sieve_relation(); - bool neg_sieved = neg.get_plugin().is_sieve_relation(); - SASSERT(r_sieved || neg_sieved); - const sieve_relation * sr = r_sieved ? static_cast(&r) : 0; - const sieve_relation * sneg = neg_sieved ? static_cast(&neg) : 0; - const relation_base & inner_r = r_sieved ? sr->get_inner() : r; - const relation_base & inner_neg = neg_sieved ? sneg->get_inner() : neg; - - unsigned_vector ir_cols; - unsigned_vector ineg_cols; - - for(unsigned i=0; iis_inner_col(r_cols[i]); - bool neg_col_inner = neg_sieved && !sneg->is_inner_col(neg_cols[i]); - if(r_col_inner && neg_col_inner) { - ir_cols.push_back( r_sieved ? sr->get_inner_col(i) : i ); - ineg_cols.push_back( neg_sieved ? sneg->get_inner_col(i) : i ); - } - else if(!r_col_inner && neg_col_inner) { - //Sieved (i.e. full) column in r is matched on an inner column in neg. - //If we assume the column in neg is not full, no rows from the inner relation of - //r would be removed. So in this case we perform no operation at cost of a little - //impresicion. - return alloc(identity_relation_intersection_filter_fn); - } - else { - //Inner or sieved column in r must match a sieved column in neg. - //Since sieved columns are full, this is always true so we can skip the equality. - continue; - } - } - - relation_intersection_filter_fn * inner_fun = - get_manager().mk_filter_by_negation_fn(inner_r, inner_neg, ir_cols, ineg_cols); - if(!inner_fun) { - return 0; - } - return alloc(negation_filter_fn, inner_fun); - } - - -}; diff --git a/src/muz/dl_sieve_relation.h b/src/muz/dl_sieve_relation.h deleted file mode 100644 index 551f5d705..000000000 --- a/src/muz/dl_sieve_relation.h +++ /dev/null @@ -1,197 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_sieve_relation.h - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-11-11. - -Revision History: - ---*/ - -#ifndef _DL_SIEVE_RELATION_H_ -#define _DL_SIEVE_RELATION_H_ - -#include "dl_context.h" - -namespace datalog { - - class sieve_relation; - - class sieve_relation_plugin : public relation_plugin { - friend class sieve_relation; - public: - struct rel_spec { - svector m_inner_cols; - family_id m_inner_kind; - - /** - Create uninitialized rel_spec. - */ - rel_spec() {} - /** - \c inner_kind==null_family_id means we will not specify a relation kind when requesting - the relation object from the relation_manager. - - \c inner_kind==null_family_id cannot hold in a specification of existing relation object. - */ - rel_spec(unsigned sig_sz, const bool * inner_cols, family_id inner_kind=null_family_id) - : m_inner_cols(sig_sz, inner_cols), m_inner_kind(inner_kind) {} - - bool operator==(const rel_spec & o) const { - return m_inner_kind==o.m_inner_kind && vectors_equal(m_inner_cols, o.m_inner_cols); - } - - struct hash { - unsigned operator()(const rel_spec & s) const { - return svector_hash()(s.m_inner_cols)^s.m_inner_kind; - } - }; - }; - private: - - class join_fn; - class transformer_fn; - class union_fn; - class filter_fn; - class negation_filter_fn; - - rel_spec_store > m_spec_store; - - family_id get_relation_kind(sieve_relation & r, const bool * inner_columns); - - void extract_inner_columns(const relation_signature & s, relation_plugin & inner, - svector & inner_columns); - void extract_inner_signature(const relation_signature & s, relation_signature & inner_sig); - void collect_inner_signature(const relation_signature & s, const svector & inner_columns, - relation_signature & inner_sig); - public: - static symbol get_name() { return symbol("sieve_relation"); } - static sieve_relation_plugin& get_plugin(relation_manager & rmgr); - - static sieve_relation& get(relation_base& r); - static sieve_relation const & get(relation_base const& r); - static sieve_relation* get(relation_base* r); - static sieve_relation const* get(relation_base const* r); - - sieve_relation_plugin(relation_manager & manager); - - virtual void initialize(family_id fid); - - family_id get_relation_kind(const relation_signature & sig, const bool * inner_columns, - family_id inner_kind); - family_id get_relation_kind(const relation_signature & sig, const svector & inner_columns, - family_id inner_kind) { - SASSERT(sig.size()==inner_columns.size()); - return get_relation_kind(sig, inner_columns.c_ptr(), inner_kind); - } - - virtual bool can_handle_signature(const relation_signature & s); - - virtual relation_base * mk_empty(const relation_signature & s); - sieve_relation * mk_empty(const sieve_relation & original); - virtual relation_base * mk_empty(const relation_base & original); - virtual relation_base * mk_empty(const relation_signature & s, family_id kind); - sieve_relation * mk_empty(const relation_signature & s, relation_plugin & inner_plugin); - - virtual relation_base * mk_full(func_decl* p, const relation_signature & s); - sieve_relation * mk_full(func_decl* p, const relation_signature & s, relation_plugin & inner_plugin); - - - sieve_relation * mk_from_inner(const relation_signature & s, const bool * inner_columns, - relation_base * inner_rel); - sieve_relation * mk_from_inner(const relation_signature & s, const svector inner_columns, - relation_base * inner_rel) { - SASSERT(inner_columns.size()==s.size()); - return mk_from_inner(s, inner_columns.c_ptr(), inner_rel); - } - - protected: - - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); - }; - - - // ----------------------------------- - // - // sieve_relation - // - // ----------------------------------- - - class sieve_relation : public relation_base { - friend class sieve_relation_plugin; - friend class sieve_relation_plugin::join_fn; - friend class sieve_relation_plugin::transformer_fn; - friend class sieve_relation_plugin::union_fn; - friend class sieve_relation_plugin::filter_fn; - - svector m_inner_cols; - - unsigned_vector m_sig2inner; - unsigned_vector m_inner2sig; - unsigned_vector m_ignored_cols; //in ascending order, so that it can be used in project-like functions - - scoped_rel m_inner; - - - sieve_relation(sieve_relation_plugin & p, const relation_signature & s, - const bool * inner_columns, relation_base * inner); - - public: - sieve_relation_plugin & get_plugin() const { - return static_cast(relation_base::get_plugin()); - } - - bool is_inner_col(unsigned idx) const { return m_sig2inner[idx]!=UINT_MAX; } - unsigned get_inner_col(unsigned idx) const { - SASSERT(is_inner_col(idx)); - return m_sig2inner[idx]; - } - bool no_sieved_columns() const { return m_ignored_cols.size()==0; } - bool no_inner_columns() const { return m_ignored_cols.size()==get_signature().size(); } - - relation_base & get_inner() { return *m_inner; } - const relation_base & get_inner() const { return *m_inner; } - - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual sieve_relation * clone() const; - virtual relation_base * complement(func_decl*p) const; - virtual void to_formula(expr_ref& fml) const; - - virtual bool empty() const { return get_inner().empty(); } - virtual void reset() { get_inner().reset(); } - virtual unsigned get_size_estimate_rows() const { return get_inner().get_size_estimate_rows(); } - virtual unsigned get_size_estimate_bytes() const { return get_inner().get_size_estimate_bytes(); } - - virtual void display(std::ostream & out) const; - }; - - -}; - -#endif /* _DL_SIEVE_RELATION_H_ */ - diff --git a/src/muz/dl_sparse_table.cpp b/src/muz/dl_sparse_table.cpp deleted file mode 100644 index 52d9618b8..000000000 --- a/src/muz/dl_sparse_table.cpp +++ /dev/null @@ -1,1246 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_sparse_table.cpp - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-24. - -Revision History: - ---*/ - -#include -#include"dl_context.h" -#include"dl_util.h" -#include"dl_sparse_table.h" - -namespace datalog { - - // ----------------------------------- - // - // entry_storage - // - // ----------------------------------- - - entry_storage::store_offset entry_storage::insert_or_get_reserve_content() { - SASSERT(has_reserve()); - store_offset entry_ofs = m_data_indexer.insert_if_not_there(m_reserve); - if (m_reserve == entry_ofs) { - //entry inserted, so reserve is no longer a reserve - m_reserve = NO_RESERVE; - } - return entry_ofs; - } - bool entry_storage::insert_reserve_content() { - SASSERT(has_reserve()); - store_offset entry_ofs = m_data_indexer.insert_if_not_there(m_reserve); - if (m_reserve == entry_ofs) { - //entry inserted, so reserve is no longer a reserve - m_reserve = NO_RESERVE; - return true; - } - return false; - } - - bool entry_storage::remove_reserve_content() { - SASSERT(has_reserve()); - store_offset entry_ofs; - if (!find_reserve_content(entry_ofs)) { - //the fact was not in the table - return false; - } - remove_offset(entry_ofs); - return true; - } - - void entry_storage::remove_offset(store_offset ofs) { - m_data_indexer.remove(ofs); - store_offset last_ofs = after_last_offset() - m_entry_size; - if (ofs!=last_ofs) { - SASSERT(ofs + m_entry_size <= last_ofs); - //we don't want any holes, so we put the last element at the place - //of the removed one - m_data_indexer.remove(last_ofs); - char * base = &m_data.get(0); - memcpy(base+ofs, base+last_ofs, m_entry_size); - m_data_indexer.insert(ofs); - } - if (has_reserve()) { - //we already have a reserve, so we need to shrink a little to keep having just one - resize_data(m_data_size-m_entry_size); - } - m_reserve=last_ofs; - } - - unsigned entry_storage::get_size_estimate_bytes() const { - unsigned sz = m_data.capacity(); - sz += m_data_indexer.capacity()*sizeof(storage_indexer::entry); - return sz; - } - - // ----------------------------------- - // - // sparse_table::column_layout - // - // ----------------------------------- - - unsigned get_domain_length(uint64 dom_size) { - SASSERT(dom_size>0); - - unsigned length = 0; - - unsigned dom_size_sm; - if (dom_size>UINT_MAX) { - dom_size_sm = static_cast(dom_size>>32); - length += 32; - if ( (dom_size&UINT_MAX)!=0 && dom_size_sm!=UINT_MAX ) { - dom_size_sm++; - } - } - else { - dom_size_sm=static_cast(dom_size); - } - if (dom_size_sm == 1) { - length += 1; //unary domains - } - else if (dom_size_sm > 0x80000000u) { - length += 32; - } - else { - length += get_num_1bits(next_power_of_two(dom_size_sm)-1); //ceil(log2(dom_size)) - } - return length; - } - - sparse_table::column_layout::column_layout(const table_signature & sig) - : m_functional_col_cnt(sig.functional_columns()) { - SASSERT(sig.size() > 0); - unsigned ofs = 0; - unsigned sig_sz = sig.size(); - unsigned first_functional = sig_sz-m_functional_col_cnt; - for (unsigned i=0; i0); - SASSERT(length<=64); - - if (size() > 0 && (length > 54 || i == first_functional)) { - //large domains must start byte-aligned, as well as functional columns - make_byte_aligned_end(size()-1); - ofs = back().next_ofs(); - } - - push_back(column_info(ofs, length)); - ofs += length; - } - make_byte_aligned_end(size()-1); - SASSERT(back().next_ofs()%8 == 0);//the entries must be aligned to whole bytes - m_entry_size = back().next_ofs()/8; - if (m_functional_col_cnt) { - SASSERT((*this)[first_functional].m_offset%8 == 0); - m_functional_part_size = m_entry_size - (*this)[first_functional].m_offset/8; - } - else { - m_functional_part_size = 0; - } - } - - void sparse_table::column_layout::make_byte_aligned_end(unsigned col_index0) { - unsigned ofs = (*this)[col_index0].next_ofs(); - unsigned ofs_bit_part = ofs%8; - unsigned rounded_ofs = (ofs_bit_part == 0) ? ofs : (ofs+8-ofs_bit_part); - - if (rounded_ofs!=ofs) { - SASSERT(rounded_ofs>ofs); - int diff = rounded_ofs-ofs; - unsigned col_idx = col_index0+1; - while(diff!=0) { - //we should always be able to fix the alignment by the time we reach zero - SASSERT(col_idx>0); - col_idx--; - column_info & ci = (*this)[col_idx]; - unsigned new_length = ci.m_length; - if (ci.m_length < 64) { - unsigned swallowed = std::min(64-static_cast(ci.m_length), diff); - diff -= swallowed; - new_length += swallowed; - } - unsigned new_ofs = ci.m_offset+diff; - ci = column_info(new_ofs, new_length); - } - } - - SASSERT(rounded_ofs%8 == 0); - SASSERT((*this)[col_index0].next_ofs()%8 == 0); - } - - // ----------------------------------- - // - // sparse_table - // - // ----------------------------------- - - class sparse_table::our_iterator_core : public iterator_core { - - class our_row : public row_interface { - const our_iterator_core & m_parent; - public: - our_row(const sparse_table & t, const our_iterator_core & parent) : - row_interface(t), - m_parent(parent) {} - - virtual table_element operator[](unsigned col) const { - return m_parent.m_layout.get(m_parent.m_ptr, col); - } - - }; - - const char * m_end; - const char * m_ptr; - unsigned m_fact_size; - our_row m_row_obj; - const column_layout & m_layout; - - public: - our_iterator_core(const sparse_table & t, bool finished) : - m_end(t.m_data.after_last()), - m_ptr(finished ? m_end : t.m_data.begin()), - m_fact_size(t.m_fact_size), - m_row_obj(t, *this), - m_layout(t.m_column_layout) {} - - virtual bool is_finished() const { - return m_ptr == m_end; - } - - virtual row_interface & operator*() { - SASSERT(!is_finished()); - return m_row_obj; - } - virtual void operator++() { - SASSERT(!is_finished()); - m_ptr+=m_fact_size; - } - }; - - class sparse_table::key_indexer { - protected: - unsigned_vector m_key_cols; - public: - typedef const store_offset * offset_iterator; - - /** - Iterators returned by \c begin() and \c end() are valid only as long as the \c query_result - object that returned them exists. - */ - struct query_result { - private: - bool m_singleton; - union { - store_offset m_single_result; - struct { - offset_iterator begin; - offset_iterator end; - } m_many; - }; - public: - /** - \brief Empty result. - */ - query_result() : m_singleton(false) { - m_many.begin = 0; - m_many.end = 0; - } - query_result(offset_iterator begin, offset_iterator end) : m_singleton(false) { - m_many.begin = begin; - m_many.end = end; - } - query_result(store_offset single_result) : m_singleton(true), m_single_result(single_result) {} - - offset_iterator begin() const { return m_singleton ? &m_single_result : m_many.begin; } - offset_iterator end() const { return m_singleton ? (&m_single_result+1) : m_many.end; } - bool empty() const { return begin() == end(); } - }; - - key_indexer(unsigned key_len, const unsigned * key_cols) - : m_key_cols(key_len, key_cols) {} - - virtual ~key_indexer() {} - - virtual void update(const sparse_table & t) {} - - virtual query_result get_matching_offsets(const key_value & key) const = 0; - }; - - - class sparse_table::general_key_indexer : public key_indexer { - typedef svector offset_vector; - typedef u_map index_map; - - index_map m_map; - mutable entry_storage m_keys; - store_offset m_first_nonindexed; - - - void key_to_reserve(const key_value & key) const { - m_keys.ensure_reserve(); - m_keys.write_into_reserve(reinterpret_cast(key.c_ptr())); - } - - offset_vector & get_matching_offset_vector(const key_value & key) { - key_to_reserve(key); - store_offset ofs = m_keys.insert_or_get_reserve_content(); - index_map::entry * e = m_map.find_core(ofs); - if (!e) { - TRACE("dl_table_relation", tout << "inserting\n";); - e = m_map.insert_if_not_there2(ofs, offset_vector()); - } - return e->get_data().m_value; - } - public: - general_key_indexer(unsigned key_len, const unsigned * key_cols) - : key_indexer(key_len, key_cols), - m_keys(key_len*sizeof(table_element)), - m_first_nonindexed(0) {} - - virtual void update(const sparse_table & t) { - if (m_first_nonindexed == t.m_data.after_last_offset()) { - return; - } - SASSERT(m_first_nonindexedinsert(ofs); - } - - m_first_nonindexed = t.m_data.after_last_offset(); - } - - virtual query_result get_matching_offsets(const key_value & key) const { - key_to_reserve(key); - store_offset ofs; - if (!m_keys.find_reserve_content(ofs)) { - return query_result(); - } - index_map::entry * e = m_map.find_core(ofs); - if (!e) { - return query_result(); - } - const offset_vector & res = e->get_data().m_value; - return query_result(res.begin(), res.end()); - } - }; - - /** - When doing lookup using this index, the content of the reserve in sparse_table::m_data changes. - */ - class sparse_table::full_signature_key_indexer : public key_indexer { - const sparse_table & m_table; - - /** - Permutation of key columns to make it into table facts. If empty, no permutation is necessary. - */ - unsigned_vector m_permutation; - mutable table_fact m_key_fact; - public: - - static bool can_handle(unsigned key_len, const unsigned * key_cols, const sparse_table & t) { - unsigned non_func_cols = t.get_signature().first_functional(); - if (key_len!=non_func_cols) { - return false; - } - counter ctr; - ctr.count(key_len, key_cols); - if (ctr.get_max_counter_value()!=1 || ctr.get_max_positive()!=non_func_cols-1) { - return false; - } - SASSERT(ctr.get_positive_count() == non_func_cols); - return true; - } - - full_signature_key_indexer(unsigned key_len, const unsigned * key_cols, const sparse_table & t) - : key_indexer(key_len, key_cols), - m_table(t) { - SASSERT(can_handle(key_len, key_cols, t)); - - m_permutation.resize(key_len); - for (unsigned i=0; i(m_table); - t.write_into_reserve(m_key_fact.c_ptr()); - - store_offset res; - if (!t.m_data.find_reserve_content(res)) { - return query_result(); - } - return query_result(res); - } - }; - - sparse_table::sparse_table(sparse_table_plugin & p, const table_signature & sig, unsigned init_capacity) - : table_base(p, sig), - m_column_layout(sig), - m_fact_size(m_column_layout.m_entry_size), - m_data(m_fact_size, m_column_layout.m_functional_part_size, init_capacity) {} - - sparse_table::sparse_table(const sparse_table & t) - : table_base(t.get_plugin(), t.get_signature()), - m_column_layout(t.m_column_layout), - m_fact_size(t.m_fact_size), - m_data(t.m_data) {} - - table_base * sparse_table::clone() const { - return get_plugin().mk_clone(*this); - } - - sparse_table::~sparse_table() { - reset_indexes(); - } - - void sparse_table::reset() { - reset_indexes(); - m_data.reset(); - } - - table_base::iterator sparse_table::begin() const { - return mk_iterator(alloc(our_iterator_core, *this, false)); - } - - table_base::iterator sparse_table::end() const { - return mk_iterator(alloc(our_iterator_core, *this, true)); - } - - sparse_table::key_indexer& sparse_table::get_key_indexer(unsigned key_len, - const unsigned * key_cols) const { -#if Z3DEBUG - //We allow indexes only on non-functional columns because we want to be able to modify them - //without having to worry about updating indexes. - //Maybe we might keep a list of indexes that contain functional columns and on an update reset - //only those. - SASSERT(key_len == 0 || - counter().count(key_len, key_cols).get_max_positive()get_data().m_value) { - if (full_signature_key_indexer::can_handle(key_len, key_cols, *this)) { - key_map_entry->get_data().m_value = alloc(full_signature_key_indexer, key_len, key_cols, *this); - } - else { - key_map_entry->get_data().m_value = alloc(general_key_indexer, key_len, key_cols); - } - } - key_indexer & indexer = *key_map_entry->get_data().m_value; - indexer.update(*this); - return indexer; - } - - void sparse_table::reset_indexes() { - key_index_map::iterator kmit = m_key_indexes.begin(); - key_index_map::iterator kmend = m_key_indexes.end(); - for (; kmit!=kmend; ++kmit) { - dealloc((*kmit).m_value); - } - m_key_indexes.reset(); - } - - void sparse_table::write_into_reserve(const table_element* f) { - TRACE("dl_table_relation", tout << "\n";); - m_data.ensure_reserve(); - char * reserve = m_data.get_reserve_ptr(); - unsigned col_cnt = m_column_layout.size(); - for (unsigned i = 0; i < col_cnt; ++i) { - SASSERT(f[i] < get_signature()[i]); //the value fits into the table signature - m_column_layout.set(reserve, i, f[i]); - } - } - - bool sparse_table::add_fact(const char * data) { - m_data.write_into_reserve(data); - return add_reserve_content(); - } - - void sparse_table::add_fact(const table_fact & f) { - write_into_reserve(f.c_ptr()); - add_reserve_content(); - } - - bool sparse_table::add_reserve_content() { - return m_data.insert_reserve_content(); - } - - bool sparse_table::contains_fact(const table_fact & f) const { - sparse_table & t = const_cast(*this); - t.write_into_reserve(f.c_ptr()); - unsigned func_col_cnt = get_signature().functional_columns(); - if (func_col_cnt == 0) { - return t.m_data.reserve_content_already_present(); - } - else { - store_offset ofs; - if (!t.m_data.find_reserve_content(ofs)) { - return false; - } - unsigned sz = get_signature().size(); - for (unsigned i=func_col_cnt; i(*this); - t.write_into_reserve(f.c_ptr()); - store_offset ofs; - if (!t.m_data.find_reserve_content(ofs)) { - return false; - } - unsigned sz = sig.size(); - for (unsigned i=sig.first_functional(); ipre_projection_idx); - dest_layout.set(dest, dest_idx++, src_layout.get(src, i)); - } - } - - void sparse_table::concatenate_rows(const column_layout & layout1, const column_layout & layout2, - const column_layout & layout_res, const char * ptr1, const char * ptr2, char * res, - const unsigned * removed_cols) { - unsigned t1non_func = layout1.size()-layout1.m_functional_col_cnt; - unsigned t2non_func = layout2.size()-layout2.m_functional_col_cnt; - unsigned t1cols = layout1.size(); - unsigned t2cols = layout2.size(); - unsigned orig_i = 0; - unsigned res_i = 0; - const unsigned * next_removed = removed_cols; - copy_columns(layout1, layout_res, 0, t1non_func, ptr1, res, res_i, orig_i, next_removed); - copy_columns(layout2, layout_res, 0, t2non_func, ptr2, res, res_i, orig_i, next_removed); - copy_columns(layout1, layout_res, t1non_func, t1cols, ptr1, res, res_i, orig_i, next_removed); - copy_columns(layout2, layout_res, t2non_func, t2cols, ptr2, res, res_i, orig_i, next_removed); - } - - void sparse_table::garbage_collect() { - if (memory::above_high_watermark()) { - get_plugin().garbage_collect(); - } - if (memory::above_high_watermark()) { - IF_VERBOSE(1, verbose_stream() << "Ran out of memory while filling table of size: " << get_size_estimate_rows() << " rows " << get_size_estimate_bytes() << " bytes\n";); - throw out_of_memory_error(); - } - } - - void sparse_table::self_agnostic_join_project(const sparse_table & t1, const sparse_table & t2, - unsigned joined_col_cnt, const unsigned * t1_joined_cols, const unsigned * t2_joined_cols, - const unsigned * removed_cols, bool tables_swapped, sparse_table & result) { - - unsigned t1_entry_size = t1.m_fact_size; - unsigned t2_entry_size = t2.m_fact_size; - - unsigned t1idx = 0; - unsigned t1end = t1.m_data.after_last_offset(); - - TRACE("dl_table_relation", - tout << "joined_col_cnt: " << joined_col_cnt << "\n"; - tout << "t1_entry_size: " << t1_entry_size << "\n"; - tout << "t2_entry_size: " << t2_entry_size << "\n"; - t1.display(tout); - t2.display(tout); - tout << (&t1) << " " << (&t2) << " " << (&result) << "\n"; - ); - - if (joined_col_cnt == 0) { - unsigned t2idx = 0; - unsigned t2end = t2.m_data.after_last_offset(); - - for (; t1idx!=t1end; t1idx+=t1_entry_size) { - for (t2idx = 0; t2idx != t2end; t2idx += t2_entry_size) { - result.m_data.ensure_reserve(); - result.garbage_collect(); - char * res_reserve = result.m_data.get_reserve_ptr(); - char const* t1ptr = t1.get_at_offset(t1idx); - char const* t2ptr = t2.get_at_offset(t2idx); - if (tables_swapped) { - concatenate_rows(t2.m_column_layout, t1.m_column_layout, result.m_column_layout, - t2ptr, t1ptr, res_reserve, removed_cols); - } else { - concatenate_rows(t1.m_column_layout, t2.m_column_layout, result.m_column_layout, - t1ptr, t2ptr, res_reserve, removed_cols); - } - result.add_reserve_content(); - } - } - return; - } - - key_value t1_key; - t1_key.resize(joined_col_cnt); - key_indexer& t2_indexer = t2.get_key_indexer(joined_col_cnt, t2_joined_cols); - - bool key_modified = true; - key_indexer::query_result t2_offsets; - - for (; t1idx != t1end; t1idx += t1_entry_size) { - for (unsigned i = 0; i < joined_col_cnt; i++) { - table_element val = t1.m_column_layout.get(t1.get_at_offset(t1idx), t1_joined_cols[i]); - TRACE("dl_table_relation", tout << "val: " << val << " " << t1idx << " " << t1_joined_cols[i] << "\n";); - if (t1_key[i] != val) { - t1_key[i] = val; - key_modified = true; - } - } - if (key_modified) { - t2_offsets = t2_indexer.get_matching_offsets(t1_key); - key_modified = false; - } - - if (t2_offsets.empty()) { - continue; - } - - key_indexer::offset_iterator t2ofs_it = t2_offsets.begin(); - key_indexer::offset_iterator t2ofs_end = t2_offsets.end(); - for (; t2ofs_it != t2ofs_end; ++t2ofs_it) { - store_offset t2ofs = *t2ofs_it; - result.m_data.ensure_reserve(); - result.garbage_collect(); - char * res_reserve = result.m_data.get_reserve_ptr(); - char const * t1ptr = t1.get_at_offset(t1idx); - char const * t2ptr = t2.get_at_offset(t2ofs); - if (tables_swapped) { - concatenate_rows(t2.m_column_layout, t1.m_column_layout, result.m_column_layout, - t2ptr, t1ptr, res_reserve, removed_cols); - } else { - concatenate_rows(t1.m_column_layout, t2.m_column_layout, result.m_column_layout, - t1ptr, t2ptr, res_reserve, removed_cols); - } - result.add_reserve_content(); - } - } - } - - - // ----------------------------------- - // - // sparse_table_plugin - // - // ----------------------------------- - - sparse_table_plugin::sparse_table_plugin(relation_manager & manager) - : table_plugin(symbol("sparse"), manager) {} - - sparse_table_plugin::~sparse_table_plugin() { - reset(); - } - - void sparse_table_plugin::reset() { - table_pool::iterator it = m_pool.begin(); - table_pool::iterator end = m_pool.end(); - for (; it!=end; ++it) { - sp_table_vector * vect = it->m_value; - sp_table_vector::iterator it = vect->begin(); - sp_table_vector::iterator end = vect->end(); - for (; it!=end; ++it) { - (*it)->destroy(); //calling deallocate() would only put the table back into the pool - } - dealloc(vect); - } - m_pool.reset(); - } - - void sparse_table_plugin::garbage_collect() { - IF_VERBOSE(2, verbose_stream() << "garbage collecting "<< memory::get_allocation_size() << " bytes down to ";); - reset(); - IF_VERBOSE(2, verbose_stream() << memory::get_allocation_size() << " bytes\n";); - } - - void sparse_table_plugin::recycle(sparse_table * t) { - const table_signature & sig = t->get_signature(); - t->reset(); - - table_pool::entry * e = m_pool.insert_if_not_there2(sig, 0); - sp_table_vector * & vect = e->get_data().m_value; - if (vect == 0) { - vect = alloc(sp_table_vector); - } - IF_VERBOSE(12, verbose_stream() << "Recycle: " << t->get_size_estimate_bytes() << "\n";); - - vect->push_back(t); - } - - table_base * sparse_table_plugin::mk_empty(const table_signature & s) { - SASSERT(can_handle_signature(s)); - - sp_table_vector * vect; - if (!m_pool.find(s, vect) || vect->empty()) { - return alloc(sparse_table, *this, s); - } - sparse_table * res = vect->back(); - vect->pop_back(); - return res; - } - - sparse_table * sparse_table_plugin::mk_clone(const sparse_table & t) { - sparse_table * res = static_cast(mk_empty(t.get_signature())); - res->m_data = t.m_data; - return res; - } - - - bool sparse_table_plugin::join_involves_functional(const table_signature & s1, const table_signature & s2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if (col_cnt == 0) { - return false; - } - return counter().count(col_cnt, cols1).get_max_positive()>=s1.first_functional() - || counter().count(col_cnt, cols2).get_max_positive()>=s2.first_functional(); - } - - - class sparse_table_plugin::join_project_fn : public convenient_table_join_project_fn { - public: - join_project_fn(const table_signature & t1_sig, const table_signature & t2_sig, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols) - : convenient_table_join_project_fn(t1_sig, t2_sig, col_cnt, cols1, cols2, - removed_col_cnt, removed_cols) { - m_removed_cols.push_back(UINT_MAX); - } - - virtual table_base * operator()(const table_base & tb1, const table_base & tb2) { - - const sparse_table & t1 = static_cast(tb1); - const sparse_table & t2 = static_cast(tb2); - - sparse_table_plugin & plugin = t1.get_plugin(); - - sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); - - //If we join with some intersection, want to iterate over the smaller table and - //do indexing into the bigger one. If we simply do a product, we want the bigger - //one to be at the outer iteration (then the small one will hopefully fit into - //the cache) - if ( (t1.row_count() > t2.row_count()) == (!m_cols1.empty()) ) { - sparse_table::self_agnostic_join_project(t2, t1, m_cols1.size(), m_cols2.c_ptr(), - m_cols1.c_ptr(), m_removed_cols.c_ptr(), true, *res); - } - else { - sparse_table::self_agnostic_join_project(t1, t2, m_cols1.size(), m_cols1.c_ptr(), - m_cols2.c_ptr(), m_removed_cols.c_ptr(), false, *res); - } - TRACE("dl_table_relation", tb1.display(tout); tb2.display(tout); res->display(tout); ); - return res; - } - }; - - table_join_fn * sparse_table_plugin::mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - const table_signature & sig1 = t1.get_signature(); - const table_signature & sig2 = t2.get_signature(); - if (t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind() - || join_involves_functional(sig1, sig2, col_cnt, cols1, cols2)) { - //We also don't allow indexes on functional columns (and they are needed for joins) - return 0; - } - return mk_join_project_fn(t1, t2, col_cnt, cols1, cols2, 0, static_cast(0)); - } - - table_join_fn * sparse_table_plugin::mk_join_project_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols) { - const table_signature & sig1 = t1.get_signature(); - const table_signature & sig2 = t2.get_signature(); - if (t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind() - || removed_col_cnt == t1.get_signature().size()+t2.get_signature().size() - || join_involves_functional(sig1, sig2, col_cnt, cols1, cols2)) { - //We don't allow sparse tables with zero signatures (and project on all columns leads to such) - //We also don't allow indexes on functional columns. - return 0; - } - return alloc(join_project_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, - removed_col_cnt, removed_cols); - } - - class sparse_table_plugin::union_fn : public table_union_fn { - public: - virtual void operator()(table_base & tgt0, const table_base & src0, table_base * delta0) { - - sparse_table & tgt = static_cast(tgt0); - const sparse_table & src = static_cast(src0); - sparse_table * delta = static_cast(delta0); - - unsigned fact_size = tgt.m_fact_size; - const char* ptr = src.m_data.begin(); - const char* after_last=src.m_data.after_last(); - for (; ptradd_fact(ptr); - } - } - } - }; - - table_union_fn * sparse_table_plugin::mk_union_fn(const table_base & tgt, const table_base & src, - const table_base * delta) { - if (tgt.get_kind()!=get_kind() || src.get_kind()!=get_kind() - || (delta && delta->get_kind()!=get_kind()) - || tgt.get_signature()!=src.get_signature() - || (delta && delta->get_signature()!=tgt.get_signature())) { - return 0; - } - return alloc(union_fn); - } - - class sparse_table_plugin::project_fn : public convenient_table_project_fn { - const unsigned m_inp_col_cnt; - const unsigned m_removed_col_cnt; - const unsigned m_result_col_cnt; - public: - project_fn(const table_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) - : convenient_table_project_fn(orig_sig, removed_col_cnt, removed_cols), - m_inp_col_cnt(orig_sig.size()), - m_removed_col_cnt(removed_col_cnt), - m_result_col_cnt(orig_sig.size()-removed_col_cnt) { - SASSERT(removed_col_cnt>0); - } - - virtual void transform_row(const char * src, char * tgt, - const sparse_table::column_layout & src_layout, - const sparse_table::column_layout & tgt_layout) { - unsigned r_idx=0; - unsigned tgt_i=0; - for (unsigned i=0; i(tb); - - unsigned t_fact_size = t.m_fact_size; - - sparse_table_plugin & plugin = t.get_plugin(); - sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); - - const sparse_table::column_layout & src_layout = t.m_column_layout; - const sparse_table::column_layout & tgt_layout = res->m_column_layout; - - const char* t_ptr = t.m_data.begin(); - const char* t_end = t.m_data.after_last(); - for (; t_ptr!=t_end; t_ptr+=t_fact_size) { - SASSERT(t_ptrm_data.ensure_reserve(); - char * res_ptr = res->m_data.get_reserve_ptr(); - transform_row(t_ptr, res_ptr, src_layout, tgt_layout); - res->m_data.insert_reserve_content(); - } - return res; - } - }; - - table_transformer_fn * sparse_table_plugin::mk_project_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols) { - if (col_cnt == t.get_signature().size()) { - return 0; - } - return alloc(project_fn, t.get_signature(), col_cnt, removed_cols); - } - - - class sparse_table_plugin::select_equal_and_project_fn : public convenient_table_transformer_fn { - const unsigned m_col; - sparse_table::key_value m_key; - public: - select_equal_and_project_fn(const table_signature & orig_sig, table_element val, unsigned col) - : m_col(col) { - table_signature::from_project(orig_sig, 1, &col, get_result_signature()); - m_key.push_back(val); - } - - virtual table_base * operator()(const table_base & tb) { - const sparse_table & t = static_cast(tb); - - sparse_table_plugin & plugin = t.get_plugin(); - sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); - - const sparse_table::column_layout & t_layout = t.m_column_layout; - const sparse_table::column_layout & res_layout = res->m_column_layout; - unsigned t_cols = t_layout.size(); - - sparse_table::key_indexer & indexer = t.get_key_indexer(1, &m_col); - sparse_table::key_indexer::query_result t_offsets = indexer.get_matching_offsets(m_key); - if (t_offsets.empty()) { - //no matches - return res; - } - sparse_table::key_indexer::offset_iterator ofs_it=t_offsets.begin(); - sparse_table::key_indexer::offset_iterator ofs_end=t_offsets.end(); - - for (; ofs_it!=ofs_end; ++ofs_it) { - sparse_table::store_offset t_ofs = *ofs_it; - const char * t_ptr = t.get_at_offset(t_ofs); - - res->m_data.ensure_reserve(); - char * res_reserve = res->m_data.get_reserve_ptr(); - - unsigned res_i = 0; - for (unsigned i=0; iadd_reserve_content(); - } - return res; - } - }; - - table_transformer_fn * sparse_table_plugin::mk_select_equal_and_project_fn(const table_base & t, - const table_element & value, unsigned col) { - if (t.get_kind()!=get_kind() || t.get_signature().size() == 1 || col>=t.get_signature().first_functional()) { - //We don't allow sparse tables with zero signatures (and project on a single - //column table produces one). - //We also don't allow indexes on functional columns. And our implementation of - //select_equal_and_project uses index on \c col. - return 0; - } - return alloc(select_equal_and_project_fn, t.get_signature(), value, col); - } - - - class sparse_table_plugin::rename_fn : public convenient_table_rename_fn { - unsigned_vector m_out_of_cycle; - public: - rename_fn(const table_signature & orig_sig, unsigned permutation_cycle_len, const unsigned * permutation_cycle) - : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle) { - SASSERT(permutation_cycle_len>=2); - idx_set cycle_cols; - for (unsigned i=0; i < permutation_cycle_len; ++i) { - cycle_cols.insert(permutation_cycle[i]); - } - for (unsigned i=0; i < orig_sig.size(); ++i) { - if (!cycle_cols.contains(i)) { - m_out_of_cycle.push_back(i); - } - } - } - - void transform_row(const char * src, char * tgt, - const sparse_table::column_layout & src_layout, - const sparse_table::column_layout & tgt_layout) { - - for (unsigned i=1; i < m_cycle.size(); ++i) { - tgt_layout.set(tgt, m_cycle[i-1], src_layout.get(src, m_cycle[i])); - } - tgt_layout.set(tgt, m_cycle[m_cycle.size()-1], src_layout.get(src, m_cycle[0])); - - unsigned_vector::const_iterator it = m_out_of_cycle.begin(); - unsigned_vector::const_iterator end = m_out_of_cycle.end(); - for (; it!=end; ++it) { - unsigned col = *it; - tgt_layout.set(tgt, col, src_layout.get(src, col)); - } - } - - virtual table_base * operator()(const table_base & tb) { - - const sparse_table & t = static_cast(tb); - - unsigned t_fact_size = t.m_fact_size; - - sparse_table_plugin & plugin = t.get_plugin(); - sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); - - unsigned res_fact_size = res->m_fact_size; - unsigned res_data_size = res_fact_size*t.row_count(); - - res->m_data.resize_data(res_data_size); - - //here we can separate data creatin and insertion into hashmap, since we know - //that no row will become duplicit - - //create the data - const char* t_ptr = t.m_data.begin(); - char* res_ptr = res->m_data.begin(); - char* res_end = res_ptr+res_data_size; - for (; res_ptr!=res_end; t_ptr+=t_fact_size, res_ptr+=res_fact_size) { - transform_row(t_ptr, res_ptr, t.m_column_layout, res->m_column_layout); - } - - //and insert them into the hash-map - for (unsigned i=0; i!=res_data_size; i+=res_fact_size) { - TRUSTME(res->m_data.insert_offset(i)); - } - - return res; - } - }; - - table_transformer_fn * sparse_table_plugin::mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle) { - if (t.get_kind()!=get_kind()) { - return 0; - } - return alloc(rename_fn, t.get_signature(), permutation_cycle_len, permutation_cycle); - } - - class sparse_table_plugin::negation_filter_fn : public convenient_table_negation_filter_fn { - typedef sparse_table::store_offset store_offset; - typedef sparse_table::key_value key_value; - typedef sparse_table::key_indexer key_indexer; - - bool m_joining_neg_non_functional; - - /** - Used by \c collect_intersection_offsets function. - If tgt_is_first is false, contains the same items as \c res. - */ - idx_set m_intersection_content; - - public: - negation_filter_fn(const table_base & tgt, const table_base & neg, - unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) - : convenient_table_negation_filter_fn(tgt, neg, joined_col_cnt, t_cols, negated_cols) { - unsigned neg_fisrt_func = neg.get_signature().first_functional(); - counter ctr; - ctr.count(m_cols2); - m_joining_neg_non_functional = ctr.get_max_counter_value() == 1 - && ctr.get_positive_count() == neg_fisrt_func - && (neg_fisrt_func == 0 || ctr.get_max_positive() == neg_fisrt_func-1); - } - - /** - Collect offsets of rows in \c t1 or \c t2 (depends on whether \c tgt_is_first is true or false) - that have a match in the other table into \c res. Offsets in \c res are in ascending order. - */ - void collect_intersection_offsets(const sparse_table & t1, const sparse_table & t2, - bool tgt_is_first, svector & res) { - SASSERT(res.empty()); - - if (!tgt_is_first) { - m_intersection_content.reset(); - } - - unsigned joined_col_cnt = m_cols1.size(); - unsigned t1_entry_size = t1.m_data.entry_size(); - - const unsigned * cols1 = tgt_is_first ? m_cols1.c_ptr() : m_cols2.c_ptr(); - const unsigned * cols2 = tgt_is_first ? m_cols2.c_ptr() : m_cols1.c_ptr(); - - key_value t1_key; - t1_key.resize(joined_col_cnt); - key_indexer & t2_indexer = t2.get_key_indexer(joined_col_cnt, cols2); - - bool key_modified=true; - key_indexer::query_result t2_offsets; - store_offset t1_after_last = t1.m_data.after_last_offset(); - for (store_offset t1_ofs=0; t1_ofs(tgt0); - const sparse_table & neg = static_cast(neg0); - - if (m_cols1.size() == 0) { - if (!neg.empty()) { - tgt.reset(); - } - return; - } - - svector to_remove; //offsets here are in increasing order - - //We don't do just the simple tgt.row_count()>neg.row_count() because the swapped case is - //more expensive. The constant 4 is, however, just my guess what the ratio might be. - if (tgt.row_count()/4>neg.row_count()) { - collect_intersection_offsets(neg, tgt, false, to_remove); - } - else { - collect_intersection_offsets(tgt, neg, true, to_remove); - } - - if (to_remove.empty()) { - return; - } - - //the largest offsets are at the end, so we can remove them one by one - while(!to_remove.empty()) { - store_offset removed_ofs = to_remove.back(); - to_remove.pop_back(); - tgt.m_data.remove_offset(removed_ofs); - } - tgt.reset_indexes(); - } - - }; - - table_intersection_filter_fn * sparse_table_plugin::mk_filter_by_negation_fn(const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols) { - if (!check_kind(t) || !check_kind(negated_obj) - || join_involves_functional(t.get_signature(), negated_obj.get_signature(), joined_col_cnt, - t_cols, negated_cols) ) { - return 0; - } - return alloc(negation_filter_fn, t, negated_obj, joined_col_cnt, t_cols, negated_cols); - } - - unsigned sparse_table::get_size_estimate_bytes() const { - unsigned sz = 0; - sz += m_data.get_size_estimate_bytes(); - sz += m_key_indexes.capacity()*8; // TBD - return sz; - } - - -}; - diff --git a/src/muz/dl_sparse_table.h b/src/muz/dl_sparse_table.h deleted file mode 100644 index 010277b6b..000000000 --- a/src/muz/dl_sparse_table.h +++ /dev/null @@ -1,480 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_table.h - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-01. - -Revision History: - ---*/ - -#ifndef _DL_SPARSE_TABLE_H_ -#define _DL_SPARSE_TABLE_H_ - -#include -#include -#include - -#include "ast.h" -#include "bit_vector.h" -#include "buffer.h" -#include "hashtable.h" -#include "map.h" -#include "ref_vector.h" -#include "vector.h" - -#include "dl_base.h" - - -namespace datalog { - class sparse_table; - - class sparse_table_plugin : public table_plugin { - friend class sparse_table; - protected: - class join_project_fn; - class union_fn; - class transformer_fn; - class rename_fn; - class project_fn; - class negation_filter_fn; - class select_equal_and_project_fn; - - typedef ptr_vector sp_table_vector; - typedef map table_pool; - - table_pool m_pool; - - void recycle(sparse_table * t); - - void garbage_collect(); - - void reset(); - - static bool join_involves_functional(const table_signature & s1, const table_signature & s2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - - public: - typedef sparse_table table; - - sparse_table_plugin(relation_manager & manager); - ~sparse_table_plugin(); - - virtual bool can_handle_signature(const table_signature & s) - { return s.size()>0; } - - virtual table_base * mk_empty(const table_signature & s); - sparse_table * mk_clone(const sparse_table & t); - - protected: - virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols); - virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, - const table_base * delta); - virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t, - const table_element & value, unsigned col); - virtual table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); - }; - - class entry_storage { - public: - typedef unsigned store_offset; - private: - typedef svector storage; - - class offset_hash_proc { - storage & m_storage; - unsigned m_unique_entry_size; - public: - offset_hash_proc(storage & s, unsigned unique_entry_sz) - : m_storage(s), m_unique_entry_size(unique_entry_sz) {} - unsigned operator()(store_offset ofs) const { - return string_hash(m_storage.c_ptr()+ofs, m_unique_entry_size, 0); - } - }; - - class offset_eq_proc { - storage & m_storage; - unsigned m_unique_entry_size; - public: - offset_eq_proc(storage & s, unsigned unique_entry_sz) - : m_storage(s), m_unique_entry_size(unique_entry_sz) {} - bool operator()(store_offset o1, store_offset o2) const { - const char * base = m_storage.c_ptr(); - return memcmp(base+o1, base+o2, m_unique_entry_size)==0; - } - }; - - typedef hashtable storage_indexer; - - static const store_offset NO_RESERVE = UINT_MAX; - - unsigned m_entry_size; - unsigned m_unique_part_size; - unsigned m_data_size; - /** - Invariant: Every or all but one blocks of length \c m_entry_size in the \c m_data vector - are unique sequences of bytes and have their offset stored in the \c m_data_indexer hashtable. - If the offset of the last block is not stored in the hashtable, it is stored in the \c m_reserve - variable. Otherwise \c m_reserve==NO_RESERVE. - - The size of m_data is actually 8 bytes larger than stated in m_data_size, so that we may - deref an uint64 pointer at the end of the array. - */ - storage m_data; - storage_indexer m_data_indexer; - store_offset m_reserve; - public: - entry_storage(unsigned entry_size, unsigned functional_size = 0, unsigned init_size = 0) - : m_entry_size(entry_size), - m_unique_part_size(entry_size-functional_size), - m_data_indexer(next_power_of_two(std::max(8u,init_size)), - offset_hash_proc(m_data, m_unique_part_size), offset_eq_proc(m_data, m_unique_part_size)), - m_reserve(NO_RESERVE) { - SASSERT(entry_size>0); - SASSERT(functional_size<=entry_size); - resize_data(init_size); - resize_data(0); - } - entry_storage(const entry_storage &s) - : m_entry_size(s.m_entry_size), - m_unique_part_size(s.m_unique_part_size), - m_data_size(s.m_data_size), - m_data(s.m_data), - m_data_indexer(next_power_of_two(std::max(8u,s.entry_count())), - offset_hash_proc(m_data, m_unique_part_size), offset_eq_proc(m_data, m_unique_part_size)), - m_reserve(s.m_reserve) { - store_offset after_last=after_last_offset(); - for(store_offset i=0; i(this)->get(ofs); } - - unsigned entry_count() const { return m_data_indexer.size(); } - - store_offset after_last_offset() const { - return (m_reserve==NO_RESERVE) ? m_data_size : m_reserve; - } - - char * begin() { return get(0); } - const char * begin() const { return get(0); } - const char * after_last() const { return get(after_last_offset()); } - - - bool has_reserve() const { return m_reserve!=NO_RESERVE; } - store_offset reserve() const { SASSERT(has_reserve()); return m_reserve; } - - void ensure_reserve() { - if(has_reserve()) { - SASSERT(m_reserve==m_data_size-m_entry_size); - return; - } - m_reserve=m_data_size; - resize_data(m_data_size+m_entry_size); - } - - /** - \brief Return pointer to the reserve. - - The reserve must exist when the function is called. - */ - char * get_reserve_ptr() { - SASSERT(has_reserve()); - return &m_data.get(reserve()); - } - - bool reserve_content_already_present() const { - SASSERT(has_reserve()); - return m_data_indexer.contains(reserve()); - } - - bool find_reserve_content(store_offset & result) const { - SASSERT(has_reserve()); - storage_indexer::entry * indexer_entry = m_data_indexer.find_core(reserve()); - if(!indexer_entry) { - return false; - } - result = indexer_entry->get_data(); - return true; - } - - /** - \brief Write fact \c f into the reserve at the end of the \c m_data storage. - - If the reserve does not exist, this function creates it. - */ - void write_into_reserve(const char * data) { - ensure_reserve(); - memcpy(get_reserve_ptr(), data, m_entry_size); - } - - /** - \brief If the fact in reserve is not in the table, insert it there and return true; - otherwise return false. - - When a fact is inserted into the table, the reserve becomes part of the table and - is no longer a reserve. - */ - bool insert_reserve_content(); - store_offset insert_or_get_reserve_content(); - bool remove_reserve_content(); - /** - Remove data at the offset \c ofs. - - Data with offset lower than \c ofs are not be modified by this function, data with - higher offset may be moved. - */ - void remove_offset(store_offset ofs); - - - //the following two operations allow breaking of the object invariant! - void resize_data(unsigned sz) { - m_data_size = sz; - m_data.resize(sz + sizeof(uint64)); - } - - bool insert_offset(store_offset ofs) { - return m_data_indexer.insert_if_not_there(ofs)==ofs; - } - }; - - class sparse_table : public table_base { - friend class sparse_table_plugin; - friend class sparse_table_plugin::join_project_fn; - friend class sparse_table_plugin::union_fn; - friend class sparse_table_plugin::transformer_fn; - friend class sparse_table_plugin::rename_fn; - friend class sparse_table_plugin::project_fn; - friend class sparse_table_plugin::negation_filter_fn; - friend class sparse_table_plugin::select_equal_and_project_fn; - - class our_iterator_core; - class key_indexer; - class general_key_indexer; - class full_signature_key_indexer; - typedef entry_storage::store_offset store_offset; - - - class column_info { - unsigned m_big_offset; - unsigned m_small_offset; - uint64 m_mask; - uint64 m_write_mask; - public: - unsigned m_offset; //!< in bits - unsigned m_length; //!< in bits - - column_info(unsigned offset, unsigned length) \ - : m_big_offset(offset/8), - m_small_offset(offset%8), - m_mask( length==64 ? ULLONG_MAX : (static_cast(1)<(rec+m_big_offset); - uint64 res = *ptr; - res>>=m_small_offset; - res&=m_mask; - return res; - } - void set(char * rec, table_element val) const { - SASSERT( (val&~m_mask)==0 ); //the value fits into the column - uint64 * ptr = reinterpret_cast(rec+m_big_offset); - *ptr&=m_write_mask; - *ptr|=val< { - - void make_byte_aligned_end(unsigned col_index); - public: - - unsigned m_entry_size; - /** - Number of last bytes which correspond to functional columns in the signature. - */ - unsigned m_functional_part_size; - unsigned m_functional_col_cnt; - - column_layout(const table_signature & sig); - - table_element get(const char * rec, unsigned col) const { - return (*this)[col].get(rec); - } - void set(char * rec, unsigned col, table_element val) const { - return (*this)[col].set(rec, val); - } - }; - - - typedef svector key_spec; //sequence of columns in a key - typedef svector key_value; //values of key columns - typedef map, - vector_eq_proc > key_index_map; - - static const store_offset NO_RESERVE = UINT_MAX; - - column_layout m_column_layout; - unsigned m_fact_size; - entry_storage m_data; - mutable key_index_map m_key_indexes; - - - const char * get_at_offset(store_offset i) const { - return m_data.get(i); - } - - table_element get_cell(store_offset ofs, unsigned column) const { - return m_column_layout.get(m_data.get(ofs), column); - } - - void set_cell(store_offset ofs, unsigned column, table_element val) { - m_column_layout.set(m_data.get(ofs), column, val); - } - - void write_into_reserve(const table_element* f); - - /** - \brief Return reference to an indexer over columns in \c key_cols. - - An indexer can retrieve a sequence of offsets that with \c key_cols columns equal to - the specified key. Indexers are populated lazily -- they remember the position of the - last fact they contain, and when an indexer is retrieved by the \c get_key_indexer function, - all the new facts are added into the indexer. - - When a fact is removed from the table, all indexers are destroyed. This is not an extra - expense in the current use scenario, because we first perform all fact removals and do the - joins only after that (joins are the only operations that lead to index construction). - */ - key_indexer& get_key_indexer(unsigned key_len, const unsigned * key_cols) const; - - void reset_indexes(); - - static void copy_columns(const column_layout & src_layout, const column_layout & dest_layout, - unsigned start_index, unsigned after_last, const char * src, char * dest, - unsigned & dest_idx, unsigned & pre_projection_idx, const unsigned * & next_removed); - - /** - \c array \c removed_cols contains column indexes to be removed in ascending order and - is terminated by a number greated than the highest column index of a join the the two tables. - This is to simplify the traversal of the array when building facts. - */ - static void concatenate_rows(const column_layout & layout1, const column_layout & layout2, - const column_layout & layout_res, const char * ptr1, const char * ptr2, char * res, - const unsigned * removed_cols); - - /** - \brief Perform join-project between t1 and t2 iterating through t1 and retrieving relevant - columns from t2 using indexing. - - \c array \c removed_cols contains column indexes to be removed in ascending order and - is terminated by a number greated than the highest column index of a join the the two tables. - This is to simplify the traversal of the array when building facts. - - \c tables_swapped value means that the resulting facts should contain facts from t2 first, - instead of the default behavior that would concatenate the two facts as \c (t1,t2). - - \remark The function is called \c self_agnostic_join since, unlike the virtual method - \c join, it is static and therefore allows to easily swap the roles of the two joined - tables (the indexed and iterated one) in a way that is expected to give better performance. - */ - static void self_agnostic_join_project(const sparse_table & t1, const sparse_table & t2, - unsigned joined_col_cnt, const unsigned * t1_joined_cols, const unsigned * t2_joined_cols, - const unsigned * removed_cols, bool tables_swapped, sparse_table & result); - - - /** - If the fact at \c data (in table's native representation) is not in the table, - add it and return true. Otherwise return false. - */ - bool add_fact(const char * data); - - bool add_reserve_content(); - - void garbage_collect(); - - sparse_table(sparse_table_plugin & p, const table_signature & sig, unsigned init_capacity=0); - sparse_table(const sparse_table & t); - virtual ~sparse_table(); - public: - - virtual void deallocate() { - get_plugin().recycle(this); - } - - unsigned row_count() const { return m_data.entry_count(); } - - sparse_table_plugin & get_plugin() const - { return static_cast(table_base::get_plugin()); } - - virtual bool empty() const { return row_count()==0; } - virtual void add_fact(const table_fact & f); - virtual bool contains_fact(const table_fact & f) const; - virtual bool fetch_fact(table_fact & f) const; - virtual void ensure_fact(const table_fact & f); - virtual void remove_fact(const table_element* fact); - virtual void reset(); - - virtual table_base * clone() const; - - virtual table_base::iterator begin() const; - virtual table_base::iterator end() const; - - virtual unsigned get_size_estimate_rows() const { return row_count(); } - virtual unsigned get_size_estimate_bytes() const; - virtual bool knows_exact_size() const { return true; } - }; - - }; - - #endif /* _DL_SPARSE_TABLE_H_ */ diff --git a/src/muz/dl_table.cpp b/src/muz/dl_table.cpp deleted file mode 100644 index 99a868bea..000000000 --- a/src/muz/dl_table.cpp +++ /dev/null @@ -1,772 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_table.cpp - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-01. - -Revision History: - ---*/ - -#include"dl_context.h" -#include"dl_util.h" -#include"dl_table.h" - -namespace datalog { - - // ----------------------------------- - // - // hashtable_table - // - // ----------------------------------- - - table_base * hashtable_table_plugin::mk_empty(const table_signature & s) { - SASSERT(can_handle_signature(s)); - return alloc(hashtable_table, *this, s); - } - - - class hashtable_table_plugin::join_fn : public convenient_table_join_fn { - unsigned m_joined_col_cnt; - public: - join_fn(const table_signature & t1_sig, const table_signature & t2_sig, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) - : convenient_table_join_fn(t1_sig, t2_sig, col_cnt, cols1, cols2), - m_joined_col_cnt(col_cnt) {} - - virtual table_base * operator()(const table_base & t1, const table_base & t2) { - - const hashtable_table & ht1 = static_cast(t1); - const hashtable_table & ht2 = static_cast(t2); - - hashtable_table_plugin & plugin = ht1.get_plugin(); - - hashtable_table * res = static_cast(plugin.mk_empty(get_result_signature())); - - hashtable_table::storage::iterator els1it = ht1.m_data.begin(); - hashtable_table::storage::iterator els1end = ht1.m_data.end(); - hashtable_table::storage::iterator els2end = ht2.m_data.end(); - - table_fact acc; - - for(; els1it!=els1end; ++els1it) { - const table_fact & row1 = *els1it; - - hashtable_table::storage::iterator els2it = ht2.m_data.begin(); - for(; els2it!=els2end; ++els2it) { - const table_fact & row2 = *els2it; - - bool match=true; - for(unsigned i=0; im_data.insert(acc); - } - } - return res; - } - }; - - table_join_fn * hashtable_table_plugin::mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if(t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind()) { - return 0; - } - return alloc(join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); - } - - - class hashtable_table::our_iterator_core : public iterator_core { - const hashtable_table & m_parent; - storage::iterator m_inner; - storage::iterator m_end; - - class our_row : public row_interface { - const our_iterator_core & m_parent; - public: - our_row(const our_iterator_core & parent) : row_interface(parent.m_parent), m_parent(parent) {} - - virtual void get_fact(table_fact & result) const { - result = *m_parent.m_inner; - } - virtual table_element operator[](unsigned col) const { - return (*m_parent.m_inner)[col]; - } - - }; - - our_row m_row_obj; - - public: - our_iterator_core(const hashtable_table & t, bool finished) : - m_parent(t), m_inner(finished ? t.m_data.end() : t.m_data.begin()), - m_end(t.m_data.end()), m_row_obj(*this) {} - - virtual bool is_finished() const { - return m_inner==m_end; - } - - virtual row_interface & operator*() { - SASSERT(!is_finished()); - return m_row_obj; - } - virtual void operator++() { - SASSERT(!is_finished()); - ++m_inner; - } - }; - - - - table_base::iterator hashtable_table::begin() const { - return mk_iterator(alloc(our_iterator_core, *this, false)); - } - - table_base::iterator hashtable_table::end() const { - return mk_iterator(alloc(our_iterator_core, *this, true)); - } - - // ----------------------------------- - // - // bitvector_table - // - // ----------------------------------- - - bool bitvector_table_plugin::can_handle_signature(const table_signature & sig) { - if(sig.functional_columns()!=0) { - return false; - } - unsigned cols = sig.size(); - unsigned shift = 0; - for (unsigned i = 0; i < cols; ++i) { - unsigned s = static_cast(sig[i]); - if (s != sig[i] || !is_power_of_two(s)) { - return false; - } - unsigned num_bits = 0; - unsigned bit_pos = 1; - for (num_bits = 1; num_bits < 32; ++num_bits) { - if (bit_pos & s) { - break; - } - bit_pos <<= 1; - } - shift += num_bits; - if (shift >= 32) { - return false; - } - } - return true; - } - - table_base * bitvector_table_plugin::mk_empty(const table_signature & s) { - SASSERT(can_handle_signature(s)); - return alloc(bitvector_table, *this, s); - } - - class bitvector_table::bv_iterator : public iterator_core { - - bitvector_table const& m_bv; - unsigned m_offset; - - class our_row : public caching_row_interface { - const bv_iterator& m_parent; - public: - our_row(const bv_iterator & p) : caching_row_interface(p.m_bv), m_parent(p) {} - virtual void get_fact(table_fact& result) const { - if (result.size() < size()) { - result.resize(size(), 0); - } - m_parent.m_bv.offset2fact(m_parent.m_offset, result); - } - }; - our_row m_row_obj; - - public: - bv_iterator(const bitvector_table& bv, bool end): - m_bv(bv), m_offset(end?m_bv.m_bv.size():0), m_row_obj(*this) - { - if (!is_finished() && !m_bv.m_bv.get(m_offset)) { - ++(*this); - } - } - - virtual bool is_finished() const { - return m_offset == m_bv.m_bv.size(); - } - - virtual row_interface & operator*() { - SASSERT(!is_finished()); - return m_row_obj; - } - virtual void operator++() { - SASSERT(!is_finished()); - ++m_offset; - while (!is_finished() && !m_bv.m_bv.get(m_offset)) { - ++m_offset; - } - m_row_obj.reset(); - } - }; - - bitvector_table::bitvector_table(bitvector_table_plugin & plugin, const table_signature & sig) - : table_base(plugin, sig) { - SASSERT(plugin.can_handle_signature(sig)); - - m_num_cols = sig.size(); - unsigned shift = 0; - for (unsigned i = 0; i < m_num_cols; ++i) { - unsigned s = static_cast(sig[i]); - if (s != sig[i] || !is_power_of_two(s)) { - throw default_exception("bit-vector table is specialized to small domains that are powers of two"); - } - m_shift.push_back(shift); - m_mask.push_back(s - 1); - unsigned num_bits = 0; - unsigned bit_pos = 1; - for (num_bits = 1; num_bits < 32; ++num_bits) { - if (bit_pos & s) { - break; - } - bit_pos <<= 1; - } - shift += num_bits; - if (shift >= 32) { - throw default_exception("bit-vector table is specialized to small domains that are powers of two"); - } - m_bv.reserve(1 << shift); - } - } - - unsigned bitvector_table::fact2offset(const table_element* f) const { - unsigned result = 0; - for (unsigned i = 0; i < m_num_cols; ++i) { - SASSERT(f[i]> m_shift[i]); - } - } - - void bitvector_table::add_fact(const table_fact & f) { - m_bv.set(fact2offset(f.c_ptr())); - } - - void bitvector_table::remove_fact(const table_element* fact) { - m_bv.unset(fact2offset(fact)); - } - - bool bitvector_table::contains_fact(const table_fact & f) const { - return m_bv.get(fact2offset(f.c_ptr())); - } - - table_base::iterator bitvector_table::begin() const { - return mk_iterator(alloc(bv_iterator, *this, false)); - } - - table_base::iterator bitvector_table::end() const { - return mk_iterator(alloc(bv_iterator, *this, true)); - } - - - - - // ----------------------------------- - // - // equivalence_table - // - // ----------------------------------- - - bool equivalence_table_plugin::can_handle_signature(const table_signature & sig) { - return sig.functional_columns() == 0 && sig.size() == 2 && sig[0] < UINT_MAX && sig[0] == sig[1]; - } - - bool equivalence_table_plugin::is_equivalence_table(table_base const& tbl) const { - if (tbl.get_kind() != get_kind()) return false; - equivalence_table const& t = static_cast(tbl); - return !t.is_sparse(); - } - - table_base * equivalence_table_plugin::mk_empty(const table_signature & s) { - TRACE("dl", for (unsigned i = 0; i < s.size(); ++i) tout << s[i] << " "; tout << "\n";); - SASSERT(can_handle_signature(s)); - return alloc(equivalence_table, *this, s); - } - - class equivalence_table_plugin::select_equal_and_project_fn : public table_transformer_fn { - unsigned m_val; - table_sort m_sort; - public: - select_equal_and_project_fn(const table_signature & sig, table_element val, unsigned col) - : m_val(static_cast(val)), - m_sort(sig[0]) { - SASSERT(val <= UINT_MAX); - SASSERT(col == 0 || col == 1); - SASSERT(sig.functional_columns() == 0); - SASSERT(sig.size() == 2); - SASSERT(sig[0] < UINT_MAX && sig[0] == sig[1]); - } - - virtual table_base* operator()(const table_base& tb) { - TRACE("dl", tout << "\n";); - table_plugin & plugin = tb.get_plugin(); - table_plugin* rp = plugin.get_manager().get_table_plugin(symbol("sparse")); - SASSERT(rp); - table_signature sig; - sig.push_back(m_sort); - table_base* result = rp->mk_empty(sig); - equivalence_table const& eq_table = static_cast(tb); - if (eq_table.is_valid(m_val)) { - table_fact fact; - fact.resize(1); - unsigned r = m_val; - do { - fact[0] = r; - result->add_fact(fact); - r = eq_table.m_uf.next(r); - } - while (r != m_val); - } - TRACE("dl", tb.display(tout << "src:\n"); result->display(tout << "result\n");); - return result; - } - }; - - table_transformer_fn * equivalence_table_plugin::mk_select_equal_and_project_fn( - const table_base & t, const table_element & value, unsigned col) { - return alloc(select_equal_and_project_fn, t.get_signature(), value, col); - } - - class equivalence_table_plugin::union_fn : public table_union_fn { - - equivalence_table_plugin& m_plugin; - - - void mk_union1(equivalence_table & tgt, const equivalence_table & src, table_base * delta) { - unsigned num_vars = src.m_uf.get_num_vars(); - table_fact fact; - fact.resize(2); - for (unsigned i = 0; i < num_vars; ++i) { - if (src.is_valid(i) && src.m_uf.find(i) == i) { - fact[0] = i; - equivalence_table::class_iterator it = src.class_begin(i); - equivalence_table::class_iterator end = src.class_end(i); - for (; it != end; ++it) { - fact[1] = *it; - if (!tgt.contains_fact(fact)) { - tgt.add_fact(fact); - if (delta) { - delta->add_fact(fact); - } - } - } - } - } - } - - void mk_union2(equivalence_table & tgt, const table_base & src, table_base * delta) { - table_fact fact; - table_base::iterator it = src.begin(), end = src.end(); - for (; it != end; ++it) { - it->get_fact(fact); - if (!tgt.contains_fact(fact)) { - tgt.add_fact(fact); - if (delta) { - delta->add_fact(fact); - TRACE("dl", - tout << "Add: "; - for (unsigned i = 0; i < fact.size(); ++i) tout << fact[i] << " "; - tout << "\n";); - } - } - } - } - - public: - union_fn(equivalence_table_plugin& p) : m_plugin(p) {} - - virtual void operator()(table_base & tgt0, const table_base & src, table_base * delta) { - TRACE("dl", tout << "union\n";); - equivalence_table & tgt = static_cast(tgt0); - if (m_plugin.is_equivalence_table(src)) { - mk_union1(tgt, static_cast(src), delta); - } - else { - mk_union2(tgt, src, delta); - } - TRACE("dl", src.display(tout << "src\n"); tgt.display(tout << "tgt\n"); - if (delta) delta->display(tout << "delta\n");); - } - }; - - table_union_fn * equivalence_table_plugin::mk_union_fn( - const table_base & tgt, const table_base & src, const table_base * delta) { - if (!is_equivalence_table(tgt) || - tgt.get_signature() != src.get_signature() || - (delta && delta->get_signature() != tgt.get_signature())) { - return 0; - } - return alloc(union_fn,*this); - } - - class equivalence_table_plugin::join_project_fn : public convenient_table_join_project_fn { - equivalence_table_plugin& m_plugin; - public: - join_project_fn( - equivalence_table_plugin& plugin, const table_signature & t1_sig, const table_signature & t2_sig, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols) - : convenient_table_join_project_fn(t1_sig, t2_sig, col_cnt, cols1, cols2, removed_col_cnt, removed_cols), - m_plugin(plugin) { - m_removed_cols.push_back(UINT_MAX); - } - - virtual table_base * operator()(const table_base & tb1, const table_base & tb2) { - SASSERT(m_cols1.size() == 1); - const table_signature & res_sign = get_result_signature(); - table_plugin * plugin = &tb1.get_plugin(); - if (!plugin->can_handle_signature(res_sign)) { - plugin = &tb2.get_plugin(); - if (!plugin->can_handle_signature(res_sign)) { - plugin = &tb1.get_manager().get_appropriate_plugin(res_sign); - } - } - SASSERT(plugin->can_handle_signature(res_sign)); - table_base * result = plugin->mk_empty(res_sign); - - if (m_plugin.is_equivalence_table(tb1)) { - mk_join(0, m_cols1[0], static_cast(tb1), - 2, m_cols2[0], tb2, result); - } - else if (m_plugin.is_equivalence_table(tb2)) { - mk_join(tb1.get_signature().size(), m_cols2[0], static_cast(tb2), - 0, m_cols1[0], tb1, result); - } - else { - UNREACHABLE(); - } - TRACE("dl", tb1.display(tout << "tb1\n"); tb2.display(tout << "tb2\n"); result->display(tout << "result\n");); - return result; - } - - private: - table_base * mk_join(unsigned offs1, unsigned col1, equivalence_table const & t1, - unsigned offs2, unsigned col2, table_base const& t2, table_base* res) { - table_base::iterator els2it = t2.begin(); - table_base::iterator els2end = t2.end(); - - table_fact acc, proj; - acc.resize(t1.get_signature().size() + t2.get_signature().size()); - - for(; els2it != els2end; ++els2it) { - const table_base::row_interface & row2 = *els2it; - table_element const& e2 = row2[col2]; - equivalence_table::class_iterator it = t1.class_begin(e2); - equivalence_table::class_iterator end = t1.class_end(e2); - if (it != end) { - for (unsigned i = 0; i < row2.size(); ++i) { - acc[i+offs2] = row2[i]; - } - } - for (; it != end; ++it) { - acc[offs1+col1] = e2; - acc[offs1+1-col1] = *it; - mk_project(acc, proj); - TRACE("dl", for (unsigned i = 0; i < proj.size(); ++i) tout << proj[i] << " "; tout << "\n";); - res->add_fact(proj); - } - } - return res; - } - - virtual void mk_project(table_fact const & f, table_fact & p) const { - unsigned sz = f.size(); - p.reset(); - for (unsigned i = 0, r = 0; i < sz; ++i) { - if (r < m_removed_cols.size() && m_removed_cols[r] == i) { - ++r; - } - else { - p.push_back(f[i]); - } - } - } - - - }; - - table_join_fn * equivalence_table_plugin::mk_join_project_fn( - const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols) { - if (col_cnt != 1) { - TRACE("dl", tout << "WARNING: join_project on multiple columns is not implemented\n";); - return 0; - } - if (is_equivalence_table(t1) || is_equivalence_table(t2)) { - return alloc(join_project_fn, *this, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, - removed_col_cnt, removed_cols); - } - return 0; - } - - class equivalence_table::eq_iterator : public iterator_core { - - equivalence_table const& m_eq; - unsigned m_last; - unsigned m_current; - unsigned m_next; - - class our_row : public caching_row_interface { - const eq_iterator& m_parent; - public: - our_row(const eq_iterator & p) : caching_row_interface(p.m_eq), m_parent(p) {} - - virtual void get_fact(table_fact& result) const { - if (result.size() < size()) { - result.resize(size(), 0); - } - result[0] = m_parent.m_current; - result[1] = m_parent.m_next; - } - - virtual table_element operator[](unsigned col) const { - if (col == 0) return m_parent.m_current; - if (col == 1) return m_parent.m_next; - UNREACHABLE(); - return 0; - } - - }; - our_row m_row_obj; - - public: - eq_iterator(const equivalence_table& eq, bool end): - m_eq(eq), - m_last(eq.m_uf.get_num_vars()), - m_current(end?m_last:0), - m_next(0), - m_row_obj(*this) - { - while (m_current < m_last && !m_eq.is_valid(m_current)) { - m_current++; - m_next = m_current; - } - } - - virtual bool is_finished() const { - return m_current == m_last; - } - - virtual row_interface & operator*() { - SASSERT(!is_finished()); - return m_row_obj; - } - - virtual void operator++() { - SASSERT(!is_finished()); - m_next = m_eq.m_uf.next(m_next); - if (m_next == m_current) { - do { - m_current++; - m_next = m_current; - } - while (m_current < m_last && !m_eq.is_valid(m_current)); - } - } - }; - - equivalence_table::equivalence_table(equivalence_table_plugin & plugin, const table_signature & sig) - : table_base(plugin, sig), m_uf(m_ctx), m_sparse(0) { - SASSERT(plugin.can_handle_signature(sig)); - } - - equivalence_table::~equivalence_table() { - if (is_sparse()) { - m_sparse->deallocate(); - } - } - - - void equivalence_table::add_fact(const table_fact & f) { - if (is_sparse()) { - add_fact_sparse(f); - } - else { - TRACE("dl_verbose", for (unsigned i = 0; i < f.size(); ++i) tout << f[i] << " "; tout << "\n";); - while (first(f) >= m_uf.get_num_vars()) m_uf.mk_var(); - while (second(f) >= m_uf.get_num_vars()) m_uf.mk_var(); - m_uf.merge(first(f), second(f)); - m_valid.reserve(m_uf.get_num_vars()); - m_valid.set(first(f)); - m_valid.set(second(f)); - } - } - - void equivalence_table::remove_fact(const table_element* fact) { - mk_sparse(); - m_sparse->remove_fact(fact); - } - - void equivalence_table::mk_sparse() { - if (m_sparse) return; - - TRACE("dl",tout << "\n";); - table_plugin & plugin = get_plugin(); - table_plugin* rp = plugin.get_manager().get_table_plugin(symbol("sparse")); - SASSERT(rp); - table_base* result = rp->mk_empty(get_signature()); - table_base::iterator it = begin(), e = end(); - table_fact fact; - for (; it != e; ++it) { - it->get_fact(fact); - result->add_fact(fact); - } - m_sparse = result; - } - - void equivalence_table::add_fact_sparse(table_fact const& f) { - table_base::iterator it = m_sparse->begin(), end = m_sparse->end(); - vector to_add; - to_add.push_back(f); - table_fact f1(f); - - f1[0] = f[1]; - f1[1] = f[0]; - to_add.push_back(f1); - - f1[0] = f[1]; - f1[1] = f[1]; - to_add.push_back(f1); - - f1[0] = f[0]; - f1[1] = f[0]; - to_add.push_back(f1); - - for (; it != end; ++it) { - if ((*it)[0] == f[0]) { - f1[0] = f[1]; - f1[1] = (*it)[1]; - to_add.push_back(f1); - std::swap(f1[0],f1[1]); - to_add.push_back(f1); - } - } - for (unsigned i = 0; i < to_add.size(); ++i) { - m_sparse->add_fact(to_add[i]); - } - } - - bool equivalence_table::contains_fact(const table_fact & f) const { - TRACE("dl_verbose", for (unsigned i = 0; i < f.size(); ++i) tout << f[i] << " "; tout << "\n";); - if (is_sparse()) { - return m_sparse->contains_fact(f); - } - return - is_valid(first(f)) && - is_valid(second(f)) && - m_uf.find(first(f)) == m_uf.find(second(f)); - } - - table_base* equivalence_table::clone() const { - if (is_sparse()) { - return m_sparse->clone(); - } - TRACE("dl",tout << "\n";); - table_plugin & plugin = get_plugin(); - table_base* result = plugin.mk_empty(get_signature()); - table_fact fact; - fact.resize(2); - for (unsigned i = 0; i < m_uf.get_num_vars(); ++i) { - if (m_valid.get(i) && m_uf.find(i) == i) { - unsigned n = m_uf.next(i); - fact[0] = i; - while (n != i) { - fact[1] = n; - result->add_fact(fact); - n = m_uf.next(n); - } - } - } - return result; - } - - table_base::iterator equivalence_table::begin() const { - if (is_sparse()) return m_sparse->begin(); - return mk_iterator(alloc(eq_iterator, *this, false)); - } - - table_base::iterator equivalence_table::end() const { - if (is_sparse()) return m_sparse->end(); - return mk_iterator(alloc(eq_iterator, *this, true)); - } - - equivalence_table::class_iterator equivalence_table::class_begin(table_element const& _e) const { - SASSERT(!is_sparse()); - unsigned e = static_cast(_e); - return class_iterator(*this, e, !is_valid(e)); - } - - equivalence_table::class_iterator equivalence_table::class_end(table_element const& _e) const { - SASSERT(!is_sparse()); - unsigned e = static_cast(_e); - return class_iterator(*this, e, true); - } - - void equivalence_table::display(std::ostream& out) const { - if (is_sparse()) { - m_sparse->display(out); - return; - } - for (unsigned i = 0; i < m_uf.get_num_vars(); ++i) { - if (is_valid(i) && m_uf.find(i) == i) { - unsigned j = i, last = i; - do { - out << "<" << i << " " << j << ">\n"; - j = m_uf.next(j); - } - while (last != j); - } - } - } - - unsigned equivalence_table::get_size_estimate_rows() const { - if (is_sparse()) return m_sparse->get_size_estimate_rows(); - return static_cast(get_signature()[0]); - } - - unsigned equivalence_table::get_size_estimate_bytes() const { - if (is_sparse()) return m_sparse->get_size_estimate_bytes(); - return static_cast(get_signature()[0]); - } - - bool equivalence_table::knows_exact_size() const { - return (!is_sparse() || m_sparse->knows_exact_size()); - } - -}; - diff --git a/src/muz/dl_table.h b/src/muz/dl_table.h deleted file mode 100644 index 3a240c337..000000000 --- a/src/muz/dl_table.h +++ /dev/null @@ -1,265 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_table.h - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-01. - -Revision History: - ---*/ -#ifndef _DL_TABLE_H_ -#define _DL_TABLE_H_ - -#include -#include -#include - -#include "ast.h" -#include "bit_vector.h" -#include "buffer.h" -#include "hashtable.h" -#include "map.h" -#include "ref_vector.h" -#include "vector.h" -#include "union_find.h" -#include "dl_base.h" -#include "dl_util.h" -#include "bit_vector.h" - - -namespace datalog { - - class context; - class variable_intersection; - - - - // ----------------------------------- - // - // hashtable_table - // - // ----------------------------------- - - class hashtable_table; - - class hashtable_table_plugin : public table_plugin { - friend class hashtable_table; - protected: - class join_fn; - public: - typedef hashtable_table table; - - hashtable_table_plugin(relation_manager & manager) - : table_plugin(symbol("hashtable"), manager) {} - - virtual table_base * mk_empty(const table_signature & s); - - virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - }; - - class hashtable_table : public table_base { - friend class hashtable_table_plugin; - friend class hashtable_table_plugin::join_fn; - - class our_iterator_core; - - typedef hashtable, - vector_eq_proc > storage; - - storage m_data; - - hashtable_table(hashtable_table_plugin & plugin, const table_signature & sig) - : table_base(plugin, sig) {} - public: - hashtable_table_plugin & get_plugin() const - { return static_cast(table_base::get_plugin()); } - - virtual void add_fact(const table_fact & f) { - m_data.insert(f); - } - virtual void remove_fact(const table_element* fact) { - table_fact f(get_signature().size(), fact); - m_data.remove(f); - } - virtual bool contains_fact(const table_fact & f) const { - return m_data.contains(f); - } - - virtual iterator begin() const; - virtual iterator end() const; - - virtual unsigned get_size_estimate_rows() const { return m_data.size(); } - virtual unsigned get_size_estimate_bytes() const { return m_data.size()*get_signature().size()*8; } - virtual bool knows_exact_size() const { return true; } - }; - - // ----------------------------------- - // - // bitvector_table - // - // ----------------------------------- - - class bitvector_table; - - class bitvector_table_plugin : public table_plugin { - public: - typedef bitvector_table table; - - bitvector_table_plugin(relation_manager & manager) - : table_plugin(symbol("bitvector"), manager) {} - - virtual bool can_handle_signature(const table_signature & s); - - virtual table_base * mk_empty(const table_signature & s); - }; - - class bitvector_table : public table_base { - friend class bitvector_table_plugin; - - class bv_iterator; - bit_vector m_bv; - unsigned m_num_cols; - unsigned_vector m_shift; - unsigned_vector m_mask; - - unsigned fact2offset(const table_element* f) const; - void offset2fact(unsigned offset, table_fact& f) const; - - bitvector_table(bitvector_table_plugin & plugin, const table_signature & sig); - public: - virtual void add_fact(const table_fact & f); - virtual void remove_fact(const table_element* fact); - virtual bool contains_fact(const table_fact & f) const; - virtual iterator begin() const; - virtual iterator end() const; - }; - - // ------------------------------------------- - // Equivalence table. - // Really: partial equivalence relation table. - // ------------------------------------------- - - class equivalence_table; - - class equivalence_table_plugin : public table_plugin { - class union_fn; - class select_equal_and_project_fn; - class join_project_fn; - - bool is_equivalence_table(table_base const& tbl) const; - - public: - typedef equivalence_table table; - - equivalence_table_plugin(relation_manager & manager) - : table_plugin(symbol("equivalence"), manager) {} - - virtual bool can_handle_signature(const table_signature & s); - - virtual table_base * mk_empty(const table_signature & s); - - protected: - virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, - const table_base * delta); - virtual table_transformer_fn * mk_select_equal_and_project_fn( - const table_base & t, - const table_element & value, unsigned col); - virtual table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols); - - -#if 0 - virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - const table_element & value, unsigned col); - virtual table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, - const table_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); -#endif - }; - - class equivalence_table : public table_base { - friend class equivalence_table_plugin; - - class eq_iterator; - union_find_default_ctx m_ctx; - bit_vector m_valid; - union_find<> m_uf; - table_base* m_sparse; - - equivalence_table(equivalence_table_plugin & plugin, const table_signature & sig); - virtual ~equivalence_table(); - - unsigned first(table_fact const& f) const { return static_cast(f[0]); } - unsigned second(table_fact const& f) const { return static_cast(f[1]); } - - bool is_valid(unsigned entry) const { return entry < m_valid.size() && m_valid.get(entry); } - bool is_sparse() const { return m_sparse != 0; } - - // iterator over equivalence class of 'n'. - class class_iterator { - equivalence_table const& m_parent; - unsigned m_current; - unsigned m_last; - bool m_end; - public: - class_iterator(equivalence_table const& s, unsigned n, bool end): - m_parent(s), m_current(n), m_last(n), m_end(end) {} - - unsigned operator*() { return m_current; } - - class_iterator& operator++() { - m_current = m_parent.m_uf.next(m_current); - m_end = (m_current == m_last); - return *this; - } - - bool operator==(const class_iterator & it) const { - return - (m_end && it.m_end) || - (!m_end && !it.m_end && m_current == it.m_current); - } - bool operator!=(const class_iterator & it) const { return !operator==(it); } - - }; - class_iterator class_begin(table_element const& e) const; - class_iterator class_end(table_element const& e) const; - - void add_fact_sparse(table_fact const& f); - void mk_sparse(); - - - public: - virtual void add_fact(const table_fact & f); - virtual void remove_fact(const table_element* fact); - virtual bool contains_fact(const table_fact & f) const; - virtual table_base* clone() const; - virtual iterator begin() const; - virtual iterator end() const; - virtual unsigned get_size_estimate_rows() const; - virtual unsigned get_size_estimate_bytes() const; - virtual bool knows_exact_size() const; - virtual void display(std::ostream & out) const; - - }; - - -}; - -#endif /* _DL_TABLE_H_ */ - diff --git a/src/muz/dl_table_plugin.h b/src/muz/dl_table_plugin.h deleted file mode 100644 index 134389b61..000000000 --- a/src/muz/dl_table_plugin.h +++ /dev/null @@ -1,193 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_table_plugin.h - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-23. - -Revision History: - ---*/ -#ifndef _DL_TABLE_PLUGIN_H_ -#define _DL_TABLE_PLUGIN_H_ - -#include"ast.h" -#include"map.h" -#include"vector.h" - -#include"dl_table_ops.h" - -namespace datalog { - - /** - Termplate class containing common infrastructure for relations and tables - */ - template - struct tr_infrastructure { - - typedef typename Traits::base_object base_object; - typedef typename Traits::signature signature; - typedef typename Traits::element element; - typedef typename Traits::fact fact; - typedef typename Traits::kind kind; - - class base_fn { - public: - virtual ~base_fn() {} - }; - - class join_fn : public base_fn { - public: - virtual base_object * operator()(const base_object & t1, const base_object & t2); - }; - - class transformer_fn : public base_fn { - public: - virtual base_object * operator()(const base_object & t); - }; - - class union_fn : public base_fn { - public: - virtual void operator()(base_object & tgt, const base_object & src, base_object * delta); - }; - - class mutator_fn : public base_fn { - public: - virtual void operator()(base_object & t); - }; - - class negation_filter_fn : public base_fn { - public: - virtual void operator()(base_object & t, const base_object & negated_obj); - }; - - class plugin_object { - const kind m_kind; - protected: - plugin_object(kind k) : m_kind(k) {} - public: - kind get_kind(); - - virtual base_object * mk_empty(const signature & s) = 0; - - virtual join_fn * mk_join_fn(const table_base & t1, const table_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - NOT_IMPLEMENTED_YET(); - } - - virtual transformer_fn * mk_project_fn(const base_object & t, unsigned col_cnt, - const unsigned * removed_cols) = 0 - - virtual transformer_fn * mk_rename_fn(const base_object & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle) = 0; - - virtual union_fn * mk_union_fn(base_object & tgt, const base_object & src, base_object * delta) = 0; - - virtual mutator_fn * mk_filter_identical_fn(base_object & t, unsigned col_cnt, - const unsigned * identical_cols) = 0; - - virtual mutator_fn * mk_filter_equal_fn(base_object & t, const element & value, - unsigned col) = 0; - - virtual mutator_fn * mk_filter_interpreted_fn(base_object & t, app * condition) = 0; - - virtual negation_filter_fn * mk_filter_interpreted_fn(base_object & t, - const base_object & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols) = 0; - - }; - - class base_ancestor { - const kind m_kind; - protected: - relation_manager & m_manager; - signature m_signature; - - base_ancestor(kind k, relation_manager & m, const signature & s) - : m_kind(k), m_manager(m), m_signature(s) {} - public: - virtual ~base_ancestor() {} - - kind get_kind() const { return m_kind; } - relation_manager & get_manager() const { return m_manager; } - const signature & get_signature() const { return m_signature; } - - virtual bool empty() const = 0; - virtual void add_fact(const fact & f) = 0; - virtual bool contains_fact(const fact & f) const = 0; - - /** - \brief Return table that contains the same data as the current one. - */ - virtual base_object * clone() const; - - }; - }; - - - // ----------------------------------- - // - // relation_base - // - // ----------------------------------- - - class relation_base1; - - enum relation_kind { - RK_UNKNOWN, - RK_TABLE - }; - - struct relation_traits { - typedef relation_base1 base_object; - typedef relation_signature signature; - typedef app * element; - typedef ptr_vector fact; - typedef relation_kind kind; - }; - - typedef tr_infrastructure relation_infrastructure; - - typedef relation_infrastructure::plugin_object relation_plugin_base; - - class relation_base1 : public relation_infrastructure::base_ancestor { - - }; - - - // ----------------------------------- - // - // table_base - // - // ----------------------------------- - - class table_base1; - - struct table_traits { - typedef table_base1 base_object; - typedef table_signature signature; - typedef unsigned element; - typedef unsigned_vector fact; - typedef table_kind kind; - }; - - typedef tr_infrastructure table_infrastructure; - - typedef table_infrastructure::plugin_object table_plugin_base; - - class table_base1 : public table_infrastructure::base_ancestor { - - }; - -}; - -#endif /* _DL_TABLE_PLUGIN_H_ */ - diff --git a/src/muz/dl_table_relation.cpp b/src/muz/dl_table_relation.cpp deleted file mode 100644 index 3c30c58bb..000000000 --- a/src/muz/dl_table_relation.cpp +++ /dev/null @@ -1,490 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - dl_table_relation.cpp - -Abstract: - - - -Author: - - Krystof Hoder (t-khoder) 2010-09-14. - -Revision History: - ---*/ - - -#include -#include"dl_context.h" -#include"dl_relation_manager.h" -#include"dl_table_relation.h" - - -namespace datalog { - - // ----------------------------------- - // - // table_relation_plugin - // - // ----------------------------------- - - symbol table_relation_plugin::create_plugin_name(const table_plugin &p) { - std::string name = std::string("tr_") + p.get_name().bare_str(); - return symbol(name.c_str()); - } - - bool table_relation_plugin::can_handle_signature(const relation_signature & s) { - table_signature tsig; - if(!get_manager().relation_signature_to_table(s, tsig)) { - return false; - } - return m_table_plugin.can_handle_signature(tsig); - } - - - relation_base * table_relation_plugin::mk_empty(const relation_signature & s) { - table_signature tsig; - if(!get_manager().relation_signature_to_table(s, tsig)) { - return 0; - } - table_base * t = m_table_plugin.mk_empty(tsig); - return alloc(table_relation, *this, s, t); - } - - relation_base * table_relation_plugin::mk_full(const relation_signature & s, func_decl* p, family_id kind) { - table_signature tsig; - if(!get_manager().relation_signature_to_table(s, tsig)) { - return 0; - } - table_base * t = m_table_plugin.mk_full(p, tsig, kind); - return alloc(table_relation, *this, s, t); - } - - relation_base * table_relation_plugin::mk_from_table(const relation_signature & s, table_base * t) { - if (&t->get_plugin() == &m_table_plugin) - return alloc(table_relation, *this, s, t); - table_relation_plugin& other = t->get_manager().get_table_relation_plugin(t->get_plugin()); - return alloc(table_relation, other, s, t); - } - - class table_relation_plugin::tr_join_project_fn : public convenient_relation_join_project_fn { - scoped_ptr m_tfun; - public: - tr_join_project_fn(const relation_signature & s1, const relation_signature & s2, unsigned col_cnt, - const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols, table_join_fn * tfun) - : convenient_relation_join_project_fn(s1, s2, col_cnt, cols1, cols2, removed_col_cnt, - removed_cols), m_tfun(tfun) {} - - virtual relation_base * operator()(const relation_base & t1, const relation_base & t2) { - SASSERT(t1.from_table()); - SASSERT(t2.from_table()); - table_relation_plugin & plugin = static_cast(t1.get_plugin()); - - const table_relation & tr1 = static_cast(t1); - const table_relation & tr2 = static_cast(t2); - - table_base * tres = (*m_tfun)(tr1.get_table(), tr2.get_table()); - - TRACE("dl_table_relation", tout << "# join => "; tres->display(tout);); - if(&tres->get_plugin()!=&plugin.m_table_plugin) { - //Operation returned a table of different type than the one which is associated with - //this plugin. We need to get a correct table_relation_plugin and create the relation - //using it. - return plugin.get_manager().get_table_relation_plugin(tres->get_plugin()) - .mk_from_table(get_result_signature(), tres); - } - return plugin.mk_from_table(get_result_signature(), tres); - } - }; - - relation_join_fn * table_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { - if(!r1.from_table() || !r2.from_table()) { - return 0; - } - const table_relation & tr1 = static_cast(r1); - const table_relation & tr2 = static_cast(r2); - - table_join_fn * tfun = get_manager().mk_join_fn(tr1.get_table(), tr2.get_table(), col_cnt, cols1, cols2); - if(!tfun) { - return 0; - } - - return alloc(tr_join_project_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, - cols2, 0, static_cast(0), tfun); - } - - relation_join_fn * table_relation_plugin::mk_join_project_fn(const relation_base & r1, - const relation_base & r2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, - unsigned removed_col_cnt, const unsigned * removed_cols) { - if(!r1.from_table() || !r2.from_table()) { - return 0; - } - const table_relation & tr1 = static_cast(r1); - const table_relation & tr2 = static_cast(r2); - - table_join_fn * tfun = get_manager().mk_join_project_fn(tr1.get_table(), tr2.get_table(), joined_col_cnt, - cols1, cols2, removed_col_cnt, removed_cols); - SASSERT(tfun); - - return alloc(tr_join_project_fn, r1.get_signature(), r2.get_signature(), joined_col_cnt, cols1, - cols2, removed_col_cnt, removed_cols, tfun); - } - - - class table_relation_plugin::tr_transformer_fn : public convenient_relation_transformer_fn { - scoped_ptr m_tfun; - public: - tr_transformer_fn(const relation_signature & rsig, table_transformer_fn * tfun) - : m_tfun(tfun) { get_result_signature() = rsig; } - - virtual relation_base * operator()(const relation_base & t) { - SASSERT(t.from_table()); - table_relation_plugin & plugin = static_cast(t.get_plugin()); - - const table_relation & tr = static_cast(t); - - table_base * tres = (*m_tfun)(tr.get_table()); - - TRACE("dl_table_relation", tout << "# transform => "; tres->display(tout);); - if(&tres->get_plugin()!=&plugin.m_table_plugin) { - //Transformation returned a table of different type than the one which is associated with this plugin. - //We need to get a correct table_relation_plugin and create the relation using it. - return plugin.get_manager().get_table_relation_plugin(tres->get_plugin()) - .mk_from_table(get_result_signature(), tres); - } - return plugin.mk_from_table(get_result_signature(), tres); - } - }; - - relation_transformer_fn * table_relation_plugin::mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols) { - if(!t.from_table()) { - return 0; - } - const table_relation & tr = static_cast(t); - - table_transformer_fn * tfun = get_manager().mk_project_fn(tr.get_table(), col_cnt, removed_cols); - SASSERT(tfun); - - relation_signature sig; - relation_signature::from_project(t.get_signature(), col_cnt, removed_cols, sig); - - return alloc(tr_transformer_fn, sig, tfun); - } - - relation_transformer_fn * table_relation_plugin::mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle) { - if(!t.from_table()) { - return 0; - } - const table_relation & tr = static_cast(t); - - table_transformer_fn * tfun = get_manager().mk_rename_fn(tr.get_table(), permutation_cycle_len, permutation_cycle); - SASSERT(tfun); - - relation_signature sig; - relation_signature::from_rename(t.get_signature(), permutation_cycle_len, permutation_cycle, sig); - - return alloc(tr_transformer_fn, sig, tfun); - } - - relation_transformer_fn * table_relation_plugin::mk_permutation_rename_fn(const relation_base & t, - const unsigned * permutation) { - if(!t.from_table()) { - return 0; - } - const table_relation & tr = static_cast(t); - - table_transformer_fn * tfun = get_manager().mk_permutation_rename_fn(tr.get_table(), permutation); - SASSERT(tfun); - - relation_signature sig; - relation_signature::from_permutation_rename(t.get_signature(), permutation, sig); - - return alloc(tr_transformer_fn, sig, tfun); - } - - relation_transformer_fn * table_relation_plugin::mk_select_equal_and_project_fn(const relation_base & t, - const relation_element & value, unsigned col) { - if(!t.from_table()) { - return 0; - } - const table_relation & tr = static_cast(t); - - table_element tvalue; - get_manager().relation_to_table(tr.get_signature()[col], value, tvalue); - - table_transformer_fn * tfun = get_manager().mk_select_equal_and_project_fn(tr.get_table(), tvalue, col); - SASSERT(tfun); - relation_signature res_sig; - relation_signature::from_project(t.get_signature(), 1, &col, res_sig); - return alloc(tr_transformer_fn, res_sig, tfun); - } - - /** - Union functor that can unite table relation into any other relation (using any delta relation) - by iterating through the table and calling \c add_fact of the target relation. - */ - class table_relation_plugin::universal_target_union_fn : public relation_union_fn { - virtual void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) { - SASSERT(src.from_table()); - - const table_relation & tr_src = static_cast(src); - relation_manager & rmgr = tr_src.get_manager(); - relation_signature sig = tr_src.get_signature(); - SASSERT(tgt.get_signature()==sig); - SASSERT(!delta || delta->get_signature()==sig); - - table_base::iterator it = tr_src.get_table().begin(); - table_base::iterator end = tr_src.get_table().end(); - - table_fact tfact; - relation_fact rfact(rmgr.get_context()); - for (; it != end; ++it) { - it->get_fact(tfact); - rmgr.table_fact_to_relation(sig, tfact, rfact); - if(delta) { - if(!tgt.contains_fact(rfact)) { - tgt.add_new_fact(rfact); - delta->add_fact(rfact); - } - } - else { - tgt.add_fact(rfact); - } - } - TRACE("dl_table_relation", tout << "# universal union => "; tgt.display(tout);); - } - }; - - class table_relation_plugin::tr_union_fn : public relation_union_fn { - scoped_ptr m_tfun; - public: - tr_union_fn(table_union_fn * tfun) : m_tfun(tfun) {} - - virtual void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) { - SASSERT(tgt.from_table()); - SASSERT(src.from_table()); - SASSERT(!delta || delta->from_table()); - - table_relation & tr_tgt = static_cast(tgt); - const table_relation & tr_src = static_cast(src); - table_relation * tr_delta = static_cast(delta); - - (*m_tfun)(tr_tgt.get_table(), tr_src.get_table(), tr_delta ? &tr_delta->get_table() : 0); - - TRACE("dl_table_relation", tout << "# union => "; tr_tgt.get_table().display(tout);); - } - }; - - relation_union_fn * table_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta) { - if(!src.from_table()) { - return 0; - } - if(!tgt.from_table() || (delta && !delta->from_table())) { - return alloc(universal_target_union_fn); - } - const table_relation & tr_tgt = static_cast(tgt); - const table_relation & tr_src = static_cast(src); - const table_relation * tr_delta = static_cast(delta); - - table_union_fn * tfun = get_manager().mk_union_fn(tr_tgt.get_table(), tr_src.get_table(), - tr_delta ? &tr_delta->get_table() : 0); - SASSERT(tfun); - - return alloc(tr_union_fn, tfun); - } - - - class table_relation_plugin::tr_mutator_fn : public relation_mutator_fn { - scoped_ptr m_tfun; - public: - tr_mutator_fn(table_mutator_fn * tfun) : m_tfun(tfun) {} - - virtual void operator()(relation_base & r) { - SASSERT(r.from_table()); - table_relation & tr = static_cast(r); - (*m_tfun)(tr.get_table()); - TRACE("dl_table_relation", tout << "# mutator => "; tr.get_table().display(tout);); - } - }; - - relation_mutator_fn * table_relation_plugin::mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols) { - if(!t.from_table()) { - return 0; - } - const table_relation & tr = static_cast(t); - - table_mutator_fn * tfun = get_manager().mk_filter_identical_fn(tr.get_table(), col_cnt, identical_cols); - SASSERT(tfun); - return alloc(tr_mutator_fn, tfun); - } - - relation_mutator_fn * table_relation_plugin::mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col) { - if(!t.from_table()) { - return 0; - } - const table_relation & tr = static_cast(t); - - table_element tvalue; - get_manager().relation_to_table(tr.get_signature()[col], value, tvalue); - - table_mutator_fn * tfun = get_manager().mk_filter_equal_fn(tr.get_table(), tvalue, col); - SASSERT(tfun); - return alloc(tr_mutator_fn, tfun); - } - - relation_mutator_fn * table_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { - bool condition_needs_transforming = false; - if(!t.from_table() || condition_needs_transforming) { - return 0; - } - const table_relation & tr = static_cast(t); - table_mutator_fn * tfun = get_manager().mk_filter_interpreted_fn(tr.get_table(), condition); - SASSERT(tfun); - return alloc(tr_mutator_fn, tfun); - } - - relation_transformer_fn * table_relation_plugin::mk_filter_interpreted_and_project_fn(const relation_base & t, - app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { - if (!t.from_table()) - return 0; - - const table_relation & tr = static_cast(t); - table_transformer_fn * tfun = get_manager().mk_filter_interpreted_and_project_fn(tr.get_table(), - condition, removed_col_cnt, removed_cols); - SASSERT(tfun); - - relation_signature sig; - relation_signature::from_project(t.get_signature(), removed_col_cnt, removed_cols, sig); - return alloc(tr_transformer_fn, sig, tfun); - } - - class table_relation_plugin::tr_intersection_filter_fn : public relation_intersection_filter_fn { - scoped_ptr m_tfun; - public: - tr_intersection_filter_fn(table_intersection_filter_fn * tfun) : m_tfun(tfun) {} - - virtual void operator()(relation_base & r, const relation_base & src) { - SASSERT(r.from_table()); - SASSERT(src.from_table()); - - table_relation & tr = static_cast(r); - const table_relation & tr_src = static_cast(src); - - (*m_tfun)(tr.get_table(), tr_src.get_table()); - TRACE("dl_table_relation", tout << "# negation_filter => "; tr.get_table().display(tout);); - } - }; - - relation_intersection_filter_fn * table_relation_plugin::mk_filter_by_intersection_fn(const relation_base & r, - const relation_base & src, unsigned joined_col_cnt, const unsigned * r_cols, const unsigned * src_cols) { - if(!r.from_table() || !src.from_table()) { - return 0; - } - const table_relation & tr = static_cast(r); - const table_relation & tr_neg = static_cast(src); - table_intersection_filter_fn * tfun = get_manager().mk_filter_by_intersection_fn(tr.get_table(), - tr_neg.get_table(), joined_col_cnt, r_cols, src_cols); - if(!tfun) { - return 0; - } - - return alloc(tr_intersection_filter_fn, tfun); - } - - - relation_intersection_filter_fn * table_relation_plugin::mk_filter_by_negation_fn(const relation_base & r, - const relation_base & negated_rel, unsigned joined_col_cnt, - const unsigned * r_cols, const unsigned * negated_cols) { - if(!r.from_table() || !negated_rel.from_table()) { - return 0; - } - const table_relation & tr = static_cast(r); - const table_relation & tr_neg = static_cast(negated_rel); - table_intersection_filter_fn * tfun = get_manager().mk_filter_by_negation_fn(tr.get_table(), - tr_neg.get_table(), joined_col_cnt, r_cols, negated_cols); - SASSERT(tfun); - - return alloc(tr_intersection_filter_fn, tfun); - } - - - // ----------------------------------- - // - // table_relation - // - // ----------------------------------- - - void table_relation::add_table_fact(const table_fact & f) { - get_table().add_fact(f); - } - - void table_relation::add_fact(const relation_fact & f) { - SASSERT(f.size()==get_signature().size()); - table_fact vals; - get_manager().relation_fact_to_table(get_signature(), f, vals); - get_table().add_fact(vals); - TRACE("dl_table_relation", tout << "# add fact => "; get_table().display(tout);); - } - - bool table_relation::contains_fact(const relation_fact & f) const { - table_fact vals; - get_manager().relation_fact_to_table(get_signature(), f, vals); - return get_table().contains_fact(vals); - } - - relation_base * table_relation::clone() const { - table_base * tres = get_table().clone(); - return get_plugin().mk_from_table(get_signature(), tres); - } - - relation_base * table_relation::complement(func_decl* p) const { - table_base * tres = get_table().complement(p); - return get_plugin().mk_from_table(get_signature(), tres); - } - - void table_relation::display_tuples(func_decl & pred, std::ostream & out) const { - context & ctx = get_manager().get_context(); - unsigned arity = pred.get_arity(); - - out << "Tuples in " << pred.get_name() << ": \n"; - - table_base::iterator it = get_table().begin(); - table_base::iterator end = get_table().end(); - - table_fact fact; - for (; it != end; ++it) { - it->get_fact(fact); - - out << "\t("; - - for(unsigned i=0;i - -Author: - - Krystof Hoder (t-khoder) 2010-09-24. - -Revision History: - ---*/ -#ifndef _DL_TABLE_RELATION_H_ -#define _DL_TABLE_RELATION_H_ - - -#include "dl_base.h" -#include "dl_util.h" - -namespace datalog { - - class table_relation; - - class table_relation_plugin : public relation_plugin { - friend class table_relation; - - class tr_join_project_fn; - class tr_transformer_fn; - class universal_target_union_fn; - class tr_union_fn; - class tr_mutator_fn; - class tr_intersection_filter_fn; - - table_plugin & m_table_plugin; - - static symbol create_plugin_name(const table_plugin & p); - public: - table_relation_plugin(table_plugin & tp, relation_manager & manager) - : relation_plugin(create_plugin_name(tp), manager, ST_TABLE_RELATION), m_table_plugin(tp) {} - - table_plugin & get_table_plugin() { return m_table_plugin; } - - virtual bool can_handle_signature(const relation_signature & s); - - virtual relation_base * mk_empty(const relation_signature & s); - virtual relation_base * mk_full(const relation_signature & s, func_decl* p, family_id kind); - relation_base * mk_from_table(const relation_signature & s, table_base * t); - - protected: - virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, - unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); - virtual relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, - unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, - const unsigned * removed_cols); - virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, - const unsigned * permutation_cycle); - virtual relation_transformer_fn * mk_permutation_rename_fn(const relation_base & t, - const unsigned * permutation); - virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, - const relation_base * delta); - virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, - const unsigned * identical_cols); - virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, - unsigned col); - virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); - virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t, - app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); - virtual relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & t, - const relation_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols); - virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, - const relation_base & negated_obj, unsigned joined_col_cnt, - const unsigned * t_cols, const unsigned * negated_cols); - virtual relation_transformer_fn * mk_select_equal_and_project_fn(const relation_base & t, - const relation_element & value, unsigned col); - }; - - class table_relation : public relation_base { - friend class table_relation_plugin; - friend class table_relation_plugin::tr_join_project_fn; - friend class table_relation_plugin::tr_transformer_fn; - - scoped_rel m_table; - - /** - \brief Create a \c table_relation object. - - The newly created object takes ownership of the \c table object. - */ - table_relation(table_relation_plugin & p, const relation_signature & s, table_base * table) - : relation_base(p, s), m_table(table) { - SASSERT(s.size()==table->get_signature().size()); - } - public: - - table_relation_plugin & get_plugin() const { - return static_cast(relation_base::get_plugin()); - } - - table_base & get_table() { return *m_table; } - const table_base & get_table() const { return *m_table; } - - virtual bool empty() const { return m_table->empty(); } - - void add_table_fact(const table_fact & f); - - virtual void add_fact(const relation_fact & f); - virtual bool contains_fact(const relation_fact & f) const; - virtual relation_base * clone() const; - virtual relation_base * complement(func_decl* p) const; - virtual void to_formula(expr_ref& fml) const { get_table().to_formula(get_signature(), fml); } - - virtual void display(std::ostream & out) const { - get_table().display(out); - } - virtual void display_tuples(func_decl & pred, std::ostream & out) const; - - virtual unsigned get_size_estimate_rows() const { return m_table->get_size_estimate_rows(); } - virtual unsigned get_size_estimate_bytes() const { return m_table->get_size_estimate_bytes(); } - virtual bool knows_exact_size() const { return m_table->knows_exact_size(); } - }; - -}; - -#endif /* _DL_TABLE_RELATION_H_ */ - diff --git a/src/muz/dl_util.cpp b/src/muz/dl_util.cpp index 0b88136e2..e32999ddc 100644 --- a/src/muz/dl_util.cpp +++ b/src/muz/dl_util.cpp @@ -32,14 +32,6 @@ Revision History: namespace datalog { - void universal_delete(relation_base* ptr) { - ptr->deallocate(); - } - - void universal_delete(table_base* ptr) { - ptr->deallocate(); - } - bool contains_var(expr * trm, unsigned var_idx) { ptr_vector vars; @@ -420,18 +412,6 @@ namespace datalog { } } - void get_renaming_args(const unsigned_vector & map, const relation_signature & orig_sig, - expr_ref_vector & renaming_arg) { - ast_manager & m = renaming_arg.get_manager(); - unsigned sz = map.size(); - unsigned ofs = sz-1; - renaming_arg.resize(sz, static_cast(0)); - for(unsigned i=0; i & v) { - ptr_vector::iterator it = v.begin(); - ptr_vector::iterator end = v.end(); - for(; it!=end; ++it) { - (*it)->deallocate(); - } - } // ----------------------------------- diff --git a/src/muz/dl_util.h b/src/muz/dl_util.h index debb4d3e2..d805e683b 100644 --- a/src/muz/dl_util.h +++ b/src/muz/dl_util.h @@ -50,52 +50,6 @@ namespace datalog { LAST_CACHE_MODE }; - enum DL_ENGINE { - DATALOG_ENGINE, - PDR_ENGINE, - QPDR_ENGINE, - BMC_ENGINE, - QBMC_ENGINE, - TAB_ENGINE, - CLP_ENGINE, - LAST_ENGINE - }; - - class engine_base { - ast_manager& m; - std::string m_name; - public: - engine_base(ast_manager& m, char const* name): m(m), m_name(name) {} - virtual ~engine_base() {} - - virtual expr_ref get_answer() = 0; - virtual lbool query(expr* q) = 0; - - virtual void reset_statistics() {} - virtual void display_profile(std::ostream& out) const {} - virtual void collect_statistics(statistics& st) const {} - virtual unsigned get_num_levels(func_decl* pred) { - throw default_exception(std::string("get_num_levels is not supported for ") + m_name); - } - virtual expr_ref get_cover_delta(int level, func_decl* pred) { - throw default_exception(std::string("operation is not supported for ") + m_name); - } - virtual void add_cover(int level, func_decl* pred, expr* property) { - throw default_exception(std::string("operation is not supported for ") + m_name); - } - virtual void display_certificate(std::ostream& out) const { - throw default_exception(std::string("certificates are not supported for ") + m_name); - } - virtual model_ref get_model() { - return model_ref(alloc(model, m)); - } - virtual proof_ref get_proof() { - return proof_ref(m.mk_asserted(m.mk_true()), m); - } - virtual void updt_params() {} - virtual void cancel() {} - virtual void cleanup() {} - }; struct std_string_hash_proc { unsigned operator()(const std::string & s) const @@ -435,14 +389,6 @@ namespace datalog { void reverse_renaming(ast_manager & m, const expr_ref_vector & src, expr_ref_vector & tgt); - /** - \brief Populate vector \c renaming_args so that it can be used as an argument to \c var_subst. - The renaming we want is one that transforms variables with numbers of indexes of \c map into the - values of at those indexes. If a value if \c UINT_MAX, it means we do not transform the index - corresponding to it. - */ - void get_renaming_args(const unsigned_vector & map, const relation_signature & orig_sig, - expr_ref_vector & renaming_arg); void print_renaming(const expr_ref_vector & cont, std::ostream & out); @@ -634,8 +580,6 @@ namespace datalog { } } - void dealloc_ptr_vector_content(ptr_vector & v); - /** \brief Add elements from an iterable object \c src into the vector \c vector. */ @@ -792,9 +736,6 @@ namespace datalog { dealloc(ptr); } - void universal_delete(relation_base* ptr); - void universal_delete(table_base* ptr); - template class scoped_rel { T* m_t; diff --git a/src/muz/dl_vector_relation.h b/src/muz/dl_vector_relation.h deleted file mode 100644 index 114f4ca43..000000000 --- a/src/muz/dl_vector_relation.h +++ /dev/null @@ -1,407 +0,0 @@ -/*++ -Copyright (c) 2010 Microsoft Corporation - -Module Name: - - dl_vector_relation.h - -Abstract: - - Basic relation with equivalences. - -Author: - - Nikolaj Bjorner (nbjorner) 2010-2-11 - -Revision History: - ---*/ -#ifndef _DL_VECTOR_RELATION_H_ -#define _DL_VECTOR_RELATION_H_ - -#include "ast_pp.h" -#include "dl_context.h" -#include "union_find.h" - -namespace datalog { - - typedef std::pair u_pair; - - template - class vector_relation_helper { - public: - static void mk_project_t(T& t, unsigned_vector const& renaming) {} - }; - - template > - class vector_relation : public relation_base { - protected: - T m_default; - vector* m_elems; - bool m_empty; - union_find_default_ctx m_ctx; - union_find<>* m_eqs; - - friend class vector_relation_plugin; - - public: - vector_relation(relation_plugin& p, relation_signature const& s, bool is_empty, T const& t = T()): - relation_base(p, s), - m_default(t), - m_elems(alloc(vector)), - m_empty(is_empty), - m_eqs(alloc(union_find<>, m_ctx)) { - m_elems->resize(s.size(), t); - for (unsigned i = 0; i < s.size(); ++i) { - m_eqs->mk_var(); - } - } - - virtual ~vector_relation() { - dealloc(m_eqs); - dealloc(m_elems); - } - - virtual bool can_swap() const { return true; } - - virtual void swap(relation_base& other) { - vector_relation& o = dynamic_cast(other); - if (&o == this) return; - std::swap(o.m_eqs, m_eqs); - std::swap(o.m_empty, m_empty); - std::swap(o.m_elems, m_elems); - } - - void copy(vector_relation const& other) { - SASSERT(get_signature() == other.get_signature()); - if (other.empty()) { - set_empty(); - return; - } - m_empty = false; - for (unsigned i = 0; i < m_elems->size(); ++i) { - (*this)[i] = other[i]; - SASSERT(find(i) == i); - } - for (unsigned i = 0; i < m_elems->size(); ++i) { - merge(i, find(i)); - } - } - - - virtual bool empty() const { return m_empty; } - - T& operator[](unsigned i) { return (*m_elems)[find(i)]; } - - T const& operator[](unsigned i) const { return (*m_elems)[find(i)]; } - - virtual void display_index(unsigned i, T const& t, std::ostream& out) const = 0; - - virtual void display(std::ostream & out) const { - if (empty()) { - out << "empty\n"; - return; - } - for (unsigned i = 0; i < m_elems->size(); ++i) { - if (i == find(i)) { - display_index(i, (*m_elems)[i], out); - } - else { - out << i << " = " << find(i) << "\n"; - } - } - } - - - bool is_subset_of(vector_relation const& other) const { - if (empty()) return true; - if (other.empty()) return false; - for (unsigned i = 0; i < get_signature().size(); ++i) { - if (!is_subset_of((*this)[i], other[i])) { - return false; - } - } - return true; - } - - void set_empty() { - unsigned sz = m_elems->size(); - m_empty = true; - m_elems->reset(); - m_elems->resize(sz, m_default); - dealloc(m_eqs); - m_eqs = alloc(union_find<>,m_ctx); - for (unsigned i = 0; i < sz; ++i) { - m_eqs->mk_var(); - } - } - - - virtual T mk_intersect(T const& t1, T const& t2, bool& is_empty) const = 0; - - virtual T mk_widen(T const& t1, T const& t2) const = 0; - - virtual T mk_unite(T const& t1, T const& t2) const = 0; - - virtual bool is_subset_of(T const& t1, T const& t2) const = 0; - - virtual bool is_full(T const& t) const = 0; - - virtual bool is_empty(unsigned i, T const& t) const = 0; - - virtual void mk_rename_elem(T& t, unsigned col_cnt, unsigned const* cycle) = 0; - - virtual T mk_eq(union_find<> const& old_eqs, union_find<> const& neq_eqs, T const& t) const { return t; } - - void equate(unsigned i, unsigned j) { - SASSERT(i < get_signature().size()); - SASSERT(j < get_signature().size()); - if (!empty() && find(i) != find(j)) { - bool isempty; - T r = mk_intersect((*this)[i], (*this)[j], isempty); - if (isempty || is_empty(find(i),r)) { - m_empty = true; - } - else { - merge(i, j); - (*this)[i] = r; - } - } - } - - bool is_full() const { - for (unsigned i = 0; i < m_elems->size(); ++i) { - if (!is_full((*this)[i])) { - return false; - } - } - return true; - } - - void mk_join(vector_relation const& r1, vector_relation const& r2, - unsigned num_cols, unsigned const* cols1, unsigned const* cols2) { - SASSERT(is_full()); - bool is_empty = r1.empty() || r2.empty(); - if (is_empty) { - m_empty = true; - return; - } - unsigned sz1 = r1.get_signature().size(); - unsigned sz2 = r2.get_signature().size(); - for (unsigned i = 0; i < sz1; ++i) { - (*this)[i] = r1[i]; - } - for (unsigned i = 0; i < sz2; ++i) { - (*this)[sz1+i] = r2[i]; - } - for (unsigned i = 0; i < num_cols; ++i) { - unsigned col1 = cols1[i]; - unsigned col2 = cols2[i]; - equate(col1, sz1 + col2); - } - - TRACE("dl_relation", - r1.display(tout << "r1:\n"); - r2.display(tout << "r2:\n"); - display(tout << "dst:\n"); - ); - } - - void mk_project(vector_relation const& r, unsigned col_cnt, unsigned const* removed_cols) { - SASSERT(is_full()); - unsigned_vector classRep, repNode; - unsigned result_size = get_signature().size(); - unsigned input_size = r.get_signature().size(); - repNode.resize(input_size, UINT_MAX); - - // initialize vector entries and set class representatives. - for (unsigned i = 0, j = 0, c = 0; i < input_size; ++i) { - if (c < col_cnt && removed_cols[c] == i) { - ++c; - } - else { - (*this)[j] = r[i]; - classRep.push_back(r.find(i)); - ++j; - } - } - - // merge remaining equivalence classes. - for (unsigned i = 0; i < result_size; ++i) { - unsigned rep = classRep[i]; - if (repNode[rep] == UINT_MAX) { - repNode[rep] = i; - } - else { - merge(repNode[rep], i); - } - } - - // rename columns in image of vector relation. - unsigned_vector renaming; - for (unsigned i = 0, j = 0, c = 0; i < input_size; ++i) { - if (c < col_cnt && removed_cols[c] == i) { - renaming.push_back(UINT_MAX); - ++c; - } - else { - renaming.push_back(find(j)); - ++j; - } - } - for (unsigned k = 0; k < result_size; ++k) { - Helper::mk_project_t((*this)[k], renaming); - } - - - TRACE("dl_relation", - ast_manager& m = r.get_plugin().get_ast_manager(); - tout << "Signature: "; - for (unsigned i = 0; i < r.get_signature().size(); ++i) { - tout << mk_pp(r.get_signature()[i], m) << " "; - } - tout << "Remove: "; - for (unsigned i = 0; i < col_cnt; ++i) { - tout << removed_cols[i] << " "; - } - tout << "\n"; - r.display(tout); - tout << " --> \n"; - display(tout);); - } - - void mk_rename(vector_relation const& r, unsigned col_cnt, unsigned const* cycle) { - unsigned col1, col2; - SASSERT(is_full()); - - // roundabout way of creating permuted relation. - unsigned_vector classRep, repNode; - for (unsigned i = 0; i < r.m_elems->size(); ++i) { - classRep.push_back(r.find(i)); - repNode.push_back(UINT_MAX); - (*this)[i] = r[i]; - } - for (unsigned i = 0; i + 1 < col_cnt; ++i) { - col1 = cycle[i]; - col2 = cycle[i+1]; - (*this)[col2] = (*r.m_elems)[col1]; - classRep[col2] = r.find(col1); - } - col1 = cycle[col_cnt-1]; - col2 = cycle[0]; - (*this)[col2] = (*r.m_elems)[col1]; - classRep[col2] = r.find(col1); - - for (unsigned i = 0; i < r.m_elems->size(); ++i) { - unsigned rep = classRep[i]; - if (repNode[rep] == UINT_MAX) { - repNode[rep] = i; - } - else { - merge(repNode[rep], i); - } - } - - for (unsigned i = 0; i < r.m_elems->size(); ++i) { - mk_rename_elem((*m_elems)[i], col_cnt, cycle); - } - - TRACE("dl_relation", - ast_manager& m = r.get_plugin().get_ast_manager(); - tout << "cycle: "; - for (unsigned i = 0; i < col_cnt; ++i) { - tout << cycle[i] << " "; - } - tout << "\nold_sig: "; - for (unsigned i = 0; i < r.get_signature().size(); ++i) { - tout << mk_pp(r.get_signature()[i], m) << " "; - } - tout << "\nnew_sig: "; - for (unsigned i = 0; i < get_signature().size(); ++i) { - tout << mk_pp(get_signature()[i], m) << " "; - } - tout << "\n"; - r.display(tout << "src:\n"); - ); - } - - void mk_union(vector_relation const& src, vector_relation* delta, bool is_widen) { - TRACE("dl_relation", display(tout << "dst:\n"); src.display(tout << "src:\n");); - - if (src.empty()) { - if (delta) { - delta->copy(src); - } - return; - } - - if (empty()) { - copy(src); - if (delta) { - delta->copy(src); - } - return; - } - - // find coarsest equivalence class containing joint equalities - union_find<>* uf = alloc(union_find<>, m_ctx); - unsigned size = get_signature().size(); - map, default_eq > mp; - bool change = false; - bit_vector finds; - finds.resize(size, false); - for (unsigned i = 0; i < size; ++i) { - uf->mk_var(); - unsigned w; - u_pair p(std::make_pair(find(i), src.find(i))); - if (mp.find(p, w)) { - uf->merge(i, w); - } - else { - mp.insert(p, i); - // detect change - if (finds.get(find(i))) { - change = true; - } - else { - finds.set(find(i), true); - } - } - } - vector* elems = alloc(vector); - for (unsigned i = 0; i < size; ++i) { - T t1 = mk_eq(*m_eqs, *uf, (*this)[i]); - T t2 = mk_eq(*src.m_eqs, *uf, src[i]); - if (is_widen) { - elems->push_back(mk_widen(t1, t2)); - } - else { - elems->push_back(mk_unite(t1, t2)); - } - TRACE("dl_relation", tout << t1 << " u " << t2 << " = " << elems->back() << "\n";); - change = delta && (change || !((*elems)[i] == (*this)[i])); - } - dealloc(m_eqs); - dealloc(m_elems); - m_eqs = uf; - m_elems = elems; - if (delta && change) { - delta->copy(*this); - } - TRACE("dl_relation", display(tout << "dst':\n");); - } - - unsigned find(unsigned i) const { - return m_eqs->find(i); - } - - void merge(unsigned i, unsigned j) { - m_eqs->merge(i, j); - } - - }; - -}; - -#endif - diff --git a/src/muz/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp similarity index 98% rename from src/muz/dl_cmds.cpp rename to src/muz/fp/dl_cmds.cpp index dcdf3ebb4..7f73b0895 100644 --- a/src/muz/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -19,6 +19,7 @@ Notes: #include"dl_cmds.h" #include"dl_external_relation.h" #include"dl_context.h" +#include"dl_register_engine.h" #include"dl_decl_plugin.h" #include"dl_instruction.h" #include"dl_compiler.h" @@ -37,6 +38,7 @@ struct dl_context { params_ref m_params_ref; fixedpoint_params m_params; cmd_context & m_cmd; + datalog::register_engine m_register_engine; dl_collected_cmds* m_collected_cmds; unsigned m_ref_count; datalog::dl_decl_plugin* m_decl_plugin; @@ -70,7 +72,7 @@ struct dl_context { void init() { ast_manager& m = m_cmd.m(); if (!m_context) { - m_context = alloc(datalog::context, m, m_fparams, m_params_ref); + m_context = alloc(datalog::context, m, m_register_engine, m_fparams, m_params_ref); } if (!m_decl_plugin) { symbol name("datalog_relation"); diff --git a/src/muz/fp/dl_register_engine.cpp b/src/muz/fp/dl_register_engine.cpp new file mode 100644 index 000000000..84b64fafa --- /dev/null +++ b/src/muz/fp/dl_register_engine.cpp @@ -0,0 +1,51 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_register_engine.cpp + +Abstract: + + Class for creating Datalog engines. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-08-28 + +Revision History: + +--*/ +#include "dl_register_engine.h" +#include "dl_bmc_engine.h" +#include "clp_context.h" +#include "tab_context.h" +#include "rel_context.h" +#include "pdr_dl_interface.h" + +namespace datalog { + register_engine::register_engine(): m_ctx(0) {} + + engine_base* register_engine::mk_engine(DL_ENGINE engine_type) { + switch(engine_type) { + case PDR_ENGINE: + case QPDR_ENGINE: + return alloc(pdr::dl_interface, *m_ctx); + case DATALOG_ENGINE: + return alloc(rel_context, *m_ctx); + case BMC_ENGINE: + case QBMC_ENGINE: + return alloc(bmc, *m_ctx); + case TAB_ENGINE: + return alloc(tab, *m_ctx); + case CLP_ENGINE: + return alloc(clp, *m_ctx); + case LAST_ENGINE: + UNREACHABLE(); + return 0; + } + UNREACHABLE(); + return 0; + } + +} diff --git a/src/muz/fp/dl_register_engine.h b/src/muz/fp/dl_register_engine.h new file mode 100644 index 000000000..44f5090e6 --- /dev/null +++ b/src/muz/fp/dl_register_engine.h @@ -0,0 +1,36 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_register_engine.h + +Abstract: + + Class for creating Datalog engines. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-08-28 + +Revision History: + +--*/ +#ifndef _DL_REGISTER_ENGINE_H_ +#define _DL_REGISTER_ENGINE_H_ + +#include "dl_context.h" + +namespace datalog { + + class register_engine : public register_engine_base { + context* m_ctx; + public: + register_engine(); + engine_base* mk_engine(DL_ENGINE engine_type); + void set_context(context* ctx) { m_ctx = ctx; } + }; + +} + +#endif diff --git a/src/muz/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp similarity index 98% rename from src/muz/horn_tactic.cpp rename to src/muz/fp/horn_tactic.cpp index 07a0e2568..ca6cbc2fb 100644 --- a/src/muz/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -21,22 +21,25 @@ Revision History: #include"proof_converter.h" #include"horn_tactic.h" #include"dl_context.h" +#include"dl_register_engine.h" #include"expr_replacer.h" #include"dl_rule_transformer.h" #include"dl_mk_slice.h" #include"filter_model_converter.h" +#include"dl_transforms.h" class horn_tactic : public tactic { struct imp { ast_manager& m; bool m_is_simplify; + datalog::register_engine m_register_engine; datalog::context m_ctx; smt_params m_fparams; imp(bool t, ast_manager & m, params_ref const & p): m(m), m_is_simplify(t), - m_ctx(m, m_fparams) { + m_ctx(m, m_register_engine, m_fparams) { updt_params(p); } @@ -310,7 +313,7 @@ class horn_tactic : public tactic { func_decl* query_pred = to_app(q)->get_decl(); m_ctx.set_output_predicate(query_pred); m_ctx.get_rules(); // flush adding rules. - m_ctx.apply_default_transformation(); + apply_default_transformation(m_ctx); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); diff --git a/src/muz/horn_tactic.h b/src/muz/fp/horn_tactic.h similarity index 100% rename from src/muz/horn_tactic.h rename to src/muz/fp/horn_tactic.h diff --git a/src/muz/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp similarity index 100% rename from src/muz/pdr_context.cpp rename to src/muz/pdr/pdr_context.cpp diff --git a/src/muz/pdr_context.h b/src/muz/pdr/pdr_context.h similarity index 99% rename from src/muz/pdr_context.h rename to src/muz/pdr/pdr_context.h index 3501ca7cd..57238abb3 100644 --- a/src/muz/pdr_context.h +++ b/src/muz/pdr/pdr_context.h @@ -26,7 +26,6 @@ Revision History: #endif #include #include "pdr_manager.h" -#include "dl_base.h" #include "pdr_prop_solver.h" #include "pdr_reachable_cache.h" diff --git a/src/muz/pdr_dl_interface.cpp b/src/muz/pdr/pdr_dl_interface.cpp similarity index 98% rename from src/muz/pdr_dl_interface.cpp rename to src/muz/pdr/pdr_dl_interface.cpp index 05a13dfc7..ccd22d57f 100644 --- a/src/muz/pdr_dl_interface.cpp +++ b/src/muz/pdr/pdr_dl_interface.cpp @@ -17,7 +17,6 @@ Revision History: --*/ -#include "dl_cmds.h" #include "dl_context.h" #include "dl_mk_coi_filter.h" #include "dl_mk_interp_tail_simplifier.h" @@ -33,6 +32,7 @@ Revision History: #include "dl_mk_unfold.h" #include "dl_mk_coalesce.h" #include "model_smt2_pp.h" +#include "dl_transforms.h" using namespace pdr; @@ -102,7 +102,7 @@ lbool dl_interface::query(expr * query) { ); - m_ctx.apply_default_transformation(); + apply_default_transformation(m_ctx); if (m_ctx.get_params().slice()) { datalog::rule_transformer transformer(m_ctx); diff --git a/src/muz/pdr_dl_interface.h b/src/muz/pdr/pdr_dl_interface.h similarity index 98% rename from src/muz/pdr_dl_interface.h rename to src/muz/pdr/pdr_dl_interface.h index 2075dff47..610e7fe06 100644 --- a/src/muz/pdr_dl_interface.h +++ b/src/muz/pdr/pdr_dl_interface.h @@ -24,6 +24,7 @@ Revision History: #include "dl_rule.h" #include "dl_rule_set.h" #include "dl_util.h" +#include "dl_engine_base.h" #include "statistics.h" namespace datalog { diff --git a/src/muz/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp similarity index 100% rename from src/muz/pdr_farkas_learner.cpp rename to src/muz/pdr/pdr_farkas_learner.cpp diff --git a/src/muz/pdr_farkas_learner.h b/src/muz/pdr/pdr_farkas_learner.h similarity index 100% rename from src/muz/pdr_farkas_learner.h rename to src/muz/pdr/pdr_farkas_learner.h diff --git a/src/muz/pdr_generalizers.cpp b/src/muz/pdr/pdr_generalizers.cpp similarity index 99% rename from src/muz/pdr_generalizers.cpp rename to src/muz/pdr/pdr_generalizers.cpp index 883429315..f1ab01070 100644 --- a/src/muz/pdr_generalizers.cpp +++ b/src/muz/pdr/pdr_generalizers.cpp @@ -194,7 +194,7 @@ namespace pdr { } conv1.append(fmls); expr_ref fml = n.pt().get_formulas(n.level(), false); - expr_ref_vector fmls(m); + fmls.reset(); qe::flatten_and(fml, fmls); for (unsigned i = 0; i < fmls.size(); ++i) { fml = m.mk_not(fmls[i].get()); diff --git a/src/muz/pdr_generalizers.h b/src/muz/pdr/pdr_generalizers.h similarity index 100% rename from src/muz/pdr_generalizers.h rename to src/muz/pdr/pdr_generalizers.h diff --git a/src/muz/pdr_manager.cpp b/src/muz/pdr/pdr_manager.cpp similarity index 100% rename from src/muz/pdr_manager.cpp rename to src/muz/pdr/pdr_manager.cpp diff --git a/src/muz/pdr_manager.h b/src/muz/pdr/pdr_manager.h similarity index 100% rename from src/muz/pdr_manager.h rename to src/muz/pdr/pdr_manager.h diff --git a/src/muz/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp similarity index 100% rename from src/muz/pdr_prop_solver.cpp rename to src/muz/pdr/pdr_prop_solver.cpp diff --git a/src/muz/pdr_prop_solver.h b/src/muz/pdr/pdr_prop_solver.h similarity index 100% rename from src/muz/pdr_prop_solver.h rename to src/muz/pdr/pdr_prop_solver.h diff --git a/src/muz/pdr_reachable_cache.cpp b/src/muz/pdr/pdr_reachable_cache.cpp similarity index 100% rename from src/muz/pdr_reachable_cache.cpp rename to src/muz/pdr/pdr_reachable_cache.cpp diff --git a/src/muz/pdr_reachable_cache.h b/src/muz/pdr/pdr_reachable_cache.h similarity index 100% rename from src/muz/pdr_reachable_cache.h rename to src/muz/pdr/pdr_reachable_cache.h diff --git a/src/muz/pdr_smt_context_manager.cpp b/src/muz/pdr/pdr_smt_context_manager.cpp similarity index 100% rename from src/muz/pdr_smt_context_manager.cpp rename to src/muz/pdr/pdr_smt_context_manager.cpp diff --git a/src/muz/pdr_smt_context_manager.h b/src/muz/pdr/pdr_smt_context_manager.h similarity index 100% rename from src/muz/pdr_smt_context_manager.h rename to src/muz/pdr/pdr_smt_context_manager.h diff --git a/src/muz/pdr_sym_mux.cpp b/src/muz/pdr/pdr_sym_mux.cpp similarity index 100% rename from src/muz/pdr_sym_mux.cpp rename to src/muz/pdr/pdr_sym_mux.cpp diff --git a/src/muz/pdr_sym_mux.h b/src/muz/pdr/pdr_sym_mux.h similarity index 100% rename from src/muz/pdr_sym_mux.h rename to src/muz/pdr/pdr_sym_mux.h diff --git a/src/muz/pdr_util.cpp b/src/muz/pdr/pdr_util.cpp similarity index 100% rename from src/muz/pdr_util.cpp rename to src/muz/pdr/pdr_util.cpp diff --git a/src/muz/pdr_util.h b/src/muz/pdr/pdr_util.h similarity index 100% rename from src/muz/pdr_util.h rename to src/muz/pdr/pdr_util.h diff --git a/src/muz/aig_exporter.cpp b/src/muz/rel/aig_exporter.cpp similarity index 100% rename from src/muz/aig_exporter.cpp rename to src/muz/rel/aig_exporter.cpp diff --git a/src/muz/aig_exporter.h b/src/muz/rel/aig_exporter.h similarity index 100% rename from src/muz/aig_exporter.h rename to src/muz/rel/aig_exporter.h index 20b31f01b..78ab9fe17 100644 --- a/src/muz/aig_exporter.h +++ b/src/muz/rel/aig_exporter.h @@ -16,9 +16,9 @@ Abstract: #include "aig.h" #include "dl_rule_set.h" -#include "rel_context.h" #include #include +#include "rel_context.h" namespace datalog { class aig_exporter { diff --git a/src/muz/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp similarity index 99% rename from src/muz/dl_compiler.cpp rename to src/muz/rel/dl_compiler.cpp index 7a2b47c78..931846c35 100644 --- a/src/muz/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -21,6 +21,7 @@ Revision History: #include #include"ref_vector.h" #include"dl_context.h" +#include"rel_context.h" #include"dl_rule.h" #include"dl_util.h" #include"dl_compiler.h" diff --git a/src/muz/dl_compiler.h b/src/muz/rel/dl_compiler.h similarity index 100% rename from src/muz/dl_compiler.h rename to src/muz/rel/dl_compiler.h diff --git a/src/muz/dl_instruction.cpp b/src/muz/rel/dl_instruction.cpp similarity index 98% rename from src/muz/dl_instruction.cpp rename to src/muz/rel/dl_instruction.cpp index 55327f55b..a702c27ce 100644 --- a/src/muz/dl_instruction.cpp +++ b/src/muz/rel/dl_instruction.cpp @@ -22,6 +22,7 @@ Revision History: #include"dl_context.h" #include"dl_util.h" #include"dl_instruction.h" +#include"rel_context.h" #include"debug.h" #include"warning.h" @@ -59,7 +60,7 @@ namespace datalog { } rel_context& execution_context::get_rel_context() { - return *m_context.get_rel_context(); + return dynamic_cast(*m_context.get_rel_context()); } struct compare_size_proc { @@ -140,8 +141,9 @@ namespace datalog { process_costs(); } - void instruction::display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const { + void instruction::display_indented(rel_context_base const & _ctx, std::ostream & out, std::string indentation) const { out << indentation; + rel_context const& ctx = dynamic_cast(_ctx); display_head_impl(ctx, out); if (ctx.output_profile()) { out << " {"; @@ -313,7 +315,7 @@ namespace datalog { out << "while"; print_container(m_controls, out); } - virtual void display_body_impl(rel_context const & ctx, std::ostream & out, std::string indentation) const { + virtual void display_body_impl(rel_context_base const & ctx, std::ostream & out, std::string indentation) const { m_body->display_indented(ctx, out, indentation+" "); } }; @@ -1102,7 +1104,8 @@ namespace datalog { } } - void instruction_block::display_indented(rel_context const& ctx, std::ostream & out, std::string indentation) const { + void instruction_block::display_indented(rel_context_base const& _ctx, std::ostream & out, std::string indentation) const { + rel_context const& ctx = dynamic_cast(_ctx); instr_seq_type::const_iterator it = m_data.begin(); instr_seq_type::const_iterator end = m_data.end(); for(; it!=end; ++it) { diff --git a/src/muz/dl_instruction.h b/src/muz/rel/dl_instruction.h similarity index 96% rename from src/muz/dl_instruction.h rename to src/muz/rel/dl_instruction.h index 97622c6f3..fa705a172 100644 --- a/src/muz/dl_instruction.h +++ b/src/muz/rel/dl_instruction.h @@ -26,6 +26,7 @@ Revision History: #include "vector.h" #include "dl_base.h" #include "dl_costs.h" +#include "dl_context.h" namespace datalog { @@ -231,10 +232,10 @@ namespace datalog { virtual void make_annotations(execution_context & ctx) = 0; - void display(rel_context const& ctx, std::ostream & out) const { + void display(rel_context_base const& ctx, std::ostream & out) const { display_indented(ctx, out, ""); } - void display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const; + void display_indented(rel_context_base const & ctx, std::ostream & out, std::string indentation) const; static instruction * mk_load(ast_manager & m, func_decl * pred, reg_idx tgt); /** @@ -335,10 +336,10 @@ namespace datalog { void make_annotations(execution_context & ctx); - void display(rel_context const & ctx, std::ostream & out) const { + void display(rel_context_base const & ctx, std::ostream & out) const { display_indented(ctx, out, ""); } - void display_indented(rel_context const & ctx, std::ostream & out, std::string indentation) const; + void display_indented(rel_context_base const & ctx, std::ostream & out, std::string indentation) const; }; diff --git a/src/muz/rel_context.cpp b/src/muz/rel/rel_context.cpp similarity index 89% rename from src/muz/rel_context.cpp rename to src/muz/rel/rel_context.cpp index 75f68c7f1..c57ef2606 100644 --- a/src/muz/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -29,12 +29,23 @@ Revision History: #include"dl_product_relation.h" #include"dl_bound_relation.h" #include"dl_interval_relation.h" -#include"dl_mk_karr_invariants.h" +#include"karr_relation.h" #include"dl_finite_product_relation.h" #include"dl_sparse_table.h" #include"dl_table.h" #include"dl_table_relation.h" #include"aig_exporter.h" +#include"dl_mk_simple_joins.h" +#include"dl_mk_similarity_compressor.h" +#include"dl_mk_unbound_compressor.h" +#include"dl_mk_subsumption_checker.h" +#include"dl_mk_partial_equiv.h" +#include"dl_mk_coi_filter.h" +#include"dl_mk_filter_rules.h" +#include"dl_mk_rule_inliner.h" +#include"dl_mk_interp_tail_simplifier.h" +#include"dl_mk_bit_blast.h" + namespace datalog { @@ -75,7 +86,7 @@ namespace datalog { }; rel_context::rel_context(context& ctx) - : engine_base(ctx.get_manager(), "datalog"), + : rel_context_base(ctx.get_manager(), "datalog"), m_context(ctx), m(ctx.get_manager()), m_rmanager(ctx), @@ -127,7 +138,7 @@ namespace datalog { m_code.reset(); termination_code.reset(); m_context.ensure_closed(); - m_context.transform_rules(); + transform_rules(); if (m_context.canceled()) { result = l_undef; break; @@ -252,6 +263,39 @@ namespace datalog { return res; } + void rel_context::transform_rules() { + rule_transformer transf(m_context); + transf.register_plugin(alloc(mk_coi_filter, m_context)); + transf.register_plugin(alloc(mk_filter_rules, m_context)); + transf.register_plugin(alloc(mk_simple_joins, m_context)); + if (m_context.unbound_compressor()) { + transf.register_plugin(alloc(mk_unbound_compressor, m_context)); + } + if (m_context.similarity_compressor()) { + transf.register_plugin(alloc(mk_similarity_compressor, m_context)); + } + transf.register_plugin(alloc(mk_partial_equivalence_transformer, m_context)); + transf.register_plugin(alloc(mk_rule_inliner, m_context)); + transf.register_plugin(alloc(mk_interp_tail_simplifier, m_context)); + + if (m_context.get_params().bit_blast()) { + transf.register_plugin(alloc(mk_bit_blast, m_context, 22000)); + transf.register_plugin(alloc(mk_interp_tail_simplifier, m_context, 21000)); + } + m_context.transform_rules(transf); + } + + bool rel_context::try_get_size(func_decl* p, unsigned& rel_size) const { + relation_base* rb = try_get_relation(p); + if (rb && rb->knows_exact_size()) { + rel_size = rb->get_size_estimate_rows(); + return true; + } + else { + return false; + } + } + lbool rel_context::query(expr* query) { get_rmanager().reset_saturated_marks(); scoped_query _scoped_query(m_context); @@ -372,6 +416,20 @@ namespace datalog { relation_base & rel_context::get_relation(func_decl * pred) { return get_rmanager().get_relation(pred); } relation_base * rel_context::try_get_relation(func_decl * pred) const { return get_rmanager().try_get_relation(pred); } + expr_ref rel_context::try_get_formula(func_decl* p) const { + expr_ref result(m); + relation_base* rb = try_get_relation(p); + if (rb) { + rb->to_formula(result); + } + return result; + } + + bool rel_context::is_empty_relation(func_decl* pred) const { + relation_base* rb = try_get_relation(pred); + return !rb || rb->empty(); + } + relation_manager & rel_context::get_rmanager() { return m_rmanager; } const relation_manager & rel_context::get_rmanager() const { return m_rmanager; } diff --git a/src/muz/rel_context.h b/src/muz/rel/rel_context.h similarity index 55% rename from src/muz/rel_context.h rename to src/muz/rel/rel_context.h index 20da827ce..68a6fbd90 100644 --- a/src/muz/rel_context.h +++ b/src/muz/rel/rel_context.h @@ -23,6 +23,8 @@ Revision History: #include "ast.h" #include "dl_relation_manager.h" #include "dl_instruction.h" +#include "dl_engine_base.h" +#include "dl_context.h" #include "lbool.h" namespace datalog { @@ -30,7 +32,7 @@ namespace datalog { class context; typedef vector > fact_vector; - class rel_context : public engine_base { + class rel_context : public rel_context_base { context& m_context; ast_manager& m; relation_manager m_rmanager; @@ -50,30 +52,33 @@ namespace datalog { lbool saturate(scoped_query& sq); + void set_cancel(bool f); + public: rel_context(context& ctx); - ~rel_context(); + virtual ~rel_context(); - relation_manager & get_rmanager(); - const relation_manager & get_rmanager() const; + virtual relation_manager & get_rmanager(); + virtual const relation_manager & get_rmanager() const; ast_manager& get_manager() const { return m; } context& get_context() const { return m_context; } - relation_base & get_relation(func_decl * pred); - relation_base * try_get_relation(func_decl * pred) const; + virtual relation_base & get_relation(func_decl * pred); + virtual relation_base * try_get_relation(func_decl * pred) const; + virtual bool is_empty_relation(func_decl* pred) const; + virtual expr_ref try_get_formula(func_decl * pred) const; virtual expr_ref get_answer() { return m_answer; } - bool output_profile() const; + virtual bool output_profile() const; virtual lbool query(expr* q); - lbool query(unsigned num_rels, func_decl * const* rels); + virtual lbool query(unsigned num_rels, func_decl * const* rels); - void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, + virtual void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, symbol const * relation_names); - void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred); + virtual void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred); - void set_cancel(bool f); virtual void cancel() { set_cancel(true); } virtual void cleanup() { set_cancel(false);} @@ -83,35 +88,41 @@ namespace datalog { The function deallocates unsused relations, it does not deal with rules. */ - void restrict_predicates(func_decl_set const& predicates); + virtual void restrict_predicates(func_decl_set const& predicates); + virtual void transform_rules(); + virtual bool try_get_size(func_decl* pred, unsigned& rel_size) const; /** \brief query result if it contains fact. */ - bool result_contains_fact(relation_fact const& f); + virtual bool result_contains_fact(relation_fact const& f); + + virtual void collect_non_empty_predicates(func_decl_set& ps) { + return get_rmanager().collect_non_empty_predicates(ps); + } /** \brief add facts to relation */ - void add_fact(func_decl* pred, relation_fact const& fact); - void add_fact(func_decl* pred, table_fact const& fact); + virtual void add_fact(func_decl* pred, relation_fact const& fact); + virtual void add_fact(func_decl* pred, table_fact const& fact); /** \brief check if facts were added to relation */ - bool has_facts(func_decl * pred) const; + virtual bool has_facts(func_decl * pred) const; /** \brief Store the relation \c rel under the predicate \c pred. The \c context object takes over the ownership of the relation object. */ - void store_relation(func_decl * pred, relation_base * rel); + virtual void store_relation(func_decl * pred, relation_base * rel); - void display_output_facts(rule_set const& rules, std::ostream & out) const; - void display_facts(std::ostream & out) const; + virtual void display_output_facts(rule_set const& rules, std::ostream & out) const; + virtual void display_facts(std::ostream & out) const; - void display_profile(std::ostream& out); + virtual void display_profile(std::ostream& out); - lbool saturate(); + virtual lbool saturate(); }; }; diff --git a/src/muz/tab_context.cpp b/src/muz/tab/tab_context.cpp similarity index 100% rename from src/muz/tab_context.cpp rename to src/muz/tab/tab_context.cpp diff --git a/src/muz/tab_context.h b/src/muz/tab/tab_context.h similarity index 96% rename from src/muz/tab_context.h rename to src/muz/tab/tab_context.h index c23ccb7d3..4689598c0 100644 --- a/src/muz/tab_context.h +++ b/src/muz/tab/tab_context.h @@ -22,7 +22,7 @@ Revision History: #include "ast.h" #include "lbool.h" #include "statistics.h" -#include "dl_util.h" +#include "dl_engine_base.h" namespace datalog { class context; diff --git a/src/muz/dl_mk_array_blast.cpp b/src/muz/transforms/dl_mk_array_blast.cpp similarity index 100% rename from src/muz/dl_mk_array_blast.cpp rename to src/muz/transforms/dl_mk_array_blast.cpp diff --git a/src/muz/dl_mk_array_blast.h b/src/muz/transforms/dl_mk_array_blast.h similarity index 100% rename from src/muz/dl_mk_array_blast.h rename to src/muz/transforms/dl_mk_array_blast.h diff --git a/src/muz/dl_mk_backwards.cpp b/src/muz/transforms/dl_mk_backwards.cpp similarity index 100% rename from src/muz/dl_mk_backwards.cpp rename to src/muz/transforms/dl_mk_backwards.cpp diff --git a/src/muz/dl_mk_backwards.h b/src/muz/transforms/dl_mk_backwards.h similarity index 100% rename from src/muz/dl_mk_backwards.h rename to src/muz/transforms/dl_mk_backwards.h diff --git a/src/muz/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp similarity index 100% rename from src/muz/dl_mk_bit_blast.cpp rename to src/muz/transforms/dl_mk_bit_blast.cpp diff --git a/src/muz/dl_mk_bit_blast.h b/src/muz/transforms/dl_mk_bit_blast.h similarity index 100% rename from src/muz/dl_mk_bit_blast.h rename to src/muz/transforms/dl_mk_bit_blast.h diff --git a/src/muz/dl_mk_coalesce.cpp b/src/muz/transforms/dl_mk_coalesce.cpp similarity index 100% rename from src/muz/dl_mk_coalesce.cpp rename to src/muz/transforms/dl_mk_coalesce.cpp diff --git a/src/muz/dl_mk_coalesce.h b/src/muz/transforms/dl_mk_coalesce.h similarity index 100% rename from src/muz/dl_mk_coalesce.h rename to src/muz/transforms/dl_mk_coalesce.h diff --git a/src/muz/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp similarity index 92% rename from src/muz/dl_mk_coi_filter.cpp rename to src/muz/transforms/dl_mk_coi_filter.cpp index a0fc845bf..fc4c411ff 100644 --- a/src/muz/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -48,7 +48,7 @@ namespace datalog { } rule_set * mk_coi_filter::bottom_up(rule_set const & source) { - decl_set all, reached; + func_decl_set all, reached; ptr_vector todo; rule_set::decl2rules body2rules; // initialization for reachability @@ -117,7 +117,7 @@ namespace datalog { // set to false each unreached predicate if (m_context.get_model_converter()) { extension_model_converter* mc0 = alloc(extension_model_converter, m); - for (decl_set::iterator it = all.begin(); it != all.end(); ++it) { + for (func_decl_set::iterator it = all.begin(); it != all.end(); ++it) { if (!reached.contains(*it)) { mc0->insert(*it, m.mk_false()); } @@ -134,13 +134,13 @@ namespace datalog { rule_set * mk_coi_filter::top_down(rule_set const & source) { - decl_set interesting_preds; - decl_set pruned_preds; + func_decl_set interesting_preds; + func_decl_set pruned_preds; ptr_vector todo; { - const decl_set& output_preds = source.get_output_predicates(); - decl_set::iterator oend = output_preds.end(); - for (decl_set::iterator it = output_preds.begin(); it!=oend; ++it) { + const func_decl_set& output_preds = source.get_output_predicates(); + func_decl_set::iterator oend = output_preds.end(); + for (func_decl_set::iterator it = output_preds.begin(); it!=oend; ++it) { todo.push_back(*it); interesting_preds.insert(*it); } @@ -185,8 +185,8 @@ namespace datalog { } if (res && m_context.get_model_converter()) { - decl_set::iterator end = pruned_preds.end(); - decl_set::iterator it = pruned_preds.begin(); + func_decl_set::iterator end = pruned_preds.end(); + func_decl_set::iterator it = pruned_preds.begin(); extension_model_converter* mc0 = alloc(extension_model_converter, m); for (; it != end; ++it) { mc0->insert(*it, m.mk_true()); diff --git a/src/muz/dl_mk_coi_filter.h b/src/muz/transforms/dl_mk_coi_filter.h similarity index 100% rename from src/muz/dl_mk_coi_filter.h rename to src/muz/transforms/dl_mk_coi_filter.h diff --git a/src/muz/dl_mk_different.h b/src/muz/transforms/dl_mk_different.h similarity index 100% rename from src/muz/dl_mk_different.h rename to src/muz/transforms/dl_mk_different.h diff --git a/src/muz/dl_mk_filter_rules.cpp b/src/muz/transforms/dl_mk_filter_rules.cpp similarity index 100% rename from src/muz/dl_mk_filter_rules.cpp rename to src/muz/transforms/dl_mk_filter_rules.cpp diff --git a/src/muz/dl_mk_filter_rules.h b/src/muz/transforms/dl_mk_filter_rules.h similarity index 100% rename from src/muz/dl_mk_filter_rules.h rename to src/muz/transforms/dl_mk_filter_rules.h diff --git a/src/muz/dl_mk_interp_tail_simplifier.cpp b/src/muz/transforms/dl_mk_interp_tail_simplifier.cpp similarity index 100% rename from src/muz/dl_mk_interp_tail_simplifier.cpp rename to src/muz/transforms/dl_mk_interp_tail_simplifier.cpp diff --git a/src/muz/dl_mk_interp_tail_simplifier.h b/src/muz/transforms/dl_mk_interp_tail_simplifier.h similarity index 100% rename from src/muz/dl_mk_interp_tail_simplifier.h rename to src/muz/transforms/dl_mk_interp_tail_simplifier.h diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp new file mode 100644 index 000000000..4c0a24b65 --- /dev/null +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -0,0 +1,325 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_karr_invariants.cpp + +Abstract: + + Extract integer linear invariants. + + The linear invariants are extracted according to Karr's method. + A short description is in + Nikolaj Bjorner, Anca Browne and Zohar Manna. Automatic Generation + of Invariants and Intermediate Assertions, in CP 95. + + The algorithm is here adapted to Horn clauses. + The idea is to maintain two data-structures for each recursive relation. + We call them R and RD + - R - set of linear congruences that are true of R. + - RD - the dual basis of of solutions for R. + + RD is updated by accumulating basis vectors for solutions + to R (the homogeneous dual of R) + R is updated from the inhomogeneous dual of RD. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-09 + +Revision History: + +--*/ + +#include"expr_safe_replace.h" +#include"bool_rewriter.h" +#include"for_each_expr.h" + +#include"dl_mk_karr_invariants.h" +#include"dl_mk_backwards.h" +#include"dl_mk_loop_counter.h" + +namespace datalog { + + + mk_karr_invariants::mk_karr_invariants(context & ctx, unsigned priority): + rule_transformer::plugin(priority, false), + m_ctx(ctx), + m(ctx.get_manager()), + rm(ctx.get_rule_manager()), + m_inner_ctx(m, ctx.get_register_engine(), ctx.get_fparams()), + a(m), + m_pinned(m), + m_cancel(false) { + params_ref params; + params.set_sym("default_relation", symbol("karr_relation")); + params.set_sym("engine", symbol("datalog")); + params.set_bool("karr", false); + m_inner_ctx.updt_params(params); + } + + mk_karr_invariants::~mk_karr_invariants() { } + + matrix& matrix::operator=(matrix const& other) { + reset(); + append(other); + return *this; + } + + void matrix::display_row( + std::ostream& out, vector const& row, rational const& b, bool is_eq) { + for (unsigned j = 0; j < row.size(); ++j) { + out << row[j] << " "; + } + out << (is_eq?" = ":" >= ") << -b << "\n"; + } + + void matrix::display_ineq( + std::ostream& out, vector const& row, rational const& b, bool is_eq) { + bool first = true; + for (unsigned j = 0; j < row.size(); ++j) { + if (!row[j].is_zero()) { + if (!first && row[j].is_pos()) { + out << "+ "; + } + if (row[j].is_minus_one()) { + out << "- "; + } + if (row[j] > rational(1) || row[j] < rational(-1)) { + out << row[j] << "*"; + } + out << "x" << j << " "; + first = false; + } + } + out << (is_eq?"= ":">= ") << -b << "\n"; + } + + void matrix::display(std::ostream& out) const { + for (unsigned i = 0; i < A.size(); ++i) { + display_row(out, A[i], b[i], eq[i]); + } + } + + + class mk_karr_invariants::add_invariant_model_converter : public model_converter { + ast_manager& m; + arith_util a; + func_decl_ref_vector m_funcs; + expr_ref_vector m_invs; + public: + + add_invariant_model_converter(ast_manager& m): m(m), a(m), m_funcs(m), m_invs(m) {} + + virtual ~add_invariant_model_converter() { } + + void add(func_decl* p, expr* inv) { + if (!m.is_true(inv)) { + m_funcs.push_back(p); + m_invs.push_back(inv); + } + } + + virtual void operator()(model_ref & mr) { + for (unsigned i = 0; i < m_funcs.size(); ++i) { + func_decl* p = m_funcs[i].get(); + func_interp* f = mr->get_func_interp(p); + expr_ref body(m); + unsigned arity = p->get_arity(); + SASSERT(0 < arity); + if (f) { + SASSERT(f->num_entries() == 0); + if (!f->is_partial()) { + bool_rewriter(m).mk_and(f->get_else(), m_invs[i].get(), body); + } + } + else { + f = alloc(func_interp, m, arity); + mr->register_decl(p, f); + body = m.mk_false(); // fragile: assume that relation was pruned by being infeasible. + } + f->set_else(body); + } + } + + virtual model_converter * translate(ast_translation & translator) { + add_invariant_model_converter* mc = alloc(add_invariant_model_converter, m); + for (unsigned i = 0; i < m_funcs.size(); ++i) { + mc->add(translator(m_funcs[i].get()), m_invs[i].get()); + } + return mc; + } + + private: + void mk_body(matrix const& M, expr_ref& body) { + expr_ref_vector conj(m); + for (unsigned i = 0; i < M.size(); ++i) { + mk_body(M.A[i], M.b[i], M.eq[i], conj); + } + bool_rewriter(m).mk_and(conj.size(), conj.c_ptr(), body); + } + + void mk_body(vector const& row, rational const& b, bool is_eq, expr_ref_vector& conj) { + expr_ref_vector sum(m); + expr_ref zero(m), lhs(m); + zero = a.mk_numeral(rational(0), true); + + for (unsigned i = 0; i < row.size(); ++i) { + if (row[i].is_zero()) { + continue; + } + var* var = m.mk_var(i, a.mk_int()); + if (row[i].is_one()) { + sum.push_back(var); + } + else { + sum.push_back(a.mk_mul(a.mk_numeral(row[i], true), var)); + } + } + if (!b.is_zero()) { + sum.push_back(a.mk_numeral(b, true)); + } + lhs = a.mk_add(sum.size(), sum.c_ptr()); + if (is_eq) { + conj.push_back(m.mk_eq(lhs, zero)); + } + else { + conj.push_back(a.mk_ge(lhs, zero)); + } + } + }; + + void mk_karr_invariants::cancel() { + m_cancel = true; + m_inner_ctx.cancel(); + } + + rule_set * mk_karr_invariants::operator()(rule_set const & source) { + if (!m_ctx.get_params().karr()) { + return 0; + } + rule_set::iterator it = source.begin(), end = source.end(); + for (; it != end; ++it) { + rule const& r = **it; + if (r.has_negation()) { + return 0; + } + } + mk_loop_counter lc(m_ctx); + mk_backwards bwd(m_ctx); + + scoped_ptr src_loop = lc(source); + TRACE("dl", src_loop->display(tout << "source loop\n");); + + get_invariants(*src_loop); + + if (m_cancel) { + return 0; + } + + // figure out whether to update same rules as used for saturation. + scoped_ptr rev_source = bwd(*src_loop); + get_invariants(*rev_source); + scoped_ptr src_annot = update_rules(*src_loop); + rule_set* rules = lc.revert(*src_annot); + rules->inherit_predicates(source); + TRACE("dl", rules->display(tout);); + m_pinned.reset(); + m_fun2inv.reset(); + return rules; + } + + void mk_karr_invariants::get_invariants(rule_set const& src) { + m_inner_ctx.reset(); + rel_context_base& rctx = *m_inner_ctx.get_rel_context(); + ptr_vector heads; + func_decl_set const& predicates = m_ctx.get_predicates(); + for (func_decl_set::iterator fit = predicates.begin(); fit != predicates.end(); ++fit) { + m_inner_ctx.register_predicate(*fit, false); + } + m_inner_ctx.ensure_opened(); + m_inner_ctx.replace_rules(src); + m_inner_ctx.close(); + rule_set::decl2rules::iterator dit = src.begin_grouped_rules(); + rule_set::decl2rules::iterator dend = src.end_grouped_rules(); + for (; dit != dend; ++dit) { + heads.push_back(dit->m_key); + } + m_inner_ctx.rel_query(heads.size(), heads.c_ptr()); + + // retrieve invariants. + dit = src.begin_grouped_rules(); + for (; dit != dend; ++dit) { + func_decl* p = dit->m_key; + expr_ref fml = rctx.try_get_formula(p); + if (fml && !m.is_true(fml)) { + expr* inv = 0; + if (m_fun2inv.find(p, inv)) { + fml = m.mk_and(inv, fml); + } + m_pinned.push_back(fml); + m_fun2inv.insert(p, fml); + } + } + } + + rule_set* mk_karr_invariants::update_rules(rule_set const& src) { + scoped_ptr dst = alloc(rule_set, m_ctx); + rule_set::iterator it = src.begin(), end = src.end(); + for (; it != end; ++it) { + update_body(*dst, **it); + } + if (m_ctx.get_model_converter()) { + add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m); + rule_set::decl2rules::iterator git = src.begin_grouped_rules(); + rule_set::decl2rules::iterator gend = src.end_grouped_rules(); + for (; git != gend; ++git) { + func_decl* p = git->m_key; + expr* fml = 0; + if (m_fun2inv.find(p, fml)) { + kmc->add(p, fml); + } + } + m_ctx.add_model_converter(kmc); + } + + dst->inherit_predicates(src); + return dst.detach(); + } + + void mk_karr_invariants::update_body(rule_set& rules, rule& r) { + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned tsz = r.get_tail_size(); + app_ref_vector tail(m); + expr_ref fml(m); + for (unsigned i = 0; i < tsz; ++i) { + tail.push_back(r.get_tail(i)); + } + for (unsigned i = 0; i < utsz; ++i) { + func_decl* q = r.get_decl(i); + expr* fml = 0; + if (m_fun2inv.find(q, fml)) { + expr_safe_replace rep(m); + for (unsigned j = 0; j < q->get_arity(); ++j) { + rep.insert(m.mk_var(j, q->get_domain(j)), + r.get_tail(i)->get_arg(j)); + } + expr_ref tmp(fml, m); + rep(tmp); + tail.push_back(to_app(tmp)); + } + } + rule* new_rule = &r; + if (tail.size() != tsz) { + new_rule = rm.mk(r.get_head(), tail.size(), tail.c_ptr(), 0, r.name()); + } + rules.add_rule(new_rule); + rm.mk_rule_rewrite_proof(r, *new_rule); // should be weakening rule. + } + + + + +}; + diff --git a/src/muz/transforms/dl_mk_karr_invariants.h b/src/muz/transforms/dl_mk_karr_invariants.h new file mode 100644 index 000000000..378a7e587 --- /dev/null +++ b/src/muz/transforms/dl_mk_karr_invariants.h @@ -0,0 +1,81 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_mk_karr_invariants.h + +Abstract: + + Extract integer linear invariants. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-08 + +Revision History: + +--*/ +#ifndef _DL_MK_KARR_INVARIANTS_H_ +#define _DL_MK_KARR_INVARIANTS_H_ + +#include"dl_context.h" +#include"dl_rule_set.h" +#include"dl_rule_transformer.h" +#include"arith_decl_plugin.h" +#include"hilbert_basis.h" + +namespace datalog { + + /** + \brief Rule transformer that strengthens bodies with invariants. + */ + + struct matrix { + vector > A; + vector b; + svector eq; + unsigned size() const { return A.size(); } + void reset() { A.reset(); b.reset(); eq.reset(); } + matrix& operator=(matrix const& other); + void append(matrix const& other) { A.append(other.A); b.append(other.b); eq.append(other.eq); } + void display(std::ostream& out) const; + static void display_row( + std::ostream& out, vector const& row, rational const& b, bool is_eq); + static void display_ineq( + std::ostream& out, vector const& row, rational const& b, bool is_eq); + }; + + class mk_karr_invariants : public rule_transformer::plugin { + + class add_invariant_model_converter; + + context& m_ctx; + ast_manager& m; + rule_manager& rm; + context m_inner_ctx; + arith_util a; + obj_map m_fun2inv; + ast_ref_vector m_pinned; + volatile bool m_cancel; + + void get_invariants(rule_set const& src); + + void update_body(rule_set& result, rule& r); + rule_set* update_rules(rule_set const& src); + public: + mk_karr_invariants(context & ctx, unsigned priority); + + virtual ~mk_karr_invariants(); + + virtual void cancel(); + + rule_set * operator()(rule_set const & source); + + }; + + +}; + +#endif /* _DL_MK_KARR_INVARIANTS_H_ */ + diff --git a/src/muz/dl_mk_loop_counter.cpp b/src/muz/transforms/dl_mk_loop_counter.cpp similarity index 100% rename from src/muz/dl_mk_loop_counter.cpp rename to src/muz/transforms/dl_mk_loop_counter.cpp diff --git a/src/muz/dl_mk_loop_counter.h b/src/muz/transforms/dl_mk_loop_counter.h similarity index 100% rename from src/muz/dl_mk_loop_counter.h rename to src/muz/transforms/dl_mk_loop_counter.h diff --git a/src/muz/dl_mk_magic_sets.cpp b/src/muz/transforms/dl_mk_magic_sets.cpp similarity index 99% rename from src/muz/dl_mk_magic_sets.cpp rename to src/muz/transforms/dl_mk_magic_sets.cpp index 24d9d01cb..48bd69255 100644 --- a/src/muz/dl_mk_magic_sets.cpp +++ b/src/muz/transforms/dl_mk_magic_sets.cpp @@ -362,7 +362,7 @@ namespace datalog { rule * r = *it; transform_rule(task.m_adornment, r, *result); } - if (!m_context.get_rel_context()->get_relation(task.m_pred).empty()) { + if (!m_context.get_rel_context()->is_empty_relation(task.m_pred)) { //we need a rule to copy facts that are already in a relation into the adorned //relation (since out intentional predicates can have facts, not only rules) create_transfer_rule(task, *result); diff --git a/src/muz/dl_mk_magic_sets.h b/src/muz/transforms/dl_mk_magic_sets.h similarity index 100% rename from src/muz/dl_mk_magic_sets.h rename to src/muz/transforms/dl_mk_magic_sets.h diff --git a/src/muz/dl_mk_magic_symbolic.cpp b/src/muz/transforms/dl_mk_magic_symbolic.cpp similarity index 100% rename from src/muz/dl_mk_magic_symbolic.cpp rename to src/muz/transforms/dl_mk_magic_symbolic.cpp diff --git a/src/muz/dl_mk_magic_symbolic.h b/src/muz/transforms/dl_mk_magic_symbolic.h similarity index 100% rename from src/muz/dl_mk_magic_symbolic.h rename to src/muz/transforms/dl_mk_magic_symbolic.h diff --git a/src/muz/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp similarity index 100% rename from src/muz/dl_mk_quantifier_abstraction.cpp rename to src/muz/transforms/dl_mk_quantifier_abstraction.cpp diff --git a/src/muz/dl_mk_quantifier_abstraction.h b/src/muz/transforms/dl_mk_quantifier_abstraction.h similarity index 100% rename from src/muz/dl_mk_quantifier_abstraction.h rename to src/muz/transforms/dl_mk_quantifier_abstraction.h diff --git a/src/muz/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp similarity index 100% rename from src/muz/dl_mk_quantifier_instantiation.cpp rename to src/muz/transforms/dl_mk_quantifier_instantiation.cpp diff --git a/src/muz/dl_mk_quantifier_instantiation.h b/src/muz/transforms/dl_mk_quantifier_instantiation.h similarity index 100% rename from src/muz/dl_mk_quantifier_instantiation.h rename to src/muz/transforms/dl_mk_quantifier_instantiation.h diff --git a/src/muz/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp similarity index 99% rename from src/muz/dl_mk_rule_inliner.cpp rename to src/muz/transforms/dl_mk_rule_inliner.cpp index 5e0d6446b..65ce44b8b 100644 --- a/src/muz/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -49,9 +49,6 @@ Subsumption transformation (remove rule): #include #include "ast_pp.h" -#include "dl_finite_product_relation.h" -#include "dl_product_relation.h" -#include "dl_sieve_relation.h" #include "rewriter.h" #include "rewriter_def.h" #include "dl_mk_rule_inliner.h" @@ -206,9 +203,9 @@ namespace datalog { void mk_rule_inliner::count_pred_occurrences(rule_set const & orig) { - rel_context* rel = m_context.get_rel_context(); + rel_context_base* rel = m_context.get_rel_context(); if (rel) { - rel->get_rmanager().collect_non_empty_predicates(m_preds_with_facts); + rel->collect_non_empty_predicates(m_preds_with_facts); } rule_set::iterator rend = orig.end(); diff --git a/src/muz/dl_mk_rule_inliner.h b/src/muz/transforms/dl_mk_rule_inliner.h similarity index 98% rename from src/muz/dl_mk_rule_inliner.h rename to src/muz/transforms/dl_mk_rule_inliner.h index 3a933f990..ed555492a 100644 --- a/src/muz/dl_mk_rule_inliner.h +++ b/src/muz/transforms/dl_mk_rule_inliner.h @@ -106,9 +106,9 @@ namespace datalog { context & m_context; th_rewriter& m_simp; rule_ref_vector m_pinned; - decl_set m_forbidden_preds; - decl_set m_preds_with_facts; - decl_set m_preds_with_neg_occurrence; + func_decl_set m_forbidden_preds; + func_decl_set m_preds_with_facts; + func_decl_set m_preds_with_neg_occurrence; ast_counter m_head_pred_ctr; ast_counter m_head_pred_non_empty_tails_ctr; ast_counter m_tail_pred_ctr; diff --git a/src/muz/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp similarity index 100% rename from src/muz/dl_mk_scale.cpp rename to src/muz/transforms/dl_mk_scale.cpp diff --git a/src/muz/dl_mk_scale.h b/src/muz/transforms/dl_mk_scale.h similarity index 100% rename from src/muz/dl_mk_scale.h rename to src/muz/transforms/dl_mk_scale.h diff --git a/src/muz/dl_mk_slice.cpp b/src/muz/transforms/dl_mk_slice.cpp similarity index 100% rename from src/muz/dl_mk_slice.cpp rename to src/muz/transforms/dl_mk_slice.cpp diff --git a/src/muz/dl_mk_slice.h b/src/muz/transforms/dl_mk_slice.h similarity index 100% rename from src/muz/dl_mk_slice.h rename to src/muz/transforms/dl_mk_slice.h diff --git a/src/muz/dl_mk_subsumption_checker.cpp b/src/muz/transforms/dl_mk_subsumption_checker.cpp similarity index 96% rename from src/muz/dl_mk_subsumption_checker.cpp rename to src/muz/transforms/dl_mk_subsumption_checker.cpp index 0d32a5c3b..9b2c5627b 100644 --- a/src/muz/dl_mk_subsumption_checker.cpp +++ b/src/muz/transforms/dl_mk_subsumption_checker.cpp @@ -24,7 +24,6 @@ Revision History: #include "rewriter.h" #include "rewriter_def.h" #include"dl_mk_subsumption_checker.h" -#include"dl_table_relation.h" namespace datalog { @@ -249,23 +248,21 @@ namespace datalog { } void mk_subsumption_checker::scan_for_relations_total_due_to_facts(rule_set const& source) { - rel_context* rel = m_context.get_rel_context(); + rel_context_base* rel = m_context.get_rel_context(); if (!rel) { return; } relation_manager& rm = rel->get_rmanager(); - decl_set const& candidate_preds = m_context.get_predicates(); + func_decl_set const& candidate_preds = m_context.get_predicates(); - decl_set::iterator end = candidate_preds.end(); - for(decl_set::iterator it = candidate_preds.begin(); it!=end; ++it) { + func_decl_set::iterator end = candidate_preds.end(); + for(func_decl_set::iterator it = candidate_preds.begin(); it!=end; ++it) { func_decl * pred = *it; + unsigned rel_sz; - if (m_total_relations.contains(pred)) { continue; } //already total - - relation_base * rel = rm.try_get_relation(pred); - - if (!rel || !rel->knows_exact_size()) { continue; } + if (m_total_relations.contains(pred)) { continue; } // already total + if (!rel->try_get_size(pred, rel_sz)) { continue; } unsigned arity = pred->get_arity(); if (arity > 30) { continue; } @@ -280,7 +277,6 @@ namespace datalog { { unsigned total_size = 1<get_size_estimate_rows(); obj_hashtable * head_store; if(m_ground_unconditional_rule_heads.find(pred, head_store)) { diff --git a/src/muz/dl_mk_subsumption_checker.h b/src/muz/transforms/dl_mk_subsumption_checker.h similarity index 100% rename from src/muz/dl_mk_subsumption_checker.h rename to src/muz/transforms/dl_mk_subsumption_checker.h diff --git a/src/muz/dl_mk_unbound_compressor.cpp b/src/muz/transforms/dl_mk_unbound_compressor.cpp similarity index 99% rename from src/muz/dl_mk_unbound_compressor.cpp rename to src/muz/transforms/dl_mk_unbound_compressor.cpp index 71d4d5479..68c35e2c9 100644 --- a/src/muz/dl_mk_unbound_compressor.cpp +++ b/src/muz/transforms/dl_mk_unbound_compressor.cpp @@ -334,9 +334,9 @@ namespace datalog { // TODO mc m_modified = false; - rel_context* rel = m_context.get_rel_context(); + rel_context_base* rel = m_context.get_rel_context(); if (rel) { - rel->get_rmanager().collect_non_empty_predicates(m_non_empty_rels); + rel->collect_non_empty_predicates(m_non_empty_rels); } unsigned init_rule_cnt = source.get_num_rules(); SASSERT(m_rules.empty()); diff --git a/src/muz/dl_mk_unbound_compressor.h b/src/muz/transforms/dl_mk_unbound_compressor.h similarity index 98% rename from src/muz/dl_mk_unbound_compressor.h rename to src/muz/transforms/dl_mk_unbound_compressor.h index 4e2ff0b3c..44877e646 100644 --- a/src/muz/dl_mk_unbound_compressor.h +++ b/src/muz/transforms/dl_mk_unbound_compressor.h @@ -62,7 +62,7 @@ namespace datalog { /** Relations that contain facts */ - decl_set m_non_empty_rels; + func_decl_set m_non_empty_rels; ast_counter m_head_occurrence_ctr; diff --git a/src/muz/dl_mk_unfold.cpp b/src/muz/transforms/dl_mk_unfold.cpp similarity index 100% rename from src/muz/dl_mk_unfold.cpp rename to src/muz/transforms/dl_mk_unfold.cpp diff --git a/src/muz/dl_mk_unfold.h b/src/muz/transforms/dl_mk_unfold.h similarity index 100% rename from src/muz/dl_mk_unfold.h rename to src/muz/transforms/dl_mk_unfold.h diff --git a/src/muz/transforms/dl_transforms.cpp b/src/muz/transforms/dl_transforms.cpp new file mode 100644 index 000000000..7c5707ccf --- /dev/null +++ b/src/muz/transforms/dl_transforms.cpp @@ -0,0 +1,81 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_transforms.cpp + +Abstract: + + Default transformations. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-08-28. + +Revision History: + + Extracted from dl_context + +--*/ + +#include"dl_transforms.h" +#include"dl_rule_transformer.h" +#include"dl_mk_coi_filter.h" +#include"dl_mk_filter_rules.h" +#include"dl_mk_interp_tail_simplifier.h" +#include"dl_mk_rule_inliner.h" +#include"dl_mk_bit_blast.h" +#include"dl_mk_array_blast.h" +#include"dl_mk_karr_invariants.h" +#include"dl_mk_magic_symbolic.h" +#include"dl_mk_quantifier_abstraction.h" +#include"dl_mk_quantifier_instantiation.h" +#include"dl_mk_subsumption_checker.h" +#include"dl_mk_scale.h" + +namespace datalog { + + void apply_default_transformation(context& ctx) { + rule_transformer transf(ctx); + ctx.ensure_closed(); + transf.reset(); + transf.register_plugin(alloc(datalog::mk_coi_filter, ctx)); + transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, ctx)); + + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 35005)); + transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 35000)); + transf.register_plugin(alloc(datalog::mk_coi_filter, ctx, 34990)); + transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, ctx, 34980)); + + //and another round of inlining + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34975)); + transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34970)); + transf.register_plugin(alloc(datalog::mk_coi_filter, ctx, 34960)); + transf.register_plugin(alloc(datalog::mk_interp_tail_simplifier, ctx, 34950)); + + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34940)); + transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34930)); + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34920)); + transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34910)); + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34900)); + transf.register_plugin(alloc(datalog::mk_rule_inliner, ctx, 34890)); + transf.register_plugin(alloc(datalog::mk_subsumption_checker, ctx, 34880)); + + + if (ctx.get_params().quantify_arrays()) { + transf.register_plugin(alloc(datalog::mk_quantifier_abstraction, ctx, 33000)); + transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 32500)); + } + transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, ctx, 32000)); + + transf.register_plugin(alloc(datalog::mk_bit_blast, ctx, 35000)); + transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 36000)); + transf.register_plugin(alloc(datalog::mk_karr_invariants, ctx, 36010)); + if (ctx.get_params().magic()) { + transf.register_plugin(alloc(datalog::mk_magic_symbolic, ctx, 36020)); + } + transf.register_plugin(alloc(datalog::mk_scale, ctx, 36030)); + ctx.transform_rules(transf); + } +} diff --git a/src/muz/transforms/dl_transforms.h b/src/muz/transforms/dl_transforms.h new file mode 100644 index 000000000..4f9a92dd8 --- /dev/null +++ b/src/muz/transforms/dl_transforms.h @@ -0,0 +1,30 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_transforms.h + +Abstract: + + Default transformations. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-08-28. + +Revision History: + + Extracted from dl_context + +--*/ +#ifndef _DL_TRANSFORMS_H_ +#define _DL_TRANSFORMS_H_ + +#include "dl_context.h" + +namespace datalog { + void apply_default_transformation(context& ctx); +} + +#endif diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 56f60bfa0..15681ea36 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -31,6 +31,8 @@ Revision History: #include"dl_mk_filter_rules.h" #include"dl_finite_product_relation.h" #include"dl_context.h" +#include"rel_context.h" +#include"dl_register_engine.h" #include"datalog_parser.h" #include"datalog_frontend.h" #include"timeout.h" @@ -118,13 +120,14 @@ unsigned read_datalog(char const * file) { IF_VERBOSE(1, verbose_stream() << "Z3 Datalog Engine\n";); smt_params s_params; ast_manager m; + datalog::register_engine re; g_overall_time.start(); register_on_timeout_proc(on_timeout); signal(SIGINT, on_ctrl_c); params_ref params; params.set_sym("engine", symbol("datalog")); - datalog::context ctx(m, s_params, params); + datalog::context ctx(m, re, s_params, params); datalog::relation_manager & rmgr = ctx.get_rel_context()->get_rmanager(); datalog::relation_plugin & inner_plg = *rmgr.get_relation_plugin(symbol("tr_hashtable")); SASSERT(&inner_plg); @@ -179,11 +182,11 @@ unsigned read_datalog(char const * file) { bool early_termination; unsigned timeout = ctx.initial_restart_timeout(); - if(timeout == 0) { + if (timeout == 0) { timeout = UINT_MAX; } do { - ctx.transform_rules(); + ctx.get_rel_context()->transform_rules(); datalog::compiler::compile(ctx, ctx.get_rules(), rules_code, termination_code); diff --git a/src/test/datalog_parser.cpp b/src/test/datalog_parser.cpp index 64ee4201e..e23650e3b 100644 --- a/src/test/datalog_parser.cpp +++ b/src/test/datalog_parser.cpp @@ -2,6 +2,7 @@ #include "ast_pp.h" #include "arith_decl_plugin.h" #include "dl_context.h" +#include "dl_register_engine.h" #include "smt_params.h" #include "reg_decl_plugins.h" @@ -12,8 +13,8 @@ static void dparse_string(char const* str) { ast_manager m; smt_params params; reg_decl_plugins(m); - - context ctx(m, params); + register_engine re; + context ctx(m, re, params); parser* p = parser::create(ctx,m); bool res=p->parse_string(str); @@ -39,8 +40,9 @@ static void dparse_file(char const* file) { ast_manager m; smt_params params; reg_decl_plugins(m); + register_engine re; - context ctx(m, params); + context ctx(m, re, params); parser* p = parser::create(ctx,m); if (!p->parse_file(file)) { diff --git a/src/test/dl_context.cpp b/src/test/dl_context.cpp index 9e8a37974..5c70aa8b5 100644 --- a/src/test/dl_context.cpp +++ b/src/test/dl_context.cpp @@ -3,6 +3,7 @@ #include "arith_decl_plugin.h" #include "dl_context.h" #include "smt_params.h" +#include "dl_register_engine.h" using namespace datalog; @@ -26,9 +27,9 @@ static lbool dl_context_eval_unary_predicate(ast_manager & m, context & ctx, cha static void dl_context_simple_query_test(params_ref & params) { ast_manager m; dl_decl_util decl_util(m); - + register_engine re; smt_params fparams; - context ctx(m, fparams); + context ctx(m, re, fparams); ctx.updt_params(params); /* lbool status = */ dl_context_eval_unary_predicate(m, ctx, "Z 64\n\nP(x:Z)\nP(\"a\").", "P"); @@ -50,7 +51,8 @@ void dl_context_saturate_file(params_ref & params, const char * f) { ast_manager m; dl_decl_util decl_util(m); smt_params fparams; - context ctx(m, fparams); + register_engine re; + context ctx(m, re, fparams); ctx.updt_params(params); datalog::parser * parser = datalog::parser::create(ctx, m); diff --git a/src/test/dl_product_relation.cpp b/src/test/dl_product_relation.cpp index d58603be1..357ccd604 100644 --- a/src/test/dl_product_relation.cpp +++ b/src/test/dl_product_relation.cpp @@ -1,7 +1,9 @@ #ifdef _WINDOWS #include "dl_context.h" +#include "dl_register_engine.h" #include "dl_finite_product_relation.h" #include "dl_sparse_table.h" +#include "rel_context.h" namespace datalog { @@ -21,8 +23,9 @@ namespace datalog { void test_functional_columns(smt_params fparams, params_ref& params) { ast_manager m; - context ctx(m, fparams); - rel_context& rctx = *ctx.get_rel_context(); + register_engine re; + context ctx(m, re, fparams); + rel_context_base& rctx = *ctx.get_rel_context(); ctx.updt_params(params); relation_manager & rmgr(rctx.get_rmanager()); @@ -124,7 +127,8 @@ namespace datalog { void test_finite_product_relation(smt_params fparams, params_ref& params) { ast_manager m; - context ctx(m, fparams); + register_engine re; + context ctx(m, re, fparams); ctx.updt_params(params); dl_decl_util dl_util(m); relation_manager & rmgr = ctx.get_rel_context()->get_rmanager(); diff --git a/src/test/dl_query.cpp b/src/test/dl_query.cpp index 17781d7bb..bb991c65f 100644 --- a/src/test/dl_query.cpp +++ b/src/test/dl_query.cpp @@ -2,9 +2,11 @@ #include "ast_pp.h" #include "dl_table_relation.h" #include "dl_context.h" +#include "dl_register_engine.h" #include "smt_params.h" #include "stopwatch.h" #include "reg_decl_plugins.h" +#include "dl_relation_manager.h" using namespace datalog; @@ -50,7 +52,8 @@ void dl_query_test(ast_manager & m, smt_params & fparams, params_ref& params, dl_decl_util decl_util(m); random_gen ran(0); - context ctx_q(m, fparams); + register_engine re; + context ctx_q(m, re, fparams); params.set_bool("magic_sets_for_queries", use_magic_sets); ctx_q.updt_params(params); { @@ -135,7 +138,8 @@ void dl_query_test_wpa(smt_params & fparams, params_ref& params) { dl_decl_util dl_util(m); std::cerr << "Testing queries on " << problem_dir <<"\n"; - context ctx(m, fparams); + register_engine re; + context ctx(m, re, fparams); ctx.updt_params(params); { wpa_parser* p = wpa_parser::create(ctx, m); @@ -204,7 +208,8 @@ void tst_dl_query() { std::cerr << "Testing queries on " << problem_file <<"\n"; - context ctx_base(m, fparams); + register_engine re; + context ctx_base(m, re, fparams); ctx_base.updt_params(params); { parser* p = parser::create(ctx_base,m); diff --git a/src/test/dl_relation.cpp b/src/test/dl_relation.cpp index 609dca3da..bb1c8614c 100644 --- a/src/test/dl_relation.cpp +++ b/src/test/dl_relation.cpp @@ -1,5 +1,7 @@ #ifdef _WINDOWS #include "dl_context.h" +#include "dl_register_engine.h" +#include "dl_relation_manager.h" #include "dl_interval_relation.h" #include "dl_bound_relation.h" #include "dl_product_relation.h" @@ -10,7 +12,8 @@ namespace datalog { static void test_interval_relation() { smt_params params; ast_manager ast_m; - context ctx(ast_m, params); + register_engine re; + context ctx(ast_m, re, params); arith_util autil(ast_m); relation_manager & m = ctx.get_rel_context()->get_rmanager(); m.register_plugin(alloc(interval_relation_plugin, m)); @@ -113,7 +116,8 @@ namespace datalog { smt_params params; ast_manager ast_m; - context ctx(ast_m, params); + register_engine re; + context ctx(ast_m, re, params); arith_util autil(ast_m); relation_manager & m = ctx.get_rel_context()->get_rmanager(); m.register_plugin(alloc(bound_relation_plugin, m)); diff --git a/src/test/dl_table.cpp b/src/test/dl_table.cpp index d7025ed48..d24200f9b 100644 --- a/src/test/dl_table.cpp +++ b/src/test/dl_table.cpp @@ -1,6 +1,8 @@ #ifdef _WINDOWS #include "dl_context.h" #include "dl_table.h" +#include "dl_register_engine.h" +#include "dl_relation_manager.h" typedef datalog::table_base* (*mk_table_fn)(datalog::relation_manager& m, datalog::table_signature& sig); @@ -18,7 +20,8 @@ static void test_table(mk_table_fn mk_table) { sig.push_back(4); smt_params params; ast_manager ast_m; - datalog::context ctx(ast_m, params); + datalog::register_engine re; + datalog::context ctx(ast_m, re, params); datalog::relation_manager & m = ctx.get_rel_context()->get_rmanager(); m.register_plugin(alloc(datalog::bitvector_table_plugin, m)); From c8f953525105a2c98f55e402faf6c2eb66b96059 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Aug 2013 21:23:16 -0700 Subject: [PATCH 247/281] re-organize muz_qe into separate units Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_base.cpp | 490 ++++ src/muz/rel/dl_base.h | 1231 ++++++++++ src/muz/rel/dl_bound_relation.cpp | 707 ++++++ src/muz/rel/dl_bound_relation.h | 178 ++ src/muz/rel/dl_check_table.cpp | 439 ++++ src/muz/rel/dl_check_table.h | 135 ++ src/muz/rel/dl_external_relation.cpp | 456 ++++ src/muz/rel/dl_external_relation.h | 154 ++ src/muz/rel/dl_finite_product_relation.cpp | 2377 +++++++++++++++++++ src/muz/rel/dl_finite_product_relation.h | 366 +++ src/muz/rel/dl_interval_relation.cpp | 653 +++++ src/muz/rel/dl_interval_relation.h | 142 ++ src/muz/rel/dl_mk_explanations.cpp | 879 +++++++ src/muz/rel/dl_mk_explanations.h | 86 + src/muz/rel/dl_mk_partial_equiv.cpp | 155 ++ src/muz/rel/dl_mk_partial_equiv.h | 50 + src/muz/rel/dl_mk_similarity_compressor.cpp | 546 +++++ src/muz/rel/dl_mk_similarity_compressor.h | 78 + src/muz/rel/dl_mk_simple_joins.cpp | 742 ++++++ src/muz/rel/dl_mk_simple_joins.h | 63 + src/muz/rel/dl_product_relation.cpp | 1117 +++++++++ src/muz/rel/dl_product_relation.h | 191 ++ src/muz/rel/dl_relation_manager.cpp | 1702 +++++++++++++ src/muz/rel/dl_relation_manager.h | 688 ++++++ src/muz/rel/dl_sieve_relation.cpp | 666 ++++++ src/muz/rel/dl_sieve_relation.h | 198 ++ src/muz/rel/dl_sparse_table.cpp | 1246 ++++++++++ src/muz/rel/dl_sparse_table.h | 480 ++++ src/muz/rel/dl_table.cpp | 773 ++++++ src/muz/rel/dl_table.h | 265 +++ src/muz/rel/dl_table_plugin.h | 193 ++ src/muz/rel/dl_table_relation.cpp | 490 ++++ src/muz/rel/dl_table_relation.h | 133 ++ src/muz/rel/dl_vector_relation.h | 407 ++++ src/muz/rel/karr_relation.cpp | 790 ++++++ src/muz/rel/karr_relation.h | 88 + 36 files changed, 19354 insertions(+) create mode 100644 src/muz/rel/dl_base.cpp create mode 100644 src/muz/rel/dl_base.h create mode 100644 src/muz/rel/dl_bound_relation.cpp create mode 100644 src/muz/rel/dl_bound_relation.h create mode 100644 src/muz/rel/dl_check_table.cpp create mode 100644 src/muz/rel/dl_check_table.h create mode 100644 src/muz/rel/dl_external_relation.cpp create mode 100644 src/muz/rel/dl_external_relation.h create mode 100644 src/muz/rel/dl_finite_product_relation.cpp create mode 100644 src/muz/rel/dl_finite_product_relation.h create mode 100644 src/muz/rel/dl_interval_relation.cpp create mode 100644 src/muz/rel/dl_interval_relation.h create mode 100644 src/muz/rel/dl_mk_explanations.cpp create mode 100644 src/muz/rel/dl_mk_explanations.h create mode 100644 src/muz/rel/dl_mk_partial_equiv.cpp create mode 100644 src/muz/rel/dl_mk_partial_equiv.h create mode 100644 src/muz/rel/dl_mk_similarity_compressor.cpp create mode 100644 src/muz/rel/dl_mk_similarity_compressor.h create mode 100644 src/muz/rel/dl_mk_simple_joins.cpp create mode 100644 src/muz/rel/dl_mk_simple_joins.h create mode 100644 src/muz/rel/dl_product_relation.cpp create mode 100644 src/muz/rel/dl_product_relation.h create mode 100644 src/muz/rel/dl_relation_manager.cpp create mode 100644 src/muz/rel/dl_relation_manager.h create mode 100644 src/muz/rel/dl_sieve_relation.cpp create mode 100644 src/muz/rel/dl_sieve_relation.h create mode 100644 src/muz/rel/dl_sparse_table.cpp create mode 100644 src/muz/rel/dl_sparse_table.h create mode 100644 src/muz/rel/dl_table.cpp create mode 100644 src/muz/rel/dl_table.h create mode 100644 src/muz/rel/dl_table_plugin.h create mode 100644 src/muz/rel/dl_table_relation.cpp create mode 100644 src/muz/rel/dl_table_relation.h create mode 100644 src/muz/rel/dl_vector_relation.h create mode 100644 src/muz/rel/karr_relation.cpp create mode 100644 src/muz/rel/karr_relation.h diff --git a/src/muz/rel/dl_base.cpp b/src/muz/rel/dl_base.cpp new file mode 100644 index 000000000..dc10b5f8e --- /dev/null +++ b/src/muz/rel/dl_base.cpp @@ -0,0 +1,490 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_base.cpp + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-14. + +Revision History: + +--*/ + + +#include"ast_pp.h" +#include"union_find.h" +#include"vector.h" +#include"dl_context.h" +#include"dl_base.h" +#include"bool_rewriter.h" +#include"dl_relation_manager.h" +#include + + +namespace datalog { + + void universal_delete(relation_base* ptr) { + ptr->deallocate(); + } + + void universal_delete(table_base* ptr) { + ptr->deallocate(); + } + + void dealloc_ptr_vector_content(ptr_vector & v) { + ptr_vector::iterator it = v.begin(); + ptr_vector::iterator end = v.end(); + for(; it!=end; ++it) { + (*it)->deallocate(); + } + } + + void get_renaming_args(const unsigned_vector & map, const relation_signature & orig_sig, + expr_ref_vector & renaming_arg) { + ast_manager & m = renaming_arg.get_manager(); + unsigned sz = map.size(); + unsigned ofs = sz-1; + renaming_arg.resize(sz, static_cast(0)); + for(unsigned i=0; i reset_fn = + get_manager().mk_filter_interpreted_fn(static_cast(*this), bottom_ref); + if(!reset_fn) { + NOT_IMPLEMENTED_YET(); + } + (*reset_fn)(*this); + } + + + + void table_signature::from_join(const table_signature & s1, const table_signature & s2, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2, table_signature & result) { + result.reset(); + + unsigned s1sz=s1.size(); + unsigned s2sz=s2.size(); + unsigned s1first_func=s1sz-s1.functional_columns(); + unsigned s2first_func=s2sz-s2.functional_columns(); + for(unsigned i=0; i=col_cnt); + result.set_functional_columns(func_cnt-col_cnt); + } + } + + void table_signature::from_project_with_reduce(const table_signature & src, unsigned col_cnt, + const unsigned * removed_cols, table_signature & result) { + signature_base::from_project(src, col_cnt, removed_cols, result); + + unsigned remaining_fun = src.functional_columns(); + unsigned first_src_fun = src.first_functional(); + for(int i=col_cnt-1; i>=0; i--) { + if(removed_cols[i] remaining_in_equivalence_class; + remaining_in_equivalence_class.resize(join_sig_sz, 0); + bool merging_rows_can_happen = false; + + union_find_default_ctx uf_ctx; + union_find<> uf(uf_ctx); //the numbers in uf correspond to column indexes after the join + for(unsigned i=0; icols1[i]) ? cols1[i] : (first_func_ofs+cols1[i]-s1_first_func); + unsigned idx2 = (s2_first_func>cols2[i]) ? (second_ofs+cols2[i]) : (second_func_ofs+cols2[i]-s2_first_func); + uf.merge(idx1, idx2); + } + for(unsigned i=0; i=first_func_ofs) { + //removing functional columns won't make us merge rows + continue; + } + unsigned eq_class_idx = uf.find(rc); + if(remaining_in_equivalence_class[eq_class_idx]>1) { + remaining_in_equivalence_class[eq_class_idx]--; + } + else { + merging_rows_can_happen = true; + break; + } + } + + if(merging_rows_can_happen) { + //this one marks all columns as non-functional + from_project(aux, removed_col_cnt, removed_cols, result); + SASSERT(result.functional_columns()==0); + } + else { + //this one preserves columns to be functional + from_project_with_reduce(aux, removed_col_cnt, removed_cols, result); + } + } + + + + + // ----------------------------------- + // + // table_base + // + // ----------------------------------- + + //here we give generic implementation of table operations using iterators + + bool table_base::empty() const { + return begin()==end(); + } + + void table_base::remove_facts(unsigned fact_cnt, const table_fact * facts) { + for(unsigned i=0; i to_remove; + table_base::iterator it = begin(); + table_base::iterator iend = end(); + table_fact row; + for(; it!=iend; ++it) { + it->get_fact(row); + to_remove.push_back(row); + } + remove_facts(to_remove.size(), to_remove.c_ptr()); + } + + bool table_base::contains_fact(const table_fact & f) const { + iterator it = begin(); + iterator iend = end(); + + table_fact row; + + for(; it!=iend; ++it) { + it->get_fact(row); + if(vectors_equal(row, f)) { + return true; + } + } + return false; + } + + bool table_base::fetch_fact(table_fact & f) const { + if(get_signature().functional_columns()==0) { + return contains_fact(f); + } + else { + unsigned sig_sz = get_signature().size(); + unsigned non_func_cnt = sig_sz-get_signature().functional_columns(); + table_base::iterator it = begin(); + table_base::iterator iend = end(); + table_fact row; + for(; it!=iend; ++it) { + it->get_fact(row); + bool differs = false; + for(unsigned i=0; iget_fact(row); + res->add_new_fact(row); + } + return res; + } + + /** + \brief Default method for complementation. + + It assumes that the compiler creates only tables with + at most one column (0 or 1 columns). + Complementation of tables with more than one columns + is transformed into a cross product of complements and/or + difference. + + */ + table_base * table_base::complement(func_decl* p, const table_element * func_columns) const { + const table_signature & sig = get_signature(); + SASSERT(sig.functional_columns()==0 || func_columns!=0); + SASSERT(sig.first_functional() <= 1); + + table_base * res = get_plugin().mk_empty(sig); + + table_fact fact; + fact.resize(sig.first_functional()); + fact.append(sig.functional_columns(), func_columns); + + if (sig.first_functional() == 0) { + if (empty()) { + res->add_fact(fact); + } + return res; + } + + VERIFY(sig.first_functional() == 1); + + uint64 upper_bound = get_signature()[0]; + bool empty_table = empty(); + + if (upper_bound > (1 << 18)) { + std::ostringstream buffer; + buffer << "creating large table of size " << upper_bound; + if (p) buffer << " for relation " << p->get_name(); + warning_msg(buffer.str().c_str()); + } + + for(table_element i = 0; i < upper_bound; i++) { + fact[0] = i; + if(empty_table || !contains_fact(fact)) { + res->add_fact(fact); + } + } + return res; + } + + void table_base::display(std::ostream & out) const { + out << "table with signature "; + print_container(get_signature(), out); + out << ":\n"; + + iterator it = begin(); + iterator iend = end(); + for(; it!=iend; ++it) { + const row_interface & r = *it; + r.display(out); + } + + out << "\n"; + } + + + class table_base::row_interface::fact_row_iterator : public table_base::row_iterator_core { + const row_interface & m_parent; + unsigned m_index; + protected: + virtual bool is_finished() const { return m_index==m_parent.size(); } + public: + fact_row_iterator(const row_interface & row, bool finished) + : m_parent(row), m_index(finished ? row.size() : 0) {} + + virtual table_element operator*() { + SASSERT(!is_finished()); + return m_parent[m_index]; + } + + virtual void operator++() { + m_index++; + SASSERT(m_index<=m_parent.size()); + } + }; + + table_base::row_iterator table_base::row_interface::begin() const { + return row_iterator(alloc(fact_row_iterator, *this, false)); + } + table_base::row_iterator table_base::row_interface::end() const { + return row_iterator(alloc(fact_row_iterator, *this, true)); + } + + void table_base::row_interface::get_fact(table_fact & result) const { + result.reset(); + unsigned n=size(); + for(unsigned i=0; i + +Author: + + Krystof Hoder (t-khoder) 2010-09-23. + +Revision History: + +--*/ +#ifndef _DL_BASE_H_ +#define _DL_BASE_H_ + +#define DL_LEAK_HUNTING 0 + +#include + +#include"ast.h" +#include"map.h" +#include"vector.h" +#include"ref.h" +#include"dl_util.h" +#include"dl_context.h" + +namespace datalog { + + class context; + class relation_manager; + + ast_manager & get_ast_manager_from_rel_manager(const relation_manager & rm); + context & get_context_from_rel_manager(const relation_manager & rm); + + typedef func_decl_set decl_set; + +#if DL_LEAK_HUNTING + void leak_guard_check(const symbol & s); +#endif + + void universal_delete(relation_base* ptr); + void universal_delete(table_base* ptr); + void dealloc_ptr_vector_content(ptr_vector & v); + + + /** + Termplate class containing common infrastructure for relations and tables + */ + template + struct tr_infrastructure { + + typedef typename Traits::plugin plugin; + typedef typename Traits::base_object base_object; + typedef typename Traits::element element; + typedef typename Traits::fact fact; + typedef typename Traits::sort sort; + typedef typename Traits::signature_base_base signature_base_base; //this must be a vector-like type + typedef typename Traits::signature signature; //this must be a vector-like type + + /** + The client submits an initial class to be used as a base for signature. Then we excend it by + the common signature methods into a signature_base class which then the client inherits from + to obtain the actual signature class. + */ + class signature_base : public signature_base_base { + public: + bool operator==(const signature & o) const { + unsigned n=signature_base_base::size(); + if(n!=o.size()) { + return false; + } + return memcmp(this->c_ptr(), o.c_ptr(), n*sizeof(sort))==0; + /*for(unsigned i=0; i=2); + result=src; + + permutate_by_cycle(result, cycle_len, permutation_cycle); + } + + /** + \brief Into \c result assign signature \c src with reordered columns. + */ + static void from_permutation_rename(const signature & src, + const unsigned * permutation, signature & result) { + result.reset(); + unsigned n = src.size(); + for(unsigned i=0; i(0)); + } + }; + + /** + \brief Mutator for relations that propagate constraints as a consequence of + combination. + + - supports_attachment + is used to query the mutator if it allows communicating + constraints to relations of the kind of the relation. + + - attach + is used to associate downstream clients. + It assumes that the relation kind is supported (supports_kind returns true) + */ + class mutator_fn : public base_fn { + public: + virtual void operator()(base_object & t) = 0; + + virtual bool supports_attachment(base_object& other) { return false; } + + virtual void attach(base_object& other) { UNREACHABLE(); } + }; + + class intersection_filter_fn : public base_fn { + public: + virtual void operator()(base_object & t, const base_object & intersected_obj) = 0; + }; + + class default_join_project_fn; + + /** + \brief Plugin class providing factory functions for a table and operations on it. + + The functor factory functions (mk_*_fn) may return 0. It means that the plugin + is unable to perform the operation on relations/tables of the particular kind. + */ + class plugin_object { + friend class relation_manager; + friend class check_table_plugin; + + family_id m_kind; + symbol m_name; + relation_manager & m_manager; + protected: + plugin_object(symbol const& name, relation_manager & manager) + : m_kind(null_family_id), m_name(name), m_manager(manager) {} + + /** + \brief Check \c r is of the same kind as the plugin. + */ + bool check_kind(base_object const& r) const { return &r.get_plugin()==this; } + public: + virtual ~plugin_object() {} + + virtual void initialize(family_id fid) { m_kind = fid; } + + family_id get_kind() const { return m_kind; } + + symbol const& get_name() const { return m_name; } + + virtual void set_cancel(bool f) {} + + relation_manager & get_manager() const { return m_manager; } + ast_manager& get_ast_manager() const { return datalog::get_ast_manager_from_rel_manager(m_manager); } + context& get_context() const { return datalog::get_context_from_rel_manager(m_manager); } + + virtual bool can_handle_signature(const signature & s) = 0; + + virtual bool can_handle_signature(const signature & s, family_id kind) { + return can_handle_signature(s); + } + + /** + \brief Create empty table/relation with given signature and return pointer to it. + + Precondition: can_handle_signature(s)==true + */ + virtual base_object * mk_empty(const signature & s) = 0; + + /** + \brief Create empty table/relation with signature \c s and kind \c kind. + + Precondition: &orig.get_plugin()==this + */ + virtual base_object * mk_empty(const signature & s, family_id kind) { + SASSERT(kind==get_kind()); //if plugin uses multiple kinds, this function needs to be overriden + return mk_empty(s); + } + + /** + \brief Create empty table/relation of the same specification as \c orig and return pointer to it. + + Precondition: &orig.get_plugin()==this + */ + virtual base_object * mk_empty(const base_object & orig) { + return mk_empty(orig.get_signature(), orig.get_kind()); + } + + /** + \brief Create full table/relation with given signature and return pointer to it. + + Precondition: can_handle_signature(s)==true + */ + virtual base_object * mk_full(func_decl* p, const signature & s) { + base_object * aux = mk_empty(s); + base_object * res = aux->complement(p); + aux->deallocate(); + return res; + } + + virtual base_object * mk_full(func_decl* p, const signature & s, family_id kind) { + if (kind == get_kind() || kind == null_family_id) { + return mk_full(p, s); + } + base_object * aux = mk_empty(s, kind); + base_object * res = aux->complement(p); + aux->deallocate(); + return res; + } + + protected: + //see \c relation_manager for documentation of the operations + + virtual join_fn * mk_join_fn(const base_object & t1, const base_object & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { return 0; } + + virtual transformer_fn * mk_project_fn(const base_object & t, unsigned col_cnt, + const unsigned * removed_cols) { return 0; } + + virtual join_fn * mk_join_project_fn(const base_object & t1, const base_object & t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) { return 0; } + + virtual transformer_fn * mk_rename_fn(const base_object & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) { return 0; } + + virtual transformer_fn * mk_permutation_rename_fn(const base_object & t, + const unsigned * permutation) { return 0; } + + public: + virtual union_fn * mk_union_fn(const base_object & tgt, const base_object & src, + const base_object * delta) { return 0; } + protected: + + virtual union_fn * mk_widen_fn(const base_object & tgt, const base_object & src, + const base_object * delta) { return 0; } + + virtual mutator_fn * mk_filter_identical_fn(const base_object & t, unsigned col_cnt, + const unsigned * identical_cols) { return 0; } + + virtual mutator_fn * mk_filter_equal_fn(const base_object & t, const element & value, + unsigned col) { return 0; } + + virtual mutator_fn * mk_filter_interpreted_fn(const base_object & t, app * condition) + { return 0; } + + virtual transformer_fn * mk_filter_interpreted_and_project_fn(const base_object & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) + { return 0; } + + virtual transformer_fn * mk_select_equal_and_project_fn(const base_object & t, + const element & value, unsigned col) { return 0; } + + virtual intersection_filter_fn * mk_filter_by_intersection_fn(const base_object & t, + const base_object & src, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * src_cols) + { return 0; } + + virtual intersection_filter_fn * mk_filter_by_negation_fn(const base_object & t, + const base_object & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) + { return 0; } + }; + + class base_ancestor { + plugin & m_plugin; + signature m_signature; + family_id m_kind; +#if DL_LEAK_HUNTING + sort_ref m_leak_guard; +#endif + protected: + base_ancestor(plugin & p, const signature & s) + : m_plugin(p), m_signature(s), m_kind(p.get_kind()) +#if DL_LEAK_HUNTING + , m_leak_guard(p.get_ast_manager().mk_fresh_sort(p.get_name().bare_str()), p.get_ast_manager()) +#endif + { +#if DL_LEAK_HUNTING + leak_guard_check(m_leak_guard->get_name()); +#endif + } + +#if DL_LEAK_HUNTING + base_ancestor(const base_ancestor & o) + : m_plugin(o.m_plugin), + m_signature(o.m_signature), + m_kind(o.m_kind), + m_leak_guard(m_plugin.get_ast_manager().mk_fresh_sort(m_plugin.get_name().bare_str()), + m_plugin.get_ast_manager()) { + leak_guard_check(m_leak_guard->get_name()); + } +#endif + + virtual ~base_ancestor() {} + + void set_kind(family_id kind) { SASSERT(kind>=0); m_kind = kind; } + + /** + Since the destructor is protected, we cannot use the \c dealloc macro. + */ + void destroy() { + SASSERT(this); + this->~base_ancestor(); +#if _DEBUG + memory::deallocate(__FILE__, __LINE__, this); +#else + memory::deallocate(this); +#endif + } + public: + /** + Deallocate the current object. + + Pointers and references to the current object become invalid after a call to this function. + */ + virtual void deallocate() { + destroy(); + } + /** + It must hold that operations created for particular table/relation are able to operate on + tables/relations of the same signature and kind. In most cases it is sufficient to use the kind + of the plugin object. + + However, it there is some parameter that is not reflected in the signature, the plugin may need to + allocate different kind numbers to the tables is creates. + */ + family_id get_kind() const { return m_kind; } + const signature & get_signature() const { return m_signature; } + plugin & get_plugin() const { return m_plugin; } + relation_manager & get_manager() const { return get_plugin().get_manager(); } + + virtual bool empty() const = 0; + virtual void add_fact(const fact & f) = 0; + /** + \brief Like \c add_fact, only here the caller guarantees that the fact is not present in + the table yet. + */ + virtual void add_new_fact(const fact & f) { + add_fact(f); + } + virtual bool contains_fact(const fact & f) const = 0; + + virtual void reset() = 0; + + /** + \brief Return table/relation that contains the same data as the current one. + */ + virtual base_object * clone() const = 0; + + virtual bool can_swap(const base_object & o) const { return false; } + + virtual void swap(base_object & o) { + std::swap(m_kind, o.m_kind); +#if DL_LEAK_HUNTING + m_leak_guard = get_plugin().get_ast_manager().mk_fresh_sort(get_plugin().get_name().bare_str()); + o.m_leak_guard = get_plugin().get_ast_manager().mk_fresh_sort(get_plugin().get_name().bare_str()); + leak_guard_check(m_leak_guard->get_name()); + leak_guard_check(o.m_leak_guard->get_name()); +#endif + } + + virtual unsigned get_size_estimate_rows() const { return UINT_MAX; } + virtual unsigned get_size_estimate_bytes() const { return UINT_MAX; } + virtual bool knows_exact_size() const { return false; } + + virtual void display(std::ostream & out) const = 0; + }; + + + class convenient_join_fn : public join_fn { + signature m_result_sig; + protected: + unsigned_vector m_cols1; + unsigned_vector m_cols2; + + convenient_join_fn(const signature & o1_sig, const signature & o2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : m_cols1(col_cnt, cols1), + m_cols2(col_cnt, cols2) { + signature::from_join(o1_sig, o2_sig, col_cnt, cols1, cols2, m_result_sig); + } + + const signature & get_result_signature() const { return m_result_sig; } + }; + + class convenient_join_project_fn : public join_fn { + signature m_result_sig; + protected: + unsigned_vector m_cols1; + unsigned_vector m_cols2; + //it is non-const because it needs to be modified in sparse_table version of the join_project operator + unsigned_vector m_removed_cols; + + convenient_join_project_fn(const signature & o1_sig, const signature & o2_sig, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) + : m_cols1(joined_col_cnt, cols1), + m_cols2(joined_col_cnt, cols2), + m_removed_cols(removed_col_cnt, removed_cols) { + + signature::from_join_project(o1_sig, o2_sig, joined_col_cnt, cols1, cols2, + removed_col_cnt, removed_cols, m_result_sig); + } + + const signature & get_result_signature() const { return m_result_sig; } + }; + + class convenient_transformer_fn : public transformer_fn { + signature m_result_sig; + protected: + signature & get_result_signature() { return m_result_sig; } + const signature & get_result_signature() const { return m_result_sig; } + }; + + class convenient_project_fn : public convenient_transformer_fn { + protected: + unsigned_vector m_removed_cols; + + convenient_project_fn(const signature & orig_sig, unsigned col_cnt, const unsigned * removed_cols) + : m_removed_cols(col_cnt, removed_cols) { + signature::from_project(orig_sig, col_cnt, removed_cols, + convenient_transformer_fn::get_result_signature()); + } + }; + + class convenient_rename_fn : public convenient_transformer_fn { + protected: + const unsigned_vector m_cycle; + + convenient_rename_fn(const signature & orig_sig, unsigned cycle_len, + const unsigned * permutation_cycle) + : m_cycle(cycle_len, permutation_cycle) { + signature::from_rename(orig_sig, cycle_len, permutation_cycle, + convenient_transformer_fn::get_result_signature()); + } + }; + + class convenient_negation_filter_fn : public intersection_filter_fn { + protected: + unsigned m_joined_col_cnt; + const unsigned_vector m_cols1; + const unsigned_vector m_cols2; + bool m_all_neg_bound; //all columns are bound at least once + bool m_overlap; //one column in negated table is bound multiple times + svector m_bound; + + convenient_negation_filter_fn(const base_object & tgt, const base_object & neg_t, + unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) + : m_joined_col_cnt(joined_col_cnt), m_cols1(joined_col_cnt, t_cols), + m_cols2(joined_col_cnt, negated_cols) { + unsigned neg_sig_size = neg_t.get_signature().size(); + m_overlap = false; + m_bound.resize(neg_sig_size, false); + for(unsigned i=0; i + void make_neg_bindings(T & tgt_neg, const U & src) const { + SASSERT(m_all_neg_bound); + SASSERT(!m_overlap); + for(unsigned i=0; i + bool bindings_match(const T & tgt_neg, const U & src) const { + for(unsigned i=0; i renamer_vector; + + unsigned_vector m_permutation; //this is valid only before m_renamers_initialized becomes true + bool m_renamers_initialized; + renamer_vector m_renamers; + public: + default_permutation_rename_fn(const base_object & o, const unsigned * permutation) + : m_permutation(o.get_signature().size(), permutation), + m_renamers_initialized(false) {} + + ~default_permutation_rename_fn() { + dealloc_ptr_vector_content(m_renamers); + } + + base_object * operator()(const base_object & o) { + const base_object * res = &o; + scoped_rel res_scoped; + if(m_renamers_initialized) { + typename renamer_vector::iterator rit = m_renamers.begin(); + typename renamer_vector::iterator rend = m_renamers.end(); + for(; rit!=rend; ++rit) { + res_scoped = (**rit)(*res); + res = res_scoped.get(); + } + } + else { + SASSERT(m_renamers.empty()); + unsigned_vector cycle; + while(try_remove_cycle_from_permutation(m_permutation, cycle)) { + transformer_fn * renamer = o.get_manager().mk_rename_fn(*res, cycle); + SASSERT(renamer); + m_renamers.push_back(renamer); + cycle.reset(); + + res_scoped = (*renamer)(*res); + res = res_scoped.get(); + } + m_renamers_initialized = true; + } + if(res_scoped) { + SASSERT(res==res_scoped.get()); + //we don't want to delete the last one since we'll be returning it + return res_scoped.release(); + } + else { + SASSERT(res==&o); + return res->clone(); + } + } + + }; + + + }; + + + // ----------------------------------- + // + // relation_base + // + // ----------------------------------- + + class relation_signature; + class relation_plugin; + class relation_base; + + typedef ptr_vector relation_signature_base0; + typedef ptr_hash relation_sort_hash; + + + struct relation_traits { + typedef relation_plugin plugin; + typedef relation_base base_object; + typedef relation_element element; + typedef relation_fact fact; + typedef relation_sort sort; + typedef relation_signature_base0 signature_base_base; + typedef relation_signature signature; + }; + + typedef tr_infrastructure relation_infrastructure; + + typedef relation_infrastructure::base_fn base_relation_fn; + typedef relation_infrastructure::join_fn relation_join_fn; + typedef relation_infrastructure::transformer_fn relation_transformer_fn; + typedef relation_infrastructure::union_fn relation_union_fn; + typedef relation_infrastructure::mutator_fn relation_mutator_fn; + typedef relation_infrastructure::intersection_filter_fn relation_intersection_filter_fn; + + typedef relation_infrastructure::convenient_join_fn convenient_relation_join_fn; + typedef relation_infrastructure::convenient_join_project_fn convenient_relation_join_project_fn; + typedef relation_infrastructure::convenient_transformer_fn convenient_relation_transformer_fn; + typedef relation_infrastructure::convenient_project_fn convenient_relation_project_fn; + typedef relation_infrastructure::convenient_rename_fn convenient_relation_rename_fn; + typedef relation_infrastructure::convenient_negation_filter_fn convenient_relation_negation_filter_fn; + typedef relation_infrastructure::identity_transformer_fn identity_relation_transformer_fn; + typedef relation_infrastructure::identity_mutator_fn identity_relation_mutator_fn; + typedef relation_infrastructure::identity_intersection_filter_fn identity_relation_intersection_filter_fn; + typedef relation_infrastructure::default_permutation_rename_fn default_relation_permutation_rename_fn; + + class relation_signature : public relation_infrastructure::signature_base { + public: + bool operator!=(const relation_signature & o) const { + return !(*this==o); + } + + void output(ast_manager & m, std::ostream & out) const; + + struct hash { + unsigned operator()(relation_signature const& s) const { + return obj_vector_hash(s); + } + }; + + struct eq { + bool operator()(relation_signature const& s1, relation_signature const& s2) const { + return s1 == s2; + } + }; + }; + + class relation_plugin : public relation_infrastructure::plugin_object { + protected: + enum special_relation_type { + ST_ORDINARY, + ST_TABLE_RELATION, + ST_FINITE_PRODUCT_RELATION, + ST_PRODUCT_RELATION, + ST_SIEVE_RELATION + }; + private: + special_relation_type m_special_type; + protected: + relation_plugin(symbol const& name, relation_manager & manager, + special_relation_type special_type = ST_ORDINARY) + : plugin_object(name, manager), + m_special_type(special_type) {} + public: + bool from_table() const { return m_special_type==ST_TABLE_RELATION; } + bool is_finite_product_relation() const { return m_special_type==ST_FINITE_PRODUCT_RELATION; } + bool is_product_relation() const { return m_special_type==ST_PRODUCT_RELATION; } + bool is_sieve_relation() const { return m_special_type==ST_SIEVE_RELATION; } + + /** + \brief If true, the relation can contain only one or zero elements. + + Having this zero allows the finite_product_relation to perform some operations in a simpler way. + (KH: I started implementing finite_product_relation::inner_singleton_union_fn that takes advantage of + it, but it's not finished.) + */ + virtual bool is_singleton_relation() const { return false; } + }; + + class relation_base : public relation_infrastructure::base_ancestor { + protected: + relation_base(relation_plugin & plugin, const relation_signature & s) + : base_ancestor(plugin, s) {} + virtual ~relation_base() {} + public: + virtual relation_base * complement(func_decl* p) const = 0; + + virtual void reset(); + + virtual void display_tuples(func_decl & pred, std::ostream & out) const { + out << "Tuples in " << pred.get_name() << ": \n"; + display(out); + } + + virtual void to_formula(expr_ref& fml) const = 0; + + bool from_table() const { return get_plugin().from_table(); } + virtual bool is_precise() const { return true; } + }; + + typedef ptr_vector relation_vector; + + // ----------------------------------- + // + // table_base + // + // ----------------------------------- + + class table_signature; + class table_plugin; + class table_base; + + typedef uint64 table_sort; + typedef svector table_signature_base0; + typedef uint64_hash table_sort_hash; + + typedef uint64_hash table_element_hash; + + struct table_traits { + typedef table_plugin plugin; + typedef table_base base_object; + typedef table_element element; + typedef table_fact fact; + typedef table_sort sort; + typedef table_signature_base0 signature_base_base; + typedef table_signature signature; + }; + + typedef tr_infrastructure table_infrastructure; + + typedef table_infrastructure::base_fn base_table_fn; + typedef table_infrastructure::join_fn table_join_fn; + typedef table_infrastructure::transformer_fn table_transformer_fn; + typedef table_infrastructure::union_fn table_union_fn; + typedef table_infrastructure::mutator_fn table_mutator_fn; + typedef table_infrastructure::intersection_filter_fn table_intersection_filter_fn; + + typedef table_infrastructure::convenient_join_fn convenient_table_join_fn; + typedef table_infrastructure::convenient_join_project_fn convenient_table_join_project_fn; + typedef table_infrastructure::convenient_transformer_fn convenient_table_transformer_fn; + typedef table_infrastructure::convenient_project_fn convenient_table_project_fn; + typedef table_infrastructure::convenient_rename_fn convenient_table_rename_fn; + typedef table_infrastructure::convenient_negation_filter_fn convenient_table_negation_filter_fn; + typedef table_infrastructure::identity_transformer_fn identity_table_transformer_fn; + typedef table_infrastructure::identity_mutator_fn identity_table_mutator_fn; + typedef table_infrastructure::identity_intersection_filter_fn identity_table_intersection_filter_fn; + typedef table_infrastructure::default_permutation_rename_fn default_table_permutation_rename_fn; + + class table_row_mutator_fn { + public: + /** + \brief The function is called for a particular table row. The \c func_columns contains + a pointer to an array of functional column values that can be modified. If the function + returns true, the modification will appear in the table; otherwise the row will be deleted. + + It is possible that one call to the function stands for multiple table rows that share + the same functional column values. + */ + virtual bool operator()(table_element * func_columns) = 0; + }; + + class table_row_pair_reduce_fn { + public: + /** + \brief The function is called for pair of table rows that became duplicit due to projection. + The values that are in the first array after return from the function will be used for the + resulting row. + + It is assumed that the function is idempotent: when the two functional sub-tuples are equal, + the result is assumed to be equal to them as well, so the function may not be evaluated for them. + */ + virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) = 0; + }; + + + class table_signature : public table_infrastructure::signature_base { + public: + struct hash { + unsigned operator()(table_signature const& s) const { + return svector_hash()(s); + } + }; + + struct eq { + bool operator()(table_signature const& s1, table_signature const& s2) const { + return s1 == s2; + } + }; + private: + unsigned m_functional_columns; + public: + table_signature() : m_functional_columns(0) {} + + void swap(table_signature & s) { + signature_base::swap(s); + std::swap(m_functional_columns, s.m_functional_columns); + } + + /** + \brief The returned value is the number of last columns that are functional. + + The uniqueness is enforced on non-functional columns. When projection causes two + facts to have equal non-functional parts, it is not defined which one of them is retained. + */ + unsigned functional_columns() const { return m_functional_columns; } + void set_functional_columns(unsigned val) { SASSERT(size()>=val); m_functional_columns = val; } + + /** + \brief Return index of the first functional column, or the size of the signature if there + are no functional columns. + */ + unsigned first_functional() const { return size()-m_functional_columns; } + + bool operator==(const table_signature & o) const { + return signature_base::operator==(o) && m_functional_columns==o.m_functional_columns; + } + bool operator!=(const table_signature & o) const { + return !(*this==o); + } + + /** + \brief return true iof the two signatures are equal when we ignore which columns are functional. + */ + bool equal_up_to_fn_mark(const table_signature & o) const { + return signature_base::operator==(o); + } + + + /** + \brief Into \c result assign signature of result of join of relations with signatures \c s1 + and \c s2. The result is + + (non-functional of s1)(non-functional of s2)(functional of s1)(functional of s2) + */ + static void from_join(const table_signature & s1, const table_signature & s2, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2, table_signature & result); + + static void from_join_project(const table_signature & s1, const table_signature & s2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols, table_signature & result); + + + /** + \brief Into \c result assign signature projected from \c src. + + The array of removed columns must be sorted in ascending order. + + If we remove at least one non-functional column, all the columns in the result are non-functional. + */ + static void from_project(const table_signature & src, unsigned col_cnt, + const unsigned * removed_cols, table_signature & result); + + static void from_project_with_reduce(const table_signature & src, unsigned col_cnt, + const unsigned * removed_cols, table_signature & result); + + /** + \brief Into \c result assign signature \c src with reordered columns. + + Permutations between functional and nonfunctional columns are not allowed. + */ + static void from_rename(const table_signature & src, unsigned cycle_len, + const unsigned * permutation_cycle, table_signature & result) { + signature_base::from_rename(src, cycle_len, permutation_cycle, result); + result.set_functional_columns(src.functional_columns()); +#if Z3DEBUG + unsigned first_src_fun = src.size()-src.functional_columns(); + bool in_func = permutation_cycle[0]>=first_src_fun; + for(unsigned i=1;i=first_src_fun)); + } +#endif + } + + /** + \brief Into \c result assign signature \c src with reordered columns. + + Permutations mixing functional and nonfunctional columns are not allowed. + */ + static void from_permutation_rename(const table_signature & src, + const unsigned * permutation, table_signature & result) { + signature_base::from_permutation_rename(src, permutation, result); + result.set_functional_columns(src.functional_columns()); +#if Z3DEBUG + unsigned sz = src.size(); + unsigned first_src_fun = sz-src.functional_columns(); + for(unsigned i=first_src_fun;i=first_src_fun); + } +#endif + } + + }; + + class table_plugin : public table_infrastructure::plugin_object { + friend class relation_manager; + protected: + table_plugin(symbol const& n, relation_manager & manager) : plugin_object(n, manager) {} + public: + + virtual bool can_handle_signature(const table_signature & s) { return s.functional_columns()==0; } + + protected: + /** + If the returned value is non-zero, the returned object must take ownership of \c mapper. + Otherwise \c mapper must remain unmodified. + */ + virtual table_mutator_fn * mk_map_fn(const table_base & t, table_row_mutator_fn * mapper) { return 0; } + + /** + If the returned value is non-zero, the returned object must take ownership of \c reducer. + Otherwise \c reducer must remain unmodified. + */ + virtual table_transformer_fn * mk_project_with_reduce_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols, table_row_pair_reduce_fn * reducer) { return 0; } + + }; + + class table_base : public table_infrastructure::base_ancestor { + protected: + table_base(table_plugin & plugin, const table_signature & s) + : base_ancestor(plugin, s) {} + virtual ~table_base() {} + public: + virtual table_base * clone() const; + virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const; + virtual bool empty() const; + + /** + \brief Return true if table contains fact that corresponds to \c f in all non-functional + columns. + */ + virtual bool contains_fact(const table_fact & f) const; + + /** + \brief If \c f (i.e. its non-functional part) is not present in the table, + add it and return true. Otherwise update \c f, so that the values of functional + columns correspond to the ones present in the table. + */ + virtual bool suggest_fact(table_fact & f); + + /** + \brief If \c f (i.e. its non-functional part) is not present in the table, + return false. Otherwise update \c f, so that the values of functional + columns correspond to the ones present in the table and return true. + */ + virtual bool fetch_fact(table_fact & f) const; + + /** + \brief Ensure fact \c f is present in the table (including the values of its functional columns). + */ + virtual void ensure_fact(const table_fact & f); + + virtual void remove_fact(const table_fact & fact) { + SASSERT(fact.size() == get_signature().size()); + remove_fact(fact.c_ptr()); } + + virtual void remove_fact(table_element const* fact) = 0; + virtual void remove_facts(unsigned fact_cnt, const table_fact * facts); + virtual void remove_facts(unsigned fact_cnt, const table_element * facts); + virtual void reset(); + + class row_interface; + + virtual void display(std::ostream & out) const; + + /** + \brief Convert table to a formula that encodes the table. + The columns correspond to bound variables indexed as + 0, .., sig.size()-1 + */ + virtual void to_formula(relation_signature const& sig, expr_ref& fml) const; + + protected: + + + class iterator_core { + unsigned m_ref_cnt; + public: + iterator_core() : m_ref_cnt(0) {} + virtual ~iterator_core() {} + + void inc_ref() { m_ref_cnt++; } + void dec_ref() { + SASSERT(m_ref_cnt>0); + m_ref_cnt--; + if(m_ref_cnt==0) { + dealloc(this); + } + } + + virtual bool is_finished() const = 0; + + virtual row_interface & operator*() = 0; + virtual void operator++() = 0; + virtual bool operator==(const iterator_core & it) { + //we worry about the equality operator only because of checking + //the equality with the end() iterator + if(is_finished() && it.is_finished()) { + return true; + } + return false; + } + private: + //private and undefined copy constructor and assignment operator + iterator_core(const iterator_core &); + iterator_core & operator=(const iterator_core &); + }; + + struct row_iterator_core { + unsigned m_ref_cnt; + public: + row_iterator_core() : m_ref_cnt(0) {} + virtual ~row_iterator_core() {} + + void inc_ref() { m_ref_cnt++; } + void dec_ref() { + SASSERT(m_ref_cnt>0); + m_ref_cnt--; + if(m_ref_cnt==0) { + dealloc(this); + } + } + + virtual bool is_finished() const = 0; + + virtual table_element operator*() = 0; + virtual void operator++() = 0; + virtual bool operator==(const row_iterator_core & it) { + //we worry about the equality operator only because of checking + //the equality with the end() iterator + if(is_finished() && it.is_finished()) { + return true; + } + return false; + } + private: + //private and undefined copy constructor and assignment operator + row_iterator_core(const row_iterator_core &); + row_iterator_core & operator=(const row_iterator_core &); + }; + + public: + class iterator { + friend class table_base; + + ref m_core; + + iterator(iterator_core * core) : m_core(core) {} + public: + /** + \brief Return reference to a row_interface object for the current row. + + The reference is valid only until the \c operator++() is called or + until the iterator is invalidated. + */ + row_interface & operator*() + { return *(*m_core); } + row_interface * operator->() + { return &(*(*m_core)); } + iterator & operator++() + { ++(*m_core); return *this; } + bool operator==(const iterator & it) + { return (*m_core)==(*it.m_core); } + bool operator!=(const iterator & it) + { return !operator==(it); } + }; + + class row_iterator { + friend class table_base; + friend class row_interface; + + ref m_core; + + row_iterator(row_iterator_core * core) : m_core(core) {} + public: + table_element operator*() + { return *(*m_core); } + row_iterator & operator++() + { ++(*m_core); return *this; } + bool operator==(const row_iterator & it) + { return (*m_core)==(*it.m_core); } + bool operator!=(const row_iterator & it) + { return !operator==(it); } + }; + + virtual iterator begin() const = 0; + virtual iterator end() const = 0; + + class row_interface { + class fact_row_iterator; + + const table_base & m_parent_table; + public: + typedef row_iterator iterator; + typedef row_iterator const_iterator; + + row_interface(const table_base & parent_table) : m_parent_table(parent_table) {} + virtual ~row_interface() {} + + virtual table_element operator[](unsigned col) const = 0; + + unsigned size() const { return m_parent_table.get_signature().size(); } + virtual void get_fact(table_fact & result) const; + virtual row_iterator begin() const; + virtual row_iterator end() const; + virtual void display(std::ostream & out) const; + }; + + protected: + + class caching_row_interface : public row_interface { + mutable table_fact m_current; + + bool populated() const { return !m_current.empty(); } + void ensure_populated() const { + if(!populated()) { + get_fact(m_current); + } + } + public: + caching_row_interface(const table_base & parent) : row_interface(parent) {} + + virtual void get_fact(table_fact & result) const = 0; + + virtual table_element operator[](unsigned col) const { + ensure_populated(); + return m_current[col]; + } + /** + \brief Resets the cache of the row object. + + Must be called when the row object begins to represent a different row in the table. + */ + void reset() { m_current.reset(); } + }; + + //This function is here to create iterator instances in classes that derive from table_base. + //We do not want to make the constructor of the iterator class public, and being private, the + //inheritor classes cannot see it directly. + static iterator mk_iterator(iterator_core * core) { + return iterator(core); + } + }; + + /** + \brief Populate vector \c renaming_args so that it can be used as an argument to \c var_subst. + The renaming we want is one that transforms variables with numbers of indexes of \c map into the + values of at those indexes. If a value if \c UINT_MAX, it means we do not transform the index + corresponding to it. + */ + void get_renaming_args(const unsigned_vector & map, const relation_signature & orig_sig, + expr_ref_vector & renaming_arg); + + +}; + +#endif /* _DL_BASE_H_ */ + diff --git a/src/muz/rel/dl_bound_relation.cpp b/src/muz/rel/dl_bound_relation.cpp new file mode 100644 index 000000000..182046c1e --- /dev/null +++ b/src/muz/rel/dl_bound_relation.cpp @@ -0,0 +1,707 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + dl_bound_relation.cpp + +Abstract: + + Basic (strict upper) bound relation. + +Author: + + Nikolaj Bjorner (nbjorner) 2010-2-11 + +Revision History: + +--*/ + +#include "dl_bound_relation.h" +#include "debug.h" +#include "ast_pp.h" + +namespace datalog { + + bound_relation_plugin::bound_relation_plugin(relation_manager& m): + relation_plugin(bound_relation_plugin::get_name(), m), + m_arith(get_ast_manager()), + m_bsimp(get_ast_manager()) { + } + + bool bound_relation_plugin::can_handle_signature(const relation_signature & sig) { + for (unsigned i = 0; i < sig.size(); ++i) { + if (!m_arith.is_int(sig[i]) && !m_arith.is_real(sig[i])) { + return false; + } + } + return true; + } + + bound_relation& bound_relation_plugin::get(relation_base& r) { + return dynamic_cast(r); + } + + bound_relation const & bound_relation_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + + bound_relation* bound_relation_plugin::get(relation_base* r) { + return dynamic_cast(r); + } + + bool bound_relation_plugin::is_interval_relation(relation_base const& r) { + return symbol("interval_relation") == r.get_plugin().get_name(); + } + + interval_relation& bound_relation_plugin::get_interval_relation(relation_base& r) { + SASSERT(is_interval_relation(r)); + return dynamic_cast(r); + } + + interval_relation const& bound_relation_plugin::get_interval_relation(relation_base const& r) { + SASSERT(is_interval_relation(r)); + return dynamic_cast(r); + } + + relation_base * bound_relation_plugin::mk_empty(const relation_signature & s) { + return alloc(bound_relation, *this, s, true); + } + + relation_base * bound_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { + return alloc(bound_relation, *this, s, false); + } + + class bound_relation_plugin::join_fn : public convenient_relation_join_fn { + public: + join_fn(const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2) { + } + + virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + bound_relation const& r1 = get(_r1); + bound_relation const& r2 = get(_r2); + bound_relation_plugin& p = r1.get_plugin(); + bound_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_join(r1, r2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); + return result; + } + }; + + relation_join_fn * bound_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (!check_kind(r1) || !check_kind(r2)) { + return 0; + } + return alloc(join_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2); + } + + + class bound_relation_plugin::project_fn : public convenient_relation_project_fn { + public: + project_fn(const relation_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) + : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { + } + + virtual relation_base * operator()(const relation_base & _r) { + bound_relation const& r = get(_r); + bound_relation_plugin& p = r.get_plugin(); + bound_relation* result = get(p.mk_full(0, get_result_signature())); + result->mk_project(r, m_removed_cols.size(), m_removed_cols.c_ptr()); + return result; + } + }; + + relation_transformer_fn * bound_relation_plugin::mk_project_fn(const relation_base & r, + unsigned col_cnt, const unsigned * removed_cols) { + return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); + } + + class bound_relation_plugin::rename_fn : public convenient_relation_rename_fn { + public: + rename_fn(const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) { + } + + virtual relation_base * operator()(const relation_base & _r) { + bound_relation const& r = get(_r); + bound_relation_plugin& p = r.get_plugin(); + bound_relation* result = get(p.mk_full(0, get_result_signature())); + result->mk_rename(r, m_cycle.size(), m_cycle.c_ptr()); + return result; + } + }; + + relation_transformer_fn * bound_relation_plugin::mk_rename_fn(const relation_base & r, + unsigned cycle_len, const unsigned * permutation_cycle) { + if(check_kind(r)) { + return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle); + } + return 0; + } + + + class bound_relation_plugin::union_fn : public relation_union_fn { + bool m_is_widen; + public: + union_fn(bool is_widen) : + m_is_widen(is_widen) { + } + virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + TRACE("bound_relation", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); + get(_r).mk_union(get(_src), get(_delta), m_is_widen); + } + }; + + class bound_relation_plugin::union_fn_i : public relation_union_fn { + bool m_is_widen; + public: + union_fn_i(bool is_widen) : + m_is_widen(is_widen) { + } + virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + TRACE("bound_relation", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); + get(_r).mk_union_i(get_interval_relation(_src), get(_delta), m_is_widen); + TRACE("bound_relation", _r.display(tout << "dst':\n");); + } + }; + + + relation_union_fn * bound_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (check_kind(tgt) && is_interval_relation(src) && (!delta || check_kind(*delta))) { + return alloc(union_fn_i, false); + } + if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) { + return alloc(union_fn, false); + } + return 0; + } + + relation_union_fn * bound_relation_plugin::mk_widen_fn( + const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (check_kind(tgt) && is_interval_relation(src) && (!delta || check_kind(*delta))) { + return alloc(union_fn_i, true); + } + if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) { + return alloc(union_fn, true); + } + return 0; + } + + class bound_relation_plugin::filter_identical_fn : public relation_mutator_fn { + unsigned_vector m_cols; + public: + filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) + : m_cols(col_cnt, identical_cols) {} + + virtual void operator()(relation_base & r) { + for (unsigned i = 1; i < m_cols.size(); ++i) { + get(r).equate(m_cols[0], m_cols[i]); + } + } + }; + + relation_mutator_fn * bound_relation_plugin::mk_filter_identical_fn( + const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { + if(check_kind(t)) { + return alloc(filter_identical_fn, col_cnt, identical_cols); + } + return 0; + } + + class bound_relation_plugin::filter_equal_fn : public relation_mutator_fn { + public: + filter_equal_fn(relation_element const& value, unsigned col) {} + + virtual void operator()(relation_base & r) { } + }; + + relation_mutator_fn * bound_relation_plugin::mk_filter_equal_fn(const relation_base & r, + const relation_element & value, unsigned col) { + if (check_kind(r)) { + return alloc(filter_equal_fn, value, col); + } + return 0; + } + + class bound_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { + enum kind_t { NOT_APPLICABLE, EQ_VAR, EQ_SUB, LT_VAR, LE_VAR, K_FALSE }; + app_ref m_cond; + app_ref m_lt; + arith_util m_arith; + interval_relation* m_interval; + unsigned_vector m_vars; + kind_t m_kind; + + unsigned get_var(expr* a) { + SASSERT(is_var(a)); + return to_var(a)->get_idx(); + } + + // x = z - y + void mk_sub_eq(expr* x, expr* z, expr* y) { + SASSERT(is_var(x)); + SASSERT(is_var(z)); + SASSERT(is_var(y)); + m_vars.push_back(get_var(x)); + m_vars.push_back(get_var(z)); + m_vars.push_back(get_var(y)); + m_kind = EQ_SUB; + } + + void mk_lt(expr* l, expr* r) { + SASSERT(is_var(l)); + SASSERT(is_var(r)); + m_vars.push_back(get_var(l)); + m_vars.push_back(get_var(r)); + m_lt = m_arith.mk_lt(l, r); + m_kind = LT_VAR; + } + + + void mk_le(expr* l, expr* r) { + SASSERT(is_var(l)); + SASSERT(is_var(r)); + m_vars.push_back(get_var(l)); + m_vars.push_back(get_var(r)); + m_kind = LE_VAR; + } + + void mk_eq(expr* l, expr* r) { + m_vars.push_back(get_var(l)); + m_vars.push_back(get_var(r)); + m_kind = EQ_VAR; + } + + public: + + filter_interpreted_fn(ast_manager& m, app* cond) : + m_cond(cond, m), + m_lt(m), m_arith(m), m_interval(0), m_kind(NOT_APPLICABLE) { + expr* l, *r, *r1, *r2, *c2; + rational n1; + if ((m_arith.is_lt(cond, l, r) || m_arith.is_gt(cond, r, l)) && + is_var(l) && is_var(r)) { + mk_lt(l, r); + } + else if (m.is_not(cond, c2) && + (m_arith.is_ge(c2, l, r) || m_arith.is_le(c2, r, l)) && + is_var(l) && is_var(r)) { + mk_lt(l, r); + } + else if ((m_arith.is_le(cond, l, r) || m_arith.is_ge(cond, r, l)) && + is_var(l) && is_var(r)) { + mk_le(l, r); + } + else if (m.is_not(cond, c2) && + (m_arith.is_gt(c2, l, r) || m_arith.is_lt(c2, r, l)) && + is_var(l) && is_var(r)) { + mk_le(l, r); + } + else if (m.is_false(cond)) { + m_kind = K_FALSE; + } + else if (m.is_eq(cond, l, r) && is_var(l) && is_var(r)) { + mk_eq(l, r); + } + else if (m.is_eq(cond, l, r) && + m_arith.is_sub(r, r1, r2) && + is_var(l) && is_var(r1) && is_var(r2)) { + mk_sub_eq(l, r1, r2); + } + else if (m.is_eq(cond, l, r) && + m_arith.is_sub(l, r1, r2) && + is_var(r) && is_var(r1) && is_var(r2)) { + mk_sub_eq(r, r1, r2); + } + else if (m.is_eq(cond, l, r) && + m_arith.is_add(r, r1, r2) && + m_arith.is_numeral(r1, n1) && + n1.is_pos() && is_var(l) && is_var(r2)) { + mk_lt(r2, l); + } + else if (m.is_eq(cond, l, r) && + m_arith.is_add(r, r1, r2) && + m_arith.is_numeral(r2, n1) && + n1.is_pos() && is_var(l) && is_var(r1)) { + mk_lt(r1, l); + } + else { + + } + } + + // + // x = z - y + // x = y + // x < y + // x <= y + // x < y + z + // + + void operator()(relation_base& t) { + TRACE("dl", tout << mk_pp(m_cond, m_cond.get_manager()) << "\n"; t.display(tout);); + bound_relation& r = get(t); + switch(m_kind) { + case K_FALSE: + r.set_empty(); + break; + case NOT_APPLICABLE: + break; + case EQ_VAR: + r.equate(m_vars[0], m_vars[1]); + break; + case EQ_SUB: + // TBD + break; + case LT_VAR: + r.mk_lt(m_vars[0], m_vars[1]); + break; + case LE_VAR: + r.mk_le(m_vars[0], m_vars[1]); + break; + default: + UNREACHABLE(); + break; + } + TRACE("dl", t.display(tout << "result\n");); + } + + bool supports_attachment(relation_base& t) { + return is_interval_relation(t); + } + + void attach(relation_base& t) { + SASSERT(is_interval_relation(t)); + interval_relation& r = get_interval_relation(t); + m_interval = &r; + } + }; + + relation_mutator_fn * bound_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { + return alloc(filter_interpreted_fn, t.get_plugin().get_ast_manager(), condition); + } + + // ----------------------------- + // bound_relation + + void bound_relation_helper::mk_project_t(uint_set2& t, unsigned_vector const& renaming) { + if (t.lt.empty() && t.le.empty()) { + return; + } + uint_set::iterator it = t.lt.begin(), end = t.lt.end(); + unsigned_vector ltv, lev; + for (; it != end; ++it) { + ltv.push_back(renaming[*it]); + } + it = t.le.begin(), end = t.le.end(); + for (; it != end; ++it) { + lev.push_back(renaming[*it]); + } + TRACE("dl", + tout << "project: "; + for (unsigned i = 0; i < renaming.size(); ++i) + if (renaming[i] == UINT_MAX) tout << i << " "; + tout << ": "; + it = t.lt.begin(); end = t.lt.end(); + for (; it != end; ++it) tout << *it << " "; + tout << " le "; + it = t.le.begin(); end = t.le.end(); + for (; it != end; ++it) tout << *it << " "; + tout << " => "; + for (unsigned i = 0; i < ltv.size(); ++i) tout << ltv[i] << " "; + tout << " le "; + for (unsigned i = 0; i < lev.size(); ++i) tout << lev[i] << " "; + tout << "\n";); + t.lt.reset(); + for (unsigned i = 0; i < ltv.size(); ++i) { + t.lt.insert(ltv[i]); + } + t.le.reset(); + for (unsigned i = 0; i < lev.size(); ++i) { + t.le.insert(lev[i]); + } + } + + bound_relation::bound_relation(bound_relation_plugin& p, relation_signature const& s, bool is_empty): + vector_relation(p, s, is_empty, uint_set2()) + { + } + + + uint_set2 bound_relation::mk_intersect(uint_set2 const& t1, uint_set2 const& t2, bool& is_empty) const { + is_empty = false; + uint_set2 r(t1); + r.lt |= t2.lt; + r.le |= t2.le; + return r; + } + + uint_set2 bound_relation::mk_widen(uint_set2 const& t1, uint_set2 const& t2) const { + return mk_unite(t1, t2); + } + + uint_set2 bound_relation::mk_unite(uint_set2 const& t1, uint_set2 const& t2) const { + uint_set2 s1(t1); + s1.lt &= t2.lt; + s1.le &= t2.le; + return s1; + } + + uint_set2 bound_relation::mk_eq(union_find<> const& old_eqs, union_find<> const& new_eqs, uint_set2 const& t) const { + unsigned sz = old_eqs.get_num_vars(); + SASSERT(sz == new_eqs.get_num_vars()); + uint_set2 result; + for (unsigned i = 0; i < sz; ++i) { + if (t.lt.contains(i)) { + unsigned j = i; + do { + result.lt.insert(new_eqs.find(j)); + j = old_eqs.next(j); + } + while (j != i); + } + if (t.le.contains(i)) { + unsigned j = i; + do { + result.le.insert(new_eqs.find(j)); + j = old_eqs.next(j); + } + while (j != i); + } + } + return result; + } + + bool bound_relation::is_subset_of(uint_set2 const& t1, uint_set2 const& t2) const { + uint_set2 s1, s2; + normalize(t1, s1); + normalize(t2, s2); + return s1.lt.subset_of(s2.lt) && s1.le.subset_of(s2.le); + } + + void bound_relation::mk_rename_elem(uint_set2& t, unsigned col_cnt, unsigned const* cycle) { + // [ 0 -> 2 -> 3 -> 0] + if (col_cnt == 0) return; + unsigned col1, col2; + col1 = find(cycle[0]); + col2 = find(cycle[col_cnt-1]); + bool has_col2_lt = t.lt.contains(col2); + t.lt.remove(col2); + bool has_col2_le = t.le.contains(col2); + t.le.remove(col2); + for (unsigned i = 0; i + 1 < col_cnt; ++i) { + col1 = find(cycle[i]); + col2 = find(cycle[i+1]); + if (t.lt.contains(col1)) { + t.lt.remove(col1); + t.lt.insert(col2); + } + if (t.le.contains(col1)) { + t.le.remove(col1); + t.le.insert(col2); + } + } + if (has_col2_lt) { + col1 = find(cycle[0]); + t.lt.insert(col1); + } + if (has_col2_le) { + col1 = find(cycle[0]); + t.le.insert(col1); + } + } + + + bool bound_relation::is_full(uint_set2 const& t) const { + return t.lt.empty() && t.le.empty(); + } + + bool bound_relation::is_empty(unsigned index, uint_set2 const& t) const { + return t.lt.contains(find(index)) || t.le.contains(find(index)); + } + + void bound_relation::normalize(uint_set const& src, uint_set& dst) const { + uint_set::iterator it = src.begin(), end = src.end(); + for (; it != end; ++it) { + dst.insert(find(*it)); + } + } + void bound_relation::normalize(uint_set2 const& src, uint_set2& dst) const { + normalize(src.lt, dst.lt); + normalize(src.le, dst.le); + } + + + void bound_relation::mk_lt(unsigned i) { + uint_set2& dst = (*this)[i]; + while (!m_todo.empty()) { + unsigned j = m_todo.back().first; + bool strict = m_todo.back().second; + if (i == j && strict) { + m_todo.reset(); + m_empty = true; + return; + } + m_todo.pop_back(); + if (i == j) { + continue; + } + uint_set2& src = (*m_elems)[j]; + uint_set::iterator it = src.lt.begin(), end = src.lt.end(); + for(; it != end; ++it) { + m_todo.push_back(std::make_pair(*it, true)); + } + it = src.le.begin(), end = src.le.end(); + for(; it != end; ++it) { + m_todo.push_back(std::make_pair(*it, strict)); + } + if (strict) { + dst.lt.insert(j); + } + else { + dst.le.insert(j); + } + } + } + + void bound_relation::mk_lt(unsigned i, unsigned j) { + m_todo.reset(); + i = find(i); + m_todo.push_back(std::make_pair(find(j), true)); + mk_lt(i); + } + + void bound_relation::mk_le(unsigned i, unsigned j) { + m_todo.reset(); + i = find(i); + m_todo.push_back(std::make_pair(find(j), false)); + mk_lt(i); + } + + bool bound_relation::is_lt(unsigned i, unsigned j) const { + return (*this)[i].lt.contains(find(j)); + } + + void bound_relation::add_fact(const relation_fact & f) { + bound_relation r(get_plugin(), get_signature(), false); + for (unsigned i = 0; i < f.size(); ++i) { + scoped_ptr fe = get_plugin().mk_filter_equal_fn(r, f[i], i); + (*fe)(r); + } + mk_union(r, 0, false); + } + + bool bound_relation::contains_fact(const relation_fact & f) const { + if (empty()) { + return false; + } + // this is a very rough approximation. + return true; + } + + bound_relation * bound_relation::clone() const { + bound_relation* result = 0; + if (empty()) { + result = bound_relation_plugin::get(get_plugin().mk_empty(get_signature())); + } + else { + result = bound_relation_plugin::get(get_plugin().mk_full(0, get_signature())); + result->copy(*this); + } + return result; + } + + void bound_relation::mk_union_i(interval_relation const& src, bound_relation* delta, bool is_widen) { + unsigned size = get_signature().size(); + for (unsigned i = 0; i < size; ++i) { + if (find(i) != i) { + continue; + } + uint_set2& s = (*this)[i]; + ext_numeral const& lo = src[i].sup(); + if (lo.is_infinite()) { + s.lt.reset(); + s.le.reset(); + continue; + } + uint_set::iterator it = s.lt.begin(), end = s.lt.end(); + for(; it != end; ++it) { + ext_numeral const& hi = src[*it].inf(); + if (hi.is_infinite() || lo.to_rational() >= hi.to_rational()) { + s.lt.remove(*it); + } + } + it = s.le.begin(), end = s.le.end(); + for(; it != end; ++it) { + ext_numeral const& hi = src[*it].inf(); + if (hi.is_infinite() || lo.to_rational() > hi.to_rational()) { + s.le.remove(*it); + } + } + } + } + + bound_relation * bound_relation::complement(func_decl* p) const { + UNREACHABLE(); + return 0; + } + + void bound_relation::to_formula(expr_ref& fml) const { + ast_manager& m = get_plugin().get_ast_manager(); + arith_util& arith = get_plugin().m_arith; + basic_simplifier_plugin& bsimp = get_plugin().m_bsimp; + expr_ref_vector conjs(m); + relation_signature const& sig = get_signature(); + for (unsigned i = 0; i < sig.size(); ++i) { + if (i != find(i)) { + conjs.push_back(m.mk_eq(m.mk_var(i, sig[i]), m.mk_var(find(i), sig[find(i)]))); + continue; + } + uint_set2 const& upper = (*this)[i]; + uint_set::iterator it = upper.lt.begin(), end = upper.lt.end(); + for (; it != end; ++it) { + conjs.push_back(arith.mk_lt(m.mk_var(i, sig[i]), m.mk_var(*it, sig[*it]))); + } + it = upper.le.begin(), end = upper.le.end(); + for (; it != end; ++it) { + conjs.push_back(arith.mk_le(m.mk_var(i, sig[i]), m.mk_var(*it, sig[*it]))); + } + } + bsimp.mk_and(conjs.size(), conjs.c_ptr(), fml); + } + + + void bound_relation::display_index(unsigned i, uint_set2 const& src, std::ostream & out) const { + uint_set::iterator it = src.lt.begin(), end = src.lt.end(); + out << "#" << i; + if (!src.lt.empty()) { + out << " < "; + for(; it != end; ++it) { + out << *it << " "; + } + } + if (!src.le.empty()) { + it = src.le.begin(), end = src.le.end(); + out << " <= "; + for(; it != end; ++it) { + out << *it << " "; + } + } + if (src.lt.empty() && src.le.empty()) { + out << " < oo"; + } + out << "\n"; + } + + bound_relation_plugin& bound_relation::get_plugin() const { + return dynamic_cast(relation_base::get_plugin()); + } + + +}; + + diff --git a/src/muz/rel/dl_bound_relation.h b/src/muz/rel/dl_bound_relation.h new file mode 100644 index 000000000..906ba571a --- /dev/null +++ b/src/muz/rel/dl_bound_relation.h @@ -0,0 +1,178 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + dl_bound_relation.h + +Abstract: + + Basic (strict upper) bound relation. + +Author: + + Nikolaj Bjorner (nbjorner) 2010-2-11 + +Revision History: + +--*/ +#ifndef _DL_BOUND_RELATION_H_ +#define _DL_BOUND_RELATION_H_ + +#include "dl_context.h" +#include "dl_relation_manager.h" +#include "dl_base.h" +#include "uint_set.h" +#include "dl_vector_relation.h" +#include "dl_interval_relation.h" +#include "arith_decl_plugin.h" +#include "basic_simplifier_plugin.h" + +namespace datalog { + + class bound_relation; + + class bound_relation_plugin : public relation_plugin { + friend class bound_relation; + class join_fn; + class project_fn; + class rename_fn; + class union_fn; + class union_fn_i; + class filter_equal_fn; + class filter_identical_fn; + class filter_interpreted_fn; + class filter_intersection_fn; + arith_util m_arith; + basic_simplifier_plugin m_bsimp; + public: + bound_relation_plugin(relation_manager& m); + virtual bool can_handle_signature(const relation_signature & s); + static symbol get_name() { return symbol("bound_relation"); } + virtual relation_base * mk_empty(const relation_signature & s); + virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + + virtual relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) { return 0; } + + +#if 0 + virtual intersection_filter_fn * mk_filter_by_intersection_fn( + const relation_base & t, + const relation_base & src, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * src_cols) { + return 0; + } +#endif + + static bound_relation* get(relation_base* r); + private: + static bound_relation& get(relation_base& r); + static bound_relation const & get(relation_base const& r); + + + static bool is_interval_relation(relation_base const& r); + static interval_relation& get_interval_relation(relation_base& r); + static interval_relation const& get_interval_relation(relation_base const& r); + }; + + struct uint_set2 { + uint_set lt; + uint_set le; + uint_set2(uint_set2 const& other):lt(other.lt), le(other.le) {} + uint_set2() {} + bool operator==(const uint_set2& other) const { + return other.lt == lt && other.le == le; + } + bool operator!=(const uint_set2& other) const { + return other.lt != lt || other.le != le; + } + }; + + inline std::ostream & operator<<(std::ostream & target, const uint_set2 & s) { + return target << s.lt << " " << s.le; + } + + + class bound_relation_helper { + public: + static void mk_project_t(uint_set2& t, unsigned_vector const& renaming); + }; + + class bound_relation : public vector_relation { + friend class bound_relation_plugin; + svector > m_todo; + + public: + bound_relation(bound_relation_plugin& p, relation_signature const& s, bool is_empty); + bound_relation& operator=(bound_relation const& other); + + virtual bool empty() const { return m_empty; } + virtual void add_fact(const relation_fact & f); + virtual bool contains_fact(const relation_fact & f) const; + virtual bound_relation * clone() const; + virtual bound_relation * complement(func_decl* p) const; + virtual void to_formula(expr_ref& fml) const; + bound_relation_plugin& get_plugin() const; + + void mk_union_i(interval_relation const& src, bound_relation* delta, bool is_widen); + + void mk_lt(unsigned i, unsigned j); + + void mk_lt(unsigned i); + + void mk_le(unsigned i, unsigned j); + + bool is_lt(unsigned i, unsigned j) const; + + virtual bool is_precise() const { return false; } + + private: + typedef uint_set2 T; + virtual T mk_intersect(T const& t1, T const& t2, bool& is_empty) const; + + virtual T mk_widen(T const& t1, T const& t2) const; + + virtual T mk_unite(T const& t1, T const& t2) const; + + virtual T mk_eq(union_find<> const& old_eqs, union_find<> const& new_eqs, T const& t) const; + + virtual void mk_rename_elem(T& i, unsigned col_cnt, unsigned const* cycle); + + + virtual bool is_subset_of(T const& t1, T const& t2) const; + + virtual bool is_full(T const& t) const; + + virtual bool is_empty(unsigned idx, T const& t) const; + + virtual void display_index(unsigned idx, T const& t, std::ostream& out) const; + + void normalize(T const& src, T& dst) const; + + void normalize(uint_set const& src, uint_set& dst) const; + + + + }; + +}; + +#endif + diff --git a/src/muz/rel/dl_check_table.cpp b/src/muz/rel/dl_check_table.cpp new file mode 100644 index 000000000..ea4003e5f --- /dev/null +++ b/src/muz/rel/dl_check_table.cpp @@ -0,0 +1,439 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + dl_check_table.cpp + +Abstract: + + + +Author: + + Nikolaj Bjorner (nbjorner) 2010-11-15 + + +Revision History: + +--*/ + + +#include "dl_check_table.h" +#include "dl_table.h" + + +namespace datalog { + + bool check_table_plugin::can_handle_signature(table_signature const& s) { + return m_tocheck.can_handle_signature(s) && m_checker.can_handle_signature(s); + } + + + check_table & check_table_plugin::get(table_base& r) { + return static_cast(r); + } + + check_table const & check_table_plugin::get(table_base const& r) { + return static_cast(r); + } + + table_base& check_table_plugin::checker(table_base& r) { return *get(r).m_checker; } + table_base const& check_table_plugin::checker(table_base const& r) { return *get(r).m_checker; } + table_base* check_table_plugin::checker(table_base* r) { return r?(get(*r).m_checker):0; } + table_base const* check_table_plugin::checker(table_base const* r) { return r?(get(*r).m_checker):0; } + table_base& check_table_plugin::tocheck(table_base& r) { return *get(r).m_tocheck; } + table_base const& check_table_plugin::tocheck(table_base const& r) { return *get(r).m_tocheck; } + table_base* check_table_plugin::tocheck(table_base* r) { return r?(get(*r).m_tocheck):0; } + table_base const* check_table_plugin::tocheck(table_base const* r) { return r?(get(*r).m_tocheck):0; } + + table_base * check_table_plugin::mk_empty(const table_signature & s) { + IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); + table_base* checker = m_checker.mk_empty(s); + table_base* tocheck = m_tocheck.mk_empty(s); + return alloc(check_table, *this, s, tocheck, checker); + } + + class check_table_plugin::join_fn : public table_join_fn { + scoped_ptr m_tocheck; + scoped_ptr m_checker; + public: + join_fn(check_table_plugin& p, + const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + m_tocheck = p.get_manager().mk_join_fn(tocheck(t1), tocheck(t2), col_cnt, cols1, cols2); + m_checker = p.get_manager().mk_join_fn(checker(t1), checker(t2), col_cnt, cols1, cols2); + } + + virtual table_base* operator()(const table_base & t1, const table_base & t2) { + IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); + table_base* ttocheck = (*m_tocheck)(tocheck(t1), tocheck(t2)); + table_base* tchecker = (*m_checker)(checker(t1), checker(t2)); + check_table* result = alloc(check_table, get(t1).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); + return result; + } + }; + + table_join_fn * check_table_plugin::mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (!check_kind(t1) || !check_kind(t2)) { + return 0; + } + return alloc(join_fn, *this, t1, t2, col_cnt, cols1, cols2); + } + + class check_table_plugin::join_project_fn : public table_join_fn { + scoped_ptr m_tocheck; + scoped_ptr m_checker; + public: + join_project_fn(check_table_plugin& p, const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) { + m_tocheck = p.get_manager().mk_join_project_fn(tocheck(t1), tocheck(t2), col_cnt, cols1, cols2, removed_col_cnt, removed_cols); + m_checker = p.get_manager().mk_join_project_fn(checker(t1), checker(t2), col_cnt, cols1, cols2, removed_col_cnt, removed_cols); + } + + virtual table_base* operator()(const table_base & t1, const table_base & t2) { + table_base* ttocheck = (*m_tocheck)(tocheck(t1), tocheck(t2)); + table_base* tchecker = (*m_checker)(checker(t1), checker(t2)); + check_table* result = alloc(check_table, get(t1).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); + return result; + } + }; + + table_join_fn * check_table_plugin::mk_join_project_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols) { + if (!check_kind(t1) || !check_kind(t2)) { + return 0; + } + return alloc(join_project_fn, *this, t1, t2, col_cnt, cols1, cols2, removed_col_cnt, removed_cols); + } + + class check_table_plugin::union_fn : public table_union_fn { + scoped_ptr m_tocheck; + scoped_ptr m_checker; + public: + union_fn(check_table_plugin& p, table_base const& tgt, const table_base& src, table_base const* delta) { + m_tocheck = p.get_manager().mk_union_fn(tocheck(tgt), tocheck(src), tocheck(delta)); + m_checker = p.get_manager().mk_union_fn(checker(tgt), checker(src), checker(delta)); + } + + virtual void operator()(table_base& tgt, const table_base& src, table_base* delta) { + IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); + (*m_tocheck)(tocheck(tgt), tocheck(src), tocheck(delta)); + (*m_checker)(checker(tgt), checker(src), checker(delta)); + get(tgt).well_formed(); + if (delta) { + get(*delta).well_formed(); + } + } + }; + + table_union_fn * check_table_plugin::mk_union_fn(const table_base & tgt, const table_base & src, const table_base * delta) { + if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { + return 0; + } + return alloc(union_fn, *this, tgt, src, delta); + + } + + class check_table_plugin::project_fn : public table_transformer_fn { + scoped_ptr m_checker; + scoped_ptr m_tocheck; + public: + project_fn(check_table_plugin& p, const table_base & t, unsigned col_cnt, const unsigned * removed_cols) { + m_checker = p.get_manager().mk_project_fn(checker(t), col_cnt, removed_cols); + m_tocheck = p.get_manager().mk_project_fn(tocheck(t), col_cnt, removed_cols); + } + + table_base* operator()(table_base const& src) { + table_base* tchecker = (*m_checker)(checker(src)); + table_base* ttocheck = (*m_tocheck)(tocheck(src)); + check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker); + return result; + } + }; + + table_transformer_fn * check_table_plugin::mk_project_fn(const table_base & t, unsigned col_cnt, const unsigned * removed_cols) { + if (!check_kind(t)) { + return 0; + } + return alloc(project_fn, *this, t, col_cnt, removed_cols); + } + + class check_table_plugin::select_equal_and_project_fn : public table_transformer_fn { + scoped_ptr m_checker; + scoped_ptr m_tocheck; + public: + select_equal_and_project_fn(check_table_plugin& p, const table_base & t, const table_element & value, unsigned col) { + m_checker = p.get_manager().mk_select_equal_and_project_fn(checker(t), value, col); + m_tocheck = p.get_manager().mk_select_equal_and_project_fn(tocheck(t), value, col); + } + + table_base* operator()(table_base const& src) { + table_base* tchecker = (*m_checker)(checker(src)); + table_base* ttocheck = (*m_tocheck)(tocheck(src)); + check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker); + return result; + } + }; + + table_transformer_fn * check_table_plugin::mk_select_equal_and_project_fn(const table_base & t, + const table_element & value, unsigned col) { + if (!check_kind(t)) { + return 0; + } + return alloc(select_equal_and_project_fn, *this, t, value, col); + } + + class check_table_plugin::rename_fn : public table_transformer_fn { + scoped_ptr m_checker; + scoped_ptr m_tocheck; + public: + rename_fn(check_table_plugin& p, const table_base & t, unsigned cycle_len, unsigned const* cycle) { + m_checker = p.get_manager().mk_rename_fn(checker(t), cycle_len, cycle); + m_tocheck = p.get_manager().mk_rename_fn(tocheck(t), cycle_len, cycle); + } + + table_base* operator()(table_base const& src) { + IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); + table_base* tchecker = (*m_checker)(checker(src)); + table_base* ttocheck = (*m_tocheck)(tocheck(src)); + check_table* result = alloc(check_table, get(src).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); + return result; + } + }; + + table_transformer_fn * check_table_plugin::mk_rename_fn(const table_base & t, unsigned len, const unsigned * cycle) { + if (!check_kind(t)) { + return 0; + } + return alloc(rename_fn, *this, t, len, cycle); + } + + class check_table_plugin::filter_identical_fn : public table_mutator_fn { + scoped_ptr m_checker; + scoped_ptr m_tocheck; + public: + filter_identical_fn(check_table_plugin& p, const table_base & t,unsigned cnt, unsigned const* cols) + { + m_checker = p.get_manager().mk_filter_identical_fn(checker(t), cnt, cols); + m_tocheck = p.get_manager().mk_filter_identical_fn(tocheck(t), cnt, cols); + } + + void operator()(table_base & t) { + (*m_checker)(checker(t)); + (*m_tocheck)(tocheck(t)); + get(t).well_formed(); + } + }; + + table_mutator_fn * check_table_plugin::mk_filter_identical_fn(const table_base & t, unsigned col_cnt, + const unsigned * identical_cols) { + if (check_kind(t)) { + return alloc(filter_identical_fn, *this, t, col_cnt, identical_cols); + } + return 0; + } + + class check_table_plugin::filter_equal_fn : public table_mutator_fn { + scoped_ptr m_checker; + scoped_ptr m_tocheck; + public: + filter_equal_fn(check_table_plugin& p, const table_base & t, const table_element & v, unsigned col) + { + m_checker = p.get_manager().mk_filter_equal_fn(checker(t), v, col); + m_tocheck = p.get_manager().mk_filter_equal_fn(tocheck(t), v, col); + } + + virtual void operator()(table_base& src) { + (*m_checker)(checker(src)); + (*m_tocheck)(tocheck(src)); + get(src).well_formed(); + } + }; + + table_mutator_fn * check_table_plugin::mk_filter_equal_fn(const table_base & t, const table_element & value, unsigned col) { + if (check_kind(t)) { + return alloc(filter_equal_fn, *this, t, value, col); + } + return 0; + } + + class check_table_plugin::filter_interpreted_fn : public table_mutator_fn { + scoped_ptr m_checker; + scoped_ptr m_tocheck; + public: + filter_interpreted_fn(check_table_plugin& p, const table_base & t, app * condition) + { + m_checker = p.get_manager().mk_filter_interpreted_fn(checker(t), condition); + m_tocheck = p.get_manager().mk_filter_interpreted_fn(tocheck(t), condition); + } + + virtual void operator()(table_base& src) { + (*m_checker)(checker(src)); + (*m_tocheck)(tocheck(src)); + get(src).well_formed(); + } + }; + + table_mutator_fn * check_table_plugin::mk_filter_interpreted_fn(const table_base & t, app * condition) { + if (check_kind(t)) { + return alloc(filter_interpreted_fn, *this, t, condition); + } + return 0; + } + + class check_table_plugin::filter_interpreted_and_project_fn : public table_transformer_fn { + scoped_ptr m_checker; + scoped_ptr m_tocheck; + public: + filter_interpreted_and_project_fn(check_table_plugin& p, const table_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols) + { + m_checker = p.get_manager().mk_filter_interpreted_and_project_fn(checker(t), condition, removed_col_cnt, removed_cols); + m_tocheck = p.get_manager().mk_filter_interpreted_and_project_fn(tocheck(t), condition, removed_col_cnt, removed_cols); + } + + table_base* operator()(table_base const& src) { + table_base* tchecker = (*m_checker)(checker(src)); + table_base* ttocheck = (*m_tocheck)(tocheck(src)); + check_table* result = alloc(check_table, get(src).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker); + return result; + } + }; + + table_transformer_fn * check_table_plugin::mk_filter_interpreted_and_project_fn(const table_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { + if (check_kind(t)) { + return alloc(filter_interpreted_and_project_fn, *this, t, condition, removed_col_cnt, removed_cols); + } + return 0; + } + + class check_table_plugin::filter_by_negation_fn : public table_intersection_filter_fn { + scoped_ptr m_checker; + scoped_ptr m_tocheck; + public: + filter_by_negation_fn( + check_table_plugin& p, + const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) { + m_checker = p.get_manager().mk_filter_by_negation_fn(checker(t), checker(negated_obj), joined_col_cnt, t_cols, negated_cols); + m_tocheck = p.get_manager().mk_filter_by_negation_fn(tocheck(t), tocheck(negated_obj), joined_col_cnt, t_cols, negated_cols); + } + + virtual void operator()(table_base& src, table_base const& negated_obj) { + IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); + (*m_checker)(checker(src), checker(negated_obj)); + (*m_tocheck)(tocheck(src), tocheck(negated_obj)); + get(src).well_formed(); + } + + }; + + table_intersection_filter_fn * check_table_plugin::mk_filter_by_negation_fn(const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) { + if (check_kind(t) && check_kind(negated_obj)) { + return alloc(filter_by_negation_fn, *this, t, negated_obj, joined_col_cnt, t_cols, negated_cols); + } + return 0; + } + + // ------------------ + // check_table + + + check_table::check_table(check_table_plugin & p, const table_signature & sig): + table_base(p, sig) { + (well_formed()); + } + + check_table::check_table(check_table_plugin & p, const table_signature & sig, table_base* tocheck, table_base* checker): + table_base(p, sig), + m_checker(checker), + m_tocheck(tocheck) { + well_formed(); + } + + check_table::~check_table() { + m_tocheck->deallocate(); + m_checker->deallocate(); + } + + bool check_table::well_formed() const { + get_plugin().m_count++; + iterator it = m_tocheck->begin(), end = m_tocheck->end(); + for (; it != end; ++it) { + table_fact fact; + it->get_fact(fact); + if (!m_checker->contains_fact(fact)) { + m_tocheck->display(verbose_stream()); + m_checker->display(verbose_stream()); + verbose_stream() << get_plugin().m_count << "\n"; + UNREACHABLE(); + fatal_error(0); + return false; + } + } + iterator it2 = m_checker->begin(), end2 = m_checker->end(); + for (; it2 != end2; ++it2) { + table_fact fact; + it2->get_fact(fact); + if (!m_tocheck->contains_fact(fact)) { + m_tocheck->display(verbose_stream()); + m_checker->display(verbose_stream()); + verbose_stream() << get_plugin().m_count << "\n"; + UNREACHABLE(); + fatal_error(0); + return false; + } + } + return true; + } + + bool check_table::empty() const { + if (m_tocheck->empty() != m_checker->empty()) { + m_tocheck->display(verbose_stream()); + m_checker->display(verbose_stream()); + verbose_stream() << get_plugin().m_count << "\n"; + fatal_error(0); + } + return m_tocheck->empty(); + } + + + void check_table::add_fact(const table_fact & f) { + IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); + m_tocheck->add_fact(f); + m_checker->add_fact(f); + well_formed(); + } + + void check_table::remove_fact(const table_element* f) { + IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); + m_tocheck->remove_fact(f); + m_checker->remove_fact(f); + well_formed(); + } + + bool check_table::contains_fact(const table_fact & f) const { + return m_checker->contains_fact(f); + } + + table_base * check_table::clone() const { + IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";); + check_table* result = alloc(check_table, get_plugin(), get_signature(), m_tocheck->clone(), m_checker->clone()); + return result; + } + + table_base * check_table::complement(func_decl* p, const table_element * func_columns) const { + check_table* result = alloc(check_table, get_plugin(), get_signature(), m_tocheck->complement(p, func_columns), m_checker->complement(p, func_columns)); + return result; + } + +}; + diff --git a/src/muz/rel/dl_check_table.h b/src/muz/rel/dl_check_table.h new file mode 100644 index 000000000..e4f439590 --- /dev/null +++ b/src/muz/rel/dl_check_table.h @@ -0,0 +1,135 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + dl_check_table.h + +Abstract: + + + +Author: + + Nikolaj Bjorner (nbjorner) 2010-11-15 + + +Revision History: + +--*/ + +#ifndef _DL_CHECK_TABLE_H_ +#define _DL_CHECK_TABLE_H_ + +#include "dl_base.h" +#include "dl_decl_plugin.h" +#include "dl_relation_manager.h" + +namespace datalog { + class check_table; + + class check_table_plugin : public table_plugin { + friend class check_table; + table_plugin& m_checker; + table_plugin& m_tocheck; + unsigned m_count; + protected: + class join_fn; + class join_project_fn; + class union_fn; + class transformer_fn; + class rename_fn; + class project_fn; + class select_equal_and_project_fn; + class filter_equal_fn; + class filter_identical_fn; + class filter_interpreted_fn; + class filter_interpreted_and_project_fn; + class filter_by_negation_fn; + + public: + check_table_plugin(relation_manager & manager, symbol const& checker, symbol const& tocheck) + : table_plugin(symbol("check"), manager), + m_checker(*manager.get_table_plugin(checker)), + m_tocheck(*manager.get_table_plugin(tocheck)), m_count(0) {} + + virtual table_base * mk_empty(const table_signature & s); + + virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols); + virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, + const table_base * delta); + virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t, + const table_element & value, unsigned col); + virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual table_mutator_fn * mk_filter_identical_fn(const table_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value, + unsigned col); + virtual table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition); + virtual table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); + virtual table_intersection_filter_fn * mk_filter_by_negation_fn( + const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols); + + virtual bool can_handle_signature(table_signature const& s); + + private: + static check_table& get(table_base& r); + + static check_table const & get(table_base const& r); + + static table_base& checker(table_base& r); + static table_base const& checker(table_base const& r); + static table_base* checker(table_base* r); + static table_base const* checker(table_base const* r); + static table_base& tocheck(table_base& r); + static table_base const& tocheck(table_base const& r); + static table_base* tocheck(table_base* r); + static table_base const* tocheck(table_base const* r); + }; + + class check_table : public table_base { + friend class check_table_plugin; + + table_base* m_checker; + table_base* m_tocheck; + + check_table(check_table_plugin & p, const table_signature & sig); + check_table(check_table_plugin & p, const table_signature & sig, table_base* tocheck, table_base* checker); + + virtual ~check_table(); + + bool well_formed() const; + + public: + + check_table_plugin & get_plugin() const { + return static_cast(table_base::get_plugin()); + } + + virtual bool empty() const; + virtual void add_fact(const table_fact & f); + virtual void remove_fact(const table_element* fact); + virtual bool contains_fact(const table_fact & f) const; + virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const; + virtual table_base * clone() const; + + virtual iterator begin() const { SASSERT(well_formed()); return m_tocheck->begin(); } + virtual iterator end() const { return m_tocheck->end(); } + + virtual unsigned get_size_estimate_rows() const { return m_tocheck->get_size_estimate_rows(); } + virtual unsigned get_size_estimate_bytes() const { return m_tocheck->get_size_estimate_bytes(); } + }; + + }; + + #endif /* _DL_CHECK_TABLE_H_ */ diff --git a/src/muz/rel/dl_external_relation.cpp b/src/muz/rel/dl_external_relation.cpp new file mode 100644 index 000000000..f32509473 --- /dev/null +++ b/src/muz/rel/dl_external_relation.cpp @@ -0,0 +1,456 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + dl_external_relation.cpp + +Abstract: + + + +Author: + + Nikolaj Bjorner (nbjorner) 2010-05-10 + +Revision History: + +--*/ + +#include "debug.h" +#include "ast_pp.h" +#include "dl_context.h" +#include "dl_external_relation.h" +#include "dl_decl_plugin.h" + +namespace datalog { + + external_relation::external_relation(external_relation_plugin & p, const relation_signature & s, expr* r) + : relation_base(p, s), + m_rel(r, p.get_ast_manager()), + m_select_fn(p.get_ast_manager()), + m_store_fn(p.get_ast_manager()), + m_is_empty_fn(p.get_ast_manager()) + { + } + + external_relation::~external_relation() { + } + + void external_relation::mk_accessor(decl_kind k, func_decl_ref& fn, const relation_fact& f, bool destructive, expr_ref& res) const { + ast_manager& m = m_rel.get_manager(); + family_id fid = get_plugin().get_family_id(); + ptr_vector args; + args.push_back(m_rel); + for (unsigned i = 0; i < f.size(); ++i) { + args.push_back(f[i]); + } + if (!fn.get()) { + fn = m.mk_func_decl(fid, k, 0, 0, args.size(), args.c_ptr()); + } + if (destructive) { + get_plugin().reduce_assign(fn, args.size(), args.c_ptr(), 1, args.c_ptr()); + res = m_rel; + } + else { + get_plugin().reduce(fn, args.size(), args.c_ptr(), res); + } + } + + bool external_relation::empty() const { + ast_manager& m = m_rel.get_manager(); + expr* r = m_rel.get(); + expr_ref res(m); + if (!m_is_empty_fn.get()) { + family_id fid = get_plugin().get_family_id(); + const_cast(m_is_empty_fn) = m.mk_func_decl(fid, OP_RA_IS_EMPTY, 0, 0, 1, &r); + } + get_plugin().reduce(m_is_empty_fn, 1, &r, res); + return m.is_true(res); + } + + void external_relation::add_fact(const relation_fact & f) { + mk_accessor(OP_RA_STORE, m_store_fn, f, true, m_rel); + } + + bool external_relation::contains_fact(const relation_fact & f) const { + ast_manager& m = get_plugin().get_ast_manager(); + expr_ref res(m); + mk_accessor(OP_RA_SELECT, const_cast(m_select_fn), f, false, res); + return !m.is_false(res); + } + + external_relation * external_relation::clone() const { + ast_manager& m = m_rel.get_manager(); + family_id fid = get_plugin().get_family_id(); + expr* rel = m_rel.get(); + expr_ref res(m.mk_fresh_const("T", m.get_sort(rel)), m); + expr* rel_out = res.get(); + func_decl_ref fn(m.mk_func_decl(fid, OP_RA_CLONE,0,0, 1, &rel), m); + get_plugin().reduce_assign(fn, 1, &rel, 1, &rel_out); + return alloc(external_relation, get_plugin(), get_signature(), res); + } + + external_relation * external_relation::complement(func_decl* p) const { + ast_manager& m = m_rel.get_manager(); + family_id fid = get_plugin().get_family_id(); + expr_ref res(m); + expr* rel = m_rel; + func_decl_ref fn(m.mk_func_decl(fid, OP_RA_COMPLEMENT,0,0, 1, &rel), m); + get_plugin().reduce(fn, 1, &rel, res); + return alloc(external_relation, get_plugin(), get_signature(), res); + } + + void external_relation::display(std::ostream & out) const { + out << mk_pp(m_rel, m_rel.get_manager()) << "\n"; + } + + void external_relation::display_tuples(func_decl & pred, std::ostream & out) const { + display(out); + } + + + external_relation_plugin & external_relation::get_plugin() const { + return static_cast(relation_base::get_plugin()); + } + + + // ----------------------------------- + // + // external_relation_plugin + // + // ----------------------------------- + + + external_relation_plugin::external_relation_plugin(external_relation_context& ctx, relation_manager & m) + : relation_plugin(external_relation_plugin::get_name(), m), m_ext(ctx) {} + + external_relation const & external_relation_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + + external_relation & external_relation_plugin::get(relation_base & r) { + return dynamic_cast(r); + } + + relation_base * external_relation_plugin::mk_empty(const relation_signature & s) { + ast_manager& m = get_ast_manager(); + sort* r_sort = get_relation_sort(s); + parameter param(r_sort); + family_id fid = get_family_id(); + expr_ref e(m.mk_fresh_const("T", r_sort), m); + expr* args[1] = { e.get() }; + func_decl_ref empty_decl(m.mk_func_decl(fid, OP_RA_EMPTY, 1, ¶m, 0, (sort*const*)0), m); + reduce_assign(empty_decl, 0, 0, 1, args); + return alloc(external_relation, *this, s, e); + } + + sort* external_relation_plugin::get_relation_sort(relation_signature const& sig) { + vector sorts; + ast_manager& m = get_ast_manager(); + family_id fid = get_family_id(); + for (unsigned i = 0; i < sig.size(); ++i) { + sorts.push_back(parameter(sig[i])); + } + return m.mk_sort(fid, DL_RELATION_SORT, sorts.size(), sorts.c_ptr()); + } + + sort* external_relation_plugin::get_column_sort(unsigned col, sort* s) { + SASSERT(s->get_num_parameters() > col); + SASSERT(s->get_parameter(col).is_ast()); + SASSERT(is_sort(s->get_parameter(col).get_ast())); + return to_sort(s->get_parameter(col).get_ast()); + } + + family_id external_relation_plugin::get_family_id() { + return m_ext.get_family_id(); + } + + + void external_relation_plugin::mk_filter_fn(sort* s, app* condition, func_decl_ref& f) { + ast_manager& m = get_ast_manager(); + family_id fid = get_family_id(); + parameter param(condition); + f = m.mk_func_decl(fid, OP_RA_FILTER, 1, ¶m, 1, &s); + } + + class external_relation_plugin::join_fn : public convenient_relation_join_fn { + external_relation_plugin& m_plugin; + func_decl_ref m_join_fn; + expr* m_args[2]; + public: + join_fn(external_relation_plugin& p, const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2), + m_plugin(p), + m_join_fn(p.get_ast_manager()) { + ast_manager& m = p.get_ast_manager(); + family_id fid = p.get_family_id(); + vector params; + for (unsigned i = 0; i < col_cnt; ++i) { + params.push_back(parameter(cols1[i])); + params.push_back(parameter(cols2[i])); + } + sort* domain[2] = { p.get_relation_sort(o1_sig), p.get_relation_sort(o2_sig) }; + m_join_fn = m.mk_func_decl(fid, OP_RA_JOIN, params.size(), params.c_ptr(), 2, domain); + } + + virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + expr_ref res(m_plugin.get_ast_manager()); + m_args[0] = get(r1).get_relation(); + m_args[1] = get(r2).get_relation(); + m_plugin.reduce(m_join_fn, 2, m_args, res); + return alloc(external_relation, m_plugin, get_result_signature(), res); + } + }; + + relation_join_fn * external_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (!check_kind(r1) || !check_kind(r2)) { + return 0; + } + return alloc(join_fn, *this, r1.get_signature(), r2.get_signature() , col_cnt, cols1, cols2); + } + + + class external_relation_plugin::project_fn : public convenient_relation_project_fn { + external_relation_plugin& m_plugin; + func_decl_ref m_project_fn; + public: + project_fn(external_relation_plugin& p, sort* relation_sort, + const relation_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) + : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols), + m_plugin(p), + m_project_fn(p.get_ast_manager()) { + vector params; + ast_manager& m = p.get_ast_manager(); + family_id fid = p.get_family_id(); + for (unsigned i = 0; i < removed_col_cnt; ++i) { + params.push_back(parameter(removed_cols[i])); + } + m_project_fn = m.mk_func_decl(fid, OP_RA_PROJECT, params.size(), params.c_ptr(), 1, &relation_sort); + } + + virtual relation_base * operator()(const relation_base & r) { + expr_ref res(m_plugin.get_ast_manager()); + expr* rel = get(r).get_relation(); + m_plugin.reduce(m_project_fn, 1, &rel, res); + return alloc(external_relation, m_plugin, get_result_signature(), to_app(res)); + } + }; + + relation_transformer_fn * external_relation_plugin::mk_project_fn(const relation_base & r, + unsigned col_cnt, const unsigned * removed_cols) { + return alloc(project_fn, *this, get(r).get_sort(), r.get_signature(), col_cnt, removed_cols); + } + + + class external_relation_plugin::rename_fn : public convenient_relation_rename_fn { + external_relation_plugin& m_plugin; + func_decl_ref m_rename_fn; + expr* m_args[2]; + public: + rename_fn(external_relation_plugin& p, sort* relation_sort, const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(orig_sig, cycle_len, cycle), + m_plugin(p), + m_rename_fn(p.get_ast_manager()) { + + ast_manager& m = p.get_ast_manager(); + family_id fid = p.get_family_id(); + vector params; + for (unsigned i = 0; i < cycle_len; ++i) { + SASSERT(cycle[i] < orig_sig.size()); + params.push_back(parameter(cycle[i])); + } + m_rename_fn = m.mk_func_decl(fid, OP_RA_RENAME, params.size(), params.c_ptr(), 1, &relation_sort); + } + + virtual relation_base * operator()(const relation_base & r) { + expr* rel = get(r).get_relation(); + expr_ref res(m_plugin.get_ast_manager()); + m_args[0] = rel; + m_plugin.reduce(m_rename_fn, 1, &rel, res); + return alloc(external_relation, m_plugin, get_result_signature(), res); + } + }; + + relation_transformer_fn * external_relation_plugin::mk_rename_fn(const relation_base & r, + unsigned cycle_len, const unsigned * permutation_cycle) { + if(!check_kind(r)) { + return 0; + } + return alloc(rename_fn, *this, get(r).get_sort(), r.get_signature(), cycle_len, permutation_cycle); + } + + + class external_relation_plugin::union_fn : public relation_union_fn { + external_relation_plugin& m_plugin; + func_decl_ref m_union_fn; + expr* m_args[2]; + expr* m_outs[2]; + + public: + union_fn(external_relation_plugin& p, decl_kind k, sort* relation_sort): + m_plugin(p), + m_union_fn(p.get_ast_manager()) { + ast_manager& m = p.get_ast_manager(); + sort* domain[2] = { relation_sort, relation_sort }; + m_union_fn = m.mk_func_decl(p.get_family_id(), k, 0, 0, 2, domain); + } + + virtual void operator()(relation_base & r, const relation_base & src, relation_base * delta) { + ast_manager& m = m_plugin.get_ast_manager(); + expr_ref_vector res(m); + m_args[0] = get(r).get_relation(); + m_args[1] = get(src).get_relation(); + m_outs[0] = m_args[0]; + unsigned num_out = 1; + if (delta) { + m_outs[1] = get(*delta).get_relation(); + ++num_out; + } + m_plugin.reduce_assign(m_union_fn, 2, m_args, num_out, m_outs); + } + }; + + relation_union_fn * external_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { + return 0; + } + return alloc(union_fn, *this, OP_RA_UNION, get(src).get_sort()); + } + + relation_union_fn * external_relation_plugin::mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { + return 0; + } + return alloc(union_fn, *this, OP_RA_WIDEN, get(src).get_sort()); + } + + class external_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { + external_relation_plugin& m_plugin; + app_ref m_condition; + func_decl_ref m_filter_fn; + public: + filter_interpreted_fn(external_relation_plugin& p, sort* relation_sort, app * condition) + : 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)); + } + + virtual void operator()(relation_base & r) { + SASSERT(m_plugin.check_kind(r)); + expr* arg = get(r).get_relation(); + m_plugin.reduce_assign(m_filter_fn, 1, &arg, 1, &arg); + } + }; + + relation_mutator_fn * external_relation_plugin::mk_filter_interpreted_fn(const relation_base & r, app * condition) { + if(!check_kind(r)) { + return 0; + } + return alloc(filter_interpreted_fn, *this, get(r).get_sort(), condition); + } + + relation_mutator_fn * external_relation_plugin::mk_filter_equal_fn(const relation_base & r, + const relation_element & value, unsigned col) { + if(!check_kind(r)) { + return 0; + } + ast_manager& m = get_ast_manager(); + app_ref condition(m); + expr_ref var(m); + sort* relation_sort = get(r).get_sort(); + sort* column_sort = get_column_sort(col, relation_sort); + var = m.mk_var(col, column_sort); + condition = m.mk_eq(var, value); + return mk_filter_interpreted_fn(r, condition); + } + + class external_relation_plugin::filter_identical_fn : public relation_mutator_fn { + external_relation_plugin& m_plugin; + func_decl_ref_vector m_filter_fn; + public: + filter_identical_fn(external_relation_plugin& p, sort* relation_sort, + unsigned col_cnt, const unsigned * identical_cols) + : m_plugin(p), m_filter_fn(p.get_ast_manager()) { + ast_manager& m = p.get_ast_manager(); + func_decl_ref fn(m); + app_ref eq(m); + if (col_cnt <= 1) { + return; + } + unsigned col = identical_cols[0]; + sort* s = p.get_column_sort(col, relation_sort); + var* v0 = m.mk_var(col, s); + for (unsigned i = 1; i < col_cnt; ++i) { + col = identical_cols[i]; + s = p.get_column_sort(col, relation_sort); + eq = m.mk_eq(v0, m.mk_var(col, s)); + p.mk_filter_fn(relation_sort, eq.get(), fn); + m_filter_fn.push_back(fn); + } + } + + virtual void operator()(relation_base & r) { + expr* r0 = get(r).get_relation(); + for (unsigned i = 0; i < m_filter_fn.size(); ++i) { + m_plugin.reduce_assign(m_filter_fn[i].get(), 1, &r0, 1, &r0); + } + } + }; + + relation_mutator_fn * external_relation_plugin::mk_filter_identical_fn(const relation_base & r, + unsigned col_cnt, const unsigned * identical_cols) { + if (!check_kind(r)) { + return 0; + } + return alloc(filter_identical_fn, *this, get(r).get_sort(), col_cnt, identical_cols); + } + + + class external_relation_plugin::negation_filter_fn : public convenient_relation_negation_filter_fn { + external_relation_plugin& m_plugin; + func_decl_ref m_negated_filter_fn; + expr* m_args[2]; + public: + negation_filter_fn(external_relation_plugin& p, + const relation_base & tgt, const relation_base & neg_t, + unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) : + convenient_negation_filter_fn(tgt, neg_t, joined_col_cnt, t_cols, negated_cols), + m_plugin(p), + m_negated_filter_fn(p.get_ast_manager()) + { + ast_manager& m = p.get_ast_manager(); + family_id fid = p.get_family_id(); + vector params; + for (unsigned i = 0; i < joined_col_cnt; ++i) { + params.push_back(parameter(t_cols[i])); + params.push_back(parameter(negated_cols[i])); + } + sort* domain[2] = { get(tgt).get_sort(), get(neg_t).get_sort() }; + m_negated_filter_fn = m.mk_func_decl(fid, OP_RA_NEGATION_FILTER, params.size(), params.c_ptr(), 2, domain); + } + + void operator()(relation_base & t, const relation_base & negated_obj) { + m_args[0] = get(t).get_relation(); + m_args[1] = get(negated_obj).get_relation(); + m_plugin.reduce_assign(m_negated_filter_fn.get(), 2, m_args, 1, m_args); + } + }; + + relation_intersection_filter_fn * external_relation_plugin::mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) { + if (!check_kind(t) || !check_kind(negated_obj)) { + return 0; + } + return alloc(negation_filter_fn, *this, t, negated_obj, joined_col_cnt, t_cols, negated_cols); + } + +}; diff --git a/src/muz/rel/dl_external_relation.h b/src/muz/rel/dl_external_relation.h new file mode 100644 index 000000000..03838ecc4 --- /dev/null +++ b/src/muz/rel/dl_external_relation.h @@ -0,0 +1,154 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + dl_external_relation.h + +Abstract: + + + +Author: + + Nikolaj Bjorner (nbjorner) 2010-05-10 + +Revision History: + +--*/ +#ifndef _DL_EXTERNAL_RELATION_H_ +#define _DL_EXTERNAL_RELATION_H_ + +#include "dl_base.h" + +namespace datalog { + + class external_relation; + + class external_relation_context { + public: + virtual ~external_relation_context() {} + + virtual family_id get_family_id() const = 0; + + // reduce arguments. + virtual void reduce(func_decl* f, unsigned num_args, expr * const* args, expr_ref& result) = 0; + + // overwrite terms passed in outs vector with values computed by function. + virtual void reduce_assign(func_decl* f, unsigned num_args, expr * const* args, unsigned num_out, expr* const* outs) = 0; + }; + + class external_relation_plugin : public relation_plugin { + + friend class external_relation; + class join_fn; + class project_fn; + class rename_fn; + class union_fn; + class filter_identical_fn; + class filter_interpreted_fn; + class negation_filter_fn; + + external_relation_context& m_ext; + + public: + external_relation_plugin(external_relation_context& ctx, relation_manager & m); + + virtual bool can_handle_signature(const relation_signature & s) { return true; } + + static symbol get_name() { return symbol("external_relation"); } + + virtual relation_base * mk_empty(const relation_signature & s); + + virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols); + + private: + + static external_relation& get(relation_base& r); + static external_relation const & get(relation_base const& r); + + void reduce(func_decl* f, unsigned num_args, expr * const* args, expr_ref& result) { + m_ext.reduce(f, num_args, args, result); + } + + void reduce_assign(func_decl* f, unsigned num_args, expr * const* args, unsigned num_out, expr* const* outs) { + m_ext.reduce_assign(f, num_args, args, num_out, outs); + } + + sort* get_relation_sort(relation_signature const& sig); + + sort* get_column_sort(unsigned col, sort* relation_sort); + + void mk_filter_fn(sort* s, app* condition, func_decl_ref& f); + + family_id get_family_id(); + }; + + class external_relation : public relation_base { + friend class external_relation_plugin; + friend class external_relation_plugin::join_fn; + friend class external_relation_plugin::project_fn; + friend class external_relation_plugin::rename_fn; + friend class external_relation_plugin::union_fn; + friend class external_relation_plugin::filter_identical_fn; + friend class external_relation_plugin::filter_interpreted_fn; + friend class external_relation_plugin::negation_filter_fn; + + expr_ref m_rel; + func_decl_ref m_select_fn; + func_decl_ref m_store_fn; + func_decl_ref m_is_empty_fn; + + unsigned size() const { return get_signature().size(); } + + sort* get_sort() const { return m_rel.get_manager().get_sort(m_rel); } + + void mk_accessor(decl_kind k, func_decl_ref& fn, const relation_fact& f, bool destructive, expr_ref& res) const; + + external_relation(external_relation_plugin & p, const relation_signature & s, expr* r); + virtual ~external_relation(); + + public: + external_relation_plugin & get_plugin() const; + + virtual bool empty() const; + + virtual void add_fact(const relation_fact & f); + + virtual bool contains_fact(const relation_fact & f) const; + + virtual external_relation * clone() const; + + virtual external_relation * complement(func_decl*) const; + + virtual void display(std::ostream & out) const; + + virtual void display_tuples(func_decl & pred, std::ostream & out) const; + + expr* get_relation() const { return m_rel.get(); } + + virtual void to_formula(expr_ref& fml) const { fml = get_relation(); } + + }; + + +}; + +#endif diff --git a/src/muz/rel/dl_finite_product_relation.cpp b/src/muz/rel/dl_finite_product_relation.cpp new file mode 100644 index 000000000..86fef433b --- /dev/null +++ b/src/muz/rel/dl_finite_product_relation.cpp @@ -0,0 +1,2377 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_finite_product_relation.cpp + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-14. + +Revision History: + +--*/ + + +#include +#include"dl_context.h" +#include"dl_relation_manager.h" +#include"dl_table_relation.h" +#include"dl_finite_product_relation.h" +#include"bool_rewriter.h" + +namespace datalog { + + //static variables + + const table_sort finite_product_relation::s_rel_idx_sort = INT_MAX; + + void universal_delete(finite_product_relation* ptr) { + ptr->deallocate(); + } + + + // ----------------------------------- + // + // finite_product_relation_plugin + // + // ----------------------------------- + + finite_product_relation & finite_product_relation_plugin::get(relation_base & r) { + SASSERT(r.get_plugin().is_finite_product_relation()); + return static_cast(r); + } + + const finite_product_relation & finite_product_relation_plugin::get(const relation_base & r) { + SASSERT(r.get_plugin().is_finite_product_relation()); + return static_cast(r); + } + + finite_product_relation * finite_product_relation_plugin::get(relation_base * r) { + SASSERT(!r || r->get_plugin().is_finite_product_relation()); + return static_cast(r); + } + + const finite_product_relation * finite_product_relation_plugin::get(const relation_base * r) { + SASSERT(!r || r->get_plugin().is_finite_product_relation()); + return static_cast(r); + } + + symbol finite_product_relation_plugin::get_name(relation_plugin & inner_plugin) { + std::string str = std::string("fpr_")+inner_plugin.get_name().bare_str(); + return symbol(str.c_str()); + } + + finite_product_relation_plugin & finite_product_relation_plugin::get_plugin(relation_manager & rmgr, + relation_plugin & inner) { + finite_product_relation_plugin * res; + if(!rmgr.try_get_finite_product_relation_plugin(inner, res)) { + res = alloc(finite_product_relation_plugin, inner, rmgr); + rmgr.register_plugin(res); + } + return *res; + } + + finite_product_relation_plugin::finite_product_relation_plugin(relation_plugin & inner_plugin, + relation_manager & manager) + : relation_plugin(get_name(inner_plugin), manager, ST_FINITE_PRODUCT_RELATION), + m_inner_plugin(inner_plugin), m_spec_store(*this) { + } + + void finite_product_relation_plugin::initialize(family_id fid) { + relation_plugin::initialize(fid); + m_spec_store.add_available_kind(get_kind()); + } + + family_id finite_product_relation_plugin::get_relation_kind(finite_product_relation & r, + const bool * table_columns) { + const relation_signature & sig = r.get_signature(); + svector table_cols_vect(sig.size(), table_columns); + return m_spec_store.get_relation_kind(sig, rel_spec(table_cols_vect)); + } + + void finite_product_relation_plugin::get_all_possible_table_columns(relation_manager & rmgr, + const relation_signature & s, svector & table_columns) { + SASSERT(table_columns.empty()); + unsigned s_sz = s.size(); + for(unsigned i=0; i table_columns; + get_all_possible_table_columns(s, table_columns); +#ifndef _EXTERNAL_RELEASE + unsigned s_sz = s.size(); + unsigned rel_col_cnt = 0; + for(unsigned i=0; icomplement_self(p); + return res; + } + + bool finite_product_relation_plugin::can_convert_to_table_relation(const finite_product_relation & r) { + return r.m_other_sig.empty(); + } + + table_relation * finite_product_relation_plugin::to_table_relation(const finite_product_relation & r) { + SASSERT(can_convert_to_table_relation(r)); + r.garbage_collect(true); + //now all rows in the table will correspond to rows in the resulting table_relation + + const table_base & t = r.get_table(); + + unsigned removed_col = t.get_signature().size()-1; + scoped_ptr project_fun = + get_manager().mk_project_fn(r.get_table(), 1, &removed_col); + + table_base * res_table = (*project_fun)(t); + SASSERT(res_table->get_signature().functional_columns()==0); + return static_cast(get_manager().mk_table_relation(r.get_signature(), res_table)); + } + + + bool finite_product_relation_plugin::can_be_converted(const relation_base & r) { + if(&r.get_plugin()==&get_inner_plugin()) { + //can be converted by mk_from_inner_relation + return true; + } + if(r.from_table()) { + //We can convert directly from table plugin only if the inner plugin can handle empty signatures. + + //TODO: If the inner plugin cannot handle empty signatures, we may try to move some of the + //table columns into the inner relation signature. + return get_inner_plugin().can_handle_signature(relation_signature()); + } + return false; + } + + finite_product_relation * finite_product_relation_plugin::mk_from_table_relation(const table_relation & r) { + func_decl* pred = 0; + const relation_signature & sig = r.get_signature(); + const table_base & t = r.get_table(); + table_plugin & tplugin = r.get_table().get_plugin(); + + relation_signature inner_sig; //empty signature for the inner relation + if(!get_inner_plugin().can_handle_signature(inner_sig)) { + return 0; + } + + table_signature idx_singleton_sig; + idx_singleton_sig.push_back(finite_product_relation::s_rel_idx_sort); + idx_singleton_sig.set_functional_columns(1); + + scoped_rel idx_singleton; + if(tplugin.can_handle_signature(idx_singleton_sig)) { + idx_singleton = tplugin.mk_empty(idx_singleton_sig); + } + else { + idx_singleton = get_manager().mk_empty_table(idx_singleton_sig); + } + table_fact idx_singleton_fact; + idx_singleton_fact.push_back(0); + idx_singleton->add_fact(idx_singleton_fact); + + scoped_ptr join_fun = get_manager().mk_join_fn(t, *idx_singleton, 0, 0, 0); + SASSERT(join_fun); + scoped_rel res_table = (*join_fun)(t, *idx_singleton); + + svector table_cols(sig.size(), true); + finite_product_relation * res = mk_empty(sig, table_cols.c_ptr()); + + //this one does not need to be deleted -- it will be taken over by \c res in the \c init function + relation_base * inner_rel = get_inner_plugin().mk_full(pred, inner_sig, get_inner_plugin().get_kind()); + + relation_vector rels; + rels.push_back(inner_rel); + + res->init(*res_table, rels, true); + return res; + } + + finite_product_relation * finite_product_relation_plugin::mk_from_inner_relation(const relation_base & r) { + SASSERT(&r.get_plugin()==&get_inner_plugin()); + const relation_signature & sig = r.get_signature(); + + table_signature idx_singleton_sig; + idx_singleton_sig.push_back(finite_product_relation::s_rel_idx_sort); + idx_singleton_sig.set_functional_columns(1); + + scoped_rel idx_singleton = get_manager().mk_empty_table(idx_singleton_sig); + table_fact idx_singleton_fact; + idx_singleton_fact.push_back(0); + idx_singleton->add_fact(idx_singleton_fact); + + svector table_cols(sig.size(), false); + finite_product_relation * res = mk_empty(sig, table_cols.c_ptr()); + + relation_vector rels; + rels.push_back(r.clone()); + + res->init(*idx_singleton, rels, true); + return res; + } + + class finite_product_relation_plugin::converting_join_fn : public convenient_relation_join_fn { + finite_product_relation_plugin & m_plugin; + scoped_ptr m_native_join; + + finite_product_relation * convert(const relation_base & r) { + SASSERT(&r.get_plugin()!=&m_plugin); + if(&r.get_plugin()==&m_plugin.get_inner_plugin()) { + return m_plugin.mk_from_inner_relation(r); + } + SASSERT(r.from_table()); + const table_relation & tr = static_cast(r); + finite_product_relation * res = m_plugin.mk_from_table_relation(tr); + SASSERT(res); + return res; + } + + public: + converting_join_fn(finite_product_relation_plugin & plugin, const relation_signature & sig1, + const relation_signature & sig2, unsigned col_cnt, const unsigned * cols1, + const unsigned * cols2) + : convenient_relation_join_fn(sig1, sig2, col_cnt, cols1, cols2), + m_plugin(plugin) {} + + virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + scoped_rel r1_conv; + if(&r1.get_plugin()!=&m_plugin) { + r1_conv = convert(r1); + } + scoped_rel r2_conv; + if(&r2.get_plugin()!=&m_plugin) { + r2_conv = convert(r2); + } + + const finite_product_relation & fpr1 = r1_conv ? *r1_conv : get(r1); + const finite_product_relation & fpr2 = r2_conv ? *r2_conv : get(r2); + + SASSERT(&fpr1.get_plugin()==&m_plugin); + SASSERT(&fpr2.get_plugin()==&m_plugin); + + if(!m_native_join) { + m_native_join = m_plugin.get_manager().mk_join_fn(fpr1, fpr2, m_cols1, m_cols2, false); + } + return (*m_native_join)(fpr1, fpr2); + } + }; + + + class finite_product_relation_plugin::join_fn : public convenient_relation_join_fn { + scoped_ptr m_tjoin_fn; + scoped_ptr m_rjoin_fn; + + unsigned_vector m_t_joined_cols1; + unsigned_vector m_t_joined_cols2; + unsigned_vector m_r_joined_cols1; + unsigned_vector m_r_joined_cols2; + + //Column equalities betweet table and inner relations. + //The columns numbers correspont to the columns of the table/inner relation + //in the result of the join operation + unsigned_vector m_tr_table_joined_cols; + unsigned_vector m_tr_rel_joined_cols; + + scoped_ptr m_filter_tr_identities; + + scoped_ptr m_tjoined_second_rel_remover; + + //determines which columns of the result are table columns and which are in the inner relation + svector m_res_table_columns; + + public: + class join_maker : public table_row_mutator_fn { + join_fn & m_parent; + const finite_product_relation & m_r1; + const finite_product_relation & m_r2; + relation_vector & m_rjoins; + public: + join_maker(join_fn & parent, const finite_product_relation & r1, const finite_product_relation & r2, + relation_vector & rjoins) + : m_parent(parent), m_r1(r1), m_r2(r2), m_rjoins(rjoins) {} + + virtual bool operator()(table_element * func_columns) { + const relation_base & or1 = m_r1.get_inner_rel(func_columns[0]); + const relation_base & or2 = m_r2.get_inner_rel(func_columns[1]); + SASSERT(&or1); + SASSERT(&or2); + unsigned new_rel_num = m_rjoins.size(); + m_rjoins.push_back(m_parent.do_rjoin(or1, or2)); + func_columns[0]=new_rel_num; + return true; + } + }; + + join_fn(const finite_product_relation & r1, const finite_product_relation & r2, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_relation_join_fn(r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2) { + unsigned second_table_after_join_ofs = r1.m_table2sig.size(); + unsigned second_inner_rel_after_join_ofs = r1.m_other2sig.size(); + for(unsigned i=0;i tjoined = (*m_tjoin_fn)(r1.get_table(), r2.get_table()); + + relation_vector joined_orelations; + + { + join_maker * mutator = alloc(join_maker, *this, r1, r2, joined_orelations); //dealocated in inner_join_mapper + scoped_ptr inner_join_mapper = rmgr.mk_map_fn(*tjoined, mutator); + (*inner_join_mapper)(*tjoined); + } + + + if(!m_tjoined_second_rel_remover) { + unsigned removed_col = tjoined->get_signature().size()-1; + m_tjoined_second_rel_remover = rmgr.mk_project_fn(*tjoined, 1, &removed_col); + } + //remove the second functional column from tjoined to get a table that corresponds + //to the table signature of the resulting relation + scoped_rel res_table = (*m_tjoined_second_rel_remover)(*tjoined); + + relation_plugin & res_oplugin = + joined_orelations.empty() ? r1.m_other_plugin : joined_orelations.back()->get_plugin(); + + //TODO: Maybe we might want to specify a particular relation kind, instead of just null_family_id. + //It would however need to be somehow inferred for the new signature. + + finite_product_relation * res = alloc(finite_product_relation, r1.get_plugin(), get_result_signature(), + m_res_table_columns.c_ptr(), res_table->get_plugin(), res_oplugin, null_family_id); + + res->init(*res_table, joined_orelations, true); + + if(m_tr_table_joined_cols.size()) { + //There were some shared variables between the table and the relation part. + //We enforce those equalities here. + if(!m_filter_tr_identities) { + m_filter_tr_identities = plugin.mk_filter_identical_pairs(*res, m_tr_table_joined_cols.size(), + m_tr_table_joined_cols.c_ptr(), m_tr_rel_joined_cols.c_ptr()); + SASSERT(m_filter_tr_identities); + } + (*m_filter_tr_identities)(*res); + } + return res; + } + }; + + + + + relation_join_fn * finite_product_relation_plugin::mk_join_fn(const relation_base & rb1, const relation_base & rb2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if(!check_kind(rb1) || !check_kind(rb2)) { + bool r1foreign = &rb1.get_plugin()!=this; + bool r2foreign = &rb2.get_plugin()!=this; + if( (!r1foreign || can_be_converted(rb1)) && (!r2foreign || can_be_converted(rb2))) { + return alloc(converting_join_fn, *this, rb1.get_signature(), rb2.get_signature(), col_cnt, cols1, + cols2); + } + return 0; + } + const finite_product_relation & r1 = get(rb1); + const finite_product_relation & r2 = get(rb2); + + return alloc(join_fn, r1, r2, col_cnt, cols1, cols2); + } + + + class finite_product_relation_plugin::project_fn : public convenient_relation_project_fn { + unsigned_vector m_removed_table_cols; + unsigned_vector m_removed_rel_cols; + + scoped_ptr m_rel_projector; + scoped_ptr m_inner_rel_union; + + //determines which columns of the result are table columns and which are in the inner relation + svector m_res_table_columns; + public: + project_fn(const finite_product_relation & r, unsigned col_cnt, const unsigned * removed_cols) + : convenient_relation_project_fn(r.get_signature(), col_cnt, removed_cols) { + SASSERT(col_cnt>0); + for(unsigned i=0; ii); + m_res_table_columns.push_back(r.is_table_column(i)); + } + } + + class project_reducer : public table_row_pair_reduce_fn { + project_fn & m_parent; + relation_vector & m_relations; + public: + + project_reducer(project_fn & parent, relation_vector & relations) + : m_parent(parent), m_relations(relations) {} + + virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) { + relation_base * tgt = m_relations[static_cast(func_columns[0])]->clone(); + relation_base & src = *m_relations[static_cast(merged_func_columns[0])]; + if(!m_parent.m_inner_rel_union) { + m_parent.m_inner_rel_union = tgt->get_manager().mk_union_fn(*tgt, src); + } + (*m_parent.m_inner_rel_union)(*tgt, src); + + unsigned new_idx = m_relations.size(); + m_relations.push_back(tgt); + func_columns[0] = new_idx; + } + }; + + virtual relation_base * operator()(const relation_base & rb) { + const finite_product_relation & r = get(rb); + finite_product_relation_plugin & plugin = r.get_plugin(); + const table_base & rtable = r.get_table(); + relation_manager & rmgr = plugin.get_manager(); + + r.garbage_collect(false); + relation_vector res_relations; + unsigned orig_rel_cnt = r.m_others.size(); + for(unsigned i=0; iclone() : 0); + } + SASSERT(res_relations.size()==orig_rel_cnt); + + bool shared_res_table = false; + const table_base * res_table; + + if(m_removed_table_cols.empty()) { + shared_res_table = true; + res_table = &rtable; + } + else { + project_reducer * preducer = alloc(project_reducer, *this, res_relations); + scoped_ptr tproject = + rmgr.mk_project_with_reduce_fn(rtable, m_removed_table_cols.size(), m_removed_table_cols.c_ptr(), preducer); + res_table = (*tproject)(rtable); + } + + relation_plugin * res_oplugin = 0; + + if(!m_removed_rel_cols.empty()) { + unsigned res_rel_cnt = res_relations.size(); + for(unsigned i=0; ideallocate(); + if(!res_oplugin) { + res_oplugin = &res_relations[i]->get_plugin(); + } + } + } + + if(!res_oplugin) { + res_oplugin = &r.m_other_plugin; + } + + //TODO: Maybe we might want to specify a particular relation kind, instead of just null_family_id. + //It would however need to be somehow inferred for the new signature. + + finite_product_relation * res = alloc(finite_product_relation, r.get_plugin(), get_result_signature(), + m_res_table_columns.c_ptr(), res_table->get_plugin(), *res_oplugin, null_family_id); + + res->init(*res_table, res_relations, false); + + if(!shared_res_table) { + const_cast(res_table)->deallocate(); + } + + return res; + } + }; + + relation_transformer_fn * finite_product_relation_plugin::mk_project_fn(const relation_base & rb, unsigned col_cnt, + const unsigned * removed_cols) { + if(&rb.get_plugin()!=this) { + return 0; + } + return alloc(project_fn, get(rb), col_cnt, removed_cols); + } + + + + class finite_product_relation_plugin::rename_fn : public convenient_relation_rename_fn { + scoped_ptr m_table_renamer; + scoped_ptr m_rel_renamer; + bool m_rel_identity; + + unsigned_vector m_rel_permutation; + + //determines which columns of the result are table columns and which are in the inner relation + svector m_res_table_columns; + public: + rename_fn(const finite_product_relation & r, unsigned cycle_len, const unsigned * permutation_cycle) + : convenient_relation_rename_fn(r.get_signature(), cycle_len, permutation_cycle) { + SASSERT(cycle_len>1); + + unsigned sig_sz = r.get_signature().size(); + unsigned_vector permutation; + add_sequence(0, sig_sz, permutation); + permutate_by_cycle(permutation, cycle_len, permutation_cycle); + + unsigned_vector table_permutation; + + bool table_identity = true; + m_rel_identity = true; + for(unsigned new_i=0; new_iclone() : 0); + } + + if(!m_rel_identity) { + unsigned res_rel_cnt = res_relations.size(); + for(unsigned i=0; i inner_rel = res_relations[i]; + if(!m_rel_renamer) { + m_rel_renamer = r.get_manager().mk_permutation_rename_fn(*inner_rel, m_rel_permutation); + } + + res_relations[i] = (*m_rel_renamer)(*inner_rel); + } + } + scoped_rel res_table_scoped; + const table_base * res_table = &rtable; + + if(m_table_renamer) { + res_table_scoped = (*m_table_renamer)(*res_table); + res_table = res_table_scoped.get(); + } + + //TODO: Maybe we might want to specify a particular relation kind, instead of just null_family_id. + //It would however need to be somehow inferred for the new signature. + + finite_product_relation * res = alloc(finite_product_relation, r.get_plugin(), get_result_signature(), + m_res_table_columns.c_ptr(), res_table->get_plugin(), r.m_other_plugin, null_family_id); + + res->init(*res_table, res_relations, false); + + return res; + } + }; + + relation_transformer_fn * finite_product_relation_plugin::mk_rename_fn(const relation_base & rb, + unsigned permutation_cycle_len, const unsigned * permutation_cycle) { + + if(&rb.get_plugin()!=this) { + return 0; + } + const finite_product_relation & r = get(rb); + return alloc(rename_fn, r, permutation_cycle_len, permutation_cycle); + } + + + class finite_product_relation_plugin::union_fn : public relation_union_fn { + bool m_use_delta; + unsigned_vector m_data_cols;//non-functional columns in the product-relation table (useful for creating operations) + scoped_ptr m_common_join; //result of the join contains (data columns), tgt_rel_idx, src_rel_idx + scoped_ptr m_rel_union; + scoped_ptr m_table_union; + scoped_ptr m_remove_overlaps; + scoped_ptr m_remove_src_column_from_overlap; + + //this one is populated only if we're doing union with delta + scoped_ptr m_delta_merging_union; + + scoped_ptr m_overlap_delta_table_builder; + public: + union_fn(const finite_product_relation & tgt, bool use_delta) : m_use_delta(use_delta) {} + + relation_union_fn & get_inner_rel_union_op(relation_base & r) { + if(!m_rel_union) { + m_rel_union = r.get_manager().mk_union_fn(r, r, m_use_delta ? &r : 0); + } + return *m_rel_union; + } + + class union_mapper : public table_row_mutator_fn { + union_fn & m_parent; + finite_product_relation & m_tgt; + const finite_product_relation & m_src; + table_base * m_delta_indexes; //table with signature (updated tgt rel index, delta_index in m_delta_rels) + relation_vector * m_delta_rels; + table_fact m_di_fact; //auxiliary fact for inserting into \c m_delta_indexes + public: + /** + If \c delta_indexes is 0, it means we are not collecting indexes. + */ + union_mapper(union_fn & parent, finite_product_relation & tgt, const finite_product_relation & src, + table_base * delta_indexes, relation_vector * delta_rels) + : m_parent(parent), + m_tgt(tgt), + m_src(src), + m_delta_indexes(delta_indexes), + m_delta_rels(delta_rels) {} + + virtual ~union_mapper() {} + + virtual bool operator()(table_element * func_columns) { + relation_base & otgt_orig = m_tgt.get_inner_rel(func_columns[0]); + const relation_base & osrc = m_src.get_inner_rel(func_columns[1]); + + relation_base * otgt = otgt_orig.clone(); + unsigned new_tgt_idx = m_tgt.get_next_rel_idx(); + m_tgt.set_inner_rel(new_tgt_idx, otgt); + if(m_delta_indexes) { + relation_base * odelta = otgt->get_plugin().mk_empty(otgt->get_signature()); + m_parent.get_inner_rel_union_op(*otgt)(*otgt, osrc, odelta); + + unsigned delta_idx = m_delta_rels->size(); + m_delta_rels->push_back(odelta); + m_di_fact.reset(); + m_di_fact.push_back(new_tgt_idx); + m_di_fact.push_back(delta_idx); + m_delta_indexes->add_fact(m_di_fact); + } + else { + m_parent.get_inner_rel_union_op(*otgt)(*otgt, osrc); + } + + func_columns[0]=new_tgt_idx; + return true; + } + }; + + /** + Makes a table whose last column has indexes to relations in \c src into a table + with indexes to relation \c tgt. + */ + class src_copying_mapper : public table_row_mutator_fn { + finite_product_relation & m_tgt; + const finite_product_relation & m_src; + public: + /** + If \c delta_indexes is 0, it means we are not collecting indexes. + */ + src_copying_mapper(finite_product_relation & tgt, const finite_product_relation & src) + : m_tgt(tgt), m_src(src) {} + + virtual bool operator()(table_element * func_columns) { + const relation_base & osrc = m_src.get_inner_rel(func_columns[0]); + unsigned new_tgt_idx = m_tgt.get_next_rel_idx(); + m_tgt.set_inner_rel(new_tgt_idx, osrc.clone()); + func_columns[0]=new_tgt_idx; + return true; + } + }; + + virtual void operator()(relation_base & tgtb, const relation_base & srcb, relation_base * deltab) { + finite_product_relation & tgt = get(tgtb); + const finite_product_relation & src0 = get(srcb); + finite_product_relation * delta = get(deltab); + + relation_manager & rmgr = tgt.get_manager(); + + scoped_rel src_aux_copy; //copy of src in case its specification needs to be modified + + if(!vectors_equal(tgt.m_table2sig, src0.m_table2sig) + || (delta && !vectors_equal(tgt.m_table2sig, delta->m_table2sig)) ) { + src_aux_copy = src0.clone(); + ptr_vector orig_rels; + orig_rels.push_back(src_aux_copy.get()); + orig_rels.push_back(&tgt); + if(delta) { + orig_rels.push_back(delta); + } + if(!finite_product_relation::try_unify_specifications(orig_rels)) { + throw default_exception("finite_product_relation union: cannot convert relations to common specification"); + } + } + + const finite_product_relation & src = src_aux_copy ? *src_aux_copy : src0; + + table_plugin & tplugin = tgt.get_table_plugin(); + + if(!m_common_join) { + unsigned data_cols_cnt = tgt.m_table_sig.size()-1; + for(unsigned i=0; i table_overlap = (*m_common_join)(tgt.get_table(), src.get_table()); + + scoped_rel delta_indexes; + relation_vector delta_rels; + if(m_use_delta) { + table_signature di_sig; + di_sig.push_back(finite_product_relation::s_rel_idx_sort); + di_sig.push_back(finite_product_relation::s_rel_idx_sort); + di_sig.set_functional_columns(1); + delta_indexes = tplugin.mk_empty(di_sig); + } + + { + union_mapper * umapper = alloc(union_mapper, *this, tgt, src, delta_indexes.get(), &delta_rels); + scoped_ptr mapping_fn = rmgr.mk_map_fn(*table_overlap, umapper); + (*mapping_fn)(*table_overlap); + } + + if(!m_remove_src_column_from_overlap) { + unsigned removed_cols[] = { table_overlap->get_signature().size()-1 }; + m_remove_src_column_from_overlap = rmgr.mk_project_fn(*table_overlap, 1, removed_cols); + } + //transform table_overlap into the signature of tgt.get_table(), so that the functional + //column contains indexes of the united relations + scoped_rel regular_overlap = (*m_remove_src_column_from_overlap)(*table_overlap); + + + if(!m_remove_overlaps) { + m_remove_overlaps = rmgr.mk_filter_by_negation_fn(tgt.get_table(), *regular_overlap, m_data_cols, + m_data_cols); + } + + //in tgt keep only the rows that are in tgt only + (*m_remove_overlaps)(tgt.get_table(), *regular_overlap); + + //add rows in which tgt and src overlapped + if(!m_table_union) { + m_table_union = rmgr.mk_union_fn(tgt.get_table(), tgt.get_table()); + } + (*m_table_union)(tgt.get_table(), *regular_overlap); + + scoped_rel src_only = src.get_table().clone(); + (*m_remove_overlaps)(*src_only, *regular_overlap); + + scoped_rel src_only2; //a copy of src_only for use in building the delta + if(m_use_delta) { + src_only2 = src_only->clone(); + } + + { + src_copying_mapper * cpmapper = alloc(src_copying_mapper, tgt, src); + scoped_ptr mapping_fn = rmgr.mk_map_fn(*src_only, cpmapper); + (*mapping_fn)(*src_only); + } + + //add rows that were only in src + (*m_table_union)(tgt.get_table(), *src_only); + + if(m_use_delta) { + bool extending_delta = !delta->empty(); + //current delta, we will add it to the deltab argument later if it was not given to us empty + finite_product_relation * cdelta; + if(extending_delta) { + cdelta = delta->get_plugin().mk_empty(*delta); + } + else { + cdelta = delta; + } + + if(!m_overlap_delta_table_builder) { + unsigned table_fn_col = regular_overlap->get_signature().size()-1; + unsigned first_col = 0; + unsigned removed_cols[] = { table_fn_col, table_fn_col+1 }; + m_overlap_delta_table_builder = rmgr.mk_join_project_fn(*regular_overlap, *delta_indexes, 1, + &table_fn_col, &first_col, 2, removed_cols); + } + + scoped_rel overlap_delta_table = + (*m_overlap_delta_table_builder)(*regular_overlap, *delta_indexes); + + cdelta->init(*overlap_delta_table, delta_rels, true); + + { + src_copying_mapper * cpmapper = alloc(src_copying_mapper, *cdelta, src); + scoped_ptr mapping_fn = rmgr.mk_map_fn(*src_only2, cpmapper); + (*mapping_fn)(*src_only2); + } + + //add rows that were only in src + (*m_table_union)(cdelta->get_table(), *src_only2); + + if(extending_delta) { + if(!m_delta_merging_union) { + m_delta_merging_union = rmgr.mk_union_fn(*delta, *cdelta); + } + (*m_delta_merging_union)(*delta, *cdelta); + cdelta->deallocate(); + } + } + } + }; + +#if 0 + /** + Union operation taking advantage of the fact that the inner relation of all the arguments + is a singleton relation. + */ + class finite_product_relation_plugin::inner_singleton_union_fn : public relation_union_fn { + + class offset_row_mapper : public table_row_mutator_fn { + public: + unsigned m_ofs; + virtual bool operator()(table_element * func_columns) { + func_columns[0] += m_ofs; + return true; + } + }; + + // [Leo]: gcc complained about the following class. + // It does not have a constructor and uses a reference + + class inner_relation_copier : public table_row_mutator_fn { + finite_product_relation & m_tgt; + const finite_product_relation & m_src; + finite_product_relation * m_delta; + unsigned m_tgt_ofs; + unsigned m_delta_ofs; + public: + virtual bool operator()(table_element * func_columns) { + unsigned src_idx = static_cast(func_columns[0]); + unsigned tgt_idx = src_idx + m_tgt_ofs; + unsigned delta_idx = m_delta ? (src_idx + m_delta_ofs) : 0; + SASSERT(!m_delta || m_tgt.m_others[tgt_idx]==m_delta->m_others[delta_idx]); + SASSERT(m_tgt.m_others[tgt_idx]==0 || m_tgt.m_others[tgt_idx]==m_src.m_others[src_idx]); + if(m_tgt.m_others[tgt_idx]==0) { + m_tgt.m_others[tgt_idx] = m_src.m_others[src_idx]->clone(); + if(m_delta) { + m_delta->m_others[delta_idx] = m_src.m_others[src_idx]->clone(); + } + } + return true; + } + }; + + scoped_ptr m_t_union_fun; + offset_row_mapper * m_offset_mapper_obj; //initialized together with m_offset_mapper_fun, and deallocated by it + scoped_ptr m_offset_mapper_fun; + + + + public: + virtual void operator()(relation_base & tgtb, const relation_base & srcb, relation_base * deltab) { + finite_product_relation & tgt = get(tgtb); + const finite_product_relation & src = get(srcb); + finite_product_relation * delta = get(deltab); + + finite_product_relation_plugin & plugin = tgt.get_plugin(); + relation_manager & rmgr = plugin.get_manager(); + + //we want only non-empty inner relations to remain + tgt.garbage_collect(true); + src.garbage_collect(true); + + table_base & tgt_table = tgt.get_table(); + const table_base & src_table = src.get_table(); + + scoped_rel offsetted_src = src_table.clone(); + + if(!m_offset_mapper_fun) { + m_offset_mapper_obj = alloc(offset_row_mapper); + m_offset_mapper_fun = rmgr.mk_map_fn(*offsetted_src, m_offset_mapper_obj); + } + unsigned src_rel_offset = tgt.m_others.size(); + m_offset_mapper_obj->m_ofs = src_rel_offset; + + (*m_offset_mapper_fun)(*offsetted_src); + + //if we need to generate a delta, we get collect it into an empty relation and then union + //it with the delta passed in as argument. + scoped_rel loc_delta = delta ? get(plugin.mk_empty(*delta)) : 0; + //even if we don't need to generate the delta for the caller, we still want to have a delta + //table to know which relations to copy. + scoped_rel loc_delta_table_scoped; + if(!loc_delta) { + loc_delta_table_scoped = tgt_table.get_plugin().mk_empty(tgt_table); + } + table_base * loc_delta_table = loc_delta ? &loc_delta->get_table() : loc_delta_table_scoped.get(); + + if(!m_t_union_fun) { + m_t_union_fun = rmgr.mk_union_fn(tgt_table, *offsetted_src, loc_delta_table); + } + (*m_t_union_fun)(tgt_table, *offsetted_src, loc_delta_table); + + + //TODO: copy the relations into tgt and (possibly) delta using inner_relation_copier + //TODO: unite the local delta with the delta passed in as an argument + NOT_IMPLEMENTED_YET(); + } + }; +#endif + + class finite_product_relation_plugin::converting_union_fn : public relation_union_fn { + scoped_ptr m_tr_union_fun; + public: + virtual void operator()(relation_base & tgtb, const relation_base & srcb, relation_base * deltab) { + SASSERT(srcb.get_plugin().is_finite_product_relation()); + const finite_product_relation & src = get(srcb); + finite_product_relation_plugin & plugin = src.get_plugin(); + scoped_rel tr_src = plugin.to_table_relation(src); + if(!m_tr_union_fun) { + m_tr_union_fun = plugin.get_manager().mk_union_fn(tgtb, *tr_src, deltab); + SASSERT(m_tr_union_fun); + } + (*m_tr_union_fun)(tgtb, *tr_src, deltab); + } + }; + + relation_union_fn * finite_product_relation_plugin::mk_union_fn(const relation_base & tgtb, const relation_base & srcb, + const relation_base * deltab) { + if(&srcb.get_plugin()!=this) { + return 0; + } + const finite_product_relation & src = get(srcb); + if(&tgtb.get_plugin()!=this || (deltab && &deltab->get_plugin()!=this) ) { + if(can_convert_to_table_relation(src)) { + return alloc(converting_union_fn); + } + return 0; + } + + const finite_product_relation * delta = get(deltab); + + return alloc(union_fn, get(tgtb), delta!=0); + } + + + class finite_product_relation_plugin::filter_identical_fn : public relation_mutator_fn { + //the table and relation columns that should be identical + //the column numbering is local to the table or inner relation + unsigned_vector m_table_cols; + unsigned_vector m_rel_cols; + + scoped_ptr m_table_filter; + scoped_ptr m_rel_filter; + scoped_ptr m_tr_filter; + public: + filter_identical_fn(const finite_product_relation & r, unsigned col_cnt, const unsigned * identical_cols) + : m_table_filter(0), m_rel_filter(0), m_tr_filter(0) { + finite_product_relation_plugin & plugin = r.get_plugin(); + for(unsigned i=0; i1) { + m_table_filter = r.get_manager().mk_filter_identical_fn(r.get_table(), m_table_cols.size(), + m_table_cols.c_ptr()); + SASSERT(m_table_filter); + } + if(!m_table_cols.empty() && !m_rel_cols.empty()) { + unsigned tr_filter_table_cols[] = { m_table_cols[0] }; + unsigned tr_filter_rel_cols[] = { m_rel_cols[0] }; + m_tr_filter = plugin.mk_filter_identical_pairs(r, 1, tr_filter_table_cols, tr_filter_rel_cols); + SASSERT(m_tr_filter); + } + } + + void ensure_rel_filter(const relation_base & orel) { + SASSERT(m_rel_cols.size()>1); + if(m_rel_filter) { + return; + } + m_rel_filter = orel.get_manager().mk_filter_identical_fn(orel, m_rel_cols.size(), m_rel_cols.c_ptr()); + SASSERT(m_rel_filter); + } + + virtual void operator()(relation_base & rb) { + finite_product_relation & r = get(rb); + + if(m_table_cols.size()>1) { + (*m_table_filter)(r.get_table()); + } + + if(m_rel_cols.size()>1) { + r.garbage_collect(true); + unsigned rel_cnt = r.m_others.size(); + for(unsigned rel_idx=0; rel_idx m_table_filter; + scoped_ptr m_rel_filter; + unsigned m_col; + app_ref m_value; + public: + filter_equal_fn(const finite_product_relation & r, const relation_element & value, unsigned col) + : m_col(col), m_value(value, r.get_context().get_manager()) { + if(r.is_table_column(col)) { + table_element tval; + r.get_manager().relation_to_table(r.get_signature()[col], value, tval); + m_table_filter = r.get_manager().mk_filter_equal_fn(r.get_table(), tval, r.m_sig2table[col]); + } + } + + virtual void operator()(relation_base & rb) { + finite_product_relation & r = get(rb); + + if(m_table_filter) { + (*m_table_filter)(r.get_table()); + return; + } + r.garbage_collect(false); + relation_vector & inner_rels = r.m_others; + unsigned rel_cnt = inner_rels.size(); + for(unsigned i=0; i m_table_filter; + scoped_ptr m_rel_filter; + app_ref m_cond; + + idx_set m_table_cond_columns; + idx_set m_rel_cond_columns; + + //like m_table_cond_columns and m_rel_cond_columns, only the indexes are local to the + //table/relation, not to the signature of the whole relation + idx_set m_table_local_cond_columns; + idx_set m_rel_local_cond_columns; + + /** + If equal to 0, it means the interpreted condition uses all table columns. Then the original + table is used instead of the result of the projection. + */ + scoped_ptr m_table_cond_columns_project; + /** + \brief Column indexes of the global relations to which correspond the data columns in the table + that is result of applying the \c m_table_cond_columns_project functor. + */ + unsigned_vector m_global_origins_of_projected_columns; + + scoped_ptr m_assembling_join_project; + + + /** + \brief Renaming that transforms the variable numbers pointing to the global relation into + variables that point to the inner relation variables. + + The elements that do not correspond to columns of the inner relation (but rather to the table + columns) is modified in \c operator() when evaluating the condition for all the relevant + combinations of table values. + */ + expr_ref_vector m_renaming_for_inner_rel; + public: + filter_interpreted_fn(const finite_product_relation & r, app * condition) + : m_manager(r.get_context().get_manager()), + m_subst(r.get_context().get_var_subst()), + m_cond(condition, m_manager), + m_renaming_for_inner_rel(m_manager) { + relation_manager & rmgr = r.get_manager(); + + rule_manager& rm = r.get_context().get_rule_manager(); + idx_set& cond_columns = rm.collect_vars(m_cond); + + unsigned sig_sz = r.get_signature().size(); + for(unsigned i=0; i tproj_scope; + const table_base * tproj; + if(m_table_cond_columns_project) { + tproj_scope = (*m_table_cond_columns_project)(rtable); + tproj = tproj_scope.get(); + } + else { + tproj = &rtable; + } + unsigned projected_data_cols = tproj->get_signature().size()-1; + SASSERT(m_table_cond_columns.num_elems()==projected_data_cols); + + table_signature filtered_sig = tproj->get_signature(); + filtered_sig.push_back(finite_product_relation::s_rel_idx_sort); + filtered_sig.set_functional_columns(1); + + relation_vector new_rels; + + scoped_rel filtered_table = tplugin.mk_empty(filtered_sig); + table_fact f; + unsigned renaming_ofs = m_renaming_for_inner_rel.size()-1; + table_base::iterator pit = tproj->begin(); + table_base::iterator pend = tproj->end(); + for(; pit!=pend; ++pit) { + pit->get_fact(f); + unsigned old_rel_idx = static_cast(f.back()); + const relation_base & old_rel = r.get_inner_rel(old_rel_idx); + + //put the table values into the substitution + for(unsigned i=0; i filter = rmgr.mk_filter_interpreted_fn(*new_rel, to_app(inner_cond)); + (*filter)(*new_rel); + + if(new_rel->empty()) { + new_rel->deallocate(); + continue; + } + + unsigned new_rel_idx = new_rels.size(); + new_rels.push_back(new_rel); + f.push_back(new_rel_idx); + filtered_table->add_fact(f); + } + + if(!m_assembling_join_project) { + unsigned_vector table_cond_columns_vect; + for(unsigned i=0; i new_table = (*m_assembling_join_project)(rtable, *filtered_table); + r.reset(); + r.init(*new_table, new_rels, true); + } + }; + + relation_mutator_fn * finite_product_relation_plugin::mk_filter_interpreted_fn(const relation_base & rb, + app * condition) { + if(&rb.get_plugin()!=this) { + return 0; + } + return alloc(filter_interpreted_fn, get(rb), condition); + } + + class finite_product_relation_plugin::negation_filter_fn : public relation_intersection_filter_fn { + + unsigned_vector m_r_cols; + unsigned_vector m_neg_cols; + + scoped_ptr m_table_neg_filter; + scoped_ptr m_table_neg_complement_selector; + scoped_ptr m_neg_intersection_join; + scoped_ptr m_table_intersection_join; + scoped_ptr m_table_overlap_union; + scoped_ptr m_table_subtract; + scoped_ptr m_inner_subtract; + scoped_ptr m_overlap_table_last_column_remover; + scoped_ptr m_r_table_union; + + bool m_table_overlaps_only; + + unsigned_vector m_r_shared_table_cols; + unsigned_vector m_neg_shared_table_cols; + + unsigned_vector m_r_shared_rel_cols; + unsigned_vector m_neg_shared_rel_cols; + public: + negation_filter_fn(const finite_product_relation & r, const finite_product_relation & neg, + unsigned joined_col_cnt, const unsigned * r_cols, const unsigned * neg_cols) + : m_r_cols(joined_col_cnt, r_cols), + m_neg_cols(joined_col_cnt, neg_cols), + m_table_overlaps_only(true) { + const table_signature & tsig = r.m_table_sig; + const table_base & rtable = r.get_table(); + relation_manager & rmgr = r.get_manager(); + + for(unsigned i=0; iget_signature().size() , all_rel_cols); + m_parent.m_inner_subtract = m_r.get_manager().mk_filter_by_negation_fn(*r_inner, + inters_inner, all_rel_cols, all_rel_cols); + } + (*m_parent.m_inner_subtract)(*r_inner, inters_inner); + + unsigned new_rel_num = m_r.get_next_rel_idx(); + m_r.set_inner_rel(new_rel_num, r_inner); + func_columns[0]=new_rel_num; + return true; + } + }; + + + virtual void operator()(relation_base & rb, const relation_base & negb) { + finite_product_relation & r = get(rb); + const finite_product_relation & neg = get(negb); + + if(m_table_overlaps_only) { + handle_only_tables_overlap_case(r, neg); + 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()); + + table_base & r_table = r.get_table(); + table_plugin & tplugin = r_table.get_plugin(); + relation_manager & rmgr = r.get_manager(); + + //we need to do this before we perform the \c m_table_subtract + //the sigrature of the \c table_overlap0 relation is + //(data_columns)(original rel idx)(subtracted rel idx) + scoped_rel table_overlap0 = (*m_table_intersection_join)(r_table, + intersection->get_table()); + + //the rows that don't appear in the table of the intersection are safe to stay + (*m_table_subtract)(r_table, intersection->get_table()); + + //now we will examine the rows that do appear in the intersection + + //There are no functional columns in the \c table_overlap0 relation (because of + //the project we did). We need to make both rel idx columns functional. + //We do not lose any rows, since the data columns by themselves are unique. + + table_signature table_overlap_sig(table_overlap0->get_signature()); + table_overlap_sig.set_functional_columns(2); + scoped_rel table_overlap = tplugin.mk_empty(table_overlap_sig); + + if(!m_table_overlap_union) { + m_table_overlap_union = rmgr.mk_union_fn(*table_overlap, *table_overlap0); + SASSERT(m_table_overlap_union); + } + (*m_table_overlap_union)(*table_overlap, *table_overlap0); + + { + rel_subtractor * mutator = alloc(rel_subtractor, *this, r, *intersection); + scoped_ptr mapper = rmgr.mk_map_fn(*table_overlap, mutator); + (*mapper)(*table_overlap); + } + + if(!m_overlap_table_last_column_remover) { + unsigned removed_col = table_overlap->get_signature().size()-1; + m_overlap_table_last_column_remover = rmgr.mk_project_fn(*table_overlap, 1, &removed_col); + } + scoped_rel final_overlapping_rows_table = + (*m_overlap_table_last_column_remover)(*table_overlap); + + if(!m_r_table_union) { + m_r_table_union = rmgr.mk_union_fn(r_table, *final_overlapping_rows_table); + } + + (*m_r_table_union)(r_table, *final_overlapping_rows_table); + } + }; + + relation_intersection_filter_fn * finite_product_relation_plugin::mk_filter_by_negation_fn(const relation_base & rb, + const relation_base & negb, unsigned joined_col_cnt, + const unsigned * r_cols, const unsigned * negated_cols) { + if(&rb.get_plugin()!=this || &negb.get_plugin()!=this) { + return 0; + } + + return alloc(negation_filter_fn, get(rb), get(negb), joined_col_cnt, r_cols, negated_cols); + } + + + class finite_product_relation_plugin::filter_identical_pairs_fn : public relation_mutator_fn { + scoped_ptr m_tproject_fn; //if zero, no columns need to be projected away + unsigned m_col_cnt; + unsigned_vector m_table_cols; + unsigned_vector m_rel_cols; + + scoped_ptr m_assembling_join_project; + scoped_ptr m_updating_union; + public: + filter_identical_pairs_fn(const finite_product_relation & r, unsigned col_cnt, const unsigned * table_cols, + const unsigned * rel_cols) : + m_col_cnt(col_cnt), + m_table_cols(col_cnt, table_cols), + m_rel_cols(col_cnt, rel_cols) { + SASSERT(col_cnt>0); + const table_signature & tsig = r.m_table_sig; + unsigned t_sz = tsig.size(); + + sort_two_arrays(col_cnt, m_table_cols.begin(), m_rel_cols.begin()); + SASSERT(m_table_cols.back() tproj; + if(m_tproject_fn) { + tproj = (*m_tproject_fn)(r.get_table()); + } + else { + tproj = r.get_table().clone(); + } + SASSERT(m_col_cnt+1==tproj->get_signature().size()); + + table_signature filtered_sig = tproj->get_signature(); + filtered_sig.push_back(finite_product_relation::s_rel_idx_sort); + filtered_sig.set_functional_columns(1); + + relation_vector new_rels; + scoped_rel filtered_table = tplugin.mk_empty(filtered_sig); + table_fact f; + table_base::iterator pit = tproj->begin(); + table_base::iterator pend = tproj->end(); + for(; pit!=pend; ++pit) { + pit->get_fact(f); + unsigned old_rel_idx = static_cast(f.back()); + const relation_base & old_rel = r.get_inner_rel(old_rel_idx); + relation_base * new_rel = old_rel.clone(); + for(unsigned i=0; i filter = rmgr.mk_filter_equal_fn(*new_rel, r_el, m_rel_cols[i]); + (*filter)(*new_rel); + } + + if(new_rel->empty()) { + new_rel->deallocate(); + continue; + } + + unsigned new_rel_idx = new_rels.size(); + new_rels.push_back(new_rel); + f.push_back(new_rel_idx); + filtered_table->add_fact(f); + } + + if(!m_assembling_join_project) { + m_assembling_join_project = mk_assembler_of_filter_result(rtable, *filtered_table, m_table_cols); + } + + scoped_rel new_table = (*m_assembling_join_project)(r.get_table(), *filtered_table); + + r.reset(); + r.init(*new_table, new_rels, true); + } + }; + + relation_mutator_fn * finite_product_relation_plugin::mk_filter_identical_pairs(const finite_product_relation & r, + unsigned col_cnt, const unsigned * table_cols, const unsigned * rel_cols) { + return alloc(filter_identical_pairs_fn, r, col_cnt, table_cols, rel_cols); + } + + table_join_fn * finite_product_relation_plugin::mk_assembler_of_filter_result(const table_base & relation_table, + const table_base & filtered_table, const unsigned_vector & selected_columns) { + + table_plugin & tplugin = relation_table.get_plugin(); + const table_signature & rtable_sig = relation_table.get_signature(); + unsigned rtable_sig_sz = rtable_sig.size(); + unsigned selected_col_cnt = selected_columns.size(); + SASSERT(selected_col_cnt+2==filtered_table.get_signature().size()); + SASSERT(rtable_sig.functional_columns()==1); + SASSERT(filtered_table.get_signature().functional_columns()==1); + + unsigned_vector rtable_joined_cols; + rtable_joined_cols.append(selected_col_cnt, selected_columns.c_ptr()); //filtered table cols + rtable_joined_cols.push_back(rtable_sig_sz-1); //unfiltered relation indexes + + unsigned_vector filtered_joined_cols; + add_sequence(0, selected_col_cnt, filtered_joined_cols); //filtered table cols + filtered_joined_cols.push_back(selected_col_cnt); //unfiltered relation indexes + SASSERT(rtable_joined_cols.size()==filtered_joined_cols.size()); + + //the signature after join: + //(all relation table columns)(all filtered relation table columns)(unfiltered rel idx non-func from 'filtered') + // (unfiltered rel idx func from 'rtable')(filtered rel idx) + unsigned_vector removed_cols; + unsigned filtered_nonfunc_ofs = rtable_sig_sz-1; + add_sequence(filtered_nonfunc_ofs, selected_col_cnt, removed_cols); //data columns from 'filtered' + unsigned idx_ofs = filtered_nonfunc_ofs+selected_col_cnt; + removed_cols.push_back(idx_ofs); //unfiltered relation indexes from 'filtered' + removed_cols.push_back(idx_ofs+1); //unfiltered relation indexes from rtable + + table_join_fn * res = tplugin.get_manager().mk_join_project_fn(relation_table, filtered_table, + rtable_joined_cols, filtered_joined_cols, removed_cols); + SASSERT(res); + return res; + } + + // ----------------------------------- + // + // finite_product_relation + // + // ----------------------------------- + + finite_product_relation::finite_product_relation(finite_product_relation_plugin & p, + const relation_signature & s, const bool * table_columns, table_plugin & tplugin, + relation_plugin & oplugin, family_id other_kind) + : relation_base(p, s), + m_other_plugin(oplugin), + m_other_kind(other_kind), + m_full_rel_idx(UINT_MAX) { + const relation_signature & rel_sig = get_signature(); + unsigned sz = rel_sig.size(); + m_sig2table.resize(sz, UINT_MAX); + m_sig2other.resize(sz, UINT_MAX); + for(unsigned i=0; iclone()), + m_others(r.m_others), + m_available_rel_indexes(r.m_available_rel_indexes), + m_full_rel_idx(r.m_full_rel_idx), + m_live_rel_collection_project(), + m_empty_rel_removal_filter() { + //m_others is now just a shallow copy, we need use clone of the relations that in it now + unsigned other_sz = m_others.size(); + for(unsigned i=0; ideallocate(); + relation_vector::iterator it = m_others.begin(); + relation_vector::iterator end = m_others.end(); + for(; it!=end; ++it) { + relation_base * rel= *it; + if(rel) { + rel->deallocate(); + } + } + } + + context & finite_product_relation::get_context() const { + return get_manager().get_context(); + } + + unsigned finite_product_relation::get_next_rel_idx() const { + unsigned res; + if(!m_available_rel_indexes.empty()) { + res = m_available_rel_indexes.back(); + m_available_rel_indexes.pop_back(); + } + else { + res = m_others.size(); + m_others.push_back(0); + } + SASSERT(m_others[res]==0); + return res; + } + + void finite_product_relation::recycle_rel_idx(unsigned idx) const { + SASSERT(m_others[idx]==0); + m_available_rel_indexes.push_back(idx); + } + + unsigned finite_product_relation::get_full_rel_idx() { + if(m_full_rel_idx==UINT_MAX) { + m_full_rel_idx = get_next_rel_idx(); + relation_base * full_other = mk_full_inner(0); + m_others[m_full_rel_idx] = full_other; + } + return m_full_rel_idx; + } + + void finite_product_relation::init(const table_base & table_vals, const relation_vector & others, bool contiguous) { + SASSERT(m_table_sig.equal_up_to_fn_mark(table_vals.get_signature())); + SASSERT(empty()); + if(!m_others.empty()) { + garbage_collect(false); + } + SASSERT(m_others.empty()); + + m_others = others; + scoped_ptr table_union = get_manager().mk_union_fn(get_table(), table_vals); + (*table_union)(get_table(), table_vals); + + if(!contiguous) { + unsigned rel_cnt = m_others.size(); + for(unsigned i=0; isuggest_fact(t_f)) { + SASSERT(t_f.back()==new_rel_idx); + new_rel = mk_empty_inner(); + } else { + new_rel = get_inner_rel(t_f.back()).clone(); + + t_f[t_f.size()-1]=new_rel_idx; + m_table->ensure_fact(t_f); + } + new_rel->add_fact(o_f); + set_inner_rel(new_rel_idx, new_rel); + } + + bool finite_product_relation::contains_fact(const relation_fact & f) const { + table_fact t_f; + extract_table_fact(f, t_f); + + if(!m_table->fetch_fact(t_f)) { + return false; + } + + relation_fact o_f(get_context()); + extract_other_fact(f, o_f); + + const relation_base & other = get_inner_rel(t_f.back()); + + return other.contains_fact(o_f); + } + + bool finite_product_relation::empty() const { + garbage_collect(true); + return m_table->empty(); + } + + finite_product_relation * finite_product_relation::clone() const { + return alloc(finite_product_relation, *this); + } + + void finite_product_relation::complement_self(func_decl* p) { + unsigned other_sz = m_others.size(); + for(unsigned i=0; icomplement(p); + std::swap(m_others[i],r); + r->deallocate(); + } + table_element full_rel_idx = get_full_rel_idx(); + scoped_rel complement_table = m_table->complement(p, &full_rel_idx); + + scoped_ptr u_fn = get_manager().mk_union_fn(*m_table, *complement_table, 0); + SASSERT(u_fn); + (*u_fn)(*m_table, *complement_table, 0); + } + + finite_product_relation * finite_product_relation::complement(func_decl* p) const { + finite_product_relation * res = clone(); + res->complement_self(p); + return res; + } + + class finite_product_relation::live_rel_collection_reducer : public table_row_pair_reduce_fn { + idx_set & m_accumulator; + public: + live_rel_collection_reducer(idx_set & accumulator) : m_accumulator(accumulator) {} + + virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) { + m_accumulator.insert(static_cast(merged_func_columns[0])); + } + }; + + void finite_product_relation::collect_live_relation_indexes(idx_set & res) const { + SASSERT(res.empty()); + unsigned table_data_col_cnt = m_table_sig.size()-1; + + if(table_data_col_cnt==0) { + if(!get_table().empty()) { + table_base::iterator iit = get_table().begin(); + table_base::iterator iend = get_table().end(); + + SASSERT(iit!=iend); + res.insert(static_cast((*iit)[0])); + SASSERT((++iit)==iend); + } + return; + } + + if(!m_live_rel_collection_project) { + buffer removed_cols; + removed_cols.resize(table_data_col_cnt); + for(unsigned i=0; i live_indexes_table = (*m_live_rel_collection_project)(get_table()); + res.swap(m_live_rel_collection_acc); + + SASSERT(live_indexes_table->get_signature().size()==1); + SASSERT(live_indexes_table->get_signature().functional_columns()==1); + if(!live_indexes_table->empty()) { + table_base::iterator iit = live_indexes_table->begin(); + table_base::iterator iend = live_indexes_table->end(); + + SASSERT(iit!=iend); + res.insert(static_cast((*iit)[0])); + SASSERT((++iit)==iend); + } + } + + void finite_product_relation::garbage_collect(bool remove_empty) const { + idx_set live_indexes; + collect_live_relation_indexes(live_indexes); + + scoped_rel empty_rel_indexes; //populated only if \c remove_empty==true + table_fact empty_rel_fact; + + unsigned rel_cnt = m_others.size(); +#if Z3DEBUG + unsigned encountered_live_indexes = 0; +#endif + for(unsigned rel_idx=0; rel_idxempty()) { + continue; + } + if(empty_rel_indexes==0) { + table_signature empty_rel_indexes_sig; + empty_rel_indexes_sig.push_back(s_rel_idx_sort); + empty_rel_indexes = get_table_plugin().mk_empty(empty_rel_indexes_sig); + } + empty_rel_fact.reset(); + empty_rel_fact.push_back(rel_idx); + empty_rel_indexes->add_fact(empty_rel_fact); + } + m_others[rel_idx]->deallocate(); + m_others[rel_idx] = 0; + if(rel_idx==m_full_rel_idx) { + m_full_rel_idx = UINT_MAX; + } + recycle_rel_idx(rel_idx); + } + SASSERT(encountered_live_indexes==live_indexes.num_elems()); + + if(m_available_rel_indexes.size()==m_others.size()) { + m_available_rel_indexes.reset(); + m_others.reset(); + } + + if(empty_rel_indexes) { + SASSERT(remove_empty); + + if(!m_empty_rel_removal_filter) { + unsigned t_joined_cols[] = { m_table_sig.size()-1 }; + unsigned ei_joined_cols[] = { 0 }; + m_empty_rel_removal_filter = get_manager().mk_filter_by_negation_fn(get_table(), *empty_rel_indexes, + 1, t_joined_cols, ei_joined_cols); + } + + (*m_empty_rel_removal_filter)(*m_table, *empty_rel_indexes); + } + } + + bool finite_product_relation::try_unify_specifications(ptr_vector & rels) { + if(rels.empty()) { + return true; + } + unsigned sig_sz = rels.back()->get_signature().size(); + svector table_cols(sig_sz, true); + + ptr_vector::iterator it = rels.begin(); + ptr_vector::iterator end = rels.end(); + for(; it!=end; ++it) { + finite_product_relation & rel = **it; + for(unsigned i=0; i pr_fun = get_manager().mk_project_fn(get_table(), to_project_away); + table_base * moved_cols_table = (*pr_fun)(get_table()); //gets destroyed inside moved_cols_trel + scoped_rel moved_cols_trel = + rmgr.get_table_relation_plugin(moved_cols_table->get_plugin()).mk_from_table(moved_cols_sig, moved_cols_table); + + svector moved_cols_table_flags(moved_cols_sig.size(), false); + + scoped_rel moved_cols_rel = get_plugin().mk_empty(moved_cols_sig, + moved_cols_table_flags.c_ptr()); + + scoped_ptr union_fun = + get_manager().mk_union_fn(*moved_cols_rel, *moved_cols_trel); + SASSERT(union_fun); //the table_relation should be able to be 'unioned into' any relation + + (*union_fun)(*moved_cols_rel, *moved_cols_trel); + + unsigned_vector all_moved_cols_indexes; + add_sequence(0, moved_cols_sig.size(), all_moved_cols_indexes); + + scoped_ptr join_fun = get_manager().mk_join_project_fn(*this, *moved_cols_rel, new_rel_columns, + all_moved_cols_indexes, new_rel_columns, false); + + scoped_rel unordered_rel = (*join_fun)(*this, *moved_cols_rel); + SASSERT(unordered_rel->get_signature().size()==sig_sz); //the signature size should be the same as original + + //now we need to reorder the columns in the \c new_rel to match the original table + unsigned_vector permutation; + unsigned moved_cols_cnt = new_rel_columns.size(); + unsigned next_replaced_idx = 0; + unsigned next_orig_idx = 0; + for(unsigned i=0; i perm_fun = get_manager().mk_rename_fn(*unordered_rel, cycle); + //the scoped_rel wrapper does the destruction of the old object + unordered_rel = (*perm_fun)(*unordered_rel); + cycle.reset(); + } + + finite_product_relation & new_rel = finite_product_relation_plugin::get(*unordered_rel); + + //Swap the content of the current object and new_rel. On exitting the function new_rel will be destroyed + //since it points to the content of scoped_rel unordered_rel. + swap(new_rel); + + return true; + } + + void finite_product_relation::display(std::ostream & out) const { + + garbage_collect(true); + + out << "finite_product_relation:\n"; + + out << " table:\n"; + get_table().display(out); + + unsigned other_sz = m_others.size(); + for(unsigned i=0; iget_fact(tfact); + + const table_relation & orel = static_cast(get_inner_rel(tfact[rel_idx_col])); + const table_base & otable = orel.get_table(); + table_base::iterator oit = otable.begin(); + table_base::iterator oend = otable.end(); + for(; oit!=oend; ++oit) { + oit->get_fact(ofact); + + out << "\t("; + for(unsigned i=0; iget_fact(fact); + conjs.reset(); + SASSERT(fact.size() == fact_sz); + unsigned rel_idx = static_cast(fact[fact_sz-1]); + m_others[rel_idx]->to_formula(tmp); + for (unsigned i = 0; i + 1 < fact_sz; ++i) { + conjs.push_back(m.mk_eq(m.mk_var(i, sig[i]), util.mk_numeral(fact[i], sig[i]))); + } + sh(tmp, fact_sz-1, tmp); + conjs.push_back(tmp); + disjs.push_back(m.mk_and(conjs.size(), conjs.c_ptr())); + } + bool_rewriter(m).mk_or(disjs.size(), disjs.c_ptr(), fml); + } + +}; + diff --git a/src/muz/rel/dl_finite_product_relation.h b/src/muz/rel/dl_finite_product_relation.h new file mode 100644 index 000000000..d5181d122 --- /dev/null +++ b/src/muz/rel/dl_finite_product_relation.h @@ -0,0 +1,366 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_finite_product_relation.h + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-24. + +Revision History: + +--*/ +#ifndef _DL_FINITE_PRODUCT_RELATION_H_ +#define _DL_FINITE_PRODUCT_RELATION_H_ + + +#include "dl_base.h" +#include "dl_relation_manager.h" +#include "dl_table_relation.h" + +namespace datalog { + + class finite_product_relation; + + void universal_delete(finite_product_relation* ptr); + + + class finite_product_relation_plugin : public relation_plugin { + friend class finite_product_relation; + public: + struct rel_spec { + family_id m_inner_kind; //null_family_id means we don't care about the kind + svector m_table_cols; + + rel_spec() : m_inner_kind(null_family_id) {} + rel_spec(const svector& table_cols) + : m_inner_kind(null_family_id), m_table_cols(table_cols) {} + + bool operator==(const rel_spec & o) const { + return m_inner_kind==o.m_inner_kind && vectors_equal(m_table_cols, o.m_table_cols); + } + struct hash { + unsigned operator()(const rel_spec & o) const { + return o.m_inner_kind^svector_hash()(o.m_table_cols); + } + }; + }; + private: + + class join_fn; + class converting_join_fn; + class project_fn; + class rename_fn; + class union_fn; + class inner_singleton_union_fn; + class converting_union_fn; + class filter_identical_fn; + class filter_equal_fn; + class filter_interpreted_fn; + class negation_filter_fn; + class filter_identical_pairs_fn; + + relation_plugin & m_inner_plugin; + + rel_spec_store > m_spec_store; + + static symbol get_name(relation_plugin & inner_plugin); + family_id get_relation_kind(finite_product_relation & r, const bool * table_columns); + + static void get_all_possible_table_columns(relation_manager & rmgr, const relation_signature & s, + svector & table_columns); + void get_all_possible_table_columns(const relation_signature & s, svector & table_columns) { + get_all_possible_table_columns(get_manager(), s, table_columns); + } + + void split_signatures(const relation_signature & s, table_signature & table_sig, + relation_signature & remaining_sig); + void split_signatures(const relation_signature & s, const bool * table_columns, + table_signature & table_sig, relation_signature & remaining_sig); + public: + static finite_product_relation & get(relation_base & r); + static const finite_product_relation & get(const relation_base & r); + static finite_product_relation * get(relation_base * r); + static const finite_product_relation * get(const relation_base * r); + + static finite_product_relation_plugin & get_plugin(relation_manager & rmgr, relation_plugin & inner); + + finite_product_relation_plugin(relation_plugin & inner_plugin, relation_manager & manager); + + virtual void initialize(family_id fid); + + relation_plugin & get_inner_plugin() const { return m_inner_plugin; } + + virtual bool can_handle_signature(const relation_signature & s); + + virtual relation_base * mk_empty(const relation_signature & s); + /** + \c inner_kind==null_family_id means we don't care about the kind of the inner relation + */ + finite_product_relation * mk_empty(const relation_signature & s, const bool * table_columns, + family_id inner_kind=null_family_id); + finite_product_relation * mk_empty(const finite_product_relation & original); + virtual relation_base * mk_empty(const relation_base & original); + virtual relation_base * mk_empty(const relation_signature & s, family_id kind); + + virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + + /** + \brief Return true if \c r can be converted to \c finite_product_relation_plugin either + by \c mk_from_table_relation or by \c mk_from_inner_relation. + */ + bool can_be_converted(const relation_base & r); + + /** + If the conversion cannot be performed, 0 is returned. + */ + finite_product_relation * mk_from_table_relation(const table_relation & r); + finite_product_relation * mk_from_inner_relation(const relation_base & r); + + bool can_convert_to_table_relation(const finite_product_relation & r); + table_relation * to_table_relation(const finite_product_relation & r); + + protected: + virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols); + + private: + /** + \brief Create a filter that enforces equality between pairs of table and relation columns + + The column numbers in arrays \c table_cols and \c rel_cols must be local to the table/inner relation. + */ + relation_mutator_fn * mk_filter_identical_pairs(const finite_product_relation & r, unsigned col_cnt, + const unsigned * table_cols, const unsigned * rel_cols); + + /** + \brief Create a join-project operation that creates a table according to \c relation_table + but with references to relations updated and removed according to the content of \c filtered_table. + \c selected_columns contains sorted indexes of data columns in \c relation_table that are also in + the \c filtered_table (so that the first column in \c filtered_table corresponds to + \c selected_columns[0] -th column in \c relation_table etc...) + + Signature of \c relation_table: + (data columns)(functional column with indexes of relation objects) + + Signature of \c filtered_table: + (selected data columns)(non-functional column with original relation object indexes) + (functional column with indexes of filtered relation objects) + + */ + static table_join_fn * mk_assembler_of_filter_result(const table_base & relation_table, + const table_base & filtered_table, const unsigned_vector & selected_columns); + + }; + + class finite_product_relation : public relation_base { + friend class finite_product_relation_plugin; + friend class finite_product_relation_plugin::join_fn; + friend class finite_product_relation_plugin::project_fn; + friend class finite_product_relation_plugin::union_fn; + friend class finite_product_relation_plugin::rename_fn; + friend class finite_product_relation_plugin::inner_singleton_union_fn; + friend class finite_product_relation_plugin::filter_equal_fn; + friend class finite_product_relation_plugin::filter_identical_pairs_fn; + + class live_rel_collection_reducer; + + + public: + /** + Size of this sort determines how many different relation objects can we refer to. + */ + static const table_sort s_rel_idx_sort; + + + /** + \brief The last column in the signature is a functional column with index of the + associated inner relation. The other columns correspond to the relation signature + according to \c m_table2sig. + + It holds that \c m_table_sig.size()-1==m_table2sig.size() + */ + + table_signature m_table_sig; + unsigned_vector m_table2sig; // (ordered list) + unsigned_vector m_sig2table; //index of corresponding table column or UINT_MAX + private: + relation_signature m_other_sig; + unsigned_vector m_other2sig; // (ordered list) + public: + unsigned_vector m_sig2other; //index of corresponding other relation column or UINT_MAX + private: + relation_plugin & m_other_plugin; + family_id m_other_kind; + + mutable table_base * m_table; + public: + mutable relation_vector m_others; + private: + mutable unsigned_vector m_available_rel_indexes; + + /** + \c UINT_MAX means uninitialized. + If we can get away with it, we want to have a single full relation to refer to. + */ + mutable unsigned m_full_rel_idx; + + mutable idx_set m_live_rel_collection_acc; + mutable scoped_ptr m_live_rel_collection_project; + + mutable scoped_ptr m_empty_rel_removal_filter; + + void recycle_rel_idx(unsigned idx) const; + + // creates a full relation if it does not exist. + unsigned get_full_rel_idx(); + + + + public: + relation_base & get_inner_rel(table_element idx) + { SASSERT(idx(idx)); } + relation_base & get_inner_rel(unsigned idx) { SASSERT(m_others[idx]); return *m_others[idx]; } + const relation_base & get_inner_rel(unsigned idx) const + { return const_cast(*this).get_inner_rel(idx); } + + unsigned get_next_rel_idx() const; + + /** + The relation takes ownership of the \c inner object. + */ + void set_inner_rel(table_element idx, relation_base * inner) + { SASSERT(idx(idx), inner); } + /** + The relation takes ownership of the \c inner object. + */ + void set_inner_rel(unsigned idx, relation_base * inner) { + SASSERT(!m_others[idx]); + SASSERT(inner); + m_others[idx] = inner; + } + table_base & get_table() { return *m_table; } + + table_plugin & get_table_plugin() const { return get_table().get_plugin(); } + + void garbage_collect(bool remove_empty) const; + + /** + \brief Initialize an empty relation with table \c table_vals and relations in \c others. + + The relation object takes ownership of relations inside the \c others vector. + + If \c contiguous is true, it can be assumed that there are no zero elements in the \c others array. + */ + void init(const table_base & table_vals, const relation_vector & others, bool contiguous); + + private: + + + /** + \brief Extract the values of table non-functional columns from the relation fact. + The value of the functional column which determines index of the inner relation is undefined. + */ + void extract_table_fact(const relation_fact rf, table_fact & tf) const; + /** + \brief Extract the values of the inner relation columns from the relation fact. + */ + void extract_other_fact(const relation_fact rf, relation_fact & of) const; + + relation_base * mk_empty_inner(); + relation_base * mk_full_inner(func_decl* pred); + + + void complement_self(func_decl* pred); + + void collect_live_relation_indexes(idx_set & res) const; + + + /** + \brief Try to modify relations in \c rels so that they have the same columns corresponding to the table + and the inner relation (so that the union can be perofrmed on theim in a straightforward way). + + Relations in \c rels must all have equal signature. + + Even if the function fails and false is returned, some relations may already be modified. They are + in a valid state, but with different specification. + */ + static bool try_unify_specifications(ptr_vector & rels); + + bool try_modify_specification(const bool * table_cols); + + virtual bool can_swap(const relation_base & r) const + { return &get_plugin()==&r.get_plugin(); } + + /** + \brief Swap content of the current relation with the content of \c r. + + Both relations must come from the same plugin and be of the same signature. + */ + virtual void swap(relation_base & r); + + /** + \brief Create a \c finite_product_relation object. + */ + finite_product_relation(finite_product_relation_plugin & p, const relation_signature & s, + const bool * table_columns, table_plugin & tplugin, relation_plugin & oplugin, family_id other_kind); + finite_product_relation(const finite_product_relation & r); + virtual ~finite_product_relation(); + public: + context & get_context() const; + finite_product_relation_plugin & get_plugin() const { + return static_cast(relation_base::get_plugin()); + } + + bool is_table_column(unsigned col_idx) const { return m_sig2table[col_idx]!=UINT_MAX; } + + const table_base & get_table() const { return *m_table; } + + const relation_base & get_inner_rel(table_element idx) const + { SASSERT(idx(idx)); } + + /** + The function calls garbage_collect, so the internal state may change when it is called. + */ + virtual bool empty() const; + void reset() { m_table->reset(); garbage_collect(false); } + + virtual void add_fact(const relation_fact & f); + virtual bool contains_fact(const relation_fact & f) const; + + virtual finite_product_relation * clone() const; + virtual finite_product_relation * complement(func_decl* p) const; + + virtual void display(std::ostream & out) const; + virtual void display_tuples(func_decl & pred, std::ostream & out) const; + + virtual unsigned get_size_estimate_rows() const { return m_table->get_size_estimate_rows(); } + virtual unsigned get_size_estimate_bytes() const { return m_table->get_size_estimate_bytes(); } + + virtual void to_formula(expr_ref& fml) const; + }; + +}; + +#endif /* _DL_FINITE_PRODUCT_RELATION_H_ */ + diff --git a/src/muz/rel/dl_interval_relation.cpp b/src/muz/rel/dl_interval_relation.cpp new file mode 100644 index 000000000..c04269b02 --- /dev/null +++ b/src/muz/rel/dl_interval_relation.cpp @@ -0,0 +1,653 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + dl_interval_relation.cpp + +Abstract: + + Basic interval reatlion. + +Author: + + Nikolaj Bjorner (nbjorner) 2010-2-11 + +Revision History: + +--*/ + +#include "debug.h" +#include "optional.h" +#include "ast_pp.h" +#include "dl_interval_relation.h" +#include "dl_relation_manager.h" +#include "bool_rewriter.h" + + +namespace datalog { + // ------------------------- + // interval_relation_plugin + + interval_relation_plugin::interval_relation_plugin(relation_manager& m): + relation_plugin(interval_relation_plugin::get_name(), m), + m_empty(m_dep), + m_arith(get_ast_manager()) { + } + + bool interval_relation_plugin::can_handle_signature(const relation_signature & sig) { + for (unsigned i = 0; i < sig.size(); ++i) { + if (!m_arith.is_int(sig[i]) && !m_arith.is_real(sig[i])) { + return false; + } + } + return true; + } + + + relation_base * interval_relation_plugin::mk_empty(const relation_signature & s) { + return alloc(interval_relation, *this, s, true); + } + + relation_base * interval_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { + return alloc(interval_relation, *this, s, false); + } + + class interval_relation_plugin::join_fn : public convenient_relation_join_fn { + public: + join_fn(const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2){ + } + + virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + interval_relation const& r1 = get(_r1); + interval_relation const& r2 = get(_r2); + interval_relation_plugin& p = r1.get_plugin(); + interval_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_join(r1, r2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); + return result; + } + }; + + relation_join_fn * interval_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (!check_kind(r1) || !check_kind(r2)) { + return 0; + } + return alloc(join_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2); + } + + + class interval_relation_plugin::project_fn : public convenient_relation_project_fn { + public: + project_fn(const relation_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) + : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { + } + + virtual relation_base * operator()(const relation_base & _r) { + interval_relation const& r = get(_r); + interval_relation_plugin& p = r.get_plugin(); + interval_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_project(r, m_removed_cols.size(), m_removed_cols.c_ptr()); + return result; + } + }; + + relation_transformer_fn * interval_relation_plugin::mk_project_fn(const relation_base & r, + unsigned col_cnt, const unsigned * removed_cols) { + return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); + } + + class interval_relation_plugin::rename_fn : public convenient_relation_rename_fn { + public: + rename_fn(const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) { + } + + virtual relation_base * operator()(const relation_base & _r) { + interval_relation const& r = get(_r); + interval_relation_plugin& p = r.get_plugin(); + interval_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_rename(r, m_cycle.size(), m_cycle.c_ptr()); + return result; + } + }; + + relation_transformer_fn * interval_relation_plugin::mk_rename_fn(const relation_base & r, + unsigned cycle_len, const unsigned * permutation_cycle) { + if(!check_kind(r)) { + return 0; + } + return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle); + } + + interval interval_relation_plugin::unite(interval const& src1, interval const& src2) { + bool l_open = src1.is_lower_open(); + bool r_open = src1.is_upper_open(); + ext_numeral low = src1.inf(); + ext_numeral high = src1.sup(); + if (src2.inf() < low || (src2.inf() == low && l_open)) { + low = src2.inf(); + l_open = src2.is_lower_open(); + } + if (src2.sup() > high || (src2.sup() == high && r_open)) { + high = src2.sup(); + r_open = src2.is_upper_open(); + } + return interval(dep(), low, l_open, 0, high, r_open, 0); + } + + interval interval_relation_plugin::widen(interval const& src1, interval const& src2) { + bool l_open = src1.is_lower_open(); + bool r_open = src1.is_upper_open(); + ext_numeral low = src1.inf(); + ext_numeral high = src1.sup(); + + if (src2.inf() < low || (low == src2.inf() && l_open && !src2.is_lower_open())) { + low = ext_numeral(false); + l_open = true; + } + if (high < src2.sup() || (src2.sup() == high && !r_open && src2.is_upper_open())) { + high = ext_numeral(true); + r_open = true; + } + return interval(dep(), low, l_open, 0, high, r_open, 0); + } + + interval interval_relation_plugin::meet(interval const& src1, interval const& src2, bool& isempty) { + isempty = false; + if (is_empty(0, src1) || is_infinite(src2)) { + return src1; + } + if (is_empty(0, src2) || is_infinite(src1)) { + return src2; + } + bool l_open = src1.is_lower_open(); + bool r_open = src1.is_upper_open(); + ext_numeral low = src1.inf(); + ext_numeral high = src1.sup(); + if (src2.inf() > low || (src2.inf() == low && !l_open)) { + low = src2.inf(); + l_open = src2.is_lower_open(); + } + if (src2.sup() < high || (src2.sup() == high && !r_open)) { + high = src2.sup(); + r_open = src2.is_upper_open(); + } + if (low > high || (low == high && (l_open || r_open))) { + isempty = true; + return interval(dep()); + } + else { + return interval(dep(), low, l_open, 0, high, r_open, 0); + } + } + + bool interval_relation_plugin::is_infinite(interval const& i) { + return i.plus_infinity() && i.minus_infinity(); + } + + bool interval_relation_plugin::is_empty(unsigned, interval const& i) { + return i.sup() < i.inf(); + } + + class interval_relation_plugin::union_fn : public relation_union_fn { + bool m_is_widen; + public: + union_fn(bool is_widen) : + m_is_widen(is_widen) { + } + + virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + + TRACE("interval_relation", _r.display(tout << "dst:\n"); _src.display(tout << "src:\n");); + + interval_relation& r = get(_r); + interval_relation const& src = get(_src); + if (_delta) { + interval_relation& d = get(*_delta); + r.mk_union(src, &d, m_is_widen); + } + else { + r.mk_union(src, 0, m_is_widen); + } + } + }; + + relation_union_fn * interval_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { + return 0; + } + return alloc(union_fn, false); + } + + relation_union_fn * interval_relation_plugin::mk_widen_fn( + const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { + return 0; + } + return alloc(union_fn, true); + } + + class interval_relation_plugin::filter_identical_fn : public relation_mutator_fn { + unsigned_vector m_identical_cols; + public: + filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) + : m_identical_cols(col_cnt, identical_cols) {} + + virtual void operator()(relation_base & r) { + interval_relation & pr = get(r); + for (unsigned i = 1; i < m_identical_cols.size(); ++i) { + unsigned c1 = m_identical_cols[0]; + unsigned c2 = m_identical_cols[i]; + pr.equate(c1, c2); + } + } + }; + + relation_mutator_fn * interval_relation_plugin::mk_filter_identical_fn( + const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { + if(!check_kind(t)) { + return 0; + } + return alloc(filter_identical_fn, col_cnt, identical_cols); + } + + + class interval_relation_plugin::filter_equal_fn : public relation_mutator_fn { + unsigned m_col; + rational m_value; + public: + filter_equal_fn(relation_manager & m, const relation_element & value, unsigned col) + : m_col(col) { + arith_util arith(m.get_context().get_manager()); + VERIFY(arith.is_numeral(value, m_value)); + } + + virtual void operator()(relation_base & _r) { + interval_relation & r = get(_r); + interval_relation_plugin & p = r.get_plugin(); + r.mk_intersect(m_col, interval(p.dep(), m_value)); + TRACE("interval_relation", tout << m_value << "\n"; r.display(tout);); + } + }; + + relation_mutator_fn * interval_relation_plugin::mk_filter_equal_fn(const relation_base & r, + const relation_element & value, unsigned col) { + if(check_kind(r)) { + return alloc(filter_equal_fn, get_manager(), value, col); + } + return 0; + } + + + class interval_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { + app_ref m_cond; + public: + filter_interpreted_fn(interval_relation const& t, app* cond): + m_cond(cond, t.get_plugin().get_ast_manager()) { + } + + void operator()(relation_base& t) { + get(t).filter_interpreted(m_cond); + TRACE("interval_relation", tout << mk_pp(m_cond, m_cond.get_manager()) << "\n"; t.display(tout);); + } + }; + + relation_mutator_fn * interval_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { + if (check_kind(t)) { + return alloc(filter_interpreted_fn, get(t), condition); + } + return 0; + } + + interval_relation& interval_relation_plugin::get(relation_base& r) { + return dynamic_cast(r); + } + + interval_relation const & interval_relation_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + + // ----------------------- + // interval_relation + + interval_relation::interval_relation(interval_relation_plugin& p, relation_signature const& s, bool is_empty): + vector_relation(p, s, is_empty, interval(p.dep())) + { + TRACE("interval_relation", tout << s.size() << "\n";); + } + + void interval_relation::add_fact(const relation_fact & f) { + interval_relation r(get_plugin(), get_signature(), false); + ast_manager& m = get_plugin().get_ast_manager(); + for (unsigned i = 0; i < f.size(); ++i) { + app_ref eq(m); + expr* e = f[i]; + eq = m.mk_eq(m.mk_var(i, m.get_sort(e)), e); + r.filter_interpreted(eq.get()); + } + mk_union(r, 0, false); + } + + bool interval_relation::contains_fact(const relation_fact & f) const { + SASSERT(f.size() == get_signature().size()); + interval_relation_plugin& p = get_plugin(); + + for (unsigned i = 0; i < f.size(); ++i) { + if (f[i] != f[find(i)]) { + return false; + } + interval const& iv = (*this)[i]; + if (p.is_infinite(iv)) { + continue; + } + rational v; + if (p.m_arith.is_numeral(f[i], v)) { + if (!iv.contains(v)) { + return false; + } + } + else { + // TBD: may or must? + } + } + return true; + } + + interval_relation * interval_relation::clone() const { + interval_relation* result = alloc(interval_relation, get_plugin(), get_signature(), empty()); + result->copy(*this); + return result; + } + + interval_relation * interval_relation::complement(func_decl*) const { + UNREACHABLE(); + return 0; + } + + void interval_relation::to_formula(expr_ref& fml) const { + ast_manager& m = get_plugin().get_ast_manager(); + arith_util& arith = get_plugin().m_arith; + expr_ref_vector conjs(m); + relation_signature const& sig = get_signature(); + for (unsigned i = 0; i < sig.size(); ++i) { + if (i != find(i)) { + conjs.push_back(m.mk_eq(m.mk_var(i, sig[i]), + m.mk_var(find(i), sig[find(i)]))); + continue; + } + interval const& iv = (*this)[i]; + sort* ty = sig[i]; + expr_ref var(m.mk_var(i, ty), m); + if (!iv.minus_infinity()) { + expr* lo = arith.mk_numeral(iv.get_lower_value(), ty); + if (iv.is_lower_open()) { + conjs.push_back(arith.mk_lt(lo, var)); + } + else { + conjs.push_back(arith.mk_le(lo, var)); + } + } + if (!iv.plus_infinity()) { + expr* hi = arith.mk_numeral(iv.get_upper_value(), ty); + if (iv.is_upper_open()) { + conjs.push_back(arith.mk_lt(var, hi)); + } + else { + conjs.push_back(arith.mk_le(var, hi)); + } + } + } + bool_rewriter br(m); + br.mk_and(conjs.size(), conjs.c_ptr(), fml); + } + + + void interval_relation::display_index(unsigned i, interval const& j, std::ostream & out) const { + out << i << " in " << j << "\n"; + } + + interval_relation_plugin& interval_relation::get_plugin() const { + return static_cast(relation_base::get_plugin()); + } + + void interval_relation::mk_intersect(unsigned idx, interval const& i) { + bool isempty; + (*this)[idx] = mk_intersect((*this)[idx], i, isempty); + if (isempty || is_empty(idx, (*this)[idx])) { + set_empty(); + } + } + + void interval_relation::mk_rename_elem(interval& i, unsigned, unsigned const* ) { + + } + + void interval_relation::filter_interpreted(app* cond) { + interval_relation_plugin& p = get_plugin(); + rational k; + unsigned x, y; + if (p.is_lt(cond, x, k, y)) { + // 0 < x - y + k + if (x == UINT_MAX) { + // y < k + mk_intersect(y, interval(p.dep(), k, true, false, 0)); + return; + } + if (y == UINT_MAX) { + // -k < x + mk_intersect(x, interval(p.dep(), -k, true, true, 0)); + return; + } + // y < x + k + ext_numeral x_hi = (*this)[x].sup(); + ext_numeral y_lo = (*this)[y].inf(); + if (!x_hi.is_infinite()) { + mk_intersect(y, interval(p.dep(), k + x_hi.to_rational(), true, false, 0)); + } + if (!y_lo.is_infinite()) { + mk_intersect(x, interval(p.dep(), y_lo.to_rational() - k, true, true, 0)); + } + return; + } + bool is_int = false; + if (p.is_le(cond, x, k, y, is_int)) { + // 0 <= x - y + k + if (x == UINT_MAX) { + // y <= k + mk_intersect(y, interval(p.dep(), k, false, false, 0)); + return; + } + if (y == UINT_MAX) { + // -k <= x + mk_intersect(x, interval(p.dep(), -k, false, true, 0)); + return; + } + ext_numeral x_hi = (*this)[x].sup(); + ext_numeral y_lo = (*this)[y].inf(); + if (!x_hi.is_infinite()) { + mk_intersect(y, interval(p.dep(), k + x_hi.to_rational(), false, false, 0)); + } + if (!y_lo.is_infinite()) { + mk_intersect(x, interval(p.dep(), y_lo.to_rational() - k, false, true, 0)); + } + return; + } + if (p.is_eq(cond, x, k, y)) { + // y = x + k + if (x == UINT_MAX) { + SASSERT(y != UINT_MAX); + mk_intersect(y, interval(p.dep(), k)); + return; + } + if (y == UINT_MAX) { + // x = - k + SASSERT(x != UINT_MAX); + mk_intersect(x, interval(p.dep(), -k)); + return; + } + interval x_i = (*this)[x]; + interval y_i = (*this)[y]; + x_i += interval(p.dep(), k); + y_i -= interval(p.dep(), k); + mk_intersect(x, y_i); + mk_intersect(y, x_i); + } + if (get_plugin().get_ast_manager().is_false(cond)) { + set_empty(); + } + } + + bool interval_relation_plugin::is_linear(expr* e, unsigned& neg, unsigned& pos, rational& k, bool is_pos) const { +#define SET_VAR(_idx_) \ + if (is_pos &&pos == UINT_MAX) { \ + pos = _idx_; \ + return true; \ + } \ + if (!is_pos && neg == UINT_MAX) { \ + neg = _idx_; \ + return true; \ + } \ + else { \ + return false; \ + } + + if (is_var(e)) { + SET_VAR(to_var(e)->get_idx()); + } + if (!is_app(e)) { + return false; + } + app* a = to_app(e); + + if (m_arith.is_add(e)) { + for (unsigned i = 0; i < a->get_num_args(); ++i) { + if (!is_linear(a->get_arg(i), neg, pos, k, is_pos)) return false; + } + return true; + } + if (m_arith.is_sub(e)) { + SASSERT(a->get_num_args() == 2); + return + is_linear(a->get_arg(0), neg, pos, k, is_pos) && + is_linear(a->get_arg(1), neg, pos, k, !is_pos); + } + rational k1; + SASSERT(!m_arith.is_mul(e) || a->get_num_args() == 2); + if (m_arith.is_mul(e) && + m_arith.is_numeral(a->get_arg(0), k1) && + k1.is_minus_one() && + is_var(a->get_arg(1))) { + SET_VAR(to_var(a->get_arg(1))->get_idx()); + } + + if (m_arith.is_numeral(e, k1)) { + if (is_pos) { + k += k1; + } + else { + k -= k1; + } + return true; + } + return false; + } + + // 0 <= x - y + k + bool interval_relation_plugin::is_le(app* cond, unsigned& x, rational& k, unsigned& y, bool& is_int) const { + ast_manager& m = get_ast_manager(); + k.reset(); + x = UINT_MAX; + y = UINT_MAX; + + if (m_arith.is_le(cond)) { + is_int = m_arith.is_int(cond->get_arg(0)); + if (!is_linear(cond->get_arg(0), y, x, k, false)) return false; + if (!is_linear(cond->get_arg(1), y, x, k, true)) return false; + return (x != UINT_MAX || y != UINT_MAX); + } + if (m_arith.is_ge(cond)) { + is_int = m_arith.is_int(cond->get_arg(0)); + if (!is_linear(cond->get_arg(0), y, x, k, true)) return false; + if (!is_linear(cond->get_arg(1), y, x, k, false)) return false; + return (x != UINT_MAX || y != UINT_MAX); + } + if (m_arith.is_lt(cond) && m_arith.is_int(cond->get_arg(0))) { + is_int = true; + if (!is_linear(cond->get_arg(0), y, x, k, false)) return false; + if (!is_linear(cond->get_arg(1), y, x, k, true)) return false; + k -= rational::one(); + return (x != UINT_MAX || y != UINT_MAX); + } + if (m_arith.is_gt(cond) && m_arith.is_int(cond->get_arg(0))) { + is_int = true; + if (!is_linear(cond->get_arg(0), y, x, k, true)) return false; + if (!is_linear(cond->get_arg(1), y, x, k, false)) return false; + k += rational::one(); + return (x != UINT_MAX || y != UINT_MAX); + } + if (m.is_not(cond) && is_app(cond->get_arg(0))) { + // not (0 <= x - y + k) + // <=> + // 0 > x - y + k + // <=> + // 0 <= y - x - k - 1 + if (is_le(to_app(cond->get_arg(0)), x, k, y, is_int) && is_int) { + k.neg(); + k -= rational::one(); + std::swap(x, y); + return true; + } + // not (0 < x - y + k) + // <=> + // 0 >= x - y + k + // <=> + // 0 <= y - x - k + if (is_lt(to_app(cond->get_arg(0)), x, k, y)) { + is_int = false; + k.neg(); + std::swap(x, y); + return true; + } + } + return false; + } + + // 0 < x - y + k + bool interval_relation_plugin::is_lt(app* cond, unsigned& x, rational& k, unsigned& y) const { + k.reset(); + x = UINT_MAX; + y = UINT_MAX; + if (m_arith.is_lt(cond) && m_arith.is_real(cond->get_arg(0))) { + if (!is_linear(cond->get_arg(0), y, x, k, false)) return false; + if (!is_linear(cond->get_arg(1), y, x, k, true)) return false; + return (x != UINT_MAX || y != UINT_MAX); + } + if (m_arith.is_gt(cond) && m_arith.is_real(cond->get_arg(0))) { + if (!is_linear(cond->get_arg(0), y, x, k, true)) return false; + if (!is_linear(cond->get_arg(1), y, x, k, false)) return false; + return (x != UINT_MAX || y != UINT_MAX); + } + return false; + } + + // 0 = x - y + k + bool interval_relation_plugin::is_eq(app* cond, unsigned& x, rational& k, unsigned& y) const { + ast_manager& m = get_ast_manager(); + k.reset(); + x = UINT_MAX; + y = UINT_MAX; + if (m.is_eq(cond)) { + if (!is_linear(cond->get_arg(0), y, x, k, false)) return false; + if (!is_linear(cond->get_arg(1), y, x, k, true)) return false; + return (x != UINT_MAX || y != UINT_MAX); + } + return false; + } + +}; + diff --git a/src/muz/rel/dl_interval_relation.h b/src/muz/rel/dl_interval_relation.h new file mode 100644 index 000000000..703cb43c5 --- /dev/null +++ b/src/muz/rel/dl_interval_relation.h @@ -0,0 +1,142 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + dl_interval_relation.h + +Abstract: + + Basic interval reatlion. + +Author: + + Nikolaj Bjorner (nbjorner) 2010-2-11 + +Revision History: + +--*/ +#ifndef _DL_INTERVAL_RELATION_H_ +#define _DL_INTERVAL_RELATION_H_ + + +#include "dl_context.h" +#include "dl_relation_manager.h" +#include "dl_base.h" +#include "old_interval.h" +#include "dl_vector_relation.h" +#include "arith_decl_plugin.h" +#include "basic_simplifier_plugin.h" + +namespace datalog { + + class interval_relation; + + class interval_relation_plugin : public relation_plugin { + v_dependency_manager m_dep; + interval m_empty; + arith_util m_arith; + + class join_fn; + class project_fn; + class rename_fn; + class union_fn; + class filter_equal_fn; + class filter_identical_fn; + class filter_interpreted_fn; + friend class interval_relation; + + interval unite(interval const& src1, interval const& src2); + interval widen(interval const& src1, interval const& src2); + interval meet(interval const& src1, interval const& src2, bool& is_empty); + + v_dependency_manager & dep() const { return const_cast(m_dep); } + + public: + interval_relation_plugin(relation_manager& m); + virtual bool can_handle_signature(const relation_signature & s); + static symbol get_name() { return symbol("interval_relation"); } + virtual relation_base * mk_empty(const relation_signature & s); + virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + + static bool is_empty(unsigned idx, interval const& i); + static bool is_infinite(interval const& i); + + private: + static interval_relation& get(relation_base& r); + static interval_relation const & get(relation_base const& r); + + bool is_linear(expr* e, unsigned& pos, unsigned& neg, rational& k, bool is_pos) const; + + // x + k <= y + bool is_le(app* cond, unsigned& x, rational& k, unsigned& y, bool& is_int) const; + // x + k < y + bool is_lt(app* cond, unsigned& x, rational& k, unsigned& y) const; + // x + k = y + bool is_eq(app* cond, unsigned& x, rational& k, unsigned& y) const; + }; + + + class interval_relation : public vector_relation { + friend class interval_relation_plugin; + friend class interval_relation_plugin::filter_equal_fn; + public: + interval_relation(interval_relation_plugin& p, relation_signature const& s, bool is_empty); + + virtual void add_fact(const relation_fact & f); + virtual bool contains_fact(const relation_fact & f) const; + virtual interval_relation * clone() const; + virtual interval_relation * complement(func_decl*) const; + virtual void to_formula(expr_ref& fml) const; + interval_relation_plugin& get_plugin() const; + + void filter_interpreted(app* cond); + virtual bool is_precise() const { return false; } + + private: + + virtual interval mk_intersect(interval const& t1, interval const& t2, bool& is_empty) const { + return get_plugin().meet(t1, t2, is_empty); + } + + virtual interval mk_unite(interval const& t1, interval const& t2) const { return get_plugin().unite(t1,t2); } + + virtual interval mk_widen(interval const& t1, interval const& t2) const { return get_plugin().widen(t1,t2); } + + virtual bool is_subset_of(interval const& t1, interval const& t2) const { NOT_IMPLEMENTED_YET(); return false; } + + virtual bool is_full(interval const& t) const { + return interval_relation_plugin::is_infinite(t); + } + + virtual bool is_empty(unsigned idx, interval const& t) const { + return interval_relation_plugin::is_empty(idx, t); + } + + virtual void mk_rename_elem(interval& i, unsigned col_cnt, unsigned const* cycle); + + virtual void display_index(unsigned idx, interval const & i, std::ostream& out) const; + + void mk_intersect(unsigned idx, interval const& i); + + }; + +}; + +#endif + diff --git a/src/muz/rel/dl_mk_explanations.cpp b/src/muz/rel/dl_mk_explanations.cpp new file mode 100644 index 000000000..60a10190a --- /dev/null +++ b/src/muz/rel/dl_mk_explanations.cpp @@ -0,0 +1,879 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_mk_explanations.cpp + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-11-08. + +Revision History: + +--*/ + + +#include +#include"ast_pp.h" +#include"ast_smt_pp.h" +#include"dl_finite_product_relation.h" +#include"dl_product_relation.h" +#include"dl_sieve_relation.h" +#include"dl_mk_explanations.h" + +namespace datalog { + + // ----------------------------------- + // + // explanation_relation_plugin declaration + // + // ----------------------------------- + + class explanation_relation; + + class explanation_relation_plugin : public relation_plugin { + friend class explanation_relation; + + class join_fn; + class project_fn; + class rename_fn; + class union_fn; + class foreign_union_fn; + class assignment_filter_fn; + class negation_filter_fn; + class intersection_filter_fn; + + bool m_relation_level_explanations; + + func_decl_ref m_union_decl; + + vector > m_pool; + + + app * mk_union(app * a1, app * a2) { + return get_ast_manager().mk_app(m_union_decl, a1, a2); + } + + public: + static symbol get_name(bool relation_level) { + return symbol(relation_level ? "relation_explanation" : "fact_explanation"); + } + + explanation_relation_plugin(bool relation_level, relation_manager & manager) + : relation_plugin(get_name(relation_level), manager), + m_relation_level_explanations(relation_level), + m_union_decl(mk_explanations::get_union_decl(get_context()), get_ast_manager()) {} + + ~explanation_relation_plugin() { + for (unsigned i = 0; i < m_pool.size(); ++i) { + for (unsigned j = 0; j < m_pool[i].size(); ++j) { + dealloc(m_pool[i][j]); + } + } + } + + virtual bool can_handle_signature(const relation_signature & s) { + unsigned n=s.size(); + for (unsigned i=0; i(relation_base::get_plugin()); + } + + virtual void to_formula(expr_ref& fml) const { + ast_manager& m = fml.get_manager(); + fml = m.mk_eq(m.mk_var(0, m.get_sort(m_data[0])), m_data[0]); + } + + bool is_undefined(unsigned col_idx) const { + return m_data[col_idx]==0; + } + bool no_undefined() const { + if (empty()) { + return true; + } + unsigned n = get_signature().size(); + for (unsigned i=0; i(get_plugin().mk_empty(get_signature())); + res->m_empty = m_empty; + SASSERT(res->m_data.empty()); + res->m_data.append(m_data); + return res; + } + + virtual relation_base * complement(func_decl* pred) const { + explanation_relation * res = static_cast(get_plugin().mk_empty(get_signature())); + if (empty()) { + res->set_undefined(); + } + return res; + } + + void display_explanation(app * expl, std::ostream & out) const { + if (expl) { + //TODO: some nice explanation output + ast_smt_pp pp(get_plugin().get_ast_manager()); + pp.display_expr_smt2(out, expl); + } + else { + out << ""; + } + } + + virtual void display(std::ostream & out) const { + if (empty()) { + out << "\n"; + return; + } + unsigned sz = get_signature().size(); + for (unsigned i=0; i s.size() && !m_pool[s.size()].empty()) { + explanation_relation* r = m_pool[s.size()].back(); + m_pool[s.size()].pop_back(); + r->m_empty = true; + r->m_data.reset(); + return r; + } + return alloc(explanation_relation, *this, s); + } + + void explanation_relation_plugin::recycle(explanation_relation* r) { + relation_signature const& sig = r->get_signature(); + if (m_pool.size() <= sig.size()) { + m_pool.resize(sig.size()+1); + } + m_pool[sig.size()].push_back(r); + } + + + class explanation_relation_plugin::join_fn : public convenient_relation_join_fn { + public: + join_fn(const relation_signature & sig1, const relation_signature & sig2) + : convenient_relation_join_fn(sig1, sig2, 0, 0, 0) {} + + virtual relation_base * operator()(const relation_base & r1_0, const relation_base & r2_0) { + const explanation_relation & r1 = static_cast(r1_0); + const explanation_relation & r2 = static_cast(r2_0); + explanation_relation_plugin & plugin = r1.get_plugin(); + + explanation_relation * res = static_cast(plugin.mk_empty(get_result_signature())); + if (!r1.empty() && !r2.empty()) { + res->m_empty = false; + SASSERT(res->m_data.empty()); + res->m_data.append(r1.m_data); + res->m_data.append(r2.m_data); + } + return res; + } + }; + + relation_join_fn * explanation_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (&r1.get_plugin()!=this || &r2.get_plugin()!=this) { + return 0; + } + if (col_cnt!=0) { + return 0; + } + return alloc(join_fn, r1.get_signature(), r2.get_signature()); + } + + + class explanation_relation_plugin::project_fn : public convenient_relation_project_fn { + public: + project_fn(const relation_signature & sig, unsigned col_cnt, const unsigned * removed_cols) + : convenient_relation_project_fn(sig, col_cnt, removed_cols) {} + + virtual relation_base * operator()(const relation_base & r0) { + const explanation_relation & r = static_cast(r0); + explanation_relation_plugin & plugin = r.get_plugin(); + + explanation_relation * res = static_cast(plugin.mk_empty(get_result_signature())); + if (!r.empty()) { + relation_fact proj_data = r.m_data; + project_out_vector_columns(proj_data, m_removed_cols); + res->assign_data(proj_data); + } + return res; + } + }; + + relation_transformer_fn * explanation_relation_plugin::mk_project_fn(const relation_base & r, unsigned col_cnt, + const unsigned * removed_cols) { + if (&r.get_plugin()!=this) { + return 0; + } + return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); + } + + + class explanation_relation_plugin::rename_fn : public convenient_relation_rename_fn { + public: + rename_fn(const relation_signature & sig, unsigned permutation_cycle_len, const unsigned * permutation_cycle) + : convenient_relation_rename_fn(sig, permutation_cycle_len, permutation_cycle) {} + + virtual relation_base * operator()(const relation_base & r0) { + const explanation_relation & r = static_cast(r0); + explanation_relation_plugin & plugin = r.get_plugin(); + + explanation_relation * res = static_cast(plugin.mk_empty(get_result_signature())); + if (!r.empty()) { + relation_fact permutated_data = r.m_data; + permutate_by_cycle(permutated_data, m_cycle); + res->assign_data(permutated_data); + } + return res; + } + }; + + relation_transformer_fn * explanation_relation_plugin::mk_rename_fn(const relation_base & r, + unsigned permutation_cycle_len, const unsigned * permutation_cycle) { + return alloc(rename_fn, r.get_signature(), permutation_cycle_len, permutation_cycle); + } + + + class explanation_relation_plugin::union_fn : public relation_union_fn { + scoped_ptr m_delta_union_fun; + public: + virtual void operator()(relation_base & tgt0, const relation_base & src0, relation_base * delta0) { + explanation_relation & tgt = static_cast(tgt0); + const explanation_relation & src = static_cast(src0); + explanation_relation * delta = delta0 ? static_cast(delta0) : 0; + explanation_relation_plugin & plugin = tgt.get_plugin(); + + if (!src.no_undefined() || !tgt.no_undefined() || (delta && !delta->no_undefined())) { + UNREACHABLE(); + } + if (src.empty()) { + return; + } + if (plugin.m_relation_level_explanations) { + tgt.unite_with_data(src.m_data); + if (delta) { + if (!m_delta_union_fun) { + m_delta_union_fun = plugin.get_manager().mk_union_fn(*delta, src); + SASSERT(m_delta_union_fun); + } + (*m_delta_union_fun)(*delta, src); + } + } + else { + if (tgt.empty()) { + tgt.assign_data(src.m_data); + if (delta && delta->empty()) { + delta->assign_data(src.m_data); + } + } + } + } + }; + + class explanation_relation_plugin::foreign_union_fn : public relation_union_fn { + scoped_ptr m_delta_union_fun; + public: + virtual void operator()(relation_base & tgt0, const relation_base & src, relation_base * delta0) { + explanation_relation & tgt = static_cast(tgt0); + explanation_relation * delta = delta0 ? static_cast(delta0) : 0; + + if (src.empty()) { + return; + } + tgt.set_undefined(); + if (delta) { + delta->set_undefined(); + } + } + }; + + relation_union_fn * explanation_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (!check_kind(tgt) || (delta && !check_kind(*delta))) { + return 0; + } + if (!check_kind(src)) { + //this is to handle the product relation + return alloc(foreign_union_fn); + } + return alloc(union_fn); + } + + class explanation_relation_plugin::assignment_filter_fn : public relation_mutator_fn { + ast_manager & m_manager; + var_subst & m_subst; + unsigned m_col_idx; + app_ref m_new_rule; + public: + assignment_filter_fn(context & ctx, unsigned col_idx, app_ref new_rule) + : m_manager(ctx.get_manager()), + m_subst(ctx.get_var_subst()), + m_col_idx(col_idx), + m_new_rule(new_rule) {} + + virtual void operator()(relation_base & r0) { + explanation_relation & r = static_cast(r0); + + if (!r.is_undefined(m_col_idx)) { + UNREACHABLE(); + } + + unsigned sz = r.get_signature().size(); + ptr_vector subst_arg; + subst_arg.resize(sz, 0); + unsigned ofs = sz-1; + for (unsigned i=0; iget_arg(0); + expr * arg2 = cond->get_arg(1); + + if (is_var(arg2)) { + std::swap(arg1, arg2); + } + + if (!is_var(arg1) || !is_app(arg2)) { + return 0; + } + var * col_var = to_var(arg1); + app * new_rule = to_app(arg2); + if (!get_context().get_decl_util().is_rule_sort(col_var->get_sort())) { + return 0; + } + unsigned col_idx = col_var->get_idx(); + + return alloc(assignment_filter_fn, get_context(), col_idx, app_ref(new_rule, get_ast_manager())); + } + + + class explanation_relation_plugin::negation_filter_fn : public relation_intersection_filter_fn { + public: + virtual void operator()(relation_base & r, const relation_base & neg) { + if (!neg.empty()) { + r.reset(); + } + } + }; + + relation_intersection_filter_fn * explanation_relation_plugin::mk_filter_by_negation_fn(const relation_base & r, + const relation_base & neg, unsigned joined_col_cnt, const unsigned * t_cols, + const unsigned * negated_cols) { + if (&r.get_plugin()!=this || &neg.get_plugin()!=this) { + return 0; + } + return alloc(negation_filter_fn); + } + + class explanation_relation_plugin::intersection_filter_fn : public relation_intersection_filter_fn { + func_decl_ref m_union_decl; + public: + intersection_filter_fn(explanation_relation_plugin & plugin) + : m_union_decl(plugin.m_union_decl) {} + + virtual void operator()(relation_base & tgt0, const relation_base & src0) { + explanation_relation & tgt = static_cast(tgt0); + const explanation_relation & src = static_cast(src0); + + if (src.empty()) { + tgt.reset(); + return; + } + if (tgt.empty()) { + return; + } + unsigned sz = tgt.get_signature().size(); + for (unsigned i=0; iget_decl()==m_union_decl.get()) { + if (curr_tgt->get_arg(0)==curr_src || curr_tgt->get_arg(1)==curr_src) { + tgt.m_data.set(i, curr_src); + continue; + } + } + //the intersection is imprecise because we do nothing here, but it is good enough for + //the purpose of explanations + } + } + }; + + relation_intersection_filter_fn * explanation_relation_plugin::mk_filter_by_intersection_fn( + const relation_base & tgt, const relation_base & src, unsigned joined_col_cnt, + const unsigned * tgt_cols, const unsigned * src_cols) { + if (&tgt.get_plugin()!=this || &src.get_plugin()!=this) { + return 0; + } + //this checks the join is one to one on all columns + if (tgt.get_signature()!=src.get_signature() + || joined_col_cnt!=tgt.get_signature().size() + || !containers_equal(tgt_cols, tgt_cols+joined_col_cnt, src_cols, src_cols+joined_col_cnt)) { + return 0; + } + counter ctr; + ctr.count(joined_col_cnt, tgt_cols); + if (ctr.get_max_counter_value()>1 || (joined_col_cnt && ctr.get_max_positive()!=joined_col_cnt-1)) { + return 0; + } + return alloc(intersection_filter_fn, *this); + } + + + // ----------------------------------- + // + // mk_explanations + // + // ----------------------------------- + + + mk_explanations::mk_explanations(context & ctx) + : plugin(50000), + m_manager(ctx.get_manager()), + m_context(ctx), + m_decl_util(ctx.get_decl_util()), + m_relation_level(ctx.explanations_on_relation_level()), + m_pinned(m_manager) { + m_e_sort = m_decl_util.mk_rule_sort(); + m_pinned.push_back(m_e_sort); + + relation_manager & rmgr = ctx.get_rel_context()->get_rmanager(); + symbol er_symbol = explanation_relation_plugin::get_name(m_relation_level); + m_er_plugin = static_cast(rmgr.get_relation_plugin(er_symbol)); + if (!m_er_plugin) { + m_er_plugin = alloc(explanation_relation_plugin, m_relation_level, rmgr); + rmgr.register_plugin(m_er_plugin); + if (!m_relation_level) { + DEBUG_CODE( + finite_product_relation_plugin * dummy; + SASSERT(!rmgr.try_get_finite_product_relation_plugin(*m_er_plugin, dummy)); + ); + rmgr.register_plugin(alloc(finite_product_relation_plugin, *m_er_plugin, rmgr)); + } + } + DEBUG_CODE( + if (!m_relation_level) { + finite_product_relation_plugin * dummy; + SASSERT(rmgr.try_get_finite_product_relation_plugin(*m_er_plugin, dummy)); + } + ); + } + + func_decl * mk_explanations::get_union_decl(context & ctx) { + ast_manager & m = ctx.get_manager(); + sort_ref s(ctx.get_decl_util().mk_rule_sort(), m); + //can it happen that the function name would collide with some other symbol? + //if functions can be overloaded by their ranges, it should be fine. + return m.mk_func_decl(symbol("e_union"), s, s, s); + } + + void mk_explanations::assign_rel_level_kind(func_decl * e_decl, func_decl * orig) { + SASSERT(m_relation_level); + + relation_manager & rmgr = m_context.get_rel_context()->get_rmanager(); + unsigned sz = e_decl->get_arity(); + relation_signature sig; + rmgr.from_predicate(e_decl, sig); + + svector inner_sieve(sz-1, true); + inner_sieve.push_back(false); + + svector expl_sieve(sz-1, false); + expl_sieve.push_back(true); + + sieve_relation_plugin & sieve_plugin = sieve_relation_plugin::get_plugin(rmgr); + + family_id inner_kind = rmgr.get_requested_predicate_kind(orig); //may be null_family_id + family_id inner_sieve_kind = sieve_plugin.get_relation_kind(sig, inner_sieve, inner_kind); + family_id expl_kind = m_er_plugin->get_kind(); + family_id expl_sieve_kind = sieve_plugin.get_relation_kind(sig, expl_sieve, expl_kind); + + product_relation_plugin::rel_spec product_spec; + product_spec.push_back(inner_sieve_kind); + product_spec.push_back(expl_sieve_kind); + + family_id pred_kind = + product_relation_plugin::get_plugin(rmgr).get_relation_kind(sig, product_spec); + + rmgr.set_predicate_kind(e_decl, pred_kind); + } + + func_decl * mk_explanations::get_e_decl(func_decl * orig_decl) { + decl_map::obj_map_entry * e = m_e_decl_map.insert_if_not_there2(orig_decl, 0); + if (e->get_data().m_value==0) { + relation_signature e_domain; + e_domain.append(orig_decl->get_arity(), orig_decl->get_domain()); + e_domain.push_back(m_e_sort); + func_decl * new_decl = m_context.mk_fresh_head_predicate(orig_decl->get_name(), symbol("expl"), + e_domain.size(), e_domain.c_ptr(), orig_decl); + m_pinned.push_back(new_decl); + e->get_data().m_value = new_decl; + + if (m_relation_level) { + assign_rel_level_kind(new_decl, orig_decl); + } + } + return e->get_data().m_value; + } + + app * mk_explanations::get_e_lit(app * lit, unsigned e_var_idx) { + expr_ref_vector args(m_manager); + func_decl * e_decl = get_e_decl(lit->get_decl()); + args.append(lit->get_num_args(), lit->get_args()); + args.push_back(m_manager.mk_var(e_var_idx, m_e_sort)); + return m_manager.mk_app(e_decl, args.c_ptr()); + } + + symbol mk_explanations::get_rule_symbol(rule * r) { + if (r->name() == symbol::null) { + std::stringstream sstm; + r->display(m_context, sstm); + std::string res = sstm.str(); + res = res.substr(0, res.find_last_not_of('\n')+1); + return symbol(res.c_str()); + } + else { + return r->name(); + } + } + + rule * mk_explanations::get_e_rule(rule * r) { + rule_counter ctr; + ctr.count_rule_vars(m_manager, r); + unsigned max_var; + unsigned next_var = ctr.get_max_positive(max_var) ? (max_var+1) : 0; + unsigned head_var = next_var++; + app_ref e_head(get_e_lit(r->get_head(), head_var), m_manager); + + app_ref_vector e_tail(m_manager); + svector neg_flags; + unsigned pos_tail_sz = r->get_positive_tail_size(); + for (unsigned i=0; iget_tail(i), e_var)); + neg_flags.push_back(false); + } + unsigned tail_sz = r->get_tail_size(); + for (unsigned i=pos_tail_sz; iget_tail(i)); + neg_flags.push_back(r->is_neg_tail(i)); + } + + symbol rule_repr = get_rule_symbol(r); + + expr_ref_vector rule_expr_args(m_manager); + for (unsigned tail_idx=0; tail_idxget_arg(tail->get_num_args()-1)); + } + else { + //this adds argument values and the explanation term + //(values will be substituted for variables at runtime by the finite_product_relation) + rule_expr_args.append(tail->get_num_args(), tail->get_args()); + } + } + //rule_expr contains rule function with string representation of the rule as symbol and + //for each positive uninterpreted tail it contains its argument values and its explanation term + expr * rule_expr = m_decl_util.mk_rule(rule_repr, rule_expr_args.size(), rule_expr_args.c_ptr()); + + app_ref e_record(m_manager.mk_eq(m_manager.mk_var(head_var, m_e_sort), rule_expr), m_manager); + e_tail.push_back(e_record); + neg_flags.push_back(false); + SASSERT(e_tail.size()==neg_flags.size()); + + return m_context.get_rule_manager().mk(e_head, e_tail.size(), e_tail.c_ptr(), neg_flags.c_ptr()); + } + + void mk_explanations::transform_rules(const rule_set & src, rule_set & dst) { + rule_set::iterator rit = src.begin(); + rule_set::iterator rend = src.end(); + for (; rit!=rend; ++rit) { + rule * e_rule = get_e_rule(*rit); + dst.add_rule(e_rule); + } + + //add rules that will (for output predicates) copy facts from explained relations back to + //the original ones + expr_ref_vector lit_args(m_manager); + decl_set::iterator pit = src.get_output_predicates().begin(); + decl_set::iterator pend = src.get_output_predicates().end(); + for (; pit != pend; ++pit) { + func_decl * orig_decl = *pit; + + lit_args.reset(); + unsigned arity = orig_decl->get_arity(); + for (unsigned i=0; iget_domain(i))); + } + app_ref orig_lit(m_manager.mk_app(orig_decl, lit_args.c_ptr()), m_manager); + app_ref e_lit(get_e_lit(orig_lit, arity), m_manager); + app * tail[] = { e_lit.get() }; + dst.add_rule(m_context.get_rule_manager().mk(orig_lit, 1, tail, 0)); + } + } + + void mk_explanations::translate_rel_level_relation(relation_manager & rmgr, relation_base & orig, + relation_base & e_rel) { + SASSERT(m_e_fact_relation); + SASSERT(e_rel.get_plugin().is_product_relation()); + + product_relation & prod_rel = static_cast(e_rel); + SASSERT(prod_rel.size()==2); + SASSERT(prod_rel[0].get_plugin().is_sieve_relation()); + SASSERT(prod_rel[1].get_plugin().is_sieve_relation()); + sieve_relation * srels[] = { + static_cast(&prod_rel[0]), + static_cast(&prod_rel[1]) }; + if (&srels[0]->get_inner().get_plugin()==m_er_plugin) { + std::swap(srels[0], srels[1]); + } + SASSERT(&srels[0]->get_inner().get_plugin()==&orig.get_plugin()); + SASSERT(&srels[1]->get_inner().get_plugin()==m_er_plugin); + + relation_base & new_orig = srels[0]->get_inner(); + explanation_relation & expl_rel = static_cast(srels[1]->get_inner()); + + { + scoped_ptr orig_union_fun = rmgr.mk_union_fn(new_orig, orig); + SASSERT(orig_union_fun); + (*orig_union_fun)(new_orig, orig); + } + + { + scoped_ptr expl_union_fun = rmgr.mk_union_fn(expl_rel, *m_e_fact_relation); + SASSERT(expl_union_fun); + (*expl_union_fun)(expl_rel, *m_e_fact_relation); + } + } + + void mk_explanations::transform_facts(relation_manager & rmgr, rule_set const& src, rule_set& dst) { + + if (!m_e_fact_relation) { + relation_signature expl_singleton_sig; + expl_singleton_sig.push_back(m_e_sort); + + relation_base * expl_singleton = rmgr.mk_empty_relation(expl_singleton_sig, m_er_plugin->get_kind()); + relation_fact es_fact(m_manager); + es_fact.push_back(m_decl_util.mk_fact(symbol("fact"))); + expl_singleton->add_fact(es_fact); + + SASSERT(&expl_singleton->get_plugin()==m_er_plugin); + m_e_fact_relation = static_cast(expl_singleton); + } + func_decl_set const& predicates = m_context.get_predicates(); + decl_set::iterator it = predicates.begin(); + decl_set::iterator end = predicates.end(); + for (; it!=end; ++it) { + func_decl * orig_decl = *it; + func_decl * e_decl = get_e_decl(orig_decl); + + if (!rmgr.try_get_relation(orig_decl) && + !src.contains(orig_decl)) { + // there are no facts or rules for this predicate + continue; + } + + dst.inherit_predicate(src, orig_decl, e_decl); + + relation_base & orig_rel = rmgr.get_relation(orig_decl); + relation_base & e_rel = rmgr.get_relation(e_decl); + SASSERT(e_rel.empty()); //the e_rel should be a new relation + + if (m_relation_level) { + translate_rel_level_relation(rmgr, orig_rel, e_rel); + } + else { + scoped_ptr product_fun = rmgr.mk_join_fn(orig_rel, *m_e_fact_relation, 0, 0, 0); + SASSERT(product_fun); + scoped_rel aux_extended_rel = (*product_fun)(orig_rel, *m_e_fact_relation); + scoped_ptr union_fun = rmgr.mk_union_fn(e_rel, *aux_extended_rel); + SASSERT(union_fun); + (*union_fun)(e_rel, *aux_extended_rel); + } + } + } + + rule_set * mk_explanations::operator()(rule_set const & source) { + + if (source.empty()) { + return 0; + } + if (!m_context.generate_explanations()) { + return 0; + } + rule_set * res = alloc(rule_set, m_context); + transform_facts(m_context.get_rel_context()->get_rmanager(), source, *res); + transform_rules(source, *res); + return res; + } + +}; + diff --git a/src/muz/rel/dl_mk_explanations.h b/src/muz/rel/dl_mk_explanations.h new file mode 100644 index 000000000..9e4d705c3 --- /dev/null +++ b/src/muz/rel/dl_mk_explanations.h @@ -0,0 +1,86 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_mk_explanations.h + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-11-08. + +Revision History: + +--*/ + +#ifndef _DL_MK_EXPLANATIONS_H_ +#define _DL_MK_EXPLANATIONS_H_ + +#include "dl_context.h" +#include "dl_rule_transformer.h" + +namespace datalog { + + class explanation_relation; + class explanation_relation_plugin; + + class mk_explanations : public rule_transformer::plugin { + + typedef obj_map decl_map; + + ast_manager & m_manager; + context & m_context; + dl_decl_util & m_decl_util; + bool m_relation_level; + ast_ref_vector m_pinned; + explanation_relation_plugin * m_er_plugin; + sort * m_e_sort; + scoped_rel m_e_fact_relation; + + decl_map m_e_decl_map; + + symbol get_rule_symbol(rule * r); + + app * get_e_lit(app * lit, unsigned e_var_idx); + rule * get_e_rule(rule * r); + + /** + If \c m_relation_level is true, ensure \c e_decl predicate will be represented by + the right relation object. \c orig is the predicate corresponding to \c e_decl without + the explanation column. + */ + void assign_rel_level_kind(func_decl * e_decl, func_decl * orig); + void translate_rel_level_relation(relation_manager & rmgr, relation_base & orig, relation_base & e_rel); + + void transform_rules(const rule_set & src, rule_set & dst); + + void transform_facts(relation_manager & rmgr, rule_set const& src, rule_set& dst); + public: + /** + If relation_level is true, the explanation will not be stored for each fact, + but we will rather store history of the whole relation. + */ + mk_explanations(context & ctx); + + /** + \brief Return explanation predicate that corresponds to \c orig_decl. + */ + func_decl * get_e_decl(func_decl * orig_decl); + + static func_decl * get_union_decl(context & ctx); + func_decl * get_union_decl() const { + return get_union_decl(m_context); + } + + rule_set * operator()(rule_set const & source); + + static expr* get_explanation(relation_base const& r); + }; +}; + +#endif /* _DL_MK_EXPLANATIONS_H_ */ + diff --git a/src/muz/rel/dl_mk_partial_equiv.cpp b/src/muz/rel/dl_mk_partial_equiv.cpp new file mode 100644 index 000000000..d79a46720 --- /dev/null +++ b/src/muz/rel/dl_mk_partial_equiv.cpp @@ -0,0 +1,155 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + dl_mk_partial_equiv.cpp + +Abstract: + + Rule transformer which identifies predicates that are partial equivalence relations. + +Author: + + Nikolaj Bjorner (nbjorner) 2012-05-14 + +Revision History: + +--*/ + +#include "dl_mk_partial_equiv.h" +#include "dl_relation_manager.h" +#include "ast_pp.h" + +namespace datalog { + + bool mk_partial_equivalence_transformer::is_symmetry(rule const* r) { + func_decl* p = r->get_decl(); + return + p->get_arity() == 2 && + p->get_domain(0) == p->get_domain(1) && + r->get_tail_size() == 1 && + r->get_tail(0)->get_decl() == p && + r->get_head()->get_arg(0) == r->get_tail(0)->get_arg(1) && + r->get_head()->get_arg(1) == r->get_tail(0)->get_arg(0) && + is_var(r->get_head()->get_arg(0)) && + is_var(r->get_head()->get_arg(1)) && + r->get_head()->get_arg(0) != r->get_head()->get_arg(1); + } + + + bool mk_partial_equivalence_transformer::is_transitivity(rule const* r) { + func_decl* p = r->get_decl(); + if (p->get_arity() != 2 || + p->get_domain(0) != p->get_domain(1) || + r->get_tail_size() != 2 || + r->get_tail(0)->get_decl() != p || + r->get_tail(1)->get_decl() != p) { + return false; + } + app* h = r->get_head(); + app* a = r->get_tail(0); + app* b = r->get_tail(1); + expr* x1 = h->get_arg(0); + expr* x2 = h->get_arg(1); + expr* a1 = a->get_arg(0); + expr* a2 = a->get_arg(1); + expr* b1 = b->get_arg(0); + expr* b2 = b->get_arg(1); + + if (!(is_var(x1) && is_var(x2) && is_var(a1) && is_var(a2) && is_var(b1) && is_var(b2))) { + return false; + } + if (x1 == x2 || a1 == a2 || b1 == b2) { + return false; + } + if (a2 == b1) { + if (x1 == b2 && x2 == a1) { + return true; + } + if (x1 == a1 && x2 == b2) { + return true; + } + return false; + } + if (a1 == b2) { + if (x1 == b1 && x2 == a2) { + return true; + } + if (x1 == a2 && x2 == b1) { + return true; + } + return false; + } + + return false; +; + } + + + rule_set * mk_partial_equivalence_transformer::operator()(rule_set const & source) { + // TODO mc + + if (source.get_num_rules() == 0) { + return 0; + } + + if (m_context.get_engine() != DATALOG_ENGINE) { + return 0; + } + + relation_manager & rm = m_context.get_rel_context()->get_rmanager(); + rule_set::decl2rules::iterator it = source.begin_grouped_rules(); + rule_set::decl2rules::iterator end = source.end_grouped_rules(); + + rule_set* res = alloc(rule_set, m_context); + + for (; it != end; ++it) { + func_decl* p = it->m_key; + rule_vector const& rv = *(it->m_value); + bool has_symmetry = false; + bool has_transitivity = false; + unsigned i_symmetry, i_transitivity; + family_id kind = rm.get_requested_predicate_kind(p); + for (unsigned i = 0; i < rv.size(); ++i) { + + if (kind != null_family_id) { + res->add_rule(rv[i]); + } + else if (is_symmetry(rv[i])) { + i_symmetry = i; + has_symmetry = true; + } + else if (is_transitivity(rv[i])) { + i_transitivity = i; + has_transitivity = true; + } + else { + res->add_rule(rv[i]); + } + } + if (has_symmetry && !has_transitivity) { + res->add_rule(rv[i_symmetry]); + } + else if (!has_symmetry && has_transitivity) { + res->add_rule(rv[i_transitivity]); + } + else if (has_symmetry && has_transitivity) { + TRACE("dl", tout << "updating predicate " << mk_pp(p, m) << " to partial equivalence\n";); + SASSERT(kind == null_family_id); + rm.set_predicate_kind(p, rm.get_table_plugin(symbol("equivalence"))->get_kind()); + } + } + + if (res->get_num_rules() == source.get_num_rules()) { + dealloc(res); + return 0; + } + res->inherit_predicates(source); + + return res; + } + +}; + + diff --git a/src/muz/rel/dl_mk_partial_equiv.h b/src/muz/rel/dl_mk_partial_equiv.h new file mode 100644 index 000000000..54a70b3c0 --- /dev/null +++ b/src/muz/rel/dl_mk_partial_equiv.h @@ -0,0 +1,50 @@ +/*++ +Copyright (c) 2012 Microsoft Corporation + +Module Name: + + dl_mk_partial_equiv.h + +Abstract: + + Rule transformer which identifies predicates that are partial equivalence relations. + +Author: + + Nikolaj Bjorner (nbjorner) 2012-05-14 + +Revision History: + +--*/ + + +#ifndef _DL_MK_PARTIAL_EQUIVALENCE_TRANSFORMER_H_ +#define _DL_MK_PARTIAL_EQUIVALENCE_TRANSFORMER_H_ + +#include "dl_context.h" +#include "dl_rule_transformer.h" + +namespace datalog { + + class mk_partial_equivalence_transformer : public rule_transformer::plugin { + ast_manager & m; + context & m_context; + public: + mk_partial_equivalence_transformer(context & ctx, unsigned priority=45000) + : plugin(priority), + m(ctx.get_manager()), + m_context(ctx) {} + + rule_set * operator()(rule_set const & source); + + private: + + bool is_symmetry(rule const* r); + bool is_transitivity(rule const* r); + }; + +}; + +#endif /* _DL_MK_PARTIAL_EQUIV_TRANSFORMER_H_ */ + + diff --git a/src/muz/rel/dl_mk_similarity_compressor.cpp b/src/muz/rel/dl_mk_similarity_compressor.cpp new file mode 100644 index 000000000..aa2fe8ab9 --- /dev/null +++ b/src/muz/rel/dl_mk_similarity_compressor.cpp @@ -0,0 +1,546 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_mk_similarity_compressor.cpp + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-10-22. + +Revision History: + +--*/ + +#include +#include +#include"dl_mk_similarity_compressor.h" +#include"dl_relation_manager.h" + +namespace datalog { + + mk_similarity_compressor::mk_similarity_compressor(context & ctx) : + plugin(5000), + m_context(ctx), + m_manager(ctx.get_manager()), + m_threshold_count(ctx.similarity_compressor_threshold()), + m_result_rules(ctx.get_rule_manager()), + m_modified(false), + m_pinned(m_manager) { + SASSERT(m_threshold_count>1); + } + + void mk_similarity_compressor::reset() { + m_rules.reset(); + m_result_rules.reset(); + m_pinned.reset(); + } + + /** + Allows to traverse head and positive tails in a single for loop starting from -1 + */ + static app * get_by_tail_index(rule * r, int idx) { + if (idx < 0) { + return r->get_head(); + } + SASSERT(idx < static_cast(r->get_positive_tail_size())); + return r->get_tail(idx); + } + + template + static int aux_compare(T a, T b) { + return (a>b) ? 1 : ( (a==b) ? 0 : -1); + } + + template + static int aux_compare(T* a, T* b); + + static int compare_var_args(app* t1, app* t2) { + SASSERT(t1->get_num_args()==t2->get_num_args()); + int res; + unsigned n = t1->get_num_args(); + for (unsigned i = 0; i < n; i++) { + expr * a1 = t1->get_arg(i); + expr * a2 = t2->get_arg(i); + res = aux_compare(is_var(a1), is_var(a2)); + if (res != 0) { + return res; + } + if (is_var(a1)) { + res = aux_compare(to_var(a1)->get_idx(), to_var(a2)->get_idx()); + if (res != 0) { + return res; + } + } + } + return 0; + } + + static int compare_args(app* t1, app* t2, int & skip_countdown) { + SASSERT(t1->get_num_args()==t2->get_num_args()); + int res; + unsigned n = t1->get_num_args(); + for (unsigned i=0; iget_arg(i))) { + SASSERT(t1->get_arg(i) == t2->get_arg(i)); + continue; + } + if ((skip_countdown--) == 0) { + continue; + } + res = aux_compare(t1->get_arg(i)->get_id(), t2->get_arg(i)->get_id()); + if (res!=0) { return res; } + } + return 0; + } + + /** + \brief Return 0 if r1 and r2 could be similar. If the rough similarity + equaivelance class of r1 is greater than the one of r2, return 1; otherwise return -1. + + Two rules are in the same rough similarity class if they differ only in constant arguments + of positive uninterpreted predicates. + */ + static int rough_compare(rule * r1, rule * r2) { + int res = aux_compare(r1->get_tail_size(), r2->get_tail_size()); + if (res!=0) { return res; } + res = aux_compare(r1->get_uninterpreted_tail_size(), r2->get_uninterpreted_tail_size()); + if (res!=0) { return res; } + res = aux_compare(r1->get_positive_tail_size(), r2->get_positive_tail_size()); + if (res!=0) { return res; } + + int pos_tail_sz = r1->get_positive_tail_size(); + for (int i=-1; iget_decl()->get_id(), t2->get_decl()->get_id()); + if (res!=0) { return res; } + res = compare_var_args(t1, t2); + if (res!=0) { return res; } + } + + unsigned tail_sz = r1->get_tail_size(); + for (unsigned i=pos_tail_sz; iget_tail(i)->get_id(), r2->get_tail(i)->get_id()); + if (res!=0) { return res; } + } + + return 0; + } + + /** + \c r1 and \c r2 must be equal according to the \c rough_compare function for this function + to be called. + */ + static int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) { + SASSERT(rough_compare(r1, r2)==0); + int pos_tail_sz = r1->get_positive_tail_size(); + for (int i=-1; i info_vector; + + static void collect_const_indexes(app * t, int tail_index, info_vector & res) { + unsigned n = t->get_num_args(); + for (unsigned i=0; iget_arg(i))) { + continue; + } + res.push_back(const_info(tail_index, i)); + } + } + + static void collect_const_indexes(rule * r, info_vector & res) { + collect_const_indexes(r->get_head(), -1, res); + unsigned pos_tail_sz = r->get_positive_tail_size(); + for (unsigned i=0; iget_tail(i), i, res); + } + } + + template + static void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) { + unsigned const_cnt = const_infos.size(); + tgt.reset(); + for (unsigned i=0; iget_arg(inf.arg_index()))); + SASSERT(tgt.back()->get_num_args()==0); + } + } + template + static void collect_orphan_sorts(rule * r, const info_vector & const_infos, T & tgt) { + unsigned const_cnt = const_infos.size(); + tgt.reset(); + for (unsigned i=0; iget_decl()->get_domain(inf.arg_index())); + } + } + + /** + \brief From the \c tail_indexes and \c arg_indexes remove elements corresponding to constants + that are the same in rules \c *first ... \c *(after_last-1). + */ + static void remove_stable_constants(rule_vector::iterator first, rule_vector::iterator after_last, + info_vector & const_infos) { + SASSERT(after_last-first>1); + unsigned const_cnt = const_infos.size(); + ptr_vector vals; + rule * r = *(first++); + collect_orphan_consts(r, const_infos, vals); + SASSERT(vals.size()==const_cnt); + rule_vector::iterator it = first; + for (; it!=after_last; ++it) { + for (unsigned i=0; iget_arg(const_infos[i].arg_index())); + if (vals[i]!=val) { + vals[i] = 0; + } + } + } + unsigned removed_cnt = 0; + for (unsigned i=0; i vals; + ptr_vector sorts; + rule * r = *(first++); + collect_orphan_consts(r, const_infos, vals); + collect_orphan_sorts(r, const_infos, sorts); + SASSERT(vals.size()==const_cnt); + vector possible_parents(const_cnt); + for (unsigned i=1; iget_head()->get_num_args() - count_variable_arguments(r->get_head()); + unsigned pos_tail_sz = r->get_positive_tail_size(); + for (unsigned i=0; iget_tail(i)->get_num_args() - count_variable_arguments(r->get_tail(i)); + } + return res; + } + + static bool initial_comparator(rule * r1, rule * r2) { + int res = rough_compare(r1, r2); + if (res!=0) { return res>0; } + return total_compare(r1, r2)>0; + } + + class arg_ignoring_comparator { + unsigned m_ignored_index; + public: + arg_ignoring_comparator(unsigned ignored_index) : m_ignored_index(ignored_index) {} + bool operator()(rule * r1, rule * r2) const { + return total_compare(r1, r2, m_ignored_index)>0; + } + bool eq(rule * r1, rule * r2) const { + return total_compare(r1, r2, m_ignored_index)==0; + } + }; + + void mk_similarity_compressor::merge_class(rule_vector::iterator first, + rule_vector::iterator after_last) { + SASSERT(after_last-first>1); + info_vector const_infos; + rule * r = *first; //an arbitrary representative of the class + collect_const_indexes(r, const_infos); + remove_stable_constants(first, after_last, const_infos); + + unsigned const_cnt = const_infos.size(); + SASSERT(const_cnt>0); + + detect_equal_constants(first, after_last, const_infos); + + + //The aux relation contains column for each constant which does not have an earlier constant + //that it is equal to (i.e. only has no parent) + ptr_vector aux_domain; + collect_orphan_sorts(r, const_infos, aux_domain); + + func_decl* head_pred = r->get_decl(); + symbol const& name_prefix = head_pred->get_name(); + std::string name_suffix = "sc_" + to_string(const_cnt); + func_decl * aux_pred = m_context.mk_fresh_head_predicate(name_prefix, symbol(name_suffix.c_str()), + aux_domain.size(), aux_domain.c_ptr(), head_pred); + m_pinned.push_back(aux_pred); + + relation_fact val_fact(m_manager, const_cnt); + rule_vector::iterator it = first; + for (; it!=after_last; ++it) { + collect_orphan_consts(*it, const_infos, val_fact); + m_context.add_fact(aux_pred, val_fact); + } + m_context.get_rel_context()->get_rmanager().mark_saturated(aux_pred); + + app * new_head = r->get_head(); + ptr_vector new_tail; + svector new_negs; + unsigned tail_sz = r->get_tail_size(); + for (unsigned i=0; iget_tail(i)); + new_negs.push_back(r->is_neg_tail(i)); + } + + rule_counter ctr; + ctr.count_rule_vars(m_manager, r); + unsigned max_var_idx, new_var_idx_base; + if (ctr.get_max_positive(max_var_idx)) { + new_var_idx_base = max_var_idx+1; + } + else { + new_var_idx_base = 0; + } + + ptr_vector const_vars; //variables at indexes of their corresponding constants + expr_ref_vector aux_vars(m_manager); //variables as arguments for the auxiliary predicate + + unsigned aux_column_index = 0; + + for (unsigned i=0; i mod_args(mod_tail->get_num_args(), mod_tail->get_args()); + + for (; iget_decl(), mod_args.c_ptr()); + m_pinned.push_back(upd_tail); + mod_tail = upd_tail; + } + + app_ref aux_tail(m_manager.mk_app(aux_pred, aux_vars.c_ptr()), m_manager); + new_tail.push_back(aux_tail); + new_negs.push_back(false); + + rule * new_rule = m_context.get_rule_manager().mk(new_head, new_tail.size(), new_tail.c_ptr(), + new_negs.c_ptr()); + m_result_rules.push_back(new_rule); + + //TODO: allow for a rule to have multiple parent objects + new_rule->set_accounting_parent_object(m_context, r); + m_modified = true; + } + + void mk_similarity_compressor::process_class(rule_set const& source, rule_vector::iterator first, + rule_vector::iterator after_last) { + SASSERT(first!=after_last); + //remove duplicates + { + rule_vector::iterator it = first; + rule_vector::iterator prev = it; + ++it; + while(it!=after_last) { + if (it!=after_last && total_compare(*prev, *it)==0) { + --after_last; + std::swap(*it, *after_last); + m_modified = true; + } + else { + prev = it; + ++it; + } + } + } + SASSERT(first!=after_last); + + unsigned const_cnt = get_constant_count(*first); +#if 0 + for (unsigned ignored_index=0; ignored_indexm_threshold_count) { + merge_class(grp_begin, it); + //group was processed, so we remove it from the class + if (it==after_last) { + after_last=grp_begin; + it=after_last; + } + else { + while(it!=grp_begin) { + std::swap(*--it, *--after_last); + } + } + } + grp_begin = it; + grp_size = 0; + } + } + } +#endif + //TODO: compress also rules with pairs (or tuples) of equal constants + +#if 1 + if (const_cnt>0 && !source.is_output_predicate((*first)->get_decl())) { + unsigned rule_cnt = static_cast(after_last-first); + if (rule_cnt>m_threshold_count) { + merge_class(first, after_last); + return; + } + } +#endif + + //put rules which weren't merged into result + rule_vector::iterator it = first; + for (; it!=after_last; ++it) { + m_result_rules.push_back(*it); + } + } + + rule_set * mk_similarity_compressor::operator()(rule_set const & source) { + // TODO mc + m_modified = false; + unsigned init_rule_cnt = source.get_num_rules(); + SASSERT(m_rules.empty()); + for (unsigned i=0; i(0); + if (m_modified) { + result = alloc(rule_set, m_context); + unsigned fin_rule_cnt = m_result_rules.size(); + for (unsigned i=0; iadd_rule(m_result_rules.get(i)); + } + result->inherit_predicates(source); + } + reset(); + return result; + } +}; diff --git a/src/muz/rel/dl_mk_similarity_compressor.h b/src/muz/rel/dl_mk_similarity_compressor.h new file mode 100644 index 000000000..34b76e7e1 --- /dev/null +++ b/src/muz/rel/dl_mk_similarity_compressor.h @@ -0,0 +1,78 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_mk_similarity_compressor.h + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-10-22. + +Revision History: + +--*/ +#ifndef _DL_MK_SIMILARITY_COMPRESSOR_H_ +#define _DL_MK_SIMILARITY_COMPRESSOR_H_ + +#include + +#include"map.h" +#include"obj_pair_hashtable.h" + +#include"dl_context.h" +#include"dl_rule_set.h" +#include"dl_rule_transformer.h" + +namespace datalog { + + /** + \brief Functor for merging groups of similar rules. + + A rule sequence + + P("1",x):-Q(x). + ... + P("N",x):-Q(x). + + will be replaced by + + P(y,x):-Q(x), Aux(y). + + and a set of facts + + Aux("1"). + ... + Aux("N"). + + Similar transformation is performed when the varying constant appears in the positive tail. + */ + class mk_similarity_compressor : public rule_transformer::plugin { + + context & m_context; + ast_manager & m_manager; + /** number of similar rules necessary for a group to be introduced */ + unsigned m_threshold_count; + rule_vector m_rules; + rule_ref_vector m_result_rules; + bool m_modified; + ast_ref_vector m_pinned; + + void merge_class(rule_vector::iterator first, rule_vector::iterator after_last); + void process_class(rule_set const& source, rule_vector::iterator first, rule_vector::iterator after_last); + + void reset(); + public: + mk_similarity_compressor(context & ctx); + + rule_set * operator()(rule_set const & source); + }; + +}; + +#endif /* _DL_MK_SIMILARITY_COMPRESSOR_H_ */ + diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp new file mode 100644 index 000000000..4b9ce582a --- /dev/null +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -0,0 +1,742 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_mk_simple_joins.cpp + +Abstract: + + + +Author: + + Leonardo de Moura (leonardo) 2010-05-20. + +Revision History: + +--*/ + +#include +#include +#include +#include"dl_mk_simple_joins.h" +#include"dl_relation_manager.h" +#include"ast_pp.h" +#include"trace.h" + + +namespace datalog { + + mk_simple_joins::mk_simple_joins(context & ctx): + plugin(1000), + m_context(ctx), + rm(ctx.get_rule_manager()) { + } + + class join_planner { + typedef float cost; + + class pair_info { + cost m_total_cost; + /** + \brief Number of rules longer than two that contain this pair. + + This number is being updated by \c add_rule and \remove rule. Even though between + adding a rule and removing it, the length of a rule can decrease without this pair + being notified about it, it will surely see the decrease from length 3 to 2 which + the threshold for rule being counted in this counter. + */ + unsigned m_consumers; + bool m_stratified; + unsigned m_src_stratum; + public: + var_idx_set m_all_nonlocal_vars; + rule_vector m_rules; + + pair_info() : m_consumers(0), m_stratified(true), m_src_stratum(0) {} + + bool can_be_joined() const { + return m_consumers>0; + } + + cost get_cost() const { + /*if(m_instantiated) { + return std::numeric_limits::min(); + }*/ + SASSERT(m_consumers>0); + cost amortized = m_total_cost/m_consumers; + if(m_stratified) { + return amortized * ( (amortized>0) ? (1/16.0f) : 16.0f); + } + else { + return amortized; + } + } + + /** + \brief Add rule \c r among rules interested in current predicate pair. + + The \c pl.m_rule_content entry of the rule has to be properly filled in + by the time of a call to this function + */ + void add_rule(join_planner & pl, app * t1, app * t2, rule * r, + const var_idx_set & non_local_vars_normalized) { + if(m_rules.empty()) { + m_total_cost = pl.compute_cost(t1, t2); + m_src_stratum = std::max(pl.get_stratum(t1->get_decl()), pl.get_stratum(t2->get_decl())); + } + m_rules.push_back(r); + if(pl.m_rules_content.find_core(r)->get_data().m_value.size()>2) { + m_consumers++; + } + if(m_stratified) { + unsigned head_stratum = pl.get_stratum(r->get_decl()); + SASSERT(head_stratum>=m_src_stratum); + if(head_stratum==m_src_stratum) { + m_stratified = false; + } + } + idx_set_union(m_all_nonlocal_vars, non_local_vars_normalized); + } + /** + \brief Remove rule from the pair record. Return true if no rules remain + in the pair, and so it should be removed. + */ + bool remove_rule(rule * r, unsigned original_length) { + TRUSTME( remove_from_vector(m_rules, r) ); + if(original_length>2) { + SASSERT(m_consumers>0); + m_consumers--; + } + SASSERT(!m_rules.empty() || m_consumers==0); + return m_rules.empty(); + } + private: + pair_info & operator=(const pair_info &); //to avoid the implicit one + }; + typedef std::pair app_pair; + typedef map, obj_ptr_hash >, default_eq > cost_map; + typedef map, ptr_hash, ptr_eq > rule_pred_map; + + context & m_context; + ast_manager & m; + rule_manager & rm; + var_subst & m_var_subst; + rule_set & m_rs_aux_copy; //reference to a rule_set that will allow to ask for stratum levels + + cost_map m_costs; + ptr_vector m_interpreted; + rule_pred_map m_rules_content; + rule_ref_vector m_introduced_rules; + ptr_hashtable, ptr_eq > m_modified_rules; + + ast_ref_vector m_pinned; + mutable ptr_vector m_vars; + + public: + join_planner(context & ctx, rule_set & rs_aux_copy) + : m_context(ctx), m(ctx.get_manager()), + rm(ctx.get_rule_manager()), + m_var_subst(ctx.get_var_subst()), + m_rs_aux_copy(rs_aux_copy), + m_introduced_rules(ctx.get_rule_manager()), + m_pinned(ctx.get_manager()) + { + } + + ~join_planner() + { + cost_map::iterator it = m_costs.begin(); + cost_map::iterator end = m_costs.end(); + for (; it != end; ++it) { + dealloc(it->m_value); + } + m_costs.reset(); + } + private: + + void get_normalizer(app * t, unsigned & next_var, expr_ref_vector & result) const { + SASSERT(result.size()>0); + unsigned res_ofs = result.size()-1; + unsigned n=t->get_num_args(); + for(unsigned i=0; iget_arg(i))); + var * v = to_var(t->get_arg(i)); + unsigned var_idx = v->get_idx(); + if(result[res_ofs-var_idx]==0) { + result[res_ofs-var_idx]=m.mk_var(next_var, v->get_sort()); + next_var++; + } + } + } + + void get_normalizer(app * t1, app * t2, expr_ref_vector & result) const { + SASSERT(result.empty()); + if(t1->get_num_args()==0 && t2->get_num_args()==0) { + return; //nothing to normalize + } + SASSERT(!t1->is_ground() || !t2->is_ground()); + + unsigned max_var_idx = 0; + { + var_idx_set& orig_var_set = rm.collect_vars(t1, t2); + var_idx_set::iterator ovit = orig_var_set.begin(); + var_idx_set::iterator ovend = orig_var_set.end(); + for(; ovit!=ovend; ++ovit) { + unsigned var_idx = *ovit; + if(var_idx>max_var_idx) { + max_var_idx = var_idx; + } + } + } + + if(t1->get_decl()!=t2->get_decl()) { + if(t1->get_decl()->get_id()get_decl()->get_id()) { + std::swap(t1, t2); + } + } + else { + int_vector norm1(max_var_idx+1, -1); + int_vector norm2(max_var_idx+1, -1); + unsigned n=t1->get_num_args(); + SASSERT(n==t2->get_num_args()); + for(unsigned i=0; iget_arg(i)); + var * v2 = to_var(t2->get_arg(i)); + if(v1->get_sort()!=v2->get_sort()) { + //different sorts mean we can distinguish the two terms + if(v1->get_sort()->get_id()get_sort()->get_id()) { + std::swap(t1, t2); + } + break; + } + unsigned v1_idx = v1->get_idx(); + unsigned v2_idx = v2->get_idx(); + //since the rules already went through the mk_filter_rules transformer, + //variables must be linear + SASSERT(norm1[v1_idx]==-1); + SASSERT(norm2[v2_idx]==-1); + + if(norm2[v1_idx]!=norm1[v2_idx]) { + //now we can distinguish the two terms + if(norm2[v1_idx](0)); + unsigned next_var = 0; + get_normalizer(t1, next_var, result); + get_normalizer(t2, next_var, result); + } + + app_pair get_key(app * t1, app * t2) { + expr_ref_vector norm_subst(m); + get_normalizer(t1, t2, norm_subst); + expr_ref t1n_ref(m); + expr_ref t2n_ref(m); + m_var_subst(t1, norm_subst.size(), norm_subst.c_ptr(), t1n_ref); + m_var_subst(t2, norm_subst.size(), norm_subst.c_ptr(), t2n_ref); + app * t1n = to_app(t1n_ref); + app * t2n = to_app(t2n_ref); + if(t1n>t2n) { + std::swap(t1n, t2n); + } + m_pinned.push_back(t1n); + m_pinned.push_back(t2n); + + /* + IF_VERBOSE(0, + print_renaming(norm_subst, verbose_stream()); + display_predicate(m_context, t1, verbose_stream()); + display_predicate(m_context, t2, verbose_stream()); + display_predicate(m_context, t1n, verbose_stream()); + display_predicate(m_context, t2n, verbose_stream());); + */ + return app_pair(t1n, t2n); + } + + /** + \brief Add rule \c r among rules interested in predicate pair \c t1, \c t2. + + The \c m_rule_content entry of the rule \c r has to be properly filled in + by the time of a call to this function + */ + void register_pair(app * t1, app * t2, rule * r, const var_idx_set & non_local_vars) { + TRACE("dl", tout << mk_pp(t1, m) << " " << mk_pp(t2, m) << "\n"; + r->display(m_context, tout); tout << "\n";); + SASSERT(t1!=t2); + cost_map::entry * e = m_costs.insert_if_not_there2(get_key(t1, t2), 0); + pair_info * & ptr_inf = e->get_data().m_value; + if(ptr_inf==0) { + ptr_inf = alloc(pair_info); + } + pair_info & inf = *ptr_inf; + + expr_ref_vector normalizer(m); + get_normalizer(t1, t2, normalizer); + unsigned norm_ofs = normalizer.size()-1; + var_idx_set normalized_vars; + var_idx_set::iterator vit = non_local_vars.begin(); + var_idx_set::iterator vend = non_local_vars.end(); + for(; vit!=vend; ++vit) { + unsigned norm_var = to_var(normalizer.get(norm_ofs-*vit))->get_idx(); + normalized_vars.insert(norm_var); + } + + inf.add_rule(*this, t1, t2, r, normalized_vars); + } + + pair_info & get_pair(app_pair key) const { + cost_map::entry * e = m_costs.find_core(key); + SASSERT(e); + return *e->get_data().m_value; + } + + void remove_rule_from_pair(app_pair key, rule * r, unsigned original_len) { + pair_info * ptr = &get_pair(key); + if(ptr->remove_rule(r, original_len)) { + SASSERT(ptr->m_rules.empty()); + m_costs.remove(key); + dealloc(ptr); + } + } + + void register_rule(rule * r) { + rule_counter counter; + counter.count_rule_vars(m, r, 1); + + ptr_vector & rule_content = + m_rules_content.insert_if_not_there2(r, ptr_vector())->get_data().m_value; + SASSERT(rule_content.empty()); + + unsigned pos_tail_size=r->get_positive_tail_size(); + for(unsigned i=0; iget_tail(i)); + } + for(unsigned i=0; iget_tail(i); + var_idx_set t1_vars = rm.collect_vars(t1); + counter.count_vars(m, t1, -1); //temporarily remove t1 variables from counter + for(unsigned j=i+1; jget_tail(j); + counter.count_vars(m, t2, -1); //temporarily remove t2 variables from counter + var_idx_set scope_vars = rm.collect_vars(t2); + scope_vars |= t1_vars; + var_idx_set non_local_vars; + counter.collect_positive(non_local_vars); + counter.count_vars(m, t2, 1); //restore t2 variables in counter + set_intersection(non_local_vars, scope_vars); + register_pair(t1, t2, r, non_local_vars); + } + counter.count_vars(m, t1, 1); //restore t1 variables in counter + } + } + + bool extract_argument_info(unsigned var_idx, app * t, expr_ref_vector & args, + ptr_vector & domain) { + unsigned n=t->get_num_args(); + for(unsigned i=0; iget_arg(i)); + if(v->get_idx()==var_idx) { + args.push_back(v); + domain.push_back(m.get_sort(v)); + return true; + } + } + return false; + } + + void join_pair(app_pair pair_key) { + app * t1 = pair_key.first; + app * t2 = pair_key.second; + pair_info & inf = get_pair(pair_key); + SASSERT(!inf.m_rules.empty()); + var_idx_set & output_vars = inf.m_all_nonlocal_vars; + expr_ref_vector args(m); + ptr_vector domain; + + unsigned arity = output_vars.num_elems(); + idx_set::iterator ovit=output_vars.begin(); + idx_set::iterator ovend=output_vars.end(); + //TODO: improve quadratic complexity + for(;ovit!=ovend;++ovit) { + unsigned var_idx=*ovit; + + bool found=extract_argument_info(var_idx, t1, args, domain); + if(!found) { + found=extract_argument_info(var_idx, t2, args, domain); + } + SASSERT(found); + } + + SASSERT(args.size()==arity); + SASSERT(domain.size()==arity); + + rule * one_parent = inf.m_rules.back(); + + func_decl* parent_head = one_parent->get_decl(); + const char * one_parent_name = parent_head->get_name().bare_str(); + std::string parent_name; + if(inf.m_rules.size()>1) { + parent_name = one_parent_name + std::string("_and_") + to_string(inf.m_rules.size()-1); + } + else { + parent_name = one_parent_name; + } + + func_decl * decl = m_context.mk_fresh_head_predicate( + symbol(parent_name.c_str()), symbol("split"), + arity, domain.c_ptr(), parent_head); + + app_ref head(m.mk_app(decl, arity, args.c_ptr()), m); + + app * tail[] = {t1, t2}; + + rule * new_rule = m_context.get_rule_manager().mk(head, 2, tail, 0); + + //TODO: update accounting so that it can handle multiple parents + new_rule->set_accounting_parent_object(m_context, one_parent); + + m_introduced_rules.push_back(new_rule); + + //here we copy the inf.m_rules vector because inf.m_rules will get changed + //in the iteration. Also we use hashtable instead of vector because we do + //not want to process one rule twice. + typedef ptr_hashtable, default_eq > rule_hashtable; + rule_hashtable relevant_rules; + insert_into_set(relevant_rules, inf.m_rules); + rule_hashtable::iterator rit = relevant_rules.begin(); + rule_hashtable::iterator rend = relevant_rules.end(); + for(; rit!=rend; ++rit) { + apply_binary_rule(*rit, pair_key, head); + } + + // SASSERT(!m_costs.contains(pair_key)); + } + + void replace_edges(rule * r, const ptr_vector & removed_tails, + const ptr_vector & added_tails0, const ptr_vector & rule_content) { + SASSERT(removed_tails.size()>=added_tails0.size()); + unsigned len = rule_content.size(); + unsigned original_len = len+removed_tails.size()-added_tails0.size(); + ptr_vector added_tails(added_tails0); //we need a copy since we'll be modifying it + + unsigned rt_sz = removed_tails.size(); + //remove edges between removed tails + for(unsigned i=0; iget_head(); + + var_counter counter; + counter.count_vars(m, head, 1); + + unsigned tail_size=r->get_tail_size(); + unsigned pos_tail_size=r->get_positive_tail_size(); + + for(unsigned i=pos_tail_size; iget_tail(i), 1); + } + for(unsigned i=0; i & rule_content = m_rules_content.find_core(r)->get_data().m_value; + unsigned len = rule_content.size(); + if(len==1) { + return; + } + + func_decl * t1_pred = t1->get_decl(); + func_decl * t2_pred = t2->get_decl(); + ptr_vector removed_tails; + ptr_vector added_tails; + for(unsigned i1=0; i1get_decl()!=t1_pred) { + continue; + } + unsigned i2start = (t1_pred==t2_pred) ? (i1+1) : 0; + for(unsigned i2=i2start; i2get_decl()!=t2_pred) { + continue; + } + if(get_key(rt1, rt2)!=pair_key) { + continue; + } + expr_ref_vector normalizer(m); + get_normalizer(rt1, rt2, normalizer); + expr_ref_vector denormalizer(m); + reverse_renaming(m, normalizer, denormalizer); + expr_ref new_transf(m); + m_var_subst(t_new, denormalizer.size(), denormalizer.c_ptr(), new_transf); + app * new_lit = to_app(new_transf); + + m_pinned.push_back(new_lit); + rule_content[i1]=new_lit; + rule_content[i2]=rule_content.back(); + rule_content.pop_back(); + len--; //here the bound of both loops changes!!! + removed_tails.push_back(rt1); + removed_tails.push_back(rt2); + added_tails.push_back(new_lit); + //this exits the inner loop, the outer one continues in case there will + //be other matches + break; + } + } + SASSERT(!removed_tails.empty()); + SASSERT(!added_tails.empty()); + m_modified_rules.insert(r); + replace_edges(r, removed_tails, added_tails, rule_content); + } + + cost get_domain_size(func_decl * pred, unsigned arg_index) const { + relation_sort sort = pred->get_domain(arg_index); + return static_cast(m_context.get_sort_size_estimate(sort)); + //unsigned sz; + //if(!m_context.get_sort_size(sort, sz)) { + // sz=UINT_MAX; + //} + //return static_cast(sz); + } + + unsigned get_stratum(func_decl * pred) const { + return m_rs_aux_copy.get_predicate_strat(pred); + } + + cost estimate_size(app * t) const { + func_decl * pred = t->get_decl(); + unsigned n=pred->get_arity(); + rel_context_base* rel = m_context.get_rel_context(); + if (!rel) { + return cost(1); + } + relation_manager& rm = rel->get_rmanager(); + if( (m_context.saturation_was_run() && rm.try_get_relation(pred)) + || rm.is_saturated(pred)) { + SASSERT(rm.try_get_relation(pred)); //if it is saturated, it should exist + unsigned rel_size_int = rel->get_relation(pred).get_size_estimate_rows(); + if(rel_size_int!=0) { + cost rel_size = static_cast(rel_size_int); + cost curr_size = rel_size; + for(unsigned i=0; iget_arg(i))) { + curr_size /= get_domain_size(pred, i); + } + } + return curr_size; + } + } + cost res = 1; + for(unsigned i=0; iget_arg(i))) { + res *= get_domain_size(pred, i); + } + } + return res; + } + + cost compute_cost(app * t1, app * t2) const { + func_decl * t1_pred = t1->get_decl(); + func_decl * t2_pred = t2->get_decl(); + cost inters_size = 1; + variable_intersection vi(m_context.get_manager()); + vi.populate(t1, t2); + unsigned n = vi.size(); + for(unsigned i=0; i0) { + res /= 2; + } + else { + res *= 2; + } + } + }*/ + + TRACE("report_costs", + display_predicate(m_context, t1, tout); + display_predicate(m_context, t2, tout); + tout << res << "\n";); + return res; + } + + + bool pick_best_pair(app_pair & p) { + app_pair best; + bool found = false; + cost best_cost; + + cost_map::iterator it = m_costs.begin(); + cost_map::iterator end = m_costs.end(); + for(; it!=end; ++it) { + app_pair key = it->m_key; + pair_info & inf = *it->m_value; + if(!inf.can_be_joined()) { + continue; + } + cost c = inf.get_cost(); + if(!found || cm_key; + ptr_vector content = rcit->m_value; + SASSERT(content.size()<=2); + if(content.size()==orig_r->get_positive_tail_size()) { + //rule did not change + result->add_rule(orig_r); + continue; + } + + ptr_vector tail(content); + svector negs(tail.size(), false); + unsigned or_len = orig_r->get_tail_size(); + for(unsigned i=orig_r->get_positive_tail_size(); iget_tail(i)); + negs.push_back(orig_r->is_neg_tail(i)); + } + + rule * new_rule = m_context.get_rule_manager().mk(orig_r->get_head(), tail.size(), tail.c_ptr(), + negs.c_ptr()); + + new_rule->set_accounting_parent_object(m_context, orig_r); + m_context.get_rule_manager().mk_rule_rewrite_proof(*orig_r, *new_rule); + result->add_rule(new_rule); + } + while (!m_introduced_rules.empty()) { + result->add_rule(m_introduced_rules.back()); + m_context.get_rule_manager().mk_rule_asserted_proof(*m_introduced_rules.back()); + m_introduced_rules.pop_back(); + } + result->inherit_predicates(source); + return result; + } + }; + + rule_set * mk_simple_joins::operator()(rule_set const & source) { + rule_set rs_aux_copy(m_context); + rs_aux_copy.replace_rules(source); + if(!rs_aux_copy.is_closed()) { + rs_aux_copy.close(); + } + + join_planner planner(m_context, rs_aux_copy); + + return planner.run(source); + } + + +}; + diff --git a/src/muz/rel/dl_mk_simple_joins.h b/src/muz/rel/dl_mk_simple_joins.h new file mode 100644 index 000000000..36eb08dd5 --- /dev/null +++ b/src/muz/rel/dl_mk_simple_joins.h @@ -0,0 +1,63 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_mk_simple_joins.h + +Abstract: + + + +Author: + + Leonardo de Moura (leonardo) 2010-05-20. + +Revision History: + +--*/ +#ifndef _DL_MK_SIMPLE_JOINS_H_ +#define _DL_MK_SIMPLE_JOINS_H_ + +#include"map.h" +#include"obj_pair_hashtable.h" + +#include"dl_context.h" +#include"dl_rule_set.h" +#include"dl_rule_transformer.h" + +namespace datalog { + + /** + \brief Functor for creating rules that contain simple joins. + A simple join is the join of two tables. + + After applying this transformation, every rule has at most one join. + So, the rules will have the form + + HEAD :- TAIL. + HEAD :- TAIL_1, TAIL_2. + + We also assume a rule may contain interpreted expressions that work as filtering conditions. + So, we may also have: + + HEAD :- TAIL, C_1, ..., C_n. + HEAD :- TAIL_1, TAIL_2, C_1, ..., C_n. + + Where the C_i's are interpreted expressions. + + We say that a rule containing C_i's is a rule with a "big tail". + */ + class mk_simple_joins : public rule_transformer::plugin { + context & m_context; + rule_manager & rm; + public: + mk_simple_joins(context & ctx); + + rule_set * operator()(rule_set const & source); + }; + +}; + +#endif /* _DL_MK_SIMPLE_JOINS_H_ */ + diff --git a/src/muz/rel/dl_product_relation.cpp b/src/muz/rel/dl_product_relation.cpp new file mode 100644 index 000000000..48cd666e6 --- /dev/null +++ b/src/muz/rel/dl_product_relation.cpp @@ -0,0 +1,1117 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + dl_product_relation.cpp + +Abstract: + + A Relation combinator. + +Author: + + Nikolaj Bjorner (nbjorner) 2010-4-11 + +Revision History: + +Notes: + + join = + more refined version lets augment the product + relation as a consequence of join. + join Q = + join = + + + u = + more refined version: + < (R u R') n (R u S') n (R' u S), (S u S') n (S u R') n (S' u R)> + + + proj = < proj R, proj S> + + & phi = + attach S to [R & phi] whenever R & phi can propagate to S + + + [rename] = + + + +--*/ + + +#include "dl_sieve_relation.h" +#include "dl_table_relation.h" +#include "dl_product_relation.h" +#include "bool_rewriter.h" +#include "ast_pp.h" + +namespace datalog { + + // ----------------------------------- + // + // product_relation_plugin + // + // ----------------------------------- + + product_relation_plugin & product_relation_plugin::get_plugin(relation_manager & rmgr) { + product_relation_plugin * res = + static_cast(rmgr.get_relation_plugin(get_name())); + if(!res) { + res = alloc(product_relation_plugin, rmgr); + rmgr.register_plugin(res); + } + return *res; + } + + product_relation_plugin::product_relation_plugin(relation_manager& m): + relation_plugin(product_relation_plugin::get_name(), m, ST_PRODUCT_RELATION), + m_spec_store(*this) { + } + + void product_relation_plugin::initialize(family_id fid) { + relation_plugin::initialize(fid); + m_spec_store.add_available_kind(get_kind()); + } + + family_id product_relation_plugin::get_relation_kind(const relation_signature & sig, const rel_spec & spec) { + return m_spec_store.get_relation_kind(sig, spec); + } + + family_id product_relation_plugin::get_relation_kind(const product_relation & r) { + return get_relation_kind(r.get_signature(), r.m_spec); + } + + bool product_relation_plugin::can_handle_signature(const relation_signature & s) { + return m_spec_store.contains_signature(s); + } + + bool product_relation_plugin::can_handle_signature(const relation_signature & s, family_id k) { + return true; + } + + product_relation& product_relation_plugin::get(relation_base& r) { + return dynamic_cast(r); + } + + product_relation const & product_relation_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + + product_relation* product_relation_plugin::get(relation_base* r) { + return dynamic_cast(r); + } + + product_relation const* product_relation_plugin::get(relation_base const* r) { + return dynamic_cast(r); + } + + bool product_relation_plugin::is_product_relation(relation_base const& r) { + return r.get_plugin().get_name() == product_relation_plugin::get_name(); + } + + bool product_relation_plugin::are_aligned(const product_relation& r1, const product_relation& r2) { + unsigned sz = r1.size(); + if(sz!=r2.size()) { + return false; + } + for(unsigned i=0; i & rels, + rel_spec & res) { + vector specs; + ptr_vector::const_iterator rit = rels.begin(); + ptr_vector::const_iterator rend = rels.end(); + for(; rit!=rend; ++rit) { + specs.push_back((*rit)->m_spec); + } + + vector::iterator sit = specs.begin(); + vector::iterator send = specs.end(); + for(; sit!=send; ++sit) { + rel_spec & s = *sit; + std::sort(s.begin(), s.end()); + } + + res.reset(); + for(;;) { + family_id next = -1; + + sit = specs.begin(); + for(; sit!=send; ++sit) { + rel_spec & s = *sit; + if(!s.empty() && s.back()>next) { + next = s.back(); + } + } + if(next==-1) { + //we're done + break; + } + res.push_back(next); + sit = specs.begin(); + for(; sit!=send; ++sit) { + rel_spec & s = *sit; + if(!s.empty() && s.back()==next) { + s.pop_back(); + } + } + } + } + + + relation_base * product_relation_plugin::mk_empty(const relation_signature & s) { + return alloc(product_relation,*this, s); + } + + relation_base * product_relation_plugin::mk_empty(const relation_signature & s, family_id kind) { + rel_spec spec; + m_spec_store.get_relation_spec(s, kind, spec); + relation_vector inner_rels; + unsigned rel_cnt = spec.size(); + for(unsigned i=0; i m_joins; + ptr_vector m_full; + unsigned_vector m_offset1; + svector m_kind1; + unsigned_vector m_offset2; + svector m_kind2; + + const relation_base & get_nonsieve_relation(const relation_base & r) { + relation_plugin & rp = r.get_plugin(); + if(rp.is_sieve_relation()) { + return static_cast(r).get_inner(); + } + else { + return r; + } + } + + relation_plugin & get_nonsieve_plugin(const relation_base & r) { + return get_nonsieve_relation(r).get_plugin(); + } + + family_id get_nonsieve_kind(const relation_base & r) { + return get_nonsieve_relation(r).get_kind(); + } + + /** + A tableish relatio is either a table_relation or a sieve_relation with a table_relation inside. + */ + bool is_tableish_relation(const relation_base & r) { + return get_nonsieve_plugin(r).from_table(); + } + + relation_base * get_full_tableish_relation(const relation_signature & sig, func_decl* p, family_id kind) { + relation_manager& rmgr = m_plugin.get_manager(); + table_signature tsig; + if(rmgr.relation_signature_to_table(sig, tsig)) { + return rmgr.mk_table_relation(sig, rmgr.get_appropriate_plugin(tsig).mk_full(p, tsig, kind)); + } + unsigned sz = sig.size(); + tsig.reset(); + for(unsigned i=0; i relations; + unsigned sz = m_joins.size(); + relation_base* result = 0; + for (unsigned i = 0; i < sz; ++i) { + relation_base const& r1 = (m_kind1[i] == T_FULL)?(*m_full[m_offset1[i]]):access(m_offset1[i], _r1); + relation_base const& r2 = (m_kind2[i] == T_FULL)?(*m_full[m_offset2[i]]):access(m_offset2[i], _r2); + relations.push_back((*m_joins[i])(r1, r2)); + } + result = alloc(product_relation, m_plugin, get_result_signature(), sz, relations.c_ptr()); + TRACE("dl",result->display(tout);); + return result; + } + }; + + relation_join_fn * product_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (is_product_relation(r1) && is_product_relation(r2)) { + return alloc(join_fn, *this, get(r1), get(r2), col_cnt, cols1, cols2); + } + if (is_product_relation(r1)) { + return alloc(join_fn, *this, get(r1), r2, col_cnt, cols1, cols2); + } + if (is_product_relation(r2)) { + return alloc(join_fn, *this, r1, get(r2), col_cnt, cols1, cols2); + } + if (r1.get_kind() != r2.get_kind()) { + return alloc(join_fn, *this, r1, r2, col_cnt, cols1, cols2); + } + return 0; + } + + + class product_relation_plugin::transform_fn : public relation_transformer_fn { + relation_signature m_sig; + ptr_vector m_transforms; + public: + transform_fn(relation_signature s, unsigned num_trans, relation_transformer_fn** trans): + m_sig(s), + m_transforms(num_trans, trans) {} + + ~transform_fn() { dealloc_ptr_vector_content(m_transforms); } + + virtual relation_base * operator()(const relation_base & _r) { + product_relation const& r = get(_r); + product_relation_plugin& p = r.get_plugin(); + SASSERT(m_transforms.size() == r.size()); + ptr_vector relations; + for (unsigned i = 0; i < r.size(); ++i) { + relations.push_back((*m_transforms[i])(r[i])); + } + relation_base* result = alloc(product_relation, p, m_sig, relations.size(), relations.c_ptr()); + TRACE("dl", _r.display(tout); result->display(tout);); + return result; + } + }; + + relation_transformer_fn * product_relation_plugin::mk_project_fn(const relation_base & _r, + unsigned col_cnt, const unsigned * removed_cols) { + if (is_product_relation(_r)) { + product_relation const& r = get(_r); + ptr_vector projs; + for (unsigned i = 0; i < r.size(); ++i) { + projs.push_back(get_manager().mk_project_fn(r[i], col_cnt, removed_cols)); + } + relation_signature s; + relation_signature::from_project(r.get_signature(), col_cnt, removed_cols, s); + return alloc(transform_fn, s, projs.size(), projs.c_ptr()); + } + return 0; + } + + relation_transformer_fn * product_relation_plugin::mk_rename_fn(const relation_base & _r, + unsigned cycle_len, const unsigned * permutation_cycle) { + if(is_product_relation(_r)) { + ptr_vector trans; + product_relation const& r = get(_r); + for (unsigned i = 0; i < r.size(); ++i) { + trans.push_back(get_manager().mk_rename_fn(r[i], cycle_len, permutation_cycle)); + } + relation_signature s; + relation_signature::from_rename(r.get_signature(), cycle_len, permutation_cycle, s); + return alloc(transform_fn, s, trans.size(), trans.c_ptr()); + } + return 0; + } + + class product_relation_plugin::aligned_union_fn : public relation_union_fn { + relation_manager & m_rmgr; + bool m_is_widen; + + //m_union[i][j] is union between i-th and j-th relation. + //It can be zero which means that particular union should be skipped. + vector > m_unions; + + void mk_union_fn(unsigned i, unsigned j, relation_base const& r1, relation_base const& r2, + const relation_base* delta) { + relation_manager& rmgr = r1.get_manager(); + relation_union_fn* u = 0; + if (m_is_widen) { + u = rmgr.mk_widen_fn(r1, r2, delta); + } + else { + u = rmgr.mk_union_fn(r1, r2, delta); + } + m_unions.back().push_back(u); + } + + void init(const relation_vector & tgts, const relation_vector & srcs, const relation_vector * deltas) { + SASSERT(tgts.size()==srcs.size()); + unsigned num = tgts.size(); + for (unsigned i = 0; i < num; ++i) { + relation_base& r1 = *tgts[i]; + relation_base* delta = deltas ? (*deltas)[i] : 0; + m_unions.push_back(ptr_vector()); + for (unsigned j = 0; j < num; ++j) { + relation_base& r2 = *srcs[j]; + mk_union_fn(i, j, r1, r2, delta); + } + } + } + + bool can_do_inner_union(unsigned tgt_idx, unsigned src_idx) { + return m_unions[tgt_idx][src_idx]!=0; + } + + void do_inner_union(unsigned tgt_idx, unsigned src_idx, relation_base& tgt, + relation_base& src, relation_base * delta) { + SASSERT(m_unions[tgt_idx][src_idx]); + (*m_unions[tgt_idx][src_idx])(tgt, src, delta); + } + + /** + If tgt is zero, it is assumed to be a full relation. + */ + void do_destructive_intersection(scoped_rel& tgt, scoped_rel& src) { + if(!src) { + return; + } + if(!tgt) { + tgt=src.release(); + return; + } + do_intersection(*tgt, *src); + src = 0; + } + + void do_intersection(relation_base& tgt, relation_base& src) { + scoped_ptr intersect_fun = + m_rmgr.mk_filter_by_intersection_fn(tgt, src); + if(!intersect_fun) { + warning_msg("intersection does not exist"); + return; + } + (*intersect_fun)(tgt, src); + } + void do_delta_union(unsigned rel_idx, relation_base& tgt, relation_base& src) { + scoped_ptr union_fun = m_rmgr.mk_union_fn(tgt, src); + SASSERT(union_fun); + (*union_fun)(tgt, src); + } + public: + aligned_union_fn(product_relation const& tgt, product_relation const& src, product_relation const* delta, + bool is_widen) : + m_rmgr(tgt.get_manager()), + m_is_widen(is_widen) { + SASSERT(vectors_equal(tgt.m_spec, src.m_spec)); + SASSERT(!delta || vectors_equal(tgt.m_spec, delta->m_spec)); + init(tgt.m_relations, src.m_relations, delta ? &delta->m_relations : 0); + } + + ~aligned_union_fn() { + unsigned sz = m_unions.size(); + for(unsigned i=0; i side_results; + ptr_vector side_deltas; + + for (unsigned i = 0; i < num; ++i) { + relation_base& itgt = tgt[i]; + relation_base* idelta = delta ? &(*delta)[i] : 0; + + scoped_rel fresh_delta = idelta ? idelta->get_plugin().mk_empty(*idelta) : 0; + scoped_rel side_result; + scoped_rel side_delta; + + //compute the side unions with which we will intersect the result of the basic one + for (unsigned j = 0; j < num; ++j) { + if (i == j) { + continue; //this is the basic union which we will perform later + } + if (can_do_inner_union(i, j)) { + TRACE("dl", itgt.display(tout << "tgt:\n"); src[j].display(tout << "src:\n");); + // union[i][j] + scoped_rel one_side_union = itgt.clone(); + scoped_rel one_side_delta = fresh_delta ? fresh_delta->clone() : 0; + TRACE("dl", one_side_union->display(tout << "union 1:\n"); src[j].display(tout);); + do_inner_union(i, j, *one_side_union, src[j], one_side_delta.get()); + TRACE("dl", one_side_union->display(tout << "union:\n");); + do_destructive_intersection(side_result, one_side_union); + TRACE("dl", + side_result->display(tout << "inner-union: " << i << " " << j << "\n"); + itgt.display(tout << "tgt:\n");); + if (one_side_delta) { + do_destructive_intersection(side_delta, one_side_delta); + } + + // union[j][i] + one_side_union = src[i].clone(); + one_side_delta = fresh_delta ? fresh_delta->clone() : 0; + TRACE("dl", one_side_union->display(tout << "union 2:\n"); tgt[j].display(tout);); + do_inner_union(i, j, *one_side_union, tgt[j], one_side_delta.get()); + TRACE("dl", one_side_union->display(tout << "union:\n");); + do_destructive_intersection(side_result, one_side_union); + TRACE("dl", + side_result->display(tout << "inner-union: " << i << " " << j << "\n"); + itgt.display(tout << "tgt:\n");); + if (one_side_delta) { + do_destructive_intersection(side_delta, one_side_delta); + } + } + } + side_results.push_back(side_result.release()); + side_deltas.push_back(side_delta.release()); + } + for (unsigned i = 0; i < num; ++i) { + relation_base& itgt = tgt[i]; + relation_base* idelta = delta ? &(*delta)[i] : 0; + scoped_rel fresh_delta = idelta ? idelta->get_plugin().mk_empty(*idelta) : 0; + scoped_rel side_result(side_results[i]); + scoped_rel side_delta(side_deltas[i]); + + // perform the basic union + // assume a relation can always perform union with the relation of the same type + VERIFY(can_do_inner_union(i,i)); + do_inner_union(i, i, itgt, src[i], fresh_delta.get()); + + if (side_result) { + do_intersection(itgt, *side_result); + TRACE("dl", side_result->display(tout << "inner-union-end: " << i << "\n");); + } + if (fresh_delta) { + do_destructive_intersection(fresh_delta,side_delta); + SASSERT(idelta); + do_delta_union(i, *idelta, *fresh_delta); + } + } + if (num == 0) { + //we need to handle product relation of no relations separately + if (!src.m_default_empty && tgt.m_default_empty) { + tgt.m_default_empty = false; + if (delta) { + delta->m_default_empty = false; + } + } + } + TRACE("dl", _tgt.display(tout << "dst':\n"); + if (_delta) _delta->display(tout << "delta:\n"); ;); + } + }; + + class product_relation_plugin::unaligned_union_fn : public relation_union_fn { + bool m_is_widen; + rel_spec m_common_spec; + scoped_ptr m_aligned_union_fun; + public: + unaligned_union_fn(product_relation const& tgt, product_relation const& src, + product_relation const* delta, bool is_widen) : m_is_widen(is_widen) { + ptr_vector rels; + rels.push_back(&tgt); + rels.push_back(&src); + if(delta) { + rels.push_back(delta); + } + get_common_spec(rels, m_common_spec); + } + + + virtual void operator()(relation_base& _tgt, const relation_base& _src, relation_base* _delta) { + TRACE("dl", _tgt.display(tout << "dst:\n"); _src.display(tout << "src:\n");); + product_relation& tgt = get(_tgt); + product_relation const& src0 = get(_src); + product_relation* delta = _delta ? get(_delta) : 0; + + tgt.convert_spec(m_common_spec); + if(delta) { + delta->convert_spec(m_common_spec); + } + scoped_rel src_scoped; + if(src0.get_kind()!=tgt.get_kind()) { + src_scoped = src0.clone(); + src_scoped->convert_spec(m_common_spec); + } + product_relation const& src = src_scoped ? *src_scoped : src0; + + if(!m_aligned_union_fun) { + m_aligned_union_fun = alloc(aligned_union_fn, tgt, src, delta, m_is_widen); + SASSERT(m_aligned_union_fun); + } + (*m_aligned_union_fun)(tgt, src, delta); + TRACE("dl", _tgt.display(tout << "dst':\n"); + if (_delta) _delta->display(tout << "delta:\n");); + } + }; + + class product_relation_plugin::single_non_transparent_src_union_fn : public relation_union_fn { + unsigned m_single_rel_idx; + scoped_ptr m_inner_union_fun; + public: + single_non_transparent_src_union_fn(unsigned single_rel_idx, relation_union_fn* inner_union_fun) + : m_single_rel_idx(single_rel_idx), + m_inner_union_fun(inner_union_fun) {} + + virtual void operator()(relation_base& tgt, const relation_base& _src, relation_base* delta) { + product_relation const& src = get(_src); + (*m_inner_union_fun)(tgt, src[m_single_rel_idx], delta); + } + }; + + relation_union_fn * product_relation_plugin::mk_union_w_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta, bool is_widen) { + if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) { + if(are_aligned(get(tgt), get(src)) && (!delta || are_aligned(get(tgt), *get(delta)))) { + return alloc(aligned_union_fn, get(tgt), get(src), get(delta), is_widen); + } + return alloc(unaligned_union_fn, get(tgt), get(src), get(delta), is_widen); + } + if(check_kind(src)) { + const product_relation & p_src = get(src); + unsigned single_idx; + if(p_src.try_get_single_non_transparent(single_idx)) { + relation_union_fn * inner; + if(is_widen) { + inner = get_manager().mk_widen_fn(tgt, p_src[single_idx], delta); + } + else { + inner = get_manager().mk_union_fn(tgt, p_src[single_idx], delta); + } + if(inner) { + return alloc(single_non_transparent_src_union_fn, single_idx, inner); + } + } + } + return 0; + } + + relation_union_fn * product_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + return mk_union_w_fn(tgt, src, delta, false); + } + + relation_union_fn * product_relation_plugin::mk_widen_fn( + const relation_base & tgt, const relation_base & src, const relation_base * delta) { + return mk_union_w_fn(tgt, src, delta, true); + } + + class product_relation_plugin::mutator_fn : public relation_mutator_fn { + ptr_vector m_mutators; + public: + mutator_fn(unsigned sz, relation_mutator_fn** muts): + m_mutators(sz, muts) {} + + ~mutator_fn() { dealloc_ptr_vector_content(m_mutators); } + + virtual void operator()(relation_base & _r) { + TRACE("dl", _r.display(tout);); + product_relation& r = get(_r); + SASSERT(m_mutators.size() == r.size()); + for (unsigned i = 0; i < r.size(); ++i) { + relation_mutator_fn* m = m_mutators[i]; + if (m) { + (*m)(r[i]); + } + } + TRACE("dl", _r.display(tout);); + } + }; + + + relation_mutator_fn * product_relation_plugin::mk_filter_identical_fn( + const relation_base & _t, unsigned col_cnt, const unsigned * identical_cols) { + + if(is_product_relation(_t)) { + bool found = false; + product_relation const& r = get(_t); + ptr_vector mutators; + for (unsigned i = 0; i < r.size(); ++i) { + relation_mutator_fn* m = get_manager().mk_filter_identical_fn(r[i], col_cnt, identical_cols); + mutators.push_back(m); + if (m) found = true; + } + if (found) { + return alloc(mutator_fn, mutators.size(), mutators.c_ptr()); + } + } + return 0; + } + + relation_mutator_fn * product_relation_plugin::mk_filter_equal_fn(const relation_base & _t, + const relation_element & value, unsigned col) { + if(is_product_relation(_t)) { + product_relation const& r = get(_t); + ptr_vector mutators; + bool found = false; + for (unsigned i = 0; i < r.size(); ++i) { + relation_mutator_fn* m = get_manager().mk_filter_equal_fn(r[i], value, col); + mutators.push_back(m); + if (m) found = true; + } + if (found) { + return alloc(mutator_fn, mutators.size(), mutators.c_ptr()); + } + } + return 0; + } + + class product_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { + ptr_vector m_mutators; + svector > m_attach; + public: + + filter_interpreted_fn(product_relation const& r, app* cond) { + for (unsigned i = 0; i < r.size(); ++i) { + m_mutators.push_back(r.get_manager().mk_filter_interpreted_fn(r[i], cond)); + } + for (unsigned i = 0; i < r.size(); ++i) { + relation_mutator_fn& m1 = *(m_mutators[i]); + for (unsigned j = i + 1; j < r.size(); ++j) { + relation_mutator_fn& m2 = *(m_mutators[j]); + if (m1.supports_attachment(r[j])) { + m_attach.push_back(std::make_pair(i,j)); + } + if (m2.supports_attachment(r[i])) { + m_attach.push_back(std::make_pair(j,i)); + } + } + } + } + + ~filter_interpreted_fn() { dealloc_ptr_vector_content(m_mutators); } + + void operator()(relation_base& _r) { + TRACE("dl", _r.display(tout);); + product_relation const& r = get(_r); + for (unsigned i = 0; i < m_attach.size(); ++i) { + m_mutators[m_attach[i].first]->attach(r[m_attach[i].second]); + } + for (unsigned i = 0; i < m_mutators.size(); ++i) { + (*m_mutators[i])(r[i]); + } + TRACE("dl", _r.display(tout);); + } + }; + + relation_mutator_fn * product_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { + return alloc(filter_interpreted_fn, get(t), condition); + } + + + // ----------------------------------- + // + // product_relation + // + // ----------------------------------- + + product_relation::product_relation(product_relation_plugin& p, relation_signature const& s): + relation_base(p, s), + m_default_empty(true) { + ensure_correct_kind(); + } + + product_relation::product_relation(product_relation_plugin& p, relation_signature const& s, unsigned num_relations, relation_base** relations) : + relation_base(p, s), + m_default_empty(true) { + for (unsigned i = 0; i < num_relations; ++i) { + SASSERT(relations[i]->get_signature()==s); + m_relations.push_back(relations[i]); + } + ensure_correct_kind(); + } + + product_relation::~product_relation() { + unsigned num_relations = m_relations.size(); + for (unsigned i = 0; i < num_relations; ++i) { + m_relations[i]->deallocate(); + } + } + + product_relation_plugin& product_relation::get_plugin() const { + return dynamic_cast(relation_base::get_plugin()); + } + + void product_relation::ensure_correct_kind() { + unsigned rel_cnt = m_relations.size(); + //the rel_cnt==0 part makes us to update the kind also when the relation is newly created + bool spec_changed = rel_cnt!=m_spec.size() || rel_cnt==0; + if(spec_changed) { + m_spec.resize(rel_cnt); + } + for(unsigned i=0;iget_kind(); + if(spec_changed || m_spec[i]!=rkind) { + spec_changed = true; + m_spec[i]=rkind; + } + } + if(spec_changed) { + family_id new_kind = get_plugin().get_relation_kind(*this); + set_kind(new_kind); + } + } + + void product_relation::convert_spec(const rel_spec & spec) { + + func_decl* p = 0; + const relation_signature & sig = get_signature(); + family_id new_kind = get_plugin().get_relation_kind(sig, spec); + if(new_kind==get_kind()) { + return; + } + + unsigned old_sz = size(); + unsigned new_sz = spec.size(); + unsigned old_remain = old_sz; + relation_vector new_rels; + + //the loop is quadratic with the number of relations, maybe we want to fix it + for(unsigned i=0; iget_kind()==ikind) { + irel = m_relations[j]; + m_relations[j] = 0; + old_remain--; + break; + } + } + if(!irel) { + if(old_sz==0 && m_default_empty) { + //The relation didn't contain any inner relations but it was empty, + //so we make the newly added relations empty as well. + irel = get_manager().mk_empty_relation(sig, new_kind); + } + else { + irel = get_manager().mk_full_relation(sig, p, new_kind); + } + } + new_rels.push_back(irel); + } + SASSERT(old_remain==0); //the new specification must be a superset of the old one + m_relations = new_rels; + + set_kind(new_kind); + DEBUG_CODE( + ensure_correct_kind(); + SASSERT(get_kind()==new_kind); + ); + } + + bool product_relation::try_get_single_non_transparent(unsigned & idx) const { + unsigned sz = size(); + bool found = false; + unsigned candidate; + for(unsigned i=0; i relations; + for (unsigned i = 0; i < size(); ++i) { + relations.push_back((*this)[i].clone()); + } + product_relation_plugin& p = get_plugin(); + return alloc(product_relation, p, get_signature(), relations.size(), relations.c_ptr()); + } + + product_relation * product_relation::complement(func_decl*) const { + if(m_relations.empty()) { + product_relation * res = clone(); + res->m_default_empty = !m_default_empty; + return res; + } + UNREACHABLE(); + return 0; + } + + bool product_relation::empty() const { + if(m_relations.empty()) { + return m_default_empty; + } + for (unsigned i = 0; i < m_relations.size(); ++i) { + if (m_relations[i]->empty()) { + return true; + } + } + return false; + } + + void product_relation::to_formula(expr_ref& fml) const { + ast_manager& m = fml.get_manager(); + expr_ref_vector conjs(m); + expr_ref tmp(m); + for (unsigned i = 0; i < m_relations.size(); ++i) { + m_relations[i]->to_formula(tmp); + conjs.push_back(tmp); + } + bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), fml); + } + + void product_relation::display(std::ostream & out) const { + out<<"Product of the following relations:\n"; + for (unsigned i = 0; i < m_relations.size(); ++i) { + m_relations[i]->display(out); + } + } + +}; + + + diff --git a/src/muz/rel/dl_product_relation.h b/src/muz/rel/dl_product_relation.h new file mode 100644 index 000000000..0633ddbf1 --- /dev/null +++ b/src/muz/rel/dl_product_relation.h @@ -0,0 +1,191 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + dl_product_relation.h + +Abstract: + + A Relation relation combinator. + +Author: + + Nikolaj Bjorner (nbjorner) 2010-4-11 + +Revision History: + +--*/ +#ifndef _DL_PRODUCT_RELATION_H_ +#define _DL_PRODUCT_RELATION_H_ + + +#include "dl_context.h" +#include "dl_relation_manager.h" + +namespace datalog { + + class product_relation; + + class product_relation_plugin : public relation_plugin { + friend class product_relation; + public: + typedef svector rel_spec; + private: + class join_fn; + class transform_fn; + class mutator_fn; + class aligned_union_fn; + class unaligned_union_fn; + class single_non_transparent_src_union_fn; + class filter_equal_fn; + class filter_identical_fn; + class filter_interpreted_fn; + struct fid_hash { + typedef family_id data; + unsigned operator()(data x) const { return static_cast(x); } + }; + + rel_spec_store > m_spec_store; + + family_id get_relation_kind(const product_relation & r); + + bool is_product_relation(relation_base * r) { return r->get_plugin().is_product_relation(); } + + public: + static product_relation_plugin& get_plugin(relation_manager & rmgr); + + product_relation_plugin(relation_manager& m); + + virtual void initialize(family_id fid); + + virtual bool can_handle_signature(const relation_signature & s); + virtual bool can_handle_signature(const relation_signature & s, family_id kind); + + static symbol get_name() { return symbol("product_relation"); } + + family_id get_relation_kind(const relation_signature & sig, const rel_spec & spec); + + virtual relation_base * mk_empty(const relation_signature & s); + virtual relation_base * mk_empty(const relation_signature & s, family_id kind); + + virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + virtual relation_base * mk_full(func_decl* p, const relation_signature & s, family_id kind); + + protected: + virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + + static bool is_product_relation(relation_base const& r); + + private: + static product_relation& get(relation_base& r); + static product_relation const & get(relation_base const& r); + static product_relation* get(relation_base* r); + static product_relation const* get(relation_base const* r); + + relation_union_fn * mk_union_w_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta, bool is_widen); + + bool are_aligned(const product_relation& r1, const product_relation& r2); + static void get_common_spec(const ptr_vector & rels, rel_spec & res); + }; + + + class product_relation : public relation_base { + friend class product_relation_plugin; + + friend class product_relation_plugin::join_fn; + friend class product_relation_plugin::transform_fn; + friend class product_relation_plugin::mutator_fn; + friend class product_relation_plugin::aligned_union_fn; + friend class product_relation_plugin::unaligned_union_fn; + friend class product_relation_plugin::single_non_transparent_src_union_fn; + friend class product_relation_plugin::filter_equal_fn; + friend class product_relation_plugin::filter_identical_fn; + friend class product_relation_plugin::filter_interpreted_fn; + + + + typedef product_relation_plugin::rel_spec rel_spec; + + /** + If m_relations is empty, value of this determines whether the relation is empty or full. + */ + bool m_default_empty; + + /** + There must not be two relations of the same kind + */ + ptr_vector m_relations; + + /** + Array of kinds of inner relations. + + If two product relations have equal signature and specification, their + m_relations arrays contain corresponding relations at the same indexes. + + The value returned by get_kind() depends uniquely on the specification. + */ + rel_spec m_spec; + + /** + \brief Ensure the kind assigned to this relation reflects the types of inner relations. + */ + void ensure_correct_kind(); + /** + The current specification must be a subset of the new one. + */ + void convert_spec(const rel_spec & spec); + public: + product_relation(product_relation_plugin& p, relation_signature const& s); + product_relation(product_relation_plugin& p, relation_signature const& s, unsigned num_relations, relation_base** relations); + + ~product_relation(); + + virtual bool empty() const; + virtual void add_fact(const relation_fact & f); + virtual bool contains_fact(const relation_fact & f) const; + virtual product_relation * clone() const; + virtual product_relation * complement(func_decl* p) const; + virtual void display(std::ostream & out) const; + virtual void to_formula(expr_ref& fml) const; + product_relation_plugin& get_plugin() const; + + unsigned size() const { return m_relations.size(); } + relation_base& operator[](unsigned i) const { return *m_relations[i]; } + + /** + If all relations except one are sieve_relations with no inner columns, + return true and into \c idx assign index of that relation. Otherwise return + false. + */ + bool try_get_single_non_transparent(unsigned & idx) const; + + virtual bool is_precise() const { + for (unsigned i = 0; i < m_relations.size(); ++i) { + if (!m_relations[i]->is_precise()) { + return false; + } + } + return true; + } + }; + +}; + +#endif + diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp new file mode 100644 index 000000000..457ef28c0 --- /dev/null +++ b/src/muz/rel/dl_relation_manager.cpp @@ -0,0 +1,1702 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_relation_manager.cpp + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-14. + +Revision History: + +--*/ + + +#include +#include"ast_pp.h" +#include"dl_check_table.h" +#include"dl_context.h" +#include"dl_finite_product_relation.h" +#include"dl_product_relation.h" +#include"dl_sieve_relation.h" +#include"dl_table_relation.h" +#include"dl_relation_manager.h" + +namespace datalog { + + relation_manager::~relation_manager() { + reset(); + } + + + void relation_manager::reset_relations() { + relation_map::iterator it=m_relations.begin(); + relation_map::iterator end=m_relations.end(); + for(;it!=end;++it) { + func_decl * pred = it->m_key; + get_context().get_manager().dec_ref(pred); //inc_ref in get_relation + relation_base * r=(*it).m_value; + r->deallocate(); + } + m_relations.reset(); + } + + void relation_manager::reset() { + reset_relations(); + + m_favourite_table_plugin = static_cast(0); + m_favourite_relation_plugin = static_cast(0); + dealloc_ptr_vector_content(m_table_plugins); + m_table_plugins.reset(); + dealloc_ptr_vector_content(m_relation_plugins); + m_relation_plugins.reset(); + m_next_table_fid = 0; + m_next_relation_fid = 0; + } + + dl_decl_util & relation_manager::get_decl_util() const { + return get_context().get_decl_util(); + } + + family_id relation_manager::get_next_relation_fid(relation_plugin & claimer) { + unsigned res = m_next_relation_fid++; + m_kind2plugin.insert(res, &claimer); + return res; + } + + void relation_manager::set_predicate_kind(func_decl * pred, family_id kind) { + SASSERT(!m_relations.contains(pred)); + m_pred_kinds.insert(pred, kind); + } + + family_id relation_manager::get_requested_predicate_kind(func_decl * pred) { + family_id res; + if(m_pred_kinds.find(pred, res)) { + return res; + } + else { + return null_family_id; + } + } + + relation_base & relation_manager::get_relation(func_decl * pred) { + relation_base * res = try_get_relation(pred); + if(!res) { + relation_signature sig; + from_predicate(pred, sig); + family_id rel_kind = get_requested_predicate_kind(pred); + res = mk_empty_relation(sig, rel_kind); + store_relation(pred, res); + } + return *res; + } + + relation_base * relation_manager::try_get_relation(func_decl * pred) const { + relation_base * res = 0; + if(!m_relations.find(pred, res)) { + return 0; + } + SASSERT(res); + return res; + } + + void relation_manager::store_relation(func_decl * pred, relation_base * rel) { + SASSERT(rel); + relation_map::entry * e = m_relations.insert_if_not_there2(pred, 0); + if (e->get_data().m_value) { + e->get_data().m_value->deallocate(); + } + else { + get_context().get_manager().inc_ref(pred); //dec_ref in reset + } + e->get_data().m_value = rel; + } + + void relation_manager::collect_non_empty_predicates(decl_set & res) const { + relation_map::iterator it = m_relations.begin(); + relation_map::iterator end = m_relations.end(); + for(; it!=end; ++it) { + if(!it->m_value->empty()) { + res.insert(it->m_key); + } + } + } + + void relation_manager::restrict_predicates(const decl_set & preds) { + typedef ptr_vector fd_vector; + fd_vector to_remove; + + relation_map::iterator rit = m_relations.begin(); + relation_map::iterator rend = m_relations.end(); + for(; rit!=rend; ++rit) { + func_decl * pred = rit->m_key; + if (!preds.contains(pred)) { + to_remove.insert(pred); + } + } + + fd_vector::iterator pit = to_remove.begin(); + fd_vector::iterator pend = to_remove.end(); + for(; pit!=pend; ++pit) { + func_decl * pred = *pit; + relation_base * rel; + VERIFY( m_relations.find(pred, rel) ); + rel->deallocate(); + m_relations.remove(pred); + get_context().get_manager().dec_ref(pred); + } + + set_intersection(m_saturated_rels, preds); + } + + void relation_manager::register_plugin(table_plugin * plugin) { + plugin->initialize(get_next_table_fid()); + m_table_plugins.push_back(plugin); + + if(plugin->get_name()==get_context().default_table()) { + m_favourite_table_plugin = plugin; + } + + table_relation_plugin * tr_plugin = alloc(table_relation_plugin, *plugin, *this); + register_relation_plugin_impl(tr_plugin); + m_table_relation_plugins.insert(plugin, tr_plugin); + + symbol checker_name = get_context().default_table_checker(); + if(get_context().default_table_checked() && get_table_plugin(checker_name)) { + if( m_favourite_table_plugin && + (plugin==m_favourite_table_plugin || plugin->get_name()==checker_name) ) { + symbol checked_name = get_context().default_table(); + //the plugins we need to create the checking plugin were just added + SASSERT(m_favourite_table_plugin->get_name()==get_context().default_table()); + table_plugin * checking_plugin = alloc(check_table_plugin, *this, checker_name, checked_name); + register_plugin(checking_plugin); + m_favourite_table_plugin = checking_plugin; + } + if(m_favourite_relation_plugin && m_favourite_relation_plugin->from_table()) { + table_relation_plugin * fav_rel_plugin = + static_cast(m_favourite_relation_plugin); + if(&fav_rel_plugin->get_table_plugin()==plugin || plugin->get_name()==checker_name) { + //the plugins we need to create the checking table_relation_plugin were just added + SASSERT(m_favourite_relation_plugin->get_name() == + get_context().default_relation()); + symbol checked_name = fav_rel_plugin->get_table_plugin().get_name(); + table_plugin * checking_plugin = alloc(check_table_plugin, *this, checker_name, checked_name); + register_plugin(checking_plugin); + + table_relation_plugin * checking_tr_plugin = + alloc(table_relation_plugin, *checking_plugin, *this); + register_relation_plugin_impl(checking_tr_plugin); + m_table_relation_plugins.insert(checking_plugin, checking_tr_plugin); + m_favourite_relation_plugin = checking_tr_plugin; + } + } + } + + } + + void relation_manager::register_relation_plugin_impl(relation_plugin * plugin) { + m_relation_plugins.push_back(plugin); + plugin->initialize(get_next_relation_fid(*plugin)); + if (plugin->get_name() == get_context().default_relation()) { + m_favourite_relation_plugin = plugin; + } + if(plugin->is_finite_product_relation()) { + finite_product_relation_plugin * fprp = static_cast(plugin); + relation_plugin * inner = &fprp->get_inner_plugin(); + m_finite_product_relation_plugins.insert(inner, fprp); + } + } + + relation_plugin * relation_manager::try_get_appropriate_plugin(const relation_signature & s) { + if(m_favourite_relation_plugin && m_favourite_relation_plugin->can_handle_signature(s)) { + return m_favourite_relation_plugin; + } + relation_plugin_vector::iterator rpit = m_relation_plugins.begin(); + relation_plugin_vector::iterator rpend = m_relation_plugins.end(); + for(; rpit!=rpend; ++rpit) { + if((*rpit)->can_handle_signature(s)) { + return *rpit; + } + } + return 0; + } + + relation_plugin & relation_manager::get_appropriate_plugin(const relation_signature & s) { + relation_plugin * res = try_get_appropriate_plugin(s); + if (!res) { + throw default_exception("no suitable plugin found for given relation signature"); + } + return *res; + } + + table_plugin * relation_manager::try_get_appropriate_plugin(const table_signature & t) { + if (m_favourite_table_plugin && m_favourite_table_plugin->can_handle_signature(t)) { + return m_favourite_table_plugin; + } + table_plugin_vector::iterator tpit = m_table_plugins.begin(); + table_plugin_vector::iterator tpend = m_table_plugins.end(); + for(; tpit!=tpend; ++tpit) { + if((*tpit)->can_handle_signature(t)) { + return *tpit; + } + } + return 0; + } + + table_plugin & relation_manager::get_appropriate_plugin(const table_signature & t) { + table_plugin * res = try_get_appropriate_plugin(t); + if(!res) { + throw default_exception("no suitable plugin found for given table signature"); + } + return *res; + } + + relation_plugin * relation_manager::get_relation_plugin(symbol const& s) { + relation_plugin_vector::iterator rpit = m_relation_plugins.begin(); + relation_plugin_vector::iterator rpend = m_relation_plugins.end(); + for(; rpit!=rpend; ++rpit) { + if((*rpit)->get_name()==s) { + return *rpit; + } + } + return 0; + } + + relation_plugin & relation_manager::get_relation_plugin(family_id kind) { + SASSERT(kind>=0); + SASSERT(kindget_name()==k) { + return *tpit; + } + } + return 0; + } + + table_relation_plugin & relation_manager::get_table_relation_plugin(table_plugin & tp) { + table_relation_plugin * res; + VERIFY( m_table_relation_plugins.find(&tp, res) ); + return *res; + } + + bool relation_manager::try_get_finite_product_relation_plugin(const relation_plugin & inner, + finite_product_relation_plugin * & res) { + return m_finite_product_relation_plugins.find(&inner, res); + } + + table_base * relation_manager::mk_empty_table(const table_signature & s) { + return get_appropriate_plugin(s).mk_empty(s); + } + + + bool relation_manager::is_non_explanation(relation_signature const& s) const { + dl_decl_util & decl_util = get_context().get_decl_util(); + unsigned n = s.size(); + for(unsigned i = 0; i < n; i++) { + if(decl_util.is_rule_sort(s[i])) { + return false; + } + } + return true; + } + + relation_base * relation_manager::mk_empty_relation(const relation_signature & s, func_decl* pred) { + return mk_empty_relation(s, get_requested_predicate_kind(pred)); + } + + relation_base * relation_manager::mk_empty_relation(const relation_signature & s, family_id kind) { + if (kind != null_family_id) { + relation_plugin & plugin = get_relation_plugin(kind); + if (plugin.can_handle_signature(s, kind)) + return plugin.mk_empty(s, kind); + } + relation_base * res; + relation_plugin* p = m_favourite_relation_plugin; + + if (p && p->can_handle_signature(s)) { + return p->mk_empty(s); + } + + if (mk_empty_table_relation(s, res)) { + return res; + } + + for (unsigned i = 0; i < m_relation_plugins.size(); ++i) { + p = m_relation_plugins[i]; + if (p->can_handle_signature(s)) { + return p->mk_empty(s); + } + } + + //If there is no plugin to handle the signature, we just create an empty product relation and + //stuff will be added to it by later operations. + return product_relation_plugin::get_plugin(*this).mk_empty(s); + } + + + relation_base * relation_manager::mk_table_relation(const relation_signature & s, table_base * table) { + SASSERT(s.size()==table->get_signature().size()); + return get_table_relation_plugin(table->get_plugin()).mk_from_table(s, table); + } + + bool relation_manager::mk_empty_table_relation(const relation_signature & s, relation_base * & result) { + table_signature tsig; + if(!relation_signature_to_table(s, tsig)) { + return false; + } + table_base * table = mk_empty_table(tsig); + result = mk_table_relation(s, table); + return true; + } + + + relation_base * relation_manager::mk_full_relation(const relation_signature & s, func_decl* p, family_id kind) { + if (kind != null_family_id) { + relation_plugin & plugin = get_relation_plugin(kind); + if (plugin.can_handle_signature(s, kind)) { + return plugin.mk_full(p, s, kind); + } + } + return get_appropriate_plugin(s).mk_full(p, s, null_family_id); + } + + relation_base * relation_manager::mk_full_relation(const relation_signature & s, func_decl* pred) { + family_id kind = get_requested_predicate_kind(pred); + return mk_full_relation(s, pred, kind); + } + + void relation_manager::relation_to_table(const relation_sort & sort, const relation_element & from, + table_element & to) { + SASSERT(from->get_num_args()==0); + VERIFY(get_context().get_decl_util().is_numeral_ext(from, to)); + } + + void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from, + relation_element & to) { + to = get_decl_util().mk_numeral(from, sort); + } + + void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from, + relation_element_ref & to) { + relation_element rel_el; + table_to_relation(sort, from, rel_el); + to = rel_el; + } + + void relation_manager::table_to_relation(const relation_sort & sort, const table_element & from, + const relation_fact::el_proxy & to) { + relation_element rel_el; + table_to_relation(sort, from, rel_el); + to = rel_el; + } + + bool relation_manager::relation_sort_to_table(const relation_sort & from, table_sort & to) { + return get_context().get_decl_util().try_get_size(from, to); + } + + void relation_manager::from_predicate(func_decl * pred, unsigned arg_index, relation_sort & result) { + result = pred->get_domain(arg_index); + } + + void relation_manager::from_predicate(func_decl * pred, relation_signature & result) { + result.reset(); + unsigned arg_num=pred->get_arity(); + for(unsigned i=0;iset_cancel(f); + } + } + + std::string relation_manager::to_nice_string(const relation_element & el) const { + uint64 val; + std::stringstream stm; + if(get_context().get_decl_util().is_numeral_ext(el, val)) { + stm << val; + } + else { + stm << mk_pp(el, get_context().get_manager()); + } + return stm.str(); + } + + std::string relation_manager::to_nice_string(const relation_sort & s, const relation_element & el) const { + std::stringstream stm; + uint64 val; + if(get_context().get_decl_util().is_numeral_ext(el, val)) { + get_context().print_constant_name(s, val, stm); + } + else { + stm << mk_pp(el, get_context().get_manager()); + } + return stm.str(); + } + + std::string relation_manager::to_nice_string(const relation_sort & s) const { + return std::string(s->get_name().bare_str()); + } + + std::string relation_manager::to_nice_string(const relation_signature & s) const { + std::string res("["); + bool first = true; + relation_signature::const_iterator it = s.begin(); + relation_signature::const_iterator end = s.end(); + for(; it!=end; ++it) { + if(first) { + first = false; + } + else { + res+=','; + } + res+=to_nice_string(*it); + } + res+=']'; + + return res; + } + + void relation_manager::display(std::ostream & out) const { + relation_map::iterator it=m_relations.begin(); + relation_map::iterator end=m_relations.end(); + for(;it!=end;++it) { + out << "Table " << it->m_key->get_name() << "\n"; + it->m_value->display(out); + } + } + + void relation_manager::display_relation_sizes(std::ostream & out) const { + relation_map::iterator it=m_relations.begin(); + relation_map::iterator end=m_relations.end(); + for(;it!=end;++it) { + out << "Relation " << it->m_key->get_name() << " has size " + << it->m_value->get_size_estimate_rows() << "\n"; + } + } + + void relation_manager::display_output_tables(rule_set const& rules, std::ostream & out) const { + const decl_set & output_preds = rules.get_output_predicates(); + decl_set::iterator it=output_preds.begin(); + decl_set::iterator end=output_preds.end(); + for(; it!=end; ++it) { + func_decl * pred = *it; + relation_base * rel = try_get_relation(pred); + if(!rel) { + out << "Tuples in " << pred->get_name() << ": \n"; + continue; + } + rel->display_tuples(*pred, out); + } + } + + + // ----------------------------------- + // + // relation operations + // + // ----------------------------------- + + class relation_manager::empty_signature_relation_join_fn : public relation_join_fn { + public: + virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + TRACE("dl", tout << r1.get_plugin().get_name() << " " << r2.get_plugin().get_name() << "\n";); + if(r1.get_signature().empty()) { + if(r1.empty()) { + return r2.get_manager().mk_empty_relation(r2.get_signature(), r2.get_kind()); + } + else { + return r2.clone(); + } + } + else { + SASSERT(r2.get_signature().empty()); + if(r2.empty()) { + return r1.get_manager().mk_empty_relation(r1.get_signature(), r1.get_kind()); + } + else { + return r1.clone(); + } + } + } + }; + + relation_join_fn * relation_manager::mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, bool allow_product_relation) { + relation_plugin * p1 = &t1.get_plugin(); + relation_plugin * p2 = &t2.get_plugin(); + + relation_join_fn * res = p1->mk_join_fn(t1, t2, col_cnt, cols1, cols2); + if(!res && p1!=p2) { + res = p2->mk_join_fn(t1, t2, col_cnt, cols1, cols2); + } + + if(!res && (t1.get_signature().empty() || t2.get_signature().empty())) { + res = alloc(empty_signature_relation_join_fn); + } + + finite_product_relation_plugin * fprp; + if(!res && p1->from_table() && try_get_finite_product_relation_plugin(*p2, fprp)) { + //we downcast here to relation_plugin so that we don't have to declare + //relation_manager as a friend class of finite_product_relation_plugin + res = static_cast(fprp)->mk_join_fn(t1, t2, col_cnt, cols1, cols2); + } + if(!res && p2->from_table() && try_get_finite_product_relation_plugin(*p1, fprp)) { + res = static_cast(fprp)->mk_join_fn(t1, t2, col_cnt, cols1, cols2); + } + + if(!res && allow_product_relation) { + relation_plugin & product_plugin = product_relation_plugin::get_plugin(*this); + res = product_plugin.mk_join_fn(t1, t2, col_cnt, cols1, cols2); + } + + return res; + } + + relation_transformer_fn * relation_manager::mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) { + return t.get_plugin().mk_project_fn(t, col_cnt, removed_cols); + } + + class relation_manager::default_relation_filter_interpreted_and_project_fn : public relation_transformer_fn { + scoped_ptr m_filter; + scoped_ptr m_project; + unsigned_vector m_removed_cols; + public: + /** + This constructor should be used only if we know that the projection operation + exists for the result of the join. + */ + default_relation_filter_interpreted_and_project_fn( + relation_mutator_fn* filter, + unsigned removed_col_cnt, + const unsigned * removed_cols) + : m_filter(filter), + m_project(0), + m_removed_cols(removed_col_cnt, removed_cols) {} + + virtual relation_base * operator()(const relation_base & t) { + scoped_rel t1 = t.clone(); + (*m_filter)(*t1); + if( !m_project) { + relation_manager & rmgr = t1->get_plugin().get_manager(); + m_project = rmgr.mk_project_fn(*t1, m_removed_cols.size(), m_removed_cols.c_ptr()); + if (!m_project) { + throw default_exception("projection does not exist"); + } + } + return (*m_project)(*t1); + } + }; + + relation_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn( + const relation_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols) { + + relation_transformer_fn* res = + t.get_plugin().mk_filter_interpreted_and_project_fn( + t, + condition, + removed_col_cnt, + removed_cols); + + if (!res) { + relation_mutator_fn* filter_fn = mk_filter_interpreted_fn(t, condition); + if (filter_fn) { + res = alloc(default_relation_filter_interpreted_and_project_fn, + filter_fn, + removed_col_cnt, + removed_cols); + } + } + return res; + } + + + class relation_manager::default_relation_join_project_fn : public relation_join_fn { + scoped_ptr m_join; + scoped_ptr m_project; + + unsigned_vector m_removed_cols; + public: + /** + This constructor should be used only if we know that the projection operation + exists for the result of the join. + */ + default_relation_join_project_fn(join_fn * join, unsigned removed_col_cnt, + const unsigned * removed_cols) + : m_join(join), m_project(0), m_removed_cols(removed_col_cnt, removed_cols) {} + + virtual relation_base * operator()(const relation_base & t1, const relation_base & t2) { + scoped_rel aux = (*m_join)(t1, t2); + if(!m_project) { + relation_manager & rmgr = aux->get_plugin().get_manager(); + m_project = rmgr.mk_project_fn(*aux, m_removed_cols.size(), m_removed_cols.c_ptr()); + if(!m_project) { + throw default_exception("projection does not exist"); + } + } + relation_base * res = (*m_project)(*aux); + return res; + } + }; + + + relation_join_fn * relation_manager::mk_join_project_fn(const relation_base & t1, const relation_base & t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols, bool allow_product_relation_join) { + relation_join_fn * res = t1.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, + removed_col_cnt, removed_cols); + if(!res && &t1.get_plugin()!=&t2.get_plugin()) { + res = t2.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt, + removed_cols); + } + if(!res) { + relation_join_fn * join = mk_join_fn(t1, t2, joined_col_cnt, cols1, cols2, allow_product_relation_join); + if(join) { + res = alloc(default_relation_join_project_fn, join, removed_col_cnt, removed_cols); + } + } + return res; + + } + + relation_transformer_fn * relation_manager::mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) { + return t.get_plugin().mk_rename_fn(t, permutation_cycle_len, permutation_cycle); + } + + relation_transformer_fn * relation_manager::mk_permutation_rename_fn(const relation_base & t, + const unsigned * permutation) { + relation_transformer_fn * res = t.get_plugin().mk_permutation_rename_fn(t, permutation); + if(!res) { + res = alloc(default_relation_permutation_rename_fn, t, permutation); + } + return res; + } + + + relation_union_fn * relation_manager::mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + relation_union_fn * res = tgt.get_plugin().mk_union_fn(tgt, src, delta); + if(!res && &tgt.get_plugin()!=&src.get_plugin()) { + res = src.get_plugin().mk_union_fn(tgt, src, delta); + } + if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { + res = delta->get_plugin().mk_union_fn(tgt, src, delta); + } + return res; + } + + relation_union_fn * relation_manager::mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + relation_union_fn * res = tgt.get_plugin().mk_widen_fn(tgt, src, delta); + if(!res && &tgt.get_plugin()!=&src.get_plugin()) { + res = src.get_plugin().mk_widen_fn(tgt, src, delta); + } + if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { + res = delta->get_plugin().mk_widen_fn(tgt, src, delta); + } + if(!res) { + res = mk_union_fn(tgt, src, delta); + } + return res; + } + + relation_mutator_fn * relation_manager::mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) { + return t.get_plugin().mk_filter_identical_fn(t, col_cnt, identical_cols); + } + + relation_mutator_fn * relation_manager::mk_filter_equal_fn(const relation_base & t, + const relation_element & value, unsigned col) { + + return t.get_plugin().mk_filter_equal_fn(t, value, col); + } + + relation_mutator_fn * relation_manager::mk_filter_interpreted_fn(const relation_base & t, app * condition) { + return t.get_plugin().mk_filter_interpreted_fn(t, condition); + } + + class relation_manager::default_relation_select_equal_and_project_fn : public relation_transformer_fn { + scoped_ptr m_filter; + scoped_ptr m_project; + public: + default_relation_select_equal_and_project_fn(relation_mutator_fn * filter, relation_transformer_fn * project) + : m_filter(filter), m_project(project) {} + + virtual relation_base * operator()(const relation_base & t1) { + TRACE("dl", tout << t1.get_plugin().get_name() << "\n";); + scoped_rel aux = t1.clone(); + (*m_filter)(*aux); + relation_base * res = (*m_project)(*aux); + return res; + } + }; + + relation_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const relation_base & t, + const relation_element & value, unsigned col) { + relation_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col); + if(!res) { + relation_mutator_fn * selector = mk_filter_equal_fn(t, value, col); + if(selector) { + relation_transformer_fn * projector = mk_project_fn(t, 1, &col); + if(projector) { + res = alloc(default_relation_select_equal_and_project_fn, selector, projector); + } + else { + dealloc(selector); + } + } + } + return res; + } + + + class relation_manager::default_relation_intersection_filter_fn : public relation_intersection_filter_fn { + scoped_ptr m_join_fun; + scoped_ptr m_union_fun; + public: + + default_relation_intersection_filter_fn(relation_join_fn * join_fun, relation_union_fn * union_fun) + : m_join_fun(join_fun), m_union_fun(union_fun) {} + + virtual void operator()(relation_base & tgt, const relation_base & intersected_obj) { + scoped_rel filtered_rel = (*m_join_fun)(tgt, intersected_obj); + TRACE("dl", + tgt.display(tout << "tgt:\n"); + intersected_obj.display(tout << "intersected:\n"); + filtered_rel->display(tout << "filtered:\n"); + ); + if(!m_union_fun) { + SASSERT(tgt.can_swap(*filtered_rel)); + tgt.swap(*filtered_rel); + } + tgt.reset(); + TRACE("dl", tgt.display(tout << "target reset:\n"); ); + (*m_union_fun)(tgt, *filtered_rel); + TRACE("dl", tgt.display(tout << "intersected target:\n"); ); + } + + }; + + relation_intersection_filter_fn * relation_manager::try_mk_default_filter_by_intersection_fn( + const relation_base & tgt, const relation_base & src, unsigned joined_col_cnt, + const unsigned * tgt_cols, const unsigned * src_cols) { + TRACE("dl_verbose", tout << tgt.get_plugin().get_name() << "\n";); + unsigned_vector join_removed_cols; + add_sequence(tgt.get_signature().size(), src.get_signature().size(), join_removed_cols); + scoped_rel join_fun = mk_join_project_fn(tgt, src, joined_col_cnt, tgt_cols, src_cols, + join_removed_cols.size(), join_removed_cols.c_ptr(), false); + if(!join_fun) { + return 0; + } + //we perform the join operation here to see what the result is + scoped_rel join_res = (*join_fun)(tgt, src); + if(tgt.can_swap(*join_res)) { + return alloc(default_relation_intersection_filter_fn, join_fun.release(), 0); + } + if(join_res->get_plugin().is_product_relation()) { + //we cannot have the product relation here, since it uses the intersection operation + //for unions and therefore we would get into an infinite recursion + return 0; + } + scoped_rel union_fun = mk_union_fn(tgt, *join_res); + if(!union_fun) { + return 0; + } + return alloc(default_relation_intersection_filter_fn, join_fun.release(), union_fun.release()); + } + + + relation_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const relation_base & t, + const relation_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) { + TRACE("dl_verbose", tout << t.get_plugin().get_name() << "\n";); + relation_intersection_filter_fn * res = t.get_plugin().mk_filter_by_intersection_fn(t, src, joined_col_cnt, + t_cols, src_cols); + if(!res && &t.get_plugin()!=&src.get_plugin()) { + res = src.get_plugin().mk_filter_by_intersection_fn(t, src, joined_col_cnt, t_cols, src_cols); + } + if(!res) { + res = try_mk_default_filter_by_intersection_fn(t, src, joined_col_cnt, t_cols, src_cols); + } + return res; + } + + relation_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const relation_base & tgt, + const relation_base & src) { + TRACE("dl_verbose", tout << tgt.get_plugin().get_name() << "\n";); + SASSERT(tgt.get_signature()==src.get_signature()); + unsigned sz = tgt.get_signature().size(); + unsigned_vector cols; + add_sequence(0, sz, cols); + return mk_filter_by_intersection_fn(tgt, src, cols, cols); + } + + + relation_intersection_filter_fn * relation_manager::mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) { + TRACE("dl", tout << t.get_plugin().get_name() << "\n";); + relation_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, + t_cols, negated_cols); + if(!res && &t.get_plugin()!=&negated_obj.get_plugin()) { + res = negated_obj.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, t_cols, + negated_cols); + } + return res; + } + + + + + + // ----------------------------------- + // + // table operations + // + // ----------------------------------- + + class relation_manager::default_table_join_fn : public convenient_table_join_fn { + unsigned m_col_cnt; + public: + default_table_join_fn(const table_signature & t1_sig, const table_signature & t2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_table_join_fn(t1_sig, t2_sig, col_cnt, cols1, cols2), m_col_cnt(col_cnt) {} + + virtual table_base * operator()(const table_base & t1, const table_base & t2) { + table_plugin * plugin = &t1.get_plugin(); + + const table_signature & res_sign = get_result_signature(); + if (!plugin->can_handle_signature(res_sign)) { + plugin = &t2.get_plugin(); + if (!plugin->can_handle_signature(res_sign)) { + plugin = &t1.get_manager().get_appropriate_plugin(res_sign); + } + } + SASSERT(plugin->can_handle_signature(res_sign)); + table_base * res = plugin->mk_empty(res_sign); + + unsigned t1cols = t1.get_signature().size(); + unsigned t2cols = t2.get_signature().size(); + unsigned t1first_func = t1.get_signature().first_functional(); + unsigned t2first_func = t2.get_signature().first_functional(); + + table_base::iterator els1it = t1.begin(); + table_base::iterator els1end = t1.end(); + table_base::iterator els2end = t2.end(); + + table_fact acc; + + for(; els1it!=els1end; ++els1it) { + const table_base::row_interface & row1 = *els1it; + + table_base::iterator els2it = t2.begin(); + for(; els2it!=els2end; ++els2it) { + const table_base::row_interface & row2 = *els2it; + + bool match=true; + for(unsigned i=0; iadd_fact(acc); + } + } + return res; + } + }; + + table_join_fn * relation_manager::mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + table_join_fn * res = t1.get_plugin().mk_join_fn(t1, t2, col_cnt, cols1, cols2); + if(!res && &t1.get_plugin()!=&t2.get_plugin()) { + res = t2.get_plugin().mk_join_fn(t1, t2, col_cnt, cols1, cols2); + } + if(!res) { + table_signature sig; + table_signature::from_join(t1.get_signature(), t2.get_signature(), + col_cnt, cols1, cols2, sig); + res = alloc(default_table_join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); + } + return res; + } + + + class relation_manager::auxiliary_table_transformer_fn { + table_fact m_row; + public: + virtual ~auxiliary_table_transformer_fn() {} + virtual const table_signature & get_result_signature() const = 0; + virtual void modify_fact(table_fact & f) const = 0; + + table_base * operator()(const table_base & t) { + table_plugin & plugin = t.get_plugin(); + const table_signature & res_sign = get_result_signature(); + SASSERT(plugin.can_handle_signature(res_sign)); + table_base * res = plugin.mk_empty(res_sign); + + table_base::iterator it = t.begin(); + table_base::iterator end = t.end(); + + for(; it!=end; ++it) { + it->get_fact(m_row); + modify_fact(m_row); + res->add_fact(m_row); + } + return res; + } + }; + + class relation_manager::default_table_project_fn + : public convenient_table_project_fn, auxiliary_table_transformer_fn { + public: + default_table_project_fn(const table_signature & orig_sig, unsigned removed_col_cnt, + const unsigned * removed_cols) + : convenient_table_project_fn(orig_sig, removed_col_cnt, removed_cols) { + SASSERT(removed_col_cnt>0); + } + + virtual const table_signature & get_result_signature() const { + return convenient_table_project_fn::get_result_signature(); + } + + virtual void modify_fact(table_fact & f) const { + project_out_vector_columns(f, m_removed_cols); + } + + virtual table_base * operator()(const table_base & t) { + return auxiliary_table_transformer_fn::operator()(t); + } + }; + + class relation_manager::null_signature_table_project_fn : public table_transformer_fn { + const table_signature m_empty_sig; + public: + null_signature_table_project_fn() : m_empty_sig() {} + virtual table_base * operator()(const table_base & t) { + relation_manager & m = t.get_plugin().get_manager(); + table_base * res = m.mk_empty_table(m_empty_sig); + if(!t.empty()) { + table_fact el; + res->add_fact(el); + } + return res; + } + }; + + + + table_transformer_fn * relation_manager::mk_project_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols) { + table_transformer_fn * res = t.get_plugin().mk_project_fn(t, col_cnt, removed_cols); + if(!res && col_cnt==t.get_signature().size()) { + //all columns are projected out + res = alloc(null_signature_table_project_fn); + } + if(!res) { + res = alloc(default_table_project_fn, t.get_signature(), col_cnt, removed_cols); + } + return res; + } + + + class relation_manager::default_table_join_project_fn : public convenient_table_join_project_fn { + scoped_ptr m_join; + scoped_ptr m_project; + + unsigned_vector m_removed_cols; + public: + default_table_join_project_fn(join_fn * join, const table_base & t1, const table_base & t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols) + : convenient_table_join_project_fn(t1.get_signature(), t2.get_signature(), joined_col_cnt, cols1, + cols2, removed_col_cnt, removed_cols), + m_join(join), + m_removed_cols(removed_col_cnt, removed_cols) {} + + class unreachable_reducer : public table_row_pair_reduce_fn { + virtual void operator()(table_element * func_columns, const table_element * merged_func_columns) { + //we do project_with_reduce only if we are sure there will be no reductions + //(see code of the table_signature::from_join_project function) + UNREACHABLE(); + } + }; + + virtual table_base * operator()(const table_base & t1, const table_base & t2) { + table_base * aux = (*m_join)(t1, t2); + if(m_project==0) { + relation_manager & rmgr = aux->get_plugin().get_manager(); + if(get_result_signature().functional_columns()!=0) { + //to preserve functional columns we need to do the project_with_reduction + unreachable_reducer * reducer = alloc(unreachable_reducer); + m_project = rmgr.mk_project_with_reduce_fn(*aux, m_removed_cols.size(), m_removed_cols.c_ptr(), reducer); + } + else { + m_project = rmgr.mk_project_fn(*aux, m_removed_cols); + } + if(!m_project) { + throw default_exception("projection for table does not exist"); + } + } + table_base * res = (*m_project)(*aux); + aux->deallocate(); + return res; + } + }; + + table_join_fn * relation_manager::mk_join_project_fn(const table_base & t1, const table_base & t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) { + table_join_fn * res = t1.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, + removed_col_cnt, removed_cols); + if(!res && &t1.get_plugin()!=&t2.get_plugin()) { + res = t2.get_plugin().mk_join_project_fn(t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt, + removed_cols); + } + if(!res) { + table_join_fn * join = mk_join_fn(t1, t2, joined_col_cnt, cols1, cols2); + if(join) { + res = alloc(default_table_join_project_fn, join, t1, t2, joined_col_cnt, cols1, cols2, + removed_col_cnt, removed_cols); + } + } + return res; + + } + + class relation_manager::default_table_rename_fn + : public convenient_table_rename_fn, auxiliary_table_transformer_fn { + public: + default_table_rename_fn(const table_signature & orig_sig, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) + : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle) { + SASSERT(permutation_cycle_len>=2); + } + + virtual const table_signature & get_result_signature() const { + return convenient_table_rename_fn::get_result_signature(); + } + + virtual void modify_fact(table_fact & f) const { + permutate_by_cycle(f, m_cycle); + } + + virtual table_base * operator()(const table_base & t) { + return auxiliary_table_transformer_fn::operator()(t); + } + + }; + + table_transformer_fn * relation_manager::mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) { + table_transformer_fn * res = t.get_plugin().mk_rename_fn(t, permutation_cycle_len, permutation_cycle); + if(!res) { + res = alloc(default_table_rename_fn, t.get_signature(), permutation_cycle_len, permutation_cycle); + } + return res; + } + + table_transformer_fn * relation_manager::mk_permutation_rename_fn(const table_base & t, + const unsigned * permutation) { + table_transformer_fn * res = t.get_plugin().mk_permutation_rename_fn(t, permutation); + if(!res) { + res = alloc(default_table_permutation_rename_fn, t, permutation); + } + return res; + } + + + class relation_manager::default_table_union_fn : public table_union_fn { + table_fact m_row; + public: + virtual void operator()(table_base & tgt, const table_base & src, table_base * delta) { + table_base::iterator it = src.begin(); + table_base::iterator iend = src.end(); + + for(; it!=iend; ++it) { + it->get_fact(m_row); + + if(delta) { + if(!tgt.contains_fact(m_row)) { + tgt.add_new_fact(m_row); + delta->add_fact(m_row); + } + } + else { + //if there's no delta, we don't need to know whether we are actually adding a new fact + tgt.add_fact(m_row); + } + } + } + }; + + table_union_fn * relation_manager::mk_union_fn(const table_base & tgt, const table_base & src, + const table_base * delta) { + table_union_fn * res = tgt.get_plugin().mk_union_fn(tgt, src, delta); + if(!res && &tgt.get_plugin()!=&src.get_plugin()) { + res = src.get_plugin().mk_union_fn(tgt, src, delta); + } + if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { + res = delta->get_plugin().mk_union_fn(tgt, src, delta); + } + if(!res) { + res = alloc(default_table_union_fn); + } + return res; + } + + table_union_fn * relation_manager::mk_widen_fn(const table_base & tgt, const table_base & src, + const table_base * delta) { + table_union_fn * res = tgt.get_plugin().mk_widen_fn(tgt, src, delta); + if(!res && &tgt.get_plugin()!=&src.get_plugin()) { + res = src.get_plugin().mk_widen_fn(tgt, src, delta); + } + if(!res && delta && &tgt.get_plugin()!=&delta->get_plugin() && &src.get_plugin()!=&delta->get_plugin()) { + res = delta->get_plugin().mk_widen_fn(tgt, src, delta); + } + if(!res) { + res = mk_union_fn(tgt, src, delta); + } + return res; + } + + + /** + An auixiliary class for functors that perform filtering. It performs the table traversal + and only asks for each individual row whether it should be removed. + + When using this class in multiple inheritance, this class should not be inherited publicly + and should be mentioned as last. This should ensure that deteletion of the object will + go well when initiated from a pointer to the first ancestor. + */ + class relation_manager::auxiliary_table_filter_fn { + table_fact m_row; + svector m_to_remove; + public: + virtual ~auxiliary_table_filter_fn() {} + virtual bool should_remove(const table_fact & f) const = 0; + + void operator()(table_base & r) { + m_to_remove.reset(); + unsigned sz = 0; + table_base::iterator it = r.begin(); + table_base::iterator iend = r.end(); + for(; it!=iend; ++it) { + it->get_fact(m_row); + if(should_remove(m_row)) { + m_to_remove.append(m_row.size(), m_row.c_ptr()); + ++sz; + } + } + r.remove_facts(sz, m_to_remove.c_ptr()); + } + }; + + class relation_manager::default_table_filter_identical_fn : public table_mutator_fn, auxiliary_table_filter_fn { + const unsigned m_col_cnt; + const unsigned_vector m_identical_cols; + public: + default_table_filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) + : m_col_cnt(col_cnt), + m_identical_cols(col_cnt, identical_cols) { + SASSERT(col_cnt>=2); + } + + virtual bool should_remove(const table_fact & f) const { + table_element val=f[m_identical_cols[0]]; + for(unsigned i=1; iget_arg(0); + if (!m.is_eq(condition)) { + return 0; + } + expr* x = to_app(condition)->get_arg(0); + expr* y = to_app(condition)->get_arg(1); + if (!is_var(x)) { + std::swap(x, y); + } + if (!is_var(x)) { + return 0; + } + dl_decl_util decl_util(m); + uint64 value = 0; + if (!decl_util.is_numeral_ext(y, value)) { + return 0; + } + return alloc(default_table_filter_not_equal_fn, ctx, to_var(x)->get_idx(), value); + } + }; + + + + class relation_manager::default_table_filter_interpreted_fn + : public table_mutator_fn, auxiliary_table_filter_fn { + ast_manager & m_ast_manager; + var_subst & m_vs; + dl_decl_util & m_decl_util; + th_rewriter & m_simp; + app_ref m_condition; + ptr_vector m_var_sorts; + expr_ref_vector m_args; + public: + default_table_filter_interpreted_fn(context & ctx, unsigned col_cnt, app* condition) + : m_ast_manager(ctx.get_manager()), + m_vs(ctx.get_var_subst()), + m_decl_util(ctx.get_decl_util()), + m_simp(ctx.get_rewriter()), + m_condition(condition, ctx.get_manager()), + m_args(ctx.get_manager()) { + m_var_sorts.resize(col_cnt); + get_free_vars(m_condition, m_var_sorts); + } + + virtual bool should_remove(const table_fact & f) const { + expr_ref_vector& args = const_cast(m_args); + + args.reset(); + //arguments need to be in reverse order for the substitution + unsigned col_cnt = f.size(); + for(int i=col_cnt-1;i>=0;i--) { + sort * var_sort = m_var_sorts[i]; + if(!var_sort) { + args.push_back(0); + continue; //this variable does not occur in the condition; + } + + table_element el = f[i]; + args.push_back(m_decl_util.mk_numeral(el, var_sort)); + } + + expr_ref ground(m_ast_manager); + m_vs(m_condition.get(), args.size(), args.c_ptr(), ground); + m_simp(ground); + + return m_ast_manager.is_false(ground); + } + + virtual void operator()(table_base & t) { + auxiliary_table_filter_fn::operator()(t); + } + }; + + table_mutator_fn * relation_manager::mk_filter_interpreted_fn(const table_base & t, app * condition) { + context & ctx = get_context(); + table_mutator_fn * res = t.get_plugin().mk_filter_interpreted_fn(t, condition); + if (!res) { + res = default_table_filter_not_equal_fn::mk(ctx, condition); + } + if(!res) { + res = alloc(default_table_filter_interpreted_fn, ctx, t.get_signature().size(), condition); + } + return res; + } + + + class relation_manager::default_table_filter_interpreted_and_project_fn + : public table_transformer_fn { + scoped_ptr m_filter; + scoped_ptr m_project; + app_ref m_condition; + unsigned_vector m_removed_cols; + public: + default_table_filter_interpreted_and_project_fn(context & ctx, table_mutator_fn * filter, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) + : m_filter(filter), m_condition(condition, ctx.get_manager()), + m_removed_cols(removed_col_cnt, removed_cols) {} + + virtual table_base* operator()(const table_base & tb) { + table_base *t2 = tb.clone(); + (*m_filter)(*t2); + if (!m_project) { + relation_manager & rmgr = t2->get_plugin().get_manager(); + m_project = rmgr.mk_project_fn(*t2, m_removed_cols.size(), m_removed_cols.c_ptr()); + if (!m_project) { + throw default_exception("projection does not exist"); + } + } + return (*m_project)(*t2); + } + }; + + table_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn(const table_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { + table_transformer_fn * res = t.get_plugin().mk_filter_interpreted_and_project_fn(t, condition, removed_col_cnt, removed_cols); + if (res) + return res; + + table_mutator_fn * filter = mk_filter_interpreted_fn(t, condition); + SASSERT(filter); + res = alloc(default_table_filter_interpreted_and_project_fn, get_context(), filter, condition, removed_col_cnt, removed_cols); + return res; + } + + + table_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const table_base & t, + const table_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) { + table_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, src, joined_col_cnt, + t_cols, src_cols); + if(!res && &t.get_plugin()!=&src.get_plugin()) { + res = src.get_plugin().mk_filter_by_negation_fn(t, src, joined_col_cnt, t_cols, src_cols); + } + return res; + } + + + + class relation_manager::default_table_negation_filter_fn : public convenient_table_negation_filter_fn, + auxiliary_table_filter_fn { + const table_base * m_negated_table; + mutable table_fact m_aux_fact; + public: + default_table_negation_filter_fn(const table_base & tgt, const table_base & neg_t, + unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) + : convenient_table_negation_filter_fn(tgt, neg_t, joined_col_cnt, t_cols, negated_cols), + m_negated_table(0) { + m_aux_fact.resize(neg_t.get_signature().size()); + } + + virtual bool should_remove(const table_fact & f) const { + if(!m_all_neg_bound || m_overlap) { + table_base::iterator nit = m_negated_table->begin(); + table_base::iterator nend = m_negated_table->end(); + for(; nit!=nend; ++nit) { + const table_base::row_interface & nrow = *nit; + if(bindings_match(nrow, f)) { + return true; + } + } + return false; + } + else { + make_neg_bindings(m_aux_fact, f); + return m_negated_table->contains_fact(m_aux_fact); + } + } + + virtual void operator()(table_base & tgt, const table_base & negated_table) { + SASSERT(m_negated_table==0); + flet flet_neg_table(m_negated_table, &negated_table); + auxiliary_table_filter_fn::operator()(tgt); + } + + }; + + table_intersection_filter_fn * relation_manager::mk_filter_by_negation_fn(const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) { + table_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, + t_cols, negated_cols); + if(!res && &t.get_plugin()!=&negated_obj.get_plugin()) { + res = negated_obj.get_plugin().mk_filter_by_negation_fn(t, negated_obj, joined_col_cnt, t_cols, + negated_cols); + } + if(!res) { + res = alloc(default_table_negation_filter_fn, t, negated_obj, joined_col_cnt, t_cols, negated_cols); + } + return res; + } + + + class relation_manager::default_table_select_equal_and_project_fn : public table_transformer_fn { + scoped_ptr m_filter; + scoped_ptr m_project; + public: + default_table_select_equal_and_project_fn(table_mutator_fn * filter, table_transformer_fn * project) + : m_filter(filter), m_project(project) {} + + virtual table_base * operator()(const table_base & t1) { + TRACE("dl", tout << t1.get_plugin().get_name() << "\n";); + scoped_rel aux = t1.clone(); + (*m_filter)(*aux); + table_base * res = (*m_project)(*aux); + return res; + } + }; + + table_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const table_base & t, + const table_element & value, unsigned col) { + table_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col); + if(!res) { + table_mutator_fn * selector = mk_filter_equal_fn(t, value, col); + SASSERT(selector); + table_transformer_fn * projector = mk_project_fn(t, 1, &col); + SASSERT(projector); + res = alloc(default_table_select_equal_and_project_fn, selector, projector); + } + return res; + } + + + class relation_manager::default_table_map_fn : public table_mutator_fn { + scoped_ptr m_mapper; + unsigned m_first_functional; + scoped_rel m_aux_table; + scoped_ptr m_union_fn; + table_fact m_curr_fact; + public: + default_table_map_fn(const table_base & t, table_row_mutator_fn * mapper) + : m_mapper(mapper), m_first_functional(t.get_signature().first_functional()) { + SASSERT(t.get_signature().functional_columns()>0); + table_plugin & plugin = t.get_plugin(); + m_aux_table = plugin.mk_empty(t.get_signature()); + m_union_fn = plugin.mk_union_fn(t, *m_aux_table, static_cast(0)); + } + + virtual void operator()(table_base & t) { + SASSERT(t.get_signature()==m_aux_table->get_signature()); + if(!m_aux_table->empty()) { + m_aux_table->reset(); + } + + + table_base::iterator it = t.begin(); + table_base::iterator iend = t.end(); + for(; it!=iend; ++it) { + it->get_fact(m_curr_fact); + if((*m_mapper)(m_curr_fact.c_ptr()+m_first_functional)) { + m_aux_table->add_fact(m_curr_fact); + } + } + + t.reset(); + (*m_union_fn)(t, *m_aux_table, static_cast(0)); + } + }; + + table_mutator_fn * relation_manager::mk_map_fn(const table_base & t, table_row_mutator_fn * mapper) { + SASSERT(t.get_signature().functional_columns()>0); + table_mutator_fn * res = t.get_plugin().mk_map_fn(t, mapper); + if(!res) { + res = alloc(default_table_map_fn, t, mapper); + } + return res; + } + + + class relation_manager::default_table_project_with_reduce_fn : public convenient_table_transformer_fn { + unsigned_vector m_removed_cols; + const unsigned m_inp_col_cnt; + const unsigned m_removed_col_cnt; + const unsigned m_result_col_cnt; + scoped_ptr m_reducer; + unsigned m_res_first_functional; + table_fact m_row; + table_fact m_former_row; + public: + default_table_project_with_reduce_fn(const table_signature & orig_sig, unsigned removed_col_cnt, + const unsigned * removed_cols, table_row_pair_reduce_fn * reducer) + : m_removed_cols(removed_col_cnt, removed_cols), + m_inp_col_cnt(orig_sig.size()), + m_removed_col_cnt(removed_col_cnt), + m_result_col_cnt(orig_sig.size()-removed_col_cnt), + m_reducer(reducer) { + SASSERT(removed_col_cnt>0); + table_signature::from_project_with_reduce(orig_sig, removed_col_cnt, removed_cols, + get_result_signature()); + m_res_first_functional = get_result_signature().first_functional(); + m_row.resize(get_result_signature().size()); + m_former_row.resize(get_result_signature().size()); + } + + virtual void modify_fact(table_fact & f) const { + unsigned ofs=1; + unsigned r_i=1; + for(unsigned i=m_removed_cols[0]+1; isuggest_fact(m_former_row)) { + (*m_reducer)(m_former_row.c_ptr()+m_res_first_functional, m_row.c_ptr()+m_res_first_functional); + res->ensure_fact(m_former_row); + } + } + return res; + } + }; + + table_transformer_fn * relation_manager::mk_project_with_reduce_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols, table_row_pair_reduce_fn * reducer) { + SASSERT(t.get_signature().functional_columns()>0); + table_transformer_fn * res = t.get_plugin().mk_project_with_reduce_fn(t, col_cnt, removed_cols, reducer); + if(!res) { + res = alloc(default_table_project_with_reduce_fn, t.get_signature(), col_cnt, removed_cols, reducer); + } + return res; + } + +}; + diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h new file mode 100644 index 000000000..9f12b4bb6 --- /dev/null +++ b/src/muz/rel/dl_relation_manager.h @@ -0,0 +1,688 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_relation_manager.h + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-24. + +Revision History: + +--*/ +#ifndef _DL_RELATION_MANAGER_H_ +#define _DL_RELATION_MANAGER_H_ + + +#include"map.h" +#include"vector.h" +#include"dl_base.h" + +namespace datalog { + + class context; + class dl_decl_util; + class table_relation; + class table_relation_plugin; + class finite_product_relation; + class finite_product_relation_plugin; + class sieve_relation; + class sieve_relation_plugin; + class rule_set; + + + class relation_manager { + class empty_signature_relation_join_fn; + class default_relation_join_project_fn; + class default_relation_select_equal_and_project_fn; + class default_relation_intersection_filter_fn; + class default_relation_filter_interpreted_and_project_fn; + + class auxiliary_table_transformer_fn; + class auxiliary_table_filter_fn; + + class default_table_join_fn; + class default_table_project_fn; + class null_signature_table_project_fn; + class default_table_join_project_fn; + class default_table_rename_fn; + class default_table_union_fn; + class default_table_filter_equal_fn; + class default_table_filter_identical_fn; + class default_table_filter_interpreted_fn; + class default_table_filter_interpreted_and_project_fn; + class default_table_negation_filter_fn; + class default_table_filter_not_equal_fn; + class default_table_select_equal_and_project_fn; + class default_table_map_fn; + class default_table_project_with_reduce_fn; + + typedef obj_map decl2kind_map; + + typedef u_map kind2plugin_map; + + typedef map, + ptr_eq > tp2trp_map; + typedef map, + ptr_eq > rp2fprp_map; + + typedef map, ptr_eq > relation_map; + typedef ptr_vector table_plugin_vector; + typedef ptr_vector relation_plugin_vector; + + context & m_context; + table_plugin_vector m_table_plugins; + relation_plugin_vector m_relation_plugins; + //table_relation_plugins corresponding to table_plugins + tp2trp_map m_table_relation_plugins; + rp2fprp_map m_finite_product_relation_plugins; + + kind2plugin_map m_kind2plugin; + + table_plugin * m_favourite_table_plugin; + + relation_plugin * m_favourite_relation_plugin; + + relation_map m_relations; + + decl_set m_saturated_rels; + + family_id m_next_table_fid; + family_id m_next_relation_fid; + + /** + Map specifying what kind of relation should be used to represent particular predicate. + */ + decl2kind_map m_pred_kinds; + + void register_relation_plugin_impl(relation_plugin * plugin); + + relation_manager(const relation_manager &); //private and undefined copy constructor + relation_manager & operator=(const relation_manager &); //private and undefined operator= + public: + relation_manager(context & ctx) : + m_context(ctx), + m_favourite_table_plugin(0), + m_favourite_relation_plugin(0), + m_next_table_fid(0), + m_next_relation_fid(0) {} + + virtual ~relation_manager(); + + void reset(); + void reset_relations(); + + context & get_context() const { return m_context; } + dl_decl_util & get_decl_util() const; + + family_id get_next_table_fid() { return m_next_table_fid++; } + family_id get_next_relation_fid(relation_plugin & claimer); + + + /** + Set what kind of relation is going to be used to represent the predicate \c pred. + + This function can be called only before the relation object for \c pred is created + (i.e. before the \c get_relation function is called with \c pred as argument for the + first time). + */ + void set_predicate_kind(func_decl * pred, family_id kind); + /** + Return the relation kind that was requested to represent the predicate \c pred by + \c set_predicate_kind. If there was no such request, return \c null_family_id. + */ + family_id get_requested_predicate_kind(func_decl * pred); + relation_base & get_relation(func_decl * pred); + relation_base * try_get_relation(func_decl * pred) const; + /** + \brief Store the relation \c rel under the predicate \c pred. The \c relation_manager + takes over the relation object. + */ + void store_relation(func_decl * pred, relation_base * rel); + + bool is_saturated(func_decl * pred) const { return m_saturated_rels.contains(pred); } + void mark_saturated(func_decl * pred) { m_saturated_rels.insert(pred); } + void reset_saturated_marks() { + if(!m_saturated_rels.empty()) { + m_saturated_rels.reset(); + } + } + + void collect_non_empty_predicates(decl_set & res) const; + void restrict_predicates(const decl_set & preds); + + void register_plugin(table_plugin * plugin); + /** + table_relation_plugins should not be passed to this function since they are + created automatically when registering a table plugin. + */ + void register_plugin(relation_plugin * plugin) { + SASSERT(!plugin->from_table()); + register_relation_plugin_impl(plugin); + } + + table_plugin & get_appropriate_plugin(const table_signature & t); + relation_plugin & get_appropriate_plugin(const relation_signature & t); + table_plugin * try_get_appropriate_plugin(const table_signature & t); + relation_plugin * try_get_appropriate_plugin(const relation_signature & t); + + table_plugin * get_table_plugin(symbol const& s); + relation_plugin * get_relation_plugin(symbol const& s); + relation_plugin & get_relation_plugin(family_id kind); + table_relation_plugin & get_table_relation_plugin(table_plugin & tp); + bool try_get_finite_product_relation_plugin(const relation_plugin & inner, + finite_product_relation_plugin * & res); + + table_base * mk_empty_table(const table_signature & s); + relation_base * mk_implicit_relation(const relation_signature & s, app * expr); + + relation_base * mk_empty_relation(const relation_signature & s, family_id kind); + relation_base * mk_empty_relation(const relation_signature & s, func_decl* pred); + + relation_base * mk_full_relation(const relation_signature & s, func_decl* pred, family_id kind); + relation_base * mk_full_relation(const relation_signature & s, func_decl* pred); + + relation_base * mk_table_relation(const relation_signature & s, table_base * table); + bool mk_empty_table_relation(const relation_signature & s, relation_base * & result); + + bool is_non_explanation(relation_signature const& s) const; + + + /** + \brief Convert relation value to table one. + + This function can be called only for the relation sorts that have a table counterpart. + */ + void relation_to_table(const relation_sort & sort, const relation_element & from, table_element & to); + + void table_to_relation(const relation_sort & sort, const table_element & from, relation_element & to); + void table_to_relation(const relation_sort & sort, const table_element & from, + const relation_fact::el_proxy & to); + void table_to_relation(const relation_sort & sort, const table_element & from, + relation_element_ref & to); + + bool relation_sort_to_table(const relation_sort & from, table_sort & to); + void from_predicate(func_decl * pred, unsigned arg_index, relation_sort & result); + void from_predicate(func_decl * pred, relation_signature & result); + + /** + \brief Convert relation signature to table signature and return true if successful. If false + is returned, the value of \c to is undefined. + */ + bool relation_signature_to_table(const relation_signature & from, table_signature & to); + + void relation_fact_to_table(const relation_signature & s, const relation_fact & from, + table_fact & to); + void table_fact_to_relation(const relation_signature & s, const table_fact & from, + relation_fact & to); + + + void set_cancel(bool f); + + + // ----------------------------------- + // + // relation operations + // + // ----------------------------------- + + //TODO: If multiple operation implementations are available, we may want to do something to + //select the best one here. + + /** + If \c allow_product_relation is true, we will create a join that builds a product relation, + if there is no other way to do the join. If \c allow_product_relation is false, we will return + zero in that case. + */ + relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, bool allow_product_relation=true); + + relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + const unsigned_vector & cols1, const unsigned_vector & cols2, bool allow_product_relation=true) { + SASSERT(cols1.size()==cols2.size()); + return mk_join_fn(t1, t2, cols1.size(), cols1.c_ptr(), cols2.c_ptr(), allow_product_relation); + } + + /** + \brief Return functor that transforms a table into one that lacks columns listed in + \c removed_cols array. + + The \c removed_cols cotains columns of table \c t in strictly ascending order. + */ + relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + + relation_transformer_fn * mk_project_fn(const relation_base & t, const unsigned_vector & removed_cols) { + return mk_project_fn(t, removed_cols.size(), removed_cols.c_ptr()); + } + + /** + \brief Return an operation that is a composition of a join an a project operation. + */ + relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols, bool allow_product_relation_join=true); + + relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, + const unsigned_vector & cols1, const unsigned_vector & cols2, + const unsigned_vector & removed_cols, bool allow_product_relation_join=true) { + return mk_join_project_fn(t1, t2, cols1.size(), cols1.c_ptr(), cols2.c_ptr(), removed_cols.size(), + removed_cols.c_ptr(), allow_product_relation_join); + } + + relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + relation_transformer_fn * mk_rename_fn(const relation_base & t, const unsigned_vector & permutation_cycle) { + return mk_rename_fn(t, permutation_cycle.size(), permutation_cycle.c_ptr()); + } + + /** + Like \c mk_rename_fn, only the permutation is not specified by cycle, but by a permutated array + of column number. + */ + relation_transformer_fn * mk_permutation_rename_fn(const relation_base & t, + const unsigned * permutation); + relation_transformer_fn * mk_permutation_rename_fn(const relation_base & t, + const unsigned_vector permutation) { + SASSERT(t.get_signature().size()==permutation.size()); + return mk_permutation_rename_fn(t, permutation.c_ptr()); + } + + + /** + The post-condition for an ideal union operation is be + + Union(tgt, src, delta): + tgt_1==tgt_0 \union src + delta_1== delta_0 \union ( tgt_1 \setminus tgt_0 ) + + A required post-condition is + + Union(tgt, src, delta): + tgt_1==tgt_0 \union src + tgt_1==tgt_0 => delta_1==delta_0 + delta_0 \subset delta_1 + delta_1 \subset (delta_0 \union tgt_1) + ( tgt_1 \setminus tgt_0 ) \subset delta_1 + + So that a sufficient implementation is + + Union(tgt, src, delta) { + oldTgt:=tgt.clone(); + tgt:=tgt \union src + if(tgt!=oldTgt) { + delta:=delta \union src //also ?delta \union tgt? would work + } + } + + If rules are compiled with all_or_nothing_deltas parameter set to true, a sufficient + post-condition is + Union(tgt, src, delta): + tgt_1==tgt_0 \union src + (tgt_1==tgt_0 || delta_0 is non-empty) <=> delta_1 is non-empty + */ + relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + + relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src) { + return mk_union_fn(tgt, src, static_cast(0)); + } + + /** + Similar to union, but this one should be used inside loops to allow for abstract + domain convergence. + */ + relation_union_fn * mk_widen_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, const unsigned_vector identical_cols) { + return mk_filter_identical_fn(t, identical_cols.size(), identical_cols.c_ptr()); + } + + relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + + relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + + relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols); + + /** + \brief Operations that returns all rows of \c t for which is column \c col equal to \c value + with the column \c col removed. + + This operation can often be efficiently implemented and is useful for evaluating rules + of the form + + F(x):-P("c",x). + */ + relation_transformer_fn * mk_select_equal_and_project_fn(const relation_base & t, + const relation_element & value, unsigned col); + + + relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & tgt, + const relation_base & src, unsigned joined_col_cnt, + const unsigned * tgt_cols, const unsigned * src_cols); + relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & tgt, + const relation_base & src, const unsigned_vector & tgt_cols, const unsigned_vector & src_cols) { + SASSERT(tgt_cols.size()==src_cols.size()); + return mk_filter_by_intersection_fn(tgt, src, tgt_cols.size(), tgt_cols.c_ptr(), src_cols.c_ptr()); + } + relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & tgt, + const relation_base & src); + + /** + The filter_by_negation postcondition: + filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, + corresponding columns in neg: d1,...,dN): + tgt_1:={x: x\in tgt_0 && ! \exists y: ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) } + */ + relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols); + relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, const unsigned_vector & t_cols, + const unsigned_vector & negated_cols) { + SASSERT(t_cols.size()==negated_cols.size()); + return mk_filter_by_negation_fn(t, negated_obj, t_cols.size(), t_cols.c_ptr(), negated_cols.c_ptr()); + } + + + // ----------------------------------- + // + // table operations + // + // ----------------------------------- + + + table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + + table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, + const unsigned_vector & cols1, const unsigned_vector & cols2) { + SASSERT(cols1.size()==cols2.size()); + return mk_join_fn(t1, t2, cols1.size(), cols1.c_ptr(), cols2.c_ptr()); + } + + /** + \brief Return functor that transforms a table into one that lacks columns listed in + \c removed_cols array. + + The \c removed_cols cotains columns of table \c t in strictly ascending order. + + If a project operation removes a non-functional column, all functional columns become + non-functional (so that none of the values in functional columns are lost) + */ + table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols); + + table_transformer_fn * mk_project_fn(const table_base & t, const unsigned_vector & removed_cols) { + return mk_project_fn(t, removed_cols.size(), removed_cols.c_ptr()); + } + + /** + \brief Return an operation that is a composition of a join an a project operation. + + This operation is equivalent to the two operations performed separately, unless functional + columns are involved. + + The ordinary project would make all of the functional columns into non-functional if any + non-functional column was removed. In function, however, we group columns into equivalence + classes (according to the equalities in \c cols1 and \c cols2) and make everything non-functional + only if some equivalence class of non-functional columns would have no non-functional columns + remain after the removal. + + This behavior is implemented in the \c table_signature::from_join_project function. + */ + table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols); + + table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, + const unsigned_vector & cols1, const unsigned_vector & cols2, + const unsigned_vector & removed_cols) { + return mk_join_project_fn(t1, t2, cols1.size(), cols1.c_ptr(), cols2.c_ptr(), removed_cols.size(), + removed_cols.c_ptr()); + } + + table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + table_transformer_fn * mk_rename_fn(const table_base & t, const unsigned_vector & permutation_cycle) { + return mk_rename_fn(t, permutation_cycle.size(), permutation_cycle.c_ptr()); + } + + /** + Like \c mk_rename_fn, only the permutation is not specified by cycle, but by a permutated array + of column number. + */ + table_transformer_fn * mk_permutation_rename_fn(const table_base & t, const unsigned * permutation); + table_transformer_fn * mk_permutation_rename_fn(const table_base & t, const unsigned_vector permutation) { + SASSERT(t.get_signature().size()==permutation.size()); + return mk_permutation_rename_fn(t, permutation.c_ptr()); + } + + + /** + The post-condition for an ideal union operation is be + + Union(tgt, src, delta): + tgt_1==tgt_0 \union src + delta_1== delta_0 \union ( tgt_1 \setminus tgt_0 ) + + A required post-condition is + + Union(tgt, src, delta): + tgt_1==tgt_0 \union src + tgt_1==tgt_0 => delta_1==delta_0 + delta_0 \subset delta_1 + delta_1 \subset (delta_0 \union tgt_1) + ( tgt_1 \setminus tgt_0 ) \subset delta_1 + + So that a sufficient implementation is + + Union(tgt, src, delta) { + oldTgt:=tgt.clone(); + tgt:=tgt \union src + if(tgt!=oldTgt) { + delta:=delta \union src //also ?delta \union tgt? would work + } + } + + If rules are compiled with all_or_nothing_deltas parameter set to true, a sufficient + post-condition is + Union(tgt, src, delta): + tgt_1==tgt_0 \union src + (tgt_1==tgt_0 || delta_0 is non-empty) <=> delta_1 is non-empty + */ + table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, + const table_base * delta); + + table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src) { + return mk_union_fn(tgt, src, static_cast(0)); + } + + /** + Similar to union, but this one should be used inside loops to allow for abstract + domain convergence. + */ + table_union_fn * mk_widen_fn(const table_base & tgt, const table_base & src, + const table_base * delta); + + table_mutator_fn * mk_filter_identical_fn(const table_base & t, unsigned col_cnt, + const unsigned * identical_cols); + table_mutator_fn * mk_filter_identical_fn(const table_base & t, const unsigned_vector identical_cols) { + return mk_filter_identical_fn(t, identical_cols.size(), identical_cols.c_ptr()); + } + + table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value, + unsigned col); + + table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition); + + table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, app * condition, + unsigned removed_col_cnt, const unsigned * removed_cols); + + /** + \brief Operations that returns all rows of \c t for which is column \c col equal to \c value + with the column \c col removed. + + This operation can often be efficiently implemented and is useful for evaluating rules + of the form + + F(x):-P("c",x). + */ + table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t, + const table_element & value, unsigned col); + + table_intersection_filter_fn * mk_filter_by_intersection_fn(const table_base & t, + const table_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols); + table_intersection_filter_fn * mk_filter_by_intersection_fn(const table_base & t, + const table_base & src, const unsigned_vector & t_cols, const unsigned_vector & src_cols) { + SASSERT(t_cols.size()==src_cols.size()); + return mk_filter_by_intersection_fn(t, src, t_cols.size(), t_cols.c_ptr(), src_cols.c_ptr()); + } + + /** + The filter_by_negation postcondition: + filter_by_negation(tgt, neg, columns in tgt: c1,...,cN, + corresponding columns in neg: d1,...,dN): + tgt_1:={x: x\in tgt_0 && ! \exists y: ( y \in neg & pi_c1(x)= pi_d1(y) & ... & pi_cN(x)= pi_dN(y) ) } + */ + table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, const table_base & negated_obj, + unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols); + table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, const table_base & negated_obj, + const unsigned_vector & t_cols, const unsigned_vector & negated_cols) { + SASSERT(t_cols.size()==negated_cols.size()); + return mk_filter_by_negation_fn(t, negated_obj, t_cols.size(), t_cols.c_ptr(), negated_cols.c_ptr()); + } + + /** + \c t must contain at least one functional column. + + Created object takes ownership of the \c mapper object. + */ + virtual table_mutator_fn * mk_map_fn(const table_base & t, table_row_mutator_fn * mapper); + + /** + \c t must contain at least one functional column. + + Created object takes ownership of the \c mapper object. + */ + virtual table_transformer_fn * mk_project_with_reduce_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols, table_row_pair_reduce_fn * reducer); + + + + + // ----------------------------------- + // + // output functions + // + // ----------------------------------- + + + std::string to_nice_string(const relation_element & el) const; + /** + This one may give a nicer representation of \c el than the + \c to_nice_string(const relation_element & el) function, by unsing the information about the sort + of the element. + */ + std::string to_nice_string(const relation_sort & s, const relation_element & el) const; + std::string to_nice_string(const relation_sort & s) const; + std::string to_nice_string(const relation_signature & s) const; + + void display(std::ostream & out) const; + void display_relation_sizes(std::ostream & out) const; + void display_output_tables(rule_set const& rules, std::ostream & out) const; + + private: + relation_intersection_filter_fn * try_mk_default_filter_by_intersection_fn(const relation_base & t, + const relation_base & src, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * src_cols); + + }; + + /** + This is a helper class for relation_plugins whose relations can be of various kinds. + */ + template > + class rel_spec_store { + typedef relation_signature::hash r_hash; + typedef relation_signature::eq r_eq; + + typedef map family_id_idx_store; + typedef map sig2store; + + typedef u_map family_id2spec; + typedef map sig2spec_store; + + relation_plugin & m_parent; + svector m_allocated_kinds; + sig2store m_kind_assignment; + sig2spec_store m_kind_specs; + + + relation_manager & get_manager() { return m_parent.get_manager(); } + + void add_new_kind() { + add_available_kind(get_manager().get_next_relation_fid(m_parent)); + } + + public: + rel_spec_store(relation_plugin & parent) : m_parent(parent) {} + + ~rel_spec_store() { + reset_dealloc_values(m_kind_assignment); + reset_dealloc_values(m_kind_specs); + } + + void add_available_kind(family_id k) { + m_allocated_kinds.push_back(k); + } + + bool contains_signature(relation_signature const& sig) const { + return m_kind_assignment.contains(sig); + } + + family_id get_relation_kind(const relation_signature & sig, const Spec & spec) { + typename sig2store::entry * e = m_kind_assignment.find_core(sig); + if(!e) { + e = m_kind_assignment.insert_if_not_there2(sig, alloc(family_id_idx_store)); + m_kind_specs.insert(sig, alloc(family_id2spec)); + } + family_id_idx_store & ids = *e->get_data().m_value; + + unsigned res_idx; + if(!ids.find(spec, res_idx)) { + res_idx = ids.size(); + if(res_idx==m_allocated_kinds.size()) { + add_new_kind(); + } + SASSERT(res_idxinsert(m_allocated_kinds[res_idx], spec); + } + return m_allocated_kinds[res_idx]; + } + + void get_relation_spec(const relation_signature & sig, family_id kind, Spec & spec) { + family_id2spec * idspecs = m_kind_specs.find(sig); + spec = idspecs->find(kind); + } + + }; + +}; + +#endif /* _DL_RELATION_MANAGER_H_ */ + diff --git a/src/muz/rel/dl_sieve_relation.cpp b/src/muz/rel/dl_sieve_relation.cpp new file mode 100644 index 000000000..9f9419089 --- /dev/null +++ b/src/muz/rel/dl_sieve_relation.cpp @@ -0,0 +1,666 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_mk_explanations.cpp + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-11-08. + +Revision History: + +--*/ + +#include +#include"ast_pp.h" +#include"dl_sieve_relation.h" + +namespace datalog { + + // ----------------------------------- + // + // sieve_relation + // + // ----------------------------------- + + sieve_relation::sieve_relation(sieve_relation_plugin & p, const relation_signature & s, + const bool * inner_columns, relation_base * inner) + : relation_base(p, s), m_inner_cols(s.size(), inner_columns), m_inner(inner) { + unsigned n = s.size(); + for(unsigned i=0; i 0; ) { + --i; + unsigned idx = m_inner2sig[i]; + s.push_back(m.mk_var(idx, sig[i])); + } + get_inner().to_formula(tmp); + get_plugin().get_context().get_var_subst()(tmp, sz, s.c_ptr(), fml); + } + + + void sieve_relation::display(std::ostream & out) const { + out << "Sieve relation "; + print_container(m_inner_cols, out); + out <<"\n"; + get_inner().display(out); + } + + + // ----------------------------------- + // + // sieve_relation_plugin + // + // ----------------------------------- + + sieve_relation_plugin & sieve_relation_plugin::get_plugin(relation_manager & rmgr) { + sieve_relation_plugin * res = static_cast(rmgr.get_relation_plugin(get_name())); + if(!res) { + res = alloc(sieve_relation_plugin, rmgr); + rmgr.register_plugin(res); + } + return *res; + } + + sieve_relation& sieve_relation_plugin::get(relation_base& r) { + return dynamic_cast(r); + } + + sieve_relation const & sieve_relation_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + + sieve_relation* sieve_relation_plugin::get(relation_base* r) { + return dynamic_cast(r); + } + + sieve_relation const* sieve_relation_plugin::get(relation_base const* r) { + return dynamic_cast(r); + } + + sieve_relation_plugin::sieve_relation_plugin(relation_manager & manager) + : relation_plugin(get_name(), manager, ST_SIEVE_RELATION), + m_spec_store(*this) {} + + void sieve_relation_plugin::initialize(family_id fid) { + relation_plugin::initialize(fid); + m_spec_store.add_available_kind(get_kind()); + } + + family_id sieve_relation_plugin::get_relation_kind(const relation_signature & sig, + const bool * inner_columns, family_id inner_kind) { + rel_spec spec(sig.size(), inner_columns, inner_kind); + return m_spec_store.get_relation_kind(sig, spec); + } + + family_id sieve_relation_plugin::get_relation_kind(sieve_relation & r, const bool * inner_columns) { + const relation_signature & sig = r.get_signature(); + return get_relation_kind(sig, inner_columns, r.get_inner().get_kind()); + } + + void sieve_relation_plugin::extract_inner_columns(const relation_signature & s, relation_plugin & inner, + svector & inner_columns) { + SASSERT(inner_columns.size()==s.size()); + unsigned n = s.size(); + relation_signature inner_sig_singleton; + for(unsigned i=0; i & inner_columns, relation_signature & inner_sig) { + SASSERT(inner_columns.size()==s.size()); + inner_sig.reset(); + unsigned n = s.size(); + for(unsigned i=0; i inner_cols(s.size()); + extract_inner_columns(s, inner_cols.c_ptr()); + collect_inner_signature(s, inner_cols, inner_sig); +#endif + } + + bool sieve_relation_plugin::can_handle_signature(const relation_signature & s) { + //we do not want this plugin to handle anything by default + return false; +#if 0 + relation_signature inner_sig; + extract_inner_signature(s, inner_sig); + SASSERT(inner_sig.size()<=s.size()); + return !inner_sig.empty() && inner_sig.size()!=s.size(); +#endif + } + + sieve_relation * sieve_relation_plugin::mk_from_inner(const relation_signature & s, const bool * inner_columns, + relation_base * inner_rel) { + SASSERT(!inner_rel->get_plugin().is_sieve_relation()); //it does not make sense to make a sieve of a sieve + return alloc(sieve_relation, *this, s, inner_columns, inner_rel); + } + + sieve_relation * sieve_relation_plugin::mk_empty(const sieve_relation & original) { + return static_cast(mk_empty(original.get_signature(), original.get_kind())); + } + + relation_base * sieve_relation_plugin::mk_empty(const relation_base & original) { + return mk_empty(static_cast(original)); + } + + relation_base * sieve_relation_plugin::mk_empty(const relation_signature & s, family_id kind) { + rel_spec spec; + m_spec_store.get_relation_spec(s, kind, spec); + relation_signature inner_sig; + collect_inner_signature(s, spec.m_inner_cols, inner_sig); + relation_base * inner = get_manager().mk_empty_relation(inner_sig, spec.m_inner_kind); + return mk_from_inner(s, spec.m_inner_cols.c_ptr(), inner); + } + + + relation_base * sieve_relation_plugin::mk_empty(const relation_signature & s) { + UNREACHABLE(); + return 0; +#if 0 + svector inner_cols(s.size()); + extract_inner_columns(s, inner_cols.c_ptr()); + return mk_empty(s, inner_cols.c_ptr()); +#endif + } + + sieve_relation * sieve_relation_plugin::mk_empty(const relation_signature & s, relation_plugin & inner_plugin) { + SASSERT(!inner_plugin.is_sieve_relation()); //it does not make sense to make a sieve of a sieve + svector inner_cols(s.size()); + extract_inner_columns(s, inner_plugin, inner_cols); + relation_signature inner_sig; + collect_inner_signature(s, inner_cols, inner_sig); + relation_base * inner_rel = inner_plugin.mk_empty(inner_sig); + return mk_from_inner(s, inner_cols, inner_rel); + } + + relation_base * sieve_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { + relation_signature empty_sig; + relation_plugin& plugin = get_manager().get_appropriate_plugin(s); + relation_base * inner = plugin.mk_full(p, empty_sig, null_family_id); + svector inner_cols; + inner_cols.resize(s.size(), false); + return mk_from_inner(s, inner_cols, inner); + } + + sieve_relation * sieve_relation_plugin::mk_full(func_decl* p, const relation_signature & s, relation_plugin & inner_plugin) { + SASSERT(!inner_plugin.is_sieve_relation()); //it does not make sense to make a sieve of a sieve + svector inner_cols(s.size()); + extract_inner_columns(s, inner_plugin, inner_cols); + relation_signature inner_sig; + collect_inner_signature(s, inner_cols, inner_sig); + relation_base * inner_rel = inner_plugin.mk_full(p, inner_sig, null_family_id); + return mk_from_inner(s, inner_cols, inner_rel); + } + + class sieve_relation_plugin::join_fn : public convenient_relation_join_fn { + sieve_relation_plugin & m_plugin; + unsigned_vector m_inner_cols_1; + unsigned_vector m_inner_cols_2; + svector m_result_inner_cols; + + scoped_ptr m_inner_join_fun; + public: + join_fn(sieve_relation_plugin & p, const relation_base & r1, const relation_base & r2, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2, relation_join_fn * inner_join_fun) + : convenient_relation_join_fn(r1.get_signature(), r2.get_signature(), col_cnt, cols1, cols2), + m_plugin(p), + m_inner_join_fun(inner_join_fun) { + bool r1_sieved = r1.get_plugin().is_sieve_relation(); + bool r2_sieved = r2.get_plugin().is_sieve_relation(); + const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : 0; + const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : 0; + if(r1_sieved) { + m_result_inner_cols.append(sr1->m_inner_cols); + } + else { + m_result_inner_cols.resize(r1.get_signature().size(), true); + } + if(r2_sieved) { + m_result_inner_cols.append(sr2->m_inner_cols); + } + else { + m_result_inner_cols.resize(m_result_inner_cols.size() + r2.get_signature().size(), true); + } + } + + virtual relation_base * operator()(const relation_base & r1, const relation_base & r2) { + bool r1_sieved = r1.get_plugin().is_sieve_relation(); + bool r2_sieved = r2.get_plugin().is_sieve_relation(); + SASSERT(r1_sieved || r2_sieved); + const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : 0; + const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : 0; + const relation_base & inner1 = r1_sieved ? sr1->get_inner() : r1; + const relation_base & inner2 = r2_sieved ? sr2->get_inner() : r2; + + relation_base * inner_res = (*m_inner_join_fun)(inner1, inner2); + + return m_plugin.mk_from_inner(get_result_signature(), m_result_inner_cols.c_ptr(), inner_res); + } + }; + + relation_join_fn * sieve_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if( &r1.get_plugin()!=this && &r2.get_plugin()!=this ) { + //we create just operations that involve the current plugin + return 0; + } + bool r1_sieved = r1.get_plugin().is_sieve_relation(); + bool r2_sieved = r2.get_plugin().is_sieve_relation(); + const sieve_relation * sr1 = r1_sieved ? static_cast(&r1) : 0; + const sieve_relation * sr2 = r2_sieved ? static_cast(&r2) : 0; + const relation_base & inner1 = r1_sieved ? sr1->get_inner() : r1; + const relation_base & inner2 = r2_sieved ? sr2->get_inner() : r2; + + unsigned_vector inner_cols1; + unsigned_vector inner_cols2; + + for(unsigned i=0; iis_inner_col(cols1[i])) { + continue; + } + if(r2_sieved && !sr2->is_inner_col(cols2[i])) { + continue; + } + inner_cols1.push_back( r1_sieved ? sr1->get_inner_col(cols1[i]) : cols1[i] ); + inner_cols2.push_back( r2_sieved ? sr2->get_inner_col(cols2[i]) : cols2[i] ); + } + + relation_join_fn * inner_join_fun = get_manager().mk_join_fn(inner1, inner2, inner_cols1, inner_cols2, false); + if(!inner_join_fun) { + return 0; + } + return alloc(join_fn, *this, r1, r2, col_cnt, cols1, cols2, inner_join_fun); + } + + + class sieve_relation_plugin::transformer_fn : public convenient_relation_transformer_fn { + svector m_result_inner_cols; + + scoped_ptr m_inner_fun; + public: + transformer_fn(relation_transformer_fn * inner_fun, const relation_signature & result_sig, + const bool * result_inner_cols) + : m_result_inner_cols(result_sig.size(), result_inner_cols), m_inner_fun(inner_fun) { + get_result_signature() = result_sig; + } + + virtual relation_base * operator()(const relation_base & r0) { + SASSERT(r0.get_plugin().is_sieve_relation()); + const sieve_relation & r = static_cast(r0); + sieve_relation_plugin & plugin = r.get_plugin(); + + relation_base * inner_res = (*m_inner_fun)(r.get_inner()); + + return plugin.mk_from_inner(get_result_signature(), m_result_inner_cols.c_ptr(), inner_res); + } + }; + + relation_transformer_fn * sieve_relation_plugin::mk_project_fn(const relation_base & r0, unsigned col_cnt, + const unsigned * removed_cols) { + if(&r0.get_plugin()!=this) { + return 0; + } + const sieve_relation & r = static_cast(r0); + unsigned_vector inner_removed_cols; + + for(unsigned i=0; i result_inner_cols = r.m_inner_cols; + project_out_vector_columns(result_inner_cols, col_cnt, removed_cols); + + relation_signature result_sig; + relation_signature::from_project(r.get_signature(), col_cnt, removed_cols, result_sig); + + relation_transformer_fn * inner_fun; + if(inner_removed_cols.empty()) { + inner_fun = alloc(identity_relation_transformer_fn); + } + else { + inner_fun = get_manager().mk_project_fn(r.get_inner(), inner_removed_cols); + } + + if(!inner_fun) { + return 0; + } + return alloc(transformer_fn, inner_fun, result_sig, result_inner_cols.c_ptr()); + } + + relation_transformer_fn * sieve_relation_plugin::mk_rename_fn(const relation_base & r0, + unsigned cycle_len, const unsigned * permutation_cycle) { + if(&r0.get_plugin()!=this) { + return 0; + } + const sieve_relation & r = static_cast(r0); + + unsigned sig_sz = r.get_signature().size(); + unsigned_vector permutation; + add_sequence(0, sig_sz, permutation); + permutate_by_cycle(permutation, cycle_len, permutation_cycle); + + bool inner_identity; + unsigned_vector inner_permutation; + collect_sub_permutation(permutation, r.m_sig2inner, inner_permutation, inner_identity); + + svector result_inner_cols = r.m_inner_cols; + permutate_by_cycle(result_inner_cols, cycle_len, permutation_cycle); + + relation_signature result_sig; + relation_signature::from_rename(r.get_signature(), cycle_len, permutation_cycle, result_sig); + + relation_transformer_fn * inner_fun = + get_manager().mk_permutation_rename_fn(r.get_inner(), inner_permutation); + if(!inner_fun) { + return 0; + } + return alloc(transformer_fn, inner_fun, result_sig, result_inner_cols.c_ptr()); + } + + + class sieve_relation_plugin::union_fn : public relation_union_fn { + scoped_ptr m_union_fun; + public: + union_fn(relation_union_fn * union_fun) : m_union_fun(union_fun) {} + + virtual void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) { + bool tgt_sieved = tgt.get_plugin().is_sieve_relation(); + bool src_sieved = src.get_plugin().is_sieve_relation(); + bool delta_sieved = delta && delta->get_plugin().is_sieve_relation(); + sieve_relation * stgt = tgt_sieved ? static_cast(&tgt) : 0; + const sieve_relation * ssrc = src_sieved ? static_cast(&src) : 0; + sieve_relation * sdelta = delta_sieved ? static_cast(delta) : 0; + relation_base & itgt = tgt_sieved ? stgt->get_inner() : tgt; + const relation_base & isrc = src_sieved ? ssrc->get_inner() : src; + relation_base * idelta = delta_sieved ? &sdelta->get_inner() : delta; + + (*m_union_fun)(itgt, isrc, idelta); + } + }; + + relation_union_fn * sieve_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if(&tgt.get_plugin()!=this && &src.get_plugin()!=this && (delta && &delta->get_plugin()!=this)) { + //we create the operation only if it involves this plugin + return 0; + } + + bool tgt_sieved = tgt.get_plugin().is_sieve_relation(); + bool src_sieved = src.get_plugin().is_sieve_relation(); + bool delta_sieved = delta && delta->get_plugin().is_sieve_relation(); + const sieve_relation * stgt = tgt_sieved ? static_cast(&tgt) : 0; + const sieve_relation * ssrc = src_sieved ? static_cast(&src) : 0; + const sieve_relation * sdelta = delta_sieved ? static_cast(delta) : 0; + const relation_base & itgt = tgt_sieved ? stgt->get_inner() : tgt; + const relation_base & isrc = src_sieved ? ssrc->get_inner() : src; + const relation_base * idelta = delta_sieved ? &sdelta->get_inner() : delta; + + //Now we require that the sieved and inner columns must match on all relations. + //We may want to allow for some cases of misalignment even though it could introcude imprecision + if( tgt_sieved && src_sieved && (!delta || delta_sieved) ) { + if( !vectors_equal(stgt->m_inner_cols, ssrc->m_inner_cols) + || (delta && !vectors_equal(stgt->m_inner_cols, sdelta->m_inner_cols)) ) { + return 0; + } + } + else { + if( (stgt && !stgt->no_sieved_columns()) + || (ssrc && !ssrc->no_sieved_columns()) + || (sdelta && !sdelta->no_sieved_columns()) ) { + //We have an unsieved relation and then some relation with some sieved columns, + //which means there is an misalignment. + return 0; + } + } + + relation_union_fn * union_fun = get_manager().mk_union_fn(itgt, isrc, idelta); + if(!union_fun) { + return 0; + } + + return alloc(union_fn, union_fun); + } + + + class sieve_relation_plugin::filter_fn : public relation_mutator_fn { + scoped_ptr m_inner_fun; + public: + filter_fn(relation_mutator_fn * inner_fun) + : m_inner_fun(inner_fun) {} + + virtual void operator()(relation_base & r0) { + SASSERT(r0.get_plugin().is_sieve_relation()); + sieve_relation & r = static_cast(r0); + + (*m_inner_fun)(r.get_inner()); + } + }; + + relation_mutator_fn * sieve_relation_plugin::mk_filter_identical_fn(const relation_base & r0, + unsigned col_cnt, const unsigned * identical_cols) { + if(&r0.get_plugin()!=this) { + return 0; + } + const sieve_relation & r = static_cast(r0); + unsigned_vector inner_icols; + + //we ignore the columns which do not belong to the inner relation (which introduces imprecision) + for(unsigned i=0; i(r0); + if(!r.is_inner_col(col)) { + //if the column which do not belong to the inner relation, we do nothing (which introduces imprecision) + return alloc(identity_relation_mutator_fn); + } + unsigned inner_col = r.get_inner_col(col); + + relation_mutator_fn * inner_fun = get_manager().mk_filter_equal_fn(r.get_inner(), value, inner_col); + if(!inner_fun) { + return 0; + } + return alloc(filter_fn, inner_fun); + } + + relation_mutator_fn * sieve_relation_plugin::mk_filter_interpreted_fn(const relation_base & rb, + app * condition) { + if(&rb.get_plugin()!=this) { + return 0; + } + ast_manager & m = get_ast_manager(); + const sieve_relation & r = static_cast(rb); + const relation_signature sig = r.get_signature(); + unsigned sz = sig.size(); + + var_idx_set& cond_vars = get_context().get_rule_manager().collect_vars(condition); + expr_ref_vector subst_vect(m); + subst_vect.resize(sz); + unsigned subst_ofs = sz-1; + for(unsigned i=0; i m_inner_fun; + public: + negation_filter_fn(relation_intersection_filter_fn * inner_fun) + : m_inner_fun(inner_fun) {} + + virtual void operator()(relation_base & r, const relation_base & neg) { + bool r_sieved = r.get_plugin().is_sieve_relation(); + bool neg_sieved = neg.get_plugin().is_sieve_relation(); + SASSERT(r_sieved || neg_sieved); + sieve_relation * sr = r_sieved ? static_cast(&r) : 0; + const sieve_relation * sneg = neg_sieved ? static_cast(&neg) : 0; + relation_base & inner_r = r_sieved ? sr->get_inner() : r; + const relation_base & inner_neg = neg_sieved ? sneg->get_inner() : neg; + + (*m_inner_fun)(inner_r, inner_neg); + } + }; + + relation_intersection_filter_fn * sieve_relation_plugin::mk_filter_by_negation_fn(const relation_base & r, + const relation_base & neg, unsigned col_cnt, const unsigned * r_cols, + const unsigned * neg_cols) { + if(&r.get_plugin()!=this && &neg.get_plugin()!=this) { + //we create just operations that involve the current plugin + return 0; + } + bool r_sieved = r.get_plugin().is_sieve_relation(); + bool neg_sieved = neg.get_plugin().is_sieve_relation(); + SASSERT(r_sieved || neg_sieved); + const sieve_relation * sr = r_sieved ? static_cast(&r) : 0; + const sieve_relation * sneg = neg_sieved ? static_cast(&neg) : 0; + const relation_base & inner_r = r_sieved ? sr->get_inner() : r; + const relation_base & inner_neg = neg_sieved ? sneg->get_inner() : neg; + + unsigned_vector ir_cols; + unsigned_vector ineg_cols; + + for(unsigned i=0; iis_inner_col(r_cols[i]); + bool neg_col_inner = neg_sieved && !sneg->is_inner_col(neg_cols[i]); + if(r_col_inner && neg_col_inner) { + ir_cols.push_back( r_sieved ? sr->get_inner_col(i) : i ); + ineg_cols.push_back( neg_sieved ? sneg->get_inner_col(i) : i ); + } + else if(!r_col_inner && neg_col_inner) { + //Sieved (i.e. full) column in r is matched on an inner column in neg. + //If we assume the column in neg is not full, no rows from the inner relation of + //r would be removed. So in this case we perform no operation at cost of a little + //impresicion. + return alloc(identity_relation_intersection_filter_fn); + } + else { + //Inner or sieved column in r must match a sieved column in neg. + //Since sieved columns are full, this is always true so we can skip the equality. + continue; + } + } + + relation_intersection_filter_fn * inner_fun = + get_manager().mk_filter_by_negation_fn(inner_r, inner_neg, ir_cols, ineg_cols); + if(!inner_fun) { + return 0; + } + return alloc(negation_filter_fn, inner_fun); + } + + +}; diff --git a/src/muz/rel/dl_sieve_relation.h b/src/muz/rel/dl_sieve_relation.h new file mode 100644 index 000000000..48402cd6d --- /dev/null +++ b/src/muz/rel/dl_sieve_relation.h @@ -0,0 +1,198 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_sieve_relation.h + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-11-11. + +Revision History: + +--*/ + +#ifndef _DL_SIEVE_RELATION_H_ +#define _DL_SIEVE_RELATION_H_ + +#include "dl_context.h" +#include "dl_relation_manager.h" + +namespace datalog { + + class sieve_relation; + + class sieve_relation_plugin : public relation_plugin { + friend class sieve_relation; + public: + struct rel_spec { + svector m_inner_cols; + family_id m_inner_kind; + + /** + Create uninitialized rel_spec. + */ + rel_spec() {} + /** + \c inner_kind==null_family_id means we will not specify a relation kind when requesting + the relation object from the relation_manager. + + \c inner_kind==null_family_id cannot hold in a specification of existing relation object. + */ + rel_spec(unsigned sig_sz, const bool * inner_cols, family_id inner_kind=null_family_id) + : m_inner_cols(sig_sz, inner_cols), m_inner_kind(inner_kind) {} + + bool operator==(const rel_spec & o) const { + return m_inner_kind==o.m_inner_kind && vectors_equal(m_inner_cols, o.m_inner_cols); + } + + struct hash { + unsigned operator()(const rel_spec & s) const { + return svector_hash()(s.m_inner_cols)^s.m_inner_kind; + } + }; + }; + private: + + class join_fn; + class transformer_fn; + class union_fn; + class filter_fn; + class negation_filter_fn; + + rel_spec_store > m_spec_store; + + family_id get_relation_kind(sieve_relation & r, const bool * inner_columns); + + void extract_inner_columns(const relation_signature & s, relation_plugin & inner, + svector & inner_columns); + void extract_inner_signature(const relation_signature & s, relation_signature & inner_sig); + void collect_inner_signature(const relation_signature & s, const svector & inner_columns, + relation_signature & inner_sig); + public: + static symbol get_name() { return symbol("sieve_relation"); } + static sieve_relation_plugin& get_plugin(relation_manager & rmgr); + + static sieve_relation& get(relation_base& r); + static sieve_relation const & get(relation_base const& r); + static sieve_relation* get(relation_base* r); + static sieve_relation const* get(relation_base const* r); + + sieve_relation_plugin(relation_manager & manager); + + virtual void initialize(family_id fid); + + family_id get_relation_kind(const relation_signature & sig, const bool * inner_columns, + family_id inner_kind); + family_id get_relation_kind(const relation_signature & sig, const svector & inner_columns, + family_id inner_kind) { + SASSERT(sig.size()==inner_columns.size()); + return get_relation_kind(sig, inner_columns.c_ptr(), inner_kind); + } + + virtual bool can_handle_signature(const relation_signature & s); + + virtual relation_base * mk_empty(const relation_signature & s); + sieve_relation * mk_empty(const sieve_relation & original); + virtual relation_base * mk_empty(const relation_base & original); + virtual relation_base * mk_empty(const relation_signature & s, family_id kind); + sieve_relation * mk_empty(const relation_signature & s, relation_plugin & inner_plugin); + + virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + sieve_relation * mk_full(func_decl* p, const relation_signature & s, relation_plugin & inner_plugin); + + + sieve_relation * mk_from_inner(const relation_signature & s, const bool * inner_columns, + relation_base * inner_rel); + sieve_relation * mk_from_inner(const relation_signature & s, const svector inner_columns, + relation_base * inner_rel) { + SASSERT(inner_columns.size()==s.size()); + return mk_from_inner(s, inner_columns.c_ptr(), inner_rel); + } + + protected: + + virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols); + }; + + + // ----------------------------------- + // + // sieve_relation + // + // ----------------------------------- + + class sieve_relation : public relation_base { + friend class sieve_relation_plugin; + friend class sieve_relation_plugin::join_fn; + friend class sieve_relation_plugin::transformer_fn; + friend class sieve_relation_plugin::union_fn; + friend class sieve_relation_plugin::filter_fn; + + svector m_inner_cols; + + unsigned_vector m_sig2inner; + unsigned_vector m_inner2sig; + unsigned_vector m_ignored_cols; //in ascending order, so that it can be used in project-like functions + + scoped_rel m_inner; + + + sieve_relation(sieve_relation_plugin & p, const relation_signature & s, + const bool * inner_columns, relation_base * inner); + + public: + sieve_relation_plugin & get_plugin() const { + return static_cast(relation_base::get_plugin()); + } + + bool is_inner_col(unsigned idx) const { return m_sig2inner[idx]!=UINT_MAX; } + unsigned get_inner_col(unsigned idx) const { + SASSERT(is_inner_col(idx)); + return m_sig2inner[idx]; + } + bool no_sieved_columns() const { return m_ignored_cols.size()==0; } + bool no_inner_columns() const { return m_ignored_cols.size()==get_signature().size(); } + + relation_base & get_inner() { return *m_inner; } + const relation_base & get_inner() const { return *m_inner; } + + virtual void add_fact(const relation_fact & f); + virtual bool contains_fact(const relation_fact & f) const; + virtual sieve_relation * clone() const; + virtual relation_base * complement(func_decl*p) const; + virtual void to_formula(expr_ref& fml) const; + + virtual bool empty() const { return get_inner().empty(); } + virtual void reset() { get_inner().reset(); } + virtual unsigned get_size_estimate_rows() const { return get_inner().get_size_estimate_rows(); } + virtual unsigned get_size_estimate_bytes() const { return get_inner().get_size_estimate_bytes(); } + + virtual void display(std::ostream & out) const; + }; + + +}; + +#endif /* _DL_SIEVE_RELATION_H_ */ + diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp new file mode 100644 index 000000000..52d9618b8 --- /dev/null +++ b/src/muz/rel/dl_sparse_table.cpp @@ -0,0 +1,1246 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_sparse_table.cpp + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-24. + +Revision History: + +--*/ + +#include +#include"dl_context.h" +#include"dl_util.h" +#include"dl_sparse_table.h" + +namespace datalog { + + // ----------------------------------- + // + // entry_storage + // + // ----------------------------------- + + entry_storage::store_offset entry_storage::insert_or_get_reserve_content() { + SASSERT(has_reserve()); + store_offset entry_ofs = m_data_indexer.insert_if_not_there(m_reserve); + if (m_reserve == entry_ofs) { + //entry inserted, so reserve is no longer a reserve + m_reserve = NO_RESERVE; + } + return entry_ofs; + } + bool entry_storage::insert_reserve_content() { + SASSERT(has_reserve()); + store_offset entry_ofs = m_data_indexer.insert_if_not_there(m_reserve); + if (m_reserve == entry_ofs) { + //entry inserted, so reserve is no longer a reserve + m_reserve = NO_RESERVE; + return true; + } + return false; + } + + bool entry_storage::remove_reserve_content() { + SASSERT(has_reserve()); + store_offset entry_ofs; + if (!find_reserve_content(entry_ofs)) { + //the fact was not in the table + return false; + } + remove_offset(entry_ofs); + return true; + } + + void entry_storage::remove_offset(store_offset ofs) { + m_data_indexer.remove(ofs); + store_offset last_ofs = after_last_offset() - m_entry_size; + if (ofs!=last_ofs) { + SASSERT(ofs + m_entry_size <= last_ofs); + //we don't want any holes, so we put the last element at the place + //of the removed one + m_data_indexer.remove(last_ofs); + char * base = &m_data.get(0); + memcpy(base+ofs, base+last_ofs, m_entry_size); + m_data_indexer.insert(ofs); + } + if (has_reserve()) { + //we already have a reserve, so we need to shrink a little to keep having just one + resize_data(m_data_size-m_entry_size); + } + m_reserve=last_ofs; + } + + unsigned entry_storage::get_size_estimate_bytes() const { + unsigned sz = m_data.capacity(); + sz += m_data_indexer.capacity()*sizeof(storage_indexer::entry); + return sz; + } + + // ----------------------------------- + // + // sparse_table::column_layout + // + // ----------------------------------- + + unsigned get_domain_length(uint64 dom_size) { + SASSERT(dom_size>0); + + unsigned length = 0; + + unsigned dom_size_sm; + if (dom_size>UINT_MAX) { + dom_size_sm = static_cast(dom_size>>32); + length += 32; + if ( (dom_size&UINT_MAX)!=0 && dom_size_sm!=UINT_MAX ) { + dom_size_sm++; + } + } + else { + dom_size_sm=static_cast(dom_size); + } + if (dom_size_sm == 1) { + length += 1; //unary domains + } + else if (dom_size_sm > 0x80000000u) { + length += 32; + } + else { + length += get_num_1bits(next_power_of_two(dom_size_sm)-1); //ceil(log2(dom_size)) + } + return length; + } + + sparse_table::column_layout::column_layout(const table_signature & sig) + : m_functional_col_cnt(sig.functional_columns()) { + SASSERT(sig.size() > 0); + unsigned ofs = 0; + unsigned sig_sz = sig.size(); + unsigned first_functional = sig_sz-m_functional_col_cnt; + for (unsigned i=0; i0); + SASSERT(length<=64); + + if (size() > 0 && (length > 54 || i == first_functional)) { + //large domains must start byte-aligned, as well as functional columns + make_byte_aligned_end(size()-1); + ofs = back().next_ofs(); + } + + push_back(column_info(ofs, length)); + ofs += length; + } + make_byte_aligned_end(size()-1); + SASSERT(back().next_ofs()%8 == 0);//the entries must be aligned to whole bytes + m_entry_size = back().next_ofs()/8; + if (m_functional_col_cnt) { + SASSERT((*this)[first_functional].m_offset%8 == 0); + m_functional_part_size = m_entry_size - (*this)[first_functional].m_offset/8; + } + else { + m_functional_part_size = 0; + } + } + + void sparse_table::column_layout::make_byte_aligned_end(unsigned col_index0) { + unsigned ofs = (*this)[col_index0].next_ofs(); + unsigned ofs_bit_part = ofs%8; + unsigned rounded_ofs = (ofs_bit_part == 0) ? ofs : (ofs+8-ofs_bit_part); + + if (rounded_ofs!=ofs) { + SASSERT(rounded_ofs>ofs); + int diff = rounded_ofs-ofs; + unsigned col_idx = col_index0+1; + while(diff!=0) { + //we should always be able to fix the alignment by the time we reach zero + SASSERT(col_idx>0); + col_idx--; + column_info & ci = (*this)[col_idx]; + unsigned new_length = ci.m_length; + if (ci.m_length < 64) { + unsigned swallowed = std::min(64-static_cast(ci.m_length), diff); + diff -= swallowed; + new_length += swallowed; + } + unsigned new_ofs = ci.m_offset+diff; + ci = column_info(new_ofs, new_length); + } + } + + SASSERT(rounded_ofs%8 == 0); + SASSERT((*this)[col_index0].next_ofs()%8 == 0); + } + + // ----------------------------------- + // + // sparse_table + // + // ----------------------------------- + + class sparse_table::our_iterator_core : public iterator_core { + + class our_row : public row_interface { + const our_iterator_core & m_parent; + public: + our_row(const sparse_table & t, const our_iterator_core & parent) : + row_interface(t), + m_parent(parent) {} + + virtual table_element operator[](unsigned col) const { + return m_parent.m_layout.get(m_parent.m_ptr, col); + } + + }; + + const char * m_end; + const char * m_ptr; + unsigned m_fact_size; + our_row m_row_obj; + const column_layout & m_layout; + + public: + our_iterator_core(const sparse_table & t, bool finished) : + m_end(t.m_data.after_last()), + m_ptr(finished ? m_end : t.m_data.begin()), + m_fact_size(t.m_fact_size), + m_row_obj(t, *this), + m_layout(t.m_column_layout) {} + + virtual bool is_finished() const { + return m_ptr == m_end; + } + + virtual row_interface & operator*() { + SASSERT(!is_finished()); + return m_row_obj; + } + virtual void operator++() { + SASSERT(!is_finished()); + m_ptr+=m_fact_size; + } + }; + + class sparse_table::key_indexer { + protected: + unsigned_vector m_key_cols; + public: + typedef const store_offset * offset_iterator; + + /** + Iterators returned by \c begin() and \c end() are valid only as long as the \c query_result + object that returned them exists. + */ + struct query_result { + private: + bool m_singleton; + union { + store_offset m_single_result; + struct { + offset_iterator begin; + offset_iterator end; + } m_many; + }; + public: + /** + \brief Empty result. + */ + query_result() : m_singleton(false) { + m_many.begin = 0; + m_many.end = 0; + } + query_result(offset_iterator begin, offset_iterator end) : m_singleton(false) { + m_many.begin = begin; + m_many.end = end; + } + query_result(store_offset single_result) : m_singleton(true), m_single_result(single_result) {} + + offset_iterator begin() const { return m_singleton ? &m_single_result : m_many.begin; } + offset_iterator end() const { return m_singleton ? (&m_single_result+1) : m_many.end; } + bool empty() const { return begin() == end(); } + }; + + key_indexer(unsigned key_len, const unsigned * key_cols) + : m_key_cols(key_len, key_cols) {} + + virtual ~key_indexer() {} + + virtual void update(const sparse_table & t) {} + + virtual query_result get_matching_offsets(const key_value & key) const = 0; + }; + + + class sparse_table::general_key_indexer : public key_indexer { + typedef svector offset_vector; + typedef u_map index_map; + + index_map m_map; + mutable entry_storage m_keys; + store_offset m_first_nonindexed; + + + void key_to_reserve(const key_value & key) const { + m_keys.ensure_reserve(); + m_keys.write_into_reserve(reinterpret_cast(key.c_ptr())); + } + + offset_vector & get_matching_offset_vector(const key_value & key) { + key_to_reserve(key); + store_offset ofs = m_keys.insert_or_get_reserve_content(); + index_map::entry * e = m_map.find_core(ofs); + if (!e) { + TRACE("dl_table_relation", tout << "inserting\n";); + e = m_map.insert_if_not_there2(ofs, offset_vector()); + } + return e->get_data().m_value; + } + public: + general_key_indexer(unsigned key_len, const unsigned * key_cols) + : key_indexer(key_len, key_cols), + m_keys(key_len*sizeof(table_element)), + m_first_nonindexed(0) {} + + virtual void update(const sparse_table & t) { + if (m_first_nonindexed == t.m_data.after_last_offset()) { + return; + } + SASSERT(m_first_nonindexedinsert(ofs); + } + + m_first_nonindexed = t.m_data.after_last_offset(); + } + + virtual query_result get_matching_offsets(const key_value & key) const { + key_to_reserve(key); + store_offset ofs; + if (!m_keys.find_reserve_content(ofs)) { + return query_result(); + } + index_map::entry * e = m_map.find_core(ofs); + if (!e) { + return query_result(); + } + const offset_vector & res = e->get_data().m_value; + return query_result(res.begin(), res.end()); + } + }; + + /** + When doing lookup using this index, the content of the reserve in sparse_table::m_data changes. + */ + class sparse_table::full_signature_key_indexer : public key_indexer { + const sparse_table & m_table; + + /** + Permutation of key columns to make it into table facts. If empty, no permutation is necessary. + */ + unsigned_vector m_permutation; + mutable table_fact m_key_fact; + public: + + static bool can_handle(unsigned key_len, const unsigned * key_cols, const sparse_table & t) { + unsigned non_func_cols = t.get_signature().first_functional(); + if (key_len!=non_func_cols) { + return false; + } + counter ctr; + ctr.count(key_len, key_cols); + if (ctr.get_max_counter_value()!=1 || ctr.get_max_positive()!=non_func_cols-1) { + return false; + } + SASSERT(ctr.get_positive_count() == non_func_cols); + return true; + } + + full_signature_key_indexer(unsigned key_len, const unsigned * key_cols, const sparse_table & t) + : key_indexer(key_len, key_cols), + m_table(t) { + SASSERT(can_handle(key_len, key_cols, t)); + + m_permutation.resize(key_len); + for (unsigned i=0; i(m_table); + t.write_into_reserve(m_key_fact.c_ptr()); + + store_offset res; + if (!t.m_data.find_reserve_content(res)) { + return query_result(); + } + return query_result(res); + } + }; + + sparse_table::sparse_table(sparse_table_plugin & p, const table_signature & sig, unsigned init_capacity) + : table_base(p, sig), + m_column_layout(sig), + m_fact_size(m_column_layout.m_entry_size), + m_data(m_fact_size, m_column_layout.m_functional_part_size, init_capacity) {} + + sparse_table::sparse_table(const sparse_table & t) + : table_base(t.get_plugin(), t.get_signature()), + m_column_layout(t.m_column_layout), + m_fact_size(t.m_fact_size), + m_data(t.m_data) {} + + table_base * sparse_table::clone() const { + return get_plugin().mk_clone(*this); + } + + sparse_table::~sparse_table() { + reset_indexes(); + } + + void sparse_table::reset() { + reset_indexes(); + m_data.reset(); + } + + table_base::iterator sparse_table::begin() const { + return mk_iterator(alloc(our_iterator_core, *this, false)); + } + + table_base::iterator sparse_table::end() const { + return mk_iterator(alloc(our_iterator_core, *this, true)); + } + + sparse_table::key_indexer& sparse_table::get_key_indexer(unsigned key_len, + const unsigned * key_cols) const { +#if Z3DEBUG + //We allow indexes only on non-functional columns because we want to be able to modify them + //without having to worry about updating indexes. + //Maybe we might keep a list of indexes that contain functional columns and on an update reset + //only those. + SASSERT(key_len == 0 || + counter().count(key_len, key_cols).get_max_positive()get_data().m_value) { + if (full_signature_key_indexer::can_handle(key_len, key_cols, *this)) { + key_map_entry->get_data().m_value = alloc(full_signature_key_indexer, key_len, key_cols, *this); + } + else { + key_map_entry->get_data().m_value = alloc(general_key_indexer, key_len, key_cols); + } + } + key_indexer & indexer = *key_map_entry->get_data().m_value; + indexer.update(*this); + return indexer; + } + + void sparse_table::reset_indexes() { + key_index_map::iterator kmit = m_key_indexes.begin(); + key_index_map::iterator kmend = m_key_indexes.end(); + for (; kmit!=kmend; ++kmit) { + dealloc((*kmit).m_value); + } + m_key_indexes.reset(); + } + + void sparse_table::write_into_reserve(const table_element* f) { + TRACE("dl_table_relation", tout << "\n";); + m_data.ensure_reserve(); + char * reserve = m_data.get_reserve_ptr(); + unsigned col_cnt = m_column_layout.size(); + for (unsigned i = 0; i < col_cnt; ++i) { + SASSERT(f[i] < get_signature()[i]); //the value fits into the table signature + m_column_layout.set(reserve, i, f[i]); + } + } + + bool sparse_table::add_fact(const char * data) { + m_data.write_into_reserve(data); + return add_reserve_content(); + } + + void sparse_table::add_fact(const table_fact & f) { + write_into_reserve(f.c_ptr()); + add_reserve_content(); + } + + bool sparse_table::add_reserve_content() { + return m_data.insert_reserve_content(); + } + + bool sparse_table::contains_fact(const table_fact & f) const { + sparse_table & t = const_cast(*this); + t.write_into_reserve(f.c_ptr()); + unsigned func_col_cnt = get_signature().functional_columns(); + if (func_col_cnt == 0) { + return t.m_data.reserve_content_already_present(); + } + else { + store_offset ofs; + if (!t.m_data.find_reserve_content(ofs)) { + return false; + } + unsigned sz = get_signature().size(); + for (unsigned i=func_col_cnt; i(*this); + t.write_into_reserve(f.c_ptr()); + store_offset ofs; + if (!t.m_data.find_reserve_content(ofs)) { + return false; + } + unsigned sz = sig.size(); + for (unsigned i=sig.first_functional(); ipre_projection_idx); + dest_layout.set(dest, dest_idx++, src_layout.get(src, i)); + } + } + + void sparse_table::concatenate_rows(const column_layout & layout1, const column_layout & layout2, + const column_layout & layout_res, const char * ptr1, const char * ptr2, char * res, + const unsigned * removed_cols) { + unsigned t1non_func = layout1.size()-layout1.m_functional_col_cnt; + unsigned t2non_func = layout2.size()-layout2.m_functional_col_cnt; + unsigned t1cols = layout1.size(); + unsigned t2cols = layout2.size(); + unsigned orig_i = 0; + unsigned res_i = 0; + const unsigned * next_removed = removed_cols; + copy_columns(layout1, layout_res, 0, t1non_func, ptr1, res, res_i, orig_i, next_removed); + copy_columns(layout2, layout_res, 0, t2non_func, ptr2, res, res_i, orig_i, next_removed); + copy_columns(layout1, layout_res, t1non_func, t1cols, ptr1, res, res_i, orig_i, next_removed); + copy_columns(layout2, layout_res, t2non_func, t2cols, ptr2, res, res_i, orig_i, next_removed); + } + + void sparse_table::garbage_collect() { + if (memory::above_high_watermark()) { + get_plugin().garbage_collect(); + } + if (memory::above_high_watermark()) { + IF_VERBOSE(1, verbose_stream() << "Ran out of memory while filling table of size: " << get_size_estimate_rows() << " rows " << get_size_estimate_bytes() << " bytes\n";); + throw out_of_memory_error(); + } + } + + void sparse_table::self_agnostic_join_project(const sparse_table & t1, const sparse_table & t2, + unsigned joined_col_cnt, const unsigned * t1_joined_cols, const unsigned * t2_joined_cols, + const unsigned * removed_cols, bool tables_swapped, sparse_table & result) { + + unsigned t1_entry_size = t1.m_fact_size; + unsigned t2_entry_size = t2.m_fact_size; + + unsigned t1idx = 0; + unsigned t1end = t1.m_data.after_last_offset(); + + TRACE("dl_table_relation", + tout << "joined_col_cnt: " << joined_col_cnt << "\n"; + tout << "t1_entry_size: " << t1_entry_size << "\n"; + tout << "t2_entry_size: " << t2_entry_size << "\n"; + t1.display(tout); + t2.display(tout); + tout << (&t1) << " " << (&t2) << " " << (&result) << "\n"; + ); + + if (joined_col_cnt == 0) { + unsigned t2idx = 0; + unsigned t2end = t2.m_data.after_last_offset(); + + for (; t1idx!=t1end; t1idx+=t1_entry_size) { + for (t2idx = 0; t2idx != t2end; t2idx += t2_entry_size) { + result.m_data.ensure_reserve(); + result.garbage_collect(); + char * res_reserve = result.m_data.get_reserve_ptr(); + char const* t1ptr = t1.get_at_offset(t1idx); + char const* t2ptr = t2.get_at_offset(t2idx); + if (tables_swapped) { + concatenate_rows(t2.m_column_layout, t1.m_column_layout, result.m_column_layout, + t2ptr, t1ptr, res_reserve, removed_cols); + } else { + concatenate_rows(t1.m_column_layout, t2.m_column_layout, result.m_column_layout, + t1ptr, t2ptr, res_reserve, removed_cols); + } + result.add_reserve_content(); + } + } + return; + } + + key_value t1_key; + t1_key.resize(joined_col_cnt); + key_indexer& t2_indexer = t2.get_key_indexer(joined_col_cnt, t2_joined_cols); + + bool key_modified = true; + key_indexer::query_result t2_offsets; + + for (; t1idx != t1end; t1idx += t1_entry_size) { + for (unsigned i = 0; i < joined_col_cnt; i++) { + table_element val = t1.m_column_layout.get(t1.get_at_offset(t1idx), t1_joined_cols[i]); + TRACE("dl_table_relation", tout << "val: " << val << " " << t1idx << " " << t1_joined_cols[i] << "\n";); + if (t1_key[i] != val) { + t1_key[i] = val; + key_modified = true; + } + } + if (key_modified) { + t2_offsets = t2_indexer.get_matching_offsets(t1_key); + key_modified = false; + } + + if (t2_offsets.empty()) { + continue; + } + + key_indexer::offset_iterator t2ofs_it = t2_offsets.begin(); + key_indexer::offset_iterator t2ofs_end = t2_offsets.end(); + for (; t2ofs_it != t2ofs_end; ++t2ofs_it) { + store_offset t2ofs = *t2ofs_it; + result.m_data.ensure_reserve(); + result.garbage_collect(); + char * res_reserve = result.m_data.get_reserve_ptr(); + char const * t1ptr = t1.get_at_offset(t1idx); + char const * t2ptr = t2.get_at_offset(t2ofs); + if (tables_swapped) { + concatenate_rows(t2.m_column_layout, t1.m_column_layout, result.m_column_layout, + t2ptr, t1ptr, res_reserve, removed_cols); + } else { + concatenate_rows(t1.m_column_layout, t2.m_column_layout, result.m_column_layout, + t1ptr, t2ptr, res_reserve, removed_cols); + } + result.add_reserve_content(); + } + } + } + + + // ----------------------------------- + // + // sparse_table_plugin + // + // ----------------------------------- + + sparse_table_plugin::sparse_table_plugin(relation_manager & manager) + : table_plugin(symbol("sparse"), manager) {} + + sparse_table_plugin::~sparse_table_plugin() { + reset(); + } + + void sparse_table_plugin::reset() { + table_pool::iterator it = m_pool.begin(); + table_pool::iterator end = m_pool.end(); + for (; it!=end; ++it) { + sp_table_vector * vect = it->m_value; + sp_table_vector::iterator it = vect->begin(); + sp_table_vector::iterator end = vect->end(); + for (; it!=end; ++it) { + (*it)->destroy(); //calling deallocate() would only put the table back into the pool + } + dealloc(vect); + } + m_pool.reset(); + } + + void sparse_table_plugin::garbage_collect() { + IF_VERBOSE(2, verbose_stream() << "garbage collecting "<< memory::get_allocation_size() << " bytes down to ";); + reset(); + IF_VERBOSE(2, verbose_stream() << memory::get_allocation_size() << " bytes\n";); + } + + void sparse_table_plugin::recycle(sparse_table * t) { + const table_signature & sig = t->get_signature(); + t->reset(); + + table_pool::entry * e = m_pool.insert_if_not_there2(sig, 0); + sp_table_vector * & vect = e->get_data().m_value; + if (vect == 0) { + vect = alloc(sp_table_vector); + } + IF_VERBOSE(12, verbose_stream() << "Recycle: " << t->get_size_estimate_bytes() << "\n";); + + vect->push_back(t); + } + + table_base * sparse_table_plugin::mk_empty(const table_signature & s) { + SASSERT(can_handle_signature(s)); + + sp_table_vector * vect; + if (!m_pool.find(s, vect) || vect->empty()) { + return alloc(sparse_table, *this, s); + } + sparse_table * res = vect->back(); + vect->pop_back(); + return res; + } + + sparse_table * sparse_table_plugin::mk_clone(const sparse_table & t) { + sparse_table * res = static_cast(mk_empty(t.get_signature())); + res->m_data = t.m_data; + return res; + } + + + bool sparse_table_plugin::join_involves_functional(const table_signature & s1, const table_signature & s2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (col_cnt == 0) { + return false; + } + return counter().count(col_cnt, cols1).get_max_positive()>=s1.first_functional() + || counter().count(col_cnt, cols2).get_max_positive()>=s2.first_functional(); + } + + + class sparse_table_plugin::join_project_fn : public convenient_table_join_project_fn { + public: + join_project_fn(const table_signature & t1_sig, const table_signature & t2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols) + : convenient_table_join_project_fn(t1_sig, t2_sig, col_cnt, cols1, cols2, + removed_col_cnt, removed_cols) { + m_removed_cols.push_back(UINT_MAX); + } + + virtual table_base * operator()(const table_base & tb1, const table_base & tb2) { + + const sparse_table & t1 = static_cast(tb1); + const sparse_table & t2 = static_cast(tb2); + + sparse_table_plugin & plugin = t1.get_plugin(); + + sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); + + //If we join with some intersection, want to iterate over the smaller table and + //do indexing into the bigger one. If we simply do a product, we want the bigger + //one to be at the outer iteration (then the small one will hopefully fit into + //the cache) + if ( (t1.row_count() > t2.row_count()) == (!m_cols1.empty()) ) { + sparse_table::self_agnostic_join_project(t2, t1, m_cols1.size(), m_cols2.c_ptr(), + m_cols1.c_ptr(), m_removed_cols.c_ptr(), true, *res); + } + else { + sparse_table::self_agnostic_join_project(t1, t2, m_cols1.size(), m_cols1.c_ptr(), + m_cols2.c_ptr(), m_removed_cols.c_ptr(), false, *res); + } + TRACE("dl_table_relation", tb1.display(tout); tb2.display(tout); res->display(tout); ); + return res; + } + }; + + table_join_fn * sparse_table_plugin::mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + const table_signature & sig1 = t1.get_signature(); + const table_signature & sig2 = t2.get_signature(); + if (t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind() + || join_involves_functional(sig1, sig2, col_cnt, cols1, cols2)) { + //We also don't allow indexes on functional columns (and they are needed for joins) + return 0; + } + return mk_join_project_fn(t1, t2, col_cnt, cols1, cols2, 0, static_cast(0)); + } + + table_join_fn * sparse_table_plugin::mk_join_project_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols) { + const table_signature & sig1 = t1.get_signature(); + const table_signature & sig2 = t2.get_signature(); + if (t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind() + || removed_col_cnt == t1.get_signature().size()+t2.get_signature().size() + || join_involves_functional(sig1, sig2, col_cnt, cols1, cols2)) { + //We don't allow sparse tables with zero signatures (and project on all columns leads to such) + //We also don't allow indexes on functional columns. + return 0; + } + return alloc(join_project_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, + removed_col_cnt, removed_cols); + } + + class sparse_table_plugin::union_fn : public table_union_fn { + public: + virtual void operator()(table_base & tgt0, const table_base & src0, table_base * delta0) { + + sparse_table & tgt = static_cast(tgt0); + const sparse_table & src = static_cast(src0); + sparse_table * delta = static_cast(delta0); + + unsigned fact_size = tgt.m_fact_size; + const char* ptr = src.m_data.begin(); + const char* after_last=src.m_data.after_last(); + for (; ptradd_fact(ptr); + } + } + } + }; + + table_union_fn * sparse_table_plugin::mk_union_fn(const table_base & tgt, const table_base & src, + const table_base * delta) { + if (tgt.get_kind()!=get_kind() || src.get_kind()!=get_kind() + || (delta && delta->get_kind()!=get_kind()) + || tgt.get_signature()!=src.get_signature() + || (delta && delta->get_signature()!=tgt.get_signature())) { + return 0; + } + return alloc(union_fn); + } + + class sparse_table_plugin::project_fn : public convenient_table_project_fn { + const unsigned m_inp_col_cnt; + const unsigned m_removed_col_cnt; + const unsigned m_result_col_cnt; + public: + project_fn(const table_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) + : convenient_table_project_fn(orig_sig, removed_col_cnt, removed_cols), + m_inp_col_cnt(orig_sig.size()), + m_removed_col_cnt(removed_col_cnt), + m_result_col_cnt(orig_sig.size()-removed_col_cnt) { + SASSERT(removed_col_cnt>0); + } + + virtual void transform_row(const char * src, char * tgt, + const sparse_table::column_layout & src_layout, + const sparse_table::column_layout & tgt_layout) { + unsigned r_idx=0; + unsigned tgt_i=0; + for (unsigned i=0; i(tb); + + unsigned t_fact_size = t.m_fact_size; + + sparse_table_plugin & plugin = t.get_plugin(); + sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); + + const sparse_table::column_layout & src_layout = t.m_column_layout; + const sparse_table::column_layout & tgt_layout = res->m_column_layout; + + const char* t_ptr = t.m_data.begin(); + const char* t_end = t.m_data.after_last(); + for (; t_ptr!=t_end; t_ptr+=t_fact_size) { + SASSERT(t_ptrm_data.ensure_reserve(); + char * res_ptr = res->m_data.get_reserve_ptr(); + transform_row(t_ptr, res_ptr, src_layout, tgt_layout); + res->m_data.insert_reserve_content(); + } + return res; + } + }; + + table_transformer_fn * sparse_table_plugin::mk_project_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols) { + if (col_cnt == t.get_signature().size()) { + return 0; + } + return alloc(project_fn, t.get_signature(), col_cnt, removed_cols); + } + + + class sparse_table_plugin::select_equal_and_project_fn : public convenient_table_transformer_fn { + const unsigned m_col; + sparse_table::key_value m_key; + public: + select_equal_and_project_fn(const table_signature & orig_sig, table_element val, unsigned col) + : m_col(col) { + table_signature::from_project(orig_sig, 1, &col, get_result_signature()); + m_key.push_back(val); + } + + virtual table_base * operator()(const table_base & tb) { + const sparse_table & t = static_cast(tb); + + sparse_table_plugin & plugin = t.get_plugin(); + sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); + + const sparse_table::column_layout & t_layout = t.m_column_layout; + const sparse_table::column_layout & res_layout = res->m_column_layout; + unsigned t_cols = t_layout.size(); + + sparse_table::key_indexer & indexer = t.get_key_indexer(1, &m_col); + sparse_table::key_indexer::query_result t_offsets = indexer.get_matching_offsets(m_key); + if (t_offsets.empty()) { + //no matches + return res; + } + sparse_table::key_indexer::offset_iterator ofs_it=t_offsets.begin(); + sparse_table::key_indexer::offset_iterator ofs_end=t_offsets.end(); + + for (; ofs_it!=ofs_end; ++ofs_it) { + sparse_table::store_offset t_ofs = *ofs_it; + const char * t_ptr = t.get_at_offset(t_ofs); + + res->m_data.ensure_reserve(); + char * res_reserve = res->m_data.get_reserve_ptr(); + + unsigned res_i = 0; + for (unsigned i=0; iadd_reserve_content(); + } + return res; + } + }; + + table_transformer_fn * sparse_table_plugin::mk_select_equal_and_project_fn(const table_base & t, + const table_element & value, unsigned col) { + if (t.get_kind()!=get_kind() || t.get_signature().size() == 1 || col>=t.get_signature().first_functional()) { + //We don't allow sparse tables with zero signatures (and project on a single + //column table produces one). + //We also don't allow indexes on functional columns. And our implementation of + //select_equal_and_project uses index on \c col. + return 0; + } + return alloc(select_equal_and_project_fn, t.get_signature(), value, col); + } + + + class sparse_table_plugin::rename_fn : public convenient_table_rename_fn { + unsigned_vector m_out_of_cycle; + public: + rename_fn(const table_signature & orig_sig, unsigned permutation_cycle_len, const unsigned * permutation_cycle) + : convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle) { + SASSERT(permutation_cycle_len>=2); + idx_set cycle_cols; + for (unsigned i=0; i < permutation_cycle_len; ++i) { + cycle_cols.insert(permutation_cycle[i]); + } + for (unsigned i=0; i < orig_sig.size(); ++i) { + if (!cycle_cols.contains(i)) { + m_out_of_cycle.push_back(i); + } + } + } + + void transform_row(const char * src, char * tgt, + const sparse_table::column_layout & src_layout, + const sparse_table::column_layout & tgt_layout) { + + for (unsigned i=1; i < m_cycle.size(); ++i) { + tgt_layout.set(tgt, m_cycle[i-1], src_layout.get(src, m_cycle[i])); + } + tgt_layout.set(tgt, m_cycle[m_cycle.size()-1], src_layout.get(src, m_cycle[0])); + + unsigned_vector::const_iterator it = m_out_of_cycle.begin(); + unsigned_vector::const_iterator end = m_out_of_cycle.end(); + for (; it!=end; ++it) { + unsigned col = *it; + tgt_layout.set(tgt, col, src_layout.get(src, col)); + } + } + + virtual table_base * operator()(const table_base & tb) { + + const sparse_table & t = static_cast(tb); + + unsigned t_fact_size = t.m_fact_size; + + sparse_table_plugin & plugin = t.get_plugin(); + sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); + + unsigned res_fact_size = res->m_fact_size; + unsigned res_data_size = res_fact_size*t.row_count(); + + res->m_data.resize_data(res_data_size); + + //here we can separate data creatin and insertion into hashmap, since we know + //that no row will become duplicit + + //create the data + const char* t_ptr = t.m_data.begin(); + char* res_ptr = res->m_data.begin(); + char* res_end = res_ptr+res_data_size; + for (; res_ptr!=res_end; t_ptr+=t_fact_size, res_ptr+=res_fact_size) { + transform_row(t_ptr, res_ptr, t.m_column_layout, res->m_column_layout); + } + + //and insert them into the hash-map + for (unsigned i=0; i!=res_data_size; i+=res_fact_size) { + TRUSTME(res->m_data.insert_offset(i)); + } + + return res; + } + }; + + table_transformer_fn * sparse_table_plugin::mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) { + if (t.get_kind()!=get_kind()) { + return 0; + } + return alloc(rename_fn, t.get_signature(), permutation_cycle_len, permutation_cycle); + } + + class sparse_table_plugin::negation_filter_fn : public convenient_table_negation_filter_fn { + typedef sparse_table::store_offset store_offset; + typedef sparse_table::key_value key_value; + typedef sparse_table::key_indexer key_indexer; + + bool m_joining_neg_non_functional; + + /** + Used by \c collect_intersection_offsets function. + If tgt_is_first is false, contains the same items as \c res. + */ + idx_set m_intersection_content; + + public: + negation_filter_fn(const table_base & tgt, const table_base & neg, + unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) + : convenient_table_negation_filter_fn(tgt, neg, joined_col_cnt, t_cols, negated_cols) { + unsigned neg_fisrt_func = neg.get_signature().first_functional(); + counter ctr; + ctr.count(m_cols2); + m_joining_neg_non_functional = ctr.get_max_counter_value() == 1 + && ctr.get_positive_count() == neg_fisrt_func + && (neg_fisrt_func == 0 || ctr.get_max_positive() == neg_fisrt_func-1); + } + + /** + Collect offsets of rows in \c t1 or \c t2 (depends on whether \c tgt_is_first is true or false) + that have a match in the other table into \c res. Offsets in \c res are in ascending order. + */ + void collect_intersection_offsets(const sparse_table & t1, const sparse_table & t2, + bool tgt_is_first, svector & res) { + SASSERT(res.empty()); + + if (!tgt_is_first) { + m_intersection_content.reset(); + } + + unsigned joined_col_cnt = m_cols1.size(); + unsigned t1_entry_size = t1.m_data.entry_size(); + + const unsigned * cols1 = tgt_is_first ? m_cols1.c_ptr() : m_cols2.c_ptr(); + const unsigned * cols2 = tgt_is_first ? m_cols2.c_ptr() : m_cols1.c_ptr(); + + key_value t1_key; + t1_key.resize(joined_col_cnt); + key_indexer & t2_indexer = t2.get_key_indexer(joined_col_cnt, cols2); + + bool key_modified=true; + key_indexer::query_result t2_offsets; + store_offset t1_after_last = t1.m_data.after_last_offset(); + for (store_offset t1_ofs=0; t1_ofs(tgt0); + const sparse_table & neg = static_cast(neg0); + + if (m_cols1.size() == 0) { + if (!neg.empty()) { + tgt.reset(); + } + return; + } + + svector to_remove; //offsets here are in increasing order + + //We don't do just the simple tgt.row_count()>neg.row_count() because the swapped case is + //more expensive. The constant 4 is, however, just my guess what the ratio might be. + if (tgt.row_count()/4>neg.row_count()) { + collect_intersection_offsets(neg, tgt, false, to_remove); + } + else { + collect_intersection_offsets(tgt, neg, true, to_remove); + } + + if (to_remove.empty()) { + return; + } + + //the largest offsets are at the end, so we can remove them one by one + while(!to_remove.empty()) { + store_offset removed_ofs = to_remove.back(); + to_remove.pop_back(); + tgt.m_data.remove_offset(removed_ofs); + } + tgt.reset_indexes(); + } + + }; + + table_intersection_filter_fn * sparse_table_plugin::mk_filter_by_negation_fn(const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) { + if (!check_kind(t) || !check_kind(negated_obj) + || join_involves_functional(t.get_signature(), negated_obj.get_signature(), joined_col_cnt, + t_cols, negated_cols) ) { + return 0; + } + return alloc(negation_filter_fn, t, negated_obj, joined_col_cnt, t_cols, negated_cols); + } + + unsigned sparse_table::get_size_estimate_bytes() const { + unsigned sz = 0; + sz += m_data.get_size_estimate_bytes(); + sz += m_key_indexes.capacity()*8; // TBD + return sz; + } + + +}; + diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h new file mode 100644 index 000000000..010277b6b --- /dev/null +++ b/src/muz/rel/dl_sparse_table.h @@ -0,0 +1,480 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_table.h + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-01. + +Revision History: + +--*/ + +#ifndef _DL_SPARSE_TABLE_H_ +#define _DL_SPARSE_TABLE_H_ + +#include +#include +#include + +#include "ast.h" +#include "bit_vector.h" +#include "buffer.h" +#include "hashtable.h" +#include "map.h" +#include "ref_vector.h" +#include "vector.h" + +#include "dl_base.h" + + +namespace datalog { + class sparse_table; + + class sparse_table_plugin : public table_plugin { + friend class sparse_table; + protected: + class join_project_fn; + class union_fn; + class transformer_fn; + class rename_fn; + class project_fn; + class negation_filter_fn; + class select_equal_and_project_fn; + + typedef ptr_vector sp_table_vector; + typedef map table_pool; + + table_pool m_pool; + + void recycle(sparse_table * t); + + void garbage_collect(); + + void reset(); + + static bool join_involves_functional(const table_signature & s1, const table_signature & s2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + + public: + typedef sparse_table table; + + sparse_table_plugin(relation_manager & manager); + ~sparse_table_plugin(); + + virtual bool can_handle_signature(const table_signature & s) + { return s.size()>0; } + + virtual table_base * mk_empty(const table_signature & s); + sparse_table * mk_clone(const sparse_table & t); + + protected: + virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols); + virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, + const table_base * delta); + virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual table_transformer_fn * mk_select_equal_and_project_fn(const table_base & t, + const table_element & value, unsigned col); + virtual table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols); + }; + + class entry_storage { + public: + typedef unsigned store_offset; + private: + typedef svector storage; + + class offset_hash_proc { + storage & m_storage; + unsigned m_unique_entry_size; + public: + offset_hash_proc(storage & s, unsigned unique_entry_sz) + : m_storage(s), m_unique_entry_size(unique_entry_sz) {} + unsigned operator()(store_offset ofs) const { + return string_hash(m_storage.c_ptr()+ofs, m_unique_entry_size, 0); + } + }; + + class offset_eq_proc { + storage & m_storage; + unsigned m_unique_entry_size; + public: + offset_eq_proc(storage & s, unsigned unique_entry_sz) + : m_storage(s), m_unique_entry_size(unique_entry_sz) {} + bool operator()(store_offset o1, store_offset o2) const { + const char * base = m_storage.c_ptr(); + return memcmp(base+o1, base+o2, m_unique_entry_size)==0; + } + }; + + typedef hashtable storage_indexer; + + static const store_offset NO_RESERVE = UINT_MAX; + + unsigned m_entry_size; + unsigned m_unique_part_size; + unsigned m_data_size; + /** + Invariant: Every or all but one blocks of length \c m_entry_size in the \c m_data vector + are unique sequences of bytes and have their offset stored in the \c m_data_indexer hashtable. + If the offset of the last block is not stored in the hashtable, it is stored in the \c m_reserve + variable. Otherwise \c m_reserve==NO_RESERVE. + + The size of m_data is actually 8 bytes larger than stated in m_data_size, so that we may + deref an uint64 pointer at the end of the array. + */ + storage m_data; + storage_indexer m_data_indexer; + store_offset m_reserve; + public: + entry_storage(unsigned entry_size, unsigned functional_size = 0, unsigned init_size = 0) + : m_entry_size(entry_size), + m_unique_part_size(entry_size-functional_size), + m_data_indexer(next_power_of_two(std::max(8u,init_size)), + offset_hash_proc(m_data, m_unique_part_size), offset_eq_proc(m_data, m_unique_part_size)), + m_reserve(NO_RESERVE) { + SASSERT(entry_size>0); + SASSERT(functional_size<=entry_size); + resize_data(init_size); + resize_data(0); + } + entry_storage(const entry_storage &s) + : m_entry_size(s.m_entry_size), + m_unique_part_size(s.m_unique_part_size), + m_data_size(s.m_data_size), + m_data(s.m_data), + m_data_indexer(next_power_of_two(std::max(8u,s.entry_count())), + offset_hash_proc(m_data, m_unique_part_size), offset_eq_proc(m_data, m_unique_part_size)), + m_reserve(s.m_reserve) { + store_offset after_last=after_last_offset(); + for(store_offset i=0; i(this)->get(ofs); } + + unsigned entry_count() const { return m_data_indexer.size(); } + + store_offset after_last_offset() const { + return (m_reserve==NO_RESERVE) ? m_data_size : m_reserve; + } + + char * begin() { return get(0); } + const char * begin() const { return get(0); } + const char * after_last() const { return get(after_last_offset()); } + + + bool has_reserve() const { return m_reserve!=NO_RESERVE; } + store_offset reserve() const { SASSERT(has_reserve()); return m_reserve; } + + void ensure_reserve() { + if(has_reserve()) { + SASSERT(m_reserve==m_data_size-m_entry_size); + return; + } + m_reserve=m_data_size; + resize_data(m_data_size+m_entry_size); + } + + /** + \brief Return pointer to the reserve. + + The reserve must exist when the function is called. + */ + char * get_reserve_ptr() { + SASSERT(has_reserve()); + return &m_data.get(reserve()); + } + + bool reserve_content_already_present() const { + SASSERT(has_reserve()); + return m_data_indexer.contains(reserve()); + } + + bool find_reserve_content(store_offset & result) const { + SASSERT(has_reserve()); + storage_indexer::entry * indexer_entry = m_data_indexer.find_core(reserve()); + if(!indexer_entry) { + return false; + } + result = indexer_entry->get_data(); + return true; + } + + /** + \brief Write fact \c f into the reserve at the end of the \c m_data storage. + + If the reserve does not exist, this function creates it. + */ + void write_into_reserve(const char * data) { + ensure_reserve(); + memcpy(get_reserve_ptr(), data, m_entry_size); + } + + /** + \brief If the fact in reserve is not in the table, insert it there and return true; + otherwise return false. + + When a fact is inserted into the table, the reserve becomes part of the table and + is no longer a reserve. + */ + bool insert_reserve_content(); + store_offset insert_or_get_reserve_content(); + bool remove_reserve_content(); + /** + Remove data at the offset \c ofs. + + Data with offset lower than \c ofs are not be modified by this function, data with + higher offset may be moved. + */ + void remove_offset(store_offset ofs); + + + //the following two operations allow breaking of the object invariant! + void resize_data(unsigned sz) { + m_data_size = sz; + m_data.resize(sz + sizeof(uint64)); + } + + bool insert_offset(store_offset ofs) { + return m_data_indexer.insert_if_not_there(ofs)==ofs; + } + }; + + class sparse_table : public table_base { + friend class sparse_table_plugin; + friend class sparse_table_plugin::join_project_fn; + friend class sparse_table_plugin::union_fn; + friend class sparse_table_plugin::transformer_fn; + friend class sparse_table_plugin::rename_fn; + friend class sparse_table_plugin::project_fn; + friend class sparse_table_plugin::negation_filter_fn; + friend class sparse_table_plugin::select_equal_and_project_fn; + + class our_iterator_core; + class key_indexer; + class general_key_indexer; + class full_signature_key_indexer; + typedef entry_storage::store_offset store_offset; + + + class column_info { + unsigned m_big_offset; + unsigned m_small_offset; + uint64 m_mask; + uint64 m_write_mask; + public: + unsigned m_offset; //!< in bits + unsigned m_length; //!< in bits + + column_info(unsigned offset, unsigned length) \ + : m_big_offset(offset/8), + m_small_offset(offset%8), + m_mask( length==64 ? ULLONG_MAX : (static_cast(1)<(rec+m_big_offset); + uint64 res = *ptr; + res>>=m_small_offset; + res&=m_mask; + return res; + } + void set(char * rec, table_element val) const { + SASSERT( (val&~m_mask)==0 ); //the value fits into the column + uint64 * ptr = reinterpret_cast(rec+m_big_offset); + *ptr&=m_write_mask; + *ptr|=val< { + + void make_byte_aligned_end(unsigned col_index); + public: + + unsigned m_entry_size; + /** + Number of last bytes which correspond to functional columns in the signature. + */ + unsigned m_functional_part_size; + unsigned m_functional_col_cnt; + + column_layout(const table_signature & sig); + + table_element get(const char * rec, unsigned col) const { + return (*this)[col].get(rec); + } + void set(char * rec, unsigned col, table_element val) const { + return (*this)[col].set(rec, val); + } + }; + + + typedef svector key_spec; //sequence of columns in a key + typedef svector key_value; //values of key columns + typedef map, + vector_eq_proc > key_index_map; + + static const store_offset NO_RESERVE = UINT_MAX; + + column_layout m_column_layout; + unsigned m_fact_size; + entry_storage m_data; + mutable key_index_map m_key_indexes; + + + const char * get_at_offset(store_offset i) const { + return m_data.get(i); + } + + table_element get_cell(store_offset ofs, unsigned column) const { + return m_column_layout.get(m_data.get(ofs), column); + } + + void set_cell(store_offset ofs, unsigned column, table_element val) { + m_column_layout.set(m_data.get(ofs), column, val); + } + + void write_into_reserve(const table_element* f); + + /** + \brief Return reference to an indexer over columns in \c key_cols. + + An indexer can retrieve a sequence of offsets that with \c key_cols columns equal to + the specified key. Indexers are populated lazily -- they remember the position of the + last fact they contain, and when an indexer is retrieved by the \c get_key_indexer function, + all the new facts are added into the indexer. + + When a fact is removed from the table, all indexers are destroyed. This is not an extra + expense in the current use scenario, because we first perform all fact removals and do the + joins only after that (joins are the only operations that lead to index construction). + */ + key_indexer& get_key_indexer(unsigned key_len, const unsigned * key_cols) const; + + void reset_indexes(); + + static void copy_columns(const column_layout & src_layout, const column_layout & dest_layout, + unsigned start_index, unsigned after_last, const char * src, char * dest, + unsigned & dest_idx, unsigned & pre_projection_idx, const unsigned * & next_removed); + + /** + \c array \c removed_cols contains column indexes to be removed in ascending order and + is terminated by a number greated than the highest column index of a join the the two tables. + This is to simplify the traversal of the array when building facts. + */ + static void concatenate_rows(const column_layout & layout1, const column_layout & layout2, + const column_layout & layout_res, const char * ptr1, const char * ptr2, char * res, + const unsigned * removed_cols); + + /** + \brief Perform join-project between t1 and t2 iterating through t1 and retrieving relevant + columns from t2 using indexing. + + \c array \c removed_cols contains column indexes to be removed in ascending order and + is terminated by a number greated than the highest column index of a join the the two tables. + This is to simplify the traversal of the array when building facts. + + \c tables_swapped value means that the resulting facts should contain facts from t2 first, + instead of the default behavior that would concatenate the two facts as \c (t1,t2). + + \remark The function is called \c self_agnostic_join since, unlike the virtual method + \c join, it is static and therefore allows to easily swap the roles of the two joined + tables (the indexed and iterated one) in a way that is expected to give better performance. + */ + static void self_agnostic_join_project(const sparse_table & t1, const sparse_table & t2, + unsigned joined_col_cnt, const unsigned * t1_joined_cols, const unsigned * t2_joined_cols, + const unsigned * removed_cols, bool tables_swapped, sparse_table & result); + + + /** + If the fact at \c data (in table's native representation) is not in the table, + add it and return true. Otherwise return false. + */ + bool add_fact(const char * data); + + bool add_reserve_content(); + + void garbage_collect(); + + sparse_table(sparse_table_plugin & p, const table_signature & sig, unsigned init_capacity=0); + sparse_table(const sparse_table & t); + virtual ~sparse_table(); + public: + + virtual void deallocate() { + get_plugin().recycle(this); + } + + unsigned row_count() const { return m_data.entry_count(); } + + sparse_table_plugin & get_plugin() const + { return static_cast(table_base::get_plugin()); } + + virtual bool empty() const { return row_count()==0; } + virtual void add_fact(const table_fact & f); + virtual bool contains_fact(const table_fact & f) const; + virtual bool fetch_fact(table_fact & f) const; + virtual void ensure_fact(const table_fact & f); + virtual void remove_fact(const table_element* fact); + virtual void reset(); + + virtual table_base * clone() const; + + virtual table_base::iterator begin() const; + virtual table_base::iterator end() const; + + virtual unsigned get_size_estimate_rows() const { return row_count(); } + virtual unsigned get_size_estimate_bytes() const; + virtual bool knows_exact_size() const { return true; } + }; + + }; + + #endif /* _DL_SPARSE_TABLE_H_ */ diff --git a/src/muz/rel/dl_table.cpp b/src/muz/rel/dl_table.cpp new file mode 100644 index 000000000..0b8fc0388 --- /dev/null +++ b/src/muz/rel/dl_table.cpp @@ -0,0 +1,773 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_table.cpp + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-01. + +Revision History: + +--*/ + +#include"dl_context.h" +#include"dl_util.h" +#include"dl_table.h" +#include"dl_relation_manager.h" + +namespace datalog { + + // ----------------------------------- + // + // hashtable_table + // + // ----------------------------------- + + table_base * hashtable_table_plugin::mk_empty(const table_signature & s) { + SASSERT(can_handle_signature(s)); + return alloc(hashtable_table, *this, s); + } + + + class hashtable_table_plugin::join_fn : public convenient_table_join_fn { + unsigned m_joined_col_cnt; + public: + join_fn(const table_signature & t1_sig, const table_signature & t2_sig, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) + : convenient_table_join_fn(t1_sig, t2_sig, col_cnt, cols1, cols2), + m_joined_col_cnt(col_cnt) {} + + virtual table_base * operator()(const table_base & t1, const table_base & t2) { + + const hashtable_table & ht1 = static_cast(t1); + const hashtable_table & ht2 = static_cast(t2); + + hashtable_table_plugin & plugin = ht1.get_plugin(); + + hashtable_table * res = static_cast(plugin.mk_empty(get_result_signature())); + + hashtable_table::storage::iterator els1it = ht1.m_data.begin(); + hashtable_table::storage::iterator els1end = ht1.m_data.end(); + hashtable_table::storage::iterator els2end = ht2.m_data.end(); + + table_fact acc; + + for(; els1it!=els1end; ++els1it) { + const table_fact & row1 = *els1it; + + hashtable_table::storage::iterator els2it = ht2.m_data.begin(); + for(; els2it!=els2end; ++els2it) { + const table_fact & row2 = *els2it; + + bool match=true; + for(unsigned i=0; im_data.insert(acc); + } + } + return res; + } + }; + + table_join_fn * hashtable_table_plugin::mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if(t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind()) { + return 0; + } + return alloc(join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); + } + + + class hashtable_table::our_iterator_core : public iterator_core { + const hashtable_table & m_parent; + storage::iterator m_inner; + storage::iterator m_end; + + class our_row : public row_interface { + const our_iterator_core & m_parent; + public: + our_row(const our_iterator_core & parent) : row_interface(parent.m_parent), m_parent(parent) {} + + virtual void get_fact(table_fact & result) const { + result = *m_parent.m_inner; + } + virtual table_element operator[](unsigned col) const { + return (*m_parent.m_inner)[col]; + } + + }; + + our_row m_row_obj; + + public: + our_iterator_core(const hashtable_table & t, bool finished) : + m_parent(t), m_inner(finished ? t.m_data.end() : t.m_data.begin()), + m_end(t.m_data.end()), m_row_obj(*this) {} + + virtual bool is_finished() const { + return m_inner==m_end; + } + + virtual row_interface & operator*() { + SASSERT(!is_finished()); + return m_row_obj; + } + virtual void operator++() { + SASSERT(!is_finished()); + ++m_inner; + } + }; + + + + table_base::iterator hashtable_table::begin() const { + return mk_iterator(alloc(our_iterator_core, *this, false)); + } + + table_base::iterator hashtable_table::end() const { + return mk_iterator(alloc(our_iterator_core, *this, true)); + } + + // ----------------------------------- + // + // bitvector_table + // + // ----------------------------------- + + bool bitvector_table_plugin::can_handle_signature(const table_signature & sig) { + if(sig.functional_columns()!=0) { + return false; + } + unsigned cols = sig.size(); + unsigned shift = 0; + for (unsigned i = 0; i < cols; ++i) { + unsigned s = static_cast(sig[i]); + if (s != sig[i] || !is_power_of_two(s)) { + return false; + } + unsigned num_bits = 0; + unsigned bit_pos = 1; + for (num_bits = 1; num_bits < 32; ++num_bits) { + if (bit_pos & s) { + break; + } + bit_pos <<= 1; + } + shift += num_bits; + if (shift >= 32) { + return false; + } + } + return true; + } + + table_base * bitvector_table_plugin::mk_empty(const table_signature & s) { + SASSERT(can_handle_signature(s)); + return alloc(bitvector_table, *this, s); + } + + class bitvector_table::bv_iterator : public iterator_core { + + bitvector_table const& m_bv; + unsigned m_offset; + + class our_row : public caching_row_interface { + const bv_iterator& m_parent; + public: + our_row(const bv_iterator & p) : caching_row_interface(p.m_bv), m_parent(p) {} + virtual void get_fact(table_fact& result) const { + if (result.size() < size()) { + result.resize(size(), 0); + } + m_parent.m_bv.offset2fact(m_parent.m_offset, result); + } + }; + our_row m_row_obj; + + public: + bv_iterator(const bitvector_table& bv, bool end): + m_bv(bv), m_offset(end?m_bv.m_bv.size():0), m_row_obj(*this) + { + if (!is_finished() && !m_bv.m_bv.get(m_offset)) { + ++(*this); + } + } + + virtual bool is_finished() const { + return m_offset == m_bv.m_bv.size(); + } + + virtual row_interface & operator*() { + SASSERT(!is_finished()); + return m_row_obj; + } + virtual void operator++() { + SASSERT(!is_finished()); + ++m_offset; + while (!is_finished() && !m_bv.m_bv.get(m_offset)) { + ++m_offset; + } + m_row_obj.reset(); + } + }; + + bitvector_table::bitvector_table(bitvector_table_plugin & plugin, const table_signature & sig) + : table_base(plugin, sig) { + SASSERT(plugin.can_handle_signature(sig)); + + m_num_cols = sig.size(); + unsigned shift = 0; + for (unsigned i = 0; i < m_num_cols; ++i) { + unsigned s = static_cast(sig[i]); + if (s != sig[i] || !is_power_of_two(s)) { + throw default_exception("bit-vector table is specialized to small domains that are powers of two"); + } + m_shift.push_back(shift); + m_mask.push_back(s - 1); + unsigned num_bits = 0; + unsigned bit_pos = 1; + for (num_bits = 1; num_bits < 32; ++num_bits) { + if (bit_pos & s) { + break; + } + bit_pos <<= 1; + } + shift += num_bits; + if (shift >= 32) { + throw default_exception("bit-vector table is specialized to small domains that are powers of two"); + } + m_bv.reserve(1 << shift); + } + } + + unsigned bitvector_table::fact2offset(const table_element* f) const { + unsigned result = 0; + for (unsigned i = 0; i < m_num_cols; ++i) { + SASSERT(f[i]> m_shift[i]); + } + } + + void bitvector_table::add_fact(const table_fact & f) { + m_bv.set(fact2offset(f.c_ptr())); + } + + void bitvector_table::remove_fact(const table_element* fact) { + m_bv.unset(fact2offset(fact)); + } + + bool bitvector_table::contains_fact(const table_fact & f) const { + return m_bv.get(fact2offset(f.c_ptr())); + } + + table_base::iterator bitvector_table::begin() const { + return mk_iterator(alloc(bv_iterator, *this, false)); + } + + table_base::iterator bitvector_table::end() const { + return mk_iterator(alloc(bv_iterator, *this, true)); + } + + + + + // ----------------------------------- + // + // equivalence_table + // + // ----------------------------------- + + bool equivalence_table_plugin::can_handle_signature(const table_signature & sig) { + return sig.functional_columns() == 0 && sig.size() == 2 && sig[0] < UINT_MAX && sig[0] == sig[1]; + } + + bool equivalence_table_plugin::is_equivalence_table(table_base const& tbl) const { + if (tbl.get_kind() != get_kind()) return false; + equivalence_table const& t = static_cast(tbl); + return !t.is_sparse(); + } + + table_base * equivalence_table_plugin::mk_empty(const table_signature & s) { + TRACE("dl", for (unsigned i = 0; i < s.size(); ++i) tout << s[i] << " "; tout << "\n";); + SASSERT(can_handle_signature(s)); + return alloc(equivalence_table, *this, s); + } + + class equivalence_table_plugin::select_equal_and_project_fn : public table_transformer_fn { + unsigned m_val; + table_sort m_sort; + public: + select_equal_and_project_fn(const table_signature & sig, table_element val, unsigned col) + : m_val(static_cast(val)), + m_sort(sig[0]) { + SASSERT(val <= UINT_MAX); + SASSERT(col == 0 || col == 1); + SASSERT(sig.functional_columns() == 0); + SASSERT(sig.size() == 2); + SASSERT(sig[0] < UINT_MAX && sig[0] == sig[1]); + } + + virtual table_base* operator()(const table_base& tb) { + TRACE("dl", tout << "\n";); + table_plugin & plugin = tb.get_plugin(); + table_plugin* rp = plugin.get_manager().get_table_plugin(symbol("sparse")); + SASSERT(rp); + table_signature sig; + sig.push_back(m_sort); + table_base* result = rp->mk_empty(sig); + equivalence_table const& eq_table = static_cast(tb); + if (eq_table.is_valid(m_val)) { + table_fact fact; + fact.resize(1); + unsigned r = m_val; + do { + fact[0] = r; + result->add_fact(fact); + r = eq_table.m_uf.next(r); + } + while (r != m_val); + } + TRACE("dl", tb.display(tout << "src:\n"); result->display(tout << "result\n");); + return result; + } + }; + + table_transformer_fn * equivalence_table_plugin::mk_select_equal_and_project_fn( + const table_base & t, const table_element & value, unsigned col) { + return alloc(select_equal_and_project_fn, t.get_signature(), value, col); + } + + class equivalence_table_plugin::union_fn : public table_union_fn { + + equivalence_table_plugin& m_plugin; + + + void mk_union1(equivalence_table & tgt, const equivalence_table & src, table_base * delta) { + unsigned num_vars = src.m_uf.get_num_vars(); + table_fact fact; + fact.resize(2); + for (unsigned i = 0; i < num_vars; ++i) { + if (src.is_valid(i) && src.m_uf.find(i) == i) { + fact[0] = i; + equivalence_table::class_iterator it = src.class_begin(i); + equivalence_table::class_iterator end = src.class_end(i); + for (; it != end; ++it) { + fact[1] = *it; + if (!tgt.contains_fact(fact)) { + tgt.add_fact(fact); + if (delta) { + delta->add_fact(fact); + } + } + } + } + } + } + + void mk_union2(equivalence_table & tgt, const table_base & src, table_base * delta) { + table_fact fact; + table_base::iterator it = src.begin(), end = src.end(); + for (; it != end; ++it) { + it->get_fact(fact); + if (!tgt.contains_fact(fact)) { + tgt.add_fact(fact); + if (delta) { + delta->add_fact(fact); + TRACE("dl", + tout << "Add: "; + for (unsigned i = 0; i < fact.size(); ++i) tout << fact[i] << " "; + tout << "\n";); + } + } + } + } + + public: + union_fn(equivalence_table_plugin& p) : m_plugin(p) {} + + virtual void operator()(table_base & tgt0, const table_base & src, table_base * delta) { + TRACE("dl", tout << "union\n";); + equivalence_table & tgt = static_cast(tgt0); + if (m_plugin.is_equivalence_table(src)) { + mk_union1(tgt, static_cast(src), delta); + } + else { + mk_union2(tgt, src, delta); + } + TRACE("dl", src.display(tout << "src\n"); tgt.display(tout << "tgt\n"); + if (delta) delta->display(tout << "delta\n");); + } + }; + + table_union_fn * equivalence_table_plugin::mk_union_fn( + const table_base & tgt, const table_base & src, const table_base * delta) { + if (!is_equivalence_table(tgt) || + tgt.get_signature() != src.get_signature() || + (delta && delta->get_signature() != tgt.get_signature())) { + return 0; + } + return alloc(union_fn,*this); + } + + class equivalence_table_plugin::join_project_fn : public convenient_table_join_project_fn { + equivalence_table_plugin& m_plugin; + public: + join_project_fn( + equivalence_table_plugin& plugin, const table_signature & t1_sig, const table_signature & t2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols) + : convenient_table_join_project_fn(t1_sig, t2_sig, col_cnt, cols1, cols2, removed_col_cnt, removed_cols), + m_plugin(plugin) { + m_removed_cols.push_back(UINT_MAX); + } + + virtual table_base * operator()(const table_base & tb1, const table_base & tb2) { + SASSERT(m_cols1.size() == 1); + const table_signature & res_sign = get_result_signature(); + table_plugin * plugin = &tb1.get_plugin(); + if (!plugin->can_handle_signature(res_sign)) { + plugin = &tb2.get_plugin(); + if (!plugin->can_handle_signature(res_sign)) { + plugin = &tb1.get_manager().get_appropriate_plugin(res_sign); + } + } + SASSERT(plugin->can_handle_signature(res_sign)); + table_base * result = plugin->mk_empty(res_sign); + + if (m_plugin.is_equivalence_table(tb1)) { + mk_join(0, m_cols1[0], static_cast(tb1), + 2, m_cols2[0], tb2, result); + } + else if (m_plugin.is_equivalence_table(tb2)) { + mk_join(tb1.get_signature().size(), m_cols2[0], static_cast(tb2), + 0, m_cols1[0], tb1, result); + } + else { + UNREACHABLE(); + } + TRACE("dl", tb1.display(tout << "tb1\n"); tb2.display(tout << "tb2\n"); result->display(tout << "result\n");); + return result; + } + + private: + table_base * mk_join(unsigned offs1, unsigned col1, equivalence_table const & t1, + unsigned offs2, unsigned col2, table_base const& t2, table_base* res) { + table_base::iterator els2it = t2.begin(); + table_base::iterator els2end = t2.end(); + + table_fact acc, proj; + acc.resize(t1.get_signature().size() + t2.get_signature().size()); + + for(; els2it != els2end; ++els2it) { + const table_base::row_interface & row2 = *els2it; + table_element const& e2 = row2[col2]; + equivalence_table::class_iterator it = t1.class_begin(e2); + equivalence_table::class_iterator end = t1.class_end(e2); + if (it != end) { + for (unsigned i = 0; i < row2.size(); ++i) { + acc[i+offs2] = row2[i]; + } + } + for (; it != end; ++it) { + acc[offs1+col1] = e2; + acc[offs1+1-col1] = *it; + mk_project(acc, proj); + TRACE("dl", for (unsigned i = 0; i < proj.size(); ++i) tout << proj[i] << " "; tout << "\n";); + res->add_fact(proj); + } + } + return res; + } + + virtual void mk_project(table_fact const & f, table_fact & p) const { + unsigned sz = f.size(); + p.reset(); + for (unsigned i = 0, r = 0; i < sz; ++i) { + if (r < m_removed_cols.size() && m_removed_cols[r] == i) { + ++r; + } + else { + p.push_back(f[i]); + } + } + } + + + }; + + table_join_fn * equivalence_table_plugin::mk_join_project_fn( + const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols) { + if (col_cnt != 1) { + TRACE("dl", tout << "WARNING: join_project on multiple columns is not implemented\n";); + return 0; + } + if (is_equivalence_table(t1) || is_equivalence_table(t2)) { + return alloc(join_project_fn, *this, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2, + removed_col_cnt, removed_cols); + } + return 0; + } + + class equivalence_table::eq_iterator : public iterator_core { + + equivalence_table const& m_eq; + unsigned m_last; + unsigned m_current; + unsigned m_next; + + class our_row : public caching_row_interface { + const eq_iterator& m_parent; + public: + our_row(const eq_iterator & p) : caching_row_interface(p.m_eq), m_parent(p) {} + + virtual void get_fact(table_fact& result) const { + if (result.size() < size()) { + result.resize(size(), 0); + } + result[0] = m_parent.m_current; + result[1] = m_parent.m_next; + } + + virtual table_element operator[](unsigned col) const { + if (col == 0) return m_parent.m_current; + if (col == 1) return m_parent.m_next; + UNREACHABLE(); + return 0; + } + + }; + our_row m_row_obj; + + public: + eq_iterator(const equivalence_table& eq, bool end): + m_eq(eq), + m_last(eq.m_uf.get_num_vars()), + m_current(end?m_last:0), + m_next(0), + m_row_obj(*this) + { + while (m_current < m_last && !m_eq.is_valid(m_current)) { + m_current++; + m_next = m_current; + } + } + + virtual bool is_finished() const { + return m_current == m_last; + } + + virtual row_interface & operator*() { + SASSERT(!is_finished()); + return m_row_obj; + } + + virtual void operator++() { + SASSERT(!is_finished()); + m_next = m_eq.m_uf.next(m_next); + if (m_next == m_current) { + do { + m_current++; + m_next = m_current; + } + while (m_current < m_last && !m_eq.is_valid(m_current)); + } + } + }; + + equivalence_table::equivalence_table(equivalence_table_plugin & plugin, const table_signature & sig) + : table_base(plugin, sig), m_uf(m_ctx), m_sparse(0) { + SASSERT(plugin.can_handle_signature(sig)); + } + + equivalence_table::~equivalence_table() { + if (is_sparse()) { + m_sparse->deallocate(); + } + } + + + void equivalence_table::add_fact(const table_fact & f) { + if (is_sparse()) { + add_fact_sparse(f); + } + else { + TRACE("dl_verbose", for (unsigned i = 0; i < f.size(); ++i) tout << f[i] << " "; tout << "\n";); + while (first(f) >= m_uf.get_num_vars()) m_uf.mk_var(); + while (second(f) >= m_uf.get_num_vars()) m_uf.mk_var(); + m_uf.merge(first(f), second(f)); + m_valid.reserve(m_uf.get_num_vars()); + m_valid.set(first(f)); + m_valid.set(second(f)); + } + } + + void equivalence_table::remove_fact(const table_element* fact) { + mk_sparse(); + m_sparse->remove_fact(fact); + } + + void equivalence_table::mk_sparse() { + if (m_sparse) return; + + TRACE("dl",tout << "\n";); + table_plugin & plugin = get_plugin(); + table_plugin* rp = plugin.get_manager().get_table_plugin(symbol("sparse")); + SASSERT(rp); + table_base* result = rp->mk_empty(get_signature()); + table_base::iterator it = begin(), e = end(); + table_fact fact; + for (; it != e; ++it) { + it->get_fact(fact); + result->add_fact(fact); + } + m_sparse = result; + } + + void equivalence_table::add_fact_sparse(table_fact const& f) { + table_base::iterator it = m_sparse->begin(), end = m_sparse->end(); + vector to_add; + to_add.push_back(f); + table_fact f1(f); + + f1[0] = f[1]; + f1[1] = f[0]; + to_add.push_back(f1); + + f1[0] = f[1]; + f1[1] = f[1]; + to_add.push_back(f1); + + f1[0] = f[0]; + f1[1] = f[0]; + to_add.push_back(f1); + + for (; it != end; ++it) { + if ((*it)[0] == f[0]) { + f1[0] = f[1]; + f1[1] = (*it)[1]; + to_add.push_back(f1); + std::swap(f1[0],f1[1]); + to_add.push_back(f1); + } + } + for (unsigned i = 0; i < to_add.size(); ++i) { + m_sparse->add_fact(to_add[i]); + } + } + + bool equivalence_table::contains_fact(const table_fact & f) const { + TRACE("dl_verbose", for (unsigned i = 0; i < f.size(); ++i) tout << f[i] << " "; tout << "\n";); + if (is_sparse()) { + return m_sparse->contains_fact(f); + } + return + is_valid(first(f)) && + is_valid(second(f)) && + m_uf.find(first(f)) == m_uf.find(second(f)); + } + + table_base* equivalence_table::clone() const { + if (is_sparse()) { + return m_sparse->clone(); + } + TRACE("dl",tout << "\n";); + table_plugin & plugin = get_plugin(); + table_base* result = plugin.mk_empty(get_signature()); + table_fact fact; + fact.resize(2); + for (unsigned i = 0; i < m_uf.get_num_vars(); ++i) { + if (m_valid.get(i) && m_uf.find(i) == i) { + unsigned n = m_uf.next(i); + fact[0] = i; + while (n != i) { + fact[1] = n; + result->add_fact(fact); + n = m_uf.next(n); + } + } + } + return result; + } + + table_base::iterator equivalence_table::begin() const { + if (is_sparse()) return m_sparse->begin(); + return mk_iterator(alloc(eq_iterator, *this, false)); + } + + table_base::iterator equivalence_table::end() const { + if (is_sparse()) return m_sparse->end(); + return mk_iterator(alloc(eq_iterator, *this, true)); + } + + equivalence_table::class_iterator equivalence_table::class_begin(table_element const& _e) const { + SASSERT(!is_sparse()); + unsigned e = static_cast(_e); + return class_iterator(*this, e, !is_valid(e)); + } + + equivalence_table::class_iterator equivalence_table::class_end(table_element const& _e) const { + SASSERT(!is_sparse()); + unsigned e = static_cast(_e); + return class_iterator(*this, e, true); + } + + void equivalence_table::display(std::ostream& out) const { + if (is_sparse()) { + m_sparse->display(out); + return; + } + for (unsigned i = 0; i < m_uf.get_num_vars(); ++i) { + if (is_valid(i) && m_uf.find(i) == i) { + unsigned j = i, last = i; + do { + out << "<" << i << " " << j << ">\n"; + j = m_uf.next(j); + } + while (last != j); + } + } + } + + unsigned equivalence_table::get_size_estimate_rows() const { + if (is_sparse()) return m_sparse->get_size_estimate_rows(); + return static_cast(get_signature()[0]); + } + + unsigned equivalence_table::get_size_estimate_bytes() const { + if (is_sparse()) return m_sparse->get_size_estimate_bytes(); + return static_cast(get_signature()[0]); + } + + bool equivalence_table::knows_exact_size() const { + return (!is_sparse() || m_sparse->knows_exact_size()); + } + +}; + diff --git a/src/muz/rel/dl_table.h b/src/muz/rel/dl_table.h new file mode 100644 index 000000000..3a240c337 --- /dev/null +++ b/src/muz/rel/dl_table.h @@ -0,0 +1,265 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_table.h + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-01. + +Revision History: + +--*/ +#ifndef _DL_TABLE_H_ +#define _DL_TABLE_H_ + +#include +#include +#include + +#include "ast.h" +#include "bit_vector.h" +#include "buffer.h" +#include "hashtable.h" +#include "map.h" +#include "ref_vector.h" +#include "vector.h" +#include "union_find.h" +#include "dl_base.h" +#include "dl_util.h" +#include "bit_vector.h" + + +namespace datalog { + + class context; + class variable_intersection; + + + + // ----------------------------------- + // + // hashtable_table + // + // ----------------------------------- + + class hashtable_table; + + class hashtable_table_plugin : public table_plugin { + friend class hashtable_table; + protected: + class join_fn; + public: + typedef hashtable_table table; + + hashtable_table_plugin(relation_manager & manager) + : table_plugin(symbol("hashtable"), manager) {} + + virtual table_base * mk_empty(const table_signature & s); + + virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + }; + + class hashtable_table : public table_base { + friend class hashtable_table_plugin; + friend class hashtable_table_plugin::join_fn; + + class our_iterator_core; + + typedef hashtable, + vector_eq_proc > storage; + + storage m_data; + + hashtable_table(hashtable_table_plugin & plugin, const table_signature & sig) + : table_base(plugin, sig) {} + public: + hashtable_table_plugin & get_plugin() const + { return static_cast(table_base::get_plugin()); } + + virtual void add_fact(const table_fact & f) { + m_data.insert(f); + } + virtual void remove_fact(const table_element* fact) { + table_fact f(get_signature().size(), fact); + m_data.remove(f); + } + virtual bool contains_fact(const table_fact & f) const { + return m_data.contains(f); + } + + virtual iterator begin() const; + virtual iterator end() const; + + virtual unsigned get_size_estimate_rows() const { return m_data.size(); } + virtual unsigned get_size_estimate_bytes() const { return m_data.size()*get_signature().size()*8; } + virtual bool knows_exact_size() const { return true; } + }; + + // ----------------------------------- + // + // bitvector_table + // + // ----------------------------------- + + class bitvector_table; + + class bitvector_table_plugin : public table_plugin { + public: + typedef bitvector_table table; + + bitvector_table_plugin(relation_manager & manager) + : table_plugin(symbol("bitvector"), manager) {} + + virtual bool can_handle_signature(const table_signature & s); + + virtual table_base * mk_empty(const table_signature & s); + }; + + class bitvector_table : public table_base { + friend class bitvector_table_plugin; + + class bv_iterator; + bit_vector m_bv; + unsigned m_num_cols; + unsigned_vector m_shift; + unsigned_vector m_mask; + + unsigned fact2offset(const table_element* f) const; + void offset2fact(unsigned offset, table_fact& f) const; + + bitvector_table(bitvector_table_plugin & plugin, const table_signature & sig); + public: + virtual void add_fact(const table_fact & f); + virtual void remove_fact(const table_element* fact); + virtual bool contains_fact(const table_fact & f) const; + virtual iterator begin() const; + virtual iterator end() const; + }; + + // ------------------------------------------- + // Equivalence table. + // Really: partial equivalence relation table. + // ------------------------------------------- + + class equivalence_table; + + class equivalence_table_plugin : public table_plugin { + class union_fn; + class select_equal_and_project_fn; + class join_project_fn; + + bool is_equivalence_table(table_base const& tbl) const; + + public: + typedef equivalence_table table; + + equivalence_table_plugin(relation_manager & manager) + : table_plugin(symbol("equivalence"), manager) {} + + virtual bool can_handle_signature(const table_signature & s); + + virtual table_base * mk_empty(const table_signature & s); + + protected: + virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src, + const table_base * delta); + virtual table_transformer_fn * mk_select_equal_and_project_fn( + const table_base & t, + const table_element & value, unsigned col); + virtual table_join_fn * mk_join_project_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols); + + +#if 0 + virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + const table_element & value, unsigned col); + virtual table_intersection_filter_fn * mk_filter_by_negation_fn(const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols); +#endif + }; + + class equivalence_table : public table_base { + friend class equivalence_table_plugin; + + class eq_iterator; + union_find_default_ctx m_ctx; + bit_vector m_valid; + union_find<> m_uf; + table_base* m_sparse; + + equivalence_table(equivalence_table_plugin & plugin, const table_signature & sig); + virtual ~equivalence_table(); + + unsigned first(table_fact const& f) const { return static_cast(f[0]); } + unsigned second(table_fact const& f) const { return static_cast(f[1]); } + + bool is_valid(unsigned entry) const { return entry < m_valid.size() && m_valid.get(entry); } + bool is_sparse() const { return m_sparse != 0; } + + // iterator over equivalence class of 'n'. + class class_iterator { + equivalence_table const& m_parent; + unsigned m_current; + unsigned m_last; + bool m_end; + public: + class_iterator(equivalence_table const& s, unsigned n, bool end): + m_parent(s), m_current(n), m_last(n), m_end(end) {} + + unsigned operator*() { return m_current; } + + class_iterator& operator++() { + m_current = m_parent.m_uf.next(m_current); + m_end = (m_current == m_last); + return *this; + } + + bool operator==(const class_iterator & it) const { + return + (m_end && it.m_end) || + (!m_end && !it.m_end && m_current == it.m_current); + } + bool operator!=(const class_iterator & it) const { return !operator==(it); } + + }; + class_iterator class_begin(table_element const& e) const; + class_iterator class_end(table_element const& e) const; + + void add_fact_sparse(table_fact const& f); + void mk_sparse(); + + + public: + virtual void add_fact(const table_fact & f); + virtual void remove_fact(const table_element* fact); + virtual bool contains_fact(const table_fact & f) const; + virtual table_base* clone() const; + virtual iterator begin() const; + virtual iterator end() const; + virtual unsigned get_size_estimate_rows() const; + virtual unsigned get_size_estimate_bytes() const; + virtual bool knows_exact_size() const; + virtual void display(std::ostream & out) const; + + }; + + +}; + +#endif /* _DL_TABLE_H_ */ + diff --git a/src/muz/rel/dl_table_plugin.h b/src/muz/rel/dl_table_plugin.h new file mode 100644 index 000000000..134389b61 --- /dev/null +++ b/src/muz/rel/dl_table_plugin.h @@ -0,0 +1,193 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_table_plugin.h + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-23. + +Revision History: + +--*/ +#ifndef _DL_TABLE_PLUGIN_H_ +#define _DL_TABLE_PLUGIN_H_ + +#include"ast.h" +#include"map.h" +#include"vector.h" + +#include"dl_table_ops.h" + +namespace datalog { + + /** + Termplate class containing common infrastructure for relations and tables + */ + template + struct tr_infrastructure { + + typedef typename Traits::base_object base_object; + typedef typename Traits::signature signature; + typedef typename Traits::element element; + typedef typename Traits::fact fact; + typedef typename Traits::kind kind; + + class base_fn { + public: + virtual ~base_fn() {} + }; + + class join_fn : public base_fn { + public: + virtual base_object * operator()(const base_object & t1, const base_object & t2); + }; + + class transformer_fn : public base_fn { + public: + virtual base_object * operator()(const base_object & t); + }; + + class union_fn : public base_fn { + public: + virtual void operator()(base_object & tgt, const base_object & src, base_object * delta); + }; + + class mutator_fn : public base_fn { + public: + virtual void operator()(base_object & t); + }; + + class negation_filter_fn : public base_fn { + public: + virtual void operator()(base_object & t, const base_object & negated_obj); + }; + + class plugin_object { + const kind m_kind; + protected: + plugin_object(kind k) : m_kind(k) {} + public: + kind get_kind(); + + virtual base_object * mk_empty(const signature & s) = 0; + + virtual join_fn * mk_join_fn(const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + NOT_IMPLEMENTED_YET(); + } + + virtual transformer_fn * mk_project_fn(const base_object & t, unsigned col_cnt, + const unsigned * removed_cols) = 0 + + virtual transformer_fn * mk_rename_fn(const base_object & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) = 0; + + virtual union_fn * mk_union_fn(base_object & tgt, const base_object & src, base_object * delta) = 0; + + virtual mutator_fn * mk_filter_identical_fn(base_object & t, unsigned col_cnt, + const unsigned * identical_cols) = 0; + + virtual mutator_fn * mk_filter_equal_fn(base_object & t, const element & value, + unsigned col) = 0; + + virtual mutator_fn * mk_filter_interpreted_fn(base_object & t, app * condition) = 0; + + virtual negation_filter_fn * mk_filter_interpreted_fn(base_object & t, + const base_object & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) = 0; + + }; + + class base_ancestor { + const kind m_kind; + protected: + relation_manager & m_manager; + signature m_signature; + + base_ancestor(kind k, relation_manager & m, const signature & s) + : m_kind(k), m_manager(m), m_signature(s) {} + public: + virtual ~base_ancestor() {} + + kind get_kind() const { return m_kind; } + relation_manager & get_manager() const { return m_manager; } + const signature & get_signature() const { return m_signature; } + + virtual bool empty() const = 0; + virtual void add_fact(const fact & f) = 0; + virtual bool contains_fact(const fact & f) const = 0; + + /** + \brief Return table that contains the same data as the current one. + */ + virtual base_object * clone() const; + + }; + }; + + + // ----------------------------------- + // + // relation_base + // + // ----------------------------------- + + class relation_base1; + + enum relation_kind { + RK_UNKNOWN, + RK_TABLE + }; + + struct relation_traits { + typedef relation_base1 base_object; + typedef relation_signature signature; + typedef app * element; + typedef ptr_vector fact; + typedef relation_kind kind; + }; + + typedef tr_infrastructure relation_infrastructure; + + typedef relation_infrastructure::plugin_object relation_plugin_base; + + class relation_base1 : public relation_infrastructure::base_ancestor { + + }; + + + // ----------------------------------- + // + // table_base + // + // ----------------------------------- + + class table_base1; + + struct table_traits { + typedef table_base1 base_object; + typedef table_signature signature; + typedef unsigned element; + typedef unsigned_vector fact; + typedef table_kind kind; + }; + + typedef tr_infrastructure table_infrastructure; + + typedef table_infrastructure::plugin_object table_plugin_base; + + class table_base1 : public table_infrastructure::base_ancestor { + + }; + +}; + +#endif /* _DL_TABLE_PLUGIN_H_ */ + diff --git a/src/muz/rel/dl_table_relation.cpp b/src/muz/rel/dl_table_relation.cpp new file mode 100644 index 000000000..3c30c58bb --- /dev/null +++ b/src/muz/rel/dl_table_relation.cpp @@ -0,0 +1,490 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + dl_table_relation.cpp + +Abstract: + + + +Author: + + Krystof Hoder (t-khoder) 2010-09-14. + +Revision History: + +--*/ + + +#include +#include"dl_context.h" +#include"dl_relation_manager.h" +#include"dl_table_relation.h" + + +namespace datalog { + + // ----------------------------------- + // + // table_relation_plugin + // + // ----------------------------------- + + symbol table_relation_plugin::create_plugin_name(const table_plugin &p) { + std::string name = std::string("tr_") + p.get_name().bare_str(); + return symbol(name.c_str()); + } + + bool table_relation_plugin::can_handle_signature(const relation_signature & s) { + table_signature tsig; + if(!get_manager().relation_signature_to_table(s, tsig)) { + return false; + } + return m_table_plugin.can_handle_signature(tsig); + } + + + relation_base * table_relation_plugin::mk_empty(const relation_signature & s) { + table_signature tsig; + if(!get_manager().relation_signature_to_table(s, tsig)) { + return 0; + } + table_base * t = m_table_plugin.mk_empty(tsig); + return alloc(table_relation, *this, s, t); + } + + relation_base * table_relation_plugin::mk_full(const relation_signature & s, func_decl* p, family_id kind) { + table_signature tsig; + if(!get_manager().relation_signature_to_table(s, tsig)) { + return 0; + } + table_base * t = m_table_plugin.mk_full(p, tsig, kind); + return alloc(table_relation, *this, s, t); + } + + relation_base * table_relation_plugin::mk_from_table(const relation_signature & s, table_base * t) { + if (&t->get_plugin() == &m_table_plugin) + return alloc(table_relation, *this, s, t); + table_relation_plugin& other = t->get_manager().get_table_relation_plugin(t->get_plugin()); + return alloc(table_relation, other, s, t); + } + + class table_relation_plugin::tr_join_project_fn : public convenient_relation_join_project_fn { + scoped_ptr m_tfun; + public: + tr_join_project_fn(const relation_signature & s1, const relation_signature & s2, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols, table_join_fn * tfun) + : convenient_relation_join_project_fn(s1, s2, col_cnt, cols1, cols2, removed_col_cnt, + removed_cols), m_tfun(tfun) {} + + virtual relation_base * operator()(const relation_base & t1, const relation_base & t2) { + SASSERT(t1.from_table()); + SASSERT(t2.from_table()); + table_relation_plugin & plugin = static_cast(t1.get_plugin()); + + const table_relation & tr1 = static_cast(t1); + const table_relation & tr2 = static_cast(t2); + + table_base * tres = (*m_tfun)(tr1.get_table(), tr2.get_table()); + + TRACE("dl_table_relation", tout << "# join => "; tres->display(tout);); + if(&tres->get_plugin()!=&plugin.m_table_plugin) { + //Operation returned a table of different type than the one which is associated with + //this plugin. We need to get a correct table_relation_plugin and create the relation + //using it. + return plugin.get_manager().get_table_relation_plugin(tres->get_plugin()) + .mk_from_table(get_result_signature(), tres); + } + return plugin.mk_from_table(get_result_signature(), tres); + } + }; + + relation_join_fn * table_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if(!r1.from_table() || !r2.from_table()) { + return 0; + } + const table_relation & tr1 = static_cast(r1); + const table_relation & tr2 = static_cast(r2); + + table_join_fn * tfun = get_manager().mk_join_fn(tr1.get_table(), tr2.get_table(), col_cnt, cols1, cols2); + if(!tfun) { + return 0; + } + + return alloc(tr_join_project_fn, r1.get_signature(), r2.get_signature(), col_cnt, cols1, + cols2, 0, static_cast(0), tfun); + } + + relation_join_fn * table_relation_plugin::mk_join_project_fn(const relation_base & r1, + const relation_base & r2, unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, + unsigned removed_col_cnt, const unsigned * removed_cols) { + if(!r1.from_table() || !r2.from_table()) { + return 0; + } + const table_relation & tr1 = static_cast(r1); + const table_relation & tr2 = static_cast(r2); + + table_join_fn * tfun = get_manager().mk_join_project_fn(tr1.get_table(), tr2.get_table(), joined_col_cnt, + cols1, cols2, removed_col_cnt, removed_cols); + SASSERT(tfun); + + return alloc(tr_join_project_fn, r1.get_signature(), r2.get_signature(), joined_col_cnt, cols1, + cols2, removed_col_cnt, removed_cols, tfun); + } + + + class table_relation_plugin::tr_transformer_fn : public convenient_relation_transformer_fn { + scoped_ptr m_tfun; + public: + tr_transformer_fn(const relation_signature & rsig, table_transformer_fn * tfun) + : m_tfun(tfun) { get_result_signature() = rsig; } + + virtual relation_base * operator()(const relation_base & t) { + SASSERT(t.from_table()); + table_relation_plugin & plugin = static_cast(t.get_plugin()); + + const table_relation & tr = static_cast(t); + + table_base * tres = (*m_tfun)(tr.get_table()); + + TRACE("dl_table_relation", tout << "# transform => "; tres->display(tout);); + if(&tres->get_plugin()!=&plugin.m_table_plugin) { + //Transformation returned a table of different type than the one which is associated with this plugin. + //We need to get a correct table_relation_plugin and create the relation using it. + return plugin.get_manager().get_table_relation_plugin(tres->get_plugin()) + .mk_from_table(get_result_signature(), tres); + } + return plugin.mk_from_table(get_result_signature(), tres); + } + }; + + relation_transformer_fn * table_relation_plugin::mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols) { + if(!t.from_table()) { + return 0; + } + const table_relation & tr = static_cast(t); + + table_transformer_fn * tfun = get_manager().mk_project_fn(tr.get_table(), col_cnt, removed_cols); + SASSERT(tfun); + + relation_signature sig; + relation_signature::from_project(t.get_signature(), col_cnt, removed_cols, sig); + + return alloc(tr_transformer_fn, sig, tfun); + } + + relation_transformer_fn * table_relation_plugin::mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle) { + if(!t.from_table()) { + return 0; + } + const table_relation & tr = static_cast(t); + + table_transformer_fn * tfun = get_manager().mk_rename_fn(tr.get_table(), permutation_cycle_len, permutation_cycle); + SASSERT(tfun); + + relation_signature sig; + relation_signature::from_rename(t.get_signature(), permutation_cycle_len, permutation_cycle, sig); + + return alloc(tr_transformer_fn, sig, tfun); + } + + relation_transformer_fn * table_relation_plugin::mk_permutation_rename_fn(const relation_base & t, + const unsigned * permutation) { + if(!t.from_table()) { + return 0; + } + const table_relation & tr = static_cast(t); + + table_transformer_fn * tfun = get_manager().mk_permutation_rename_fn(tr.get_table(), permutation); + SASSERT(tfun); + + relation_signature sig; + relation_signature::from_permutation_rename(t.get_signature(), permutation, sig); + + return alloc(tr_transformer_fn, sig, tfun); + } + + relation_transformer_fn * table_relation_plugin::mk_select_equal_and_project_fn(const relation_base & t, + const relation_element & value, unsigned col) { + if(!t.from_table()) { + return 0; + } + const table_relation & tr = static_cast(t); + + table_element tvalue; + get_manager().relation_to_table(tr.get_signature()[col], value, tvalue); + + table_transformer_fn * tfun = get_manager().mk_select_equal_and_project_fn(tr.get_table(), tvalue, col); + SASSERT(tfun); + relation_signature res_sig; + relation_signature::from_project(t.get_signature(), 1, &col, res_sig); + return alloc(tr_transformer_fn, res_sig, tfun); + } + + /** + Union functor that can unite table relation into any other relation (using any delta relation) + by iterating through the table and calling \c add_fact of the target relation. + */ + class table_relation_plugin::universal_target_union_fn : public relation_union_fn { + virtual void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) { + SASSERT(src.from_table()); + + const table_relation & tr_src = static_cast(src); + relation_manager & rmgr = tr_src.get_manager(); + relation_signature sig = tr_src.get_signature(); + SASSERT(tgt.get_signature()==sig); + SASSERT(!delta || delta->get_signature()==sig); + + table_base::iterator it = tr_src.get_table().begin(); + table_base::iterator end = tr_src.get_table().end(); + + table_fact tfact; + relation_fact rfact(rmgr.get_context()); + for (; it != end; ++it) { + it->get_fact(tfact); + rmgr.table_fact_to_relation(sig, tfact, rfact); + if(delta) { + if(!tgt.contains_fact(rfact)) { + tgt.add_new_fact(rfact); + delta->add_fact(rfact); + } + } + else { + tgt.add_fact(rfact); + } + } + TRACE("dl_table_relation", tout << "# universal union => "; tgt.display(tout);); + } + }; + + class table_relation_plugin::tr_union_fn : public relation_union_fn { + scoped_ptr m_tfun; + public: + tr_union_fn(table_union_fn * tfun) : m_tfun(tfun) {} + + virtual void operator()(relation_base & tgt, const relation_base & src, relation_base * delta) { + SASSERT(tgt.from_table()); + SASSERT(src.from_table()); + SASSERT(!delta || delta->from_table()); + + table_relation & tr_tgt = static_cast(tgt); + const table_relation & tr_src = static_cast(src); + table_relation * tr_delta = static_cast(delta); + + (*m_tfun)(tr_tgt.get_table(), tr_src.get_table(), tr_delta ? &tr_delta->get_table() : 0); + + TRACE("dl_table_relation", tout << "# union => "; tr_tgt.get_table().display(tout);); + } + }; + + relation_union_fn * table_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if(!src.from_table()) { + return 0; + } + if(!tgt.from_table() || (delta && !delta->from_table())) { + return alloc(universal_target_union_fn); + } + const table_relation & tr_tgt = static_cast(tgt); + const table_relation & tr_src = static_cast(src); + const table_relation * tr_delta = static_cast(delta); + + table_union_fn * tfun = get_manager().mk_union_fn(tr_tgt.get_table(), tr_src.get_table(), + tr_delta ? &tr_delta->get_table() : 0); + SASSERT(tfun); + + return alloc(tr_union_fn, tfun); + } + + + class table_relation_plugin::tr_mutator_fn : public relation_mutator_fn { + scoped_ptr m_tfun; + public: + tr_mutator_fn(table_mutator_fn * tfun) : m_tfun(tfun) {} + + virtual void operator()(relation_base & r) { + SASSERT(r.from_table()); + table_relation & tr = static_cast(r); + (*m_tfun)(tr.get_table()); + TRACE("dl_table_relation", tout << "# mutator => "; tr.get_table().display(tout);); + } + }; + + relation_mutator_fn * table_relation_plugin::mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols) { + if(!t.from_table()) { + return 0; + } + const table_relation & tr = static_cast(t); + + table_mutator_fn * tfun = get_manager().mk_filter_identical_fn(tr.get_table(), col_cnt, identical_cols); + SASSERT(tfun); + return alloc(tr_mutator_fn, tfun); + } + + relation_mutator_fn * table_relation_plugin::mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col) { + if(!t.from_table()) { + return 0; + } + const table_relation & tr = static_cast(t); + + table_element tvalue; + get_manager().relation_to_table(tr.get_signature()[col], value, tvalue); + + table_mutator_fn * tfun = get_manager().mk_filter_equal_fn(tr.get_table(), tvalue, col); + SASSERT(tfun); + return alloc(tr_mutator_fn, tfun); + } + + relation_mutator_fn * table_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { + bool condition_needs_transforming = false; + if(!t.from_table() || condition_needs_transforming) { + return 0; + } + const table_relation & tr = static_cast(t); + table_mutator_fn * tfun = get_manager().mk_filter_interpreted_fn(tr.get_table(), condition); + SASSERT(tfun); + return alloc(tr_mutator_fn, tfun); + } + + relation_transformer_fn * table_relation_plugin::mk_filter_interpreted_and_project_fn(const relation_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) { + if (!t.from_table()) + return 0; + + const table_relation & tr = static_cast(t); + table_transformer_fn * tfun = get_manager().mk_filter_interpreted_and_project_fn(tr.get_table(), + condition, removed_col_cnt, removed_cols); + SASSERT(tfun); + + relation_signature sig; + relation_signature::from_project(t.get_signature(), removed_col_cnt, removed_cols, sig); + return alloc(tr_transformer_fn, sig, tfun); + } + + class table_relation_plugin::tr_intersection_filter_fn : public relation_intersection_filter_fn { + scoped_ptr m_tfun; + public: + tr_intersection_filter_fn(table_intersection_filter_fn * tfun) : m_tfun(tfun) {} + + virtual void operator()(relation_base & r, const relation_base & src) { + SASSERT(r.from_table()); + SASSERT(src.from_table()); + + table_relation & tr = static_cast(r); + const table_relation & tr_src = static_cast(src); + + (*m_tfun)(tr.get_table(), tr_src.get_table()); + TRACE("dl_table_relation", tout << "# negation_filter => "; tr.get_table().display(tout);); + } + }; + + relation_intersection_filter_fn * table_relation_plugin::mk_filter_by_intersection_fn(const relation_base & r, + const relation_base & src, unsigned joined_col_cnt, const unsigned * r_cols, const unsigned * src_cols) { + if(!r.from_table() || !src.from_table()) { + return 0; + } + const table_relation & tr = static_cast(r); + const table_relation & tr_neg = static_cast(src); + table_intersection_filter_fn * tfun = get_manager().mk_filter_by_intersection_fn(tr.get_table(), + tr_neg.get_table(), joined_col_cnt, r_cols, src_cols); + if(!tfun) { + return 0; + } + + return alloc(tr_intersection_filter_fn, tfun); + } + + + relation_intersection_filter_fn * table_relation_plugin::mk_filter_by_negation_fn(const relation_base & r, + const relation_base & negated_rel, unsigned joined_col_cnt, + const unsigned * r_cols, const unsigned * negated_cols) { + if(!r.from_table() || !negated_rel.from_table()) { + return 0; + } + const table_relation & tr = static_cast(r); + const table_relation & tr_neg = static_cast(negated_rel); + table_intersection_filter_fn * tfun = get_manager().mk_filter_by_negation_fn(tr.get_table(), + tr_neg.get_table(), joined_col_cnt, r_cols, negated_cols); + SASSERT(tfun); + + return alloc(tr_intersection_filter_fn, tfun); + } + + + // ----------------------------------- + // + // table_relation + // + // ----------------------------------- + + void table_relation::add_table_fact(const table_fact & f) { + get_table().add_fact(f); + } + + void table_relation::add_fact(const relation_fact & f) { + SASSERT(f.size()==get_signature().size()); + table_fact vals; + get_manager().relation_fact_to_table(get_signature(), f, vals); + get_table().add_fact(vals); + TRACE("dl_table_relation", tout << "# add fact => "; get_table().display(tout);); + } + + bool table_relation::contains_fact(const relation_fact & f) const { + table_fact vals; + get_manager().relation_fact_to_table(get_signature(), f, vals); + return get_table().contains_fact(vals); + } + + relation_base * table_relation::clone() const { + table_base * tres = get_table().clone(); + return get_plugin().mk_from_table(get_signature(), tres); + } + + relation_base * table_relation::complement(func_decl* p) const { + table_base * tres = get_table().complement(p); + return get_plugin().mk_from_table(get_signature(), tres); + } + + void table_relation::display_tuples(func_decl & pred, std::ostream & out) const { + context & ctx = get_manager().get_context(); + unsigned arity = pred.get_arity(); + + out << "Tuples in " << pred.get_name() << ": \n"; + + table_base::iterator it = get_table().begin(); + table_base::iterator end = get_table().end(); + + table_fact fact; + for (; it != end; ++it) { + it->get_fact(fact); + + out << "\t("; + + for(unsigned i=0;i + +Author: + + Krystof Hoder (t-khoder) 2010-09-24. + +Revision History: + +--*/ +#ifndef _DL_TABLE_RELATION_H_ +#define _DL_TABLE_RELATION_H_ + + +#include "dl_base.h" +#include "dl_util.h" + +namespace datalog { + + class table_relation; + + class table_relation_plugin : public relation_plugin { + friend class table_relation; + + class tr_join_project_fn; + class tr_transformer_fn; + class universal_target_union_fn; + class tr_union_fn; + class tr_mutator_fn; + class tr_intersection_filter_fn; + + table_plugin & m_table_plugin; + + static symbol create_plugin_name(const table_plugin & p); + public: + table_relation_plugin(table_plugin & tp, relation_manager & manager) + : relation_plugin(create_plugin_name(tp), manager, ST_TABLE_RELATION), m_table_plugin(tp) {} + + table_plugin & get_table_plugin() { return m_table_plugin; } + + virtual bool can_handle_signature(const relation_signature & s); + + virtual relation_base * mk_empty(const relation_signature & s); + virtual relation_base * mk_full(const relation_signature & s, func_decl* p, family_id kind); + relation_base * mk_from_table(const relation_signature & s, table_base * t); + + protected: + virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_join_fn * mk_join_project_fn(const relation_base & t1, const relation_base & t2, + unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_transformer_fn * mk_permutation_rename_fn(const relation_base & t, + const unsigned * permutation); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + virtual relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t, + app * condition, unsigned removed_col_cnt, const unsigned * removed_cols); + virtual relation_intersection_filter_fn * mk_filter_by_intersection_fn(const relation_base & t, + const relation_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols); + virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t, + const relation_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols); + virtual relation_transformer_fn * mk_select_equal_and_project_fn(const relation_base & t, + const relation_element & value, unsigned col); + }; + + class table_relation : public relation_base { + friend class table_relation_plugin; + friend class table_relation_plugin::tr_join_project_fn; + friend class table_relation_plugin::tr_transformer_fn; + + scoped_rel m_table; + + /** + \brief Create a \c table_relation object. + + The newly created object takes ownership of the \c table object. + */ + table_relation(table_relation_plugin & p, const relation_signature & s, table_base * table) + : relation_base(p, s), m_table(table) { + SASSERT(s.size()==table->get_signature().size()); + } + public: + + table_relation_plugin & get_plugin() const { + return static_cast(relation_base::get_plugin()); + } + + table_base & get_table() { return *m_table; } + const table_base & get_table() const { return *m_table; } + + virtual bool empty() const { return m_table->empty(); } + + void add_table_fact(const table_fact & f); + + virtual void add_fact(const relation_fact & f); + virtual bool contains_fact(const relation_fact & f) const; + virtual relation_base * clone() const; + virtual relation_base * complement(func_decl* p) const; + virtual void to_formula(expr_ref& fml) const { get_table().to_formula(get_signature(), fml); } + + virtual void display(std::ostream & out) const { + get_table().display(out); + } + virtual void display_tuples(func_decl & pred, std::ostream & out) const; + + virtual unsigned get_size_estimate_rows() const { return m_table->get_size_estimate_rows(); } + virtual unsigned get_size_estimate_bytes() const { return m_table->get_size_estimate_bytes(); } + virtual bool knows_exact_size() const { return m_table->knows_exact_size(); } + }; + +}; + +#endif /* _DL_TABLE_RELATION_H_ */ + diff --git a/src/muz/rel/dl_vector_relation.h b/src/muz/rel/dl_vector_relation.h new file mode 100644 index 000000000..114f4ca43 --- /dev/null +++ b/src/muz/rel/dl_vector_relation.h @@ -0,0 +1,407 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + dl_vector_relation.h + +Abstract: + + Basic relation with equivalences. + +Author: + + Nikolaj Bjorner (nbjorner) 2010-2-11 + +Revision History: + +--*/ +#ifndef _DL_VECTOR_RELATION_H_ +#define _DL_VECTOR_RELATION_H_ + +#include "ast_pp.h" +#include "dl_context.h" +#include "union_find.h" + +namespace datalog { + + typedef std::pair u_pair; + + template + class vector_relation_helper { + public: + static void mk_project_t(T& t, unsigned_vector const& renaming) {} + }; + + template > + class vector_relation : public relation_base { + protected: + T m_default; + vector* m_elems; + bool m_empty; + union_find_default_ctx m_ctx; + union_find<>* m_eqs; + + friend class vector_relation_plugin; + + public: + vector_relation(relation_plugin& p, relation_signature const& s, bool is_empty, T const& t = T()): + relation_base(p, s), + m_default(t), + m_elems(alloc(vector)), + m_empty(is_empty), + m_eqs(alloc(union_find<>, m_ctx)) { + m_elems->resize(s.size(), t); + for (unsigned i = 0; i < s.size(); ++i) { + m_eqs->mk_var(); + } + } + + virtual ~vector_relation() { + dealloc(m_eqs); + dealloc(m_elems); + } + + virtual bool can_swap() const { return true; } + + virtual void swap(relation_base& other) { + vector_relation& o = dynamic_cast(other); + if (&o == this) return; + std::swap(o.m_eqs, m_eqs); + std::swap(o.m_empty, m_empty); + std::swap(o.m_elems, m_elems); + } + + void copy(vector_relation const& other) { + SASSERT(get_signature() == other.get_signature()); + if (other.empty()) { + set_empty(); + return; + } + m_empty = false; + for (unsigned i = 0; i < m_elems->size(); ++i) { + (*this)[i] = other[i]; + SASSERT(find(i) == i); + } + for (unsigned i = 0; i < m_elems->size(); ++i) { + merge(i, find(i)); + } + } + + + virtual bool empty() const { return m_empty; } + + T& operator[](unsigned i) { return (*m_elems)[find(i)]; } + + T const& operator[](unsigned i) const { return (*m_elems)[find(i)]; } + + virtual void display_index(unsigned i, T const& t, std::ostream& out) const = 0; + + virtual void display(std::ostream & out) const { + if (empty()) { + out << "empty\n"; + return; + } + for (unsigned i = 0; i < m_elems->size(); ++i) { + if (i == find(i)) { + display_index(i, (*m_elems)[i], out); + } + else { + out << i << " = " << find(i) << "\n"; + } + } + } + + + bool is_subset_of(vector_relation const& other) const { + if (empty()) return true; + if (other.empty()) return false; + for (unsigned i = 0; i < get_signature().size(); ++i) { + if (!is_subset_of((*this)[i], other[i])) { + return false; + } + } + return true; + } + + void set_empty() { + unsigned sz = m_elems->size(); + m_empty = true; + m_elems->reset(); + m_elems->resize(sz, m_default); + dealloc(m_eqs); + m_eqs = alloc(union_find<>,m_ctx); + for (unsigned i = 0; i < sz; ++i) { + m_eqs->mk_var(); + } + } + + + virtual T mk_intersect(T const& t1, T const& t2, bool& is_empty) const = 0; + + virtual T mk_widen(T const& t1, T const& t2) const = 0; + + virtual T mk_unite(T const& t1, T const& t2) const = 0; + + virtual bool is_subset_of(T const& t1, T const& t2) const = 0; + + virtual bool is_full(T const& t) const = 0; + + virtual bool is_empty(unsigned i, T const& t) const = 0; + + virtual void mk_rename_elem(T& t, unsigned col_cnt, unsigned const* cycle) = 0; + + virtual T mk_eq(union_find<> const& old_eqs, union_find<> const& neq_eqs, T const& t) const { return t; } + + void equate(unsigned i, unsigned j) { + SASSERT(i < get_signature().size()); + SASSERT(j < get_signature().size()); + if (!empty() && find(i) != find(j)) { + bool isempty; + T r = mk_intersect((*this)[i], (*this)[j], isempty); + if (isempty || is_empty(find(i),r)) { + m_empty = true; + } + else { + merge(i, j); + (*this)[i] = r; + } + } + } + + bool is_full() const { + for (unsigned i = 0; i < m_elems->size(); ++i) { + if (!is_full((*this)[i])) { + return false; + } + } + return true; + } + + void mk_join(vector_relation const& r1, vector_relation const& r2, + unsigned num_cols, unsigned const* cols1, unsigned const* cols2) { + SASSERT(is_full()); + bool is_empty = r1.empty() || r2.empty(); + if (is_empty) { + m_empty = true; + return; + } + unsigned sz1 = r1.get_signature().size(); + unsigned sz2 = r2.get_signature().size(); + for (unsigned i = 0; i < sz1; ++i) { + (*this)[i] = r1[i]; + } + for (unsigned i = 0; i < sz2; ++i) { + (*this)[sz1+i] = r2[i]; + } + for (unsigned i = 0; i < num_cols; ++i) { + unsigned col1 = cols1[i]; + unsigned col2 = cols2[i]; + equate(col1, sz1 + col2); + } + + TRACE("dl_relation", + r1.display(tout << "r1:\n"); + r2.display(tout << "r2:\n"); + display(tout << "dst:\n"); + ); + } + + void mk_project(vector_relation const& r, unsigned col_cnt, unsigned const* removed_cols) { + SASSERT(is_full()); + unsigned_vector classRep, repNode; + unsigned result_size = get_signature().size(); + unsigned input_size = r.get_signature().size(); + repNode.resize(input_size, UINT_MAX); + + // initialize vector entries and set class representatives. + for (unsigned i = 0, j = 0, c = 0; i < input_size; ++i) { + if (c < col_cnt && removed_cols[c] == i) { + ++c; + } + else { + (*this)[j] = r[i]; + classRep.push_back(r.find(i)); + ++j; + } + } + + // merge remaining equivalence classes. + for (unsigned i = 0; i < result_size; ++i) { + unsigned rep = classRep[i]; + if (repNode[rep] == UINT_MAX) { + repNode[rep] = i; + } + else { + merge(repNode[rep], i); + } + } + + // rename columns in image of vector relation. + unsigned_vector renaming; + for (unsigned i = 0, j = 0, c = 0; i < input_size; ++i) { + if (c < col_cnt && removed_cols[c] == i) { + renaming.push_back(UINT_MAX); + ++c; + } + else { + renaming.push_back(find(j)); + ++j; + } + } + for (unsigned k = 0; k < result_size; ++k) { + Helper::mk_project_t((*this)[k], renaming); + } + + + TRACE("dl_relation", + ast_manager& m = r.get_plugin().get_ast_manager(); + tout << "Signature: "; + for (unsigned i = 0; i < r.get_signature().size(); ++i) { + tout << mk_pp(r.get_signature()[i], m) << " "; + } + tout << "Remove: "; + for (unsigned i = 0; i < col_cnt; ++i) { + tout << removed_cols[i] << " "; + } + tout << "\n"; + r.display(tout); + tout << " --> \n"; + display(tout);); + } + + void mk_rename(vector_relation const& r, unsigned col_cnt, unsigned const* cycle) { + unsigned col1, col2; + SASSERT(is_full()); + + // roundabout way of creating permuted relation. + unsigned_vector classRep, repNode; + for (unsigned i = 0; i < r.m_elems->size(); ++i) { + classRep.push_back(r.find(i)); + repNode.push_back(UINT_MAX); + (*this)[i] = r[i]; + } + for (unsigned i = 0; i + 1 < col_cnt; ++i) { + col1 = cycle[i]; + col2 = cycle[i+1]; + (*this)[col2] = (*r.m_elems)[col1]; + classRep[col2] = r.find(col1); + } + col1 = cycle[col_cnt-1]; + col2 = cycle[0]; + (*this)[col2] = (*r.m_elems)[col1]; + classRep[col2] = r.find(col1); + + for (unsigned i = 0; i < r.m_elems->size(); ++i) { + unsigned rep = classRep[i]; + if (repNode[rep] == UINT_MAX) { + repNode[rep] = i; + } + else { + merge(repNode[rep], i); + } + } + + for (unsigned i = 0; i < r.m_elems->size(); ++i) { + mk_rename_elem((*m_elems)[i], col_cnt, cycle); + } + + TRACE("dl_relation", + ast_manager& m = r.get_plugin().get_ast_manager(); + tout << "cycle: "; + for (unsigned i = 0; i < col_cnt; ++i) { + tout << cycle[i] << " "; + } + tout << "\nold_sig: "; + for (unsigned i = 0; i < r.get_signature().size(); ++i) { + tout << mk_pp(r.get_signature()[i], m) << " "; + } + tout << "\nnew_sig: "; + for (unsigned i = 0; i < get_signature().size(); ++i) { + tout << mk_pp(get_signature()[i], m) << " "; + } + tout << "\n"; + r.display(tout << "src:\n"); + ); + } + + void mk_union(vector_relation const& src, vector_relation* delta, bool is_widen) { + TRACE("dl_relation", display(tout << "dst:\n"); src.display(tout << "src:\n");); + + if (src.empty()) { + if (delta) { + delta->copy(src); + } + return; + } + + if (empty()) { + copy(src); + if (delta) { + delta->copy(src); + } + return; + } + + // find coarsest equivalence class containing joint equalities + union_find<>* uf = alloc(union_find<>, m_ctx); + unsigned size = get_signature().size(); + map, default_eq > mp; + bool change = false; + bit_vector finds; + finds.resize(size, false); + for (unsigned i = 0; i < size; ++i) { + uf->mk_var(); + unsigned w; + u_pair p(std::make_pair(find(i), src.find(i))); + if (mp.find(p, w)) { + uf->merge(i, w); + } + else { + mp.insert(p, i); + // detect change + if (finds.get(find(i))) { + change = true; + } + else { + finds.set(find(i), true); + } + } + } + vector* elems = alloc(vector); + for (unsigned i = 0; i < size; ++i) { + T t1 = mk_eq(*m_eqs, *uf, (*this)[i]); + T t2 = mk_eq(*src.m_eqs, *uf, src[i]); + if (is_widen) { + elems->push_back(mk_widen(t1, t2)); + } + else { + elems->push_back(mk_unite(t1, t2)); + } + TRACE("dl_relation", tout << t1 << " u " << t2 << " = " << elems->back() << "\n";); + change = delta && (change || !((*elems)[i] == (*this)[i])); + } + dealloc(m_eqs); + dealloc(m_elems); + m_eqs = uf; + m_elems = elems; + if (delta && change) { + delta->copy(*this); + } + TRACE("dl_relation", display(tout << "dst':\n");); + } + + unsigned find(unsigned i) const { + return m_eqs->find(i); + } + + void merge(unsigned i, unsigned j) { + m_eqs->merge(i, j); + } + + }; + +}; + +#endif + diff --git a/src/muz/rel/karr_relation.cpp b/src/muz/rel/karr_relation.cpp new file mode 100644 index 000000000..436cd8598 --- /dev/null +++ b/src/muz/rel/karr_relation.cpp @@ -0,0 +1,790 @@ +#include "karr_relation.h" +#include "bool_rewriter.h" + +namespace datalog { + class karr_relation : public relation_base { + friend class karr_relation_plugin; + friend class karr_relation_plugin::filter_equal_fn; + + karr_relation_plugin& m_plugin; + ast_manager& m; + mutable arith_util a; + func_decl_ref m_fn; + mutable bool m_empty; + mutable matrix m_ineqs; + mutable bool m_ineqs_valid; + mutable matrix m_basis; + mutable bool m_basis_valid; + + public: + karr_relation(karr_relation_plugin& p, func_decl* f, relation_signature const& s, bool is_empty): + relation_base(p, s), + m_plugin(p), + m(p.get_ast_manager()), + a(m), + m_fn(f, m), + m_empty(is_empty), + m_ineqs_valid(!is_empty), + m_basis_valid(false) + { + } + + virtual bool empty() const { + return m_empty; + } + + virtual bool is_precise() const { return false; } + + virtual void add_fact(const relation_fact & f) { + SASSERT(m_empty); + SASSERT(!m_basis_valid); + m_empty = false; + m_ineqs_valid = true; + for (unsigned i = 0; i < f.size(); ++i) { + rational n; + if (a.is_numeral(f[i], n) && n.is_int()) { + vector row; + row.resize(f.size()); + row[i] = rational(1); + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(-n); + m_ineqs.eq.push_back(true); + } + } + } + + virtual bool contains_fact(const relation_fact & f) const { + UNREACHABLE(); + return false; + } + + virtual void display(std::ostream & out) const { + if (m_fn) { + out << m_fn->get_name() << "\n"; + } + if (empty()) { + out << "empty\n"; + } + else { + if (m_ineqs_valid) { + m_ineqs.display(out << "ineqs:\n"); + } + if (m_basis_valid) { + m_basis.display(out << "basis:\n"); + } + } + } + + virtual karr_relation * clone() const { + karr_relation* result = alloc(karr_relation, m_plugin, m_fn, get_signature(), m_empty); + result->copy(*this); + return result; + } + + virtual karr_relation * complement(func_decl*) const { + UNREACHABLE(); + return 0; + } + + virtual void to_formula(expr_ref& fml) const { + if (empty()) { + fml = m.mk_false(); + } + else { + matrix const& M = get_ineqs(); + expr_ref_vector conj(m); + for (unsigned i = 0; i < M.size(); ++i) { + to_formula(M.A[i], M.b[i], M.eq[i], conj); + } + bool_rewriter(m).mk_and(conj.size(), conj.c_ptr(), fml); + } + } + + karr_relation_plugin& get_plugin() const { return m_plugin; } + + void filter_interpreted(app* cond) { + rational one(1), mone(-1); + expr* e1, *e2, *en; + var* v, *w; + rational n1, n2; + expr_ref_vector conjs(m); + qe::flatten_and(cond, conjs); + matrix& M = get_ineqs(); + unsigned num_columns = get_signature().size(); + + for (unsigned i = 0; i < conjs.size(); ++i) { + expr* e = conjs[i].get(); + rational b(0); + vector row; + row.resize(num_columns, rational(0)); + bool processed = true; + if (m.is_eq(e, e1, e2) && is_linear(e1, row, b, one) && is_linear(e2, row, b, mone)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(true); + } + else if ((a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(false); + } + else if ((a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b - rational(1)); + M.eq.push_back(false); + } + else if (m.is_not(e, en) && (a.is_lt(en, e2, e1) || a.is_gt(en, e1, e2)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b); + M.eq.push_back(false); + } + else if (m.is_not(e, en) && (a.is_le(en, e2, e1) || a.is_ge(en, e1, e2)) && + is_linear(e1, row, b, mone) && is_linear(e2, row, b, one)) { + M.A.push_back(row); + M.b.push_back(b - rational(1)); + M.eq.push_back(false); + } + else if (m.is_or(e, e1, e2) && is_eq(e1, v, n1) && is_eq(e2, w, n2) && v == w) { + if (n1 > n2) { + std::swap(n1, n2); + } + SASSERT(n1 <= n2); + row[v->get_idx()] = rational(1); + // v - n1 >= 0 + M.A.push_back(row); + M.b.push_back(-n1); + M.eq.push_back(false); + // -v + n2 >= 0 + row[v->get_idx()] = rational(-1); + M.A.push_back(row); + M.b.push_back(n2); + M.eq.push_back(false); + } + else { + processed = false; + } + TRACE("dl", tout << (processed?"+ ":"- ") << mk_pp(e, m) << "\n"; + if (processed) matrix::display_ineq(tout, row, M.b.back(), M.eq.back()); + ); + } + TRACE("dl", display(tout);); + } + + void mk_join(karr_relation const& r1, karr_relation const& r2, + unsigned col_cnt, unsigned const* cols1, unsigned const* cols2) { + if (r1.empty() || r2.empty()) { + m_empty = true; + return; + } + matrix const& M1 = r1.get_ineqs(); + matrix const& M2 = r2.get_ineqs(); + unsigned sig1_size = r1.get_signature().size(); + unsigned sig_size = get_signature().size(); + m_ineqs.reset(); + for (unsigned i = 0; i < M1.size(); ++i) { + vector row; + row.append(M1.A[i]); + row.resize(sig_size); + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(M1.b[i]); + m_ineqs.eq.push_back(M1.eq[i]); + } + for (unsigned i = 0; i < M2.size(); ++i) { + vector row; + row.resize(sig_size); + for (unsigned j = 0; j < M2.A[i].size(); ++j) { + row[sig1_size + j] = M2.A[i][j]; + } + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(M2.b[i]); + m_ineqs.eq.push_back(M2.eq[i]); + } + for (unsigned i = 0; i < col_cnt; ++i) { + vector row; + row.resize(sig_size); + row[cols1[i]] = rational(1); + row[sig1_size + cols2[i]] = rational(-1); + m_ineqs.A.push_back(row); + m_ineqs.b.push_back(rational(0)); + m_ineqs.eq.push_back(true); + } + m_ineqs_valid = true; + m_basis_valid = false; + m_empty = false; + if (r1.m_fn) { + m_fn = r1.m_fn; + } + if (r2.m_fn) { + m_fn = r2.m_fn; + } + } + + void mk_project(karr_relation const& r, unsigned cnt, unsigned const* cols) { + if (r.m_empty) { + m_empty = true; + return; + } + matrix const& M = r.get_basis(); + m_basis.reset(); + for (unsigned i = 0; i < M.size(); ++i) { + vector row; + unsigned k = 0; + for (unsigned j = 0; j < M.A[i].size(); ++j) { + if (k < cnt && j == cols[k]) { + ++k; + } + else { + row.push_back(M.A[i][j]); + } + } + SASSERT(row.size() + cnt == M.A[i].size()); + SASSERT(M.eq[i]); + m_basis.A.push_back(row); + m_basis.b.push_back(M.b[i]); + m_basis.eq.push_back(true); + } + m_basis_valid = true; + m_ineqs_valid = false; + m_empty = false; + m_fn = r.m_fn; + + TRACE("dl", + for (unsigned i = 0; i < cnt; ++i) { + tout << cols[i] << " "; + } + tout << "\n"; + r.display(tout); + display(tout);); + } + + void mk_rename(const karr_relation & r, unsigned col_cnt, const unsigned * cols) { + if (r.empty()) { + m_empty = true; + return; + } + m_ineqs.reset(); + m_basis.reset(); + m_ineqs_valid = r.m_ineqs_valid; + m_basis_valid = r.m_basis_valid; + if (m_ineqs_valid) { + m_ineqs.append(r.m_ineqs); + mk_rename(m_ineqs, col_cnt, cols); + } + if (m_basis_valid) { + m_basis.append(r.m_basis); + mk_rename(m_basis, col_cnt, cols); + } + m_fn = r.m_fn; + TRACE("dl", r.display(tout); display(tout);); + } + + void mk_union(karr_relation const& src, karr_relation* delta) { + if (src.empty()) { + if (delta) { + delta->m_empty = true; + } + return; + } + matrix const& M = src.get_basis(); + if (empty()) { + m_basis = M; + m_basis_valid = true; + m_empty = false; + m_ineqs_valid = false; + if (delta) { + delta->copy(*this); + } + return; + } + matrix& N = get_basis(); + unsigned N_size = N.size(); + for (unsigned i = 0; i < M.size(); ++i) { + bool found = false; + for (unsigned j = 0; !found && j < N_size; ++j) { + found = + same_row(M.A[i], N.A[j]) && + M.b[i] == N.b[j] && + M.eq[i] == N.eq[j]; + } + if (!found) { + N.A.push_back(M.A[i]); + N.b.push_back(M.b[i]); + N.eq.push_back(M.eq[i]); + } + } + m_ineqs_valid = false; + if (N_size != N.size()) { + if (delta) { + delta->copy(*this); + } + } + } + + matrix const& get_basis() const { + init_basis(); + return m_basis; + } + + matrix& get_basis() { + init_basis(); + return m_basis; + } + + matrix const& get_ineqs() const { + init_ineqs(); + return m_ineqs; + } + + matrix & get_ineqs() { + init_ineqs(); + return m_ineqs; + } + + private: + + void copy(karr_relation const& other) { + m_ineqs = other.m_ineqs; + m_basis = other.m_basis; + m_basis_valid = other.m_basis_valid; + m_ineqs_valid = other.m_ineqs_valid; + m_empty = other.m_empty; + } + + bool same_row(vector const& r1, vector const& r2) const { + SASSERT(r1.size() == r2.size()); + for (unsigned i = 0; i < r1.size(); ++i) { + if (r1[i] != r2[i]) { + return false; + } + } + return true; + } + + void mk_rename(matrix& M, unsigned col_cnt, unsigned const* cols) { + for (unsigned j = 0; j < M.size(); ++j) { + vector & row = M.A[j]; + rational tmp = row[cols[0]]; + for (unsigned i = 0; i + 1 < col_cnt; ++i) { + row[cols[i]] = row[cols[i+1]]; + } + row[cols[col_cnt-1]] = tmp; + } + } + + bool is_eq(expr* e, var*& v, rational& n) { + expr* e1, *e2; + if (!m.is_eq(e, e1, e2)) { + return false; + } + if (!is_var(e1)) { + std::swap(e1, e2); + } + if (!is_var(e1)) { + return false; + } + v = to_var(e1); + if (!a.is_numeral(e2, n)) { + return false; + } + return true; + } + + bool is_linear(expr* e, vector& row, rational& b, rational const& mul) { + if (!a.is_int(e)) { + return false; + } + if (is_var(e)) { + row[to_var(e)->get_idx()] += mul; + return true; + } + if (!is_app(e)) { + return false; + } + rational n; + if (a.is_numeral(e, n)) { + b += mul*n; + return true; + } + if (a.is_add(e)) { + for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { + if (!is_linear(to_app(e)->get_arg(i), row, b, mul)) { + return false; + } + } + return true; + } + expr* e1, *e2; + if (a.is_sub(e, e1, e2)) { + return is_linear(e1, row, b, mul) && is_linear(e2, row, b, -mul); + } + if (a.is_mul(e, e1, e2) && a.is_numeral(e1, n)) { + return is_linear(e2, row, b, mul*n); + } + if (a.is_mul(e, e1, e2) && a.is_numeral(e2, n)) { + return is_linear(e1, row, b, mul*n); + } + if (a.is_uminus(e, e1)) { + return is_linear(e1, row, b, -mul); + } + return false; + } + + void init_ineqs() const { + if (!m_ineqs_valid) { + SASSERT(m_basis_valid); + m_plugin.dualizeH(m_ineqs, m_basis); + m_ineqs_valid = true; + } + } + + void init_basis() const { + if (!m_basis_valid) { + SASSERT(m_ineqs_valid); + if (m_plugin.dualizeI(m_basis, m_ineqs)) { + m_basis_valid = true; + } + else { + m_empty = true; + } + } + } + + void to_formula(vector const& row, rational const& b, bool is_eq, expr_ref_vector& conj) const { + expr_ref_vector sum(m); + expr_ref zero(m), lhs(m); + zero = a.mk_numeral(rational(0), true); + + for (unsigned i = 0; i < row.size(); ++i) { + if (row[i].is_zero()) { + continue; + } + var* var = m.mk_var(i, a.mk_int()); + if (row[i].is_one()) { + sum.push_back(var); + } + else { + sum.push_back(a.mk_mul(a.mk_numeral(row[i], true), var)); + } + } + if (!b.is_zero()) { + sum.push_back(a.mk_numeral(b, true)); + } + lhs = a.mk_add(sum.size(), sum.c_ptr()); + if (is_eq) { + conj.push_back(m.mk_eq(lhs, zero)); + } + else { + conj.push_back(a.mk_ge(lhs, zero)); + } + } + }; + + + karr_relation& karr_relation_plugin::get(relation_base& r) { + return dynamic_cast(r); + } + + karr_relation const & karr_relation_plugin::get(relation_base const& r) { + return dynamic_cast(r); + } + + void karr_relation_plugin::set_cancel(bool f) { + m_hb.set_cancel(f); + } + + relation_base * karr_relation_plugin::mk_empty(const relation_signature & s) { + return alloc(karr_relation, *this, 0, s, true); + } + + relation_base * karr_relation_plugin::mk_full(func_decl* p, const relation_signature & s) { + return alloc(karr_relation, *this, p, s, false); + } + + class karr_relation_plugin::join_fn : public convenient_relation_join_fn { + public: + join_fn(const relation_signature & o1_sig, const relation_signature & o2_sig, unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2) + : convenient_relation_join_fn(o1_sig, o2_sig, col_cnt, cols1, cols2){ + } + + virtual relation_base * operator()(const relation_base & _r1, const relation_base & _r2) { + karr_relation const& r1 = get(_r1); + karr_relation const& r2 = get(_r2); + karr_relation_plugin& p = r1.get_plugin(); + karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_join(r1, r2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); + return result; + } + }; + + relation_join_fn * karr_relation_plugin::mk_join_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (!check_kind(t1) || !check_kind(t2)) { + return 0; + } + return alloc(join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); + } + + + class karr_relation_plugin::project_fn : public convenient_relation_project_fn { + public: + project_fn(const relation_signature & orig_sig, unsigned removed_col_cnt, const unsigned * removed_cols) + : convenient_relation_project_fn(orig_sig, removed_col_cnt, removed_cols) { + } + + virtual relation_base * operator()(const relation_base & _r) { + karr_relation const& r = get(_r); + karr_relation_plugin& p = r.get_plugin(); + karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_project(r, m_removed_cols.size(), m_removed_cols.c_ptr()); + return result; + } + }; + + relation_transformer_fn * karr_relation_plugin::mk_project_fn(const relation_base & r, + unsigned col_cnt, const unsigned * removed_cols) { + return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); + } + + class karr_relation_plugin::rename_fn : public convenient_relation_rename_fn { + public: + rename_fn(karr_relation_plugin& p, const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle) + : convenient_relation_rename_fn(orig_sig, cycle_len, cycle) {} + + virtual relation_base * operator()(const relation_base & _r) { + karr_relation const& r = get(_r); + karr_relation_plugin& p = r.get_plugin(); + karr_relation* result = dynamic_cast(p.mk_full(0, get_result_signature())); + result->mk_rename(r, m_cycle.size(), m_cycle.c_ptr()); + return result; + } + }; + + relation_transformer_fn * karr_relation_plugin::mk_rename_fn(const relation_base & r, + unsigned cycle_len, const unsigned * permutation_cycle) { + if (!check_kind(r)) { + return 0; + } + return alloc(rename_fn, *this, r.get_signature(), cycle_len, permutation_cycle); + } + + bool karr_relation_plugin::dualizeI(matrix& dst, matrix const& src) { + dst.reset(); + m_hb.reset(); + for (unsigned i = 0; i < src.size(); ++i) { + if (src.eq[i]) { + m_hb.add_eq(src.A[i], -src.b[i]); + } + else { + m_hb.add_ge(src.A[i], -src.b[i]); + } + } + for (unsigned i = 0; !src.A.empty() && i < src.A[0].size(); ++i) { + m_hb.set_is_int(i); + } + lbool is_sat = l_undef; + + try { + is_sat = m_hb.saturate(); + } + catch (...) { + is_sat = l_undef; + } + TRACE("dl_verbose", m_hb.display(tout);); + if (is_sat == l_false) { + return false; + } + if (is_sat == l_undef) { + return true; + } + unsigned basis_size = m_hb.get_basis_size(); + bool first_initial = true; + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + m_hb.get_basis_solution(i, soln, is_initial); + if (is_initial && first_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(1)); + dst.eq.push_back(true); + first_initial = false; + } + else if (!is_initial) { + dst.A.push_back(soln); + dst.b.push_back(rational(0)); + dst.eq.push_back(true); + } + } + return true; + } + + void karr_relation_plugin::dualizeH(matrix& dst, matrix const& src) { + dst.reset(); + if (src.size() == 0) { + return; + } + m_hb.reset(); + for (unsigned i = 0; i < src.size(); ++i) { + vector v(src.A[i]); + v.push_back(src.b[i]); + if (src.eq[i]) { + m_hb.add_eq(v, rational(0)); + } + else { + m_hb.add_ge(v, rational(0)); + } + } + for (unsigned i = 0; i < 1 + src.A[0].size(); ++i) { + m_hb.set_is_int(i); + } + lbool is_sat = l_undef; + try { + is_sat = m_hb.saturate(); + } + catch (...) { + is_sat = l_undef; + } + if (is_sat != l_true) { + return; + } + TRACE("dl_verbose", m_hb.display(tout);); + SASSERT(is_sat == l_true); + unsigned basis_size = m_hb.get_basis_size(); + for (unsigned i = 0; i < basis_size; ++i) { + bool is_initial; + vector soln; + m_hb.get_basis_solution(i, soln, is_initial); + if (!is_initial) { + dst.b.push_back(soln.back()); + dst.eq.push_back(true); + soln.pop_back(); + dst.A.push_back(soln); + } + } + } + + + class karr_relation_plugin::union_fn : public relation_union_fn { + public: + union_fn() {} + + virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) { + + karr_relation& r = get(_r); + karr_relation const& src = get(_src); + TRACE("dl", r.display(tout << "dst:\n"); src.display(tout << "src:\n");); + + if (_delta) { + karr_relation& d = get(*_delta); + r.mk_union(src, &d); + } + else { + r.mk_union(src, 0); + } + TRACE("dl", r.display(tout << "result:\n");); + } + }; + + relation_union_fn * karr_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta) { + if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) { + return 0; + } + return alloc(union_fn); + } + + class karr_relation_plugin::filter_identical_fn : public relation_mutator_fn { + unsigned_vector m_identical_cols; + public: + filter_identical_fn(unsigned col_cnt, const unsigned * identical_cols) + : m_identical_cols(col_cnt, identical_cols) {} + + virtual void operator()(relation_base & _r) { + karr_relation & r = get(_r); + TRACE("dl", r.display(tout << "src:\n");); + r.get_ineqs(); + for (unsigned i = 1; i < m_identical_cols.size(); ++i) { + unsigned c1 = m_identical_cols[0]; + unsigned c2 = m_identical_cols[i]; + vector row; + row.resize(r.get_signature().size()); + row[c1] = rational(1); + row[c2] = rational(-1); + r.m_ineqs.A.push_back(row); + r.m_ineqs.b.push_back(rational(0)); + r.m_ineqs.eq.push_back(true); + r.m_basis_valid = false; + } + TRACE("dl", r.display(tout << "result:\n");); + } + }; + + relation_mutator_fn * karr_relation_plugin::mk_filter_identical_fn( + const relation_base & t, unsigned col_cnt, const unsigned * identical_cols) { + if(!check_kind(t)) { + return 0; + } + return alloc(filter_identical_fn, col_cnt, identical_cols); + } + + + class karr_relation_plugin::filter_equal_fn : public relation_mutator_fn { + unsigned m_col; + rational m_value; + bool m_valid; + public: + filter_equal_fn(relation_manager & m, const relation_element & value, unsigned col) + : m_col(col) { + arith_util arith(m.get_context().get_manager()); + m_valid = arith.is_numeral(value, m_value) && m_value.is_int(); + } + + virtual void operator()(relation_base & _r) { + karr_relation & r = get(_r); + if (m_valid) { + r.get_ineqs(); + vector row; + row.resize(r.get_signature().size()); + row[m_col] = rational(1); + r.m_ineqs.A.push_back(row); + r.m_ineqs.b.push_back(rational(-1)); + r.m_ineqs.eq.push_back(true); + r.m_basis_valid = false; + } + TRACE("dl", tout << m_value << "\n"; r.display(tout);); + } + }; + + relation_mutator_fn * karr_relation_plugin::mk_filter_equal_fn(const relation_base & r, + const relation_element & value, unsigned col) { + if (check_kind(r)) { + return alloc(filter_equal_fn, get_manager(), value, col); + } + return 0; + } + + + class karr_relation_plugin::filter_interpreted_fn : public relation_mutator_fn { + app_ref m_cond; + public: + filter_interpreted_fn(karr_relation const& t, app* cond): + m_cond(cond, t.get_plugin().get_ast_manager()) { + } + + void operator()(relation_base& t) { + get(t).filter_interpreted(m_cond); + TRACE("dl", tout << mk_pp(m_cond, m_cond.get_manager()) << "\n"; t.display(tout);); + } + }; + + relation_mutator_fn * karr_relation_plugin::mk_filter_interpreted_fn(const relation_base & t, app * condition) { + if (check_kind(t)) { + return alloc(filter_interpreted_fn, get(t), condition); + } + return 0; + } +}; diff --git a/src/muz/rel/karr_relation.h b/src/muz/rel/karr_relation.h new file mode 100644 index 000000000..00a92748a --- /dev/null +++ b/src/muz/rel/karr_relation.h @@ -0,0 +1,88 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + karr_relation.h + +Abstract: + + Extract integer linear invariants. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-03-08 + +Revision History: + +--*/ +#ifndef _KARR_RELATION_H_ +#define _KARR_RELATION_H_ + +#include"dl_mk_karr_invariants.h" +#include"dl_relation_manager.h" + +namespace datalog { + + class karr_relation; + + class karr_relation_plugin : public relation_plugin { + arith_util a; + hilbert_basis m_hb; + + class join_fn; + class project_fn; + class rename_fn; + class union_fn; + class filter_equal_fn; + class filter_identical_fn; + class filter_interpreted_fn; + friend class karr_relation; + public: + karr_relation_plugin(relation_manager& rm): + relation_plugin(karr_relation_plugin::get_name(), rm), + a(get_ast_manager()) + {} + + virtual bool can_handle_signature(const relation_signature & sig) { + return true; + } + + static symbol get_name() { return symbol("karr_relation"); } + + virtual void set_cancel(bool f); + + virtual relation_base * mk_empty(const relation_signature & s); + + virtual relation_base * mk_full(func_decl* p, const relation_signature & s); + + static karr_relation& get(relation_base& r); + static karr_relation const & get(relation_base const& r); + + virtual relation_join_fn * mk_join_fn( + const relation_base & t1, const relation_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src, + const relation_base * delta); + virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt, + const unsigned * identical_cols); + virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value, + unsigned col); + virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition); + + private: + bool dualizeI(matrix& dst, matrix const& src); + void dualizeH(matrix& dst, matrix const& src); + + + }; + + +}; + +#endif /* _DL_MK_KARR_INVARIANTS_H_ */ + From add96bc98f74a029fae98679b965d5bf7e3580d1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Aug 2013 21:24:34 -0700 Subject: [PATCH 248/281] re-organize muz_qe into separate units Signed-off-by: Nikolaj Bjorner --- src/muz/fp/dl_cmds.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/muz/fp/dl_cmds.h diff --git a/src/muz/fp/dl_cmds.h b/src/muz/fp/dl_cmds.h new file mode 100644 index 000000000..d71b319c4 --- /dev/null +++ b/src/muz/fp/dl_cmds.h @@ -0,0 +1,37 @@ +/*++ +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + dl_cmds.h + +Abstract: + Datalog commands for SMT2 front-end. + +Author: + + Nikolaj Bjorner (nbjorner) 2012-11-17 + +Notes: + +--*/ +#ifndef _DL_CMDS_H_ +#define _DL_CMDS_H_ + +#include "ast.h" + +class cmd_context; + +struct dl_collected_cmds { + expr_ref_vector m_rules; + svector m_names; + expr_ref_vector m_queries; + func_decl_ref_vector m_rels; + dl_collected_cmds(ast_manager& m) : m_rules(m), m_queries(m), m_rels(m) {} +}; + +void install_dl_cmds(cmd_context & ctx); +void install_dl_collect_cmds(dl_collected_cmds& collected_cmds, cmd_context& ctx); + + +#endif From 9e61820125fc16e6d596f379ad5cc8195adcd496 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Aug 2013 21:49:53 -0700 Subject: [PATCH 249/281] re-organizing muz Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- src/muz/bmc/dl_bmc_engine.cpp | 1 + src/muz/dl_context.cpp | 3 +- src/muz/dl_rule.cpp | 1 + src/muz/dl_util.cpp | 3 +- src/muz/dl_util.h | 30 ---------- src/muz/equiv_proof_converter.cpp | 4 +- src/muz/{ => fp}/datalog_parser.cpp | 0 src/muz/{ => fp}/datalog_parser.h | 0 src/muz/pdr/pdr_context.cpp | 5 +- src/muz/pdr/pdr_dl_interface.cpp | 5 +- src/muz/pdr/pdr_util.cpp | 5 +- src/muz/scoped_proof.h | 55 +++++++++++++++++++ src/muz/tab/tab_context.cpp | 1 + src/{muz => qe}/vsubst_tactic.cpp | 0 src/{muz => qe}/vsubst_tactic.h | 0 .../tactic}/unit_subsumption_tactic.cpp | 0 .../tactic}/unit_subsumption_tactic.h | 0 .../arith}/arith_bounds_tactic.cpp | 0 .../arith}/arith_bounds_tactic.h | 0 20 files changed, 73 insertions(+), 42 deletions(-) rename src/muz/{ => fp}/datalog_parser.cpp (100%) rename src/muz/{ => fp}/datalog_parser.h (100%) create mode 100644 src/muz/scoped_proof.h rename src/{muz => qe}/vsubst_tactic.cpp (100%) rename src/{muz => qe}/vsubst_tactic.h (100%) rename src/{muz => smt/tactic}/unit_subsumption_tactic.cpp (100%) rename src/{muz => smt/tactic}/unit_subsumption_tactic.h (100%) rename src/{muz => tactic/arith}/arith_bounds_tactic.cpp (100%) rename src/{muz => tactic/arith}/arith_bounds_tactic.h (100%) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index a2b4ef9b2..248d45382 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -57,7 +57,7 @@ def init_project_def(): add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe']) add_lib('transforms', ['muz'], 'muz/transforms') add_lib('rel', ['muz', 'transforms'], 'muz/rel') - add_lib('pdr', ['muz', 'transforms'], 'muz/pdr') + add_lib('pdr', ['muz', 'transforms', 'arith_tactics', 'smt_tactic'], 'muz/pdr') add_lib('clp', ['muz', 'transforms'], 'muz/clp') add_lib('tab', ['muz', 'transforms'], 'muz/tab') add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 72e40590e..60d285a55 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -31,6 +31,7 @@ Revision History: #include "rewriter_def.h" #include "dl_transforms.h" #include "dl_mk_rule_inliner.h" +#include "scoped_proof.h" namespace datalog { diff --git a/src/muz/dl_context.cpp b/src/muz/dl_context.cpp index 5e707e315..11cb48490 100644 --- a/src/muz/dl_context.cpp +++ b/src/muz/dl_context.cpp @@ -19,8 +19,6 @@ Revision History: #include #include -#include"arith_simplifier_plugin.h" -#include"basic_simplifier_plugin.h" #include"arith_decl_plugin.h" #include"bv_decl_plugin.h" #include"dl_context.h" @@ -28,6 +26,7 @@ Revision History: #include"ast_smt_pp.h" #include"ast_smt2_pp.h" #include"datatype_decl_plugin.h" +#include"scoped_proof.h" namespace datalog { diff --git a/src/muz/dl_rule.cpp b/src/muz/dl_rule.cpp index 5ac580cb8..96e2b163a 100644 --- a/src/muz/dl_rule.cpp +++ b/src/muz/dl_rule.cpp @@ -42,6 +42,7 @@ Revision History: #include"bool_rewriter.h" #include"expr_safe_replace.h" #include"filter_model_converter.h" +#include"scoped_proof.h" namespace datalog { diff --git a/src/muz/dl_util.cpp b/src/muz/dl_util.cpp index e32999ddc..2f9eb519c 100644 --- a/src/muz/dl_util.cpp +++ b/src/muz/dl_util.cpp @@ -25,9 +25,10 @@ Revision History: #endif #include"ast_pp.h" #include"bool_rewriter.h" +#include"for_each_expr.h" +#include"scoped_proof.h" #include"dl_context.h" #include"dl_rule.h" -#include"for_each_expr.h" #include"dl_util.h" namespace datalog { diff --git a/src/muz/dl_util.h b/src/muz/dl_util.h index d805e683b..a6bd7f7f8 100644 --- a/src/muz/dl_util.h +++ b/src/muz/dl_util.h @@ -124,36 +124,6 @@ namespace datalog { */ void display_fact(context & ctx, app * f, std::ostream & out); - class scoped_proof_mode { - ast_manager& m; - proof_gen_mode m_mode; - public: - scoped_proof_mode(ast_manager& m, proof_gen_mode mode): m(m) { - m_mode = m.proof_mode(); - m.toggle_proof_mode(mode); - } - ~scoped_proof_mode() { - m.toggle_proof_mode(m_mode); - } - - }; - - class scoped_proof : public scoped_proof_mode { - public: - scoped_proof(ast_manager& m): scoped_proof_mode(m, PGM_FINE) {} - }; - - class scoped_no_proof : public scoped_proof_mode { - public: - scoped_no_proof(ast_manager& m): scoped_proof_mode(m, PGM_DISABLED) {} - }; - - class scoped_restore_proof : public scoped_proof_mode { - public: - scoped_restore_proof(ast_manager& m): scoped_proof_mode(m, m.proof_mode()) {} - }; - - class variable_intersection diff --git a/src/muz/equiv_proof_converter.cpp b/src/muz/equiv_proof_converter.cpp index 98ea88044..13b759f7e 100644 --- a/src/muz/equiv_proof_converter.cpp +++ b/src/muz/equiv_proof_converter.cpp @@ -19,11 +19,11 @@ Revision History: #include "equiv_proof_converter.h" #include "ast_pp.h" -#include "dl_util.h" +#include "scoped_proof.h" void equiv_proof_converter::insert(expr* fml1, expr* fml2) { if (fml1 != fml2) { - datalog::scoped_proof _sp(m); + scoped_proof _sp(m); proof_ref p1(m), p2(m), p3(m); p1 = m.mk_asserted(fml1); p2 = m.mk_rewrite(fml1, fml2); diff --git a/src/muz/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp similarity index 100% rename from src/muz/datalog_parser.cpp rename to src/muz/fp/datalog_parser.cpp diff --git a/src/muz/datalog_parser.h b/src/muz/fp/datalog_parser.h similarity index 100% rename from src/muz/datalog_parser.h rename to src/muz/fp/datalog_parser.h diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index db85bc5a9..f3e253071 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -46,6 +46,7 @@ Notes: #include "proof_utils.h" #include "dl_boogie_proof.h" #include "qe_util.h" +#include "scoped_proof.h" namespace pdr { @@ -1719,7 +1720,7 @@ namespace pdr { } proof_ref context::get_proof() const { - datalog::scoped_proof _sc(m); + scoped_proof _sc(m); proof_ref proof(m); SASSERT(m_last_result == l_true); proof = m_search.get_proof_trace(*this); @@ -1959,7 +1960,7 @@ namespace pdr { void context::create_children(model_node& n) { SASSERT(n.level() > 0); bool use_model_generalizer = m_params.use_model_generalizer(); - datalog::scoped_no_proof _sc(m); + scoped_no_proof _sc(m); pred_transformer& pt = n.pt(); model_ref M = n.get_model_ptr(); diff --git a/src/muz/pdr/pdr_dl_interface.cpp b/src/muz/pdr/pdr_dl_interface.cpp index ccd22d57f..45872fe99 100644 --- a/src/muz/pdr/pdr_dl_interface.cpp +++ b/src/muz/pdr/pdr_dl_interface.cpp @@ -31,8 +31,9 @@ Revision History: #include "dl_mk_slice.h" #include "dl_mk_unfold.h" #include "dl_mk_coalesce.h" -#include "model_smt2_pp.h" #include "dl_transforms.h" +#include "scoped_proof.h" +#include "model_smt2_pp.h" using namespace pdr; @@ -149,7 +150,7 @@ lbool dl_interface::query(expr * query) { m_ctx.reopen(); m_ctx.replace_rules(old_rules); - datalog::scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode. + scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode. m_context->set_proof_converter(m_ctx.get_proof_converter()); m_context->set_model_converter(m_ctx.get_model_converter()); diff --git a/src/muz/pdr/pdr_util.cpp b/src/muz/pdr/pdr_util.cpp index d23dc186e..4db835bed 100644 --- a/src/muz/pdr/pdr_util.cpp +++ b/src/muz/pdr/pdr_util.cpp @@ -45,6 +45,7 @@ Notes: #include "poly_rewriter.h" #include "poly_rewriter_def.h" #include "arith_rewriter.h" +#include "scoped_proof.h" @@ -1072,7 +1073,7 @@ namespace pdr { void hoist_non_bool_if(expr_ref& fml) { ast_manager& m = fml.get_manager(); - datalog::scoped_no_proof _sp(m); + scoped_no_proof _sp(m); params_ref p; ite_hoister_star ite_rw(m, p); expr_ref tmp(m); @@ -1419,7 +1420,7 @@ namespace pdr { void normalize_arithmetic(expr_ref& t) { ast_manager& m = t.get_manager(); - datalog::scoped_no_proof _sp(m); + scoped_no_proof _sp(m); params_ref p; arith_normalizer_star rw(m, p); expr_ref tmp(m); diff --git a/src/muz/scoped_proof.h b/src/muz/scoped_proof.h new file mode 100644 index 000000000..e37290c03 --- /dev/null +++ b/src/muz/scoped_proof.h @@ -0,0 +1,55 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + scoped_proof.h + +Abstract: + + Scoped proof environments. Toggles enabling proofs. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-08-28 + +Revision History: + +--*/ +#ifndef _SCOPED_PROOF__H_ +#define _SCOPED_PROOF_H_ + +#include "ast.h" + +class scoped_proof_mode { + ast_manager& m; + proof_gen_mode m_mode; +public: + scoped_proof_mode(ast_manager& m, proof_gen_mode mode): m(m) { + m_mode = m.proof_mode(); + m.toggle_proof_mode(mode); + } + ~scoped_proof_mode() { + m.toggle_proof_mode(m_mode); + } + +}; + +class scoped_proof : public scoped_proof_mode { +public: + scoped_proof(ast_manager& m): scoped_proof_mode(m, PGM_FINE) {} +}; + +class scoped_no_proof : public scoped_proof_mode { +public: + scoped_no_proof(ast_manager& m): scoped_proof_mode(m, PGM_DISABLED) {} +}; + +class scoped_restore_proof : public scoped_proof_mode { +public: + scoped_restore_proof(ast_manager& m): scoped_proof_mode(m, m.proof_mode()) {} +}; + + + +#endif diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index a56d16a0e..2201be73e 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -29,6 +29,7 @@ Revision History: #include "datatype_decl_plugin.h" #include "for_each_expr.h" #include "matcher.h" +#include "scoped_proof.h" namespace tb { diff --git a/src/muz/vsubst_tactic.cpp b/src/qe/vsubst_tactic.cpp similarity index 100% rename from src/muz/vsubst_tactic.cpp rename to src/qe/vsubst_tactic.cpp diff --git a/src/muz/vsubst_tactic.h b/src/qe/vsubst_tactic.h similarity index 100% rename from src/muz/vsubst_tactic.h rename to src/qe/vsubst_tactic.h diff --git a/src/muz/unit_subsumption_tactic.cpp b/src/smt/tactic/unit_subsumption_tactic.cpp similarity index 100% rename from src/muz/unit_subsumption_tactic.cpp rename to src/smt/tactic/unit_subsumption_tactic.cpp diff --git a/src/muz/unit_subsumption_tactic.h b/src/smt/tactic/unit_subsumption_tactic.h similarity index 100% rename from src/muz/unit_subsumption_tactic.h rename to src/smt/tactic/unit_subsumption_tactic.h diff --git a/src/muz/arith_bounds_tactic.cpp b/src/tactic/arith/arith_bounds_tactic.cpp similarity index 100% rename from src/muz/arith_bounds_tactic.cpp rename to src/tactic/arith/arith_bounds_tactic.cpp diff --git a/src/muz/arith_bounds_tactic.h b/src/tactic/arith/arith_bounds_tactic.h similarity index 100% rename from src/muz/arith_bounds_tactic.h rename to src/tactic/arith/arith_bounds_tactic.h From e4338f085b348365ef68a9949ccb10c8e256a4a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Aug 2013 22:11:33 -0700 Subject: [PATCH 250/281] re-organization of muz Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 7 +- src/{muz => ast}/scoped_proof.h | 0 src/{muz => math/hilbert}/heap_trie.h | 0 src/{muz => math/hilbert}/hilbert_basis.cpp | 0 src/{muz => math/hilbert}/hilbert_basis.h | 0 src/{muz => model}/model2expr.cpp | 0 src/{muz => model}/model2expr.h | 0 src/muz/README | 3 +- src/muz/{ => base}/dl_boogie_proof.cpp | 0 src/muz/{ => base}/dl_boogie_proof.h | 0 src/muz/{ => base}/dl_context.cpp | 0 src/muz/{ => base}/dl_context.h | 0 src/muz/{ => base}/dl_costs.cpp | 0 src/muz/{ => base}/dl_costs.h | 0 src/muz/{ => base}/dl_engine_base.h | 0 src/muz/{ => base}/dl_rule.cpp | 0 src/muz/{ => base}/dl_rule.h | 0 src/muz/{ => base}/dl_rule_set.cpp | 0 src/muz/{ => base}/dl_rule_set.h | 0 .../{ => base}/dl_rule_subsumption_index.cpp | 0 .../{ => base}/dl_rule_subsumption_index.h | 0 src/muz/{ => base}/dl_rule_transformer.cpp | 0 src/muz/{ => base}/dl_rule_transformer.h | 0 src/muz/{ => base}/dl_util.cpp | 0 src/muz/{ => base}/dl_util.h | 0 src/muz/{ => base}/fixedpoint_params.pyg | 0 src/muz/{ => base}/hnf.cpp | 0 src/muz/{ => base}/hnf.h | 0 src/muz/{ => base}/proof_utils.cpp | 0 src/muz/{ => base}/proof_utils.h | 0 src/muz/skip_list_base.h | 871 ------------------ src/{muz => tactic}/equiv_proof_converter.cpp | 0 src/{muz => tactic}/equiv_proof_converter.h | 0 .../horn_subsume_model_converter.cpp | 0 .../horn_subsume_model_converter.h | 0 .../replace_proof_converter.cpp | 0 src/{muz => tactic}/replace_proof_converter.h | 0 37 files changed, 6 insertions(+), 875 deletions(-) rename src/{muz => ast}/scoped_proof.h (100%) rename src/{muz => math/hilbert}/heap_trie.h (100%) rename src/{muz => math/hilbert}/hilbert_basis.cpp (100%) rename src/{muz => math/hilbert}/hilbert_basis.h (100%) rename src/{muz => model}/model2expr.cpp (100%) rename src/{muz => model}/model2expr.h (100%) rename src/muz/{ => base}/dl_boogie_proof.cpp (100%) rename src/muz/{ => base}/dl_boogie_proof.h (100%) rename src/muz/{ => base}/dl_context.cpp (100%) rename src/muz/{ => base}/dl_context.h (100%) rename src/muz/{ => base}/dl_costs.cpp (100%) rename src/muz/{ => base}/dl_costs.h (100%) rename src/muz/{ => base}/dl_engine_base.h (100%) rename src/muz/{ => base}/dl_rule.cpp (100%) rename src/muz/{ => base}/dl_rule.h (100%) rename src/muz/{ => base}/dl_rule_set.cpp (100%) rename src/muz/{ => base}/dl_rule_set.h (100%) rename src/muz/{ => base}/dl_rule_subsumption_index.cpp (100%) rename src/muz/{ => base}/dl_rule_subsumption_index.h (100%) rename src/muz/{ => base}/dl_rule_transformer.cpp (100%) rename src/muz/{ => base}/dl_rule_transformer.h (100%) rename src/muz/{ => base}/dl_util.cpp (100%) rename src/muz/{ => base}/dl_util.h (100%) rename src/muz/{ => base}/fixedpoint_params.pyg (100%) rename src/muz/{ => base}/hnf.cpp (100%) rename src/muz/{ => base}/hnf.h (100%) rename src/muz/{ => base}/proof_utils.cpp (100%) rename src/muz/{ => base}/proof_utils.h (100%) delete mode 100644 src/muz/skip_list_base.h rename src/{muz => tactic}/equiv_proof_converter.cpp (100%) rename src/{muz => tactic}/equiv_proof_converter.h (100%) rename src/{muz => tactic}/horn_subsume_model_converter.cpp (100%) rename src/{muz => tactic}/horn_subsume_model_converter.h (100%) rename src/{muz => tactic}/replace_proof_converter.cpp (100%) rename src/{muz => tactic}/replace_proof_converter.h (100%) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 248d45382..4fec0a9e7 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -14,6 +14,7 @@ def init_project_def(): add_lib('polynomial', ['util'], 'math/polynomial') add_lib('sat', ['util']) add_lib('nlsat', ['polynomial', 'sat']) + add_lib('hilbert', ['util'], 'math/hilbert') add_lib('interval', ['util'], 'math/interval') add_lib('realclosure', ['interval'], 'math/realclosure') add_lib('subpaving', ['interval'], 'math/subpaving') @@ -54,8 +55,8 @@ def init_project_def(): add_lib('smt_tactic', ['smt'], 'smt/tactic') add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls') add_lib('qe', ['smt','sat'], 'qe') - add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe']) - add_lib('transforms', ['muz'], 'muz/transforms') + add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe'], 'muz/base') + add_lib('transforms', ['muz', 'hilbert'], 'muz/transforms') add_lib('rel', ['muz', 'transforms'], 'muz/rel') add_lib('pdr', ['muz', 'transforms', 'arith_tactics', 'smt_tactic'], 'muz/pdr') add_lib('clp', ['muz', 'transforms'], 'muz/clp') @@ -64,7 +65,7 @@ def init_project_def(): add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc'], 'muz/fp') add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') - add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'fp', 'muz', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') + add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('smtparser', ['portfolio'], 'parsers/smt') API_files = ['z3_api.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h'] add_lib('api', ['portfolio', 'user_plugin', 'smtparser', 'realclosure'], diff --git a/src/muz/scoped_proof.h b/src/ast/scoped_proof.h similarity index 100% rename from src/muz/scoped_proof.h rename to src/ast/scoped_proof.h diff --git a/src/muz/heap_trie.h b/src/math/hilbert/heap_trie.h similarity index 100% rename from src/muz/heap_trie.h rename to src/math/hilbert/heap_trie.h diff --git a/src/muz/hilbert_basis.cpp b/src/math/hilbert/hilbert_basis.cpp similarity index 100% rename from src/muz/hilbert_basis.cpp rename to src/math/hilbert/hilbert_basis.cpp diff --git a/src/muz/hilbert_basis.h b/src/math/hilbert/hilbert_basis.h similarity index 100% rename from src/muz/hilbert_basis.h rename to src/math/hilbert/hilbert_basis.h diff --git a/src/muz/model2expr.cpp b/src/model/model2expr.cpp similarity index 100% rename from src/muz/model2expr.cpp rename to src/model/model2expr.cpp diff --git a/src/muz/model2expr.h b/src/model/model2expr.h similarity index 100% rename from src/muz/model2expr.h rename to src/model/model2expr.h diff --git a/src/muz/README b/src/muz/README index 5d6f433b8..03cd12bc7 100644 --- a/src/muz/README +++ b/src/muz/README @@ -1 +1,2 @@ -muZ and Quantifier Elimination modules \ No newline at end of file +muZ: routines related to solving satisfiability of Horn clauses and +solving Datalog programs. diff --git a/src/muz/dl_boogie_proof.cpp b/src/muz/base/dl_boogie_proof.cpp similarity index 100% rename from src/muz/dl_boogie_proof.cpp rename to src/muz/base/dl_boogie_proof.cpp diff --git a/src/muz/dl_boogie_proof.h b/src/muz/base/dl_boogie_proof.h similarity index 100% rename from src/muz/dl_boogie_proof.h rename to src/muz/base/dl_boogie_proof.h diff --git a/src/muz/dl_context.cpp b/src/muz/base/dl_context.cpp similarity index 100% rename from src/muz/dl_context.cpp rename to src/muz/base/dl_context.cpp diff --git a/src/muz/dl_context.h b/src/muz/base/dl_context.h similarity index 100% rename from src/muz/dl_context.h rename to src/muz/base/dl_context.h diff --git a/src/muz/dl_costs.cpp b/src/muz/base/dl_costs.cpp similarity index 100% rename from src/muz/dl_costs.cpp rename to src/muz/base/dl_costs.cpp diff --git a/src/muz/dl_costs.h b/src/muz/base/dl_costs.h similarity index 100% rename from src/muz/dl_costs.h rename to src/muz/base/dl_costs.h diff --git a/src/muz/dl_engine_base.h b/src/muz/base/dl_engine_base.h similarity index 100% rename from src/muz/dl_engine_base.h rename to src/muz/base/dl_engine_base.h diff --git a/src/muz/dl_rule.cpp b/src/muz/base/dl_rule.cpp similarity index 100% rename from src/muz/dl_rule.cpp rename to src/muz/base/dl_rule.cpp diff --git a/src/muz/dl_rule.h b/src/muz/base/dl_rule.h similarity index 100% rename from src/muz/dl_rule.h rename to src/muz/base/dl_rule.h diff --git a/src/muz/dl_rule_set.cpp b/src/muz/base/dl_rule_set.cpp similarity index 100% rename from src/muz/dl_rule_set.cpp rename to src/muz/base/dl_rule_set.cpp diff --git a/src/muz/dl_rule_set.h b/src/muz/base/dl_rule_set.h similarity index 100% rename from src/muz/dl_rule_set.h rename to src/muz/base/dl_rule_set.h diff --git a/src/muz/dl_rule_subsumption_index.cpp b/src/muz/base/dl_rule_subsumption_index.cpp similarity index 100% rename from src/muz/dl_rule_subsumption_index.cpp rename to src/muz/base/dl_rule_subsumption_index.cpp diff --git a/src/muz/dl_rule_subsumption_index.h b/src/muz/base/dl_rule_subsumption_index.h similarity index 100% rename from src/muz/dl_rule_subsumption_index.h rename to src/muz/base/dl_rule_subsumption_index.h diff --git a/src/muz/dl_rule_transformer.cpp b/src/muz/base/dl_rule_transformer.cpp similarity index 100% rename from src/muz/dl_rule_transformer.cpp rename to src/muz/base/dl_rule_transformer.cpp diff --git a/src/muz/dl_rule_transformer.h b/src/muz/base/dl_rule_transformer.h similarity index 100% rename from src/muz/dl_rule_transformer.h rename to src/muz/base/dl_rule_transformer.h diff --git a/src/muz/dl_util.cpp b/src/muz/base/dl_util.cpp similarity index 100% rename from src/muz/dl_util.cpp rename to src/muz/base/dl_util.cpp diff --git a/src/muz/dl_util.h b/src/muz/base/dl_util.h similarity index 100% rename from src/muz/dl_util.h rename to src/muz/base/dl_util.h diff --git a/src/muz/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg similarity index 100% rename from src/muz/fixedpoint_params.pyg rename to src/muz/base/fixedpoint_params.pyg diff --git a/src/muz/hnf.cpp b/src/muz/base/hnf.cpp similarity index 100% rename from src/muz/hnf.cpp rename to src/muz/base/hnf.cpp diff --git a/src/muz/hnf.h b/src/muz/base/hnf.h similarity index 100% rename from src/muz/hnf.h rename to src/muz/base/hnf.h diff --git a/src/muz/proof_utils.cpp b/src/muz/base/proof_utils.cpp similarity index 100% rename from src/muz/proof_utils.cpp rename to src/muz/base/proof_utils.cpp diff --git a/src/muz/proof_utils.h b/src/muz/base/proof_utils.h similarity index 100% rename from src/muz/proof_utils.h rename to src/muz/base/proof_utils.h diff --git a/src/muz/skip_list_base.h b/src/muz/skip_list_base.h deleted file mode 100644 index feaa00763..000000000 --- a/src/muz/skip_list_base.h +++ /dev/null @@ -1,871 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - skip_list_base.h - -Abstract: - - - -Author: - - Leonardo de Moura (leonardo) 2010-10-01. - -Revision History: - - WARNING: IT IS NOT SAFE TO STORE KEYS, VALUES in the SKIP_LIST that need non-default constructors/destructors. - ---*/ -#ifndef _SKIP_LIST_BASE_H_ -#define _SKIP_LIST_BASE_H_ - -#include -#include"util.h" -#include"memory_manager.h" -#include"small_object_allocator.h" -#include"trace.h" - -#ifdef _MSC_VER -#pragma warning(disable : 4200) -#endif - -/* - This file defines a base class for implementing skip-list like data-structures. - This base class is relies on a manager for providing some basic services. - The manager is a template parameter. - - A Skip-list manager is responsible for: - - - Providing primitives for allocating/deallocating memory - void * allocate(size_t size); - void deallocate(size_t size, void* p); - - Generating random skip-list levels efficiently - unsigned random_level(unsigned max_level); - - Call-backs that will be invoked when a reference for a "value" stored in the skip-list is incremented/decremented. - void inc_ref_eh(value const & v); - void dec_ref_eh(value const & h); -*/ - -/** - \brief Base class for generating random_levels. -*/ -class random_level_manager { -#define SL_BITS_IN_RANDOM 16 - unsigned m_random_data; - unsigned m_random_bits:16; - unsigned m_random_left:16; - - unsigned random_value() { - return ((m_random_data = m_random_data * 214013L + 2531011L) >> 16) & 0xffff; - } - - void init_random() { - m_random_data = 0; - m_random_bits = random_value(); - m_random_left = SL_BITS_IN_RANDOM/2; - } -public: - random_level_manager() { - init_random(); - } - - unsigned random_level(unsigned max_level) { - unsigned level = 1; - unsigned b; - do { - b = m_random_bits&3; - if (!b) - level++; - m_random_bits >>= 2; - m_random_left--; - if (m_random_left == 0) { - m_random_bits = random_value(); - m_random_left = SL_BITS_IN_RANDOM/2; - } - } while (!b); - return (level > max_level ? max_level : level); - } - -}; - -/** - \brief Basic skip-list manager. - The class is parametrized by the Value type that is stored in the skip-list. -*/ -template -class sl_manager_base : public random_level_manager { - typedef Value value; - - small_object_allocator m_alloc; - -public: - void * allocate(size_t size) { - return m_alloc.allocate(size); - } - - void deallocate(size_t size, void* p) { - m_alloc.deallocate(size, p); - } - - void inc_ref_eh(value const & v) { - /* do nothing */ - } - - void dec_ref_eh(value const & h) { - /* do nothing */ - } -}; - -#define SL_SIZE_NUM_BITS 12 -#define SL_CAPACITY_NUM_BITS SL_SIZE_NUM_BITS -#define SL_MAX_CAPACITY ((1 << SL_SIZE_NUM_BITS) - 1) -#define SL_LEVEL_NUM_BITS 8 -#define SL_MAX_LEVEL ((1 << SL_LEVEL_NUM_BITS) - 1) -COMPILE_TIME_ASSERT(SL_SIZE_NUM_BITS == SL_CAPACITY_NUM_BITS); -COMPILE_TIME_ASSERT(SL_SIZE_NUM_BITS + SL_CAPACITY_NUM_BITS + SL_LEVEL_NUM_BITS == 32); - -/** - \brief Base (template) class for implementing skip-list like data-structures where - entries are stored in buckets to improve cache behavior. - - The Traits template parameter must provide: - - - a definition for the class Traits::manager - - a definition for the class Traits::entry which provides: - - a definition for the types key and value - - the methods: - key const & begin_key() const - key const & end_key() const - value const & val() const - void set_begin_key(key const & k) - void set_end_key(key const & k) - void set_val(value const & v) - void display(ostream & out) const - - the maximal number of levels Traits::max_level - - the maximal capacity of each bucket Traits::max_capacity - - the initial capacity of the first bucket Traits::initial_capacity - - flag for reference counting support Traits::ref_count. If this flag is true - the methods inc_ref_eh and dec_ref_eh in the manager object will be invoked. - - the methods - bool lt(key const & k1, key const & k2) - bool eq(key const & k1, key const & k2) - bool val_eq(value const & v1, value const & v2) - key succ(key const & k) - key pred(key const & k) -*/ -template -class skip_list_base : protected Traits { -protected: - typedef typename Traits::entry entry; -public: - typedef typename Traits::manager manager; - typedef typename entry::key key; - typedef typename entry::value value; - - struct bucket { - unsigned m_size:SL_SIZE_NUM_BITS; //!< number of entries stored in the bucket. - unsigned m_capacity:SL_CAPACITY_NUM_BITS; //!< capacity (number of entries) that can be stored in the bucket. - unsigned m_level:SL_LEVEL_NUM_BITS; - char m_extra[0]; - - static unsigned get_obj_size(unsigned num_lvls, unsigned capacity) { - return sizeof(bucket) + num_lvls*sizeof(bucket*) + capacity*sizeof(entry); - } - - entry * get_entries() { return reinterpret_cast(m_extra); } - entry const * get_entries() const { return reinterpret_cast(m_extra); } - - bucket ** next_vect() { return reinterpret_cast(get_entries() + m_capacity); } - bucket * const * next_vect() const { return reinterpret_cast(get_entries() + m_capacity); } - - bucket(unsigned lvl, unsigned capacity = Traits::max_capacity): - m_size(0), - m_capacity(capacity), - m_level(lvl) { - memset(next_vect(), 0, sizeof(bucket*)*lvl); - } - - unsigned level() const { return m_level; } - unsigned size() const { return m_size; } - unsigned capacity() const { return m_capacity; } - bool empty() const { return size() == 0; } - void set_size(unsigned sz) { m_size = sz; } - void shrink(unsigned delta) { m_size -= delta; } - void expand(unsigned delta) { m_size += delta; } - entry & first_entry() { SASSERT(!empty()); return get_entries()[0]; } - entry & last_entry() { SASSERT(!empty()); return get_entries()[size() - 1]; } - entry const & first_entry() const { SASSERT(!empty()); return get_entries()[0]; } - entry const & last_entry() const { SASSERT(!empty()); return get_entries()[size() - 1]; } - entry const & get(unsigned idx) const { SASSERT(idx < size()); return get_entries()[idx]; } - entry & get(unsigned idx) { SASSERT(idx < size()); return get_entries()[idx]; } - void set(unsigned idx, entry const & e) { SASSERT(idx < capacity()); get_entries()[idx] = e; } - bucket * get_next(unsigned idx) const { return next_vect()[idx]; } - void set_next(unsigned idx, bucket * bt) { SASSERT(idx < level()); next_vect()[idx] = bt; } - }; - - // Only the header bucket has zero entries. - bucket * m_header; - - bucket * first_bucket() const { - return m_header->get_next(0); - } - -#ifdef Z3DEBUG - /** - \brief (debugging only) Return the predecessor bucket of the given bucket. - - \pre bt != m_header, and bt is a bucket of the list. - */ - bucket * pred_bucket(bucket * bt) const { - SASSERT(bt != m_header); - bucket * curr = m_header; - while (curr->get_next(0) != bt) { - curr = curr->get_next(0); - SASSERT(curr != 0); // bt is not in the list - } - return curr; - } -#endif - - bool lt(key const & k1, key const & k2) const { return Traits::lt(k1, k2); } - - bool gt(key const & k1, key const & k2) const { return lt(k2, k1); } - - bool geq(key const & k1, key const & k2) const { return !lt(k1, k2); } - - bool leq(key const & k1, key const & k2) const { return !gt(k1, k2); } - - /** - \brief Create a new bucket of the given level. - */ - static bucket * mk_bucket(manager & m, unsigned lvl, unsigned capacity = Traits::max_capacity) { - void * mem = m.allocate(bucket::get_obj_size(lvl, capacity)); - return new (mem) bucket(lvl, capacity); - } - - static bucket * mk_header(manager & m, unsigned lvl) { - return mk_bucket(m, lvl, 0); - } - - static void inc_ref(manager & m, value const & v) { - if (Traits::ref_count) - m.inc_ref_eh(v); - } - - static void dec_ref(manager & m, value const & v) { - if (Traits::ref_count) - m.dec_ref_eh(v); - } - - /** - \brief Invoke dec_ref_eh for each value stored in the bucket. - */ - static void dec_ref(manager & m, bucket * bt) { - if (Traits::ref_count) { - unsigned sz = bt->size(); - for (unsigned i = 0; i < sz; i++) - m.dec_ref_eh(bt->get(i).val()); - } - } - - /** - \brief Deallocate the given bucket. - - \remark This method invokes dec_ref_eh for each value in the bucket. - */ - template - static void deallocate_bucket(manager & m, bucket * bt) { - if (DecRef) - dec_ref(m, bt); - unsigned sz = bucket::get_obj_size(bt->level(), bt->capacity()); - bt->~bucket(); - m.deallocate(sz, bt); - } - - /** - \brief Deallocate all buckets in the skip list. - - \remark This method invokes dec_ref_eh for each value in the list. - */ - template - void deallocate_list(manager & m) { - bucket * curr = m_header; - while (curr != 0) { - bucket * old = curr; - curr = curr->get_next(0); - deallocate_bucket(m, old); - } - } - -#ifdef Z3DEBUG - /** - \brief Check the following property - - for all i \in [0, b->level()) . pred_vect[i]->get_next(i) == b - */ - bool check_pred_vect(bucket * bt, bucket * pred_vect[]) { - if (bt == 0) - return true; - for (unsigned i = 0; i < bt->level(); i++) { - SASSERT(pred_vect[i]->get_next(i) == bt); - } - return true; - } -#endif - - /** - \brief Delete the given buffer and update the forward/next pointer of the buckets in pred_vect. - - \remark This method invokes dec_ref_eh for each value in the bucket. - */ - void del_bucket(manager & m, bucket * bt, bucket * pred_vect[]) { - SASSERT(check_pred_vect(bt, pred_vect)); - for (unsigned i = 0; i < bt->level(); i++) - pred_vect[i]->set_next(i, bt->get_next(i)); - deallocate_bucket(m, bt); - } - - /** - \brief Update the \c pred_vect vector from levels [0, bt->level()). - That is, bt will be now the "predecessor" for these levels. - */ - static void update_predecessor_vector(bucket * pred_vect [], bucket * bt) { - unsigned lvl = bt->level(); - for (unsigned i = 0; i < lvl; i++) { - pred_vect[i] = bt; - } - } - - /** - \brief Similar to the previous method, but the updated vector is stored in new_pred_vect. - */ - void update_predecessor_vector(bucket * pred_vect[], bucket * bt, bucket * new_pred_vect[]) { - unsigned bt_lvl = bt->level(); - for (unsigned i = 0; i < bt_lvl; i++) { - new_pred_vect[i] = bt; - } - unsigned list_lvl = level(); - for (unsigned i = bt_lvl; i < list_lvl; i++) { - new_pred_vect[i] = pred_vect[i]; - } - } - - /** - \brief Return the list level. - */ - unsigned level() const { - return m_header->level(); - } - - /** - \brief Expand/Increase the number of levels in the header. - */ - void expand_header(manager & m, unsigned new_lvl) { - SASSERT(new_lvl > level()); - bucket * new_header = mk_header(m, new_lvl); - // copy forward pointers of the old header. - unsigned old_lvl = level(); - for (unsigned i = 0; i < old_lvl; i++) - new_header->set_next(i, m_header->get_next(i)); - // update header - deallocate_bucket(m, m_header); - m_header = new_header; - } - - /** - \brief Increase list level to lvl if lvl > level() - */ - void update_list_level(manager & m, unsigned lvl) { - if (lvl > level()) { - expand_header(m, lvl); - } - } - - /** - \brief Increase list level (and store m_header in the new levels in pred_vect) if lvl > level(). - */ - void update_list_level(manager & m, unsigned lvl, bucket * pred_vect[]) { - if (lvl > level()) { - bucket * old_header = m_header; - unsigned old_lvl = m_header->level(); - expand_header(m, lvl); - for (unsigned i = 0; i < old_lvl; i++) { - if (pred_vect[i] == old_header) - pred_vect[i] = m_header; - } - for (unsigned i = old_lvl; i < lvl; i++) { - pred_vect[i] = m_header; - } - SASSERT(level() == lvl); - } - } - - /** - \brief Add first entry to the list. - - \remark This method will invoke inc_ref_eh for e.val() - */ - void insert_first_entry(manager & m, entry const & e) { - unsigned lvl = m.random_level(Traits::max_level); - bucket * new_bucket = mk_bucket(m, lvl, Traits::initial_capacity); - update_list_level(m, lvl); - for (unsigned i = 0; i < lvl; i++) { - m_header->set_next(i, new_bucket); - } - inc_ref(m, e.val()); - new_bucket->set_size(1); - new_bucket->set(0, e); - } - - /** - \brief Expand the capacity of the first-bucket in a skip-list with only one bucket. - This method assumes the capacity of the first-bucket < Traits::max_capacity - */ - void expand_first_bucket(manager & m) { - bucket * f = first_bucket(); - SASSERT(f != 0); - SASSERT(f->get_next(0) == 0); - SASSERT(f->capacity() < Traits::max_capacity); - unsigned old_capacity = f->capacity(); - SASSERT(old_capacity > 0); - unsigned new_capacity = old_capacity * 2; - if (new_capacity > Traits::max_capacity) - new_capacity = Traits::max_capacity; - unsigned lvl = f->level(); - bucket * new_f = mk_bucket(m, lvl, new_capacity); - unsigned sz = f->size(); - new_f->set_size(sz); - for (unsigned i = 0; i < sz; i++) - new_f->set(i, f->get(i)); - for (unsigned i = 0; i < lvl; i++) - m_header->set_next(i, new_f); - deallocate_bucket(m, f); - SASSERT(first_bucket() == new_f); - } - - /** - \brief Create a new bucket and divide the elements in bt between bt and the new bucket. - */ - void splice(manager & m, bucket * bt, bucket * pred_vect[]) { - SASSERT(bt->capacity() == Traits::max_capacity); - unsigned bt_lvl = bt->level(); - unsigned new_bucket_lvl = m.random_level(Traits::max_level); - bucket * new_bucket = mk_bucket(m, new_bucket_lvl); - update_list_level(m, new_bucket_lvl, pred_vect); - unsigned _lvl = std::min(bt_lvl, new_bucket_lvl); - for (unsigned i = 0; i < _lvl; i++) { - new_bucket->set_next(i, bt->get_next(i)); - bt->set_next(i, new_bucket); - } - for (unsigned i = bt_lvl; i < new_bucket_lvl; i++) { - new_bucket->set_next(i, pred_vect[i]->get_next(i)); - pred_vect[i]->set_next(i, new_bucket); - } - unsigned old_size = bt->size(); - SASSERT(old_size >= 2); - unsigned mid = old_size/2; - new_bucket->set_size(old_size - mid); - unsigned i = mid; - unsigned j = 0; - for (; i < old_size; i++, j++) { - new_bucket->set(j, bt->get(i)); - } - bt->set_size(mid); - SASSERT(!bt->empty()); - SASSERT(!new_bucket->empty()); - } - - /** - \brief Open space at position idx. The number of entries in bt is increased by one. - - \remark This method will *NOT* invoke inc_ref_eh - */ - void open_space(bucket * bt, unsigned idx) { - SASSERT(bt->size() < bt->capacity()); - SASSERT(idx <= bt->size()); - unsigned i = bt->size(); - while (i > idx) { - bt->set(i, bt->get(i-1)); - i--; - } - bt->expand(1); - } - - /** - \brief Open two spaces at position idx. The number of entries in bt is increased by one. - - \remark This method will *NOT* invoke inc_ref_eh - */ - void open_2spaces(bucket * bt, unsigned idx) { - SASSERT(bt->size() < bt->capacity() - 1); - SASSERT(idx <= bt->size()); - unsigned i = bt->size() + 1; - unsigned end = idx + 1; - while (i > end) { - bt->set(i, bt->get(i-2)); - i--; - } - bt->expand(2); - } - - /** - \brief Delete entry at position idx. - - \remark This method will invoke dec_ref_eh for the value stored in entry at position idx. - */ - void del_entry(manager & m, bucket * bt, unsigned idx) { - SASSERT(!bt->empty()); - SASSERT(idx < bt->size()); - dec_ref(m, bt->get(idx).val()); - unsigned sz = bt->size(); - for (unsigned i = idx; i < sz - 1; i++) { - bt->set(i, bt->get(i+1)); - } - bt->shrink(1); - } - - /** - \brief Create a copy of the skip list. - - \remark This method will invoke inc_ref_eh for all values copied. - */ - void clone_core(manager & m, skip_list_base * new_list) const { - bucket * pred_vect[Traits::max_level]; - unsigned lvl = level(); - new_list->update_list_level(m, lvl); - bucket * new_header = new_list->m_header; - for (unsigned i = 0; i < lvl; i++) - pred_vect[i] = new_header; - bucket * curr = first_bucket(); - while (curr != 0) { - unsigned curr_lvl = curr->level(); - bucket * new_bucket = new_list->mk_bucket(m, curr_lvl, curr->capacity()); - for (unsigned i = 0; i < curr_lvl; i++) { - pred_vect[i]->set_next(i, new_bucket); - pred_vect[i] = new_bucket; - } - unsigned curr_sz = curr->size(); - for (unsigned i = 0; i < curr_sz; i++) { - entry const & curr_entry = curr->get(i); - inc_ref(m, curr_entry.val()); - new_bucket->set(i, curr_entry); - } - new_bucket->set_size(curr_sz); - curr = curr->get_next(0); - } - } - -public: - skip_list_base(): - m_header(0) { - SASSERT(Traits::max_capacity >= 2); - SASSERT(Traits::initial_capacity >= 2); - SASSERT(Traits::initial_capacity <= Traits::max_capacity); - SASSERT(Traits::max_level >= 1); - SASSERT(Traits::max_capacity <= SL_MAX_CAPACITY); - SASSERT(Traits::max_level <= SL_MAX_LEVEL); - } - - skip_list_base(manager & m): - m_header(0) { - SASSERT(Traits::max_capacity >= 2); - SASSERT(Traits::initial_capacity >= 2); - SASSERT(Traits::initial_capacity <= Traits::max_capacity); - SASSERT(Traits::max_level >= 1); - SASSERT(Traits::max_capacity <= SL_MAX_CAPACITY); - SASSERT(Traits::max_level <= SL_MAX_LEVEL); - init(m); - } - - ~skip_list_base() { - SASSERT(m_header == 0); - } - - void deallocate(manager & m) { - deallocate_list(m); - m_header = 0; - } - - /** - \brief Deallocate the list but do not invoke dec_ref_eh. - */ - void deallocate_no_decref(manager & m) { - deallocate_list(m); - m_header = 0; - } - - /** - \brief Initialize a list that was created using the default constructor. - It can be used also to initialized a list deallocated using the method #deallocate. - */ - void init(manager & m) { - SASSERT(m_header == 0); - m_header = mk_header(m, 1); - } - - /** - \brief Remove all elements from the skip-list. - */ - void reset(manager & m) { - deallocate_list(m); - m_header = mk_header(m, 1); - } - - /** - \brief Remove all elements from the skip-list without invoking dec_ref_eh. - */ - void reset_no_decref(manager & m) { - deallocate_list(m); - m_header = mk_header(m, 1); - } - - /** - \brief Return true if the list is empty. - */ - bool empty() const { - SASSERT(m_header != 0); - return first_bucket() == 0; - } - -protected: - /** - \brief Return the position of the bucket in the skip list. - */ - unsigned get_bucket_idx(bucket const * bt) const { - bucket * curr = m_header; - unsigned pos = 0; - while (curr != 0) { - if (curr == bt) - return pos; - pos++; - curr = curr->get_next(0); - } - UNREACHABLE(); - return pos; - } - - /** - \brief Display the given entry. - */ - void display(std::ostream & out, entry const & e) const { - e.display(out); - } - - /** - \brief Display a reference to the given bucket. - */ - void display_bucket_ref(std::ostream & out, bucket const * bt) const { - if (bt == 0) - out << "NIL"; - else - out << "#" << get_bucket_idx(bt); - } - - /** - \brief Display the predecessor vector. - */ - void display_predecessor_vector(std::ostream & out, bucket const * const pred_vect[]) const { - for (unsigned i = 0; i < level(); i++) { - out << i << ": "; - display_bucket_ref(out, pred_vect[i]); - if (pred_vect[i]) { - out << " -> "; - display_bucket_ref(out, pred_vect[i]->get_next(i)); - } - out << "\n"; - } - } - - /** - \brief Display the successors of the given bucket. - */ - void display_successors(std::ostream & out, bucket const * bt) const { - out << "["; - for (unsigned i = 0; i < bt->level(); i++) { - if (i > 0) out << ", "; - display_bucket_ref(out, bt->get_next(i)); - } - out << "]"; - } - - /** - \brief Display the given bucket. - */ - void display(std::ostream & out, bucket const * bt) const { - if (bt == 0) { - out << "NIL\n"; - return; - } - out << "bucket "; - display_bucket_ref(out, bt); - out << ", capacity: " << bt->capacity() << "\n"; - out << "successors: "; - display_successors(out, bt); - out << "\n"; - out << "entries:\n"; - for (unsigned i = 0; i < bt->size(); i++) { - display(out, bt->get(i)); - out << "\n"; - } - out << "----------\n"; - } - -public: - /** - \brief Dump the skip list for debugging purposes. - It assumes that key and value types implement operator <<. - */ - void display_physical(std::ostream & out) const { - out << "{\nskip-list level: " << m_header->level() << "\n"; - bucket * curr = m_header; - while (curr != 0) { - display(out, curr); - curr = curr->get_next(0); - } - out << "}\n"; - } - - void display(std::ostream & out) const { - bucket * curr = m_header; - while (curr != 0) { - unsigned sz = curr->size(); - for (unsigned i = 0; i < sz; i++) { - if (i > 0) - out << " "; - curr->get(i).display(out); - } - curr = curr->get_next(0); - } - } - -protected: - /** - \brief Return true if bucket b2 can be reached from b1 following get_next(i) pointers - */ - bool is_reachable_at_i(bucket const * bt1, bucket const * bt2, unsigned i) const { - bucket * curr = bt1->get_next(i); - while (curr != 0) { - if (curr == bt2) - return true; - curr = curr->get_next(i); - } - return false; - } - -protected: - static void display_size_info_core(std::ostream & out, unsigned cls_size) { - out << "sizeof root: " << cls_size << "\n"; - out << "bucket max capacity: " << Traits::max_capacity << "\n"; - out << "bucket max level: " << Traits::max_level << "\n"; - out << "sizeof(bucket): " << sizeof(bucket) << " + " << sizeof(bucket*) << "*lvl + " << sizeof(entry) << "*capacity\n"; - out << "sizeof(usual bucket): " << (sizeof(bucket) + sizeof(entry)*Traits::max_capacity) << " + " << sizeof(bucket*) << "*lvl\n"; - out << "sizeof(max. bucket): " << (sizeof(bucket) + sizeof(entry)*Traits::max_capacity + sizeof(bucket*)*Traits::max_level) << "\n"; - out << "sizeof(entry): " << sizeof(entry) << "\n"; - out << "sizeof empty: " << cls_size + bucket::get_obj_size(1, 0) << "\n";; - out << "sizeof singleton: [" - << (cls_size + bucket::get_obj_size(1, 0) + bucket::get_obj_size(1, Traits::initial_capacity)) << ", " - << (cls_size + - bucket::get_obj_size(Traits::max_level, 0) + - bucket::get_obj_size(Traits::max_level, Traits::max_capacity)) << "]\n"; - } - -public: - /** - \brief Return true if skip-list has more than k buckets (not considering the header). - - \remark This method is for debugging purposes. - */ - bool has_more_than_k_buckets(unsigned k) const { - bucket * curr = first_bucket(); - while (curr != 0 && k > 0) { - curr = curr->get_next(0); - k--; - } - return curr != 0; - } - - /** - \brief Return true if the skip-list has more than k entries. - */ - bool has_more_than_k_entries(unsigned k) const { - bucket * curr = first_bucket(); - while (curr != 0 && k >= curr->size()) { - k -= curr->size(); - curr = curr->get_next(0); - } - SASSERT(curr == 0 || curr->size() > k); - return curr != 0; - } - -protected: - /** - \brief Return the amount of memory consumed by the list. - */ - unsigned memory_core(unsigned cls_size) const { - unsigned r = 0; - r += cls_size; - bucket * curr = m_header; - while (curr != 0) { - r += bucket::get_obj_size(curr->level(), curr->capacity()); - curr = curr->get_next(0); - } - return r; - } - -public: - /** - \brief Compress the buckets of the skip-list. - Make sure that all, but the last bucket, have at least \c load entries. - - \remark If load > Traits::max_capacity, then it assumes load = Traits::max_capacity. - */ - void compress(manager & m, unsigned load = Traits::max_capacity/2) { - if (load > Traits::max_capacity) - load = Traits::max_capacity; - bucket * pred_vect[Traits::max_level]; - update_predecessor_vector(pred_vect, m_header); - bucket * curr = first_bucket(); - while (curr != 0) { - update_predecessor_vector(pred_vect, curr); - bucket * next = curr->get_next(0); - while (curr->size() < load && next != 0) { - // steal entries of the successor bucket. - unsigned deficit = load - curr->size(); - unsigned next_size = next->size(); - if (next_size <= deficit) { - for (unsigned i = 0, j = curr->size(); i < next_size; i++, j++) { - curr->set(j, next->get(i)); - } - curr->expand(next_size); - bucket * new_next = next->get_next(0); - del_bucket(m, next, pred_vect); - next = new_next; - SASSERT(curr->size() <= load); - } - else { - for (unsigned i = 0, j = curr->size(); i < deficit; i++, j++) { - curr->set(j, next->get(i)); - } - curr->expand(deficit); - for (unsigned i = deficit, j = 0; i < next_size; i++, j++) { - next->set(j, next->get(i)); - } - next->set_size(next_size - deficit); - SASSERT(curr->size() == load); - } - } - curr = curr->get_next(0); - } - } - - void swap(skip_list_base & other) { - bucket * tmp = m_header; - m_header = other.m_header; - other.m_header = tmp; - } -}; - - -#endif diff --git a/src/muz/equiv_proof_converter.cpp b/src/tactic/equiv_proof_converter.cpp similarity index 100% rename from src/muz/equiv_proof_converter.cpp rename to src/tactic/equiv_proof_converter.cpp diff --git a/src/muz/equiv_proof_converter.h b/src/tactic/equiv_proof_converter.h similarity index 100% rename from src/muz/equiv_proof_converter.h rename to src/tactic/equiv_proof_converter.h diff --git a/src/muz/horn_subsume_model_converter.cpp b/src/tactic/horn_subsume_model_converter.cpp similarity index 100% rename from src/muz/horn_subsume_model_converter.cpp rename to src/tactic/horn_subsume_model_converter.cpp diff --git a/src/muz/horn_subsume_model_converter.h b/src/tactic/horn_subsume_model_converter.h similarity index 100% rename from src/muz/horn_subsume_model_converter.h rename to src/tactic/horn_subsume_model_converter.h diff --git a/src/muz/replace_proof_converter.cpp b/src/tactic/replace_proof_converter.cpp similarity index 100% rename from src/muz/replace_proof_converter.cpp rename to src/tactic/replace_proof_converter.cpp diff --git a/src/muz/replace_proof_converter.h b/src/tactic/replace_proof_converter.h similarity index 100% rename from src/muz/replace_proof_converter.h rename to src/tactic/replace_proof_converter.h From f5b988aead99a9229eb51f6ba463fc7e49a863ca Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 28 Aug 2013 22:15:16 -0700 Subject: [PATCH 251/281] update README Signed-off-by: Nikolaj Bjorner --- src/muz/README | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/muz/README b/src/muz/README index 03cd12bc7..c7d5a9665 100644 --- a/src/muz/README +++ b/src/muz/README @@ -1,2 +1,12 @@ muZ: routines related to solving satisfiability of Horn clauses and solving Datalog programs. + +- base - contains base routines and the main context for + maintaining fixedpoint solvers +- transforms - common rule transformations +- rel - relational algebra based Datalog engine +- pdr - PDR based Horn clause solver +- clp - Dart/Symbolic execution-based solver +- tab - Tabulation based solver +- bmc - Bounded model checking based solver +- fp - main exported routines \ No newline at end of file From 912d220e947591867d6a20591be4faacdaae5707 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Aug 2013 13:40:42 -0700 Subject: [PATCH 252/281] working on generalizer Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_generalizers.cpp | 128 +++++++++++++++++++++++-------- src/muz/pdr/pdr_generalizers.h | 3 + 2 files changed, 101 insertions(+), 30 deletions(-) diff --git a/src/muz/pdr/pdr_generalizers.cpp b/src/muz/pdr/pdr_generalizers.cpp index f1ab01070..1121243f2 100644 --- a/src/muz/pdr/pdr_generalizers.cpp +++ b/src/muz/pdr/pdr_generalizers.cpp @@ -23,6 +23,7 @@ Revision History: #include "pdr_generalizers.h" #include "expr_abstract.h" #include "var_subst.h" +#include "model_smt2_pp.h" namespace pdr { @@ -157,7 +158,7 @@ namespace pdr { } void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { - // method3(n, core, uses_level, new_cores); + method3(n, core, uses_level, new_cores); method1(n, core, uses_level, new_cores); } @@ -199,6 +200,7 @@ namespace pdr { for (unsigned i = 0; i < fmls.size(); ++i) { fml = m.mk_not(fmls[i].get()); core2.reset(); + conv2.reset(); qe::flatten_and(fml, core2); if (!mk_convex(core2, 1, conv2)) { IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core2), m) << "\n";); @@ -304,10 +306,6 @@ namespace pdr { bool uses_level1; expr_ref_vector core1(m); core1.append(core); - obj_hashtable bs; - for (unsigned i = 0; i < core.size(); ++i) { - bs.insert(core[i]); - } expr_ref_vector consequences(m); { n.pt().get_solver().set_consequences(&consequences); @@ -325,6 +323,77 @@ namespace pdr { verbose_stream() << mk_pp(core1[i].get(), m) << "\n"; }); + // Create disjunction. + expr_ref tmp(m); + for (unsigned i = 0; i < consequences.size(); ++i) { + consequences[i] = m.mk_not(consequences[i].get()); + } + tmp = m.mk_and(core.size(), core.c_ptr()); + + if (!strengthen_consequences(n, consequences, tmp)) { + return; + } + + IF_VERBOSE(0, verbose_stream() << "consequences strengthened\n";); + // Use the resulting formula to find Farkas lemmas from core. + } + + bool core_convex_hull_generalizer::strengthen_consequences(model_node& n, expr_ref_vector& As, expr* B) { + expr_ref A(m), tmp(m), convA(m); + unsigned sz = As.size(); + for (unsigned i = 0; i < As.size(); ++i) { + expr_ref_vector Hs(m); + Hs.push_back(As[i].get()); + for (unsigned j = i + 1; j < As.size(); ++j) { + Hs.push_back(Hs[j].get()); + bool unsat = false; + if (mk_closure(n, Hs, A)) { + tmp = As[i].get(); + As[i] = A; + unsat = is_unsat(As, B); + As[i] = tmp; + } + if (unsat) { + convA = A; + As[j] = As.back(); + As.pop_back(); + --j; + } + else { + Hs.pop_back(); + } + } + if (Hs.size() > 1) { + As[i] = convA; + } + } + return sz > As.size(); + } + + bool core_convex_hull_generalizer::mk_closure(model_node& n, expr_ref_vector const& Hs, expr_ref& A) { + expr_ref_vector fmls(m), es(m); + add_variables(n, Hs.size(), fmls); + for (unsigned i = 0; i < Hs.size(); ++i) { + es.reset(); + qe::flatten_and(Hs[i], es); + if (!mk_convex(es, i, fmls)) { + return false; + } + } + A = m.mk_and(fmls.size(), fmls.c_ptr()); + return true; + } + + bool core_convex_hull_generalizer::is_unsat(expr_ref_vector const& As, expr* B) { + smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); + for (unsigned i = 0; i < As.size(); ++i) { + ctx.assert_expr(As[i]); + } + ctx.assert_expr(B); + return l_false == ctx.check(); + } + +#if 0 // now create the convex closure of the consequences: expr_ref tmp(m), zero(m); expr_ref_vector conv(m), es(m), enabled(m); @@ -359,19 +428,26 @@ namespace pdr { smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); for (unsigned i = 0; i < conv.size(); ++i) { ctx.assert_expr(conv[i].get()); + IF_VERBOSE(0, verbose_stream() << "CC: " << mk_pp(conv[i].get(), m) << "\n";); } for (unsigned i = 0; i < core.size(); ++i) { ctx.assert_expr(core[i]); + IF_VERBOSE(0, verbose_stream() << "Co: " << mk_pp(core[i], m) << "\n";); } vector transversal; while (l_true == ctx.check()) { - IF_VERBOSE(0, ctx.display(verbose_stream());); model_ref md; ctx.get_model(md); + IF_VERBOSE(0, + ctx.display(verbose_stream()); + verbose_stream() << "\n"; + model_smt2_pp(verbose_stream(), m, *md.get(), 0);); expr_ref_vector lits(m); unsigned_vector pos; for (unsigned i = 0; i < consequences.size(); ++i) { if (md->eval(enabled[i].get(), tmp, false)) { + IF_VERBOSE(0, + verbose_stream() << mk_pp(enabled[i].get(), m) << " |-> " << mk_pp(tmp, m) << "\n";); if (m.is_true(tmp)) { lits.push_back(tmp); pos.push_back(i); @@ -387,44 +463,37 @@ namespace pdr { // // we could no longer satisfy core using a partition. // - - } + IF_VERBOSE(0, verbose_stream() << "TBD: tranverse\n";); +#endif + void core_convex_hull_generalizer::add_variables(model_node& n, unsigned num_vars, expr_ref_vector& fmls) { manager& pm = n.pt().get_pdr_manager(); + SASSERT(num_vars > 0); while (m_vars.size() < num_vars) { m_vars.resize(m_vars.size()+1); m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); } - if (!m_vars[0].contains(n.pt().head())) { - expr_ref var(m); - m_vars[0].insert(n.pt().head(), 0); - unsigned sz = n.pt().sig_size(); - for (unsigned i = 0; i < sz; ++i) { - func_decl* fn0 = n.pt().sig(i); - sort* srt = fn0->get_range(); - if (a.is_int_real(srt)) { - func_decl* fn1 = pm.o2n(fn0, 0); - for (unsigned j = 0; j < num_vars; ++j) { - var = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); - m_vars[j].insert(fn1, var); - m_trail.push_back(var); - } - } - } - } unsigned sz = n.pt().sig_size(); + for (unsigned i = 0; i < sz; ++i) { expr* var; ptr_vector vars; func_decl* fn0 = n.pt().sig(i); func_decl* fn1 = pm.o2n(fn0, 0); - for (unsigned j = 0; j < num_vars; ++j) { - VERIFY (m_vars[j].find(fn1, var)); - vars.push_back(var); + sort* srt = fn0->get_range(); + if (a.is_int_real(srt)) { + for (unsigned j = 0; j < num_vars; ++j) { + if (!m_vars[j].find(fn1, var)) { + var = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); + m_trail.push_back(var); + m_vars[j].insert(fn1, var); + } + vars.push_back(var); + } + fmls.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(num_vars, vars.c_ptr()))); } - fmls.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(num_vars, vars.c_ptr()))); } if (m_is_closure) { for (unsigned i = 0; i < num_vars; ++i) { @@ -476,7 +545,6 @@ namespace pdr { } bool core_convex_hull_generalizer::mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv) { - conv.reset(); for (unsigned i = 0; i < core.size(); ++i) { mk_convex(core[i], index, conv); } diff --git a/src/muz/pdr/pdr_generalizers.h b/src/muz/pdr/pdr_generalizers.h index 10aa5b978..e566148ce 100644 --- a/src/muz/pdr/pdr_generalizers.h +++ b/src/muz/pdr/pdr_generalizers.h @@ -90,6 +90,9 @@ namespace pdr { void method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); void method2(model_node& n, expr_ref_vector& core, bool& uses_level); void method3(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); + bool strengthen_consequences(model_node& n, expr_ref_vector& As, expr* B); + bool is_unsat(expr_ref_vector const& As, expr* B); + bool mk_closure(model_node& n, expr_ref_vector const& Hs, expr_ref& A); void add_variables(model_node& n, unsigned num_vars, expr_ref_vector& fmls); public: core_convex_hull_generalizer(context& ctx, bool is_closure); From cdbdf60aaebcbc6d8195497f5fb6a31d9ec86868 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 29 Aug 2013 14:34:08 -0700 Subject: [PATCH 253/281] working on generalizer Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_farkas_learner.cpp | 1 + src/muz/pdr/pdr_generalizers.cpp | 280 +++++++++++++++-------------- src/muz/pdr/pdr_generalizers.h | 6 +- 3 files changed, 148 insertions(+), 139 deletions(-) diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 6202c913d..3cd1932ba 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -423,6 +423,7 @@ namespace pdr { else { bool_rewriter rw(m); rw.mk_or(n, (expr*const*)(lits), res); + res = m.mk_not(res); } } diff --git a/src/muz/pdr/pdr_generalizers.cpp b/src/muz/pdr/pdr_generalizers.cpp index 1121243f2..bd9a1b62e 100644 --- a/src/muz/pdr/pdr_generalizers.cpp +++ b/src/muz/pdr/pdr_generalizers.cpp @@ -158,7 +158,7 @@ namespace pdr { } void core_convex_hull_generalizer::operator()(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { - method3(n, core, uses_level, new_cores); + // method3(n, core, uses_level, new_cores); method1(n, core, uses_level, new_cores); } @@ -188,11 +188,7 @@ namespace pdr { return; } add_variables(n, 2, fmls); - if (!mk_convex(core, 0, conv1)) { - new_cores.push_back(std::make_pair(core, uses_level)); - IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core), m) << "\n";); - return; - } + mk_convex(core, 0, conv1); conv1.append(fmls); expr_ref fml = n.pt().get_formulas(n.level(), false); fmls.reset(); @@ -202,10 +198,7 @@ namespace pdr { core2.reset(); conv2.reset(); qe::flatten_and(fml, core2); - if (!mk_convex(core2, 1, conv2)) { - IF_VERBOSE(0, verbose_stream() << "Non-convex: " << mk_pp(pm.mk_and(core2), m) << "\n";); - continue; - } + mk_convex(core2, 1, conv2); conv2.append(conv1); expr_ref state = pm.mk_and(conv2); TRACE("pdr", @@ -323,13 +316,30 @@ namespace pdr { verbose_stream() << mk_pp(core1[i].get(), m) << "\n"; }); - // Create disjunction. expr_ref tmp(m); - for (unsigned i = 0; i < consequences.size(); ++i) { - consequences[i] = m.mk_not(consequences[i].get()); + + // Check that F(R) => \/ consequences + { + expr_ref_vector cstate(m); + for (unsigned i = 0; i < consequences.size(); ++i) { + cstate.push_back(m.mk_not(consequences[i].get())); + } + tmp = m.mk_and(cstate.size(), cstate.c_ptr()); + model_node nd(0, tmp, n.pt(), n.level()); + pred_transformer::scoped_farkas sf (n.pt(), false); + VERIFY(l_false == n.pt().is_reachable(nd, &core1, uses_level1)); } + + // Create disjunction. tmp = m.mk_and(core.size(), core.c_ptr()); + // Check that \/ consequences => not (core) + if (!is_unsat(consequences, tmp)) { + IF_VERBOSE(0, verbose_stream() << "Consequences don't contradict the core\n";); + return; + } + IF_VERBOSE(0, verbose_stream() << "Consequences contradict core\n";); + if (!strengthen_consequences(n, consequences, tmp)) { return; } @@ -345,15 +355,15 @@ namespace pdr { expr_ref_vector Hs(m); Hs.push_back(As[i].get()); for (unsigned j = i + 1; j < As.size(); ++j) { - Hs.push_back(Hs[j].get()); + Hs.push_back(As[j].get()); bool unsat = false; - if (mk_closure(n, Hs, A)) { - tmp = As[i].get(); - As[i] = A; - unsat = is_unsat(As, B); - As[i] = tmp; - } + mk_convex(n, Hs, A); + tmp = As[i].get(); + As[i] = A; + unsat = is_unsat(As, B); + As[i] = tmp; if (unsat) { + IF_VERBOSE(0, verbose_stream() << "New convex: " << mk_pp(convA, m) << "\n";); convA = A; As[j] = As.back(); As.pop_back(); @@ -370,103 +380,27 @@ namespace pdr { return sz > As.size(); } - bool core_convex_hull_generalizer::mk_closure(model_node& n, expr_ref_vector const& Hs, expr_ref& A) { + void core_convex_hull_generalizer::mk_convex(model_node& n, expr_ref_vector const& Hs, expr_ref& A) { expr_ref_vector fmls(m), es(m); add_variables(n, Hs.size(), fmls); for (unsigned i = 0; i < Hs.size(); ++i) { es.reset(); qe::flatten_and(Hs[i], es); - if (!mk_convex(es, i, fmls)) { - return false; - } + mk_convex(es, i, fmls); } A = m.mk_and(fmls.size(), fmls.c_ptr()); - return true; } bool core_convex_hull_generalizer::is_unsat(expr_ref_vector const& As, expr* B) { smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); - for (unsigned i = 0; i < As.size(); ++i) { - ctx.assert_expr(As[i]); - } + expr_ref disj(m); + disj = m.mk_or(As.size(), As.c_ptr()); + ctx.assert_expr(disj); ctx.assert_expr(B); + std::cout << "Checking\n" << mk_pp(disj, m) << "\n" << mk_pp(B, m) << "\n"; return l_false == ctx.check(); } -#if 0 - // now create the convex closure of the consequences: - expr_ref tmp(m), zero(m); - expr_ref_vector conv(m), es(m), enabled(m); - zero = a.mk_numeral(rational(0), a.mk_real()); - add_variables(n, consequences.size(), conv); - for (unsigned i = 0; i < consequences.size(); ++i) { - es.reset(); - tmp = m.mk_not(consequences[i].get()); - qe::flatten_and(tmp, es); - if (!mk_convex(es, i, conv)) { - IF_VERBOSE(0, verbose_stream() << "Failed to create convex closure\n";); - return; - } - es.reset(); - // - // enabled[i] = not (sigma_i = 0 and z_i1 = 0 and .. and z_im = 0) - // - es.push_back(m.mk_eq(m_sigma[i].get(), zero)); - for (unsigned j = 0; j < n.pt().sig_size(); ++j) { - func_decl* fn0 = n.pt().sig(j); - func_decl* fn1 = pm.o2n(fn0, 0); - expr* var; - VERIFY (m_vars[i].find(fn1, var)); - es.push_back(m.mk_eq(var, zero)); - } - - enabled.push_back(m.mk_not(m.mk_and(es.size(), es.c_ptr()))); - } - - // the convex closure was created of all consequences. - // now determine a subset of enabled constraints. - smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); - for (unsigned i = 0; i < conv.size(); ++i) { - ctx.assert_expr(conv[i].get()); - IF_VERBOSE(0, verbose_stream() << "CC: " << mk_pp(conv[i].get(), m) << "\n";); - } - for (unsigned i = 0; i < core.size(); ++i) { - ctx.assert_expr(core[i]); - IF_VERBOSE(0, verbose_stream() << "Co: " << mk_pp(core[i], m) << "\n";); - } - vector transversal; - while (l_true == ctx.check()) { - model_ref md; - ctx.get_model(md); - IF_VERBOSE(0, - ctx.display(verbose_stream()); - verbose_stream() << "\n"; - model_smt2_pp(verbose_stream(), m, *md.get(), 0);); - expr_ref_vector lits(m); - unsigned_vector pos; - for (unsigned i = 0; i < consequences.size(); ++i) { - if (md->eval(enabled[i].get(), tmp, false)) { - IF_VERBOSE(0, - verbose_stream() << mk_pp(enabled[i].get(), m) << " |-> " << mk_pp(tmp, m) << "\n";); - if (m.is_true(tmp)) { - lits.push_back(tmp); - pos.push_back(i); - } - } - } - transversal.push_back(pos); - SASSERT(!lits.empty()); - tmp = m.mk_not(m.mk_and(lits.size(), lits.c_ptr())); - TRACE("pdr", tout << "add block: " << mk_pp(tmp, m) << "\n";); - ctx.assert_expr(tmp); - } - // - // we could no longer satisfy core using a partition. - // - IF_VERBOSE(0, verbose_stream() << "TBD: tranverse\n";); -#endif - - void core_convex_hull_generalizer::add_variables(model_node& n, unsigned num_vars, expr_ref_vector& fmls) { manager& pm = n.pt().get_pdr_manager(); SASSERT(num_vars > 0); @@ -544,36 +478,42 @@ namespace pdr { return true; } - bool core_convex_hull_generalizer::mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv) { + void core_convex_hull_generalizer::mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv) { for (unsigned i = 0; i < core.size(); ++i) { mk_convex(core[i], index, conv); } - return !conv.empty() && mk_closure(conv); + mk_closure(conv); } void core_convex_hull_generalizer::mk_convex(expr* fml, unsigned index, expr_ref_vector& conv) { expr_ref result(m), r1(m), r2(m); expr* e1, *e2; bool is_not = m.is_not(fml, fml); - if (a.is_le(fml, e1, e2) && mk_convex(e1, index, false, r1) && mk_convex(e2, index, false, r2)) { + if (a.is_le(fml, e1, e2)) { + mk_convex(e1, index, false, r1); + mk_convex(e2, index, false, r2); result = a.mk_le(r1, r2); } - else if (a.is_ge(fml, e1, e2) && mk_convex(e1, index, false, r1) && mk_convex(e2, index, false, r2)) { + else if (a.is_ge(fml, e1, e2)) { + mk_convex(e1, index, false, r1); + mk_convex(e2, index, false, r2); result = a.mk_ge(r1, r2); } - else if (a.is_gt(fml, e1, e2) && mk_convex(e1, index, false, r1) && mk_convex(e2, index, false, r2)) { + else if (a.is_gt(fml, e1, e2)) { + mk_convex(e1, index, false, r1); + mk_convex(e2, index, false, r2); result = a.mk_gt(r1, r2); } - else if (a.is_lt(fml, e1, e2) && mk_convex(e1, index, false, r1) && mk_convex(e2, index, false, r2)) { + else if (a.is_lt(fml, e1, e2)) { + mk_convex(e1, index, false, r1); + mk_convex(e2, index, false, r2); result = a.mk_lt(r1, r2); } - else if (m.is_eq(fml, e1, e2) && a.is_int_real(e1) && mk_convex(e1, index, false, r1) && mk_convex(e2, index, false, r2)) { + else if (m.is_eq(fml, e1, e2) && a.is_int_real(e1)) { + mk_convex(e1, index, false, r1); + mk_convex(e2, index, false, r2); result = m.mk_eq(r1, r2); } - else { - TRACE("pdr", tout << "Did not handle " << mk_pp(fml, m) << "\n";); - return; - } if (is_not) { result = m.mk_not(result); } @@ -591,49 +531,46 @@ namespace pdr { } - bool core_convex_hull_generalizer::mk_convex(expr* term, unsigned index, bool is_mul, expr_ref& result) { + void core_convex_hull_generalizer::mk_convex(expr* term, unsigned index, bool is_mul, expr_ref& result) { if (!is_app(term)) { - return false; + result = term; + return; } app* app = to_app(term); expr* e1, *e2; expr_ref r1(m), r2(m); - if (translate(app->get_decl(), index, result)) { - return true; - } if (a.is_add(term)) { - bool ok = true; expr_ref_vector args(m); - for (unsigned i = 0; ok && i < app->get_num_args(); ++i) { - ok = mk_convex(app->get_arg(i), index, is_mul, r1); - if (ok) { - args.push_back(r1); - } + for (unsigned i = 0; i < app->get_num_args(); ++i) { + mk_convex(app->get_arg(i), index, is_mul, r1); + args.push_back(r1); } - if (ok) { - result = a.mk_add(args.size(), args.c_ptr()); - } - return ok; + result = a.mk_add(args.size(), args.c_ptr()); } - if (a.is_sub(term, e1, e2) && mk_convex(e1, index, is_mul, r1) && mk_convex(e2, index, is_mul, r2)) { + else if (a.is_sub(term, e1, e2)) { + mk_convex(e1, index, is_mul, r1); + mk_convex(e2, index, is_mul, r2); result = a.mk_sub(r1, r2); - return true; } - if (a.is_mul(term, e1, e2) && mk_convex(e1, index, true, r1) && mk_convex(e2, index, true, r2)) { + else if (a.is_mul(term, e1, e2)) { + mk_convex(e1, index, true, r1); + mk_convex(e2, index, true, r2); result = a.mk_mul(r1, r2); - return true; } - if (a.is_numeral(term)) { + else if (a.is_numeral(term)) { if (is_mul) { result = term; } else { result = a.mk_mul(m_sigma[index].get(), term); } - return true; } - IF_VERBOSE(0, verbose_stream() << "Not handled: " << mk_pp(term, m) << "\n";); - return false; + else if (translate(app->get_decl(), index, result)) { + // no-op + } + else { + result = term; + } } @@ -1088,3 +1025,74 @@ namespace pdr { } } }; + +#if 0 + // now create the convex closure of the consequences: + expr_ref tmp(m), zero(m); + expr_ref_vector conv(m), es(m), enabled(m); + zero = a.mk_numeral(rational(0), a.mk_real()); + add_variables(n, consequences.size(), conv); + for (unsigned i = 0; i < consequences.size(); ++i) { + es.reset(); + tmp = m.mk_not(consequences[i].get()); + qe::flatten_and(tmp, es); + mk_convex(es, i, conv); + es.reset(); + // + // enabled[i] = not (sigma_i = 0 and z_i1 = 0 and .. and z_im = 0) + // + es.push_back(m.mk_eq(m_sigma[i].get(), zero)); + for (unsigned j = 0; j < n.pt().sig_size(); ++j) { + func_decl* fn0 = n.pt().sig(j); + func_decl* fn1 = pm.o2n(fn0, 0); + expr* var; + VERIFY (m_vars[i].find(fn1, var)); + es.push_back(m.mk_eq(var, zero)); + } + + enabled.push_back(m.mk_not(m.mk_and(es.size(), es.c_ptr()))); + } + + // the convex closure was created of all consequences. + // now determine a subset of enabled constraints. + smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); + for (unsigned i = 0; i < conv.size(); ++i) { + ctx.assert_expr(conv[i].get()); + IF_VERBOSE(0, verbose_stream() << "CC: " << mk_pp(conv[i].get(), m) << "\n";); + } + for (unsigned i = 0; i < core.size(); ++i) { + ctx.assert_expr(core[i]); + IF_VERBOSE(0, verbose_stream() << "Co: " << mk_pp(core[i], m) << "\n";); + } + vector transversal; + while (l_true == ctx.check()) { + model_ref md; + ctx.get_model(md); + IF_VERBOSE(0, + ctx.display(verbose_stream()); + verbose_stream() << "\n"; + model_smt2_pp(verbose_stream(), m, *md.get(), 0);); + expr_ref_vector lits(m); + unsigned_vector pos; + for (unsigned i = 0; i < consequences.size(); ++i) { + if (md->eval(enabled[i].get(), tmp, false)) { + IF_VERBOSE(0, + verbose_stream() << mk_pp(enabled[i].get(), m) << " |-> " << mk_pp(tmp, m) << "\n";); + if (m.is_true(tmp)) { + lits.push_back(tmp); + pos.push_back(i); + } + } + } + transversal.push_back(pos); + SASSERT(!lits.empty()); + tmp = m.mk_not(m.mk_and(lits.size(), lits.c_ptr())); + TRACE("pdr", tout << "add block: " << mk_pp(tmp, m) << "\n";); + ctx.assert_expr(tmp); + } + // + // we could no longer satisfy core using a partition. + // + IF_VERBOSE(0, verbose_stream() << "TBD: tranverse\n";); +#endif + diff --git a/src/muz/pdr/pdr_generalizers.h b/src/muz/pdr/pdr_generalizers.h index e566148ce..e5f146d0d 100644 --- a/src/muz/pdr/pdr_generalizers.h +++ b/src/muz/pdr/pdr_generalizers.h @@ -83,16 +83,16 @@ namespace pdr { bool m_is_closure; expr_ref mk_closure(expr* e); bool mk_closure(expr_ref_vector& conj); - bool mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv); + void mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv); void mk_convex(expr* fml, unsigned index, expr_ref_vector& conv); - bool mk_convex(expr* term, unsigned index, bool is_mul, expr_ref& result); + void mk_convex(expr* term, unsigned index, bool is_mul, expr_ref& result); bool translate(func_decl* fn, unsigned index, expr_ref& result); void method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); void method2(model_node& n, expr_ref_vector& core, bool& uses_level); void method3(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); bool strengthen_consequences(model_node& n, expr_ref_vector& As, expr* B); bool is_unsat(expr_ref_vector const& As, expr* B); - bool mk_closure(model_node& n, expr_ref_vector const& Hs, expr_ref& A); + void mk_convex(model_node& n, expr_ref_vector const& Hs, expr_ref& A); void add_variables(model_node& n, unsigned num_vars, expr_ref_vector& fmls); public: core_convex_hull_generalizer(context& ctx, bool is_closure); From 58b16c55850789277ed027e3992fe8c83a8f8464 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Aug 2013 20:39:49 -0700 Subject: [PATCH 254/281] generalize mk_convex method to work with scaling Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_generalizers.cpp | 135 +++++++++++-------------------- src/muz/pdr/pdr_generalizers.h | 18 +++++ 2 files changed, 64 insertions(+), 89 deletions(-) diff --git a/src/muz/pdr/pdr_generalizers.cpp b/src/muz/pdr/pdr_generalizers.cpp index bd9a1b62e..64766ea93 100644 --- a/src/muz/pdr/pdr_generalizers.cpp +++ b/src/muz/pdr/pdr_generalizers.cpp @@ -23,6 +23,7 @@ Revision History: #include "pdr_generalizers.h" #include "expr_abstract.h" #include "var_subst.h" +#include "expr_safe_replace.h" #include "model_smt2_pp.h" @@ -147,6 +148,49 @@ namespace pdr { m_farkas_learner.collect_statistics(st); } + expr_ref scaler::operator()(expr* e, expr* k, obj_map* translate) { + m_cache[0].reset(); + m_cache[1].reset(); + m_translate = translate; + m_k = k; + return scale(e, false); + } + + expr_ref scaler::scale(expr* e, bool is_mul) { + expr* r; + if (m_cache[is_mul].find(e, r)) { + return expr_ref(r, m); + } + if (!is_app(e)) { + return expr_ref(e, m); + } + app* ap = to_app(e); + if (m_translate && m_translate->find(ap->get_decl(), r)) { + return expr_ref(r, m); + } + if (!is_mul && a.is_numeral(e)) { + return expr_ref(a.mk_mul(m_k, e), m); + } + expr_ref_vector args(m); + bool is_mul_rec = is_mul || a.is_mul(e); + for (unsigned i = 0; i < ap->get_num_args(); ++i) { + args.push_back(scale(ap->get_arg(i), is_mul_rec)); + } + expr_ref result(m); + result = m.mk_app(ap->get_decl(), args.size(), args.c_ptr()); + m_cache[is_mul].insert(e, result); + return result; + } + + expr_ref scaler::undo_k(expr* e, expr* k) { + expr_safe_replace sub(m); + th_rewriter rw(m); + expr_ref result(e, m); + sub.insert(k, a.mk_numeral(rational(1), false)); + sub(result); + rw(result); + return result; + } core_convex_hull_generalizer::core_convex_hull_generalizer(context& ctx, bool is_closure): core_generalizer(ctx), @@ -479,100 +523,13 @@ namespace pdr { } void core_convex_hull_generalizer::mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv) { + scaler sc(m); for (unsigned i = 0; i < core.size(); ++i) { - mk_convex(core[i], index, conv); + conv.push_back(sc(core[i], m_sigma[index].get(), &m_vars[index])); } mk_closure(conv); } - void core_convex_hull_generalizer::mk_convex(expr* fml, unsigned index, expr_ref_vector& conv) { - expr_ref result(m), r1(m), r2(m); - expr* e1, *e2; - bool is_not = m.is_not(fml, fml); - if (a.is_le(fml, e1, e2)) { - mk_convex(e1, index, false, r1); - mk_convex(e2, index, false, r2); - result = a.mk_le(r1, r2); - } - else if (a.is_ge(fml, e1, e2)) { - mk_convex(e1, index, false, r1); - mk_convex(e2, index, false, r2); - result = a.mk_ge(r1, r2); - } - else if (a.is_gt(fml, e1, e2)) { - mk_convex(e1, index, false, r1); - mk_convex(e2, index, false, r2); - result = a.mk_gt(r1, r2); - } - else if (a.is_lt(fml, e1, e2)) { - mk_convex(e1, index, false, r1); - mk_convex(e2, index, false, r2); - result = a.mk_lt(r1, r2); - } - else if (m.is_eq(fml, e1, e2) && a.is_int_real(e1)) { - mk_convex(e1, index, false, r1); - mk_convex(e2, index, false, r2); - result = m.mk_eq(r1, r2); - } - if (is_not) { - result = m.mk_not(result); - } - conv.push_back(result); - } - - - bool core_convex_hull_generalizer::translate(func_decl* f, unsigned index, expr_ref& result) { - expr* tmp; - if (m_vars[index].find(f, tmp)) { - result = tmp; - return true; - } - return false; - } - - - void core_convex_hull_generalizer::mk_convex(expr* term, unsigned index, bool is_mul, expr_ref& result) { - if (!is_app(term)) { - result = term; - return; - } - app* app = to_app(term); - expr* e1, *e2; - expr_ref r1(m), r2(m); - if (a.is_add(term)) { - expr_ref_vector args(m); - for (unsigned i = 0; i < app->get_num_args(); ++i) { - mk_convex(app->get_arg(i), index, is_mul, r1); - args.push_back(r1); - } - result = a.mk_add(args.size(), args.c_ptr()); - } - else if (a.is_sub(term, e1, e2)) { - mk_convex(e1, index, is_mul, r1); - mk_convex(e2, index, is_mul, r2); - result = a.mk_sub(r1, r2); - } - else if (a.is_mul(term, e1, e2)) { - mk_convex(e1, index, true, r1); - mk_convex(e2, index, true, r2); - result = a.mk_mul(r1, r2); - } - else if (a.is_numeral(term)) { - if (is_mul) { - result = term; - } - else { - result = a.mk_mul(m_sigma[index].get(), term); - } - } - else if (translate(app->get_decl(), index, result)) { - // no-op - } - else { - result = term; - } - } - // --------------------------------- // core_arith_inductive_generalizer diff --git a/src/muz/pdr/pdr_generalizers.h b/src/muz/pdr/pdr_generalizers.h index e5f146d0d..ca9c5a969 100644 --- a/src/muz/pdr/pdr_generalizers.h +++ b/src/muz/pdr/pdr_generalizers.h @@ -73,6 +73,24 @@ namespace pdr { virtual void collect_statistics(statistics& st) const; }; + // Arithmetic scaling functor. + // Variables are replaced using + // m_translate. Constants are replaced by + // multiplication with a variable 'k' (scale factor). + class scaler { + ast_manager& m; + arith_util a; + obj_map m_cache[2]; + expr* m_k; + obj_map* m_translate; + public: + scaler(ast_manager& m): m(m), a(m), m_translate(0) {} + expr_ref operator()(expr* e, expr* k, obj_map* translate = 0); + expr_ref undo_k(expr* e, expr* k); + private: + expr_ref scale(expr* e, bool is_mul); + }; + class core_convex_hull_generalizer : public core_generalizer { ast_manager& m; arith_util a; From 06a858ef3d8e77158b9620eb8e4c1e31823b0ed5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 Sep 2013 13:43:19 -0700 Subject: [PATCH 255/281] refactor closure code Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_closure.cpp | 175 +++++++++++++++++ src/muz/pdr/pdr_closure.h | 67 +++++++ src/muz/pdr/pdr_generalizers.cpp | 315 ++----------------------------- src/muz/pdr/pdr_generalizers.h | 31 +-- src/qe/qe_util.cpp | 16 ++ src/qe/qe_util.h | 4 + 6 files changed, 283 insertions(+), 325 deletions(-) create mode 100644 src/muz/pdr/pdr_closure.cpp create mode 100644 src/muz/pdr/pdr_closure.h diff --git a/src/muz/pdr/pdr_closure.cpp b/src/muz/pdr/pdr_closure.cpp new file mode 100644 index 000000000..483b48932 --- /dev/null +++ b/src/muz/pdr/pdr_closure.cpp @@ -0,0 +1,175 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + pdr_closure.cpp + +Abstract: + + Utility functions for computing closures. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-9-1. + +Revision History: + +--*/ + +#include "pdr_closure.h" +#include "pdr_context.h" +#include "expr_safe_replace.h" + +namespace pdr { + + expr_ref scaler::operator()(expr* e, expr* k, obj_map* translate) { + m_cache[0].reset(); + m_cache[1].reset(); + m_translate = translate; + m_k = k; + return scale(e, false); + } + + expr_ref scaler::scale(expr* e, bool is_mul) { + expr* r; + if (m_cache[is_mul].find(e, r)) { + return expr_ref(r, m); + } + if (!is_app(e)) { + return expr_ref(e, m); + } + app* ap = to_app(e); + if (m_translate && m_translate->find(ap->get_decl(), r)) { + return expr_ref(r, m); + } + if (!is_mul && a.is_numeral(e)) { + return expr_ref(a.mk_mul(m_k, e), m); + } + expr_ref_vector args(m); + bool is_mul_rec = is_mul || a.is_mul(e); + for (unsigned i = 0; i < ap->get_num_args(); ++i) { + args.push_back(scale(ap->get_arg(i), is_mul_rec)); + } + expr_ref result(m); + result = m.mk_app(ap->get_decl(), args.size(), args.c_ptr()); + m_cache[is_mul].insert(e, result); + return result; + } + + expr_ref scaler::undo_k(expr* e, expr* k) { + expr_safe_replace sub(m); + th_rewriter rw(m); + expr_ref result(e, m); + sub.insert(k, a.mk_numeral(rational(1), false)); + sub(result); + rw(result); + return result; + } + + + closure::closure(pred_transformer& p, bool is_closure): + m(p.get_manager()), m_pt(p), a(m), + m_is_closure(is_closure), m_sigma(m), m_trail(m) {} + + + void closure::add_variables(unsigned num_vars, expr_ref_vector& fmls) { + manager& pm = m_pt.get_pdr_manager(); + SASSERT(num_vars > 0); + while (m_vars.size() < num_vars) { + m_vars.resize(m_vars.size()+1); + m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); + } + + unsigned sz = m_pt.sig_size(); + + for (unsigned i = 0; i < sz; ++i) { + expr* var; + ptr_vector vars; + func_decl* fn0 = m_pt.sig(i); + func_decl* fn1 = pm.o2n(fn0, 0); + sort* srt = fn0->get_range(); + if (a.is_int_real(srt)) { + for (unsigned j = 0; j < num_vars; ++j) { + if (!m_vars[j].find(fn1, var)) { + var = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); + m_trail.push_back(var); + m_vars[j].insert(fn1, var); + } + vars.push_back(var); + } + fmls.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(num_vars, vars.c_ptr()))); + } + } + if (m_is_closure) { + for (unsigned i = 0; i < num_vars; ++i) { + fmls.push_back(a.mk_ge(m_sigma[i].get(), a.mk_numeral(rational(0), a.mk_real()))); + } + } + else { + // is interior: + for (unsigned i = 0; i < num_vars; ++i) { + fmls.push_back(a.mk_gt(m_sigma[i].get(), a.mk_numeral(rational(0), a.mk_real()))); + } + } + fmls.push_back(m.mk_eq(a.mk_numeral(rational(1), a.mk_real()), a.mk_add(num_vars, m_sigma.c_ptr()))); + } + + expr_ref closure::close_fml(expr* e) { + expr* e0, *e1, *e2; + expr_ref result(m); + if (a.is_lt(e, e1, e2)) { + result = a.mk_le(e1, e2); + } + else if (a.is_gt(e, e1, e2)) { + result = a.mk_ge(e1, e2); + } + else if (m.is_not(e, e0) && a.is_ge(e0, e1, e2)) { + result = a.mk_le(e1, e2); + } + else if (m.is_not(e, e0) && a.is_le(e0, e1, e2)) { + result = a.mk_ge(e1, e2); + } + else if (a.is_ge(e) || a.is_le(e) || m.is_eq(e) || + (m.is_not(e, e0) && (a.is_gt(e0) || a.is_lt(e0)))) { + result = e; + } + else { + IF_VERBOSE(1, verbose_stream() << "Cannot close: " << mk_pp(e, m) << "\n";); + } + return result; + } + + expr_ref closure::close_conjunction(expr* fml) { + expr_ref_vector fmls(m); + qe::flatten_and(fml, fmls); + for (unsigned i = 0; i < fmls.size(); ++i) { + fmls[i] = close_fml(fmls[i].get()); + } + return expr_ref(m.mk_and(fmls.size(), fmls.c_ptr()), m); + } + + expr_ref closure::relax(unsigned i, expr* fml) { + scaler sc(m); + expr_ref result = sc(fml, m_sigma[i].get(), &m_vars[i]); + return close_conjunction(result); + } + + expr_ref closure::operator()(expr_ref_vector const& As) { + if (As.empty()) { + return expr_ref(m.mk_false(), m); + } + if (As.size() == 1) { + return expr_ref(As[0], m); + } + expr_ref_vector fmls(m); + expr_ref B(m); + add_variables(As.size(), fmls); + for (unsigned i = 0; i < As.size(); ++i) { + fmls.push_back(relax(i, As[i])); + } + B = qe::mk_and(fmls); + return B; + } + +} diff --git a/src/muz/pdr/pdr_closure.h b/src/muz/pdr/pdr_closure.h new file mode 100644 index 000000000..885dbce8d --- /dev/null +++ b/src/muz/pdr/pdr_closure.h @@ -0,0 +1,67 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + pdr_closure.h + +Abstract: + + Utility functions for computing closures. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-9-1. + +Revision History: + +--*/ + +#ifndef _PDR_CLOSURE_H_ +#define _PDR_CLOSURE_H_ + +#include "arith_decl_plugin.h" + +namespace pdr { + + // Arithmetic scaling functor. + // Variables are replaced using + // m_translate. Constants are replaced by + // multiplication with a variable 'k' (scale factor). + class scaler { + ast_manager& m; + arith_util a; + obj_map m_cache[2]; + expr* m_k; + obj_map* m_translate; + public: + scaler(ast_manager& m): m(m), a(m), m_translate(0) {} + expr_ref operator()(expr* e, expr* k, obj_map* translate = 0); + expr_ref undo_k(expr* e, expr* k); + private: + expr_ref scale(expr* e, bool is_mul); + }; + + class pred_transformer; + + class closure { + ast_manager& m; + pred_transformer& m_pt; + arith_util a; + bool m_is_closure; + expr_ref_vector m_sigma; + expr_ref_vector m_trail; + vector > m_vars; + + expr_ref relax(unsigned i, expr* fml); + expr_ref close_conjunction(expr* fml); + expr_ref close_fml(expr* fml); + void add_variables(unsigned num_vars, expr_ref_vector& fmls); + public: + closure(pred_transformer& pt, bool is_closure); + expr_ref operator()(expr_ref_vector const& As); + + }; +} + +#endif diff --git a/src/muz/pdr/pdr_generalizers.cpp b/src/muz/pdr/pdr_generalizers.cpp index 64766ea93..3abf320b2 100644 --- a/src/muz/pdr/pdr_generalizers.cpp +++ b/src/muz/pdr/pdr_generalizers.cpp @@ -148,56 +148,10 @@ namespace pdr { m_farkas_learner.collect_statistics(st); } - expr_ref scaler::operator()(expr* e, expr* k, obj_map* translate) { - m_cache[0].reset(); - m_cache[1].reset(); - m_translate = translate; - m_k = k; - return scale(e, false); - } - - expr_ref scaler::scale(expr* e, bool is_mul) { - expr* r; - if (m_cache[is_mul].find(e, r)) { - return expr_ref(r, m); - } - if (!is_app(e)) { - return expr_ref(e, m); - } - app* ap = to_app(e); - if (m_translate && m_translate->find(ap->get_decl(), r)) { - return expr_ref(r, m); - } - if (!is_mul && a.is_numeral(e)) { - return expr_ref(a.mk_mul(m_k, e), m); - } - expr_ref_vector args(m); - bool is_mul_rec = is_mul || a.is_mul(e); - for (unsigned i = 0; i < ap->get_num_args(); ++i) { - args.push_back(scale(ap->get_arg(i), is_mul_rec)); - } - expr_ref result(m); - result = m.mk_app(ap->get_decl(), args.size(), args.c_ptr()); - m_cache[is_mul].insert(e, result); - return result; - } - - expr_ref scaler::undo_k(expr* e, expr* k) { - expr_safe_replace sub(m); - th_rewriter rw(m); - expr_ref result(e, m); - sub.insert(k, a.mk_numeral(rational(1), false)); - sub(result); - rw(result); - return result; - } core_convex_hull_generalizer::core_convex_hull_generalizer(context& ctx, bool is_closure): core_generalizer(ctx), m(ctx.get_manager()), - a(m), - m_sigma(m), - m_trail(m), m_is_closure(is_closure) { } @@ -224,38 +178,35 @@ namespace pdr { // update with new core. // void core_convex_hull_generalizer::method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores) { - manager& pm = n.pt().get_pdr_manager(); - expr_ref_vector conv1(m), conv2(m), core1(m), core2(m), fmls(m); - unsigned orig_size = new_cores.size(); + expr_ref_vector conv2(m), fmls(m), fml1_2(m); + bool change = false; + if (core.empty()) { new_cores.push_back(std::make_pair(core, uses_level)); return; } - add_variables(n, 2, fmls); - mk_convex(core, 0, conv1); - conv1.append(fmls); - expr_ref fml = n.pt().get_formulas(n.level(), false); - fmls.reset(); - qe::flatten_and(fml, fmls); + closure cl(n.pt(), m_is_closure); + + expr_ref fml1 = qe::mk_and(core); + expr_ref fml2 = n.pt().get_formulas(n.level(), false); + fml1_2.push_back(fml1); + fml1_2.push_back(0); + qe::flatten_and(fml2, fmls); for (unsigned i = 0; i < fmls.size(); ++i) { - fml = m.mk_not(fmls[i].get()); - core2.reset(); - conv2.reset(); - qe::flatten_and(fml, core2); - mk_convex(core2, 1, conv2); - conv2.append(conv1); - expr_ref state = pm.mk_and(conv2); + fml2 = m.mk_not(fmls[i].get()); + fml1_2[1] = fml2; + expr_ref state = cl(fml1_2); TRACE("pdr", tout << "Check states:\n" << mk_pp(state, m) << "\n"; - tout << "Old states:\n" << mk_pp(fml, m) << "\n"; + tout << "Old states:\n" << mk_pp(fml2, m) << "\n"; ); model_node nd(0, state, n.pt(), n.level()); pred_transformer::scoped_farkas sf(n.pt(), true); bool uses_level1 = uses_level; if (l_false == n.pt().is_reachable(nd, &conv2, uses_level1)) { new_cores.push_back(std::make_pair(conv2, uses_level1)); - - expr_ref state1 = pm.mk_and(conv2); + change = true; + expr_ref state1 = qe::mk_and(conv2); TRACE("pdr", tout << mk_pp(state, m) << "\n"; tout << "Generalized to:\n" << mk_pp(state1, m) << "\n";); @@ -264,70 +215,9 @@ namespace pdr { verbose_stream() << "Generalized to:\n" << mk_pp(state1, m) << "\n";); } } - if (!m_is_closure || new_cores.size() == orig_size) { + if (!m_is_closure || !change) { new_cores.push_back(std::make_pair(core, uses_level)); } - - } - - // take as starting point two points from different regions. - void core_convex_hull_generalizer::method2(model_node& n, expr_ref_vector& core, bool& uses_level) { - expr_ref_vector conv1(m), conv2(m), core1(m), core2(m); - if (core.empty()) { - return; - } - manager& pm = n.pt().get_pdr_manager(); - smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); - expr_ref goal(pm.mk_and(core)); - ctx.assert_expr(goal); - lbool r = ctx.check(); - if (r != l_true) { - IF_VERBOSE(0, verbose_stream() << "unexpected result from satisfiability check\n";); - return; - } - add_variables(n, 2, conv1); - model_ref mdl; - ctx.get_model(mdl); - - unsigned sz = n.pt().sig_size(); - for (unsigned i = 0; i < sz; ++i) { - expr_ref_vector constr(m); - expr* left, *right; - func_decl* fn0 = n.pt().sig(i); - func_decl* fn1 = pm.o2n(fn0, 0); - if (m_vars[0].find(fn1, left) && m_vars[1].find(fn1, right)) { - expr_ref val(m); - mdl->eval(fn1, val); - if (val) { - conv1.push_back(m.mk_eq(left, val)); - constr.push_back(m.mk_eq(right, val)); - } - } - expr_ref new_model = pm.mk_and(constr); - m_trail.push_back(new_model); - m_trail.push_back(goal); - m_models.insert(goal, new_model); - } - obj_map::iterator it = m_models.begin(), end = m_models.end(); - for (; it != end; ++it) { - if (it->m_key == goal) { - continue; - } - conv1.push_back(it->m_value); - expr_ref state = pm.mk_and(conv1); - TRACE("pdr", tout << "Try:\n" << mk_pp(state, m) << "\n";); - model_node nd(0, state, n.pt(), n.level()); - pred_transformer::scoped_farkas sf(n.pt(), true); - if (l_false == n.pt().is_reachable(nd, &conv2, uses_level)) { - IF_VERBOSE(0, - verbose_stream() << mk_pp(state, m) << "\n"; - verbose_stream() << "Generalized to:\n" << mk_pp(pm.mk_and(conv2), m) << "\n";); - core.reset(); - core.append(conv2); - return; - } - conv1.pop_back(); - } } /* @@ -339,7 +229,6 @@ namespace pdr { for (unsigned i = 0; i < core.size(); ++i) { tout << "B:" << mk_pp(core[i], m) << "\n"; }); - manager& pm = n.pt().get_pdr_manager(); bool uses_level1; expr_ref_vector core1(m); core1.append(core); @@ -395,13 +284,14 @@ namespace pdr { bool core_convex_hull_generalizer::strengthen_consequences(model_node& n, expr_ref_vector& As, expr* B) { expr_ref A(m), tmp(m), convA(m); unsigned sz = As.size(); + closure cl(n.pt(), m_is_closure); for (unsigned i = 0; i < As.size(); ++i) { expr_ref_vector Hs(m); Hs.push_back(As[i].get()); for (unsigned j = i + 1; j < As.size(); ++j) { Hs.push_back(As[j].get()); bool unsat = false; - mk_convex(n, Hs, A); + A = cl(Hs); tmp = As[i].get(); As[i] = A; unsat = is_unsat(As, B); @@ -424,16 +314,6 @@ namespace pdr { return sz > As.size(); } - void core_convex_hull_generalizer::mk_convex(model_node& n, expr_ref_vector const& Hs, expr_ref& A) { - expr_ref_vector fmls(m), es(m); - add_variables(n, Hs.size(), fmls); - for (unsigned i = 0; i < Hs.size(); ++i) { - es.reset(); - qe::flatten_and(Hs[i], es); - mk_convex(es, i, fmls); - } - A = m.mk_and(fmls.size(), fmls.c_ptr()); - } bool core_convex_hull_generalizer::is_unsat(expr_ref_vector const& As, expr* B) { smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); @@ -445,91 +325,6 @@ namespace pdr { return l_false == ctx.check(); } - void core_convex_hull_generalizer::add_variables(model_node& n, unsigned num_vars, expr_ref_vector& fmls) { - manager& pm = n.pt().get_pdr_manager(); - SASSERT(num_vars > 0); - while (m_vars.size() < num_vars) { - m_vars.resize(m_vars.size()+1); - m_sigma.push_back(m.mk_fresh_const("sigma", a.mk_real())); - } - - unsigned sz = n.pt().sig_size(); - - for (unsigned i = 0; i < sz; ++i) { - expr* var; - ptr_vector vars; - func_decl* fn0 = n.pt().sig(i); - func_decl* fn1 = pm.o2n(fn0, 0); - sort* srt = fn0->get_range(); - if (a.is_int_real(srt)) { - for (unsigned j = 0; j < num_vars; ++j) { - if (!m_vars[j].find(fn1, var)) { - var = m.mk_fresh_const(fn1->get_name().str().c_str(), srt); - m_trail.push_back(var); - m_vars[j].insert(fn1, var); - } - vars.push_back(var); - } - fmls.push_back(m.mk_eq(m.mk_const(fn1), a.mk_add(num_vars, vars.c_ptr()))); - } - } - if (m_is_closure) { - for (unsigned i = 0; i < num_vars; ++i) { - fmls.push_back(a.mk_ge(m_sigma[i].get(), a.mk_numeral(rational(0), a.mk_real()))); - } - } - else { - // is interior: - for (unsigned i = 0; i < num_vars; ++i) { - fmls.push_back(a.mk_gt(m_sigma[i].get(), a.mk_numeral(rational(0), a.mk_real()))); - } - } - fmls.push_back(m.mk_eq(a.mk_numeral(rational(1), a.mk_real()), a.mk_add(num_vars, m_sigma.c_ptr()))); - } - - expr_ref core_convex_hull_generalizer::mk_closure(expr* e) { - expr* e0, *e1, *e2; - expr_ref result(m); - if (a.is_lt(e, e1, e2)) { - result = a.mk_le(e1, e2); - } - else if (a.is_gt(e, e1, e2)) { - result = a.mk_ge(e1, e2); - } - else if (m.is_not(e, e0) && a.is_ge(e0, e1, e2)) { - result = a.mk_le(e1, e2); - } - else if (m.is_not(e, e0) && a.is_le(e0, e1, e2)) { - result = a.mk_ge(e1, e2); - } - else if (a.is_ge(e) || a.is_le(e) || m.is_eq(e) || - (m.is_not(e, e0) && (a.is_gt(e0) || a.is_lt(e0)))) { - result = e; - } - else { - IF_VERBOSE(1, verbose_stream() << "Cannot close: " << mk_pp(e, m) << "\n";); - } - return result; - } - - bool core_convex_hull_generalizer::mk_closure(expr_ref_vector& conj) { - for (unsigned i = 0; i < conj.size(); ++i) { - conj[i] = mk_closure(conj[i].get()); - if (!conj[i].get()) { - return false; - } - } - return true; - } - - void core_convex_hull_generalizer::mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv) { - scaler sc(m); - for (unsigned i = 0; i < core.size(); ++i) { - conv.push_back(sc(core[i], m_sigma[index].get(), &m_vars[index])); - } - mk_closure(conv); - } - // --------------------------------- // core_arith_inductive_generalizer @@ -800,7 +595,7 @@ namespace pdr { for (unsigned i = ut_size; i < t_size; i++) { conj.push_back(rule.get_tail(i)); } - result = pm.mk_and(conj); + result = qe::mk_and(conj); if (!sub.empty()) { expr_ref tmp = result; var_subst(m, false)(tmp, sub.size(), sub.c_ptr(), result); @@ -983,73 +778,3 @@ namespace pdr { } }; -#if 0 - // now create the convex closure of the consequences: - expr_ref tmp(m), zero(m); - expr_ref_vector conv(m), es(m), enabled(m); - zero = a.mk_numeral(rational(0), a.mk_real()); - add_variables(n, consequences.size(), conv); - for (unsigned i = 0; i < consequences.size(); ++i) { - es.reset(); - tmp = m.mk_not(consequences[i].get()); - qe::flatten_and(tmp, es); - mk_convex(es, i, conv); - es.reset(); - // - // enabled[i] = not (sigma_i = 0 and z_i1 = 0 and .. and z_im = 0) - // - es.push_back(m.mk_eq(m_sigma[i].get(), zero)); - for (unsigned j = 0; j < n.pt().sig_size(); ++j) { - func_decl* fn0 = n.pt().sig(j); - func_decl* fn1 = pm.o2n(fn0, 0); - expr* var; - VERIFY (m_vars[i].find(fn1, var)); - es.push_back(m.mk_eq(var, zero)); - } - - enabled.push_back(m.mk_not(m.mk_and(es.size(), es.c_ptr()))); - } - - // the convex closure was created of all consequences. - // now determine a subset of enabled constraints. - smt::kernel ctx(m, m_ctx.get_fparams(), m_ctx.get_params().p); - for (unsigned i = 0; i < conv.size(); ++i) { - ctx.assert_expr(conv[i].get()); - IF_VERBOSE(0, verbose_stream() << "CC: " << mk_pp(conv[i].get(), m) << "\n";); - } - for (unsigned i = 0; i < core.size(); ++i) { - ctx.assert_expr(core[i]); - IF_VERBOSE(0, verbose_stream() << "Co: " << mk_pp(core[i], m) << "\n";); - } - vector transversal; - while (l_true == ctx.check()) { - model_ref md; - ctx.get_model(md); - IF_VERBOSE(0, - ctx.display(verbose_stream()); - verbose_stream() << "\n"; - model_smt2_pp(verbose_stream(), m, *md.get(), 0);); - expr_ref_vector lits(m); - unsigned_vector pos; - for (unsigned i = 0; i < consequences.size(); ++i) { - if (md->eval(enabled[i].get(), tmp, false)) { - IF_VERBOSE(0, - verbose_stream() << mk_pp(enabled[i].get(), m) << " |-> " << mk_pp(tmp, m) << "\n";); - if (m.is_true(tmp)) { - lits.push_back(tmp); - pos.push_back(i); - } - } - } - transversal.push_back(pos); - SASSERT(!lits.empty()); - tmp = m.mk_not(m.mk_and(lits.size(), lits.c_ptr())); - TRACE("pdr", tout << "add block: " << mk_pp(tmp, m) << "\n";); - ctx.assert_expr(tmp); - } - // - // we could no longer satisfy core using a partition. - // - IF_VERBOSE(0, verbose_stream() << "TBD: tranverse\n";); -#endif - diff --git a/src/muz/pdr/pdr_generalizers.h b/src/muz/pdr/pdr_generalizers.h index ca9c5a969..be04ec646 100644 --- a/src/muz/pdr/pdr_generalizers.h +++ b/src/muz/pdr/pdr_generalizers.h @@ -21,6 +21,7 @@ Revision History: #define _PDR_GENERALIZERS_H_ #include "pdr_context.h" +#include "pdr_closure.h" #include "arith_decl_plugin.h" namespace pdr { @@ -73,45 +74,15 @@ namespace pdr { virtual void collect_statistics(statistics& st) const; }; - // Arithmetic scaling functor. - // Variables are replaced using - // m_translate. Constants are replaced by - // multiplication with a variable 'k' (scale factor). - class scaler { - ast_manager& m; - arith_util a; - obj_map m_cache[2]; - expr* m_k; - obj_map* m_translate; - public: - scaler(ast_manager& m): m(m), a(m), m_translate(0) {} - expr_ref operator()(expr* e, expr* k, obj_map* translate = 0); - expr_ref undo_k(expr* e, expr* k); - private: - expr_ref scale(expr* e, bool is_mul); - }; class core_convex_hull_generalizer : public core_generalizer { ast_manager& m; - arith_util a; - expr_ref_vector m_sigma; - expr_ref_vector m_trail; - vector > m_vars; obj_map m_models; bool m_is_closure; - expr_ref mk_closure(expr* e); - bool mk_closure(expr_ref_vector& conj); - void mk_convex(expr_ref_vector const& core, unsigned index, expr_ref_vector& conv); - void mk_convex(expr* fml, unsigned index, expr_ref_vector& conv); - void mk_convex(expr* term, unsigned index, bool is_mul, expr_ref& result); - bool translate(func_decl* fn, unsigned index, expr_ref& result); void method1(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); - void method2(model_node& n, expr_ref_vector& core, bool& uses_level); void method3(model_node& n, expr_ref_vector const& core, bool uses_level, cores& new_cores); bool strengthen_consequences(model_node& n, expr_ref_vector& As, expr* B); bool is_unsat(expr_ref_vector const& As, expr* B); - void mk_convex(model_node& n, expr_ref_vector const& Hs, expr_ref& A); - void add_variables(model_node& n, unsigned num_vars, expr_ref_vector& fmls); public: core_convex_hull_generalizer(context& ctx, bool is_closure); virtual ~core_convex_hull_generalizer() {} diff --git a/src/qe/qe_util.cpp b/src/qe/qe_util.cpp index 629fe4b56..77396ac49 100644 --- a/src/qe/qe_util.cpp +++ b/src/qe/qe_util.cpp @@ -1,4 +1,5 @@ #include "qe_util.h" +#include "bool_rewriter.h" namespace qe { void flatten_and(expr_ref_vector& result) { @@ -113,4 +114,19 @@ namespace qe { result.push_back(fml); flatten_or(result); } + + expr_ref mk_and(expr_ref_vector const& fmls) { + ast_manager& m = fmls.get_manager(); + expr_ref result(m); + bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), result); + return result; + } + + expr_ref mk_or(expr_ref_vector const& fmls) { + ast_manager& m = fmls.get_manager(); + expr_ref result(m); + bool_rewriter(m).mk_or(fmls.size(), fmls.c_ptr(), result); + return result; + } + } diff --git a/src/qe/qe_util.h b/src/qe/qe_util.h index 7e1fe7f79..f1a99ec6c 100644 --- a/src/qe/qe_util.h +++ b/src/qe/qe_util.h @@ -33,5 +33,9 @@ namespace qe { void flatten_or(expr* fml, expr_ref_vector& result); + expr_ref mk_and(expr_ref_vector const& fmls); + + expr_ref mk_or(expr_ref_vector const& fmls); + } #endif From 929d9f430bcc63efd42993d3ca9ed380067249ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 Sep 2013 13:45:02 -0700 Subject: [PATCH 256/281] refactor closure code Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_closure.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muz/pdr/pdr_closure.cpp b/src/muz/pdr/pdr_closure.cpp index 483b48932..3a450a68d 100644 --- a/src/muz/pdr/pdr_closure.cpp +++ b/src/muz/pdr/pdr_closure.cpp @@ -135,6 +135,7 @@ namespace pdr { result = e; } else { + result = e; IF_VERBOSE(1, verbose_stream() << "Cannot close: " << mk_pp(e, m) << "\n";); } return result; From fcc351eba66a05e8d130832d81a894b4cb01fa9f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 1 Sep 2013 13:50:18 -0700 Subject: [PATCH 257/281] refactor closure code Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_closure.cpp | 6 +++--- src/muz/pdr/pdr_generalizers.cpp | 15 +++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/muz/pdr/pdr_closure.cpp b/src/muz/pdr/pdr_closure.cpp index 3a450a68d..86af8b2f9 100644 --- a/src/muz/pdr/pdr_closure.cpp +++ b/src/muz/pdr/pdr_closure.cpp @@ -135,8 +135,8 @@ namespace pdr { result = e; } else { - result = e; IF_VERBOSE(1, verbose_stream() << "Cannot close: " << mk_pp(e, m) << "\n";); + result = m.mk_true(); } return result; } @@ -145,9 +145,9 @@ namespace pdr { expr_ref_vector fmls(m); qe::flatten_and(fml, fmls); for (unsigned i = 0; i < fmls.size(); ++i) { - fmls[i] = close_fml(fmls[i].get()); + fmls[i] = close_fml(fmls[i].get()); } - return expr_ref(m.mk_and(fmls.size(), fmls.c_ptr()), m); + return qe::mk_and(fmls); } expr_ref closure::relax(unsigned i, expr* fml) { diff --git a/src/muz/pdr/pdr_generalizers.cpp b/src/muz/pdr/pdr_generalizers.cpp index 3abf320b2..7c2557260 100644 --- a/src/muz/pdr/pdr_generalizers.cpp +++ b/src/muz/pdr/pdr_generalizers.cpp @@ -116,11 +116,10 @@ namespace pdr { void core_farkas_generalizer::operator()(model_node& n, expr_ref_vector& core, bool& uses_level) { ast_manager& m = n.pt().get_manager(); - manager& pm = n.pt().get_pdr_manager(); if (core.empty()) return; - expr_ref A(m), B(pm.mk_and(core)), C(m); + expr_ref A(m), B(qe::mk_and(core)), C(m); expr_ref_vector Bs(m); - pm.get_or(B, Bs); + qe::flatten_or(B, Bs); A = n.pt().get_propagation_formula(m_ctx.get_pred_transformers(), n.level()); bool change = false; @@ -130,13 +129,13 @@ namespace pdr { if (m_farkas_learner.get_lemma_guesses(A, B, lemmas)) { TRACE("pdr", tout << "Old core:\n" << mk_pp(B, m) << "\n"; - tout << "New core:\n" << mk_pp(pm.mk_and(lemmas), m) << "\n";); - Bs[i] = pm.mk_and(lemmas); + tout << "New core:\n" << mk_pp(qe::mk_and(lemmas), m) << "\n";); + Bs[i] = qe::mk_and(lemmas); change = true; } } if (change) { - C = pm.mk_or(Bs); + C = qe::mk_or(Bs); TRACE("pdr", tout << "prop:\n" << mk_pp(A,m) << "\ngen:" << mk_pp(B, m) << "\nto: " << mk_pp(C, m) << "\n";); core.reset(); qe::flatten_and(C, core); @@ -688,7 +687,7 @@ namespace pdr { for (unsigned i = 0; i < rules.size(); ++i) { fmls.push_back(m.mk_not(mk_transition_rule(reps, level, *rules[i]))); } - fml = pm.mk_and(fmls); + fml = qe::mk_and(fmls); TRACE("pdr", tout << mk_pp(fml, m) << "\n";); return fml; } @@ -744,7 +743,7 @@ namespace pdr { } } - expr_ref result = pm.mk_and(conjs); + expr_ref result = qe::mk_and(conjs); TRACE("pdr", tout << mk_pp(result, m) << "\n";); return result; } From 878905c13c3b2a1486dbd6d0511f313513517aab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Sep 2013 19:43:22 -0700 Subject: [PATCH 258/281] Adding overflow checks Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_sparse_table.cpp | 7 +++++-- src/muz/rel/dl_sparse_table.h | 3 +++ src/test/vector.cpp | 18 +++++++++++++++--- src/util/vector.h | 8 +++++++- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index 52d9618b8..c9bdec0b6 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -1066,11 +1066,14 @@ namespace datalog { unsigned res_fact_size = res->m_fact_size; unsigned res_data_size = res_fact_size*t.row_count(); + if (res_fact_size != 0 && (res_data_size / res_fact_size) != t.row_count()) { + throw default_exception("multiplication overflow"); + } res->m_data.resize_data(res_data_size); - //here we can separate data creatin and insertion into hashmap, since we know - //that no row will become duplicit + //here we can separate data creating and insertion into hashmap, since we know + //that no row will become duplicate //create the data const char* t_ptr = t.m_data.begin(); diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h index 010277b6b..5c5f95a75 100644 --- a/src/muz/rel/dl_sparse_table.h +++ b/src/muz/rel/dl_sparse_table.h @@ -275,6 +275,9 @@ namespace datalog { //the following two operations allow breaking of the object invariant! void resize_data(unsigned sz) { m_data_size = sz; + if (sz + sizeof(uint64) < sz) { + throw default_exception("overflow resizing data section for sparse table"); + } m_data.resize(sz + sizeof(uint64)); } diff --git a/src/test/vector.cpp b/src/test/vector.cpp index 0a3904954..86ae997ca 100644 --- a/src/test/vector.cpp +++ b/src/test/vector.cpp @@ -19,7 +19,7 @@ Revision History: #include"vector.h" static void tst1() { - vector v1; + svector v1; SASSERT(v1.empty()); for (unsigned i = 0; i < 1000; i++) { v1.push_back(i + 3); @@ -30,8 +30,8 @@ static void tst1() { for (unsigned i = 0; i < 1000; i++) { SASSERT(static_cast(v1[i]) == i + 3); } - vector::iterator it = v1.begin(); - vector::iterator end = v1.end(); + svector::iterator it = v1.begin(); + svector::iterator end = v1.end(); for (int i = 0; it != end; ++it, ++i) { SASSERT(*it == i + 3); } @@ -42,6 +42,18 @@ static void tst1() { } SASSERT(v1.empty()); SASSERT(v1.size() == 0); + unsigned i = 1000000000; + while (true) { + std::cout << "resize " << i << "\n"; + try { + v1.resize(i); + } + catch (z3_exception& e) { + std::cout << e.msg() << "\n"; + break; + } + i *= 2; + } } void tst_vector() { diff --git a/src/util/vector.h b/src/util/vector.h index c9ed900a9..8bfe7c703 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -29,6 +29,7 @@ Revision History: #include #include"memory_manager.h" #include"hash.h" +#include"z3_exception.h" // disable warning for constant 'if' expressions. // these are used heavily in templates. @@ -67,9 +68,14 @@ class vector { else { SASSERT(capacity() > 0); unsigned old_capacity = reinterpret_cast(m_data)[CAPACITY_IDX]; + unsigned old_capacity_T = sizeof(T) * old_capacity + sizeof(unsigned) * 2; unsigned new_capacity = (3 * old_capacity + 1) >> 1; + unsigned new_capacity_T = sizeof(T) * new_capacity + sizeof(unsigned) * 2; unsigned size = reinterpret_cast(m_data)[SIZE_IDX]; - unsigned * mem = reinterpret_cast(memory::allocate(sizeof(T) * new_capacity + sizeof(unsigned) * 2)); + if (new_capacity <= old_capacity || new_capacity_T <= old_capacity_T) { + throw default_exception("Overflow encountered when expanding vector"); + } + unsigned * mem = reinterpret_cast(memory::allocate(new_capacity_T)); *mem = new_capacity; mem ++; *mem = size; From 1cf2b7c2d3ea69c459c8cd0c0bc19518559dce4e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 2 Sep 2013 21:22:44 -0700 Subject: [PATCH 259/281] remove unused reference to rm Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_subsumption_checker.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/muz/transforms/dl_mk_subsumption_checker.cpp b/src/muz/transforms/dl_mk_subsumption_checker.cpp index 9b2c5627b..1967fdc93 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.cpp +++ b/src/muz/transforms/dl_mk_subsumption_checker.cpp @@ -252,7 +252,6 @@ namespace datalog { if (!rel) { return; } - relation_manager& rm = rel->get_rmanager(); func_decl_set const& candidate_preds = m_context.get_predicates(); From 7c4b2b04a7f8a24c0338153781e2029eb575be69 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 4 Sep 2013 08:54:02 -0700 Subject: [PATCH 260/281] fix coi-filter to not ignore relational tables Signed-off-by: Nikolaj Bjorner --- src/muz/transforms/dl_mk_coi_filter.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index fc4c411ff..8583fbe45 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -52,10 +52,14 @@ namespace datalog { ptr_vector todo; rule_set::decl2rules body2rules; // initialization for reachability + rel_context_base* rc = m_context.get_rel_context(); for (rule_set::iterator it = source.begin(); it != source.end(); ++it) { rule * r = *it; all.insert(r->get_decl()); - if (r->get_uninterpreted_tail_size() == 0) { + bool non_empty = + (rc && !rc->is_empty_relation(r->get_decl())) || + r->get_uninterpreted_tail_size() == 0; + if (non_empty) { if (!reached.contains(r->get_decl())) { reached.insert(r->get_decl()); todo.insert(r->get_decl()); From 5908e24728c4fef4017d66abd7d315137cee0fb2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Sep 2013 09:36:15 -0700 Subject: [PATCH 261/281] fix bug missing NNF of equality as IFF reported by Sticksel Signed-off-by: Nikolaj Bjorner --- src/qe/qe.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index d0aafb896..d63f0ae00 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -482,7 +482,7 @@ namespace qe { } void nnf_iff(app* a, bool p) { - SASSERT(m.is_iff(a) || m.is_xor(a)); + SASSERT(m.is_iff(a) || m.is_xor(a) || m.is_eq(a)); expr* a0 = a->get_arg(0); expr* a1 = a->get_arg(1); @@ -616,7 +616,7 @@ namespace qe { else if (m.is_ite(a)) { nnf_ite(a, p); } - else if (m.is_iff(a)) { + else if (m.is_iff(a) || (m.is_eq(a) && m.is_bool(a->get_arg(0)))) { nnf_iff(a, p); } else if (m.is_xor(a)) { @@ -1926,6 +1926,7 @@ namespace qe { plugin(x).get_num_branches(contains(x), fml, num_branches)) { return true; } + TRACE("qe", tout << "setting variable " << mk_pp(x, m) << " free\n";); m_free_vars.push_back(x); m_current->del_var(x); } @@ -2493,6 +2494,7 @@ namespace qe { // callback to replace variable at index 'idx' with definition 'def' and updated formula 'fml' virtual void elim_var(unsigned idx, expr* fml, expr* def) { + TRACE("qe", tout << mk_pp(m_vars->get(idx), m) << " " << mk_pp(fml, m) << "\n";); *m_fml = fml; m_vars->set(idx, m_vars->get(m_vars->size()-1)); m_vars->pop_back(); From 457b22b00e23512113b2de5a1dd85f3e36cd1ad9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Sep 2013 21:49:00 -0700 Subject: [PATCH 262/281] add TPTP example Signed-off-by: Nikolaj Bjorner --- examples/tptp/README | 18 + examples/tptp/tptp5.cpp | 2480 +++++++++++++++++ examples/tptp/tptp5.h | 38 + examples/tptp/tptp5.lex.cpp | 2672 ++++++++++++++++++ examples/tptp/tptp5.tab.c | 4475 +++++++++++++++++++++++++++++++ examples/tptp/tptp5.tab.h | 138 + scripts/mk_project.py | 1 + scripts/mk_util.py | 13 +- src/api/c++/z3++.h | 29 + src/muz/base/dl_util.h | 2 +- src/muz/rel/dl_sparse_table.cpp | 32 +- src/muz/rel/dl_sparse_table.h | 10 +- src/util/vector.h | 114 +- 13 files changed, 9943 insertions(+), 79 deletions(-) create mode 100644 examples/tptp/README create mode 100644 examples/tptp/tptp5.cpp create mode 100644 examples/tptp/tptp5.h create mode 100644 examples/tptp/tptp5.lex.cpp create mode 100644 examples/tptp/tptp5.tab.c create mode 100644 examples/tptp/tptp5.tab.h diff --git a/examples/tptp/README b/examples/tptp/README new file mode 100644 index 000000000..c28a53da4 --- /dev/null +++ b/examples/tptp/README @@ -0,0 +1,18 @@ +TPTP front-end and utilities as a sample using the C++ bindings. +To build the example execute + make examples +in the build directory. + +This command will create the executable tptp. +On Windows, you can just execute it. +On OSX and Linux, you must install z3 first using + sudo make install +OR update LD_LIBRARY_PATH (Linux) or DYLD_LIBRARY_PATH (OSX) + with the build directory. You need that to be able to + find the Z3 shared library. + +The sample illustrates using Z3 from the TPTP language. +The TPTP language is documented on http://tptp.org +It also exposes utilities for converting between SMT-LIB +and TPTP format. + diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp new file mode 100644 index 000000000..1f50bdfea --- /dev/null +++ b/examples/tptp/tptp5.cpp @@ -0,0 +1,2480 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "z3++.h" + +struct alloc_region { + std::list m_alloc; + + void * allocate(size_t s) { + char * res = new char[s]; + m_alloc.push_back(res); + return res; + } + + ~alloc_region() { + std::list::iterator it = m_alloc.begin(), end = m_alloc.end(); + for (; it != end; ++it) { + delete *it; + } + } +}; + +template +class flet { + T & m_ref; + T m_old; +public: + flet(T& x, T const& y): m_ref(x), m_old(x) { x = y; } + ~flet() { m_ref = m_old; } +}; + +struct symbol_compare { + bool operator()(z3::symbol const& s1, z3::symbol const& s2) const { + return s1 < s2; + }; +}; + + +template +struct symbol_table { + typedef std::map map; + map m_map; + + void insert(z3::symbol s, T val) { + m_map.insert(std::pair(s, val)); + } + + bool find(z3::symbol const& s, T& val) { + typename map::iterator it = m_map.find(s); + if (it == m_map.end()) { + return false; + } + else { + val = it->second; + return true; + } + } +}; + + +typedef std::set symbol_set; + + +struct named_formulas { + std::vector m_formulas; + std::vector m_names; + std::vector m_files; + bool m_has_conjecture; + + named_formulas(): m_has_conjecture(false) {} + + void push_back(z3::expr fml, char const * name, char const* file) { + m_formulas.push_back(fml); + m_names.push_back(name); + m_files.push_back(file); + } + + void set_has_conjecture() { + m_has_conjecture = true; + } + + bool has_conjecture() const { + return m_has_conjecture; + } +}; + +inline void * operator new(size_t s, alloc_region & r) { return r.allocate(s); } + +inline void * operator new[](size_t s, alloc_region & r) { return r.allocate(s); } + +inline void operator delete(void *, alloc_region & ) { /* do nothing */ } + +inline void operator delete[](void *, alloc_region & ) { /* do nothing */ } + +struct failure_ex { + std::string msg; + failure_ex(char const* m):msg(m) {} +}; + + +extern char* tptp_lval[]; +extern int yylex(); + +static char* strdup(alloc_region& r, char const* s) { + size_t l = strlen(s) + 1; + char* result = new (r) char[l]; + memcpy(result, s, l); + return result; +} + +class TreeNode { + char const* m_symbol; + int m_symbol_index; + TreeNode** m_children; + +public: + TreeNode(alloc_region& r, char const* sym, + TreeNode* A, TreeNode* B, TreeNode* C, TreeNode* D, TreeNode* E, + TreeNode* F, TreeNode* G, TreeNode* H, TreeNode* I, TreeNode* J): + m_symbol(strdup(r, sym)), + m_symbol_index(-1) { + m_children = new (r) TreeNode*[10]; + m_children[0] = A; + m_children[1] = B; + m_children[2] = C; + m_children[3] = D; + m_children[4] = E; + m_children[5] = F; + m_children[6] = G; + m_children[7] = H; + m_children[8] = I; + m_children[9] = J; + + } + + char const* symbol() const { return m_symbol; } + TreeNode *const* children() const { return m_children; } + TreeNode* child(unsigned i) const { return m_children[i]; } + int index() const { return m_symbol_index; } + + void set_index(int idx) { m_symbol_index = idx; } +}; + +TreeNode* MkToken(alloc_region& r, char* token, int symbolIndex) { + TreeNode* ss; + char* symbol = tptp_lval[symbolIndex]; + ss = new (r) TreeNode(r, symbol, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); + ss->set_index(symbolIndex); + return ss; +} + + +// ------------------------------------------------------ +// Build Z3 formulas. + +class env { + z3::context& m_context; + z3::expr_vector m_bound; // vector of bound constants. + z3::sort m_univ; + symbol_table m_decls; + symbol_table m_defined_sorts; + static std::vector* m_nodes; + static alloc_region* m_region; + char const* m_filename; + + + enum binary_connective { + IFF, + IMPLIES, + IMPLIED, + LESS_TILDE_GREATER, + TILDE_VLINE + }; + + void mk_error(TreeNode* f, char const* msg) { + std::ostringstream strm; + strm << "expected: " << msg << "\n"; + strm << "got: " << f->symbol(); + throw failure_ex(strm.str().c_str()); + } + + void mk_not_handled(TreeNode* f, char const* msg) { + std::ostringstream strm; + strm << "Construct " << f->symbol() << " not handled: " << msg; + throw failure_ex(strm.str().c_str()); + } + + void mk_input(TreeNode* f, named_formulas& fmls) { + if (!strcmp(f->symbol(),"annotated_formula")) { + mk_annotated_formula(f->child(0), fmls); + } + else if (!strcmp(f->symbol(),"include")) { + mk_include(f->child(2), f->child(3), fmls); + } + else { + mk_error(f, "annotated formula or include"); + } + } + + void mk_annotated_formula(TreeNode* f, named_formulas& fmls) { + if (!strcmp(f->symbol(),"fof_annotated")) { + fof_annotated(f->child(2), f->child(4), f->child(6), f->child(7), fmls); + } + else if (!strcmp(f->symbol(),"tff_annotated")) { + fof_annotated(f->child(2), f->child(4), f->child(6), f->child(7), fmls); + } + else if (!strcmp(f->symbol(),"cnf_annotated")) { + cnf_annotated(f->child(2), f->child(4), f->child(6), f->child(7), fmls); + } + else if (!strcmp(f->symbol(),"thf_annotated")) { + mk_error(f, "annotated formula (not thf)"); + } + else { + mk_error(f, "annotated formula"); + } + } + + void check_arity(unsigned num_args, unsigned arity) { + if (num_args != arity) { + throw failure_ex("arity missmatch"); + } + } + + void mk_include(TreeNode* file_name, TreeNode* formula_selection, named_formulas& fmls) { + char const* fn = file_name->child(0)->symbol(); + TreeNode* name_list = formula_selection->child(2); + if (name_list && !strcmp("null",name_list->symbol())) { + name_list = 0; + } + std::string inc_name; + bool f_exists = false; + for (unsigned i = 1; !f_exists && i <= 3; ++i) { + inc_name.clear(); + f_exists = mk_filename(fn, i, inc_name); + + } + if (!f_exists) { + inc_name.clear(); + f_exists = mk_env_filename(fn, inc_name); + } + if (!f_exists) { + inc_name = fn; + } + + parse(inc_name.c_str(), fmls); + while (name_list) { + return mk_error(name_list, "name list (not handled)"); + char const* name = name_list->child(0)->symbol(); + name_list = name_list->child(2); + } + } + +#define CHECK(_node_) if (0 != strcmp(_node_->symbol(),#_node_)) return mk_error(_node_,#_node_); + + const char* get_name(TreeNode* name) { + if (!name->child(0)) { + mk_error(name, "node with a child"); + } + if (!name->child(0)->child(0)) { + return name->child(0)->symbol(); + } + return name->child(0)->child(0)->symbol(); + } + + z3::expr mk_forall(z3::expr_vector& bound, z3::expr body) { + return mk_quantifier(true, bound, body); + } + + z3::expr mk_quantifier(bool is_forall, z3::expr_vector& bound, z3::expr body) { + Z3_app* vars = new Z3_app[bound.size()]; + for (unsigned i = 0; i < bound.size(); ++i) { + vars[i] = (Z3_app) bound[i]; + } + Z3_ast r = Z3_mk_quantifier_const(m_context, is_forall, 1, bound.size(), vars, 0, 0, body); + delete[] vars; + return z3::expr(m_context, r); + } + + void cnf_annotated(TreeNode* name, TreeNode* formula_role, TreeNode* formula, TreeNode* annotations, named_formulas& fmls) { + symbol_set st; + get_cnf_variables(formula, st); + symbol_set::iterator it = st.begin(), end = st.end(); + std::vector names; + m_bound.resize(0); + for(; it != end; ++it) { + names.push_back(*it); + m_bound.push_back(m_context.constant(names.back(), m_univ)); + } + z3::expr r(m_context); + cnf_formula(formula, r); + if (!m_bound.empty()) { + r = mk_forall(m_bound, r); + } + char const* role = formula_role->child(0)->symbol(); + if (!strcmp(role,"conjecture")) { + fmls.set_has_conjecture(); + r = !r; + } + fmls.push_back(r, get_name(name), m_filename); + m_bound.resize(0); + } + + void cnf_formula(TreeNode* formula, z3::expr& r) { + std::vector disj; + if (formula->child(1)) { + disjunction(formula->child(1), disj); + } + else { + disjunction(formula->child(0), disj); + } + if (disj.size() > 0) { + r = disj[0]; + } + else { + r = m_context.bool_val(false); + } + for (unsigned i = 1; i < disj.size(); ++i) { + r = r || disj[i]; + } + } + + void disjunction(TreeNode* d, std::vector& r) { + z3::expr lit(m_context); + if (d->child(2)) { + disjunction(d->child(0), r); + literal(d->child(2), lit); + r.push_back(lit); + } + else { + literal(d->child(0), lit); + r.push_back(lit); + } + } + + void literal(TreeNode* l, z3::expr& lit) { + if (!strcmp(l->child(0)->symbol(),"~")) { + fof_formula(l->child(1), lit); + lit = !lit; + } + else { + fof_formula(l->child(0), lit); + } + } + + void fof_annotated(TreeNode* name, TreeNode* formula_role, TreeNode* formula, TreeNode* annotations, named_formulas& fmls) { + z3::expr fml(m_context); + //CHECK(fof_formula); + CHECK(formula_role); + fof_formula(formula->child(0), fml); + char const* role = formula_role->child(0)->symbol(); + if (!strcmp(role,"conjecture")) { + fmls.set_has_conjecture(); + fmls.push_back(!fml, get_name(name), m_filename); + } + else if (!strcmp(role,"type")) { + } + else { + fmls.push_back(fml, get_name(name), m_filename); + } + } + + void fof_formula(TreeNode* f, z3::expr& fml) { + z3::expr f1(m_context); + char const* name = f->symbol(); + if (!strcmp(name,"fof_logic_formula") || + !strcmp(name,"fof_binary_assoc") || + !strcmp(name,"fof_binary_formula") || + !strcmp(name,"tff_logic_formula") || + !strcmp(name,"tff_binary_assoc") || + !strcmp(name,"tff_binary_formula") || + !strcmp(name,"atomic_formula") || + !strcmp(name,"defined_atomic_formula")) { + fof_formula(f->child(0), fml); + } + else if (!strcmp(name, "fof_sequent") || + !strcmp(name, "tff_sequent")) { + fof_formula(f->child(0), f1); + fof_formula(f->child(2), fml); + fml = implies(f1, fml); + } + else if (!strcmp(name, "fof_binary_nonassoc") || + !strcmp(name, "tff_binary_nonassoc")) { + fof_formula(f->child(0), f1); + fof_formula(f->child(2), fml); + //SASSERT(!strcmp("binary_connective",f->child(1)->symbol())); + char const* conn = f->child(1)->child(0)->symbol(); + if (!strcmp(conn, "<=>")) { + fml = (f1 == fml); + } + else if (!strcmp(conn, "=>")) { + fml = implies(f1, fml); + } + else if (!strcmp(conn, "<=")) { + fml = implies(fml, f1); + } + else if (!strcmp(conn, "<~>")) { + fml = ! (f1 == fml); + } + else if (!strcmp(conn, "~|")) { + fml = !(f1 || fml); + } + else if (!strcmp(conn, "~&")) { + fml = ! (f1 && fml); + } + else { + mk_error(f->child(1)->child(0), "connective"); + } + } + else if (!strcmp(name,"fof_or_formula") || + !strcmp(name,"tff_or_formula")) { + fof_formula(f->child(0), f1); + fof_formula(f->child(2), fml); + fml = f1 || fml; + } + else if (!strcmp(name,"fof_and_formula") || + !strcmp(name,"tff_and_formula")) { + fof_formula(f->child(0), f1); + fof_formula(f->child(2), fml); + fml = f1 && fml; + } + else if (!strcmp(name,"fof_unitary_formula") || + !strcmp(name,"tff_unitary_formula")) { + if (f->child(1)) { + // parenthesis + fof_formula(f->child(1), fml); + } + else { + fof_formula(f->child(0), fml); + } + } + else if (!strcmp(name,"fof_quantified_formula") || + !strcmp(name,"tff_quantified_formula")) { + fof_quantified_formula(f->child(0), f->child(2), f->child(5), fml); + } + else if (!strcmp(name,"fof_unary_formula") || + !strcmp(name,"tff_unary_formula")) { + if (!f->child(1)) { + fof_formula(f->child(0), fml); + } + else { + fof_formula(f->child(1), fml); + char const* conn = f->child(0)->child(0)->symbol(); + if (!strcmp(conn,"~")) { + fml = !fml; + } + else { + mk_error(f->child(0)->child(0), "fof_unary_formula"); + } + } + } + else if (!strcmp(name,"fof_let")) { + mk_let(f->child(2), f->child(5), fml); + } + else if (!strcmp(name,"variable")) { + char const* v = f->child(0)->symbol(); + if (!find_bound(v, fml)) { + mk_error(f->child(0), "variable"); + } + } + else if (!strcmp(name,"fof_conditional")) { + z3::expr f2(m_context); + fof_formula(f->child(2), f1); + fof_formula(f->child(4), f2); + fof_formula(f->child(6), fml); + fml = ite(f1, f2, fml); + } + else if (!strcmp(name,"plain_atomic_formula") || + !strcmp(name,"defined_plain_formula") || + !strcmp(name,"system_atomic_formula")) { + z3::sort srt(m_context.bool_sort()); + term(f->child(0), srt, fml); + } + else if (!strcmp(name,"defined_infix_formula") || + !strcmp(name,"fol_infix_unary")) { + z3::expr t1(m_context), t2(m_context); + term(f->child(0), m_univ, t1); + term(f->child(2), m_univ, t2); + TreeNode* inf = f->child(1); + while (inf && strcmp(inf->symbol(),"=") && strcmp(inf->symbol(),"!=")) { + inf = inf->child(0); + } + if (!inf) { + mk_error(f->child(1), "defined_infix_formula"); + } + char const* conn = inf->symbol(); + if (!strcmp(conn,"=")) { + fml = t1 == t2; + } + else if (!strcmp(conn,"!=")) { + fml = ! (t1 == t2); + } + else { + mk_error(inf, "defined_infix_formula"); + } + } + else if (!strcmp(name, "tff_typed_atom")) { + while (!strcmp(f->child(0)->symbol(),"(")) { + f = f->child(1); + } + char const* id = 0; + z3::sort s(m_context); + z3::sort_vector sorts(m_context); + + mk_id(f->child(0), id); + if (is_ttype(f->child(2))) { + s = mk_sort(id); + m_defined_sorts.insert(symbol(id), s); + } + else { + mk_mapping_sort(f->child(2), sorts, s); + z3::func_decl fd(m_context.function(id, sorts, s)); + m_decls.insert(symbol(id), fd); + } + } + else { + mk_error(f, "fof_formula"); + } + } + + bool is_ttype(TreeNode* t) { + char const* name = t->symbol(); + if (!strcmp(name,"atomic_defined_word")) { + return !strcmp("$tType", t->child(0)->symbol()); + } + return false; + } + + void fof_quantified_formula(TreeNode* fol_quantifier, TreeNode* vl, TreeNode* formula, z3::expr& fml) { + unsigned l = m_bound.size(); + mk_variable_list(vl); + fof_formula(formula, fml); + bool is_forall = !strcmp(fol_quantifier->child(0)->symbol(),"!"); + z3::expr_vector bound(m_context); + for (unsigned i = l; i < m_bound.size(); ++i) { + bound.push_back(m_bound[i]); + } + fml = mk_quantifier(is_forall, bound, fml); + m_bound.resize(l); + } + + void mk_variable_list(TreeNode* variable_list) { + while (variable_list) { + TreeNode* var = variable_list->child(0); + if (!strcmp(var->symbol(),"tff_variable")) { + var = var->child(0); + } + if (!strcmp(var->symbol(),"variable")) { + char const* name = var->child(0)->symbol(); + m_bound.push_back(m_context.constant(name, m_univ)); + } + else if (!strcmp(var->symbol(),"tff_typed_variable")) { + z3::sort s(m_context); + char const* name = var->child(0)->child(0)->symbol(); + mk_sort(var->child(2), s); + m_bound.push_back(m_context.constant(name, s)); + } + else { + mk_error(var, "variable_list"); + } + variable_list = variable_list->child(2); + } + } + + void mk_sort(TreeNode* t, z3::sort& s) { + char const* name = t->symbol(); + if (!strcmp(name, "tff_atomic_type") || + !strcmp(name, "defined_type")) { + mk_sort(t->child(0), s); + } + else if (!strcmp(name, "atomic_defined_word")) { + z3::symbol sname = symbol(t->child(0)->symbol()); + z3::sort srt(m_context); + if (!strcmp("$tType", t->child(0)->symbol())) { + char const* id = 0; + s = mk_sort(id); + m_defined_sorts.insert(symbol(id), s); + } + else if (m_defined_sorts.find(sname, srt)) { + s = srt; + } + else { + s = mk_sort(sname); + if (sname == symbol("$rat")) { + throw failure_ex("rational sorts are not handled\n"); + } + mk_error(t, sname.str().c_str()); + } + } + else if (!strcmp(name,"atomic_word")) { + name = t->child(0)->symbol(); + z3::symbol symname = symbol(name); + s = mk_sort(symname); + } + else { + mk_error(t, "sort"); + } + } + + void mk_mapping_sort(TreeNode* t, z3::sort_vector& domain, z3::sort& s) { + char const* name = t->symbol(); + char const* id = 0; + if (!strcmp(name,"tff_top_level_type")) { + mk_mapping_sort(t->child(0), domain, s); + } + else if (!strcmp(name,"tff_atomic_type")) { + mk_sort(t->child(0), s); + } + else if (!strcmp(name,"tff_mapping_type")) { + TreeNode* t1 = t->child(0); + if (t1->child(1)) { + mk_xprod_sort(t1->child(1), domain); + } + else { + mk_sort(t1->child(0), s); + domain.push_back(s); + } + mk_sort(t->child(2), s); + } + else { + mk_error(t, "mapping sort"); + } + } + + void mk_xprod_sort(TreeNode* t, z3::sort_vector& sorts) { + char const* name = t->symbol(); + z3::sort s1(m_context), s2(m_context); + if (!strcmp(name, "tff_atomic_type")) { + mk_sort(t->child(0), s1); + sorts.push_back(s1); + } + else if (!strcmp(name, "tff_xprod_type")) { + name = t->child(0)->symbol(); + if (!strcmp(name, "tff_atomic_type") || + !strcmp(name, "tff_xprod_type")) { + mk_xprod_sort(t->child(0), sorts); + mk_xprod_sort(t->child(2), sorts); + } + else if (t->child(1)) { + mk_xprod_sort(t->child(1), sorts); + } + else { + mk_error(t, "xprod sort"); + } + } + else { + mk_error(t, "xprod sort"); + } + } + + void term(TreeNode* t, z3::sort const& s, z3::expr& r) { + char const* name = t->symbol(); + if (!strcmp(name, "defined_plain_term") || + !strcmp(name, "system_term") || + !strcmp(name, "plain_term")) { + if (!t->child(1)) { + term(t->child(0), s, r); + } + else { + apply_term(t->child(0), t->child(2), s, r); + } + } + else if (!strcmp(name, "constant") || + !strcmp(name, "functor") || + !strcmp(name, "defined_plain_formula") || + !strcmp(name, "defined_functor") || + !strcmp(name, "defined_constant") || + !strcmp(name, "system_constant") || + !strcmp(name, "defined_atomic_term") || + !strcmp(name, "system_functor") || + !strcmp(name, "function_term") || + !strcmp(name, "term") || + !strcmp(name, "defined_term")) { + term(t->child(0), s, r); + } + + + else if (!strcmp(name, "defined_atom")) { + char const* name0 = t->child(0)->symbol(); + if (!strcmp(name0,"number")) { + name0 = t->child(0)->child(0)->symbol(); + char const* per = strchr(name0, '.'); + bool is_real = 0 != per; + bool is_rat = 0 != strchr(name0, '/'); + bool is_int = !is_real && !is_rat; + if (is_int) { + r = m_context.int_val(name0); + } + else { + r = m_context.real_val(name0); + } + } + else if (!strcmp(name0, "distinct_object")) { + throw failure_ex("distinct object not handled"); + } + else { + mk_error(t->child(0), "number or distinct object"); + } + } + else if (!strcmp(name, "atomic_defined_word")) { + char const* ch = t->child(0)->symbol(); + z3::symbol s = symbol(ch); + z3::func_decl fd(m_context); + if (!strcmp(ch, "$true")) { + r = m_context.bool_val(true); + } + else if (!strcmp(ch, "$false")) { + r = m_context.bool_val(false); + } + else if (m_decls.find(s, fd)) { + r = fd(0,0); + } + else { + mk_error(t->child(0), "atomic_defined_word"); + } + } + else if (!strcmp(name, "atomic_word")) { + z3::func_decl f(m_context); + z3::symbol sym = symbol(t->child(0)->symbol()); + if (m_decls.find(sym, f)) { + r = f(0,0); + } + else { + r = m_context.constant(sym, s); + } + } + else if (!strcmp(name, "variable")) { + char const* v = t->child(0)->symbol(); + if (!find_bound(v, r)) { + mk_error(t->child(0), "variable not bound"); + } + } + else { + mk_error(t, "term not recognized"); + } + } + + void apply_term(TreeNode* f, TreeNode* args, z3::sort const& s, z3::expr& r) { + z3::expr_vector terms(m_context); + z3::sort_vector sorts(m_context); + mk_args(args, terms); + for (unsigned i = 0; i < terms.size(); ++i) { + sorts.push_back(terms[i].get_sort()); + } + if (!strcmp(f->symbol(),"functor") || + !strcmp(f->symbol(),"system_functor") || + !strcmp(f->symbol(),"defined_functor")) { + f = f->child(0); + } + bool atomic_word = !strcmp(f->symbol(),"atomic_word"); + if (atomic_word || + !strcmp(f->symbol(),"atomic_defined_word") || + !strcmp(f->symbol(),"atomic_system_word")) { + char const* ch = f->child(0)->symbol(); + z3::symbol fn = symbol(ch); + z3::func_decl fun(m_context); + z3::context& ctx = r.ctx(); + if (!strcmp(ch,"$less")) { + check_arity(terms.size(), 2); + r = terms[0] < terms[1]; + } + else if (!strcmp(ch,"$lesseq")) { + check_arity(terms.size(), 2); + r = terms[0] <= terms[1]; + } + else if (!strcmp(ch,"$greater")) { + check_arity(terms.size(), 2); + r = terms[0] > terms[1]; + } + else if (!strcmp(ch,"$greatereq")) { + check_arity(terms.size(), 2); + r = terms[0] >= terms[1]; + } + else if (!strcmp(ch,"$uminus")) { + check_arity(terms.size(), 1); + r = -terms[0]; + } + else if (!strcmp(ch,"$sum")) { + check_arity(terms.size(), 2); + r = terms[0] + terms[1]; + } + else if (!strcmp(ch,"$plus")) { + check_arity(terms.size(), 2); + r = terms[0] + terms[1]; + } + else if (!strcmp(ch,"$difference")) { + check_arity(terms.size(), 2); + r = terms[0] - terms[1]; + } + else if (!strcmp(ch,"$product")) { + check_arity(terms.size(), 2); + r = terms[0] * terms[1]; + } + else if (!strcmp(ch,"$quotient")) { + check_arity(terms.size(), 2); + r = terms[0] / terms[1]; + } + else if (!strcmp(ch,"$quotient_e")) { + check_arity(terms.size(), 2); + r = terms[0] / terms[1]; + } + else if (!strcmp(ch,"$distinct")) { + check_arity(terms.size(), 2); + r = terms[0] != terms[1]; + } + else if (!strcmp(ch,"$floor") || !strcmp(ch,"$to_int")) { + check_arity(terms.size(), 1); + r = to_real(to_int(terms[0])); + } + else if (!strcmp(ch,"$to_real")) { + check_arity(terms.size(), 1); + r = to_real(terms[0]); + } + else if (!strcmp(ch,"$is_int")) { + check_arity(terms.size(), 1); + r = z3::expr(ctx, Z3_mk_is_int(ctx, terms[0])); + } + else if (!strcmp(ch,"$true")) { + r = ctx.bool_val(true); + } + else if (!strcmp(ch,"$false")) { + r = ctx.bool_val(false); + } + // ceiling(x) = -floor(-x) + else if (!strcmp(ch,"$ceiling")) { + check_arity(terms.size(), 1); + r = ceiling(terms[0]); + } + // truncate - The nearest integral value with magnitude not greater than the absolute value of the argument. + // if x >= 0 floor(x) else ceiling(x) + else if (!strcmp(ch,"$truncate")) { + check_arity(terms.size(), 1); + r = truncate(terms[0]); + } + // The nearest integral number to the argument. When the argument + // is halfway between two integral numbers, the nearest even integral number to the argument. + else if (!strcmp(ch,"$round")) { + check_arity(terms.size(), 1); + z3::expr t = terms[0]; + z3::expr i = to_int(t); + z3::expr i2 = i + ctx.real_val(1,2); + r = ite(t > i2, i + 1, ite(t == i2, ite(is_even(i), i, i+1), i)); + } + // $quotient_e(N,D) - the Euclidean quotient, which has a non-negative remainder. + // If D is positive then $quotient_e(N,D) is the floor (in the type of N and D) of + // the real division N/D, and if D is negative then $quotient_e(N,D) is the ceiling of N/D. + + // $quotient_t(N,D) - the truncation of the real division N/D. + else if (!strcmp(ch,"$quotient_t")) { + check_arity(terms.size(), 2); + r = truncate(terms[0] / terms[1]); + } + // $quotient_f(N,D) - the floor of the real division N/D. + else if (!strcmp(ch,"$quotient_f")) { + check_arity(terms.size(), 2); + r = to_real(to_int(terms[0] / terms[1])); + } + // For t in {$int,$rat, $real}, x in {e, t,f}, $quotient_x and $remainder_x are related by + // ! [N:t,D:t] : $sum($product($quotient_x(N,D),D),$remainder_x(N,D)) = N + // For zero divisors the result is not specified. + else if (!strcmp(ch,"$remainder_t")) { + mk_not_handled(f, ch); + } + else if (!strcmp(ch,"$remainder_e")) { + check_arity(terms.size(), 2); + r = z3::expr(ctx, Z3_mk_mod(ctx, terms[0], terms[1])); + } + else if (!strcmp(ch,"$remainder_r")) { + mk_not_handled(f, ch); + } + else if (!strcmp(ch,"$to_rat") || + !strcmp(ch,"$is_rat")) { + mk_not_handled(f, ch); + } + else if (m_decls.find(fn, fun)) { + r = fun(terms); + } + else if (true) { + z3::func_decl func(m_context); + func = m_context.function(fn, sorts, s); + r = func(terms); + } + else { + mk_error(f->child(0), "atomic, defined or system word"); + } + return; + } + mk_error(f, "function"); + } + + z3::expr to_int(z3::expr e) { + return z3::expr(e.ctx(), Z3_mk_real2int(e.ctx(), e)); + } + + z3::expr to_real(z3::expr e) { + return z3::expr(e.ctx(), Z3_mk_int2real(e.ctx(), e)); + } + + z3::expr ceiling(z3::expr e) { + return -to_real(to_int(-e)); + } + + z3::expr is_even(z3::expr e) { + z3::context& ctx = e.ctx(); + z3::expr two = ctx.int_val(2); + z3::expr m = z3::expr(ctx, Z3_mk_mod(ctx, e, two)); + return m == 0; + } + + z3::expr truncate(z3::expr e) { + return ite(e >= 0, to_int(e), ceiling(e)); + } + + bool check_app(z3::func_decl& f, unsigned num, z3::expr const* args) { + if (f.arity() == num) { + for (unsigned i = 0; i < num; ++i) { + if (!eq(args[i].get_sort(), f.domain(i))) { + return false; + } + } + return true; + } + else { + return true; + } + } + + void mk_args(TreeNode* args, z3::expr_vector& result) { + z3::expr t(m_context); + while (args) { + term(args->child(0), m_univ, t); + result.push_back(t); + args = args->child(2); + } + } + + + bool find_bound(char const* v, z3::expr& b) { + for (unsigned l = m_bound.size(); l > 0; ) { + --l; + if (v == m_bound[l].decl().name().str()) { + b = m_bound[l]; + return true; + } + } + return false; + } + + void mk_id(TreeNode* f, char const*& sym) { + char const* name = f->symbol(); + if (!strcmp(name, "tff_untyped_atom") || + !strcmp(name, "functor") || + !strcmp(name, "system_functor")) { + mk_id(f->child(0), sym); + } + else if (!strcmp(name, "atomic_word") || + !strcmp(name, "atomic_system_word")) { + sym = f->child(0)->symbol(); + } + else { + mk_error(f, "atom"); + } + } + + void mk_let(TreeNode* let_vars, TreeNode* f, z3::expr& fml) { + mk_error(f, "let construct is not handled"); + } + + FILE* open_file(char const* filename) { + FILE* fp = 0; +#ifdef _WINDOWS + if (0 > fopen_s(&fp, filename, "r") || fp == 0) { + fp = 0; + } +#else + fp = fopen(filename, "r"); +#endif + return fp; + } + + bool is_sep(char s) { + return s == '/' || s == '\\'; + } + + void add_separator(const char* rel_name, std::string& inc_name) { + size_t sz = inc_name.size(); + if (sz == 0) return; + if (sz > 0 && is_sep(inc_name[sz-1])) return; + if (is_sep(rel_name[0])) return; + inc_name += "/"; + } + + void append_rel_name(const char * rel_name, std::string& inc_name) { + if (rel_name[0] == '\'') { + add_separator(rel_name+1, inc_name); + inc_name.append(rel_name+1); + inc_name.resize(inc_name.size()-1); + } + else { + add_separator(rel_name, inc_name); + inc_name.append(rel_name); + } + } + + bool mk_filename(const char *rel_name, unsigned num_sep, std::string& inc_name) { + unsigned sep1 = 0, sep2 = 0, sep3 = 0; + size_t len = strlen(m_filename); + for (unsigned i = 0; i < len; ++i) { + if (is_sep(m_filename[i])) { + sep3 = sep2; + sep2 = sep1; + sep1 = i; + } + } + if ((num_sep == 3) && sep3 > 0) { + inc_name.append(m_filename,sep3+1); + } + if ((num_sep == 2) && sep2 > 0) { + inc_name.append(m_filename,sep2+1); + } + if ((num_sep == 1) && sep1 > 0) { + inc_name.append(m_filename,sep1+1); + } + append_rel_name(rel_name, inc_name); + return file_exists(inc_name.c_str()); + } + + bool file_exists(char const* filename) { + FILE* fp = open_file(filename); + if (!fp) { + return false; + } + fclose(fp); + return true; + } + + bool mk_env_filename(const char* rel_name, std::string& inc_name) { +#ifdef _WINDOWS + char buffer[1024]; + size_t sz; + errno_t err = getenv_s( + &sz, + buffer, + "$TPTP"); + if (err != 0) { + return false; + } +#else + char const* buffer = getenv("$TPTP"); + if (!buffer) { + return false; + } +#endif + inc_name = buffer; + append_rel_name(rel_name, inc_name); + return file_exists(inc_name.c_str()); + } + + void get_cnf_variables(TreeNode* t, symbol_set& symbols) { + std::vector todo; + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + todo.pop_back(); + if (!t) continue; + if (!strcmp(t->symbol(),"variable")) { + z3::symbol sym = symbol(t->child(0)->symbol()); + symbols.insert(sym); + } + else { + for (unsigned i = 0; i < 10; ++i) { + todo.push_back(t->child(i)); + } + } + } + } + + z3::symbol symbol(char const* s) { + return m_context.str_symbol(s); + } + + z3::sort mk_sort(char const* s) { + z3::symbol sym = symbol(s); + return mk_sort(sym); + } + + z3::sort mk_sort(z3::symbol& s) { + return z3::sort(m_context, Z3_mk_uninterpreted_sort(m_context, s)); + } + +public: + env(z3::context& ctx): + m_context(ctx), + m_bound(ctx), + m_univ(mk_sort("$i")), + m_filename(0) { + m_nodes = 0; + m_region = new alloc_region(); + m_defined_sorts.insert(symbol("$i"), m_univ); + m_defined_sorts.insert(symbol("$o"), m_context.bool_sort()); + m_defined_sorts.insert(symbol("$real"), m_context.real_sort()); + m_defined_sorts.insert(symbol("$int"), m_context.int_sort()); + + } + + ~env() { + delete m_region; + m_region = 0; + } + void parse(const char* filename, named_formulas& fmls); + static void register_node(TreeNode* t) { m_nodes->push_back(t); } + static alloc_region& r() { return *m_region; } +}; + +std::vector* env::m_nodes = 0; +alloc_region* env::m_region = 0; + +# define P_USERPROC +# define P_ACT(ss) if(verbose)printf("%7d %s\n",yylineno,ss); +# define P_BUILD(sym,A,B,C,D,E,F,G,H,I,J) new (env::r()) TreeNode(env::r(), sym,A,B,C,D,E,F,G,H,I,J) +# define P_TOKEN(tok,symbolIndex) MkToken(env::r(), tok,symbolIndex) +# define P_PRINT(ss) env::register_node(ss) + + +// ------------------------------------------------------ +// created by YACC. +#include "tptp5.tab.c" + +extern FILE* yyin; + + +void env::parse(const char* filename, named_formulas& fmls) { + std::vector nodes; + flet fn(m_filename, filename); + flet*> fnds(m_nodes, &nodes); + + FILE* fp = open_file(filename); + if (!fp) { + std::stringstream strm; + strm << "Could not open file " << filename << "\n"; + throw failure_ex(strm.str().c_str()); + } + yyin = fp; + int result = yyparse(); + fclose(fp); + + if (result != 0) { + throw failure_ex("could not parse input"); + } + + for (unsigned i = 0; i < nodes.size(); ++i) { + TreeNode* cl = nodes[i]; + if (cl) { + mk_input(cl, fmls); + } + } + +} + +class pp_tptp { + z3::context& ctx; + std::vector names; + std::vector sorts; + std::vector funs; + std::vector todo; + std::set seen_ids; + unsigned m_formula_id; + unsigned m_node_number; + std::map m_proof_ids; + std::map > m_proof_hypotheses; + std::map m_axiom_ids; + named_formulas* m_named_formulas; + +public: + pp_tptp(z3::context& ctx): ctx(ctx), m_formula_id(0) {} + + + void display_func_decl(std::ostream& out, z3::func_decl& f) { + std::string name = lower_case_fun(f.name()); + out << "tff(" << name << "_type, type, (\n " << name << ": "; + unsigned na = f.arity(); + switch(na) { + case 0: + break; + case 1: { + z3::sort s(f.domain(0)); + display_sort(out, s); + out << " > "; + break; + } + default: + out << "( "; + for (unsigned j = 0; j < na; ++j) { + z3::sort s(f.domain(j)); + display_sort(out, s); + if (j + 1 < na) { + out << " * "; + } + } + out << " ) > "; + } + z3::sort srt(f.range()); + display_sort(out, srt); + out << ")).\n"; + } + + void display_axiom(std::ostream& out, z3::expr e) { + out << "tff(formula" << (++m_formula_id) << ", axiom,\n "; + display(out, e); + out << ").\n"; + } + + void display(std::ostream& out, z3::expr e) { + if (e.is_numeral()) { + __int64 num, den; + if (Z3_get_numeral_small(ctx, e, &num, &den)) { + if (num < 0 && den == 1 && num != std::numeric_limits<__int64>::min()) { + out << "-" << (-num); + return; + } + } + // potential incompatibility: prints negative numbers with a space. + out << e; + } + else if (e.is_var()) { + unsigned idx = Z3_get_index_value(ctx, e); + out << names[names.size()-1-idx]; + } + else if (e.is_app()) { + switch(e.decl().decl_kind()) { + case Z3_OP_TRUE: + out << "$true"; + break; + case Z3_OP_FALSE: + out << "$false"; + break; + case Z3_OP_AND: + display_infix(out, "&", e); + break; + case Z3_OP_OR: + display_infix(out, "|", e); + break; + case Z3_OP_IMPLIES: + display_infix(out, "=>", e); + break; + case Z3_OP_NOT: + out << "(~"; + display(out, e.arg(0)); + out << ")"; + break; + case Z3_OP_EQ: + if (e.arg(0).is_bool()) { + display_infix(out, "<=>", e); + } + else { + display_infix(out, "=", e); + } + break; + case Z3_OP_IFF: + display_infix(out, "<=>", e); + break; + case Z3_OP_XOR: + display_infix(out, "<~>", e); + break; + case Z3_OP_MUL: + display_binary(out, "$product", e); + break; + case Z3_OP_ADD: + display_binary(out, "$sum", e); + break; + case Z3_OP_SUB: + display_prefix(out, "$difference", e); + break; + case Z3_OP_LE: + display_prefix(out, "$lesseq", e); + break; + case Z3_OP_GE: + display_prefix(out, "$greatereq", e); + break; + case Z3_OP_LT: + display_prefix(out, "$less", e); + break; + case Z3_OP_GT: + display_prefix(out, "$greater", e); + break; + case Z3_OP_UMINUS: + display_prefix(out, "$uminus", e); + break; + case Z3_OP_DIV: + display_prefix(out, "$quotient", e); + break; + case Z3_OP_IS_INT: + display_prefix(out, "$is_int", e); + break; + case Z3_OP_TO_REAL: + display_prefix(out, "$to_real", e); + break; + case Z3_OP_TO_INT: + display_prefix(out, "$to_int", e); + break; + case Z3_OP_IDIV: + display_prefix(out, "$quotient_e", e); + break; + case Z3_OP_MOD: + display_prefix(out, "$remainder_e", e); + break; + case Z3_OP_ITE: + display_prefix(out, e.is_bool()?"ite_f":"ite_t", e); + break; + case Z3_OP_DISTINCT: + display_prefix(out, "$distinct", e); + break; + case Z3_OP_REM: + throw failure_ex("rem is not handled"); + break; + case Z3_OP_OEQ: + display_prefix(out, "$oeq", e); + break; + default: + display_app(out, e); + break; + } + } + else if (e.is_quantifier()) { + Z3_bool is_forall = Z3_is_quantifier_forall(ctx, e); + unsigned nb = Z3_get_quantifier_num_bound(ctx, e); + + out << (is_forall?"!":"?") << "["; + for (unsigned i = 0; i < nb; ++i) { + Z3_symbol n = Z3_get_quantifier_bound_name(ctx, e, i); + names.push_back(upper_case_var(z3::symbol(ctx, n))); + z3::sort srt(ctx, Z3_get_quantifier_bound_sort(ctx, e, i)); + out << names.back() << ": "; + display_sort(out, srt); + if (i + 1 < nb) { + out << ", "; + } + } + out << "] : "; + display(out, e.body()); + for (unsigned i = 0; i < nb; ++i) { + names.pop_back(); + } + } + } + + void display_app(std::ostream& out, z3::expr e) { + if (e.is_const()) { + out << e; + return; + } + out << lower_case_fun(e.decl().name()) << "("; + unsigned n = e.num_args(); + for(unsigned i = 0; i < n; ++i) { + display(out, e.arg(i)); + if (i + 1 < n) { + out << ", "; + } + } + out << ")"; + } + + void display_sort(std::ostream& out, z3::sort const& s) { + if (s.is_int()) { + out << "$int"; + } + else if (s.is_real()) { + out << "$real"; + } + else if (s.is_bool()) { + out << "$o"; + } + else { + out << s; + } + } + + void display_infix(std::ostream& out, char const* conn, z3::expr& e) { + out << "("; + unsigned sz = e.num_args(); + for (unsigned i = 0; i < sz; ++i) { + display(out, e.arg(i)); + if (i + 1 < sz) { + out << " " << conn << " "; + } + } + out << ")"; + } + + void display_prefix(std::ostream& out, char const* conn, z3::expr& e) { + out << conn << "("; + unsigned sz = e.num_args(); + for (unsigned i = 0; i < sz; ++i) { + display(out, e.arg(i)); + if (i + 1 < sz) { + out << ", "; + } + } + out << ")"; + } + + void display_binary(std::ostream& out, char const* conn, z3::expr& e) { + out << conn << "("; + unsigned sz = e.num_args(); + unsigned np = 1; + for (unsigned i = 0; i < sz; ++i) { + display(out, e.arg(i)); + if (i + 1 < sz) { + out << ", "; + } + if (i + 2 < sz) { + out << conn << "("; + ++np; + } + } + for (unsigned i = 0; i < np; ++i) { + out << ")"; + } + } + + void collect_axiom_ids(named_formulas& axioms) { + m_named_formulas = &axioms; + m_axiom_ids.clear(); + for (unsigned i = 0; i < axioms.m_formulas.size(); ++i) { + z3::expr& e = axioms.m_formulas[i]; + unsigned id = Z3_get_ast_id(ctx, e); + m_axiom_ids.insert(std::make_pair(id, i)); + } + } + + void display_proof(std::ostream& out, named_formulas& fmls, z3::solver& solver) { + m_node_number = 0; + m_proof_ids.clear(); + m_proof_hypotheses.clear(); + z3::expr proof = solver.proof(); + collect_axiom_ids(fmls); + collect_decls(proof); + collect_hypotheses(proof); + display_sort_decls(out); + display_func_decls(out); + display_proof_rec(out, proof); + } + + /** + \brief collect hypotheses for each proof node. + */ + void collect_hypotheses(z3::expr& proof) { + Z3_sort proof_sort = proof.get_sort(); + size_t todo_size = todo.size(); + todo.push_back(proof); + while (todo_size != todo.size()) { + z3::expr p = todo.back(); + unsigned id = Z3_get_ast_id(ctx, p); + if (m_proof_hypotheses.find(id) != m_proof_hypotheses.end()) { + todo.pop_back(); + continue; + } + bool all_visited = true; + for (unsigned i = 0; i < p.num_args(); ++i) { + z3::expr arg = p.arg(i); + if (arg.get_sort() == proof_sort) { + if (m_proof_hypotheses.find(Z3_get_ast_id(ctx,arg)) == m_proof_hypotheses.end()) { + all_visited = false; + todo.push_back(arg); + } + } + } + if (!all_visited) { + continue; + } + todo.pop_back(); + std::set hyps; + if (p.decl().decl_kind() == Z3_OP_PR_LEMMA) { + // we assume here that all hypotheses get consumed in lemmas. + } + else { + for (unsigned i = 0; i < p.num_args(); ++i) { + z3::expr arg = p.arg(i); + if (arg.get_sort() == proof_sort) { + unsigned arg_id = Z3_get_ast_id(ctx,arg); + std::set const& arg_hyps = m_proof_hypotheses.find(arg_id)->second; + std::set::iterator it = arg_hyps.begin(), end = arg_hyps.end(); + for (; it != end; ++it) { + hyps.insert(*it); + } + } + } + } + m_proof_hypotheses.insert(std::make_pair(id, hyps)); + } + + } + + unsigned display_proof_rec(std::ostream& out, z3::expr proof) { + Z3_sort proof_sort = proof.get_sort(); + size_t todo_size = todo.size(); + todo.push_back(proof); + while (todo_size != todo.size()) { + z3::expr p = todo.back(); + unsigned id = Z3_get_ast_id(ctx, p); + if (m_proof_ids.find(id) != m_proof_ids.end()) { + todo.pop_back(); + continue; + } + + switch (p.decl().decl_kind()) { + case Z3_OP_PR_MODUS_PONENS_OEQ: { + unsigned hyp = display_proof_rec(out, p.arg(0)); + unsigned num = display_proof_hyp(out, hyp, p.arg(1)); + m_proof_ids.insert(std::make_pair(id, num)); + todo.pop_back(); + continue; + } + default: + break; + } + bool all_visited = true; + for (unsigned i = 0; i < p.num_args(); ++i) { + z3::expr arg = p.arg(i); + if (arg.get_sort() == proof_sort) { + if (m_proof_ids.find(Z3_get_ast_id(ctx,arg)) == m_proof_ids.end()) { + all_visited = false; + todo.push_back(arg); + } + } + } + if (!all_visited) { + continue; + } + todo.pop_back(); + unsigned num = ++m_node_number; + m_proof_ids.insert(std::make_pair(id, num)); + + switch (p.decl().decl_kind()) { + case Z3_OP_PR_ASSERTED: { + std::string formula_name; + std::string formula_file; + unsigned id = Z3_get_ast_id(ctx, p.arg(0)); + std::map::iterator it = m_axiom_ids.find(id); + if (it != m_axiom_ids.end()) { + formula_name = m_named_formulas->m_names[it->second]; + formula_file = m_named_formulas->m_files[it->second]; + } + else { + std::ostringstream str; + str << "axiom_" << id; + formula_name = str.str(); + formula_file = "unknown"; + } + out << "tff(" << m_node_number << ",axiom,("; + display(out, get_proof_formula(p)); + out << "), file('" << formula_file << "','"; + out << formula_name << "')).\n"; + break; + } + case Z3_OP_PR_UNDEF: + throw failure_ex("undef rule not handled"); + case Z3_OP_PR_TRUE: + display_inference(out, "true", "thm", p); + break; + case Z3_OP_PR_GOAL: + display_inference(out, "goal", "thm", p); + break; + case Z3_OP_PR_MODUS_PONENS: + display_inference(out, "modus_ponens", "thm", p); + break; + case Z3_OP_PR_REFLEXIVITY: + display_inference(out, "reflexivity", "thm", p); + break; + case Z3_OP_PR_SYMMETRY: + display_inference(out, "symmetry", "thm", p); + break; + case Z3_OP_PR_TRANSITIVITY: + case Z3_OP_PR_TRANSITIVITY_STAR: + display_inference(out, "transitivity", "thm", p); + break; + case Z3_OP_PR_MONOTONICITY: + display_inference(out, "monotonicity", "thm", p); + break; + case Z3_OP_PR_QUANT_INTRO: + display_inference(out, "quant_intro", "thm", p); + break; + case Z3_OP_PR_DISTRIBUTIVITY: + display_inference(out, "distributivity", "thm", p); + break; + case Z3_OP_PR_AND_ELIM: + display_inference(out, "and_elim", "thm", p); + break; + case Z3_OP_PR_NOT_OR_ELIM: + display_inference(out, "or_elim", "thm", p); + break; + case Z3_OP_PR_REWRITE: + case Z3_OP_PR_REWRITE_STAR: + display_inference(out, "rewrite", "thm", p); + break; + case Z3_OP_PR_PULL_QUANT: + case Z3_OP_PR_PULL_QUANT_STAR: + display_inference(out, "pull_quant", "thm", p); + break; + case Z3_OP_PR_PUSH_QUANT: + display_inference(out, "push_quant", "thm", p); + break; + case Z3_OP_PR_ELIM_UNUSED_VARS: + display_inference(out, "elim_unused_vars", "thm", p); + break; + case Z3_OP_PR_DER: + display_inference(out, "destructive_equality_resolution", "thm", p); + break; + case Z3_OP_PR_QUANT_INST: + display_inference(out, "quant_inst", "thm", p); + break; + case Z3_OP_PR_HYPOTHESIS: + out << "tff(" << m_node_number << ",assumption,("; + display(out, get_proof_formula(p)); + out << "), introduced(assumption)).\n"; + break; + case Z3_OP_PR_LEMMA: { + out << "tff(" << m_node_number << ",plain,("; + display(out, get_proof_formula(p)); + out << "), inference(lemma,lemma(discharge,"; + unsigned parent_id = Z3_get_ast_id(ctx, p.arg(0)); + std::set const& hyps = m_proof_hypotheses.find(parent_id)->second; + print_hypotheses(out, hyps); + out << ").\n"; + break; + display_inference(out, "lemma", "thm", p); + break; + } + case Z3_OP_PR_UNIT_RESOLUTION: + display_inference(out, "unit_resolution", "thm", p); + break; + case Z3_OP_PR_IFF_TRUE: + display_inference(out, "iff_true", "thm", p); + break; + case Z3_OP_PR_IFF_FALSE: + display_inference(out, "iff_false", "thm", p); + break; + case Z3_OP_PR_COMMUTATIVITY: + display_inference(out, "commutativity", "thm", p); + break; + case Z3_OP_PR_DEF_AXIOM: + display_inference(out, "tautology", "thm", p); + break; + case Z3_OP_PR_DEF_INTRO: + display_inference(out, "def_intro", "sab", p); + break; + case Z3_OP_PR_APPLY_DEF: + display_inference(out, "apply_def", "sab", p); + break; + case Z3_OP_PR_IFF_OEQ: + display_inference(out, "iff_oeq", "sab", p); + break; + case Z3_OP_PR_NNF_POS: + display_inference(out, "nnf_pos", "sab", p); + break; + case Z3_OP_PR_NNF_NEG: + display_inference(out, "nnf_neg", "sab", p); + break; + case Z3_OP_PR_NNF_STAR: + display_inference(out, "nnf", "sab", p); + break; + case Z3_OP_PR_CNF_STAR: + display_inference(out, "cnf", "sab", p); + break; + case Z3_OP_PR_SKOLEMIZE: + display_inference(out, "skolemize", "sab", p); + break; + case Z3_OP_PR_MODUS_PONENS_OEQ: + display_inference(out, "modus_ponens_sab", "sab", p); + break; + case Z3_OP_PR_TH_LEMMA: + display_inference(out, "theory_lemma", "thm", p); + break; + case Z3_OP_PR_HYPER_RESOLVE: + display_inference(out, "hyper_resolve", "thm", p); + break; + default: + out << "TBD: " << m_node_number << "\n" << p << "\n"; + throw failure_ex("rule not handled"); + } + } + return m_proof_ids.find(Z3_get_ast_id(ctx, proof))->second; + } + + unsigned display_proof_hyp(std::ostream& out, unsigned hyp, z3::expr p) { + z3::expr fml = p.arg(p.num_args()-1); + z3::expr conclusion = fml.arg(1); + switch (p.decl().decl_kind()) { + case Z3_OP_PR_REFLEXIVITY: + return display_hyp_inference(out, "reflexivity", "sab", conclusion, hyp); + case Z3_OP_PR_IFF_OEQ: { + unsigned hyp2 = display_proof_rec(out, p.arg(0)); + return display_hyp_inference(out, "modus_ponens", "thm", conclusion, hyp, hyp2); + } + case Z3_OP_PR_NNF_POS: + case Z3_OP_PR_NNF_STAR: + return display_hyp_inference(out, "nnf", "sab", conclusion, hyp); + case Z3_OP_PR_CNF_STAR: + return display_hyp_inference(out, "cnf", "sab", conclusion, hyp); + case Z3_OP_PR_SKOLEMIZE: + return display_hyp_inference(out, "skolemize", "sab", conclusion, hyp); + case Z3_OP_PR_TRANSITIVITY: + case Z3_OP_PR_TRANSITIVITY_STAR: { + unsigned na = p.num_args(); + for (unsigned i = 0; i + 1 < na; ++i) { + if (p.arg(i).num_args() != 2) { + // cop-out: Z3 produces transitivity proofs that are not a chain of equivalences/equi-sats. + // the generated proof is (most likely) not going to be checkable. + continue; + } + z3::expr conclusion = p.arg(i).arg(1); + hyp = display_hyp_inference(out, "transitivity", "sab", conclusion, hyp); + } + return hyp; + } + case Z3_OP_PR_MONOTONICITY: + throw failure_ex("monotonicity rule is not handled"); + default: + unsigned hyp2 = 0; + if (p.num_args() == 2) { + hyp2 = display_proof_rec(out, p.arg(0)); + } + if (p.num_args() > 2) { + std::cout << "unexpected number of arguments: " << p << "\n"; + throw failure_ex("unexpected number of arguments"); + } + + return display_hyp_inference(out, p.decl().name().str().c_str(), "sab", conclusion, hyp, hyp2); + } + return 0; + } + + + void display_inference(std::ostream& out, char const* name, char const* status, z3::expr p) { + unsigned id = Z3_get_ast_id(ctx, p); + std::set const& hyps = m_proof_hypotheses.find(id)->second; + out << "tff(" << m_node_number << ",plain,\n ("; + display(out, get_proof_formula(p)); + out << "),\n inference(" << name << ",[status(" << status << ")"; + if (!hyps.empty()) { + out << ", assumptions("; + print_hypotheses(out, hyps); + out << ")"; + } + out << "],"; + display_hypotheses(out, p); + out << ")).\n"; + } + + void print_hypotheses(std::ostream& out, std::set const& hyps) { + std::set::iterator it = hyps.begin(), end = hyps.end(); + bool first = true; + out << "["; + for (; it != end; ++it) { + if (!first) { + out << ", "; + } + first = false; + out << m_proof_ids.find(*it)->second; + } + out << "]"; + } + + unsigned display_hyp_inference(std::ostream& out, char const* name, char const* status, z3::expr conclusion, unsigned hyp1, unsigned hyp2 = 0) { + ++m_node_number; + out << "tff(" << m_node_number << ",plain,(\n "; + display(out, conclusion); + out << "),\n inference(" << name << ",[status(" << status << ")],"; + out << "[" << hyp1; + if (hyp2) { + out << ", " << hyp2; + } + out << "])).\n"; + return m_node_number; + } + + + + void get_free_vars(z3::expr const& e, std::vector& vars) { + std::set seen; + size_t sz = todo.size(); + todo.push_back(e); + while (todo.size() != sz) { + z3::expr e = todo.back(); + todo.pop_back(); + unsigned id = Z3_get_ast_id(e.ctx(), e); + if (seen.find(id) != seen.end()) { + continue; + } + seen.insert(id); + if (e.is_var()) { + unsigned idx = Z3_get_index_value(ctx, e); + while (idx >= vars.size()) { + vars.push_back(e.get_sort()); + } + vars[idx] = e.get_sort(); + } + else if (e.is_app()) { + unsigned sz = e.num_args(); + for (unsigned i = 0; i < sz; ++i) { + todo.push_back(e.arg(i)); + } + } + else { + // e is a quantifier + std::vector fv; + get_free_vars(e.body(), fv); + unsigned nb = Z3_get_quantifier_num_bound(e.ctx(), e); + for (unsigned i = nb; i < fv.size(); ++i) { + if (vars.size() <= i - nb) { + vars.push_back(fv[i]); + } + } + } + } + } + + z3::expr get_proof_formula(z3::expr proof) { + unsigned na = proof.num_args(); + z3::expr result = proof.arg(proof.num_args()-1); + std::vector vars; + get_free_vars(result, vars); + if (vars.empty()) { + return result; + } + Z3_sort* sorts = new Z3_sort[vars.size()]; + Z3_symbol* names = new Z3_symbol[vars.size()]; + for (unsigned i = 0; i < vars.size(); ++i) { + std::ostringstream str; + str << "X" << (i+1); + sorts[vars.size()-i-1] = vars[i]; + names[vars.size()-i-1] = Z3_mk_string_symbol(ctx, str.str().c_str()); + } + result = z3::expr(ctx, Z3_mk_forall(ctx, 1, 0, 0, static_cast(vars.size()), sorts, names, result)); + delete[] sorts; + delete[] names; + return result; + } + + void display_hypotheses(std::ostream& out, z3::expr p) { + unsigned na = p.num_args(); + out << "["; + for (unsigned i = 0; i + 1 < na; ++i) { + out << m_proof_ids.find(Z3_get_ast_id(p.ctx(), p.arg(i)))->second; + if (i + 2 < na) { + out << ", "; + } + } + out << "]"; + } + + void display_sort_decls(std::ostream& out) { + for (unsigned i = 0; i < sorts.size(); ++i) { + display_sort_decl(out, sorts[i]); + } + } + + void display_sort_decl(std::ostream& out, z3::sort& s) { + out << "tff(" << s << "_type, type, (" << s << ": $tType)).\n"; + } + + + void display_func_decls(std::ostream& out) { + for (size_t i = 0; i < funs.size(); ++i) { + display_func_decl(out, funs[i]); + } + } + + bool contains_id(unsigned id) const { + return seen_ids.find(id) != seen_ids.end(); + } + + void collect_decls(z3::expr e) { + todo.push_back(e); + while (!todo.empty()) { + z3::expr e = todo.back(); + todo.pop_back(); + unsigned id = Z3_get_ast_id(ctx, e); + if (contains_id(id)) { + continue; + } + seen_ids.insert(id); + if (e.is_app()) { + collect_fun(e.decl()); + unsigned sz = e.num_args(); + for (unsigned i = 0; i < sz; ++i) { + todo.push_back(e.arg(i)); + } + } + else if (e.is_quantifier()) { + unsigned nb = Z3_get_quantifier_num_bound(e.ctx(), e); + for (unsigned i = 0; i < nb; ++i) { + z3::sort srt(ctx, Z3_get_quantifier_bound_sort(e.ctx(), e, i)); + collect_sort(srt); + } + todo.push_back(e.body()); + } + else if (e.is_var()) { + collect_sort(e.get_sort()); + } + } + } + + void collect_sort(z3::sort s) { + unsigned id = Z3_get_sort_id(ctx, s); + if (s.sort_kind() == Z3_UNINTERPRETED_SORT && + contains_id(id)) { + seen_ids.insert(id); + sorts.push_back(s); + } + } + + void collect_fun(z3::func_decl f) { + unsigned id = Z3_get_func_decl_id(ctx, f); + if (contains_id(id)) { + return; + } + seen_ids.insert(id); + if (f.decl_kind() == Z3_OP_UNINTERPRETED) { + funs.push_back(f); + } + for (unsigned i = 0; i < f.arity(); ++i) { + collect_sort(f.domain(i)); + } + collect_sort(f.range()); + } + + std::string upper_case_var(z3::symbol const& sym) { + std::string result = sanitize(sym); + char ch = result[0]; + if ('A' <= ch && ch <= 'Z') { + return result; + } + return "X" + result; + } + + std::string lower_case_fun(z3::symbol const& sym) { + std::string result = sanitize(sym); + char ch = result[0]; + if ('a' <= ch && ch <= 'z') { + return result; + } + else { + return "tptp_fun_" + result; + } + } + + std::string sanitize(z3::symbol const& sym) { + std::ostringstream str; + if (sym.kind() == Z3_INT_SYMBOL) { + str << sym; + return str.str(); + } + std::string s = sym.str(); + size_t sz = s.size(); + for (size_t i = 0; i < sz; ++i) { + char ch = s[i]; + if ('a' <= ch && ch <= 'z') { + str << ch; + } + else if ('A' <= ch && ch <= 'Z') { + str << ch; + } + else if ('0' <= ch && ch <= '9') { + str << ch; + } + else if ('_' == ch) { + str << ch; + } + else { + str << "_"; + } + } + return str.str(); + } +}; + +static char* g_input_file = 0; +static bool g_display_smt2 = false; +static bool g_generate_model = false; +static bool g_generate_proof = false; +static bool g_generate_core = false; +static bool g_display_statistics = false; +static bool g_first_interrupt = true; +static bool g_smt2status = false; +static bool g_check_status = false; +static int g_timeout = 0; +static double g_start_time = 0; +static z3::solver* g_solver = 0; +static z3::context* g_context = 0; +static std::ostream* g_out = &std::cout; + + + +static void display_usage() { + unsigned major, minor, build_number, revision_number; + Z3_get_version(&major, &minor, &build_number, &revision_number); + std::cout << "Z3tptp [" << major << "." << minor << "." << build_number << "." << revision_number << "] (c) 2006-20**. Microsoft Corp.\n"; + std::cout << "Usage: tptp [options] [-file:]file\n"; + std::cout << " -h, -? prints this message.\n"; + std::cout << " -smt2 print SMT-LIB2 benchmark.\n"; + std::cout << " -m, -model generate model.\n"; + std::cout << " -p, -proof generate proof.\n"; + std::cout << " -c, -core generate unsat core of named formulas.\n"; + std::cout << " -st, -statistics display statistics.\n"; + std::cout << " -t:timeout set timeout (in second).\n"; + std::cout << " -smt2status display status in smt2 format instead of SZS.\n"; + std::cout << " -check_status check the status produced by Z3 against annotation in benchmark.\n"; + std::cout << " -: configuration parameter and value.\n"; + std::cout << " -o: file to place output in.\n"; +} + + +static void display_statistics() { + if (g_solver && g_display_statistics) { + std::cout.flush(); + std::cerr.flush(); + double end_time = static_cast(clock()); + z3::stats stats = g_solver->statistics(); + std::cout << stats << "\n"; + std::cout << "time: " << (end_time - g_start_time)/CLOCKS_PER_SEC << " secs\n"; + } +} + +static void on_ctrl_c(int) { + if (g_context && g_first_interrupt) { + Z3_interrupt(*g_context); + g_first_interrupt = false; + } + else { + signal (SIGINT, SIG_DFL); + display_statistics(); + raise(SIGINT); + } +} + +bool parse_token(char const*& line, char const* token) { + char const* result = line; + while (result[0] == ' ') ++result; + while (token[0] && result[0] == token[0]) { + ++token; + ++result; + } + if (!token[0]) { + line = result; + return true; + } + else { + return false; + } +} + +bool parse_is_sat_line(char const* line, bool& is_sat) { + if (!parse_token(line, "%")) return false; + if (!parse_token(line, "Status")) return false; + if (!parse_token(line, ":")) return false; + + if (parse_token(line, "Unsatisfiable")) { + is_sat = false; + return true; + } + if (parse_token(line, "Theorem")) { + is_sat = false; + return true; + } + if (parse_token(line, "Theorem")) { + is_sat = false; + return true; + } + if (parse_token(line, "CounterSatisfiable")) { + is_sat = true; + return true; + } + if (parse_token(line, "Satisfiable")) { + is_sat = true; + return true; + } + return false; +} + +bool parse_is_sat(char const* filename, bool& is_sat) { + std::ifstream is(filename); + if (is.bad() || is.fail()) { + std::stringstream strm; + strm << "Could not open file " << filename << "\n"; + throw failure_ex(strm.str().c_str()); + } + + for (unsigned i = 0; !is.eof() && i < 200; ++i) { + std::string line; + std::getline(is, line); + if (parse_is_sat_line(line.c_str(), is_sat)) { + return true; + } + } + return false; +} + + +void parse_cmd_line_args(int argc, char ** argv) { + g_input_file = 0; + g_display_smt2 = false; + int i = 1; + while (i < argc) { + char* arg = argv[i]; + char * eq = 0; + char * opt_arg = 0; + if (arg[0] == '-' || arg[0] == '/') { + ++arg; + while (*arg == '-') { + ++arg; + } + char * colon = strchr(arg, ':'); + if (colon) { + opt_arg = colon + 1; + *colon = 0; + } + if (!strcmp(arg,"h") || !strcmp(arg,"help") || !strcmp(arg,"?")) { + display_usage(); + exit(0); + } + if (!strcmp(arg,"p") || !strcmp(arg,"proof")) { + g_generate_proof = true; + } + else if (!strcmp(arg,"m") || !strcmp(arg,"model")) { + g_generate_model = true; + } + else if (!strcmp(arg,"c") || !strcmp(arg,"core")) { + g_generate_core = true; + } + else if (!strcmp(arg,"st") || !strcmp(arg,"statistics")) { + g_display_statistics = true; + } + else if (!strcmp(arg,"check_status")) { + g_check_status = true; + } + else if (!strcmp(arg,"t") || !strcmp(arg,"timeout")) { + if (!opt_arg) { + display_usage(); + exit(0); + } + g_timeout = atoi(opt_arg); + } + else if (!strcmp(arg,"smt2status")) { + g_smt2status = true; + } + else if (!strcmp(arg,"o")) { + if (opt_arg) { + g_out = new std::ofstream(opt_arg); + if (g_out->bad() || g_out->fail()) { + std::cout << "Could not open file of output: " << opt_arg << "\n"; + exit(0); + } + } + else { + display_usage(); + exit(0); + } + } + else if (!strcmp(arg,"smt2")) { + g_display_smt2 = true; + + } + else if (!strcmp(arg, "file")) { + g_input_file = opt_arg; + } + else if (opt_arg && arg[0] != '"') { + Z3_global_param_set(arg, opt_arg); + } + else { + std::cerr << "parameter " << arg << " was not recognized\n"; + display_usage(); + exit(0); + } + } + else { + g_input_file = arg; + } + ++i; + } + + if (!g_input_file) { + display_usage(); + exit(0); + } +} + +static bool is_smt2_file(char const* filename) { + size_t len = strlen(filename); + return (len > 4 && !strcmp(filename + len - 5,".smt2")); +} + +static void check_error(z3::context& ctx) { + Z3_error_code e = Z3_get_error_code(ctx); + if (e != Z3_OK) { + std::cout << Z3_get_error_msg_ex(ctx, e) << "\n"; + exit(1); + } +} + +static void display_tptp(std::ostream& out) { + // run SMT2 parser, pretty print TFA format. + z3::context ctx; + Z3_ast _fml = Z3_parse_smtlib2_file(ctx, g_input_file, 0, 0, 0, 0, 0, 0); + check_error(ctx); + z3::expr fml(ctx, _fml); + + pp_tptp pp(ctx); + pp.collect_decls(fml); + pp.display_sort_decls(out); + pp.display_func_decls(out); + + if (fml.decl().decl_kind() == Z3_OP_AND) { + for (unsigned i = 0; i < fml.num_args(); ++i) { + pp.display_axiom(out, fml.arg(i)); + } + } + else { + pp.display_axiom(out, fml); + } +} + +static void display_proof(z3::context& ctx, named_formulas& fmls, z3::solver& solver) { + pp_tptp pp(ctx); + pp.display_proof(std::cout, fmls, solver); +} + +static void display_model(z3::context& ctx, z3::model model) { + unsigned nc = model.num_consts(); + unsigned nf = model.num_funcs(); + z3::expr_vector fmls(ctx); + for (unsigned i = 0; i < nc; ++i) { + z3::func_decl f = model.get_const_decl(i); + z3::expr e = model.get_const_interp(f); + fmls.push_back(f() == e); + } + + for (unsigned i = 0; i < nf; ++i) { + z3::func_decl f = model.get_func_decl(i); + z3::func_interp fi = model.get_func_interp(f); + unsigned arity = f.arity(); + z3::expr_vector args(ctx); + for (unsigned j = 0; j < arity; ++j) { + std::ostringstream str; + str << "X" << j; + z3::symbol sym(ctx, Z3_mk_string_symbol(ctx, str.str().c_str())); + args.push_back(ctx.constant(sym, f.domain(j))); + } + unsigned ne = fi.num_entries(); + Z3_ast* conds = new Z3_ast[arity]; + Z3_ast* conds_match = new Z3_ast[ne]; + z3::expr_vector conds_matchv(ctx); + z3::expr els = fi.else_value(); + unsigned num_cases = 0; + for (unsigned k = 0; k < ne; ++k) { + z3::func_entry e = fi.entry(k); + z3::expr_vector condv(ctx), args_e(ctx); + if (((Z3_ast)els) && (Z3_get_ast_id(ctx, els) == Z3_get_ast_id(ctx, e.value()))) { + continue; + } + for (unsigned j = 0; j < arity; ++j) { + args_e.push_back(e.arg(j)); + condv.push_back(e.arg(j) == args[j]); + conds[j] = condv.back(); + } + z3::expr cond(ctx, Z3_mk_and(ctx, arity, conds)); + conds_matchv.push_back(cond); + conds_match[num_cases] = cond; + fmls.push_back(f(args_e) == e.value()); + ++num_cases; + } + if (els) { + els = f(args) == els; + switch (num_cases) { + case 0: els = forall(args, els); break; + case 1: els = forall(args, implies(!z3::expr(ctx, conds_match[0]), els)); break; + default: els = forall(args, implies(!z3::expr(ctx, Z3_mk_or(ctx, num_cases, conds_match)), els)); break; + } + fmls.push_back(els); + } + delete[] conds; + delete[] conds_match; + } + + pp_tptp pp(ctx); + for (unsigned i = 0; i < fmls.size(); ++i) { + pp.collect_decls(fmls[i]); + } + pp.display_sort_decls(std::cout); + pp.display_func_decls(std::cout); + for (unsigned i = 0; i < fmls.size(); ++i) { + pp.display_axiom(std::cout, fmls[i]); + } +} + +static void display_smt2(std::ostream& out) { + z3::config config; + z3::context ctx(config); + named_formulas fmls; + env env(ctx); + try { + env.parse(g_input_file, fmls); + } + catch (failure_ex& ex) { + std::cerr << ex.msg << "\n"; + return; + } + + size_t num_assumptions = fmls.m_formulas.size(); + + Z3_ast* assumptions = new Z3_ast[num_assumptions]; + for (size_t i = 0; i < num_assumptions; ++i) { + assumptions[i] = fmls.m_formulas[i]; + } + Z3_string s = + Z3_benchmark_to_smtlib_string( + ctx, + "Benchmark generated from TPTP", // comment + 0, // no logic is set + "unknown", // no status annotation + "", // attributes + static_cast(num_assumptions), + assumptions, + ctx.bool_val(true)); + + out << s << "\n"; + delete[] assumptions; +} + +static void prove_tptp() { + z3::config config; + if (g_generate_proof) { + config.set("proof", true); + z3::set_param("proof", true); + } + z3::context ctx(config); + z3::solver solver(ctx); + g_solver = &solver; + g_context = &ctx; + if (g_timeout) { + // TBD overflow check + z3::set_param("timeout", g_timeout*1000); + z3::params params(ctx); + params.set("timeout", static_cast(g_timeout*1000)); + solver.set(params); + } + + + named_formulas fmls; + env env(ctx); + try { + env.parse(g_input_file, fmls); + } + catch (failure_ex& ex) { + std::cerr << ex.msg << "\n"; + std::cout << "SZS status GaveUp\n"; + return; + } + + size_t num_assumptions = fmls.m_formulas.size(); + + z3::check_result result; + + if (g_generate_core) { + z3::expr_vector assumptions(ctx); + + for (size_t i = 0; i < num_assumptions; ++i) { + z3::expr pred = ctx.constant(fmls.m_names[i].c_str(), ctx.bool_sort()); + z3::expr def = fmls.m_formulas[i] == pred; + solver.add(def); + assumptions.push_back(pred); + } + result = solver.check(assumptions); + } + else { + for (unsigned i = 0; i < num_assumptions; ++i) { + solver.add(fmls.m_formulas[i]); + } + result = solver.check(); + } + + switch(result) { + case z3::unsat: + if (g_smt2status) { + std::cout << result << "\n"; + } + else if (fmls.has_conjecture()) { + std::cout << "SZS status Theorem\n"; + } + else { + std::cout << "SZS status Unsatisfiable\n"; + } + if (g_generate_proof) { + try { + display_proof(ctx, fmls, solver); + } + catch (failure_ex& ex) { + std::cerr << "Proof display could not be completed: " << ex.msg << "\n"; + } + } + if (g_generate_core) { + z3::expr_vector core = solver.unsat_core(); + std::cout << "SZS core "; + for (unsigned i = 0; i < core.size(); ++i) { + std::cout << core[i] << " "; + } + std::cout << "\n"; + } + break; + case z3::sat: + if (g_smt2status) { + std::cout << result << "\n"; + } + else if (fmls.has_conjecture()) { + std::cout << "SZS status CounterSatisfiable\n"; + } + else { + std::cout << "SZS status Satisfiable\n"; + } + if (g_generate_model) { + display_model(ctx, solver.get_model()); + } + break; + case z3::unknown: + if (g_smt2status) { + std::cout << result << "\n"; + } + else if (!g_first_interrupt) { + std::cout << "SZS status Interrupted\n"; + } + else { + std::cout << "SZS status GaveUp\n"; + std::string reason = solver.reason_unknown(); + std::cout << "SZS reason " << reason << "\n"; + } + break; + } + bool is_sat = true; + if (g_check_status && + result != z3::unknown && + parse_is_sat(g_input_file, is_sat)) { + if (is_sat && result == z3::unsat) { + std::cout << "BUG!! expected result is Satisfiable, returned result is Unsat\n"; + } + if (!is_sat && result == z3::sat) { + std::cout << "BUG!! expected result is Unsatisfiable, returned result is Satisfiable\n"; + } + } + display_statistics(); +} + +int main(int argc, char** argv) { + + std::ostream* out = &std::cout; + g_start_time = static_cast(clock()); + signal(SIGINT, on_ctrl_c); + + parse_cmd_line_args(argc, argv); + + if (is_smt2_file(g_input_file)) { + display_tptp(*g_out); + } + else if (g_display_smt2) { + display_smt2(*g_out); + } + else { + prove_tptp(); + } + return 0; +} + diff --git a/examples/tptp/tptp5.h b/examples/tptp/tptp5.h new file mode 100644 index 000000000..69fe79b28 --- /dev/null +++ b/examples/tptp/tptp5.h @@ -0,0 +1,38 @@ +#ifndef TPTP5_H_ +#define TPTP5_H_ + + +class TreeNode; + +#if 0 +class named_formulas { + expr_ref_vector m_fmls; + svector m_names; + bool m_has_conjecture; + unsigned m_conjecture_index; +public: + named_formulas(ast_manager& m) : + m_fmls(m), + m_has_conjecture(false), + m_conjecture_index(0) + {} + void push_back(expr* fml, char const* name) { + m_fmls.push_back(fml); + m_names.push_back(symbol(name)); + } + unsigned size() const { return m_fmls.size(); } + expr*const* c_ptr() const { return m_fmls.c_ptr(); } + expr* operator[](unsigned i) { return m_fmls[i].get(); } + symbol const& name(unsigned i) { return m_names[i]; } + void set_has_conjecture() { + m_has_conjecture = true; + m_conjecture_index = m_fmls.size(); + } + bool has_conjecture() const { return m_has_conjecture; } + unsigned conjecture_index() const { return m_conjecture_index; } +}; + +bool tptp5_parse(ast_manager& m, char const* filename, named_formulas& fmls); +#endif + +#endif diff --git a/examples/tptp/tptp5.lex.cpp b/examples/tptp/tptp5.lex.cpp new file mode 100644 index 000000000..639d92750 --- /dev/null +++ b/examples/tptp/tptp5.lex.cpp @@ -0,0 +1,2672 @@ +#line 2 "tptp5.lex.cpp" + +#line 4 "tptp5.lex.cpp" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart (FILE *input_file ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +void yy_delete_buffer (YY_BUFFER_STATE b ); +void yy_flush_buffer (YY_BUFFER_STATE b ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state (void ); + +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); + +void *yyalloc (yy_size_t ); +void *yyrealloc (void *,yy_size_t ); +void yyfree (void * ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +typedef unsigned char YY_CHAR; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +typedef int yy_state_type; + +#define YY_FLEX_LEX_COMPAT +extern int yylineno; + +int yylineno = 1; + +extern char yytext[]; + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + if ( yyleng + (yy_more_offset) >= YYLMAX ) \ + YY_FATAL_ERROR( "token too large, exceeds YYLMAX" ); \ + yy_flex_strncpy( &yytext[(yy_more_offset)], (yytext_ptr), yyleng + 1 ); \ + yyleng += (yy_more_offset); \ + (yy_prev_more_offset) = (yy_more_offset); \ + (yy_more_offset) = 0; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 75 +#define YY_END_OF_BUFFER 76 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_acclist[228] = + { 0, + 76, 73, 75, 72, 73, 75, 11, 74, 75, 74, + 75, 74, 75, 74, 75, 71, 74, 75, 1, 74, + 75, 74, 75, 19, 74, 75, 27, 74, 75, 28, + 53, 74, 75, 54, 74, 75, 8, 74, 75, 20, + 74, 75, 22, 74, 75, 74, 75, 63, 65, 66, + 74, 75, 63, 65, 66, 67, 74, 75, 6, 74, + 75, 56, 74, 75, 9, 74, 75, 55, 74, 75, + 23, 74, 75, 2, 74, 75, 50, 74, 75, 15, + 74, 75, 26, 74, 75, 5, 74, 75, 51, 74, + 75, 51, 74, 75, 51, 74, 75, 51, 74, 75, + + 51, 74, 75, 32, 52, 74, 75, 29, 74, 75, + 75, 13, 12, 14, 47, 48, 48, 48, 48, 48, + 71, 63, 64, 63, 64, 70, 63, 65, 66, 67, + 7, 16, 10, 25, 24, 4, 3, 50, 51, 51, + 51, 51, 51, 51, 30, 31, 49, 48, 48, 48, + 48, 48, 48, 46, 63, 64, 21, 70, 57, 59, + 69, 60, 62, 57, 59, 68, 57, 59, 68, 17, + 18, 41, 51, 42, 51, 51, 44, 51, 45, 51, + 49, 33, 48, 34, 48, 35, 48, 48, 39, 48, + 40, 48, 57, 58, 60, 61, 57, 58, 57, 58, + + 71, 57, 59, 69, 60, 62, 57, 59, 68, 51, + 36, 48, 48, 57, 58, 60, 61, 57, 58, 51, + 37, 48, 38, 48, 51, 43, 51 + } ; + +static yyconst flex_int16_t yy_accept[153] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 4, 7, 10, 12, + 14, 16, 19, 22, 24, 27, 30, 34, 37, 40, + 43, 46, 48, 53, 59, 62, 65, 68, 71, 74, + 77, 80, 83, 86, 89, 92, 95, 98, 101, 104, + 108, 111, 112, 113, 114, 115, 115, 116, 116, 116, + 117, 118, 119, 120, 121, 122, 122, 122, 124, 126, + 126, 127, 127, 127, 127, 127, 131, 132, 133, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + + 154, 154, 155, 155, 155, 155, 155, 157, 158, 159, + 159, 159, 162, 164, 167, 170, 171, 172, 174, 176, + 177, 179, 181, 182, 184, 186, 188, 189, 191, 193, + 195, 197, 199, 201, 201, 201, 202, 205, 207, 210, + 211, 213, 214, 216, 218, 220, 221, 223, 225, 226, + 228, 228 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 22, 7, 23, + 24, 25, 26, 27, 28, 28, 28, 28, 29, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 30, 31, 32, 33, 34, 7, 35, 35, 36, 37, + + 38, 39, 35, 40, 41, 35, 35, 42, 35, 43, + 44, 35, 35, 35, 35, 45, 46, 35, 35, 35, + 35, 35, 7, 47, 7, 48, 49, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50 + } ; + +static yyconst flex_int32_t yy_meta[51] = + { 0, + 1, 1, 2, 3, 3, 3, 3, 4, 3, 3, + 5, 3, 3, 3, 3, 3, 3, 3, 3, 6, + 6, 3, 3, 3, 3, 3, 3, 6, 6, 3, + 3, 3, 3, 6, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 3, 3, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[164] = + { 0, + 0, 0, 15, 16, 23, 30, 31, 38, 45, 46, + 53, 60, 61, 68, 302, 303, 303, 90, 47, 303, + 80, 0, 303, 270, 303, 303, 303, 90, 303, 103, + 97, 286, 108, 110, 275, 84, 273, 303, 108, 48, + 0, 303, 303, 303, 0, 254, 252, 252, 96, 303, + 93, 303, 303, 303, 303, 127, 303, 132, 0, 0, + 222, 213, 209, 102, 0, 62, 133, 131, 133, 228, + 135, 231, 145, 223, 147, 154, 303, 218, 217, 303, + 303, 303, 303, 303, 0, 0, 202, 201, 202, 197, + 196, 303, 303, 0, 0, 180, 131, 171, 157, 143, + + 146, 303, 148, 160, 157, 164, 168, 303, 170, 147, + 179, 174, 179, 303, 181, 303, 303, 0, 0, 105, + 0, 0, 0, 0, 0, 0, 165, 0, 0, 187, + 193, 303, 197, 131, 201, 303, 201, 203, 206, 97, + 0, 166, 208, 211, 213, 75, 0, 0, 42, 0, + 303, 244, 248, 255, 260, 262, 264, 51, 266, 271, + 278, 280, 287 + } ; + +static yyconst flex_int16_t yy_def[164] = + { 0, + 151, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 151, 151, 151, 151, 152, 151, + 153, 154, 151, 155, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, + 156, 151, 151, 151, 157, 157, 157, 157, 157, 151, + 151, 151, 151, 151, 151, 152, 151, 151, 158, 159, + 159, 159, 159, 159, 154, 160, 151, 151, 151, 151, + 151, 161, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 156, 157, 157, 157, 157, 157, + 157, 151, 151, 162, 159, 159, 159, 159, 159, 159, + + 160, 151, 151, 151, 151, 151, 151, 151, 151, 161, + 163, 151, 151, 151, 151, 151, 151, 157, 157, 157, + 157, 157, 162, 159, 159, 159, 159, 159, 159, 151, + 151, 151, 151, 161, 163, 151, 151, 151, 151, 157, + 159, 159, 151, 151, 151, 157, 159, 159, 157, 157, + 0, 151, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151 + } ; + +static yyconst flex_int16_t yy_nxt[354] = + { 0, + 16, 17, 17, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 41, 42, + 20, 43, 44, 20, 45, 46, 45, 45, 47, 45, + 48, 45, 45, 45, 49, 45, 50, 51, 16, 52, + 45, 45, 57, 45, 45, 45, 45, 94, 45, 45, + 45, 45, 83, 45, 84, 45, 45, 45, 45, 45, + 45, 45, 102, 45, 45, 45, 45, 58, 45, 150, + 45, 45, 45, 45, 45, 45, 45, 59, 45, 45, + 45, 45, 103, 45, 53, 45, 45, 45, 45, 45, + + 45, 45, 92, 45, 45, 45, 45, 78, 45, 68, + 69, 149, 45, 54, 55, 61, 71, 71, 62, 70, + 63, 81, 68, 69, 64, 73, 74, 73, 74, 76, + 76, 79, 57, 82, 90, 91, 75, 56, 75, 93, + 99, 100, 146, 66, 111, 75, 140, 75, 104, 105, + 104, 105, 107, 107, 109, 109, 102, 58, 101, 106, + 111, 106, 56, 66, 112, 112, 114, 115, 106, 125, + 106, 73, 74, 76, 76, 126, 103, 131, 101, 130, + 130, 129, 75, 132, 133, 104, 105, 107, 107, 109, + 109, 75, 135, 137, 137, 128, 106, 136, 138, 138, + + 139, 139, 75, 141, 147, 106, 143, 143, 127, 142, + 148, 75, 144, 144, 135, 106, 145, 145, 124, 136, + 137, 137, 138, 138, 106, 139, 139, 143, 143, 75, + 144, 144, 145, 145, 122, 121, 106, 120, 75, 119, + 118, 117, 116, 113, 111, 106, 56, 56, 56, 56, + 56, 60, 108, 98, 60, 65, 97, 65, 65, 65, + 65, 65, 66, 66, 96, 66, 66, 85, 85, 86, + 86, 95, 95, 101, 101, 101, 101, 101, 110, 110, + 110, 110, 110, 110, 110, 123, 123, 134, 134, 134, + 134, 134, 134, 134, 89, 88, 87, 80, 77, 72, + + 67, 151, 15, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151 + } ; + +static yyconst flex_int16_t yy_chk[354] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 4, 19, 3, 4, 3, 4, 158, 5, 3, + 4, 5, 40, 5, 40, 6, 7, 5, 6, 7, + 6, 7, 66, 8, 6, 7, 8, 19, 8, 149, + 9, 10, 8, 9, 10, 9, 10, 21, 11, 9, + 10, 11, 66, 11, 18, 12, 13, 11, 12, 13, + + 12, 13, 51, 14, 12, 13, 14, 36, 14, 28, + 28, 146, 14, 18, 18, 21, 31, 31, 21, 30, + 21, 39, 30, 30, 21, 33, 33, 34, 34, 34, + 34, 36, 56, 39, 49, 49, 33, 58, 34, 51, + 64, 64, 140, 67, 134, 33, 120, 34, 68, 68, + 69, 69, 69, 69, 71, 71, 101, 56, 103, 68, + 110, 69, 58, 67, 73, 73, 75, 75, 68, 97, + 69, 76, 76, 76, 76, 97, 101, 105, 103, 104, + 104, 100, 76, 106, 106, 107, 107, 107, 107, 109, + 109, 76, 111, 112, 112, 99, 107, 111, 113, 113, + + 115, 115, 112, 127, 142, 107, 130, 130, 98, 127, + 142, 112, 131, 131, 135, 130, 133, 133, 96, 135, + 137, 137, 138, 138, 130, 139, 139, 143, 143, 137, + 144, 144, 145, 145, 91, 90, 143, 89, 137, 88, + 87, 79, 78, 74, 72, 143, 152, 152, 152, 152, + 152, 153, 70, 63, 153, 154, 62, 154, 154, 154, + 154, 154, 155, 155, 61, 155, 155, 156, 156, 157, + 157, 159, 159, 160, 160, 160, 160, 160, 161, 161, + 161, 161, 161, 161, 161, 162, 162, 163, 163, 163, + 163, 163, 163, 163, 48, 47, 46, 37, 35, 32, + + 24, 15, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151 + } ; + +/* Table of booleans, true if rule could match eol. */ +static yyconst flex_int32_t yy_rule_can_match_eol[76] = + { 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, }; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +static yy_state_type *yy_state_buf=0, *yy_state_ptr=0; +static char *yy_full_match; +static int yy_lp; +#define REJECT \ +{ \ +*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ \ +yy_cp = (yy_full_match); /* restore poss. backed-over text */ \ +++(yy_lp); \ +goto find_rule; \ +} + +static int yy_more_offset = 0; +static int yy_prev_more_offset = 0; +#define yymore() ((yy_more_offset) = yy_flex_strlen( yytext )) +#define YY_NEED_STRLEN +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET \ + { \ + (yy_more_offset) = (yy_prev_more_offset); \ + yyleng -= (yy_more_offset); \ + } +#ifndef YYLMAX +#define YYLMAX 8192 +#endif + +char yytext[YYLMAX]; +char *yytext_ptr; +#line 1 "tptp5.l" +#line 3 "tptp5.l" +//----------------------------------------------------------------------------- +#include +#include +#include + +#if _WINDOWS + #include + #define isatty _isatty +#else + // Linux + #include + #define _strdup strdup +#endif + +#include "tptp5.h" +#include "tptp5.tab.h" + + +#define YY_NO_UNISTD_H +#define YY_SKIP_YYWRAP +static int yywrap() { return 1; } +//----------------------------------------------------------------------------- +//----Compile with -DP_VERBOSE=2 to list tokens as they are seen. +#ifndef P_VERBOSE +# define P_VERBOSE 0 +# endif +int verbose2 = P_VERBOSE; + +//----If tptp_prev_tok == PERIOD, you are outside any sentence. +//#ifndef PERIOD +//# error "Period not defined" +//# define PERIOD 46 +//# endif + +#define TPTP_STORE_SIZE 32768 + +//----These have to be external as they are references from other code that +//----is generated by lex/yacc. +int tptp_prev_tok = PERIOD; +int tptp_store_size = TPTP_STORE_SIZE; +char* tptp_lval[TPTP_STORE_SIZE]; +//----------------------------------------------------------------------------- +void tptp_print_tok(char* lval) { + + printf("%3d:%s;\n", tptp_prev_tok, lval); + + return; +} +//----------------------------------------------------------------------------- +int tptp_update_lval(char* lval) { + + static int tptp_next_store = 0; + int next = tptp_next_store; + + free(tptp_lval[tptp_next_store]); + tptp_lval[tptp_next_store] = _strdup(lval); + tptp_next_store = (tptp_next_store+1) % TPTP_STORE_SIZE; + if (verbose2 == 2) { + tptp_print_tok(lval); + } + + return next; +} +//----------------------------------------------------------------------------- +//----%Start: INITIAL begin sentence, B before formula. No others. + +#line 710 "tptp5.lex.cpp" + +#define INITIAL 0 +#define B 1 +#define FF 2 +#define SQ1 3 +#define SQ2 4 +#define Q1 5 +#define Q2 6 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (void ); + +int yyget_debug (void ); + +void yyset_debug (int debug_flag ); + +YY_EXTRA_TYPE yyget_extra (void ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in (void ); + +void yyset_in (FILE * in_str ); + +FILE *yyget_out (void ); + +void yyset_out (FILE * out_str ); + +int yyget_leng (void ); + +char *yyget_text (void ); + +int yyget_lineno (void ); + +void yyset_lineno (int line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (void ); +#else +extern int yywrap (void ); +#endif +#endif + + static void yyunput (int c,char *buf_ptr ); + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 110 "tptp5.l" + + +#line 901 "tptp5.lex.cpp" + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + /* Create the reject buffer large enough to save one state per allowed character. */ + if ( ! (yy_state_buf) ) + (yy_state_buf) = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE ); + if ( ! (yy_state_buf) ) + YY_FATAL_ERROR( "out of dynamic memory in yylex()" ); + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); + + (yy_state_ptr) = (yy_state_buf); + *(yy_state_ptr)++ = yy_current_state; + +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 152 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + *(yy_state_ptr)++ = yy_current_state; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 303 ); + +yy_find_action: + yy_current_state = *--(yy_state_ptr); + (yy_lp) = yy_accept[yy_current_state]; +goto find_rule; +find_rule: /* we branch to this label when backing up */ + for ( ; ; ) /* until we find what rule we matched */ + { + if ( (yy_lp) && (yy_lp) < yy_accept[yy_current_state + 1] ) + { + yy_act = yy_acclist[(yy_lp)]; + { + (yy_full_match) = yy_cp; + break; + } + } + --yy_cp; + yy_current_state = *--(yy_state_ptr); + (yy_lp) = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = (yy_prev_more_offset); yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + yylineno++; +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ +case 1: +YY_RULE_SETUP +#line 112 "tptp5.l" +{ + tptp_prev_tok=AMPERSAND; + yylval.ival = tptp_update_lval(yytext); + return(AMPERSAND); +} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 117 "tptp5.l" +{ + tptp_prev_tok=AT_SIGN; + yylval.ival = tptp_update_lval(yytext); + return(AT_SIGN); +} + YY_BREAK +case 3: +YY_RULE_SETUP +#line 122 "tptp5.l" +{ + tptp_prev_tok=AT_SIGN_MINUS; + yylval.ival = tptp_update_lval(yytext); + return(AT_SIGN_MINUS); +} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 127 "tptp5.l" +{ + tptp_prev_tok=AT_SIGN_PLUS; + yylval.ival = tptp_update_lval(yytext); + return(AT_SIGN_PLUS); +} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 132 "tptp5.l" +{ + tptp_prev_tok=CARET; + yylval.ival = tptp_update_lval(yytext); + return(CARET); +} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 137 "tptp5.l" +{ + tptp_prev_tok=COLON; + yylval.ival = tptp_update_lval(yytext); + return(COLON); +} + YY_BREAK +case 7: +YY_RULE_SETUP +#line 142 "tptp5.l" +{ + tptp_prev_tok=COLON_EQUALS; + yylval.ival = tptp_update_lval(yytext); + return(COLON_EQUALS); +} + YY_BREAK +case 8: +YY_RULE_SETUP +#line 147 "tptp5.l" +{ + tptp_prev_tok=COMMA; + yylval.ival = tptp_update_lval(yytext); + return(COMMA); +} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 152 "tptp5.l" +{ + tptp_prev_tok=EQUALS; + yylval.ival = tptp_update_lval(yytext); + return(EQUALS); +} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 157 "tptp5.l" +{ + tptp_prev_tok=EQUALS_GREATER; + yylval.ival = tptp_update_lval(yytext); + return(EQUALS_GREATER); +} + YY_BREAK +case 11: +YY_RULE_SETUP +#line 162 "tptp5.l" +{ + tptp_prev_tok=EXCLAMATION; + yylval.ival = tptp_update_lval(yytext); + return(EXCLAMATION); +} + YY_BREAK +case 12: +YY_RULE_SETUP +#line 167 "tptp5.l" +{ + tptp_prev_tok=EXCLAMATION_EQUALS; + yylval.ival = tptp_update_lval(yytext); + return(EXCLAMATION_EQUALS); +} + YY_BREAK +case 13: +YY_RULE_SETUP +#line 172 "tptp5.l" +{ + tptp_prev_tok=EXCLAMATION_EXCLAMATION; + yylval.ival = tptp_update_lval(yytext); + return(EXCLAMATION_EXCLAMATION); +} + YY_BREAK +case 14: +YY_RULE_SETUP +#line 177 "tptp5.l" +{ + tptp_prev_tok=EXCLAMATION_GREATER; + yylval.ival = tptp_update_lval(yytext); + return(EXCLAMATION_GREATER); +} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 182 "tptp5.l" +{ + tptp_prev_tok=LBRKT; + yylval.ival = tptp_update_lval(yytext); + return(LBRKT); +} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 187 "tptp5.l" +{ + tptp_prev_tok=LESS_EQUALS; + yylval.ival = tptp_update_lval(yytext); + return(LESS_EQUALS); +} + YY_BREAK +case 17: +YY_RULE_SETUP +#line 192 "tptp5.l" +{ + tptp_prev_tok=LESS_EQUALS_GREATER; + yylval.ival = tptp_update_lval(yytext); + return(LESS_EQUALS_GREATER); +} + YY_BREAK +case 18: +YY_RULE_SETUP +#line 197 "tptp5.l" +{ + tptp_prev_tok=LESS_TILDE_GREATER; + yylval.ival = tptp_update_lval(yytext); + return(LESS_TILDE_GREATER); +} + YY_BREAK +case 19: +YY_RULE_SETUP +#line 202 "tptp5.l" +{ + tptp_prev_tok=LPAREN; + yylval.ival = tptp_update_lval(yytext); + return(LPAREN); +} + YY_BREAK +case 20: +YY_RULE_SETUP +#line 207 "tptp5.l" +{ + tptp_prev_tok=MINUS; + yylval.ival = tptp_update_lval(yytext); + return(MINUS); +} + YY_BREAK +case 21: +YY_RULE_SETUP +#line 212 "tptp5.l" +{ + tptp_prev_tok=MINUS_MINUS_GREATER; + yylval.ival = tptp_update_lval(yytext); + return(MINUS_MINUS_GREATER); +} + YY_BREAK +case 22: +YY_RULE_SETUP +#line 217 "tptp5.l" +{ + BEGIN INITIAL; + tptp_prev_tok=PERIOD; + yylval.ival = tptp_update_lval(yytext); + return(PERIOD); +} + YY_BREAK +case 23: +YY_RULE_SETUP +#line 223 "tptp5.l" +{ + tptp_prev_tok=QUESTION; + yylval.ival = tptp_update_lval(yytext); + return(QUESTION); +} + YY_BREAK +case 24: +YY_RULE_SETUP +#line 228 "tptp5.l" +{ + tptp_prev_tok=QUESTION_QUESTION; + yylval.ival = tptp_update_lval(yytext); + return(QUESTION_QUESTION); +} + YY_BREAK +case 25: +YY_RULE_SETUP +#line 233 "tptp5.l" +{ + tptp_prev_tok=QUESTION_STAR; + yylval.ival = tptp_update_lval(yytext); + return(QUESTION_STAR); +} + YY_BREAK +case 26: +YY_RULE_SETUP +#line 238 "tptp5.l" +{ + tptp_prev_tok=RBRKT; + yylval.ival = tptp_update_lval(yytext); + return(RBRKT); +} + YY_BREAK +case 27: +YY_RULE_SETUP +#line 243 "tptp5.l" +{ + tptp_prev_tok=RPAREN; + yylval.ival = tptp_update_lval(yytext); + return(RPAREN); +} + YY_BREAK +case 28: +YY_RULE_SETUP +#line 248 "tptp5.l" +{ + tptp_prev_tok=STAR; + yylval.ival = tptp_update_lval(yytext); + return(STAR); +} + YY_BREAK +case 29: +YY_RULE_SETUP +#line 253 "tptp5.l" +{ + tptp_prev_tok=TILDE; + yylval.ival = tptp_update_lval(yytext); + return(TILDE); +} + YY_BREAK +case 30: +YY_RULE_SETUP +#line 258 "tptp5.l" +{ + tptp_prev_tok=TILDE_AMPERSAND; + yylval.ival = tptp_update_lval(yytext); + return(TILDE_AMPERSAND); +} + YY_BREAK +case 31: +YY_RULE_SETUP +#line 263 "tptp5.l" +{ + tptp_prev_tok=TILDE_VLINE; + yylval.ival = tptp_update_lval(yytext); + return(TILDE_VLINE); +} + YY_BREAK +case 32: +YY_RULE_SETUP +#line 268 "tptp5.l" +{ + tptp_prev_tok=VLINE; + yylval.ival = tptp_update_lval(yytext); + return(VLINE); +} + YY_BREAK +case 33: +YY_RULE_SETUP +#line 273 "tptp5.l" +{ + tptp_prev_tok=_DLR_cnf; + yylval.ival = tptp_update_lval(yytext); + return(_DLR_cnf); +} + YY_BREAK +case 34: +YY_RULE_SETUP +#line 278 "tptp5.l" +{ + tptp_prev_tok=_DLR_fof; + yylval.ival = tptp_update_lval(yytext); + return(_DLR_fof); +} + YY_BREAK +case 35: +YY_RULE_SETUP +#line 283 "tptp5.l" +{ + tptp_prev_tok=_DLR_fot; + yylval.ival = tptp_update_lval(yytext); + return(_DLR_fot); +} + YY_BREAK +case 36: +YY_RULE_SETUP +#line 288 "tptp5.l" +{ + tptp_prev_tok=_DLR_itef; + yylval.ival = tptp_update_lval(yytext); + return(_DLR_itef); +} + YY_BREAK +case 37: +YY_RULE_SETUP +#line 293 "tptp5.l" +{ + tptp_prev_tok=_DLR_itetf; + yylval.ival = tptp_update_lval(yytext); + return(_DLR_itetf); +} + YY_BREAK +case 38: +YY_RULE_SETUP +#line 298 "tptp5.l" +{ + tptp_prev_tok=_DLR_itett; + yylval.ival = tptp_update_lval(yytext); + return(_DLR_itett); +} + YY_BREAK +case 39: +YY_RULE_SETUP +#line 303 "tptp5.l" +{ + tptp_prev_tok=_DLR_tff; + yylval.ival = tptp_update_lval(yytext); + return(_DLR_tff); +} + YY_BREAK +case 40: +YY_RULE_SETUP +#line 308 "tptp5.l" +{ + tptp_prev_tok=_DLR_thf; + yylval.ival = tptp_update_lval(yytext); + return(_DLR_thf); +} + YY_BREAK +case 41: +YY_RULE_SETUP +#line 313 "tptp5.l" +{ + BEGIN B; + tptp_prev_tok=_LIT_cnf; + yylval.ival = tptp_update_lval(yytext); + return(_LIT_cnf); +} + YY_BREAK +case 42: +YY_RULE_SETUP +#line 319 "tptp5.l" +{ + BEGIN B; + tptp_prev_tok=_LIT_fof; + yylval.ival = tptp_update_lval(yytext); + return(_LIT_fof); +} + YY_BREAK +case 43: +YY_RULE_SETUP +#line 325 "tptp5.l" +{ + BEGIN B; + tptp_prev_tok=_LIT_include; + yylval.ival = tptp_update_lval(yytext); + return(_LIT_include); +} + YY_BREAK +case 44: +YY_RULE_SETUP +#line 331 "tptp5.l" +{ + BEGIN B; + tptp_prev_tok=_LIT_tff; + yylval.ival = tptp_update_lval(yytext); + return(_LIT_tff); +} + YY_BREAK +case 45: +YY_RULE_SETUP +#line 337 "tptp5.l" +{ + BEGIN B; + tptp_prev_tok=_LIT_thf; + yylval.ival = tptp_update_lval(yytext); + return(_LIT_thf); +} + YY_BREAK +case 46: +YY_RULE_SETUP +#line 344 "tptp5.l" +{ + tptp_prev_tok=single_quoted; + yylval.ival = tptp_update_lval(yytext); + return(single_quoted); +} + YY_BREAK +case 47: +YY_RULE_SETUP +#line 349 "tptp5.l" +{ + tptp_prev_tok=distinct_object; + yylval.ival = tptp_update_lval(yytext); + return(distinct_object); +} + YY_BREAK +case 48: +YY_RULE_SETUP +#line 354 "tptp5.l" +{ + tptp_prev_tok=dollar_word; + yylval.ival = tptp_update_lval(yytext); + return(dollar_word); +} + YY_BREAK +case 49: +YY_RULE_SETUP +#line 359 "tptp5.l" +{ + tptp_prev_tok=dollar_dollar_word; + yylval.ival = tptp_update_lval(yytext); + return(dollar_dollar_word); +} + YY_BREAK +case 50: +YY_RULE_SETUP +#line 364 "tptp5.l" +{ + tptp_prev_tok=upper_word; + yylval.ival = tptp_update_lval(yytext); + return(upper_word); +} + YY_BREAK +case 51: +YY_RULE_SETUP +#line 369 "tptp5.l" +{ + tptp_prev_tok=lower_word; + yylval.ival = tptp_update_lval(yytext); + return(lower_word); +} + YY_BREAK +case 52: +YY_RULE_SETUP +#line 374 "tptp5.l" +{ + tptp_prev_tok=vline; + yylval.ival = tptp_update_lval(yytext); + return(vline); +} + YY_BREAK +case 53: +YY_RULE_SETUP +#line 379 "tptp5.l" +{ + tptp_prev_tok=star; + yylval.ival = tptp_update_lval(yytext); + return(star); +} + YY_BREAK +case 54: +YY_RULE_SETUP +#line 384 "tptp5.l" +{ + tptp_prev_tok=plus; + yylval.ival = tptp_update_lval(yytext); + return(plus); +} + YY_BREAK +case 55: +YY_RULE_SETUP +#line 389 "tptp5.l" +{ + tptp_prev_tok=arrow; + yylval.ival = tptp_update_lval(yytext); + return(arrow); +} + YY_BREAK +case 56: +YY_RULE_SETUP +#line 394 "tptp5.l" +{ + tptp_prev_tok=less_sign; + yylval.ival = tptp_update_lval(yytext); + return(less_sign); +} + YY_BREAK +case 57: +YY_RULE_SETUP +#line 399 "tptp5.l" +{ + tptp_prev_tok=real; + yylval.ival = tptp_update_lval(yytext); + return(real); +} + YY_BREAK +case 58: +YY_RULE_SETUP +#line 404 "tptp5.l" +{ + tptp_prev_tok=signed_real; + yylval.ival = tptp_update_lval(yytext); + return(signed_real); +} + YY_BREAK +case 59: +YY_RULE_SETUP +#line 409 "tptp5.l" +{ + tptp_prev_tok=unsigned_real; + yylval.ival = tptp_update_lval(yytext); + return(unsigned_real); +} + YY_BREAK +case 60: +YY_RULE_SETUP +#line 414 "tptp5.l" +{ + tptp_prev_tok=rational; + yylval.ival = tptp_update_lval(yytext); + return(rational); +} + YY_BREAK +case 61: +YY_RULE_SETUP +#line 419 "tptp5.l" +{ + tptp_prev_tok=signed_rational; + yylval.ival = tptp_update_lval(yytext); + return(signed_rational); +} + YY_BREAK +case 62: +YY_RULE_SETUP +#line 424 "tptp5.l" +{ + tptp_prev_tok=unsigned_rational; + yylval.ival = tptp_update_lval(yytext); + return(unsigned_rational); +} + YY_BREAK +case 63: +YY_RULE_SETUP +#line 429 "tptp5.l" +{ + tptp_prev_tok=integer; + yylval.ival = tptp_update_lval(yytext); + return(integer); +} + YY_BREAK +case 64: +YY_RULE_SETUP +#line 434 "tptp5.l" +{ + tptp_prev_tok=signed_integer; + yylval.ival = tptp_update_lval(yytext); + return(signed_integer); +} + YY_BREAK +case 65: +YY_RULE_SETUP +#line 439 "tptp5.l" +{ + tptp_prev_tok=unsigned_integer; + yylval.ival = tptp_update_lval(yytext); + return(unsigned_integer); +} + YY_BREAK +case 66: +YY_RULE_SETUP +#line 444 "tptp5.l" +{ + tptp_prev_tok=decimal; + yylval.ival = tptp_update_lval(yytext); + return(decimal); +} + YY_BREAK +case 67: +YY_RULE_SETUP +#line 449 "tptp5.l" +{ + tptp_prev_tok=positive_decimal; + yylval.ival = tptp_update_lval(yytext); + return(positive_decimal); +} + YY_BREAK +case 68: +YY_RULE_SETUP +#line 454 "tptp5.l" +{ + tptp_prev_tok=decimal_exponent; + yylval.ival = tptp_update_lval(yytext); + return(decimal_exponent); +} + YY_BREAK +case 69: +YY_RULE_SETUP +#line 459 "tptp5.l" +{ + tptp_prev_tok=decimal_fraction; + yylval.ival = tptp_update_lval(yytext); + return(decimal_fraction); +} + YY_BREAK +case 70: +YY_RULE_SETUP +#line 464 "tptp5.l" +{ + tptp_prev_tok=dot_decimal; + yylval.ival = tptp_update_lval(yytext); + return(dot_decimal); +} + YY_BREAK +case 71: +/* rule 71 can match eol */ +YY_RULE_SETUP +#line 469 "tptp5.l" +tptp_update_lval(yytext); + YY_BREAK +case 72: +/* rule 72 can match eol */ +YY_RULE_SETUP +#line 470 "tptp5.l" +; + YY_BREAK +case 73: +/* rule 73 can match eol */ +YY_RULE_SETUP +#line 471 "tptp5.l" +; + YY_BREAK +case 74: +YY_RULE_SETUP +#line 472 "tptp5.l" +return(unrecognized); + YY_BREAK +case 75: +YY_RULE_SETUP +#line 473 "tptp5.l" +ECHO; + YY_BREAK +#line 1667 "tptp5.lex.cpp" + case YY_STATE_EOF(INITIAL): + case YY_STATE_EOF(B): + case YY_STATE_EOF(FF): + case YY_STATE_EOF(SQ1): + case YY_STATE_EOF(SQ2): + case YY_STATE_EOF(Q1): + case YY_STATE_EOF(Q2): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + size_t num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (int)num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + (yy_state_ptr) = (yy_state_buf); + *(yy_state_ptr)++ = yy_current_state; + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 152 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + *(yy_state_ptr)++ = yy_current_state; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + + register YY_CHAR yy_c = 1; + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 152 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 151); + if ( ! yy_is_jam ) + *(yy_state_ptr)++ = yy_current_state; + + return yy_is_jam ? 0 : yy_current_state; +} + + static void yyunput (int c, register char * yy_bp ) +{ + register char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up yytext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = (yy_n_chars) + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + register char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = (int)YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + if ( c == '\n' ){ + --yylineno; + } + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + size_t offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + if ( c == '\n' ) + + yylineno++; +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ); + + yyfree((void *) b ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + +#ifdef _WINDOWS + b->yy_is_interactive = file ? (isatty( _fileno(file) ) > 0) : 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = (int)b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) +{ + + return yy_scan_bytes(yystr,(int)strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param line_number + * + */ +void yyset_lineno (int line_number ) +{ + + yylineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * in_str ) +{ + yyin = in_str ; +} + +void yyset_out (FILE * out_str ) +{ + yyout = out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int bdebug ) +{ + yy_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + /* We do not touch yylineno unless the option is enabled. */ + yylineno = 1; + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + + (yy_state_buf) = 0; + (yy_state_ptr) = 0; + (yy_full_match) = 0; + (yy_lp) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + yyfree ( (yy_state_buf) ); + (yy_state_buf) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 473 "tptp5.l" + + diff --git a/examples/tptp/tptp5.tab.c b/examples/tptp/tptp5.tab.c new file mode 100644 index 000000000..7fcf7915b --- /dev/null +++ b/examples/tptp/tptp5.tab.c @@ -0,0 +1,4475 @@ +/* A Bison parser, made by GNU Bison 2.4.2. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2006, 2009-2010 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.2" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Copy the first part of user declarations. */ + +/* Line 189 of yacc.c */ +#line 2 "tptp5.y" + +//----------------------------------------------------------------------------- +#include +#include +#include +//----------------------------------------------------------------------------- +//----Compile with -DP_VERBOSE=1 for verbose output. +#ifndef P_VERBOSE +# define P_VERBOSE 0 +#endif +int verbose = P_VERBOSE; + +//----Compile with -DP_USERPROC=1 to #include p_user_proc.c. p_user_proc.c +//----should #define P_ACT, P_BUILD, P_TOKEN, P_PRINT to different procedures +//----from those below, and supply code. +#ifdef P_USERPROC + +#else +# define P_ACT(ss) if(verbose)printf("%7d %s\n",yylineno,ss); +# define P_BUILD(sym,A,B,C,D,E,F,G,H,I,J) pBuildTree(sym,A,B,C,D,E,F,G,H,I,J) +# define P_TOKEN(tok,symbolIndex) pToken(tok,symbolIndex) +# define P_PRINT(ss) if(verbose){printf("\n\n");pPrintTree(ss,0);} +#endif + +extern int yylineno; +extern int yychar; +extern char yytext[]; + +extern int tptp_store_size; +extern char* tptp_lval[]; + +#define MAX_CHILDREN 12 +typedef struct pTreeNode * pTree; +struct pTreeNode { + char* symbol; + int symbolIndex; + pTree children[MAX_CHILDREN+1]; +}; +//----------------------------------------------------------------------------- +int yyerror( char *s ) { + + fprintf( stderr, "%s in line %d at item \"%s\".\n", s, yylineno, yytext); + return 0; +} +//----------------------------------------------------------------------------- +pTree pBuildTree(char* symbol,pTree A,pTree B,pTree C,pTree D,pTree E,pTree F, +pTree G, pTree H, pTree I, pTree J) { + + pTree ss = (pTree)calloc(1,sizeof(struct pTreeNode)); + + ss->symbol = symbol; + ss->symbolIndex = -1; + ss->children[0] = A; + ss->children[1] = B; + ss->children[2] = C; + ss->children[3] = D; + ss->children[4] = E; + ss->children[5] = F; + ss->children[6] = G; + ss->children[7] = H; + ss->children[8] = I; + ss->children[9] = J; + ss->children[10] = NULL; + + return ss; +} +//----------------------------------------------------------------------------- +pTree pToken(char* token, int symbolIndex) { + + //char pTokenBuf[8240]; + pTree ss; + char* symbol = tptp_lval[symbolIndex]; + char* safeSym = 0; + + //strncpy(pTokenBuf, token, 39); + //strncat(pTokenBuf, symbol, 8193); + //safeSym = strdup(pTokenBuf); + ss = pBuildTree(safeSym,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); + ss->symbolIndex = symbolIndex; + + return ss; +} +//----------------------------------------------------------------------------- +void pPrintComments(int start, int depth) { + + int d, j; + char c1[4] = "%", c2[4] = "/*"; + + j = start; + while (tptp_lval[j] != NULL && (tptp_lval[j][0]==c1[0] || +(tptp_lval[j][0]==c2[0] && tptp_lval[j][1]==c2[1]))) { + for (d=0; d= 0) { + pPrintComments(pPrintIdx, 0); + pPrintIdx = -1; + } + if (ss == NULL) { + return; + } + for (d = 0; d < depth-1; d++) { + printf("| "); + } + printf("%1d ",depth % 10); + if (ss->children[0] == NULL) { + printf("%s\n", ss->symbol); + } else { + printf("<%s>\n", ss->symbol); + } + if (strcmp(ss->symbol, "PERIOD .") == 0) { + pPrintIdx = (ss->symbolIndex+1) % tptp_store_size; + } + if (ss->symbolIndex >= 0) { + pPrintComments((ss->symbolIndex+1) % tptp_store_size, depth); + } + i = 0; + while(ss->children[i] != NULL) { + pPrintTree(ss->children[i],depth+1); + i++; + } + return; +} +//----------------------------------------------------------------------------- +int yywrap(void) { + + P_PRINT(NULL); + return 1; +} +//----------------------------------------------------------------------------- + + +/* Line 189 of yacc.c */ +#line 219 "tptp5.tab.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + AMPERSAND = 258, + AT_SIGN = 259, + AT_SIGN_MINUS = 260, + AT_SIGN_PLUS = 261, + CARET = 262, + COLON = 263, + COLON_EQUALS = 264, + COMMA = 265, + EQUALS = 266, + EQUALS_GREATER = 267, + EXCLAMATION = 268, + EXCLAMATION_EQUALS = 269, + EXCLAMATION_EXCLAMATION = 270, + EXCLAMATION_GREATER = 271, + LBRKT = 272, + LESS_EQUALS = 273, + LESS_EQUALS_GREATER = 274, + LESS_TILDE_GREATER = 275, + LPAREN = 276, + MINUS = 277, + MINUS_MINUS_GREATER = 278, + PERIOD = 279, + QUESTION = 280, + QUESTION_QUESTION = 281, + QUESTION_STAR = 282, + RBRKT = 283, + RPAREN = 284, + STAR = 285, + TILDE = 286, + TILDE_AMPERSAND = 287, + TILDE_VLINE = 288, + VLINE = 289, + _DLR_cnf = 290, + _DLR_fof = 291, + _DLR_fot = 292, + _DLR_itef = 293, + _DLR_itetf = 294, + _DLR_itett = 295, + _DLR_tff = 296, + _DLR_thf = 297, + _LIT_cnf = 298, + _LIT_fof = 299, + _LIT_include = 300, + _LIT_tff = 301, + _LIT_thf = 302, + arrow = 303, + comment = 304, + comment_line = 305, + decimal = 306, + decimal_exponent = 307, + decimal_fraction = 308, + distinct_object = 309, + dollar_dollar_word = 310, + dollar_word = 311, + dot_decimal = 312, + integer = 313, + less_sign = 314, + lower_word = 315, + plus = 316, + positive_decimal = 317, + rational = 318, + real = 319, + signed_integer = 320, + signed_rational = 321, + signed_real = 322, + single_quoted = 323, + star = 324, + unrecognized = 325, + unsigned_integer = 326, + unsigned_rational = 327, + unsigned_real = 328, + upper_word = 329, + vline = 330 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 214 of yacc.c */ +#line 148 "tptp5.y" +int ival; double dval; char* sval; TreeNode* pval; + + +/* Line 214 of yacc.c */ +#line 334 "tptp5.tab.c" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 264 of yacc.c */ +#line 346 "tptp5.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 3 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 1612 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 76 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 141 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 281 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 523 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 330 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 5, 8, 10, 12, 14, 16, 18, + 20, 31, 42, 53, 64, 68, 70, 72, 74, 76, + 78, 80, 82, 84, 86, 88, 90, 94, 96, 98, + 100, 104, 108, 112, 116, 120, 124, 126, 128, 130, + 132, 134, 136, 140, 147, 149, 153, 155, 157, 161, + 166, 170, 172, 174, 178, 182, 184, 186, 188, 190, + 192, 196, 200, 204, 208, 212, 216, 218, 220, 223, + 227, 229, 233, 240, 242, 246, 250, 254, 263, 267, + 271, 273, 275, 277, 279, 281, 283, 285, 289, 291, + 293, 297, 301, 305, 309, 311, 313, 315, 317, 319, + 321, 325, 332, 334, 338, 340, 342, 346, 349, 351, + 355, 359, 361, 363, 365, 367, 369, 373, 375, 377, + 381, 385, 389, 393, 397, 404, 406, 410, 414, 419, + 423, 432, 436, 440, 442, 444, 446, 448, 450, 452, + 456, 458, 460, 464, 468, 472, 476, 478, 480, 482, + 484, 486, 488, 492, 499, 501, 505, 508, 510, 517, + 519, 523, 527, 532, 536, 545, 549, 553, 557, 559, + 561, 565, 567, 570, 572, 574, 576, 578, 582, 584, + 586, 588, 590, 592, 594, 596, 598, 600, 602, 604, + 606, 609, 611, 613, 615, 617, 619, 621, 623, 625, + 627, 629, 631, 633, 635, 637, 639, 641, 643, 645, + 647, 649, 653, 655, 657, 659, 661, 663, 665, 667, + 669, 671, 673, 675, 680, 682, 684, 686, 688, 690, + 692, 694, 696, 701, 703, 705, 707, 712, 714, 716, + 718, 720, 724, 733, 742, 744, 747, 749, 751, 758, + 763, 765, 767, 771, 773, 777, 779, 781, 786, 788, + 790, 792, 794, 799, 804, 809, 814, 819, 822, 826, + 828, 832, 834, 836, 838, 840, 842, 844, 846, 848, + 850, 852 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 77, 0, -1, 216, -1, 77, 78, -1, 79, -1, + 202, -1, 80, -1, 81, -1, 82, -1, 83, -1, + 47, 21, 210, 10, 85, 10, 86, 84, 29, 24, + -1, 46, 21, 210, 10, 85, 10, 117, 84, 29, + 24, -1, 44, 21, 210, 10, 85, 10, 142, 84, + 29, 24, -1, 43, 21, 210, 10, 85, 10, 158, + 84, 29, 24, -1, 10, 199, 200, -1, 216, -1, + 60, -1, 87, -1, 116, -1, 88, -1, 94, -1, + 100, -1, 102, -1, 89, -1, 90, -1, 105, -1, + 94, 164, 94, -1, 91, -1, 92, -1, 93, -1, + 94, 34, 94, -1, 91, 34, 94, -1, 94, 3, + 94, -1, 92, 3, 94, -1, 94, 4, 94, -1, + 93, 4, 94, -1, 95, -1, 99, -1, 109, -1, + 110, -1, 112, -1, 115, -1, 21, 87, 29, -1, + 163, 17, 96, 28, 8, 94, -1, 97, -1, 97, + 10, 96, -1, 98, -1, 196, -1, 196, 8, 103, + -1, 165, 21, 87, 29, -1, 101, 8, 103, -1, + 109, -1, 110, -1, 21, 87, 29, -1, 185, 166, + 185, -1, 87, -1, 94, -1, 106, -1, 107, -1, + 108, -1, 104, 48, 104, -1, 104, 48, 106, -1, + 104, 30, 104, -1, 107, 30, 104, -1, 104, 61, + 104, -1, 108, 61, 104, -1, 182, -1, 161, -1, + 17, 28, -1, 17, 111, 28, -1, 94, -1, 94, + 10, 111, -1, 9, 17, 113, 28, 8, 94, -1, + 114, -1, 114, 10, 113, -1, 97, 9, 87, -1, + 21, 114, 29, -1, 38, 21, 87, 10, 87, 10, + 87, 29, -1, 110, 171, 110, -1, 21, 116, 29, + -1, 118, -1, 130, -1, 141, -1, 119, -1, 124, + -1, 120, -1, 121, -1, 124, 168, 124, -1, 122, + -1, 123, -1, 124, 34, 124, -1, 122, 34, 124, + -1, 124, 3, 124, -1, 123, 3, 124, -1, 125, + -1, 129, -1, 173, -1, 137, -1, 196, -1, 140, + -1, 21, 118, 29, -1, 167, 17, 126, 28, 8, + 124, -1, 127, -1, 127, 10, 126, -1, 128, -1, + 196, -1, 196, 8, 134, -1, 170, 124, -1, 162, + -1, 131, 8, 132, -1, 21, 130, 29, -1, 186, + -1, 195, -1, 134, -1, 135, -1, 134, -1, 21, + 136, 29, -1, 211, -1, 172, -1, 133, 48, 134, + -1, 21, 135, 29, -1, 134, 30, 134, -1, 136, + 30, 134, -1, 21, 136, 29, -1, 9, 17, 138, + 28, 8, 124, -1, 139, -1, 139, 10, 138, -1, + 196, 9, 118, -1, 196, 8, 22, 182, -1, 21, + 139, 29, -1, 38, 21, 118, 10, 118, 10, 118, + 29, -1, 118, 171, 118, -1, 21, 141, 29, -1, + 143, -1, 157, -1, 144, -1, 149, -1, 145, -1, + 146, -1, 149, 168, 149, -1, 147, -1, 148, -1, + 149, 34, 149, -1, 147, 34, 149, -1, 149, 3, + 149, -1, 148, 3, 149, -1, 150, -1, 152, -1, + 173, -1, 153, -1, 196, -1, 156, -1, 21, 143, + 29, -1, 167, 17, 151, 28, 8, 149, -1, 196, + -1, 196, 10, 151, -1, 170, 149, -1, 162, -1, + 9, 17, 154, 28, 8, 149, -1, 155, -1, 155, + 10, 154, -1, 196, 9, 143, -1, 196, 8, 22, + 182, -1, 21, 155, 29, -1, 38, 21, 143, 10, + 143, 10, 143, 29, -1, 143, 171, 143, -1, 21, + 157, 29, -1, 21, 159, 29, -1, 159, -1, 160, + -1, 159, 34, 160, -1, 173, -1, 31, 173, -1, + 162, -1, 164, -1, 169, -1, 165, -1, 182, 180, + 182, -1, 167, -1, 7, -1, 16, -1, 27, -1, + 6, -1, 5, -1, 179, -1, 180, -1, 168, -1, + 170, -1, 15, -1, 26, -1, 59, 59, -1, 13, + -1, 25, -1, 19, -1, 12, -1, 18, -1, 20, + -1, 33, -1, 32, -1, 34, -1, 3, -1, 31, + -1, 23, -1, 212, -1, 174, -1, 175, -1, 181, + -1, 184, -1, 176, -1, 177, -1, 190, -1, 182, + 178, 182, -1, 179, -1, 11, -1, 14, -1, 193, + -1, 183, -1, 196, -1, 198, -1, 184, -1, 187, + -1, 193, -1, 185, -1, 186, 21, 197, 29, -1, + 186, -1, 211, -1, 188, -1, 189, -1, 214, -1, + 54, -1, 190, -1, 191, -1, 192, 21, 197, 29, + -1, 192, -1, 212, -1, 194, -1, 195, 21, 197, + 29, -1, 195, -1, 213, -1, 74, -1, 182, -1, + 182, 10, 197, -1, 40, 21, 118, 10, 182, 10, + 182, 29, -1, 39, 21, 143, 10, 182, 10, 182, + 29, -1, 205, -1, 10, 201, -1, 216, -1, 208, + -1, 45, 21, 215, 203, 29, 24, -1, 10, 17, + 204, 28, -1, 216, -1, 210, -1, 210, 10, 204, + -1, 206, -1, 206, 8, 205, -1, 208, -1, 211, + -1, 211, 21, 209, 29, -1, 196, -1, 214, -1, + 54, -1, 207, -1, 42, 21, 86, 29, -1, 41, + 21, 117, 29, -1, 36, 21, 142, 29, -1, 35, + 21, 158, 29, -1, 37, 21, 182, 29, -1, 17, + 28, -1, 17, 209, 28, -1, 205, -1, 205, 10, + 209, -1, 211, -1, 58, -1, 60, -1, 68, -1, + 56, -1, 55, -1, 58, -1, 63, -1, 64, -1, + 68, -1, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 225, 225, 226, 229, 230, 233, 234, 235, 236, + 239, 242, 245, 248, 251, 252, 255, 258, 259, 262, + 263, 264, 265, 268, 269, 270, 273, 276, 277, 278, + 281, 282, 285, 286, 289, 290, 293, 294, 295, 296, + 297, 298, 299, 302, 305, 306, 309, 310, 313, 316, + 319, 322, 323, 324, 327, 330, 333, 336, 337, 338, + 341, 342, 345, 346, 349, 350, 353, 354, 357, 358, + 361, 362, 365, 368, 369, 372, 373, 376, 379, 380, + 383, 384, 385, 388, 389, 392, 393, 396, 399, 400, + 403, 404, 407, 408, 411, 412, 413, 414, 415, 416, + 417, 420, 423, 424, 427, 428, 431, 434, 435, 438, + 439, 442, 443, 446, 447, 450, 451, 454, 455, 458, + 459, 462, 463, 464, 467, 470, 471, 474, 475, 476, + 479, 482, 483, 486, 487, 490, 491, 494, 495, 498, + 501, 502, 505, 506, 509, 510, 513, 514, 515, 516, + 517, 518, 519, 522, 525, 526, 529, 530, 533, 536, + 537, 540, 541, 542, 545, 548, 549, 552, 553, 556, + 557, 560, 561, 562, 565, 566, 567, 570, 573, 574, + 575, 576, 577, 578, 581, 582, 583, 586, 587, 588, + 591, 594, 595, 598, 599, 600, 601, 602, 603, 606, + 607, 610, 613, 616, 619, 620, 621, 624, 627, 628, + 631, 634, 637, 640, 643, 646, 649, 650, 651, 654, + 655, 656, 659, 660, 663, 666, 669, 670, 673, 674, + 677, 680, 681, 684, 687, 690, 691, 694, 697, 700, + 703, 704, 707, 708, 711, 714, 715, 718, 721, 724, + 725, 728, 729, 732, 733, 734, 737, 738, 739, 740, + 741, 742, 745, 746, 747, 748, 749, 752, 753, 756, + 757, 760, 761, 764, 765, 768, 771, 774, 775, 776, + 779, 782 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "AMPERSAND", "AT_SIGN", "AT_SIGN_MINUS", + "AT_SIGN_PLUS", "CARET", "COLON", "COLON_EQUALS", "COMMA", "EQUALS", + "EQUALS_GREATER", "EXCLAMATION", "EXCLAMATION_EQUALS", + "EXCLAMATION_EXCLAMATION", "EXCLAMATION_GREATER", "LBRKT", "LESS_EQUALS", + "LESS_EQUALS_GREATER", "LESS_TILDE_GREATER", "LPAREN", "MINUS", + "MINUS_MINUS_GREATER", "PERIOD", "QUESTION", "QUESTION_QUESTION", + "QUESTION_STAR", "RBRKT", "RPAREN", "STAR", "TILDE", "TILDE_AMPERSAND", + "TILDE_VLINE", "VLINE", "_DLR_cnf", "_DLR_fof", "_DLR_fot", "_DLR_itef", + "_DLR_itetf", "_DLR_itett", "_DLR_tff", "_DLR_thf", "_LIT_cnf", + "_LIT_fof", "_LIT_include", "_LIT_tff", "_LIT_thf", "arrow", "comment", + "comment_line", "decimal", "decimal_exponent", "decimal_fraction", + "distinct_object", "dollar_dollar_word", "dollar_word", "dot_decimal", + "integer", "less_sign", "lower_word", "plus", "positive_decimal", + "rational", "real", "signed_integer", "signed_rational", "signed_real", + "single_quoted", "star", "unrecognized", "unsigned_integer", + "unsigned_rational", "unsigned_real", "upper_word", "vline", "$accept", + "TPTP_file", "TPTP_input", "annotated_formula", "thf_annotated", + "tff_annotated", "fof_annotated", "cnf_annotated", "annotations", + "formula_role", "thf_formula", "thf_logic_formula", "thf_binary_formula", + "thf_binary_pair", "thf_binary_tuple", "thf_or_formula", + "thf_and_formula", "thf_apply_formula", "thf_unitary_formula", + "thf_quantified_formula", "thf_variable_list", "thf_variable", + "thf_typed_variable", "thf_unary_formula", "thf_type_formula", + "thf_typeable_formula", "thf_subtype", "thf_top_level_type", + "thf_unitary_type", "thf_binary_type", "thf_mapping_type", + "thf_xprod_type", "thf_union_type", "thf_atom", "thf_tuple", + "thf_tuple_list", "thf_let", "thf_let_list", "thf_defined_var", + "thf_conditional", "thf_sequent", "tff_formula", "tff_logic_formula", + "tff_binary_formula", "tff_binary_nonassoc", "tff_binary_assoc", + "tff_or_formula", "tff_and_formula", "tff_unitary_formula", + "tff_quantified_formula", "tff_variable_list", "tff_variable", + "tff_typed_variable", "tff_unary_formula", "tff_typed_atom", + "tff_untyped_atom", "tff_top_level_type", "tff_unitary_type", + "tff_atomic_type", "tff_mapping_type", "tff_xprod_type", "tff_let", + "tff_let_list", "tff_defined_var", "tff_conditional", "tff_sequent", + "fof_formula", "fof_logic_formula", "fof_binary_formula", + "fof_binary_nonassoc", "fof_binary_assoc", "fof_or_formula", + "fof_and_formula", "fof_unitary_formula", "fof_quantified_formula", + "fof_variable_list", "fof_unary_formula", "fof_let", "fof_let_list", + "fof_defined_var", "fof_conditional", "fof_sequent", "cnf_formula", + "disjunction", "literal", "thf_conn_term", "fol_infix_unary", + "thf_quantifier", "thf_pair_connective", "thf_unary_connective", + "subtype_sign", "fol_quantifier", "binary_connective", + "assoc_connective", "unary_connective", "gentzen_arrow", "defined_type", + "atomic_formula", "plain_atomic_formula", "defined_atomic_formula", + "defined_plain_formula", "defined_infix_formula", "defined_infix_pred", + "infix_equality", "infix_inequality", "system_atomic_formula", "term", + "function_term", "plain_term", "constant", "functor", "defined_term", + "defined_atom", "defined_atomic_term", "defined_plain_term", + "defined_constant", "defined_functor", "system_term", "system_constant", + "system_functor", "variable", "arguments", "conditional_term", "source", + "optional_info", "useful_info", "include", "formula_selection", + "name_list", "general_term", "general_data", "formula_data", + "general_list", "general_terms", "name", "atomic_word", + "atomic_defined_word", "atomic_system_word", "number", "file_name", + "null", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 76, 77, 77, 78, 78, 79, 79, 79, 79, + 80, 81, 82, 83, 84, 84, 85, 86, 86, 87, + 87, 87, 87, 88, 88, 88, 89, 90, 90, 90, + 91, 91, 92, 92, 93, 93, 94, 94, 94, 94, + 94, 94, 94, 95, 96, 96, 97, 97, 98, 99, + 100, 101, 101, 101, 102, 103, 104, 105, 105, 105, + 106, 106, 107, 107, 108, 108, 109, 109, 110, 110, + 111, 111, 112, 113, 113, 114, 114, 115, 116, 116, + 117, 117, 117, 118, 118, 119, 119, 120, 121, 121, + 122, 122, 123, 123, 124, 124, 124, 124, 124, 124, + 124, 125, 126, 126, 127, 127, 128, 129, 129, 130, + 130, 131, 131, 132, 132, 133, 133, 134, 134, 135, + 135, 136, 136, 136, 137, 138, 138, 139, 139, 139, + 140, 141, 141, 142, 142, 143, 143, 144, 144, 145, + 146, 146, 147, 147, 148, 148, 149, 149, 149, 149, + 149, 149, 149, 150, 151, 151, 152, 152, 153, 154, + 154, 155, 155, 155, 156, 157, 157, 158, 158, 159, + 159, 160, 160, 160, 161, 161, 161, 162, 163, 163, + 163, 163, 163, 163, 164, 164, 164, 165, 165, 165, + 166, 167, 167, 168, 168, 168, 168, 168, 168, 169, + 169, 170, 171, 172, 173, 173, 173, 174, 175, 175, + 176, 177, 178, 179, 180, 181, 182, 182, 182, 183, + 183, 183, 184, 184, 185, 186, 187, 187, 188, 188, + 189, 190, 190, 191, 192, 193, 193, 194, 195, 196, + 197, 197, 198, 198, 199, 200, 200, 201, 202, 203, + 203, 204, 204, 205, 205, 205, 206, 206, 206, 206, + 206, 206, 207, 207, 207, 207, 207, 208, 208, 209, + 209, 210, 210, 211, 211, 212, 213, 214, 214, 214, + 215, 216 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 2, 1, 1, 1, 1, 1, 1, + 10, 10, 10, 10, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, + 1, 1, 3, 6, 1, 3, 1, 1, 3, 4, + 3, 1, 1, 3, 3, 1, 1, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 1, 1, 2, 3, + 1, 3, 6, 1, 3, 3, 3, 8, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, + 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, + 3, 6, 1, 3, 1, 1, 3, 2, 1, 3, + 3, 1, 1, 1, 1, 1, 3, 1, 1, 3, + 3, 3, 3, 3, 6, 1, 3, 3, 4, 3, + 8, 3, 3, 1, 1, 1, 1, 1, 1, 3, + 1, 1, 3, 3, 3, 3, 1, 1, 1, 1, + 1, 1, 3, 6, 1, 3, 2, 1, 6, 1, + 3, 3, 4, 3, 8, 3, 3, 3, 1, 1, + 3, 1, 2, 1, 1, 1, 1, 3, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, + 1, 1, 4, 1, 1, 1, 4, 1, 1, 1, + 1, 3, 8, 8, 1, 2, 1, 1, 6, 4, + 1, 1, 3, 1, 3, 1, 1, 4, 1, 1, + 1, 1, 4, 4, 4, 4, 4, 2, 3, 1, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 281, 0, 2, 1, 0, 0, 0, 0, 0, 3, + 4, 6, 7, 8, 9, 5, 0, 0, 0, 0, + 0, 272, 273, 274, 0, 271, 0, 280, 281, 0, + 0, 0, 0, 0, 0, 250, 0, 0, 16, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 251, 248, + 0, 0, 0, 0, 0, 0, 229, 276, 275, 277, + 278, 279, 239, 281, 168, 169, 173, 171, 204, 205, + 208, 209, 206, 0, 216, 207, 222, 224, 220, 226, + 227, 210, 231, 233, 215, 235, 237, 217, 218, 225, + 234, 238, 228, 0, 191, 0, 192, 201, 0, 281, + 133, 135, 137, 138, 140, 141, 136, 146, 147, 149, + 151, 134, 157, 0, 0, 148, 150, 249, 0, 0, + 0, 0, 281, 80, 83, 85, 86, 88, 89, 84, + 94, 95, 81, 0, 97, 99, 82, 108, 0, 0, + 96, 224, 237, 98, 200, 183, 182, 179, 0, 213, + 194, 214, 188, 180, 0, 195, 193, 196, 0, 189, + 181, 198, 197, 199, 0, 281, 17, 19, 23, 24, + 27, 28, 29, 20, 36, 37, 21, 0, 22, 0, + 25, 57, 58, 59, 38, 39, 40, 41, 18, 67, + 0, 174, 176, 178, 186, 175, 187, 184, 185, 66, + 219, 222, 230, 221, 0, 172, 0, 0, 0, 0, + 0, 15, 0, 0, 212, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 202, 0, 0, 0, 0, 0, + 0, 0, 0, 156, 252, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 107, 0, 0, 68, 70, 38, 39, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 167, 0, 0, 0, 0, 0, 0, 0, 0, 260, + 258, 281, 244, 253, 261, 255, 256, 259, 0, 170, + 211, 177, 240, 0, 0, 0, 0, 0, 159, 0, + 152, 166, 0, 0, 165, 143, 145, 144, 142, 139, + 0, 154, 0, 0, 0, 125, 0, 100, 110, 132, + 0, 0, 131, 91, 93, 92, 90, 87, 0, 109, + 0, 113, 114, 118, 117, 203, 0, 102, 104, 105, + 0, 0, 0, 46, 0, 73, 47, 0, 0, 39, + 0, 69, 42, 79, 0, 0, 31, 33, 35, 32, + 34, 30, 26, 55, 50, 56, 62, 60, 61, 64, + 63, 65, 78, 0, 44, 0, 190, 54, 224, 0, + 0, 267, 269, 0, 0, 0, 0, 0, 0, 0, + 14, 246, 0, 0, 13, 0, 223, 232, 236, 0, + 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, + 0, 0, 0, 0, 11, 0, 115, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 42, 71, + 0, 10, 0, 0, 49, 0, 0, 0, 268, 0, + 0, 0, 0, 0, 245, 247, 254, 0, 241, 163, + 0, 160, 0, 161, 0, 0, 155, 129, 0, 126, + 0, 127, 0, 0, 0, 120, 116, 0, 119, 0, + 103, 106, 76, 75, 0, 74, 48, 0, 0, 45, + 0, 0, 270, 265, 264, 266, 263, 262, 257, 158, + 162, 0, 153, 124, 128, 0, 123, 121, 122, 101, + 72, 0, 43, 0, 0, 0, 0, 0, 243, 242, + 164, 130, 77 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 9, 10, 11, 12, 13, 14, 210, 39, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 383, 352, 353, 175, 176, 177, 178, 374, 179, 180, + 181, 182, 183, 255, 256, 257, 186, 354, 355, 187, + 188, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 346, 347, 348, 131, 132, 133, 339, 340, 426, 427, + 428, 134, 324, 325, 135, 136, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 320, 108, 109, 307, 308, + 110, 111, 63, 64, 65, 189, 112, 190, 191, 192, + 279, 193, 194, 195, 196, 225, 343, 115, 68, 69, + 70, 71, 213, 197, 198, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 303, 88, 291, 400, 454, 15, 34, 47, 392, + 293, 294, 295, 393, 48, 89, 90, 91, 92, 28, + 211 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -388 +static const yytype_int16 yypact[] = +{ + -388, 110, -388, -388, 12, 14, 26, 41, 46, -388, + -388, -388, -388, -388, -388, -388, -12, -12, 10, -12, + -12, -388, -388, -388, 72, -388, 74, -388, 84, 89, + 91, 52, 52, 104, 101, -388, 52, 52, -388, 132, + 141, -12, 145, 155, 164, 750, 32, 148, 174, -388, + 790, 1403, 594, 471, 177, 179, -388, -388, -388, -388, + -388, -388, -388, 201, 178, -388, -388, -388, -388, -388, + -388, -388, -388, 50, -388, 111, -388, 192, -388, -388, + -388, 127, -388, 193, 152, -388, 195, -388, -388, -388, + -388, -388, -388, 216, -388, 32, -388, -388, 214, 201, + 217, -388, -388, -388, 205, 238, 298, -388, -388, -388, + -388, -388, -388, 227, 1158, -388, 153, -388, -12, 228, + 790, 226, 201, 217, -388, -388, -388, 231, 259, 316, + -388, -388, -388, 258, -388, -388, -388, -388, 251, 1241, + -388, 19, 22, 153, -388, -388, -388, -388, 254, -388, + -388, -388, -388, -388, 1339, -388, -388, -388, 1403, -388, + -388, -388, -388, -388, 252, 201, -388, -388, -388, -388, + 240, 269, 272, 566, -388, -388, -388, 270, -388, -6, + -388, -388, 250, 220, 275, 21, -388, -388, -388, -388, + 267, -388, 268, -388, -388, -388, -388, -388, -388, -388, + -388, 234, -388, -388, 2, -388, 279, 1158, 1241, 1058, + 266, -388, 594, 471, -388, 471, 471, 471, 471, -1, + 3, 271, 1158, 274, -388, 1158, 1158, 1158, 1158, 1158, + 1158, 222, 1158, -388, -388, 0, 36, 276, 282, 1241, + 284, 1241, 1241, 1241, 1241, 1241, 1241, 29, 222, 1241, + -388, 1, 1467, -388, 287, -388, -388, 295, 285, 296, + 1467, 297, 1531, 1531, 1531, 1531, 1531, 1531, 1531, 1467, + 1531, 1531, 1531, 1531, 1531, 281, 222, 1467, 245, 23, + -388, 289, 314, 1538, 306, 308, 312, 317, 318, -388, + -388, 330, -388, 334, -388, -388, 326, -388, 331, -388, + -388, -388, 346, 329, 332, 335, -1, 337, 349, 183, + -388, -388, 353, 342, -388, -388, -388, -388, -388, -388, + 339, 358, 340, 0, 343, 360, 186, -388, -388, -388, + 362, 354, -388, -388, -388, -388, -388, -388, 77, -388, + 333, 345, -388, -388, -388, -388, 355, 369, -388, 380, + 365, 1, 387, -388, 370, 390, 389, 1467, 372, 396, + 1531, -388, 397, -388, 400, 382, -388, -388, -388, -388, + -388, -388, -388, -388, -388, -388, -388, 359, -388, -388, + -388, -388, -388, 383, 402, 385, -388, -388, -388, 471, + 471, -388, 408, 391, 750, 32, 471, 790, 1403, 404, + -388, -388, 1058, 1058, -388, 471, -388, -388, -388, 393, + 416, -1, 405, 1158, 1158, -388, 420, 222, 401, 421, + 0, 411, 1241, 1241, -388, 77, 412, 409, 167, -2, + 433, 222, -2, 418, 1467, 441, 1, 1467, -388, -388, + 1467, -388, 442, 222, -388, 443, 445, 1058, -388, 423, + 430, 431, 434, 435, -388, -388, -388, 436, -388, -388, + 1158, -388, 471, -388, 452, 1158, -388, -388, 1241, -388, + 471, -388, 457, 180, -2, -388, -388, -2, -388, 1241, + -388, -388, -388, -388, 1531, -388, -388, 458, 1531, -388, + 471, 471, -388, -388, -388, -388, -388, -388, -388, -388, + -388, 1158, -388, -388, -388, 1241, 424, -388, -388, -388, + -388, 1467, -388, 440, 444, 446, 449, 451, -388, -388, + -388, -388, -388 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -388, -388, -388, -388, -388, -388, -388, -388, -84, 99, + 96, -149, -388, -388, -388, -388, -388, -388, -85, -388, + 55, -253, -388, -388, -388, -388, -388, 58, -112, -388, + 235, -388, -388, 465, 17, 154, -388, 76, 162, -388, + 357, 120, -115, -388, -388, -388, -388, -388, -127, -388, + 87, -388, -388, -388, 399, -388, -388, -388, -168, 273, + 97, -388, 103, 198, -388, 410, 129, -93, -388, -388, + -388, -388, -388, -80, -388, 115, -388, -388, 122, 230, + -388, 447, 143, 488, 350, -388, 516, -388, 368, -388, + -388, 781, -78, -388, 842, -109, -388, 455, -388, -388, + -388, -388, -388, -54, 470, -388, -45, -388, -14, 351, + -43, -388, -388, -388, 219, -388, -388, 286, -388, -40, + 722, -200, -388, -388, -388, -388, -388, -388, 426, -196, + -388, -388, 165, -387, 88, -16, -195, -388, -160, -388, + 11 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -231 +static const yytype_int16 yytable[] = +{ + 25, 25, 220, 25, 25, 236, 199, 141, 206, 258, + 142, 2, 250, 292, 241, 223, 457, 304, 305, 214, + 306, 323, 351, 384, 270, 25, 224, -111, 230, -52, + -112, 280, 310, 16, 233, 17, 212, 200, 240, 35, + 216, 93, 271, 218, 224, 94, 21, 18, 22, 297, + 338, 246, 345, 95, 58, 272, 23, 96, 22, 224, + 492, 149, 19, 97, 151, 327, 23, 20, 185, 254, + 98, 54, 55, 62, 62, 62, 275, 141, 27, 341, + 142, 261, 31, 22, 32, 58, 56, 57, 58, 22, + 59, 23, 22, 282, 33, 60, 61, 23, 425, 36, + 23, 37, 25, 358, 24, 26, 62, 29, 30, 199, + 3, 364, 38, 199, 281, 333, 334, 335, 336, 337, + 373, 41, -219, 297, 330, -219, 332, 241, 385, 312, + 42, 40, 314, 58, 350, 43, 44, 22, -230, 322, + 200, -230, 45, 345, 200, 23, 315, 316, 317, 318, + 319, 46, 214, 4, 5, 6, 7, 8, 376, 377, + 379, 380, 381, -221, -217, 50, -221, -217, 300, 49, + 301, 302, 302, 302, 51, 185, 117, 366, 367, 368, + 369, 370, 371, 372, 118, 375, 375, 375, 375, 375, + 384, 412, 413, 296, 421, 422, 476, 477, 207, 200, + 208, 200, 200, 200, 200, 458, 456, 199, 258, 506, + 477, 209, 212, 216, 217, 199, 218, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 345, 344, 199, 219, 345, 222, 388, 345, 200, 226, + 224, 227, 297, 297, 231, 235, 200, 239, 200, 200, + 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, + 200, 478, 243, 200, 481, 242, 247, 296, 248, 359, + 202, 251, 263, 260, 262, 254, 264, 359, 269, 345, + 273, 274, 345, -51, 276, 483, 359, 297, 373, 277, + 149, 487, 382, 278, 359, 298, 62, 360, 154, 389, + 311, 228, 401, 313, 386, 328, 507, 471, 472, 508, + 150, 329, 199, 331, 362, 199, 155, 156, 157, 244, + 463, 464, 344, 361, 390, 363, 365, 394, 150, 395, + 161, 162, 229, 396, 155, 156, 157, 203, 397, 398, + 399, 503, 402, 200, 445, 446, 200, 403, 161, 162, + 245, 451, 509, 199, 141, 404, 405, 142, 406, 411, + 302, 407, 517, 414, 408, 410, 415, 416, 417, 310, + 420, 419, 423, 202, 359, 200, 200, 202, 424, 431, + 499, 429, 200, 430, 200, 502, 296, 296, 432, 199, + 516, 200, 199, -115, 327, 199, 434, 437, 435, 510, + 436, 438, 201, 512, -52, -53, 441, 271, 515, 344, + 440, 442, 443, 344, 444, 185, 344, 500, 447, 448, + 200, 283, 459, 200, 460, 504, 200, 462, 465, 468, + 467, 296, 202, 470, 202, 202, 202, 202, 475, 199, + 203, 479, 474, 199, 203, 513, 514, 482, 200, 484, + 488, 359, 493, 490, 359, 491, 200, 359, 344, 494, + 495, 344, 501, 496, 497, 498, 199, 505, 511, 518, + 200, 202, -116, 519, 200, 520, 200, 200, 521, 202, + 522, 202, 202, 202, 202, 202, 202, 202, 202, 202, + 202, 202, 202, 202, 453, 486, 202, 200, 489, 203, + 67, 203, 203, 203, 203, 140, 378, 67, 205, 201, + 54, 55, 485, 433, 439, 259, 184, 452, 480, 237, + 342, 418, 473, 469, 450, 56, 57, 58, 359, 59, + 238, 22, 466, 461, 60, 61, 409, 449, 203, 23, + 204, 268, 221, 215, 234, 62, 203, 0, 203, 203, + 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 66, 299, 203, 455, 0, 137, 0, 66, 265, + 266, 0, 0, 0, 0, 140, 202, 149, 150, 202, + 151, 0, 0, 0, 155, 156, 157, 0, 0, 0, + 0, 0, 0, 0, 140, 0, -56, 0, 161, 162, + 267, 0, 0, 201, 0, 0, 0, 0, 202, 202, + 0, 201, 0, 0, -56, 202, 0, 202, 0, 0, + 201, 0, 0, 184, 202, 53, 0, -56, 201, 0, + 387, 0, 0, 54, 55, 0, 137, 0, 0, 0, + 0, 0, 0, 203, 0, 0, 203, 0, 56, 57, + 58, 0, 59, 202, 22, 137, 202, 60, 61, 202, + 0, 0, 23, 140, 0, 0, 0, 67, 62, 0, + 0, 0, 0, 0, 0, 203, 203, 0, 0, 0, + 0, 202, 203, 0, 203, 0, 0, 0, 0, 202, + 0, 203, 0, 0, 140, 0, 140, 140, 140, 140, + 140, 140, 0, 202, 140, 0, 0, 202, 201, 202, + 202, 0, 0, 0, 0, 0, 0, 184, 0, 0, + 203, 0, 0, 203, 137, 184, 203, 0, 66, 0, + 202, 0, 0, 0, 184, 0, 0, 0, 0, 0, + 0, 0, 184, 0, 0, 0, 0, 0, 203, 201, + 0, 0, 0, 0, 0, 137, 203, 137, 137, 137, + 137, 137, 137, 0, 0, 137, 0, 0, 116, 0, + 203, 52, 143, 0, 203, 0, 203, 203, 0, 0, + 0, 53, 0, 0, 0, 201, 0, 0, 201, 54, + 55, 201, 0, 0, 0, 0, 0, 203, 0, 119, + 0, 0, 0, 94, 56, 57, 58, 0, 59, 0, + 22, 120, 0, 60, 61, 96, 0, 116, 23, 0, + 0, 97, 184, 0, 62, 0, 0, 113, 121, 54, + 55, 138, 0, 0, 0, 0, 116, 0, 0, 0, + 0, 0, 143, 0, 56, 57, 58, 0, 59, 67, + 22, 0, 140, 60, 61, 0, 0, 0, 23, 0, + 0, 143, 201, 184, 62, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 113, 140, 140, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 114, 0, + 0, 0, 139, 0, 0, 113, 0, 0, 0, 184, + 0, 138, 184, 0, 0, 184, 0, 0, 0, 0, + 66, 0, 0, 137, 0, 0, 0, 0, 0, 0, + 138, 0, 0, 140, 0, 0, 0, 0, 0, 116, + 143, 290, 0, 0, 140, 0, 0, 114, 137, 137, + 0, 309, 0, 0, 116, 0, 0, 116, 116, 116, + 116, 116, 116, 321, 116, 0, 114, 326, 0, 0, + 140, 143, 139, 143, 143, 143, 143, 143, 143, 0, + 349, 143, 0, 356, 0, 0, 184, 0, 0, 0, + 0, 139, 0, 0, 137, 0, 0, 0, 113, 138, + 0, 0, 0, 0, 0, 137, 0, 0, 356, 0, + 0, 0, 0, 113, 0, 290, 113, 113, 113, 113, + 113, 113, 0, 113, 0, 0, 0, 0, 0, 0, + 138, 137, 138, 138, 138, 138, 138, 138, 309, 0, + 138, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 326, 0, 0, 0, 114, + 139, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 114, 0, 0, 114, 114, 114, + 114, 114, 114, 356, 114, 283, 0, 0, 0, 0, + 0, 139, 0, 139, 139, 139, 139, 139, 139, 0, + 0, 139, 0, 284, 285, 286, 0, 0, 0, 287, + 288, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 289, 0, 0, 0, 59, 116, 22, 143, + 0, 60, 61, 0, 290, 290, 23, 0, 0, 0, + 0, 0, 62, 309, 0, 116, 116, 0, 0, 321, + 0, 0, 326, 0, 143, 143, 0, 0, 0, 0, + 0, 0, 0, 349, 0, 0, 0, 0, 356, 0, + 0, 0, 0, 0, 0, 356, 0, 93, 0, 290, + 0, 94, 0, 0, 0, 0, 113, 0, 138, 232, + 0, 0, 116, 96, 0, 0, 0, 116, 0, 97, + 143, 0, 0, 0, 113, 113, 98, 54, 55, 0, + 0, 143, 0, 138, 138, 0, 0, 0, 0, 0, + 0, 0, 56, 57, 58, 0, 59, 0, 22, 0, + 0, 60, 61, 116, 0, 0, 23, 143, 0, 0, + 0, 0, 62, 0, 0, 0, 0, 114, 0, 139, + 0, 113, 0, 0, 0, 0, 113, 0, 0, 138, + 119, 0, 0, 0, 94, 114, 114, 0, 0, 0, + 138, 0, 249, 0, 139, 139, 96, 0, 0, 0, + 0, 0, 97, 0, 0, 0, 0, 0, 0, 121, + 54, 55, 113, 0, 0, 0, 138, 0, 0, 0, + 0, 0, 0, 0, 0, 56, 57, 58, 0, 59, + 0, 22, 114, 0, 60, 61, 0, 114, 0, 23, + 139, 0, 0, 0, 0, 62, 0, 0, 0, 0, + 0, 139, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 144, 114, 145, 146, 147, 139, 148, 0, + 149, 150, 94, 151, 152, 153, 154, 155, 156, 157, + 252, 0, 0, 0, 96, 159, 160, 253, 0, 0, + 97, 161, 162, 163, 0, 0, 0, 164, 54, 55, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 56, 57, 58, 0, 59, 0, 22, + 0, 0, 60, 61, 0, 0, 144, 23, 145, 146, + 147, 0, 148, 62, 149, 150, 94, 151, 152, 153, + 154, 155, 156, 157, 158, 0, 0, 0, 96, 159, + 160, 0, 0, 0, 97, 161, 162, 163, 0, 0, + 0, 164, 54, 55, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 56, 57, 58, + 0, 59, 0, 22, 0, 0, 60, 61, 0, 0, + 144, 23, 145, 146, 147, 0, 148, 62, 149, 150, + 94, 151, 152, 153, 154, 155, 156, 157, 357, 0, + 0, 0, 96, 159, 160, 0, 0, 0, 97, 161, + 162, 163, 0, 0, 0, 164, 54, 55, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 56, 57, 58, 0, 59, 0, 22, 0, 0, + 60, 61, 0, 0, 144, 23, 145, 146, 147, 0, + 148, 62, 149, 150, 94, 151, 152, 153, 154, 155, + 156, 157, 252, 0, 0, 283, 96, 159, 160, 0, + 0, 0, 97, 161, 162, 163, 391, 0, 0, 164, + 54, 55, 0, 284, 285, 286, 0, 0, 0, 287, + 288, 0, 0, 0, 0, 56, 57, 58, 0, 59, + 0, 22, 289, 0, 60, 61, 59, 0, 22, 23, + 0, 60, 61, 0, 0, 62, 23, 0, 0, 0, + 0, 0, 62 +}; + +static const yytype_int16 yycheck[] = +{ + 16, 17, 95, 19, 20, 120, 51, 50, 53, 158, + 50, 0, 139, 209, 123, 99, 403, 217, 218, 73, + 21, 21, 21, 276, 30, 41, 23, 8, 106, 8, + 8, 29, 29, 21, 114, 21, 34, 51, 122, 28, + 21, 9, 48, 21, 23, 13, 58, 21, 60, 209, + 21, 129, 247, 21, 56, 61, 68, 25, 60, 23, + 447, 11, 21, 31, 14, 29, 68, 21, 51, 154, + 38, 39, 40, 74, 74, 74, 185, 120, 68, 247, + 120, 165, 10, 60, 10, 56, 54, 55, 56, 60, + 58, 68, 60, 208, 10, 63, 64, 68, 21, 10, + 68, 10, 118, 252, 16, 17, 74, 19, 20, 154, + 0, 260, 60, 158, 207, 242, 243, 244, 245, 246, + 269, 17, 11, 283, 239, 14, 241, 236, 277, 222, + 29, 32, 225, 56, 249, 36, 37, 60, 11, 232, + 154, 14, 10, 338, 158, 68, 226, 227, 228, 229, + 230, 10, 206, 43, 44, 45, 46, 47, 270, 271, + 272, 273, 274, 11, 11, 10, 14, 14, 213, 24, + 215, 216, 217, 218, 10, 158, 28, 262, 263, 264, + 265, 266, 267, 268, 10, 270, 271, 272, 273, 274, + 443, 8, 9, 209, 8, 9, 29, 30, 21, 213, + 21, 215, 216, 217, 218, 405, 402, 252, 357, 29, + 30, 10, 34, 21, 21, 260, 21, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 425, 247, 277, 17, 429, 21, 279, 432, 252, 34, + 23, 3, 402, 403, 17, 17, 260, 21, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 429, 3, 277, 432, 34, 8, 283, 17, 252, + 51, 17, 3, 21, 34, 360, 4, 260, 8, 474, + 30, 61, 477, 8, 17, 434, 269, 447, 437, 21, + 11, 440, 275, 59, 277, 29, 74, 10, 17, 10, + 29, 3, 291, 29, 59, 29, 474, 422, 423, 477, + 12, 29, 357, 29, 29, 360, 18, 19, 20, 3, + 413, 414, 338, 28, 10, 29, 29, 21, 12, 21, + 32, 33, 34, 21, 18, 19, 20, 51, 21, 21, + 10, 468, 8, 357, 389, 390, 360, 21, 32, 33, + 34, 396, 479, 398, 397, 24, 10, 397, 29, 10, + 405, 29, 511, 10, 29, 28, 24, 28, 10, 29, + 10, 28, 10, 154, 357, 389, 390, 158, 24, 10, + 460, 48, 396, 28, 398, 465, 402, 403, 8, 434, + 505, 405, 437, 48, 29, 440, 9, 8, 28, 484, + 10, 29, 51, 488, 8, 8, 24, 48, 501, 425, + 10, 28, 10, 429, 29, 398, 432, 462, 10, 28, + 434, 17, 29, 437, 8, 470, 440, 22, 8, 8, + 29, 447, 213, 22, 215, 216, 217, 218, 29, 484, + 154, 8, 30, 488, 158, 490, 491, 29, 462, 8, + 8, 434, 29, 10, 437, 10, 470, 440, 474, 29, + 29, 477, 10, 29, 29, 29, 511, 10, 10, 29, + 484, 252, 48, 29, 488, 29, 490, 491, 29, 260, + 29, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 398, 437, 277, 511, 443, 213, + 45, 215, 216, 217, 218, 50, 271, 52, 53, 158, + 39, 40, 436, 351, 360, 158, 51, 397, 431, 120, + 247, 323, 425, 420, 395, 54, 55, 56, 511, 58, + 120, 60, 417, 411, 63, 64, 306, 394, 252, 68, + 52, 173, 95, 73, 118, 74, 260, -1, 262, 263, + 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, + 274, 45, 212, 277, 399, -1, 50, -1, 52, 3, + 4, -1, -1, -1, -1, 120, 357, 11, 12, 360, + 14, -1, -1, -1, 18, 19, 20, -1, -1, -1, + -1, -1, -1, -1, 139, -1, 30, -1, 32, 33, + 34, -1, -1, 252, -1, -1, -1, -1, 389, 390, + -1, 260, -1, -1, 48, 396, -1, 398, -1, -1, + 269, -1, -1, 158, 405, 31, -1, 61, 277, -1, + 279, -1, -1, 39, 40, -1, 120, -1, -1, -1, + -1, -1, -1, 357, -1, -1, 360, -1, 54, 55, + 56, -1, 58, 434, 60, 139, 437, 63, 64, 440, + -1, -1, 68, 208, -1, -1, -1, 212, 74, -1, + -1, -1, -1, -1, -1, 389, 390, -1, -1, -1, + -1, 462, 396, -1, 398, -1, -1, -1, -1, 470, + -1, 405, -1, -1, 239, -1, 241, 242, 243, 244, + 245, 246, -1, 484, 249, -1, -1, 488, 357, 490, + 491, -1, -1, -1, -1, -1, -1, 252, -1, -1, + 434, -1, -1, 437, 208, 260, 440, -1, 212, -1, + 511, -1, -1, -1, 269, -1, -1, -1, -1, -1, + -1, -1, 277, -1, -1, -1, -1, -1, 462, 398, + -1, -1, -1, -1, -1, 239, 470, 241, 242, 243, + 244, 245, 246, -1, -1, 249, -1, -1, 46, -1, + 484, 21, 50, -1, 488, -1, 490, 491, -1, -1, + -1, 31, -1, -1, -1, 434, -1, -1, 437, 39, + 40, 440, -1, -1, -1, -1, -1, 511, -1, 9, + -1, -1, -1, 13, 54, 55, 56, -1, 58, -1, + 60, 21, -1, 63, 64, 25, -1, 95, 68, -1, + -1, 31, 357, -1, 74, -1, -1, 46, 38, 39, + 40, 50, -1, -1, -1, -1, 114, -1, -1, -1, + -1, -1, 120, -1, 54, 55, 56, -1, 58, 394, + 60, -1, 397, 63, 64, -1, -1, -1, 68, -1, + -1, 139, 511, 398, 74, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 95, 422, 423, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, + -1, -1, 50, -1, -1, 114, -1, -1, -1, 434, + -1, 120, 437, -1, -1, 440, -1, -1, -1, -1, + 394, -1, -1, 397, -1, -1, -1, -1, -1, -1, + 139, -1, -1, 468, -1, -1, -1, -1, -1, 207, + 208, 209, -1, -1, 479, -1, -1, 95, 422, 423, + -1, 219, -1, -1, 222, -1, -1, 225, 226, 227, + 228, 229, 230, 231, 232, -1, 114, 235, -1, -1, + 505, 239, 120, 241, 242, 243, 244, 245, 246, -1, + 248, 249, -1, 251, -1, -1, 511, -1, -1, -1, + -1, 139, -1, -1, 468, -1, -1, -1, 207, 208, + -1, -1, -1, -1, -1, 479, -1, -1, 276, -1, + -1, -1, -1, 222, -1, 283, 225, 226, 227, 228, + 229, 230, -1, 232, -1, -1, -1, -1, -1, -1, + 239, 505, 241, 242, 243, 244, 245, 246, 306, -1, + 249, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 323, -1, -1, -1, 207, + 208, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 222, -1, -1, 225, 226, 227, + 228, 229, 230, 351, 232, 17, -1, -1, -1, -1, + -1, 239, -1, 241, 242, 243, 244, 245, 246, -1, + -1, 249, -1, 35, 36, 37, -1, -1, -1, 41, + 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 54, -1, -1, -1, 58, 395, 60, 397, + -1, 63, 64, -1, 402, 403, 68, -1, -1, -1, + -1, -1, 74, 411, -1, 413, 414, -1, -1, 417, + -1, -1, 420, -1, 422, 423, -1, -1, -1, -1, + -1, -1, -1, 431, -1, -1, -1, -1, 436, -1, + -1, -1, -1, -1, -1, 443, -1, 9, -1, 447, + -1, 13, -1, -1, -1, -1, 395, -1, 397, 21, + -1, -1, 460, 25, -1, -1, -1, 465, -1, 31, + 468, -1, -1, -1, 413, 414, 38, 39, 40, -1, + -1, 479, -1, 422, 423, -1, -1, -1, -1, -1, + -1, -1, 54, 55, 56, -1, 58, -1, 60, -1, + -1, 63, 64, 501, -1, -1, 68, 505, -1, -1, + -1, -1, 74, -1, -1, -1, -1, 395, -1, 397, + -1, 460, -1, -1, -1, -1, 465, -1, -1, 468, + 9, -1, -1, -1, 13, 413, 414, -1, -1, -1, + 479, -1, 21, -1, 422, 423, 25, -1, -1, -1, + -1, -1, 31, -1, -1, -1, -1, -1, -1, 38, + 39, 40, 501, -1, -1, -1, 505, -1, -1, -1, + -1, -1, -1, -1, -1, 54, 55, 56, -1, 58, + -1, 60, 460, -1, 63, 64, -1, 465, -1, 68, + 468, -1, -1, -1, -1, 74, -1, -1, -1, -1, + -1, 479, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 3, 501, 5, 6, 7, 505, 9, -1, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, -1, -1, -1, 25, 26, 27, 28, -1, -1, + 31, 32, 33, 34, -1, -1, -1, 38, 39, 40, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 54, 55, 56, -1, 58, -1, 60, + -1, -1, 63, 64, -1, -1, 3, 68, 5, 6, + 7, -1, 9, 74, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, -1, -1, -1, 25, 26, + 27, -1, -1, -1, 31, 32, 33, 34, -1, -1, + -1, 38, 39, 40, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 54, 55, 56, + -1, 58, -1, 60, -1, -1, 63, 64, -1, -1, + 3, 68, 5, 6, 7, -1, 9, 74, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, -1, + -1, -1, 25, 26, 27, -1, -1, -1, 31, 32, + 33, 34, -1, -1, -1, 38, 39, 40, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 54, 55, 56, -1, 58, -1, 60, -1, -1, + 63, 64, -1, -1, 3, 68, 5, 6, 7, -1, + 9, 74, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, -1, -1, 17, 25, 26, 27, -1, + -1, -1, 31, 32, 33, 34, 28, -1, -1, 38, + 39, 40, -1, 35, 36, 37, -1, -1, -1, 41, + 42, -1, -1, -1, -1, 54, 55, 56, -1, 58, + -1, 60, 54, -1, 63, 64, 58, -1, 60, 68, + -1, 63, 64, -1, -1, 74, 68, -1, -1, -1, + -1, -1, 74 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 77, 216, 0, 43, 44, 45, 46, 47, 78, + 79, 80, 81, 82, 83, 202, 21, 21, 21, 21, + 21, 58, 60, 68, 210, 211, 210, 68, 215, 210, + 210, 10, 10, 10, 203, 216, 10, 10, 60, 85, + 85, 17, 29, 85, 85, 10, 10, 204, 210, 24, + 10, 10, 21, 31, 39, 40, 54, 55, 56, 58, + 63, 64, 74, 158, 159, 160, 162, 173, 174, 175, + 176, 177, 181, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 198, 211, + 212, 213, 214, 9, 13, 21, 25, 31, 38, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 152, 153, + 156, 157, 162, 167, 170, 173, 196, 28, 10, 9, + 21, 38, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 129, 130, 131, 137, 140, 141, 162, 167, 170, + 173, 186, 195, 196, 3, 5, 6, 7, 9, 11, + 12, 14, 15, 16, 17, 18, 19, 20, 21, 26, + 27, 32, 33, 34, 38, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 99, 100, 101, 102, 104, + 105, 106, 107, 108, 109, 110, 112, 115, 116, 161, + 163, 164, 165, 167, 168, 169, 170, 179, 180, 182, + 184, 185, 190, 193, 159, 173, 182, 21, 21, 10, + 84, 216, 34, 178, 179, 180, 21, 21, 21, 17, + 143, 157, 21, 84, 23, 171, 34, 3, 3, 34, + 168, 17, 21, 149, 204, 17, 118, 130, 141, 21, + 84, 171, 34, 3, 3, 34, 168, 8, 17, 21, + 124, 17, 21, 28, 94, 109, 110, 111, 87, 116, + 21, 84, 34, 3, 4, 3, 4, 34, 164, 8, + 30, 48, 61, 30, 61, 171, 17, 21, 59, 166, + 29, 143, 118, 17, 35, 36, 37, 41, 42, 54, + 196, 199, 205, 206, 207, 208, 211, 214, 29, 160, + 182, 182, 182, 197, 197, 197, 21, 154, 155, 196, + 29, 29, 143, 29, 143, 149, 149, 149, 149, 149, + 151, 196, 143, 21, 138, 139, 196, 29, 29, 29, + 118, 29, 118, 124, 124, 124, 124, 124, 21, 132, + 133, 134, 135, 172, 211, 212, 126, 127, 128, 196, + 118, 21, 97, 98, 113, 114, 196, 21, 87, 110, + 10, 28, 29, 29, 87, 29, 94, 94, 94, 94, + 94, 94, 94, 87, 103, 94, 104, 104, 106, 104, + 104, 104, 110, 96, 97, 87, 59, 185, 186, 10, + 10, 28, 205, 209, 21, 21, 21, 21, 21, 10, + 200, 216, 8, 21, 24, 10, 29, 29, 29, 155, + 28, 10, 8, 9, 10, 24, 28, 10, 139, 28, + 10, 8, 9, 10, 24, 21, 134, 135, 136, 48, + 28, 10, 8, 114, 9, 28, 10, 8, 29, 111, + 10, 24, 28, 10, 29, 182, 182, 10, 28, 158, + 142, 182, 117, 86, 201, 208, 205, 209, 197, 29, + 8, 154, 22, 143, 143, 8, 151, 29, 8, 138, + 22, 118, 118, 136, 30, 29, 29, 30, 134, 8, + 126, 134, 29, 87, 8, 113, 103, 87, 8, 96, + 10, 10, 209, 29, 29, 29, 29, 29, 29, 149, + 182, 10, 149, 124, 182, 10, 29, 134, 134, 124, + 94, 10, 94, 182, 182, 143, 118, 87, 29, 29, + 29, 29, 29 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + +#if 0 + switch (yytype) + { + + default: + break; + } +#endif +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + +/* Line 1464 of yacc.c */ +#line 225 "tptp5.y" + {;} + break; + + case 3: + +/* Line 1464 of yacc.c */ +#line 226 "tptp5.y" + {;} + break; + + case 4: + +/* Line 1464 of yacc.c */ +#line 229 "tptp5.y" + {P_PRINT((yyval.pval));;} + break; + + case 5: + +/* Line 1464 of yacc.c */ +#line 230 "tptp5.y" + {P_PRINT((yyval.pval));;} + break; + + case 6: + +/* Line 1464 of yacc.c */ +#line 233 "tptp5.y" + {(yyval.pval) = P_BUILD("annotated_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 7: + +/* Line 1464 of yacc.c */ +#line 234 "tptp5.y" + {(yyval.pval) = P_BUILD("annotated_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 8: + +/* Line 1464 of yacc.c */ +#line 235 "tptp5.y" + {(yyval.pval) = P_BUILD("annotated_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 9: + +/* Line 1464 of yacc.c */ +#line 236 "tptp5.y" + {(yyval.pval) = P_BUILD("annotated_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 10: + +/* Line 1464 of yacc.c */ +#line 239 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_annotated", P_TOKEN("_LIT_thf ", (yyvsp[(1) - (10)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (10)].ival)), (yyvsp[(3) - (10)].pval), P_TOKEN("COMMA ", (yyvsp[(4) - (10)].ival)), (yyvsp[(5) - (10)].pval), P_TOKEN("COMMA ", (yyvsp[(6) - (10)].ival)), (yyvsp[(7) - (10)].pval), (yyvsp[(8) - (10)].pval), P_TOKEN("RPAREN ", (yyvsp[(9) - (10)].ival)), P_TOKEN("PERIOD ", (yyvsp[(10) - (10)].ival)));;} + break; + + case 11: + +/* Line 1464 of yacc.c */ +#line 242 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_annotated", P_TOKEN("_LIT_tff ", (yyvsp[(1) - (10)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (10)].ival)), (yyvsp[(3) - (10)].pval), P_TOKEN("COMMA ", (yyvsp[(4) - (10)].ival)), (yyvsp[(5) - (10)].pval), P_TOKEN("COMMA ", (yyvsp[(6) - (10)].ival)), (yyvsp[(7) - (10)].pval), (yyvsp[(8) - (10)].pval), P_TOKEN("RPAREN ", (yyvsp[(9) - (10)].ival)), P_TOKEN("PERIOD ", (yyvsp[(10) - (10)].ival)));;} + break; + + case 12: + +/* Line 1464 of yacc.c */ +#line 245 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_annotated", P_TOKEN("_LIT_fof ", (yyvsp[(1) - (10)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (10)].ival)), (yyvsp[(3) - (10)].pval), P_TOKEN("COMMA ", (yyvsp[(4) - (10)].ival)), (yyvsp[(5) - (10)].pval), P_TOKEN("COMMA ", (yyvsp[(6) - (10)].ival)), (yyvsp[(7) - (10)].pval), (yyvsp[(8) - (10)].pval), P_TOKEN("RPAREN ", (yyvsp[(9) - (10)].ival)), P_TOKEN("PERIOD ", (yyvsp[(10) - (10)].ival)));;} + break; + + case 13: + +/* Line 1464 of yacc.c */ +#line 248 "tptp5.y" + {(yyval.pval) = P_BUILD("cnf_annotated", P_TOKEN("_LIT_cnf ", (yyvsp[(1) - (10)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (10)].ival)), (yyvsp[(3) - (10)].pval), P_TOKEN("COMMA ", (yyvsp[(4) - (10)].ival)), (yyvsp[(5) - (10)].pval), P_TOKEN("COMMA ", (yyvsp[(6) - (10)].ival)), (yyvsp[(7) - (10)].pval), (yyvsp[(8) - (10)].pval), P_TOKEN("RPAREN ", (yyvsp[(9) - (10)].ival)), P_TOKEN("PERIOD ", (yyvsp[(10) - (10)].ival)));;} + break; + + case 14: + +/* Line 1464 of yacc.c */ +#line 251 "tptp5.y" + {(yyval.pval) = P_BUILD("annotations", P_TOKEN("COMMA ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 15: + +/* Line 1464 of yacc.c */ +#line 252 "tptp5.y" + {(yyval.pval) = P_BUILD("annotations", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 16: + +/* Line 1464 of yacc.c */ +#line 255 "tptp5.y" + {(yyval.pval) = P_BUILD("formula_role", P_TOKEN("lower_word ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 17: + +/* Line 1464 of yacc.c */ +#line 258 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 18: + +/* Line 1464 of yacc.c */ +#line 259 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 19: + +/* Line 1464 of yacc.c */ +#line 262 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_logic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 20: + +/* Line 1464 of yacc.c */ +#line 263 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_logic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 21: + +/* Line 1464 of yacc.c */ +#line 264 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_logic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 22: + +/* Line 1464 of yacc.c */ +#line 265 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_logic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 23: + +/* Line 1464 of yacc.c */ +#line 268 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_binary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 24: + +/* Line 1464 of yacc.c */ +#line 269 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_binary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 25: + +/* Line 1464 of yacc.c */ +#line 270 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_binary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 26: + +/* Line 1464 of yacc.c */ +#line 273 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_binary_pair", (yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 27: + +/* Line 1464 of yacc.c */ +#line 276 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_binary_tuple", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 28: + +/* Line 1464 of yacc.c */ +#line 277 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_binary_tuple", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 29: + +/* Line 1464 of yacc.c */ +#line 278 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_binary_tuple", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 30: + +/* Line 1464 of yacc.c */ +#line 281 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_or_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("VLINE ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 31: + +/* Line 1464 of yacc.c */ +#line 282 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_or_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("VLINE ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 32: + +/* Line 1464 of yacc.c */ +#line 285 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_and_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("AMPERSAND ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 33: + +/* Line 1464 of yacc.c */ +#line 286 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_and_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("AMPERSAND ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 34: + +/* Line 1464 of yacc.c */ +#line 289 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_apply_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("AT_SIGN ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 35: + +/* Line 1464 of yacc.c */ +#line 290 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_apply_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("AT_SIGN ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 36: + +/* Line 1464 of yacc.c */ +#line 293 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 37: + +/* Line 1464 of yacc.c */ +#line 294 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 38: + +/* Line 1464 of yacc.c */ +#line 295 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 39: + +/* Line 1464 of yacc.c */ +#line 296 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 40: + +/* Line 1464 of yacc.c */ +#line 297 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 41: + +/* Line 1464 of yacc.c */ +#line 298 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 42: + +/* Line 1464 of yacc.c */ +#line 299 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unitary_formula", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 43: + +/* Line 1464 of yacc.c */ +#line 302 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_quantified_formula", (yyvsp[(1) - (6)].pval), P_TOKEN("LBRKT ", (yyvsp[(2) - (6)].ival)), (yyvsp[(3) - (6)].pval), P_TOKEN("RBRKT ", (yyvsp[(4) - (6)].ival)), P_TOKEN("COLON ", (yyvsp[(5) - (6)].ival)), (yyvsp[(6) - (6)].pval),NULL,NULL,NULL,NULL);;} + break; + + case 44: + +/* Line 1464 of yacc.c */ +#line 305 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_variable_list", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 45: + +/* Line 1464 of yacc.c */ +#line 306 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_variable_list", (yyvsp[(1) - (3)].pval), P_TOKEN("COMMA ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 46: + +/* Line 1464 of yacc.c */ +#line 309 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_variable", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 47: + +/* Line 1464 of yacc.c */ +#line 310 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_variable", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 48: + +/* Line 1464 of yacc.c */ +#line 313 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_typed_variable", (yyvsp[(1) - (3)].pval), P_TOKEN("COLON ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 49: + +/* Line 1464 of yacc.c */ +#line 316 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unary_formula", (yyvsp[(1) - (4)].pval), P_TOKEN("LPAREN ", (yyvsp[(2) - (4)].ival)), (yyvsp[(3) - (4)].pval), P_TOKEN("RPAREN ", (yyvsp[(4) - (4)].ival)),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 50: + +/* Line 1464 of yacc.c */ +#line 319 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_type_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("COLON ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 51: + +/* Line 1464 of yacc.c */ +#line 322 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_typeable_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 52: + +/* Line 1464 of yacc.c */ +#line 323 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_typeable_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 53: + +/* Line 1464 of yacc.c */ +#line 324 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_typeable_formula", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 54: + +/* Line 1464 of yacc.c */ +#line 327 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_subtype", (yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 55: + +/* Line 1464 of yacc.c */ +#line 330 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_top_level_type", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 56: + +/* Line 1464 of yacc.c */ +#line 333 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unitary_type", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 57: + +/* Line 1464 of yacc.c */ +#line 336 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_binary_type", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 58: + +/* Line 1464 of yacc.c */ +#line 337 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_binary_type", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 59: + +/* Line 1464 of yacc.c */ +#line 338 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_binary_type", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 60: + +/* Line 1464 of yacc.c */ +#line 341 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_mapping_type", (yyvsp[(1) - (3)].pval), P_TOKEN("arrow ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 61: + +/* Line 1464 of yacc.c */ +#line 342 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_mapping_type", (yyvsp[(1) - (3)].pval), P_TOKEN("arrow ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 62: + +/* Line 1464 of yacc.c */ +#line 345 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_xprod_type", (yyvsp[(1) - (3)].pval), P_TOKEN("STAR ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 63: + +/* Line 1464 of yacc.c */ +#line 346 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_xprod_type", (yyvsp[(1) - (3)].pval), P_TOKEN("STAR ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 64: + +/* Line 1464 of yacc.c */ +#line 349 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_union_type", (yyvsp[(1) - (3)].pval), P_TOKEN("plus ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 65: + +/* Line 1464 of yacc.c */ +#line 350 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_union_type", (yyvsp[(1) - (3)].pval), P_TOKEN("plus ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 66: + +/* Line 1464 of yacc.c */ +#line 353 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_atom", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 67: + +/* Line 1464 of yacc.c */ +#line 354 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_atom", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 68: + +/* Line 1464 of yacc.c */ +#line 357 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_tuple", P_TOKEN("LBRKT ", (yyvsp[(1) - (2)].ival)), P_TOKEN("RBRKT ", (yyvsp[(2) - (2)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 69: + +/* Line 1464 of yacc.c */ +#line 358 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_tuple", P_TOKEN("LBRKT ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RBRKT ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 70: + +/* Line 1464 of yacc.c */ +#line 361 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_tuple_list", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 71: + +/* Line 1464 of yacc.c */ +#line 362 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_tuple_list", (yyvsp[(1) - (3)].pval), P_TOKEN("COMMA ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 72: + +/* Line 1464 of yacc.c */ +#line 365 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_let", P_TOKEN("COLON_EQUALS ", (yyvsp[(1) - (6)].ival)), P_TOKEN("LBRKT ", (yyvsp[(2) - (6)].ival)), (yyvsp[(3) - (6)].pval), P_TOKEN("RBRKT ", (yyvsp[(4) - (6)].ival)), P_TOKEN("COLON ", (yyvsp[(5) - (6)].ival)), (yyvsp[(6) - (6)].pval),NULL,NULL,NULL,NULL);;} + break; + + case 73: + +/* Line 1464 of yacc.c */ +#line 368 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_let_list", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 74: + +/* Line 1464 of yacc.c */ +#line 369 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_let_list", (yyvsp[(1) - (3)].pval), P_TOKEN("COMMA ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 75: + +/* Line 1464 of yacc.c */ +#line 372 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_defined_var", (yyvsp[(1) - (3)].pval), P_TOKEN("COLON_EQUALS ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 76: + +/* Line 1464 of yacc.c */ +#line 373 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_defined_var", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 77: + +/* Line 1464 of yacc.c */ +#line 376 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_conditional", P_TOKEN("_DLR_itef ", (yyvsp[(1) - (8)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (8)].ival)), (yyvsp[(3) - (8)].pval), P_TOKEN("COMMA ", (yyvsp[(4) - (8)].ival)), (yyvsp[(5) - (8)].pval), P_TOKEN("COMMA ", (yyvsp[(6) - (8)].ival)), (yyvsp[(7) - (8)].pval), P_TOKEN("RPAREN ", (yyvsp[(8) - (8)].ival)),NULL,NULL);;} + break; + + case 78: + +/* Line 1464 of yacc.c */ +#line 379 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_sequent", (yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 79: + +/* Line 1464 of yacc.c */ +#line 380 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_sequent", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 80: + +/* Line 1464 of yacc.c */ +#line 383 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 81: + +/* Line 1464 of yacc.c */ +#line 384 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 82: + +/* Line 1464 of yacc.c */ +#line 385 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 83: + +/* Line 1464 of yacc.c */ +#line 388 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_logic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 84: + +/* Line 1464 of yacc.c */ +#line 389 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_logic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 85: + +/* Line 1464 of yacc.c */ +#line 392 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_binary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 86: + +/* Line 1464 of yacc.c */ +#line 393 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_binary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 87: + +/* Line 1464 of yacc.c */ +#line 396 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_binary_nonassoc", (yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 88: + +/* Line 1464 of yacc.c */ +#line 399 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_binary_assoc", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 89: + +/* Line 1464 of yacc.c */ +#line 400 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_binary_assoc", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 90: + +/* Line 1464 of yacc.c */ +#line 403 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_or_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("VLINE ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 91: + +/* Line 1464 of yacc.c */ +#line 404 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_or_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("VLINE ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 92: + +/* Line 1464 of yacc.c */ +#line 407 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_and_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("AMPERSAND ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 93: + +/* Line 1464 of yacc.c */ +#line 408 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_and_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("AMPERSAND ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 94: + +/* Line 1464 of yacc.c */ +#line 411 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 95: + +/* Line 1464 of yacc.c */ +#line 412 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 96: + +/* Line 1464 of yacc.c */ +#line 413 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 97: + +/* Line 1464 of yacc.c */ +#line 414 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 98: + +/* Line 1464 of yacc.c */ +#line 415 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 99: + +/* Line 1464 of yacc.c */ +#line 416 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 100: + +/* Line 1464 of yacc.c */ +#line 417 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_unitary_formula", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 101: + +/* Line 1464 of yacc.c */ +#line 420 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_quantified_formula", (yyvsp[(1) - (6)].pval), P_TOKEN("LBRKT ", (yyvsp[(2) - (6)].ival)), (yyvsp[(3) - (6)].pval), P_TOKEN("RBRKT ", (yyvsp[(4) - (6)].ival)), P_TOKEN("COLON ", (yyvsp[(5) - (6)].ival)), (yyvsp[(6) - (6)].pval),NULL,NULL,NULL,NULL);;} + break; + + case 102: + +/* Line 1464 of yacc.c */ +#line 423 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_variable_list", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 103: + +/* Line 1464 of yacc.c */ +#line 424 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_variable_list", (yyvsp[(1) - (3)].pval), P_TOKEN("COMMA ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 104: + +/* Line 1464 of yacc.c */ +#line 427 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_variable", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 105: + +/* Line 1464 of yacc.c */ +#line 428 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_variable", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 106: + +/* Line 1464 of yacc.c */ +#line 431 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_typed_variable", (yyvsp[(1) - (3)].pval), P_TOKEN("COLON ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 107: + +/* Line 1464 of yacc.c */ +#line 434 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_unary_formula", (yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 108: + +/* Line 1464 of yacc.c */ +#line 435 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_unary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 109: + +/* Line 1464 of yacc.c */ +#line 438 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_typed_atom", (yyvsp[(1) - (3)].pval), P_TOKEN("COLON ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 110: + +/* Line 1464 of yacc.c */ +#line 439 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_typed_atom", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 111: + +/* Line 1464 of yacc.c */ +#line 442 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_untyped_atom", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 112: + +/* Line 1464 of yacc.c */ +#line 443 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_untyped_atom", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 113: + +/* Line 1464 of yacc.c */ +#line 446 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_top_level_type", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 114: + +/* Line 1464 of yacc.c */ +#line 447 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_top_level_type", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 115: + +/* Line 1464 of yacc.c */ +#line 450 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_unitary_type", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 116: + +/* Line 1464 of yacc.c */ +#line 451 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_unitary_type", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 117: + +/* Line 1464 of yacc.c */ +#line 454 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_atomic_type", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 118: + +/* Line 1464 of yacc.c */ +#line 455 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_atomic_type", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 119: + +/* Line 1464 of yacc.c */ +#line 458 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_mapping_type", (yyvsp[(1) - (3)].pval), P_TOKEN("arrow ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 120: + +/* Line 1464 of yacc.c */ +#line 459 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_mapping_type", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 121: + +/* Line 1464 of yacc.c */ +#line 462 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_xprod_type", (yyvsp[(1) - (3)].pval), P_TOKEN("STAR ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 122: + +/* Line 1464 of yacc.c */ +#line 463 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_xprod_type", (yyvsp[(1) - (3)].pval), P_TOKEN("STAR ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 123: + +/* Line 1464 of yacc.c */ +#line 464 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_xprod_type", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 124: + +/* Line 1464 of yacc.c */ +#line 467 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_let", P_TOKEN("COLON_EQUALS ", (yyvsp[(1) - (6)].ival)), P_TOKEN("LBRKT ", (yyvsp[(2) - (6)].ival)), (yyvsp[(3) - (6)].pval), P_TOKEN("RBRKT ", (yyvsp[(4) - (6)].ival)), P_TOKEN("COLON ", (yyvsp[(5) - (6)].ival)), (yyvsp[(6) - (6)].pval),NULL,NULL,NULL,NULL);;} + break; + + case 125: + +/* Line 1464 of yacc.c */ +#line 470 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_let_list", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 126: + +/* Line 1464 of yacc.c */ +#line 471 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_let_list", (yyvsp[(1) - (3)].pval), P_TOKEN("COMMA ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 127: + +/* Line 1464 of yacc.c */ +#line 474 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_defined_var", (yyvsp[(1) - (3)].pval), P_TOKEN("COLON_EQUALS ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 128: + +/* Line 1464 of yacc.c */ +#line 475 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_defined_var", (yyvsp[(1) - (4)].pval), P_TOKEN("COLON ", (yyvsp[(2) - (4)].ival)), P_TOKEN("MINUS ", (yyvsp[(3) - (4)].ival)), (yyvsp[(4) - (4)].pval),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 129: + +/* Line 1464 of yacc.c */ +#line 476 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_defined_var", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 130: + +/* Line 1464 of yacc.c */ +#line 479 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_conditional", P_TOKEN("_DLR_itef ", (yyvsp[(1) - (8)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (8)].ival)), (yyvsp[(3) - (8)].pval), P_TOKEN("COMMA ", (yyvsp[(4) - (8)].ival)), (yyvsp[(5) - (8)].pval), P_TOKEN("COMMA ", (yyvsp[(6) - (8)].ival)), (yyvsp[(7) - (8)].pval), P_TOKEN("RPAREN ", (yyvsp[(8) - (8)].ival)),NULL,NULL);;} + break; + + case 131: + +/* Line 1464 of yacc.c */ +#line 482 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_sequent", (yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 132: + +/* Line 1464 of yacc.c */ +#line 483 "tptp5.y" + {(yyval.pval) = P_BUILD("tff_sequent", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 133: + +/* Line 1464 of yacc.c */ +#line 486 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 134: + +/* Line 1464 of yacc.c */ +#line 487 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 135: + +/* Line 1464 of yacc.c */ +#line 490 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_logic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 136: + +/* Line 1464 of yacc.c */ +#line 491 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_logic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 137: + +/* Line 1464 of yacc.c */ +#line 494 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_binary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 138: + +/* Line 1464 of yacc.c */ +#line 495 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_binary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 139: + +/* Line 1464 of yacc.c */ +#line 498 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_binary_nonassoc", (yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 140: + +/* Line 1464 of yacc.c */ +#line 501 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_binary_assoc", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 141: + +/* Line 1464 of yacc.c */ +#line 502 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_binary_assoc", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 142: + +/* Line 1464 of yacc.c */ +#line 505 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_or_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("VLINE ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 143: + +/* Line 1464 of yacc.c */ +#line 506 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_or_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("VLINE ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 144: + +/* Line 1464 of yacc.c */ +#line 509 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_and_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("AMPERSAND ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 145: + +/* Line 1464 of yacc.c */ +#line 510 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_and_formula", (yyvsp[(1) - (3)].pval), P_TOKEN("AMPERSAND ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 146: + +/* Line 1464 of yacc.c */ +#line 513 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 147: + +/* Line 1464 of yacc.c */ +#line 514 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 148: + +/* Line 1464 of yacc.c */ +#line 515 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 149: + +/* Line 1464 of yacc.c */ +#line 516 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 150: + +/* Line 1464 of yacc.c */ +#line 517 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 151: + +/* Line 1464 of yacc.c */ +#line 518 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_unitary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 152: + +/* Line 1464 of yacc.c */ +#line 519 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_unitary_formula", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 153: + +/* Line 1464 of yacc.c */ +#line 522 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_quantified_formula", (yyvsp[(1) - (6)].pval), P_TOKEN("LBRKT ", (yyvsp[(2) - (6)].ival)), (yyvsp[(3) - (6)].pval), P_TOKEN("RBRKT ", (yyvsp[(4) - (6)].ival)), P_TOKEN("COLON ", (yyvsp[(5) - (6)].ival)), (yyvsp[(6) - (6)].pval),NULL,NULL,NULL,NULL);;} + break; + + case 154: + +/* Line 1464 of yacc.c */ +#line 525 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_variable_list", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 155: + +/* Line 1464 of yacc.c */ +#line 526 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_variable_list", (yyvsp[(1) - (3)].pval), P_TOKEN("COMMA ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 156: + +/* Line 1464 of yacc.c */ +#line 529 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_unary_formula", (yyvsp[(1) - (2)].pval), (yyvsp[(2) - (2)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 157: + +/* Line 1464 of yacc.c */ +#line 530 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_unary_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 158: + +/* Line 1464 of yacc.c */ +#line 533 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_let", P_TOKEN("COLON_EQUALS ", (yyvsp[(1) - (6)].ival)), P_TOKEN("LBRKT ", (yyvsp[(2) - (6)].ival)), (yyvsp[(3) - (6)].pval), P_TOKEN("RBRKT ", (yyvsp[(4) - (6)].ival)), P_TOKEN("COLON ", (yyvsp[(5) - (6)].ival)), (yyvsp[(6) - (6)].pval),NULL,NULL,NULL,NULL);;} + break; + + case 159: + +/* Line 1464 of yacc.c */ +#line 536 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_let_list", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 160: + +/* Line 1464 of yacc.c */ +#line 537 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_let_list", (yyvsp[(1) - (3)].pval), P_TOKEN("COMMA ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 161: + +/* Line 1464 of yacc.c */ +#line 540 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_defined_var", (yyvsp[(1) - (3)].pval), P_TOKEN("COLON_EQUALS ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 162: + +/* Line 1464 of yacc.c */ +#line 541 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_defined_var", (yyvsp[(1) - (4)].pval), P_TOKEN("COLON ", (yyvsp[(2) - (4)].ival)), P_TOKEN("MINUS ", (yyvsp[(3) - (4)].ival)), (yyvsp[(4) - (4)].pval),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 163: + +/* Line 1464 of yacc.c */ +#line 542 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_defined_var", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 164: + +/* Line 1464 of yacc.c */ +#line 545 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_conditional", P_TOKEN("_DLR_itef ", (yyvsp[(1) - (8)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (8)].ival)), (yyvsp[(3) - (8)].pval), P_TOKEN("COMMA ", (yyvsp[(4) - (8)].ival)), (yyvsp[(5) - (8)].pval), P_TOKEN("COMMA ", (yyvsp[(6) - (8)].ival)), (yyvsp[(7) - (8)].pval), P_TOKEN("RPAREN ", (yyvsp[(8) - (8)].ival)),NULL,NULL);;} + break; + + case 165: + +/* Line 1464 of yacc.c */ +#line 548 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_sequent", (yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 166: + +/* Line 1464 of yacc.c */ +#line 549 "tptp5.y" + {(yyval.pval) = P_BUILD("fof_sequent", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 167: + +/* Line 1464 of yacc.c */ +#line 552 "tptp5.y" + {(yyval.pval) = P_BUILD("cnf_formula", P_TOKEN("LPAREN ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RPAREN ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 168: + +/* Line 1464 of yacc.c */ +#line 553 "tptp5.y" + {(yyval.pval) = P_BUILD("cnf_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 169: + +/* Line 1464 of yacc.c */ +#line 556 "tptp5.y" + {(yyval.pval) = P_BUILD("disjunction", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 170: + +/* Line 1464 of yacc.c */ +#line 557 "tptp5.y" + {(yyval.pval) = P_BUILD("disjunction", (yyvsp[(1) - (3)].pval), P_TOKEN("VLINE ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 171: + +/* Line 1464 of yacc.c */ +#line 560 "tptp5.y" + {(yyval.pval) = P_BUILD("literal", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 172: + +/* Line 1464 of yacc.c */ +#line 561 "tptp5.y" + {(yyval.pval) = P_BUILD("literal", P_TOKEN("TILDE ", (yyvsp[(1) - (2)].ival)), (yyvsp[(2) - (2)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 173: + +/* Line 1464 of yacc.c */ +#line 562 "tptp5.y" + {(yyval.pval) = P_BUILD("literal", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 174: + +/* Line 1464 of yacc.c */ +#line 565 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_conn_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 175: + +/* Line 1464 of yacc.c */ +#line 566 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_conn_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 176: + +/* Line 1464 of yacc.c */ +#line 567 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_conn_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 177: + +/* Line 1464 of yacc.c */ +#line 570 "tptp5.y" + {(yyval.pval) = P_BUILD("fol_infix_unary", (yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 178: + +/* Line 1464 of yacc.c */ +#line 573 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_quantifier", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 179: + +/* Line 1464 of yacc.c */ +#line 574 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_quantifier", P_TOKEN("CARET ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 180: + +/* Line 1464 of yacc.c */ +#line 575 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_quantifier", P_TOKEN("EXCLAMATION_GREATER ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 181: + +/* Line 1464 of yacc.c */ +#line 576 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_quantifier", P_TOKEN("QUESTION_STAR ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 182: + +/* Line 1464 of yacc.c */ +#line 577 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_quantifier", P_TOKEN("AT_SIGN_PLUS ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 183: + +/* Line 1464 of yacc.c */ +#line 578 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_quantifier", P_TOKEN("AT_SIGN_MINUS ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 184: + +/* Line 1464 of yacc.c */ +#line 581 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_pair_connective", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 185: + +/* Line 1464 of yacc.c */ +#line 582 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_pair_connective", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 186: + +/* Line 1464 of yacc.c */ +#line 583 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_pair_connective", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 187: + +/* Line 1464 of yacc.c */ +#line 586 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unary_connective", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 188: + +/* Line 1464 of yacc.c */ +#line 587 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unary_connective", P_TOKEN("EXCLAMATION_EXCLAMATION ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 189: + +/* Line 1464 of yacc.c */ +#line 588 "tptp5.y" + {(yyval.pval) = P_BUILD("thf_unary_connective", P_TOKEN("QUESTION_QUESTION ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 190: + +/* Line 1464 of yacc.c */ +#line 591 "tptp5.y" + {(yyval.pval) = P_BUILD("subtype_sign", P_TOKEN("less_sign ", (yyvsp[(1) - (2)].ival)), P_TOKEN("less_sign ", (yyvsp[(2) - (2)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 191: + +/* Line 1464 of yacc.c */ +#line 594 "tptp5.y" + {(yyval.pval) = P_BUILD("fol_quantifier", P_TOKEN("EXCLAMATION ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 192: + +/* Line 1464 of yacc.c */ +#line 595 "tptp5.y" + {(yyval.pval) = P_BUILD("fol_quantifier", P_TOKEN("QUESTION ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 193: + +/* Line 1464 of yacc.c */ +#line 598 "tptp5.y" + {(yyval.pval) = P_BUILD("binary_connective", P_TOKEN("LESS_EQUALS_GREATER ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 194: + +/* Line 1464 of yacc.c */ +#line 599 "tptp5.y" + {(yyval.pval) = P_BUILD("binary_connective", P_TOKEN("EQUALS_GREATER ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 195: + +/* Line 1464 of yacc.c */ +#line 600 "tptp5.y" + {(yyval.pval) = P_BUILD("binary_connective", P_TOKEN("LESS_EQUALS ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 196: + +/* Line 1464 of yacc.c */ +#line 601 "tptp5.y" + {(yyval.pval) = P_BUILD("binary_connective", P_TOKEN("LESS_TILDE_GREATER ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 197: + +/* Line 1464 of yacc.c */ +#line 602 "tptp5.y" + {(yyval.pval) = P_BUILD("binary_connective", P_TOKEN("TILDE_VLINE ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 198: + +/* Line 1464 of yacc.c */ +#line 603 "tptp5.y" + {(yyval.pval) = P_BUILD("binary_connective", P_TOKEN("TILDE_AMPERSAND ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 199: + +/* Line 1464 of yacc.c */ +#line 606 "tptp5.y" + {(yyval.pval) = P_BUILD("assoc_connective", P_TOKEN("VLINE ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 200: + +/* Line 1464 of yacc.c */ +#line 607 "tptp5.y" + {(yyval.pval) = P_BUILD("assoc_connective", P_TOKEN("AMPERSAND ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 201: + +/* Line 1464 of yacc.c */ +#line 610 "tptp5.y" + {(yyval.pval) = P_BUILD("unary_connective", P_TOKEN("TILDE ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 202: + +/* Line 1464 of yacc.c */ +#line 613 "tptp5.y" + {(yyval.pval) = P_BUILD("gentzen_arrow", P_TOKEN("MINUS_MINUS_GREATER ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 203: + +/* Line 1464 of yacc.c */ +#line 616 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_type", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 204: + +/* Line 1464 of yacc.c */ +#line 619 "tptp5.y" + {(yyval.pval) = P_BUILD("atomic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 205: + +/* Line 1464 of yacc.c */ +#line 620 "tptp5.y" + {(yyval.pval) = P_BUILD("atomic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 206: + +/* Line 1464 of yacc.c */ +#line 621 "tptp5.y" + {(yyval.pval) = P_BUILD("atomic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 207: + +/* Line 1464 of yacc.c */ +#line 624 "tptp5.y" + {(yyval.pval) = P_BUILD("plain_atomic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 208: + +/* Line 1464 of yacc.c */ +#line 627 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_atomic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 209: + +/* Line 1464 of yacc.c */ +#line 628 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_atomic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 210: + +/* Line 1464 of yacc.c */ +#line 631 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_plain_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 211: + +/* Line 1464 of yacc.c */ +#line 634 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_infix_formula", (yyvsp[(1) - (3)].pval), (yyvsp[(2) - (3)].pval), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 212: + +/* Line 1464 of yacc.c */ +#line 637 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_infix_pred", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 213: + +/* Line 1464 of yacc.c */ +#line 640 "tptp5.y" + {(yyval.pval) = P_BUILD("infix_equality", P_TOKEN("EQUALS ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 214: + +/* Line 1464 of yacc.c */ +#line 643 "tptp5.y" + {(yyval.pval) = P_BUILD("infix_inequality", P_TOKEN("EXCLAMATION_EQUALS ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 215: + +/* Line 1464 of yacc.c */ +#line 646 "tptp5.y" + {(yyval.pval) = P_BUILD("system_atomic_formula", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 216: + +/* Line 1464 of yacc.c */ +#line 649 "tptp5.y" + {(yyval.pval) = P_BUILD("term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 217: + +/* Line 1464 of yacc.c */ +#line 650 "tptp5.y" + {(yyval.pval) = P_BUILD("term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 218: + +/* Line 1464 of yacc.c */ +#line 651 "tptp5.y" + {(yyval.pval) = P_BUILD("term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 219: + +/* Line 1464 of yacc.c */ +#line 654 "tptp5.y" + {(yyval.pval) = P_BUILD("function_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 220: + +/* Line 1464 of yacc.c */ +#line 655 "tptp5.y" + {(yyval.pval) = P_BUILD("function_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 221: + +/* Line 1464 of yacc.c */ +#line 656 "tptp5.y" + {(yyval.pval) = P_BUILD("function_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 222: + +/* Line 1464 of yacc.c */ +#line 659 "tptp5.y" + {(yyval.pval) = P_BUILD("plain_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 223: + +/* Line 1464 of yacc.c */ +#line 660 "tptp5.y" + {(yyval.pval) = P_BUILD("plain_term", (yyvsp[(1) - (4)].pval), P_TOKEN("LPAREN ", (yyvsp[(2) - (4)].ival)), (yyvsp[(3) - (4)].pval), P_TOKEN("RPAREN ", (yyvsp[(4) - (4)].ival)),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 224: + +/* Line 1464 of yacc.c */ +#line 663 "tptp5.y" + {(yyval.pval) = P_BUILD("constant", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 225: + +/* Line 1464 of yacc.c */ +#line 666 "tptp5.y" + {(yyval.pval) = P_BUILD("functor", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 226: + +/* Line 1464 of yacc.c */ +#line 669 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 227: + +/* Line 1464 of yacc.c */ +#line 670 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 228: + +/* Line 1464 of yacc.c */ +#line 673 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_atom", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 229: + +/* Line 1464 of yacc.c */ +#line 674 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_atom", P_TOKEN("distinct_object ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 230: + +/* Line 1464 of yacc.c */ +#line 677 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_atomic_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 231: + +/* Line 1464 of yacc.c */ +#line 680 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_plain_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 232: + +/* Line 1464 of yacc.c */ +#line 681 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_plain_term", (yyvsp[(1) - (4)].pval), P_TOKEN("LPAREN ", (yyvsp[(2) - (4)].ival)), (yyvsp[(3) - (4)].pval), P_TOKEN("RPAREN ", (yyvsp[(4) - (4)].ival)),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 233: + +/* Line 1464 of yacc.c */ +#line 684 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_constant", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 234: + +/* Line 1464 of yacc.c */ +#line 687 "tptp5.y" + {(yyval.pval) = P_BUILD("defined_functor", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 235: + +/* Line 1464 of yacc.c */ +#line 690 "tptp5.y" + {(yyval.pval) = P_BUILD("system_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 236: + +/* Line 1464 of yacc.c */ +#line 691 "tptp5.y" + {(yyval.pval) = P_BUILD("system_term", (yyvsp[(1) - (4)].pval), P_TOKEN("LPAREN ", (yyvsp[(2) - (4)].ival)), (yyvsp[(3) - (4)].pval), P_TOKEN("RPAREN ", (yyvsp[(4) - (4)].ival)),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 237: + +/* Line 1464 of yacc.c */ +#line 694 "tptp5.y" + {(yyval.pval) = P_BUILD("system_constant", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 238: + +/* Line 1464 of yacc.c */ +#line 697 "tptp5.y" + {(yyval.pval) = P_BUILD("system_functor", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 239: + +/* Line 1464 of yacc.c */ +#line 700 "tptp5.y" + {(yyval.pval) = P_BUILD("variable", P_TOKEN("upper_word ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 240: + +/* Line 1464 of yacc.c */ +#line 703 "tptp5.y" + {(yyval.pval) = P_BUILD("arguments", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 241: + +/* Line 1464 of yacc.c */ +#line 704 "tptp5.y" + {(yyval.pval) = P_BUILD("arguments", (yyvsp[(1) - (3)].pval), P_TOKEN("COMMA ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 242: + +/* Line 1464 of yacc.c */ +#line 707 "tptp5.y" + {(yyval.pval) = P_BUILD("conditional_term", P_TOKEN("_DLR_itett ", (yyvsp[(1) - (8)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (8)].ival)), (yyvsp[(3) - (8)].pval), P_TOKEN("COMMA ", (yyvsp[(4) - (8)].ival)), (yyvsp[(5) - (8)].pval), P_TOKEN("COMMA ", (yyvsp[(6) - (8)].ival)), (yyvsp[(7) - (8)].pval), P_TOKEN("RPAREN ", (yyvsp[(8) - (8)].ival)),NULL,NULL);;} + break; + + case 243: + +/* Line 1464 of yacc.c */ +#line 708 "tptp5.y" + {(yyval.pval) = P_BUILD("conditional_term", P_TOKEN("_DLR_itetf ", (yyvsp[(1) - (8)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (8)].ival)), (yyvsp[(3) - (8)].pval), P_TOKEN("COMMA ", (yyvsp[(4) - (8)].ival)), (yyvsp[(5) - (8)].pval), P_TOKEN("COMMA ", (yyvsp[(6) - (8)].ival)), (yyvsp[(7) - (8)].pval), P_TOKEN("RPAREN ", (yyvsp[(8) - (8)].ival)),NULL,NULL);;} + break; + + case 244: + +/* Line 1464 of yacc.c */ +#line 711 "tptp5.y" + {(yyval.pval) = P_BUILD("source", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 245: + +/* Line 1464 of yacc.c */ +#line 714 "tptp5.y" + {(yyval.pval) = P_BUILD("optional_info", P_TOKEN("COMMA ", (yyvsp[(1) - (2)].ival)), (yyvsp[(2) - (2)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 246: + +/* Line 1464 of yacc.c */ +#line 715 "tptp5.y" + {(yyval.pval) = P_BUILD("optional_info", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 247: + +/* Line 1464 of yacc.c */ +#line 718 "tptp5.y" + {(yyval.pval) = P_BUILD("useful_info", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 248: + +/* Line 1464 of yacc.c */ +#line 721 "tptp5.y" + {(yyval.pval) = P_BUILD("include", P_TOKEN("_LIT_include ", (yyvsp[(1) - (6)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (6)].ival)), (yyvsp[(3) - (6)].pval), (yyvsp[(4) - (6)].pval), P_TOKEN("RPAREN ", (yyvsp[(5) - (6)].ival)), P_TOKEN("PERIOD ", (yyvsp[(6) - (6)].ival)),NULL,NULL,NULL,NULL);;} + break; + + case 249: + +/* Line 1464 of yacc.c */ +#line 724 "tptp5.y" + {(yyval.pval) = P_BUILD("formula_selection", P_TOKEN("COMMA ", (yyvsp[(1) - (4)].ival)), P_TOKEN("LBRKT ", (yyvsp[(2) - (4)].ival)), (yyvsp[(3) - (4)].pval), P_TOKEN("RBRKT ", (yyvsp[(4) - (4)].ival)),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 250: + +/* Line 1464 of yacc.c */ +#line 725 "tptp5.y" + {(yyval.pval) = P_BUILD("formula_selection", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 251: + +/* Line 1464 of yacc.c */ +#line 728 "tptp5.y" + {(yyval.pval) = P_BUILD("name_list", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 252: + +/* Line 1464 of yacc.c */ +#line 729 "tptp5.y" + {(yyval.pval) = P_BUILD("name_list", (yyvsp[(1) - (3)].pval), P_TOKEN("COMMA ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 253: + +/* Line 1464 of yacc.c */ +#line 732 "tptp5.y" + {(yyval.pval) = P_BUILD("general_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 254: + +/* Line 1464 of yacc.c */ +#line 733 "tptp5.y" + {(yyval.pval) = P_BUILD("general_term", (yyvsp[(1) - (3)].pval), P_TOKEN("COLON ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 255: + +/* Line 1464 of yacc.c */ +#line 734 "tptp5.y" + {(yyval.pval) = P_BUILD("general_term", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 256: + +/* Line 1464 of yacc.c */ +#line 737 "tptp5.y" + {(yyval.pval) = P_BUILD("general_data", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 257: + +/* Line 1464 of yacc.c */ +#line 738 "tptp5.y" + {(yyval.pval) = P_BUILD("general_data", (yyvsp[(1) - (4)].pval), P_TOKEN("LPAREN ", (yyvsp[(2) - (4)].ival)), (yyvsp[(3) - (4)].pval), P_TOKEN("RPAREN ", (yyvsp[(4) - (4)].ival)),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 258: + +/* Line 1464 of yacc.c */ +#line 739 "tptp5.y" + {(yyval.pval) = P_BUILD("general_data", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 259: + +/* Line 1464 of yacc.c */ +#line 740 "tptp5.y" + {(yyval.pval) = P_BUILD("general_data", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 260: + +/* Line 1464 of yacc.c */ +#line 741 "tptp5.y" + {(yyval.pval) = P_BUILD("general_data", P_TOKEN("distinct_object ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 261: + +/* Line 1464 of yacc.c */ +#line 742 "tptp5.y" + {(yyval.pval) = P_BUILD("general_data", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 262: + +/* Line 1464 of yacc.c */ +#line 745 "tptp5.y" + {(yyval.pval) = P_BUILD("formula_data", P_TOKEN("_DLR_thf ", (yyvsp[(1) - (4)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (4)].ival)), (yyvsp[(3) - (4)].pval), P_TOKEN("RPAREN ", (yyvsp[(4) - (4)].ival)),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 263: + +/* Line 1464 of yacc.c */ +#line 746 "tptp5.y" + {(yyval.pval) = P_BUILD("formula_data", P_TOKEN("_DLR_tff ", (yyvsp[(1) - (4)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (4)].ival)), (yyvsp[(3) - (4)].pval), P_TOKEN("RPAREN ", (yyvsp[(4) - (4)].ival)),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 264: + +/* Line 1464 of yacc.c */ +#line 747 "tptp5.y" + {(yyval.pval) = P_BUILD("formula_data", P_TOKEN("_DLR_fof ", (yyvsp[(1) - (4)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (4)].ival)), (yyvsp[(3) - (4)].pval), P_TOKEN("RPAREN ", (yyvsp[(4) - (4)].ival)),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 265: + +/* Line 1464 of yacc.c */ +#line 748 "tptp5.y" + {(yyval.pval) = P_BUILD("formula_data", P_TOKEN("_DLR_cnf ", (yyvsp[(1) - (4)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (4)].ival)), (yyvsp[(3) - (4)].pval), P_TOKEN("RPAREN ", (yyvsp[(4) - (4)].ival)),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 266: + +/* Line 1464 of yacc.c */ +#line 749 "tptp5.y" + {(yyval.pval) = P_BUILD("formula_data", P_TOKEN("_DLR_fot ", (yyvsp[(1) - (4)].ival)), P_TOKEN("LPAREN ", (yyvsp[(2) - (4)].ival)), (yyvsp[(3) - (4)].pval), P_TOKEN("RPAREN ", (yyvsp[(4) - (4)].ival)),NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 267: + +/* Line 1464 of yacc.c */ +#line 752 "tptp5.y" + {(yyval.pval) = P_BUILD("general_list", P_TOKEN("LBRKT ", (yyvsp[(1) - (2)].ival)), P_TOKEN("RBRKT ", (yyvsp[(2) - (2)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 268: + +/* Line 1464 of yacc.c */ +#line 753 "tptp5.y" + {(yyval.pval) = P_BUILD("general_list", P_TOKEN("LBRKT ", (yyvsp[(1) - (3)].ival)), (yyvsp[(2) - (3)].pval), P_TOKEN("RBRKT ", (yyvsp[(3) - (3)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 269: + +/* Line 1464 of yacc.c */ +#line 756 "tptp5.y" + {(yyval.pval) = P_BUILD("general_terms", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 270: + +/* Line 1464 of yacc.c */ +#line 757 "tptp5.y" + {(yyval.pval) = P_BUILD("general_terms", (yyvsp[(1) - (3)].pval), P_TOKEN("COMMA ", (yyvsp[(2) - (3)].ival)), (yyvsp[(3) - (3)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 271: + +/* Line 1464 of yacc.c */ +#line 760 "tptp5.y" + {(yyval.pval) = P_BUILD("name", (yyvsp[(1) - (1)].pval),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 272: + +/* Line 1464 of yacc.c */ +#line 761 "tptp5.y" + {(yyval.pval) = P_BUILD("name", P_TOKEN("integer ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 273: + +/* Line 1464 of yacc.c */ +#line 764 "tptp5.y" + {(yyval.pval) = P_BUILD("atomic_word", P_TOKEN("lower_word ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 274: + +/* Line 1464 of yacc.c */ +#line 765 "tptp5.y" + {(yyval.pval) = P_BUILD("atomic_word", P_TOKEN("single_quoted ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 275: + +/* Line 1464 of yacc.c */ +#line 768 "tptp5.y" + {(yyval.pval) = P_BUILD("atomic_defined_word", P_TOKEN("dollar_word ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 276: + +/* Line 1464 of yacc.c */ +#line 771 "tptp5.y" + {(yyval.pval) = P_BUILD("atomic_system_word", P_TOKEN("dollar_dollar_word ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 277: + +/* Line 1464 of yacc.c */ +#line 774 "tptp5.y" + {(yyval.pval) = P_BUILD("number", P_TOKEN("integer ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 278: + +/* Line 1464 of yacc.c */ +#line 775 "tptp5.y" + {(yyval.pval) = P_BUILD("number", P_TOKEN("rational ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 279: + +/* Line 1464 of yacc.c */ +#line 776 "tptp5.y" + {(yyval.pval) = P_BUILD("number", P_TOKEN("real ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 280: + +/* Line 1464 of yacc.c */ +#line 779 "tptp5.y" + {(yyval.pval) = P_BUILD("file_name", P_TOKEN("single_quoted ", (yyvsp[(1) - (1)].ival)),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + case 281: + +/* Line 1464 of yacc.c */ +#line 782 "tptp5.y" + {(yyval.pval) = P_BUILD("null",NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);;} + break; + + + +/* Line 1464 of yacc.c */ +#line 4264 "tptp5.tab.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + diff --git a/examples/tptp/tptp5.tab.h b/examples/tptp/tptp5.tab.h new file mode 100644 index 000000000..2e03c0d13 --- /dev/null +++ b/examples/tptp/tptp5.tab.h @@ -0,0 +1,138 @@ +/* A Bison parser, made by GNU Bison 2.4.2. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2006, 2009-2010 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + AMPERSAND = 258, + AT_SIGN = 259, + AT_SIGN_MINUS = 260, + AT_SIGN_PLUS = 261, + CARET = 262, + COLON = 263, + COLON_EQUALS = 264, + COMMA = 265, + EQUALS = 266, + EQUALS_GREATER = 267, + EXCLAMATION = 268, + EXCLAMATION_EQUALS = 269, + EXCLAMATION_EXCLAMATION = 270, + EXCLAMATION_GREATER = 271, + LBRKT = 272, + LESS_EQUALS = 273, + LESS_EQUALS_GREATER = 274, + LESS_TILDE_GREATER = 275, + LPAREN = 276, + MINUS = 277, + MINUS_MINUS_GREATER = 278, + PERIOD = 279, + QUESTION = 280, + QUESTION_QUESTION = 281, + QUESTION_STAR = 282, + RBRKT = 283, + RPAREN = 284, + STAR = 285, + TILDE = 286, + TILDE_AMPERSAND = 287, + TILDE_VLINE = 288, + VLINE = 289, + _DLR_cnf = 290, + _DLR_fof = 291, + _DLR_fot = 292, + _DLR_itef = 293, + _DLR_itetf = 294, + _DLR_itett = 295, + _DLR_tff = 296, + _DLR_thf = 297, + _LIT_cnf = 298, + _LIT_fof = 299, + _LIT_include = 300, + _LIT_tff = 301, + _LIT_thf = 302, + arrow = 303, + comment = 304, + comment_line = 305, + decimal = 306, + decimal_exponent = 307, + decimal_fraction = 308, + distinct_object = 309, + dollar_dollar_word = 310, + dollar_word = 311, + dot_decimal = 312, + integer = 313, + less_sign = 314, + lower_word = 315, + plus = 316, + positive_decimal = 317, + rational = 318, + real = 319, + signed_integer = 320, + signed_rational = 321, + signed_real = 322, + single_quoted = 323, + star = 324, + unrecognized = 325, + unsigned_integer = 326, + unsigned_rational = 327, + unsigned_real = 328, + upper_word = 329, + vline = 330 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 1685 of yacc.c */ +#line 148 "tptp5.y" +int ival; double dval; char* sval; TreeNode* pval; + + +/* Line 1685 of yacc.c */ +#line 130 "tptp5.tab.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +extern YYSTYPE yylval; + + diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 4fec0a9e7..6054f4769 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -83,6 +83,7 @@ def init_project_def(): set_z3py_dir('api/python') # Examples add_cpp_example('cpp_example', 'c++') + add_cpp_example('z3_tptp', 'tptp') add_c_example('c_example', 'c') add_c_example('maxsat') add_dotnet_example('dotnet_example', 'dotnet') diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 59122af32..98f213dd5 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -931,6 +931,9 @@ class ExtraExeComponent(ExeComponent): def main_component(self): return False + def require_mem_initializer(self): + return False + def get_so_ext(): sysname = os.uname()[0] if sysname == 'Darwin': @@ -1227,7 +1230,7 @@ class CppExampleComponent(ExampleComponent): out.write(' ') out.write(os.path.join(self.to_ex_dir, cppfile)) out.write('\n') - out.write('\t%s $(LINK_OUT_FLAG)%s $(LINK_FLAGS)' % (self.compiler(), exefile)) + out.write('\t%s $(OS_DEFINES) $(LINK_OUT_FLAG)%s $(LINK_FLAGS)' % (self.compiler(), exefile)) # Add include dir components out.write(' -I%s' % get_component(API_COMPONENT).to_src_dir) out.write(' -I%s' % get_component(CPP_COMPONENT).to_src_dir) @@ -1399,7 +1402,8 @@ def mk_config(): 'LINK_OUT_FLAG=/Fe\n' 'SO_EXT=.dll\n' 'SLINK=cl\n' - 'SLINK_OUT_FLAG=/Fe\n') + 'SLINK_OUT_FLAG=/Fe\n' + 'OS_DEFINES=/D _WINDOWS\n') extra_opt = '' if GIT_HASH: extra_opt = '%s /D Z3GITHASH=%s' % (extra_opt, GIT_HASH) @@ -1447,6 +1451,7 @@ def mk_config(): print('Java Compiler: %s' % JAVAC) else: global CXX, CC, GMP, CPPFLAGS, CXXFLAGS, LDFLAGS + OS_DEFINES = "" ARITH = "internal" check_ar() CXX = find_cxx_compiler() @@ -1488,18 +1493,21 @@ def mk_config(): SLIBFLAGS = '-dynamiclib' elif sysname == 'Linux': CXXFLAGS = '%s -fno-strict-aliasing -D_LINUX_' % CXXFLAGS + OS_DEFINES = '-D_LINUX' SO_EXT = '.so' LDFLAGS = '%s -lrt' % LDFLAGS SLIBFLAGS = '-shared' SLIBEXTRAFLAGS = '%s -lrt' % SLIBEXTRAFLAGS elif sysname == 'FreeBSD': CXXFLAGS = '%s -fno-strict-aliasing -D_FREEBSD_' % CXXFLAGS + OS_DEFINES = '-D_FREEBSD_' SO_EXT = '.so' LDFLAGS = '%s -lrt' % LDFLAGS SLIBFLAGS = '-shared' SLIBEXTRAFLAGS = '%s -lrt' % SLIBEXTRAFLAGS elif sysname[:6] == 'CYGWIN': CXXFLAGS = '%s -D_CYGWIN -fno-strict-aliasing' % CXXFLAGS + OS_DEFINES = '-D_CYGWIN' SO_EXT = '.dll' SLIBFLAGS = '-shared' else: @@ -1534,6 +1542,7 @@ def mk_config(): config.write('SLINK_FLAGS=%s\n' % SLIBFLAGS) config.write('SLINK_EXTRA_FLAGS=%s\n' % SLIBEXTRAFLAGS) config.write('SLINK_OUT_FLAG=-o \n') + config.write('OS_DEFINES=%s\n' % OS_DEFINES) if is_verbose(): print('Host platform: %s' % sysname) print('C++ Compiler: %s' % CXX) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 6f745d620..c75acc5e2 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -204,6 +204,8 @@ namespace z3 { func_decl function(symbol const & name, unsigned arity, sort const * domain, sort const & range); func_decl function(char const * name, unsigned arity, sort const * domain, sort const & range); + func_decl function(symbol const& name, sort_vector const& domain, sort const& range); + func_decl function(char const * name, sort_vector const& domain, sort const& range); func_decl function(char const * name, sort const & domain, sort const & range); func_decl function(char const * name, sort const & d1, sort const & d2, sort const & range); func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & range); @@ -429,6 +431,7 @@ namespace z3 { expr operator()() const; expr operator()(unsigned n, expr const * args) const; + expr operator()(expr_vector const& v) const; expr operator()(expr const & a) const; expr operator()(int a) const; expr operator()(expr const & a1, expr const & a2) const; @@ -1516,6 +1519,22 @@ namespace z3 { inline func_decl context::function(char const * name, unsigned arity, sort const * domain, sort const & range) { return function(range.ctx().str_symbol(name), arity, domain, range); } + + inline func_decl context::function(symbol const& name, sort_vector const& domain, sort const& range) { + array args(domain.size()); + for (unsigned i = 0; i < domain.size(); i++) { + check_context(domain[i], range); + args[i] = domain[i]; + } + Z3_func_decl f = Z3_mk_func_decl(m_ctx, name, domain.size(), args.ptr(), range); + check_error(); + return func_decl(*this, f); + } + + inline func_decl context::function(char const * name, sort_vector const& domain, sort const& range) { + return function(range.ctx().str_symbol(name), domain, range); + } + inline func_decl context::function(char const * name, sort const & domain, sort const & range) { check_context(domain, range); @@ -1602,6 +1621,16 @@ namespace z3 { return expr(ctx(), r); } + inline expr func_decl::operator()(expr_vector const& args) const { + array _args(args.size()); + for (unsigned i = 0; i < args.size(); i++) { + check_context(*this, args[i]); + _args[i] = args[i]; + } + Z3_ast r = Z3_mk_app(ctx(), *this, args.size(), _args.ptr()); + check_error(); + return expr(ctx(), r); + } inline expr func_decl::operator()() const { Z3_ast r = Z3_mk_app(ctx(), *this, 0, 0); ctx().check_error(); diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index a6bd7f7f8..f2c50487f 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -719,7 +719,7 @@ namespace datalog { T& operator*() { return *m_t; } const T& operator*() const { return *m_t; } operator bool() const { return m_t!=0; } - T* get() { return m_t; } + T* get() const { return m_t; } /** \brief Remove object from \c scoped_rel without deleting it. */ diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index c9bdec0b6..2cae7771f 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -81,9 +81,9 @@ namespace datalog { } unsigned entry_storage::get_size_estimate_bytes() const { - unsigned sz = m_data.capacity(); + size_t sz = m_data.capacity(); sz += m_data_indexer.capacity()*sizeof(storage_indexer::entry); - return sz; + return static_cast(sz); } // ----------------------------------- @@ -283,7 +283,7 @@ namespace datalog { class sparse_table::general_key_indexer : public key_indexer { typedef svector offset_vector; - typedef u_map index_map; + typedef size_t_map index_map; index_map m_map; mutable entry_storage m_keys; @@ -641,8 +641,8 @@ namespace datalog { unsigned t1_entry_size = t1.m_fact_size; unsigned t2_entry_size = t2.m_fact_size; - unsigned t1idx = 0; - unsigned t1end = t1.m_data.after_last_offset(); + size_t t1idx = 0; + size_t t1end = t1.m_data.after_last_offset(); TRACE("dl_table_relation", tout << "joined_col_cnt: " << joined_col_cnt << "\n"; @@ -654,8 +654,8 @@ namespace datalog { ); if (joined_col_cnt == 0) { - unsigned t2idx = 0; - unsigned t2end = t2.m_data.after_last_offset(); + size_t t2idx = 0; + size_t t2end = t2.m_data.after_last_offset(); for (; t1idx!=t1end; t1idx+=t1_entry_size) { for (t2idx = 0; t2idx != t2end; t2idx += t2_entry_size) { @@ -1064,8 +1064,8 @@ namespace datalog { sparse_table_plugin & plugin = t.get_plugin(); sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); - unsigned res_fact_size = res->m_fact_size; - unsigned res_data_size = res_fact_size*t.row_count(); + size_t res_fact_size = res->m_fact_size; + size_t res_data_size = res_fact_size*t.row_count(); if (res_fact_size != 0 && (res_data_size / res_fact_size) != t.row_count()) { throw default_exception("multiplication overflow"); } @@ -1084,7 +1084,7 @@ namespace datalog { } //and insert them into the hash-map - for (unsigned i=0; i!=res_data_size; i+=res_fact_size) { + for (size_t i = 0; i != res_data_size; i += res_fact_size) { TRUSTME(res->m_data.insert_offset(i)); } @@ -1161,7 +1161,7 @@ namespace datalog { } if (key_modified) { t2_offsets = t2_indexer.get_matching_offsets(t1_key); - key_modified=false; + key_modified = false; } if (t2_offsets.empty()) { @@ -1171,12 +1171,16 @@ namespace datalog { res.push_back(t1_ofs); } else { - key_indexer::offset_iterator it = t2_offsets.begin(); + key_indexer::offset_iterator it = t2_offsets.begin(); key_indexer::offset_iterator end = t2_offsets.end(); for (; it!=end; ++it) { store_offset ofs = *it; - if (!m_intersection_content.contains(ofs)) { - m_intersection_content.insert(ofs); + unsigned offs2 = static_cast(ofs); + if (ofs != offs2) { + throw default_exception("Z3 cannot perform negation with excessively large tables"); + } + if (!m_intersection_content.contains(offs2)) { + m_intersection_content.insert(offs2); res.push_back(ofs); } } diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h index 5c5f95a75..0a60c4e10 100644 --- a/src/muz/rel/dl_sparse_table.h +++ b/src/muz/rel/dl_sparse_table.h @@ -97,9 +97,9 @@ namespace datalog { class entry_storage { public: - typedef unsigned store_offset; + typedef size_t store_offset; private: - typedef svector storage; + typedef svector storage; class offset_hash_proc { storage & m_storage; @@ -130,7 +130,7 @@ namespace datalog { unsigned m_entry_size; unsigned m_unique_part_size; - unsigned m_data_size; + size_t m_data_size; /** Invariant: Every or all but one blocks of length \c m_entry_size in the \c m_data vector are unique sequences of bytes and have their offset stored in the \c m_data_indexer hashtable. @@ -214,7 +214,7 @@ namespace datalog { SASSERT(m_reserve==m_data_size-m_entry_size); return; } - m_reserve=m_data_size; + m_reserve = m_data_size; resize_data(m_data_size+m_entry_size); } @@ -273,7 +273,7 @@ namespace datalog { //the following two operations allow breaking of the object invariant! - void resize_data(unsigned sz) { + void resize_data(size_t sz) { m_data_size = sz; if (sz + sizeof(uint64) < sz) { throw default_exception("overflow resizing data section for sparse table"); diff --git a/src/util/vector.h b/src/util/vector.h index 8bfe7c703..9370a4eed 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -37,7 +37,7 @@ Revision History: #pragma warning(disable:4127) #endif -template +template class vector { #define SIZE_IDX -1 #define CAPACITY_IDX -2 @@ -52,13 +52,13 @@ class vector { } void free_memory() { - memory::deallocate(reinterpret_cast(reinterpret_cast(m_data) - 2)); + memory::deallocate(reinterpret_cast(reinterpret_cast(m_data) - 2)); } void expand_vector() { if (m_data == 0) { - unsigned capacity = 2; - unsigned * mem = reinterpret_cast(memory::allocate(sizeof(T) * capacity + sizeof(unsigned) * 2)); + SZ capacity = 2; + SZ * mem = reinterpret_cast(memory::allocate(sizeof(T) * capacity + sizeof(SZ) * 2)); *mem = capacity; mem++; *mem = 0; @@ -67,15 +67,15 @@ class vector { } else { SASSERT(capacity() > 0); - unsigned old_capacity = reinterpret_cast(m_data)[CAPACITY_IDX]; - unsigned old_capacity_T = sizeof(T) * old_capacity + sizeof(unsigned) * 2; - unsigned new_capacity = (3 * old_capacity + 1) >> 1; - unsigned new_capacity_T = sizeof(T) * new_capacity + sizeof(unsigned) * 2; - unsigned size = reinterpret_cast(m_data)[SIZE_IDX]; + SZ old_capacity = reinterpret_cast(m_data)[CAPACITY_IDX]; + SZ old_capacity_T = sizeof(T) * old_capacity + sizeof(SZ) * 2; + SZ new_capacity = (3 * old_capacity + 1) >> 1; + SZ new_capacity_T = sizeof(T) * new_capacity + sizeof(SZ) * 2; + SZ size = reinterpret_cast(m_data)[SIZE_IDX]; if (new_capacity <= old_capacity || new_capacity_T <= old_capacity_T) { throw default_exception("Overflow encountered when expanding vector"); } - unsigned * mem = reinterpret_cast(memory::allocate(new_capacity_T)); + SZ * mem = reinterpret_cast(memory::allocate(new_capacity_T)); *mem = new_capacity; mem ++; *mem = size; @@ -87,9 +87,9 @@ class vector { } void copy_core(vector const & source) { - unsigned size = source.size(); - unsigned capacity = source.capacity(); - unsigned * mem = reinterpret_cast(memory::allocate(sizeof(T) * capacity + sizeof(unsigned) * 2)); + SZ size = source.size(); + SZ capacity = source.capacity(); + SZ * mem = reinterpret_cast(memory::allocate(sizeof(T) * capacity + sizeof(SZ) * 2)); *mem = capacity; mem++; *mem = size; @@ -122,8 +122,8 @@ public: m_data(0) { } - vector(unsigned s) { - unsigned * mem = reinterpret_cast(memory::allocate(sizeof(T) * s + sizeof(unsigned) * 2)); + vector(SZ s) { + SZ * mem = reinterpret_cast(memory::allocate(sizeof(T) * s + sizeof(SZ) * 2)); *mem = s; mem++; *mem = s; @@ -137,7 +137,7 @@ public: } } - vector(unsigned s, T const & elem): + vector(SZ s, T const & elem): m_data(0) { resize(s, elem); } @@ -150,9 +150,9 @@ public: SASSERT(size() == source.size()); } - vector(unsigned s, T const * data): + vector(SZ s, T const * data): m_data(0) { - for (unsigned i = 0; i < s; i++) { + for (SZ i = 0; i < s; i++) { push_back(data[i]); } } @@ -186,26 +186,26 @@ public: if (CallDestructors) { destroy_elements(); } - reinterpret_cast(m_data)[SIZE_IDX] = 0; + reinterpret_cast(m_data)[SIZE_IDX] = 0; } } bool empty() const { - return m_data == 0 || reinterpret_cast(m_data)[SIZE_IDX] == 0; + return m_data == 0 || reinterpret_cast(m_data)[SIZE_IDX] == 0; } - unsigned size() const { + SZ size() const { if (m_data == 0) { return 0; } - return reinterpret_cast(m_data)[SIZE_IDX]; + return reinterpret_cast(m_data)[SIZE_IDX]; } - unsigned capacity() const { + SZ capacity() const { if (m_data == 0) { return 0; } - return reinterpret_cast(m_data)[CAPACITY_IDX]; + return reinterpret_cast(m_data)[CAPACITY_IDX]; } iterator begin() { @@ -226,41 +226,41 @@ public: void set_end(iterator it) { if (m_data) { - unsigned new_sz = static_cast(it - m_data); + SZ new_sz = static_cast(it - m_data); if (CallDestructors) { iterator e = end(); for(; it != e; ++it) { it->~T(); } } - reinterpret_cast(m_data)[SIZE_IDX] = new_sz; + reinterpret_cast(m_data)[SIZE_IDX] = new_sz; } else { SASSERT(it == 0); } } - T & operator[](unsigned idx) { + T & operator[](SZ idx) { SASSERT(idx < size()); return m_data[idx]; } - T const & operator[](unsigned idx) const { + T const & operator[](SZ idx) const { SASSERT(idx < size()); return m_data[idx]; } - T & get(unsigned idx) { + T & get(SZ idx) { SASSERT(idx < size()); return m_data[idx]; } - T const & get(unsigned idx) const { + T const & get(SZ idx) const { SASSERT(idx < size()); return m_data[idx]; } - void set(unsigned idx, T const & val) { + void set(SZ idx, T const & val) { SASSERT(idx < size()); m_data[idx] = val; } @@ -280,15 +280,15 @@ public: if (CallDestructors) { back().~T(); } - reinterpret_cast(m_data)[SIZE_IDX]--; + reinterpret_cast(m_data)[SIZE_IDX]--; } void push_back(T const & elem) { - if (m_data == 0 || reinterpret_cast(m_data)[SIZE_IDX] == reinterpret_cast(m_data)[CAPACITY_IDX]) { + if (m_data == 0 || reinterpret_cast(m_data)[SIZE_IDX] == reinterpret_cast(m_data)[CAPACITY_IDX]) { expand_vector(); } - new (m_data + reinterpret_cast(m_data)[SIZE_IDX]) T(elem); - reinterpret_cast(m_data)[SIZE_IDX]++; + new (m_data + reinterpret_cast(m_data)[SIZE_IDX]) T(elem); + reinterpret_cast(m_data)[SIZE_IDX]++; } void insert(T const & elem) { @@ -303,7 +303,7 @@ public: for(; pos != e; ++pos, ++prev) { *prev = *pos; } - reinterpret_cast(m_data)[SIZE_IDX]--; + reinterpret_cast(m_data)[SIZE_IDX]--; } void erase(T const & elem) { @@ -313,9 +313,9 @@ public: } } - void shrink(unsigned s) { + void shrink(SZ s) { if (m_data) { - SASSERT(s <= reinterpret_cast(m_data)[SIZE_IDX]); + SASSERT(s <= reinterpret_cast(m_data)[SIZE_IDX]); if (CallDestructors) { iterator it = m_data + s; iterator e = end(); @@ -323,21 +323,21 @@ public: it->~T(); } } - reinterpret_cast(m_data)[SIZE_IDX] = s; + reinterpret_cast(m_data)[SIZE_IDX] = s; } else { SASSERT(s == 0); } } - void resize(unsigned s, T const & elem=T()) { - unsigned sz = size(); + void resize(SZ s, T const & elem=T()) { + SZ sz = size(); if (s <= sz) { shrink(s); return; } while (s > capacity()) { expand_vector(); } SASSERT(m_data != 0); - reinterpret_cast(m_data)[SIZE_IDX] = s; + reinterpret_cast(m_data)[SIZE_IDX] = s; iterator it = m_data + sz; iterator end = m_data + s; for(; it != end; ++it) { @@ -346,13 +346,13 @@ public: } void append(vector const & other) { - for(unsigned i = 0; i < other.size(); ++i) { + for(SZ i = 0; i < other.size(); ++i) { push_back(other[i]); } } - void append(unsigned sz, T const * data) { - for(unsigned i = 0; i < sz; ++i) { + void append(SZ sz, T const * data) { + for(SZ i = 0; i < sz; ++i) { push_back(data[i]); } } @@ -366,8 +366,8 @@ public: } void reverse() { - unsigned sz = size(); - for (unsigned i = 0; i < sz/2; ++i) { + SZ sz = size(); + for (SZ i = 0; i < sz/2; ++i) { std::swap(m_data[i], m_data[sz-i-1]); } } @@ -392,7 +392,7 @@ public: } // set pos idx with elem. If idx >= size, then expand using default. - void setx(unsigned idx, T const & elem, T const & d) { + void setx(SZ idx, T const & elem, T const & d) { if (idx >= size()) { resize(idx+1, d); } @@ -400,14 +400,14 @@ public: } // return element at position idx, if idx >= size, then return default - T const & get(unsigned idx, T const & d) const { + T const & get(SZ idx, T const & d) const { if (idx >= size()) { return d; } return m_data[idx]; } - void reserve(unsigned s, T const & d = T()) { + void reserve(SZ s, T const & d = T()) { if (s > size()) resize(s, d); } @@ -423,14 +423,14 @@ public: ptr_vector(unsigned s, T * const * data):vector(s, const_cast(data)) {} }; -template -class svector : public vector { +template +class svector : public vector { public: - svector():vector() {} - svector(unsigned s):vector(s) {} - svector(unsigned s, T const & elem):vector(s, elem) {} - svector(svector const & source):vector(source) {} - svector(unsigned s, T const * data):vector(s, data) {} + svector():vector() {} + svector(SZ s):vector(s) {} + svector(SZ s, T const & elem):vector(s, elem) {} + svector(svector const & source):vector(source) {} + svector(SZ s, T const * data):vector(s, data) {} }; typedef svector int_vector; From d686448356961b4f03b3191f74b8d852cf312baf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Sep 2013 21:52:01 -0700 Subject: [PATCH 263/281] local changes Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index a6bd7f7f8..f2c50487f 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -719,7 +719,7 @@ namespace datalog { T& operator*() { return *m_t; } const T& operator*() const { return *m_t; } operator bool() const { return m_t!=0; } - T* get() { return m_t; } + T* get() const { return m_t; } /** \brief Remove object from \c scoped_rel without deleting it. */ From 716663b04a894ec7ae6453476491aaf62e6bd66c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Sep 2013 05:52:18 -0700 Subject: [PATCH 264/281] avoid creating full tables when negated variables are unitary, add lazy table infrastructure, fix coi_filter for relations, reduce dependencies on fixedpoing_parameters.hpp header file Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 36 +- src/muz/base/dl_context.h | 48 +- src/muz/base/dl_util.cpp | 23 + src/muz/base/dl_util.h | 32 +- src/muz/bmc/dl_bmc_engine.cpp | 1 + src/muz/fp/datalog_parser.cpp | 2 +- src/muz/fp/dl_cmds.cpp | 1 + src/muz/fp/horn_tactic.cpp | 1 + src/muz/pdr/pdr_context.cpp | 6 +- src/muz/pdr/pdr_context.h | 1 + src/muz/pdr/pdr_manager.cpp | 5 +- src/muz/pdr/pdr_manager.h | 5 +- src/muz/pdr/pdr_prop_solver.cpp | 5 +- src/muz/pdr/pdr_prop_solver.h | 4 +- src/muz/pdr/pdr_reachable_cache.cpp | 4 +- src/muz/pdr/pdr_reachable_cache.h | 2 +- src/muz/pdr/pdr_smt_context_manager.cpp | 4 +- src/muz/pdr/pdr_smt_context_manager.h | 2 +- src/muz/pdr/pdr_util.cpp | 1 - src/muz/rel/dl_base.h | 44 ++ src/muz/rel/dl_compiler.cpp | 16 +- src/muz/rel/dl_lazy_table.cpp | 468 ++++++++++++++++++ src/muz/rel/dl_lazy_table.h | 305 ++++++++++++ src/muz/rel/dl_relation_manager.cpp | 23 +- src/muz/rel/dl_relation_manager.h | 13 + src/muz/rel/dl_sparse_table.cpp | 221 +++++++-- src/muz/rel/dl_sparse_table.h | 15 + src/muz/rel/dl_table_relation.cpp | 10 +- src/muz/rel/rel_context.cpp | 18 +- src/muz/tab/tab_context.cpp | 1 + src/muz/transforms/dl_mk_bit_blast.cpp | 1 + src/muz/transforms/dl_mk_coi_filter.cpp | 17 +- src/muz/transforms/dl_mk_karr_invariants.cpp | 1 + src/muz/transforms/dl_mk_magic_symbolic.cpp | 1 + .../dl_mk_quantifier_abstraction.cpp | 2 + .../dl_mk_quantifier_instantiation.cpp | 2 + src/muz/transforms/dl_mk_rule_inliner.cpp | 1 + src/muz/transforms/dl_mk_scale.cpp | 1 + src/muz/transforms/dl_transforms.cpp | 1 + src/shell/datalog_frontend.cpp | 3 +- 40 files changed, 1221 insertions(+), 126 deletions(-) create mode 100644 src/muz/rel/dl_lazy_table.cpp create mode 100644 src/muz/rel/dl_lazy_table.h diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 11cb48490..3a62a9b98 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -27,6 +27,7 @@ Revision History: #include"ast_smt2_pp.h" #include"datatype_decl_plugin.h" #include"scoped_proof.h" +#include"fixedpoint_params.hpp" namespace datalog { @@ -199,7 +200,7 @@ namespace datalog { m_register_engine(re), m_fparams(fp), m_params_ref(pa), - m_params(m_params_ref), + m_params(alloc(fixedpoint_params, m_params_ref)), m_decl_util(m), m_rewriter(m), m_var_subst(m), @@ -263,6 +264,31 @@ namespace datalog { return *m_sorts.find(s); } + + bool context::generate_proof_trace() const { return m_params->generate_proof_trace(); } + bool context::output_profile() const { return m_params->output_profile(); } + bool context::output_tuples() const { return m_params->output_tuples(); } + bool context::use_map_names() const { return m_params->use_map_names(); } + bool context::fix_unbound_vars() const { return m_params->fix_unbound_vars(); } + symbol context::default_table() const { return m_params->default_table(); } + symbol context::default_relation() const { return m_params->default_relation(); } // external_relation_plugin::get_name()); + symbol context::default_table_checker() const { return m_params->default_table_checker(); } + bool context::default_table_checked() const { return m_params->default_table_checked(); } + bool context::dbg_fpr_nonempty_relation_signature() const { return m_params->dbg_fpr_nonempty_relation_signature(); } + unsigned context::dl_profile_milliseconds_threshold() const { return m_params->profile_timeout_milliseconds(); } + bool context::all_or_nothing_deltas() const { return m_params->all_or_nothing_deltas(); } + bool context::compile_with_widening() const { return m_params->compile_with_widening(); } + bool context::unbound_compressor() const { return m_params->unbound_compressor(); } + bool context::similarity_compressor() const { return m_params->similarity_compressor(); } + unsigned context::similarity_compressor_threshold() const { return m_params->similarity_compressor_threshold(); } + unsigned context::soft_timeout() const { return m_fparams.m_soft_timeout; } + unsigned context::initial_restart_timeout() const { return m_params->initial_restart_timeout(); } + bool context::generate_explanations() const { return m_params->generate_explanations(); } + bool context::explanations_on_relation_level() const { return m_params->explanations_on_relation_level(); } + bool context::magic_sets_for_queries() const { return m_params->magic_sets_for_queries(); } + bool context::eager_emptiness_checking() const { return m_params->eager_emptiness_checking(); } + + void context::register_finite_sort(sort * s, sort_kind k) { m_pinned.push_back(s); SASSERT(!m_sorts.contains(s)); @@ -861,7 +887,7 @@ namespace datalog { }; void context::configure_engine() { - symbol e = m_params.engine(); + symbol e = m_params->engine(); if (e == symbol("datalog")) { m_engine_type = DATALOG_ENGINE; @@ -1082,9 +1108,9 @@ namespace datalog { expr_ref fml(m); expr_ref_vector rules(m); svector names; - bool use_fixedpoint_extensions = m_params.print_with_fixedpoint_extensions(); - bool print_low_level = m_params.print_low_level_smt2(); - bool do_declare_vars = m_params.print_with_variable_declarations(); + bool use_fixedpoint_extensions = m_params->print_with_fixedpoint_extensions(); + bool print_low_level = m_params->print_low_level_smt2(); + bool do_declare_vars = m_params->print_with_variable_declarations(); #define PP(_e_) if (print_low_level) out << mk_smt_pp(_e_, m); else ast_smt2_pp(out, _e_, env); diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 97a371f5a..2eb9e0652 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -43,6 +43,8 @@ Revision History: #include"expr_functors.h" #include"dl_engine_base.h" +struct fixedpoint_params; + namespace datalog { enum execution_result { @@ -168,7 +170,7 @@ namespace datalog { register_engine_base& m_register_engine; smt_params & m_fparams; params_ref m_params_ref; - fixedpoint_params m_params; + fixedpoint_params* m_params; dl_decl_util m_decl_util; th_rewriter m_rewriter; var_subst m_var_subst; @@ -231,33 +233,35 @@ namespace datalog { ast_manager & get_manager() const { return m; } rule_manager & get_rule_manager() { return m_rule_manager; } smt_params & get_fparams() const { return m_fparams; } - fixedpoint_params const& get_params() const { return m_params; } + fixedpoint_params const& get_params() const { return *m_params; } DL_ENGINE get_engine() { configure_engine(); return m_engine_type; } register_engine_base& get_register_engine() { return m_register_engine; } th_rewriter& get_rewriter() { return m_rewriter; } var_subst & get_var_subst() { return m_var_subst; } dl_decl_util & get_decl_util() { return m_decl_util; } - bool generate_proof_trace() const { return m_params.generate_proof_trace(); } - bool output_profile() const { return m_params.output_profile(); } - bool fix_unbound_vars() const { return m_params.fix_unbound_vars(); } - symbol default_table() const { return m_params.default_table(); } - symbol default_relation() const { return m_params.default_relation(); } // external_relation_plugin::get_name()); - symbol default_table_checker() const { return m_params.default_table_checker(); } - bool default_table_checked() const { return m_params.default_table_checked(); } - bool dbg_fpr_nonempty_relation_signature() const { return m_params.dbg_fpr_nonempty_relation_signature(); } - unsigned dl_profile_milliseconds_threshold() const { return m_params.profile_timeout_milliseconds(); } - bool all_or_nothing_deltas() const { return m_params.all_or_nothing_deltas(); } - bool compile_with_widening() const { return m_params.compile_with_widening(); } - bool unbound_compressor() const { return m_params.unbound_compressor(); } - bool similarity_compressor() const { return m_params.similarity_compressor(); } - unsigned similarity_compressor_threshold() const { return m_params.similarity_compressor_threshold(); } - unsigned soft_timeout() const { return m_fparams.m_soft_timeout; } - unsigned initial_restart_timeout() const { return m_params.initial_restart_timeout(); } - bool generate_explanations() const { return m_params.generate_explanations(); } - bool explanations_on_relation_level() const { return m_params.explanations_on_relation_level(); } - bool magic_sets_for_queries() const { return m_params.magic_sets_for_queries(); } - bool eager_emptiness_checking() const { return m_params.eager_emptiness_checking(); } + bool generate_proof_trace() const; + bool output_profile() const; + bool output_tuples() const; + bool use_map_names() const; + bool fix_unbound_vars() const; + symbol default_table() const; + symbol default_relation() const; + symbol default_table_checker() const; + bool default_table_checked() const; + bool dbg_fpr_nonempty_relation_signature() const; + unsigned dl_profile_milliseconds_threshold() const; + bool all_or_nothing_deltas() const; + bool compile_with_widening() const; + bool unbound_compressor() const; + bool similarity_compressor() const; + unsigned similarity_compressor_threshold() const; + unsigned soft_timeout() const; + unsigned initial_restart_timeout() const; + bool generate_explanations() const; + bool explanations_on_relation_level() const; + bool magic_sets_for_queries() const; + bool eager_emptiness_checking() const; void register_finite_sort(sort * s, sort_kind k); diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index 2f9eb519c..c23f222e5 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -30,9 +30,32 @@ Revision History: #include"dl_context.h" #include"dl_rule.h" #include"dl_util.h" +#include"stopwatch.h" namespace datalog { + static unsigned verbose_action_inside = 0; + + verbose_action::verbose_action(char const* msg, unsigned lvl): m_lvl(lvl), m_sw(0) { + IF_VERBOSE(m_lvl, + (verbose_stream() << msg << "...").flush(); + m_sw = alloc(stopwatch); + m_sw->start();); + } + + verbose_action::~verbose_action() { + double sec = 0.0; + if (m_sw) m_sw->stop(); + sec = m_sw?m_sw->get_seconds():0.0; + if (sec < 0.001) sec = 0.0; + IF_VERBOSE(m_lvl, + (verbose_stream() << sec << "s\n").flush(); + ); + dealloc(m_sw); + } + + + bool contains_var(expr * trm, unsigned var_idx) { ptr_vector vars; diff --git a/src/muz/base/dl_util.h b/src/muz/base/dl_util.h index f2c50487f..e13e7b53a 100644 --- a/src/muz/base/dl_util.h +++ b/src/muz/base/dl_util.h @@ -26,7 +26,6 @@ Revision History: #include"horn_subsume_model_converter.h" #include"replace_proof_converter.h" #include"substitution.h" -#include"fixedpoint_params.hpp" #include"ast_counter.h" #include"statistics.h" #include"lbool.h" @@ -43,6 +42,14 @@ namespace datalog { class relation_fact; class relation_signature; + class verbose_action { + unsigned m_lvl; + class stopwatch* m_sw; + public: + verbose_action(char const* msg, unsigned lvl = 1); + ~verbose_action(); + }; + enum PDR_CACHE_MODE { NO_CACHE, HASH_CACHE, @@ -706,29 +713,6 @@ namespace datalog { dealloc(ptr); } - template - class scoped_rel { - T* m_t; - public: - scoped_rel(T* t) : m_t(t) {} - ~scoped_rel() { if (m_t) { universal_delete(m_t); } } - scoped_rel() : m_t(0) {} - scoped_rel& operator=(T* t) { if (m_t) { universal_delete(m_t); } m_t = t; return *this; } - T* operator->() { return m_t; } - const T* operator->() const { return m_t; } - T& operator*() { return *m_t; } - const T& operator*() const { return *m_t; } - operator bool() const { return m_t!=0; } - T* get() const { return m_t; } - /** - \brief Remove object from \c scoped_rel without deleting it. - */ - T* release() { - T* res = m_t; - m_t = 0; - return res; - } - }; /** \brief If it is possible to convert the beginning of \c s to uint64, diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 60d285a55..eb4bc72c4 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -32,6 +32,7 @@ Revision History: #include "dl_transforms.h" #include "dl_mk_rule_inliner.h" #include "scoped_proof.h" +#include"fixedpoint_params.hpp" namespace datalog { diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index 545f3e14a..830f6d078 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -1164,7 +1164,7 @@ public: : dparser(ctx, ctx.get_manager()), m_bool_sort(ctx.get_manager()), m_short_sort(ctx.get_manager()), - m_use_map_names(ctx.get_params().use_map_names()) { + m_use_map_names(ctx.use_map_names()) { } ~wpa_parser_impl() { reset_dealloc_values(m_sort_contents); diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 7f73b0895..35af38630 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -30,6 +30,7 @@ Notes: #include"scoped_ctrl_c.h" #include"scoped_timer.h" #include"trail.h" +#include"fixedpoint_params.hpp" #include diff --git a/src/muz/fp/horn_tactic.cpp b/src/muz/fp/horn_tactic.cpp index ca6cbc2fb..0c094c277 100644 --- a/src/muz/fp/horn_tactic.cpp +++ b/src/muz/fp/horn_tactic.cpp @@ -27,6 +27,7 @@ Revision History: #include"dl_mk_slice.h" #include"filter_model_converter.h" #include"dl_transforms.h" +#include"fixedpoint_params.hpp" class horn_tactic : public tactic { struct imp { diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index f3e253071..aab7b1388 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -77,9 +77,9 @@ namespace pdr { pred_transformer::pred_transformer(context& ctx, manager& pm, func_decl* head): pm(pm), m(pm.get_manager()), ctx(ctx), m_head(head, m), - m_sig(m), m_solver(pm, head->get_name()), + m_sig(m), m_solver(pm, ctx.get_params(), head->get_name()), m_invariants(m), m_transition(m), m_initial_state(m), - m_reachable(pm, pm.get_params()) {} + m_reachable(pm, (datalog::PDR_CACHE_MODE)ctx.get_params().cache_mode()) {} pred_transformer::~pred_transformer() { rule2inst::iterator it2 = m_rule2inst.begin(), end2 = m_rule2inst.end(); @@ -1239,7 +1239,7 @@ namespace pdr { m_params(params), m(m), m_context(0), - m_pm(m_fparams, params, m), + m_pm(m_fparams, params.max_num_contexts(), m), m_query_pred(m), m_query(0), m_search(m_params.bfs_model_search()), diff --git a/src/muz/pdr/pdr_context.h b/src/muz/pdr/pdr_context.h index 57238abb3..8a4f3e438 100644 --- a/src/muz/pdr/pdr_context.h +++ b/src/muz/pdr/pdr_context.h @@ -28,6 +28,7 @@ Revision History: #include "pdr_manager.h" #include "pdr_prop_solver.h" #include "pdr_reachable_cache.h" +#include "fixedpoint_params.hpp" namespace datalog { diff --git a/src/muz/pdr/pdr_manager.cpp b/src/muz/pdr/pdr_manager.cpp index 9eb10aba9..bda54dbd7 100644 --- a/src/muz/pdr/pdr_manager.cpp +++ b/src/muz/pdr/pdr_manager.cpp @@ -166,14 +166,13 @@ namespace pdr { return res; } - manager::manager(smt_params& fparams, fixedpoint_params const& params, ast_manager& manager) : + manager::manager(smt_params& fparams, unsigned max_num_contexts, ast_manager& manager) : m(manager), m_fparams(fparams), - m_params(params), m_brwr(m), m_mux(m, get_state_suffixes()), m_background(m.mk_true(), m), - m_contexts(fparams, params, m), + m_contexts(fparams, max_num_contexts, m), m_next_unique_num(0) { } diff --git a/src/muz/pdr/pdr_manager.h b/src/muz/pdr/pdr_manager.h index cb2c9b253..0e8e890e8 100644 --- a/src/muz/pdr/pdr_manager.h +++ b/src/muz/pdr/pdr_manager.h @@ -78,7 +78,6 @@ namespace pdr { { ast_manager& m; smt_params& m_fparams; - fixedpoint_params const& m_params; mutable bool_rewriter m_brwr; @@ -99,12 +98,10 @@ namespace pdr { void add_new_state(func_decl * s); public: - manager(smt_params& fparams, fixedpoint_params const& params, - ast_manager & manager); + manager(smt_params& fparams, unsigned max_num_contexts, ast_manager & manager); ast_manager& get_manager() const { return m; } smt_params& get_fparams() const { return m_fparams; } - fixedpoint_params const& get_params() const { return m_params; } bool_rewriter& get_brwr() const { return m_brwr; } expr_ref mk_and(unsigned sz, expr* const* exprs); diff --git a/src/muz/pdr/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp index d9b22e04e..8fe8c0e0e 100644 --- a/src/muz/pdr/pdr_prop_solver.cpp +++ b/src/muz/pdr/pdr_prop_solver.cpp @@ -30,6 +30,7 @@ Revision History: #include "pdr_farkas_learner.h" #include "ast_smt2_pp.h" #include "expr_replacer.h" +#include "fixedpoint_params.hpp" // // Auxiliary structure to introduce propositional names for assumptions that are not @@ -225,12 +226,12 @@ namespace pdr { }; - prop_solver::prop_solver(manager& pm, symbol const& name) : + prop_solver::prop_solver(manager& pm, fixedpoint_params const& p, symbol const& name) : m_fparams(pm.get_fparams()), m(pm.get_manager()), m_pm(pm), m_name(name), - m_try_minimize_core(pm.get_params().try_minimize_core()), + m_try_minimize_core(p.try_minimize_core()), m_ctx(pm.mk_fresh()), m_pos_level_atoms(m), m_neg_level_atoms(m), diff --git a/src/muz/pdr/pdr_prop_solver.h b/src/muz/pdr/pdr_prop_solver.h index 0c60a7124..a63ec2bf4 100644 --- a/src/muz/pdr/pdr_prop_solver.h +++ b/src/muz/pdr/pdr_prop_solver.h @@ -31,6 +31,8 @@ Revision History: #include "pdr_manager.h" #include "pdr_smt_context_manager.h" +struct fixedpoint_params; + namespace pdr { class prop_solver { @@ -73,7 +75,7 @@ namespace pdr { public: - prop_solver(pdr::manager& pm, symbol const& name); + prop_solver(pdr::manager& pm, fixedpoint_params const& p, symbol const& name); /** return true is s is a symbol introduced by prop_solver */ bool is_aux_symbol(func_decl * s) const { diff --git a/src/muz/pdr/pdr_reachable_cache.cpp b/src/muz/pdr/pdr_reachable_cache.cpp index 4f4f620de..85100c19f 100644 --- a/src/muz/pdr/pdr_reachable_cache.cpp +++ b/src/muz/pdr/pdr_reachable_cache.cpp @@ -21,13 +21,13 @@ Revision History: namespace pdr { - reachable_cache::reachable_cache(pdr::manager & pm, fixedpoint_params const& params) + reachable_cache::reachable_cache(pdr::manager & pm, datalog::PDR_CACHE_MODE cm) : m(pm.get_manager()), m_pm(pm), m_ctx(0), m_ref_holder(m), m_disj_connector(m), - m_cache_mode((datalog::PDR_CACHE_MODE)params.cache_mode()) { + m_cache_mode(cm) { if (m_cache_mode == datalog::CONSTRAINT_CACHE) { m_ctx = pm.mk_fresh(); m_ctx->assert_expr(m_pm.get_background()); diff --git a/src/muz/pdr/pdr_reachable_cache.h b/src/muz/pdr/pdr_reachable_cache.h index 48caa22a5..aef6f7a4f 100644 --- a/src/muz/pdr/pdr_reachable_cache.h +++ b/src/muz/pdr/pdr_reachable_cache.h @@ -47,7 +47,7 @@ namespace pdr { void add_disjuncted_formula(expr * f); public: - reachable_cache(pdr::manager & pm, fixedpoint_params const& params); + reachable_cache(pdr::manager & pm, datalog::PDR_CACHE_MODE cm); void add_init(app * f) { add_disjuncted_formula(f); } diff --git a/src/muz/pdr/pdr_smt_context_manager.cpp b/src/muz/pdr/pdr_smt_context_manager.cpp index 49ae35423..b6aa8411d 100644 --- a/src/muz/pdr/pdr_smt_context_manager.cpp +++ b/src/muz/pdr/pdr_smt_context_manager.cpp @@ -113,10 +113,10 @@ namespace pdr { return m_context.get_proof(); } - smt_context_manager::smt_context_manager(smt_params& fp, fixedpoint_params const& p, ast_manager& m): + smt_context_manager::smt_context_manager(smt_params& fp, unsigned max_num_contexts, ast_manager& m): m_fparams(fp), m(m), - m_max_num_contexts(p.max_num_contexts()), + m_max_num_contexts(max_num_contexts), m_num_contexts(0), m_predicate_list(m) { } diff --git a/src/muz/pdr/pdr_smt_context_manager.h b/src/muz/pdr/pdr_smt_context_manager.h index 7d6eebfbd..4775dc58f 100644 --- a/src/muz/pdr/pdr_smt_context_manager.h +++ b/src/muz/pdr/pdr_smt_context_manager.h @@ -97,7 +97,7 @@ namespace pdr { app_ref_vector m_predicate_list; func_decl_set m_predicate_set; public: - smt_context_manager(smt_params& fp, fixedpoint_params const& p, ast_manager& m); + smt_context_manager(smt_params& fp, unsigned max_num_contexts, ast_manager& m); ~smt_context_manager(); smt_context* mk_fresh(); void collect_statistics(statistics& st) const; diff --git a/src/muz/pdr/pdr_util.cpp b/src/muz/pdr/pdr_util.cpp index 4db835bed..d021d5fb1 100644 --- a/src/muz/pdr/pdr_util.cpp +++ b/src/muz/pdr/pdr_util.cpp @@ -37,7 +37,6 @@ Notes: #include "rewriter_def.h" #include "util.h" #include "pdr_manager.h" -#include "pdr_prop_solver.h" #include "pdr_util.h" #include "arith_decl_plugin.h" #include "expr_replacer.h" diff --git a/src/muz/rel/dl_base.h b/src/muz/rel/dl_base.h index 1556660d8..d03c94154 100644 --- a/src/muz/rel/dl_base.h +++ b/src/muz/rel/dl_base.h @@ -35,6 +35,30 @@ namespace datalog { class context; class relation_manager; + template + class scoped_rel { + T* m_t; + public: + scoped_rel(T* t) : m_t(t) {} + ~scoped_rel() { if (m_t) { universal_delete(m_t); } } + scoped_rel() : m_t(0) {} + scoped_rel& operator=(T* t) { if (m_t && t != m_t) { universal_delete(m_t); } m_t = t; return *this; } + T* operator->() { return m_t; } + const T* operator->() const { return m_t; } + T& operator*() { return *m_t; } + const T& operator*() const { return *m_t; } + operator bool() const { return m_t!=0; } + T* get() const { return m_t; } + /** + \brief Remove object from \c scoped_rel without deleting it. + */ + T* release() { + T* res = m_t; + m_t = 0; + return res; + } + }; + ast_manager & get_ast_manager_from_rel_manager(const relation_manager & rm); context & get_context_from_rel_manager(const relation_manager & rm); @@ -208,6 +232,11 @@ namespace datalog { virtual void operator()(base_object & t, const base_object & intersected_obj) = 0; }; + class intersection_join_filter_fn : public base_fn { + public: + virtual void operator()(base_object & t, const base_object & inter1, const base_object& inter2) = 0; + }; + class default_join_project_fn; /** @@ -303,6 +332,7 @@ namespace datalog { protected: //see \c relation_manager for documentation of the operations + virtual join_fn * mk_join_fn(const base_object & t1, const base_object & t2, unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { return 0; } @@ -348,10 +378,22 @@ namespace datalog { const unsigned * t_cols, const unsigned * src_cols) { return 0; } + virtual intersection_filter_fn * mk_filter_by_negation_fn(const base_object & t, const base_object & negated_obj, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) { return 0; } + + virtual intersection_join_filter_fn * mk_filter_by_negated_join_fn( + const base_object & t, + const base_object & src1, + const base_object & src2, + unsigned_vector const& t_cols, + unsigned_vector const& src_cols, + unsigned_vector const& src1_cols, + unsigned_vector const& src2_cols) + { return 0; } + }; class base_ancestor { @@ -685,6 +727,7 @@ namespace datalog { typedef relation_infrastructure::union_fn relation_union_fn; typedef relation_infrastructure::mutator_fn relation_mutator_fn; typedef relation_infrastructure::intersection_filter_fn relation_intersection_filter_fn; + typedef relation_infrastructure::intersection_join_filter_fn relation_intersection_join_filter_fn; typedef relation_infrastructure::convenient_join_fn convenient_relation_join_fn; typedef relation_infrastructure::convenient_join_project_fn convenient_relation_join_project_fn; @@ -807,6 +850,7 @@ namespace datalog { typedef table_infrastructure::union_fn table_union_fn; typedef table_infrastructure::mutator_fn table_mutator_fn; typedef table_infrastructure::intersection_filter_fn table_intersection_filter_fn; + typedef table_infrastructure::intersection_join_filter_fn table_intersection_join_filter_fn; typedef table_infrastructure::convenient_join_fn convenient_table_join_fn; typedef table_infrastructure::convenient_join_project_fn convenient_table_join_project_fn; diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 931846c35..1886563c2 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -869,6 +869,7 @@ namespace datalog { bool & dealloc, instruction_block & acc) { uint_set pos_vars; u_map neg_vars; + u_map occs; ast_manager& m = m_context.get_manager(); unsigned pt_len = r->get_positive_tail_size(); unsigned ut_len = r->get_uninterpreted_tail_size(); @@ -882,7 +883,14 @@ namespace datalog { for (unsigned j = 0; j < neg_len; ++j) { expr * e = neg_tail->get_arg(j); if (is_var(e)) { - neg_vars.insert(to_var(e)->get_idx(), e); + unsigned idx = to_var(e)->get_idx(); + neg_vars.insert(idx, e); + if (!occs.contains(idx)) { + occs.insert(idx, 1); + } + else { + occs.find(idx)++; + } } } } @@ -893,11 +901,15 @@ namespace datalog { pos_vars.insert(to_var(e)->get_idx()); } } - // add negative variables that are not in positive: + // add negative variables that are not in positive, but only + // for variables that occur more than once. u_map::iterator it = neg_vars.begin(), end = neg_vars.end(); for (; it != end; ++it) { unsigned v = it->m_key; expr* e = it->m_value; + if (occs.find(v) == 1) { + continue; + } if (!pos_vars.contains(v)) { single_res_expr.push_back(e); reg_idx new_single_res; diff --git a/src/muz/rel/dl_lazy_table.cpp b/src/muz/rel/dl_lazy_table.cpp new file mode 100644 index 000000000..16dbc2d21 --- /dev/null +++ b/src/muz/rel/dl_lazy_table.cpp @@ -0,0 +1,468 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_lazy_table.cpp + +Abstract: + + + +Author: + + Nikolaj Bjorner (nbjorner) 2013-09-04 + +Revision History: + +--*/ + +#include "dl_lazy_table.h" +#include "dl_relation_manager.h" +#include + +namespace datalog { + + // ------------------ + // lazy_table_plugin: + + symbol lazy_table_plugin::mk_name(table_plugin& p) { + std::ostringstream strm; + strm << "lazy_" << p.get_name(); + return symbol(strm.str().c_str()); + } + + table_base * lazy_table_plugin::mk_empty(const table_signature & s) { + return alloc(lazy_table, alloc(lazy_table_base, *this, m_plugin.mk_empty(s))); + } + + lazy_table const& lazy_table_plugin::get(table_base const& tb) { return dynamic_cast(tb); } + lazy_table& lazy_table_plugin::get(table_base& tb) { return dynamic_cast(tb); } + lazy_table const* lazy_table_plugin::get(table_base const* tb) { return dynamic_cast(tb); } + lazy_table* lazy_table_plugin::get(table_base* tb) { return dynamic_cast(tb); } + + // -------------------------- + // lazy_table_plugin::join_fn + + class lazy_table_plugin::join_fn : public convenient_table_join_fn { + public: + join_fn(table_signature const& s1, table_signature const& s2, unsigned col_cnt, + unsigned const* cols1, unsigned const* cols2): + convenient_table_join_fn(s1, s2, col_cnt, cols1, cols2) {} + + virtual table_base* operator()(const table_base& _t1, const table_base& _t2) { + lazy_table const& t1 = get(_t1); + lazy_table const& t2 = get(_t2); + lazy_table_plugin& p = t1.get_lplugin(); + lazy_table_ref* tr = alloc(lazy_table_join, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr(), t1, t2, get_result_signature()); + return alloc(lazy_table, tr); + } + }; + + table_join_fn * lazy_table_plugin::mk_join_fn( + const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { + if (check_kind(t1) && check_kind(t2)) { + return alloc(join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2); + } + else { + return 0; + } + } + + // ------------------------ + // lazy_table_plugin::union + + class lazy_table_plugin::union_fn : public table_union_fn { + public: + void operator()(table_base & _tgt, const table_base & _src, + table_base * _delta) { + lazy_table& tgt = get(_tgt); + lazy_table const& src = get(_src); + lazy_table* delta = get(_delta); + table_base const* t_src = src.eval(); + table_base * t_tgt = tgt.eval(); + table_base * t_delta = delta?delta->eval():0; + verbose_action _t("union"); + table_union_fn* m = tgt.get_lplugin().get_manager().mk_union_fn(*t_tgt, *t_src, t_delta); + SASSERT(m); + (*m)(*t_tgt, *t_src, t_delta); + dealloc(m); + } + }; + + + table_union_fn* lazy_table_plugin::mk_union_fn( + const table_base & tgt, const table_base & src, + const table_base * delta) { + if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) { + return alloc(union_fn); + } + else { + return 0; + } + } + + // -------------------------- + // lazy_table_plugin::project + + class lazy_table_plugin::project_fn : public convenient_table_project_fn { + public: + project_fn(table_signature const& orig_sig, unsigned cnt, unsigned const* cols): + convenient_table_project_fn(orig_sig, cnt, cols) + {} + + virtual table_base* operator()(table_base const& _t) { + lazy_table const& t = get(_t); + return alloc(lazy_table, alloc(lazy_table_project, m_removed_cols.size(), m_removed_cols.c_ptr(), t, get_result_signature())); + } + }; + + table_transformer_fn * lazy_table_plugin::mk_project_fn( + const table_base & t, unsigned col_cnt, + const unsigned * removed_cols) { + if (check_kind(t)) { + return alloc(project_fn, t.get_signature(), col_cnt, removed_cols); + } + else { + return 0; + } + } + + // ------------------------- + // lazy_table_plugin::rename + + class lazy_table_plugin::rename_fn : public convenient_table_rename_fn { + public: + rename_fn(table_signature const& orig_sig, unsigned cnt, unsigned const* cols): + convenient_table_rename_fn(orig_sig, cnt, cols) + {} + + virtual table_base* operator()(table_base const& _t) { + lazy_table const& t = get(_t); + return alloc(lazy_table, alloc(lazy_table_rename, m_cycle.size(), m_cycle.c_ptr(), t, get_result_signature())); + } + }; + + table_transformer_fn * lazy_table_plugin::mk_rename_fn( + const table_base & t, unsigned col_cnt, + const unsigned * removed_cols) { + if (check_kind(t)) { + return alloc(rename_fn, t.get_signature(), col_cnt, removed_cols); + } + else { + return 0; + } + } + + + // ----------------------------------- + // lazy_table_plugin::filter_identical + + class lazy_table_plugin::filter_identical_fn : public table_mutator_fn { + unsigned_vector m_cols; + public: + filter_identical_fn(unsigned cnt, unsigned const* cols): m_cols(cnt, cols) {} + + virtual void operator()(table_base& _t) { + lazy_table& t = get(_t); + t.set(alloc(lazy_table_filter_identical, m_cols.size(), m_cols.c_ptr(), t)); + } + }; + + table_mutator_fn * lazy_table_plugin::mk_filter_identical_fn( + const table_base & t, unsigned col_cnt, const unsigned * identical_cols) { + if (check_kind(t)) { + return alloc(filter_identical_fn, col_cnt, identical_cols); + } + else { + return 0; + } + } + + + // ------------------------------------- + // lazy_table_plugin::filter_interpreted + + class lazy_table_plugin::filter_interpreted_fn : public table_mutator_fn { + app_ref m_condition; + public: + filter_interpreted_fn(app_ref& p): m_condition(p) {} + + virtual void operator()(table_base& _t) { + lazy_table& t = get(_t); + t.set(alloc(lazy_table_filter_interpreted, t, m_condition)); + } + }; + + table_mutator_fn * lazy_table_plugin::mk_filter_interpreted_fn( + const table_base & t, app* condition) { + if (check_kind(t)) { + app_ref cond(condition, get_ast_manager()); + return alloc(filter_interpreted_fn, cond); + } + else { + return 0; + } + } + + // ------------------------------------- + // lazy_table_plugin::filter_by_negation + + class lazy_table_plugin::filter_by_negation_fn : public table_intersection_filter_fn { + unsigned_vector m_cols1; + unsigned_vector m_cols2; + public: + filter_by_negation_fn(unsigned cnt, unsigned const* cols1, unsigned const* cols2): + m_cols1(cnt, cols1), m_cols2(cnt, cols2) {} + virtual void operator()(table_base & _t, const table_base & _intersected_obj) { + lazy_table& t = get(_t); + lazy_table const& it = get(_intersected_obj); + t.set(alloc(lazy_table_filter_by_negation, t, it, m_cols1, m_cols2)); + } + }; + + table_intersection_filter_fn * lazy_table_plugin::mk_filter_by_negation_fn( + const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols) { + if (check_kind(t) && check_kind(negated_obj)) { + return alloc(filter_by_negation_fn, joined_col_cnt, t_cols, negated_cols); + } + else { + return 0; + } + } + + + // ------------------------------- + // lazy_table_plugin::filter_equal + + class lazy_table_plugin::filter_equal_fn : public table_mutator_fn { + table_element m_value; + unsigned m_col; + public: + filter_equal_fn(const table_element & value, unsigned col): + m_value(value), + m_col(col) + { } + + virtual void operator()(table_base& _t) { + lazy_table& t = get(_t); + t.set(alloc(lazy_table_filter_equal, m_col, m_value, t)); + } + }; + + table_mutator_fn * lazy_table_plugin::mk_filter_equal_fn( + const table_base & t, const table_element & value, unsigned col) { + if (check_kind(t)) { + return alloc(filter_equal_fn, value, col); + } + else { + return 0; + } + } + + table_plugin* lazy_table_plugin::mk_sparse(relation_manager& rm) { + table_plugin* sp = rm.get_table_plugin(symbol("sparse")); + SASSERT(sp); + if (sp) { + return alloc(lazy_table_plugin, *sp); + } + else { + return 0; + } + } + + + // ---------- + // lazy_table + + table_base * lazy_table::clone() const { + table_base* t = eval(); + verbose_action _t("clone"); + return alloc(lazy_table, alloc(lazy_table_base, get_lplugin(), t->clone())); + } + table_base * lazy_table::complement(func_decl* p, const table_element * func_columns) const { + table_base* t = eval()->complement(p, func_columns); + return alloc(lazy_table, alloc(lazy_table_base, get_lplugin(), t)); + } + bool lazy_table::empty() const { + return m_ref->eval()->empty(); + } + bool lazy_table::contains_fact(const table_fact & f) const { + return m_ref->eval()->contains_fact(f); + } + void lazy_table::remove_fact(table_element const* fact) { + m_ref->eval()->remove_fact(fact); + } + void lazy_table::remove_facts(unsigned fact_cnt, const table_fact * facts) { + m_ref->eval()->remove_facts(fact_cnt, facts); + } + void lazy_table::remove_facts(unsigned fact_cnt, const table_element * facts) { + m_ref->eval()->remove_facts(fact_cnt, facts); + } + void lazy_table::reset() { + m_ref = alloc(lazy_table_base, get_lplugin(), get_lplugin().m_plugin.mk_empty(get_signature())); + } + void lazy_table::add_fact(table_fact const& f) { + m_ref->eval()->add_fact(f); + } + table_base::iterator lazy_table::begin() const { + return eval()->begin(); + } + table_base::iterator lazy_table::end() const { + return eval()->end(); + } + table_base* lazy_table::eval() const { + return m_ref->eval(); + } + + // ------------------------- + // eval + + + table_base* lazy_table_join::force() { + SASSERT(!m_table); + table_base* t1 = m_t1->eval(); + table_base* t2 = m_t2->eval(); + verbose_action _t("join"); + table_join_fn* join = rm().mk_join_fn(*t1, *t2, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr()); + m_table = (*join)(*t1, *t2); + dealloc(join); + return m_table.get(); + } + + table_base* lazy_table_project::force() { + SASSERT(!m_table); + switch(m_src->kind()) { + case LAZY_TABLE_JOIN: { + lazy_table_join& src = dynamic_cast(*m_src); + table_base* t1 = src.t1()->eval(); + table_base* t2 = src.t2()->eval(); + table_join_fn* j_fn = rm().mk_join_project_fn(*t1, *t2, src.cols1(), src.cols2(), m_cols); + if (j_fn) { + verbose_action _t("join_project"); + m_table = (*j_fn)(*t1, *t2); + dealloc(j_fn); + } + break; + } + case LAZY_TABLE_FILTER_INTERPRETED: { + lazy_table_filter_interpreted& src = dynamic_cast(*m_src); + table_transformer_fn* tr = rm().mk_filter_interpreted_and_project_fn(*src.eval(), src.condition(), m_cols.size(), m_cols.c_ptr()); + if (tr) { + verbose_action _t("filter_interpreted_project"); + m_table = (*tr)(*src.eval()); + dealloc(tr); + } + break; + } + case LAZY_TABLE_FILTER_EQUAL: { + lazy_table_filter_equal& src = dynamic_cast(*m_src); + table_base* t = src.eval(); + table_transformer_fn* tr = rm().mk_select_equal_and_project_fn(*t, src.value(), src.col()); + if (tr) { + verbose_action _t("select_equal_project"); + m_table = (*tr)(*t); + dealloc(tr); + } + break; + } + default: + break; + } + if (m_table) { + return m_table.get(); + } + table_base* src = m_src->eval(); + verbose_action _t("project"); + table_transformer_fn* project = rm().mk_project_fn(*src, m_cols.size(), m_cols.c_ptr()); + SASSERT(project); + m_table = (*project)(*src); + dealloc(project); + return m_table.get(); + } + + table_base* lazy_table_rename::force() { + SASSERT(!m_table); + table_base* src = m_src->eval(); + verbose_action _t("rename"); + table_transformer_fn* rename = rm().mk_rename_fn(*src, m_cols.size(), m_cols.c_ptr()); + m_table = (*rename)(*src); + dealloc(rename); + return m_table.get(); + } + + table_base* lazy_table_filter_identical::force() { + SASSERT(!m_table); + m_table = m_src->eval(); + m_src->release_table(); + m_src = 0; + verbose_action _t("filter_identical"); + table_mutator_fn* m = rm().mk_filter_identical_fn(*m_table, m_cols.size(), m_cols.c_ptr()); + SASSERT(m); + (*m)(*m_table); + dealloc(m); + return m_table.get(); + } + + table_base* lazy_table_filter_equal::force() { + SASSERT(!m_table); + m_table = m_src->eval(); + m_src->release_table(); + m_src = 0; + verbose_action _t("filter_equal"); + table_mutator_fn* m = rm().mk_filter_equal_fn(*m_table, m_value, m_col); + SASSERT(m); + (*m)(*m_table); + dealloc(m); + return m_table.get(); + } + + table_base* lazy_table_filter_interpreted::force() { + SASSERT(!m_table); + m_table = m_src->eval(); + m_src->release_table(); + m_src = 0; + verbose_action _t("filter_interpreted"); + table_mutator_fn* m = rm().mk_filter_interpreted_fn(*m_table, m_condition); + SASSERT(m); + (*m)(*m_table); + dealloc(m); + return m_table.get(); + } + + table_base* lazy_table_filter_by_negation::force() { + SASSERT(!m_table); + m_table = m_tgt->eval(); + m_tgt->release_table(); + m_tgt = 0; + + switch(m_src->kind()) { + + case LAZY_TABLE_JOIN: { + lazy_table_join& src = dynamic_cast(*m_src); + table_base* t1 = src.t1()->eval(); + table_base* t2 = src.t2()->eval(); + verbose_action _t("filter_by_negation_join"); + table_intersection_join_filter_fn* jn = rm().mk_filter_by_negated_join_fn(*m_table, *t1, *t2, cols1(), cols2(), src.cols1(), src.cols2()); + if (jn) { + (*jn)(*m_table, *t1, *t2); + dealloc(jn); + return m_table.get(); + } + break; + } + default: + break; + } + table_base* src = m_src->eval(); + verbose_action _t("filter_by_negation"); + table_intersection_filter_fn* m = rm().mk_filter_by_negation_fn(*m_table, *src, m_cols1, m_cols2); + SASSERT(m); + (*m)(*m_table, *src); + dealloc(m); + return m_table.get(); + } +} diff --git a/src/muz/rel/dl_lazy_table.h b/src/muz/rel/dl_lazy_table.h new file mode 100644 index 000000000..34a8b6b92 --- /dev/null +++ b/src/muz/rel/dl_lazy_table.h @@ -0,0 +1,305 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + dl_lazy_table.h + +Abstract: + + Structure for delaying table operations. + + +Author: + + Nikolaj Bjorner (nbjorner) 2013-09-04 + +Revision History: + +--*/ + +#ifndef _DL_LAZY_TABLE_H_ +#define _DL_LAZY_TABLE_H_ + +#include "dl_base.h" +#include "ref.h" + +namespace datalog { + + class lazy_table; + + class lazy_table_plugin : public table_plugin { + friend class lazy_table; + class join_fn; + class project_fn; + class union_fn; + class rename_fn; + class filter_equal_fn; + class filter_identical_fn; + class filter_interpreted_fn; + class filter_by_negation_fn; + + table_plugin& m_plugin; + + static symbol mk_name(table_plugin& p); + + public: + lazy_table_plugin(table_plugin& p): + table_plugin(mk_name(p), p.get_manager()), + m_plugin(p) {} + + virtual bool can_handle_signature(const table_signature & s) { + return m_plugin.can_handle_signature(s); + } + + virtual table_base * mk_empty(const table_signature & s); + + virtual void set_cancel(bool f) { m_plugin.set_cancel(f); } + + static table_plugin* mk_sparse(relation_manager& rm); + + protected: + virtual table_join_fn * mk_join_fn( + const table_base & t1, const table_base & t2, + unsigned col_cnt, const unsigned * cols1, const unsigned * cols2); + virtual table_union_fn * mk_union_fn( + const table_base & tgt, const table_base & src, + const table_base * delta); + virtual table_transformer_fn * mk_project_fn( + const table_base & t, unsigned col_cnt, + const unsigned * removed_cols); + virtual table_transformer_fn * mk_rename_fn( + const table_base & t, unsigned permutation_cycle_len, + const unsigned * permutation_cycle); + virtual table_mutator_fn * mk_filter_identical_fn( + const table_base & t, unsigned col_cnt, const unsigned * identical_cols); + virtual table_mutator_fn * mk_filter_equal_fn( + const table_base & t, const table_element & value, unsigned col); + virtual table_mutator_fn * mk_filter_interpreted_fn( + const table_base & t, app * condition); + virtual table_intersection_filter_fn * mk_filter_by_negation_fn( + const table_base & t, + const table_base & negated_obj, unsigned joined_col_cnt, + const unsigned * t_cols, const unsigned * negated_cols); + + static lazy_table const& get(table_base const& tb); + static lazy_table& get(table_base& tb); + static lazy_table const* get(table_base const* tb); + static lazy_table* get(table_base* tb); + }; + + enum lazy_table_kind { + LAZY_TABLE_BASE, + LAZY_TABLE_JOIN, + LAZY_TABLE_PROJECT, + LAZY_TABLE_RENAME, + LAZY_TABLE_FILTER_IDENTICAL, + LAZY_TABLE_FILTER_EQUAL, + LAZY_TABLE_FILTER_INTERPRETED, + LAZY_TABLE_FILTER_BY_NEGATION + }; + + class lazy_table_ref { + protected: + lazy_table_plugin& m_plugin; + table_signature m_signature; + unsigned m_ref; + scoped_rel m_table; + relation_manager& rm() { return m_plugin.get_manager(); } + virtual table_base* force() = 0; + public: + lazy_table_ref(lazy_table_plugin& p, table_signature const& sig): + m_plugin(p), m_signature(sig), m_ref(0) {} + virtual ~lazy_table_ref() {} + void inc_ref() { ++m_ref; } + void dec_ref() { --m_ref; if (0 == m_ref) dealloc(this); } + void release_table() { m_table.release(); } + + virtual lazy_table_kind kind() const = 0; + table_signature const& get_signature() const { return m_signature; } + lazy_table_plugin & get_lplugin() const { return m_plugin; } + table_base* eval() { if (!m_table) { m_table = force(); } SASSERT(m_table); return m_table.get(); } + }; + + class lazy_table : public table_base { + protected: + mutable ref m_ref; + + public: + lazy_table(lazy_table_ref* t): + table_base(t->get_lplugin(), t->get_signature()), + m_ref(t) + {} + + virtual ~lazy_table() {} + + lazy_table_plugin& get_lplugin() const { + return dynamic_cast(table_base::get_plugin()); + } + + virtual table_base * clone() const; + virtual table_base * complement(func_decl* p, const table_element * func_columns = 0) const; + virtual bool empty() const; + virtual bool contains_fact(const table_fact & f) const; + virtual void remove_fact(table_element const* fact); + virtual void remove_facts(unsigned fact_cnt, const table_fact * facts); + virtual void remove_facts(unsigned fact_cnt, const table_element * facts); + virtual void reset(); + virtual void add_fact(table_fact const& f); + + virtual unsigned get_size_estimate_rows() const { return 1; } + virtual unsigned get_size_estimate_bytes() const { return 1; } + virtual bool knows_exact_size() const { return false; } + + table_base* eval() const; + + virtual table_base::iterator begin() const; + virtual table_base::iterator end() const; + + lazy_table_ref* ref() const { return m_ref.get(); } + void set(lazy_table_ref* r) { m_ref = r; } + }; + + class lazy_table_base : public lazy_table_ref { + public: + lazy_table_base(lazy_table_plugin & p, table_base* table) + : lazy_table_ref(p, table->get_signature()) { + m_table = table; + // SASSERT(&p.m_plugin == &table->get_lplugin()); + } + virtual ~lazy_table_base() {} + virtual lazy_table_kind kind() const { return LAZY_TABLE_BASE; } + virtual table_base* force() { return m_table.get(); } + }; + + class lazy_table_join : public lazy_table_ref { + unsigned_vector m_cols1; + unsigned_vector m_cols2; + ref m_t1; + ref m_t2; + public: + lazy_table_join(unsigned col_cnt, + const unsigned * cols1, const unsigned * cols2, + lazy_table const& t1, lazy_table const& t2, table_signature const& sig) + : lazy_table_ref(t1.get_lplugin(), sig), + m_cols1(col_cnt, cols1), + m_cols2(col_cnt, cols2), + m_t1(t1.ref()), + m_t2(t2.ref()) { } + virtual ~lazy_table_join() {} + virtual lazy_table_kind kind() const { return LAZY_TABLE_JOIN; } + unsigned_vector const& cols1() const { return m_cols1; } + unsigned_vector const& cols2() const { return m_cols2; } + lazy_table_ref* t1() const { return m_t1.get(); } + lazy_table_ref* t2() const { return m_t2.get(); } + virtual table_base* force(); + }; + + + class lazy_table_project : public lazy_table_ref { + unsigned_vector m_cols; + ref m_src; + public: + lazy_table_project(unsigned col_cnt, const unsigned * cols, lazy_table const& src, table_signature const& sig) + : lazy_table_ref(src.get_lplugin(), sig), + m_cols(col_cnt, cols), + m_src(src.ref()) {} + virtual ~lazy_table_project() {} + + virtual lazy_table_kind kind() const { return LAZY_TABLE_PROJECT; } + unsigned_vector const& cols() const { return m_cols; } + lazy_table_ref* src() const { return m_src.get(); } + virtual table_base* force(); + }; + + class lazy_table_rename : public lazy_table_ref { + unsigned_vector m_cols; + ref m_src; + public: + lazy_table_rename(unsigned col_cnt, const unsigned * cols, lazy_table const& src, table_signature const& sig) + : lazy_table_ref(src.get_lplugin(), sig), + m_cols(col_cnt, cols), + m_src(src.ref()) {} + virtual ~lazy_table_rename() {} + + virtual lazy_table_kind kind() const { return LAZY_TABLE_RENAME; } + unsigned_vector const& cols() const { return m_cols; } + lazy_table_ref* src() const { return m_src.get(); } + virtual table_base* force(); + }; + + class lazy_table_filter_identical : public lazy_table_ref { + unsigned_vector m_cols; + ref m_src; + public: + lazy_table_filter_identical(unsigned col_cnt, const unsigned * cols, lazy_table const& src) + : lazy_table_ref(src.get_lplugin(), src.get_signature()), m_cols(col_cnt, cols), m_src(src.ref()) {} + virtual ~lazy_table_filter_identical() {} + + virtual lazy_table_kind kind() const { return LAZY_TABLE_FILTER_IDENTICAL; } + unsigned_vector const& cols() const { return m_cols; } + lazy_table_ref* src() const { return m_src.get(); } + virtual table_base* force(); + }; + + class lazy_table_filter_equal : public lazy_table_ref { + unsigned m_col; + table_element m_value; + ref m_src; + public: + lazy_table_filter_equal(unsigned col, table_element value, lazy_table const& src) + : lazy_table_ref(src.get_lplugin(), src.get_signature()), + m_col(col), + m_value(value), + m_src(src.ref()) {} + virtual ~lazy_table_filter_equal() {} + + virtual lazy_table_kind kind() const { return LAZY_TABLE_FILTER_EQUAL; } + unsigned col() const { return m_col; } + table_element value() const { return m_value; } + lazy_table_ref* src() const { return m_src.get(); } + virtual table_base* force(); + }; + + class lazy_table_filter_interpreted : public lazy_table_ref { + app_ref m_condition; + ref m_src; + public: + lazy_table_filter_interpreted(lazy_table const& src, app* condition) + : lazy_table_ref(src.get_lplugin(), src.get_signature()), + m_condition(condition, src.get_lplugin().get_ast_manager()), m_src(src.ref()) {} + virtual ~lazy_table_filter_interpreted() {} + + virtual lazy_table_kind kind() const { return LAZY_TABLE_FILTER_INTERPRETED; } + app* condition() const { return m_condition; } + lazy_table_ref* src() const { return m_src.get(); } + virtual table_base* force(); + }; + + + class lazy_table_filter_by_negation : public lazy_table_ref { + ref m_tgt; + ref m_src; + unsigned_vector m_cols1; + unsigned_vector m_cols2; + public: + lazy_table_filter_by_negation(lazy_table const& tgt, lazy_table const& src, + unsigned_vector const& c1, unsigned_vector const& c2) + : lazy_table_ref(tgt.get_lplugin(), tgt.get_signature()), + m_tgt(tgt.ref()), + m_src(src.ref()), + m_cols1(c1), + m_cols2(c2) {} + virtual ~lazy_table_filter_by_negation() {} + virtual lazy_table_kind kind() const { return LAZY_TABLE_FILTER_BY_NEGATION; } + lazy_table_ref* tgt() const { return m_tgt.get(); } + lazy_table_ref* src() const { return m_src.get(); } + unsigned_vector const& cols1() const { return m_cols1; } + unsigned_vector const& cols2() const { return m_cols2; } + virtual table_base* force(); + }; + + +} + +#endif diff --git a/src/muz/rel/dl_relation_manager.cpp b/src/muz/rel/dl_relation_manager.cpp index 457ef28c0..9421b26df 100644 --- a/src/muz/rel/dl_relation_manager.cpp +++ b/src/muz/rel/dl_relation_manager.cpp @@ -167,8 +167,13 @@ namespace datalog { register_relation_plugin_impl(tr_plugin); m_table_relation_plugins.insert(plugin, tr_plugin); + if (plugin->get_name()==get_context().default_table()) { + m_favourite_table_plugin = plugin; + m_favourite_relation_plugin = tr_plugin; + } + symbol checker_name = get_context().default_table_checker(); - if(get_context().default_table_checked() && get_table_plugin(checker_name)) { + if (get_context().default_table_checked() && get_table_plugin(checker_name)) { if( m_favourite_table_plugin && (plugin==m_favourite_table_plugin || plugin->get_name()==checker_name) ) { symbol checked_name = get_context().default_table(); @@ -178,7 +183,7 @@ namespace datalog { register_plugin(checking_plugin); m_favourite_table_plugin = checking_plugin; } - if(m_favourite_relation_plugin && m_favourite_relation_plugin->from_table()) { + if (m_favourite_relation_plugin && m_favourite_relation_plugin->from_table()) { table_relation_plugin * fav_rel_plugin = static_cast(m_favourite_relation_plugin); if(&fav_rel_plugin->get_table_plugin()==plugin || plugin->get_name()==checker_name) { @@ -577,6 +582,7 @@ namespace datalog { relation_plugin * p2 = &t2.get_plugin(); relation_join_fn * res = p1->mk_join_fn(t1, t2, col_cnt, cols1, cols2); + if(!res && p1!=p2) { res = p2->mk_join_fn(t1, t2, col_cnt, cols1, cols2); } @@ -1538,6 +1544,19 @@ namespace datalog { return res; } + + table_intersection_join_filter_fn* relation_manager::mk_filter_by_negated_join_fn( + const table_base & t, + const table_base & src1, + const table_base & src2, + unsigned_vector const& t_cols, + unsigned_vector const& src_cols, + unsigned_vector const& src1_cols, + unsigned_vector const& src2_cols) { + return t.get_plugin().mk_filter_by_negated_join_fn(t, src1, src2, t_cols, src_cols, src1_cols, src2_cols); + } + + class relation_manager::default_table_select_equal_and_project_fn : public table_transformer_fn { scoped_ptr m_filter; diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index 9f12b4bb6..2c148c5e6 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -564,6 +564,19 @@ namespace datalog { return mk_filter_by_negation_fn(t, negated_obj, t_cols.size(), t_cols.c_ptr(), negated_cols.c_ptr()); } + /** + combined filter by negation with a join. + */ + table_intersection_join_filter_fn* mk_filter_by_negated_join_fn( + const table_base & t, + const table_base & src1, + const table_base & src2, + unsigned_vector const& t_cols, + unsigned_vector const& src_cols, + unsigned_vector const& src1_cols, + unsigned_vector const& src2_cols); + + /** \c t must contain at least one functional column. diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index 2cae7771f..954fcad86 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -24,6 +24,7 @@ Revision History: namespace datalog { + // ----------------------------------- // // entry_storage @@ -415,7 +416,7 @@ namespace datalog { } //We will change the content of the reserve; which does not change the 'high-level' //content of the table. - sparse_table & t = const_cast(m_table); + sparse_table & t = const_cast(m_table); t.write_into_reserve(m_key_fact.c_ptr()); store_offset res; @@ -461,6 +462,8 @@ namespace datalog { sparse_table::key_indexer& sparse_table::get_key_indexer(unsigned key_len, const unsigned * key_cols) const { + verbose_action _va("get_key_indexer"); + #if Z3DEBUG //We allow indexes only on non-functional columns because we want to be able to modify them //without having to worry about updating indexes. @@ -506,6 +509,7 @@ namespace datalog { } bool sparse_table::add_fact(const char * data) { + verbose_action _va("add_fact", 3); m_data.write_into_reserve(data); return add_reserve_content(); } @@ -520,6 +524,7 @@ namespace datalog { } bool sparse_table::contains_fact(const table_fact & f) const { + verbose_action _va("contains_fact", 2); sparse_table & t = const_cast(*this); t.write_into_reserve(f.c_ptr()); unsigned func_col_cnt = get_signature().functional_columns(); @@ -542,6 +547,7 @@ namespace datalog { } bool sparse_table::fetch_fact(table_fact & f) const { + verbose_action _va("fetch_fact", 2); const table_signature & sig = get_signature(); SASSERT(f.size() == sig.size()); if (sig.functional_columns() == 0) { @@ -567,6 +573,7 @@ namespace datalog { This is ok as long as we do not allow indexing on functional columns. */ void sparse_table::ensure_fact(const table_fact & f) { + verbose_action _va("ensure_fact", 2); const table_signature & sig = get_signature(); if (sig.functional_columns() == 0) { add_fact(f); @@ -586,6 +593,7 @@ namespace datalog { } void sparse_table::remove_fact(const table_element* f) { + verbose_action _va("remove_fact", 2); //first insert the fact so that we find it's original location and remove it write_into_reserve(f); if (!m_data.remove_reserve_content()) { @@ -638,6 +646,7 @@ namespace datalog { unsigned joined_col_cnt, const unsigned * t1_joined_cols, const unsigned * t2_joined_cols, const unsigned * removed_cols, bool tables_swapped, sparse_table & result) { + verbose_action _va("join_project", 1); unsigned t1_entry_size = t1.m_fact_size; unsigned t2_entry_size = t2.m_fact_size; @@ -737,15 +746,21 @@ namespace datalog { reset(); } + sparse_table const& sparse_table_plugin::get(table_base const& t) { return dynamic_cast(t); } + sparse_table& sparse_table_plugin::get(table_base& t) { return dynamic_cast(t); } + sparse_table const* sparse_table_plugin::get(table_base const* t) { return dynamic_cast(t); } + sparse_table* sparse_table_plugin::get(table_base* t) { return dynamic_cast(t); } + + void sparse_table_plugin::reset() { table_pool::iterator it = m_pool.begin(); table_pool::iterator end = m_pool.end(); for (; it!=end; ++it) { sp_table_vector * vect = it->m_value; - sp_table_vector::iterator it = vect->begin(); - sp_table_vector::iterator end = vect->end(); - for (; it!=end; ++it) { - (*it)->destroy(); //calling deallocate() would only put the table back into the pool + sp_table_vector::iterator vit = vect->begin(); + sp_table_vector::iterator vend = vect->end(); + for (; vit!=vend; ++vit) { + (*vit)->destroy(); //calling deallocate() would only put the table back into the pool } dealloc(vect); } @@ -759,6 +774,7 @@ namespace datalog { } void sparse_table_plugin::recycle(sparse_table * t) { + verbose_action _va("recycle", 2); const table_signature & sig = t->get_signature(); t->reset(); @@ -785,7 +801,7 @@ namespace datalog { } sparse_table * sparse_table_plugin::mk_clone(const sparse_table & t) { - sparse_table * res = static_cast(mk_empty(t.get_signature())); + sparse_table * res = get(mk_empty(t.get_signature())); res->m_data = t.m_data; return res; } @@ -813,12 +829,13 @@ namespace datalog { virtual table_base * operator()(const table_base & tb1, const table_base & tb2) { - const sparse_table & t1 = static_cast(tb1); - const sparse_table & t2 = static_cast(tb2); + verbose_action _va("join_project"); + const sparse_table & t1 = get(tb1); + const sparse_table & t2 = get(tb2); sparse_table_plugin & plugin = t1.get_plugin(); - sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); + sparse_table * res = get(plugin.mk_empty(get_result_signature())); //If we join with some intersection, want to iterate over the smaller table and //do indexing into the bigger one. If we simply do a product, we want the bigger @@ -868,10 +885,10 @@ namespace datalog { class sparse_table_plugin::union_fn : public table_union_fn { public: virtual void operator()(table_base & tgt0, const table_base & src0, table_base * delta0) { - - sparse_table & tgt = static_cast(tgt0); - const sparse_table & src = static_cast(src0); - sparse_table * delta = static_cast(delta0); + verbose_action _va("union"); + sparse_table & tgt = get(tgt0); + const sparse_table & src = get(src0); + sparse_table * delta = get(delta0); unsigned fact_size = tgt.m_fact_size; const char* ptr = src.m_data.begin(); @@ -927,12 +944,13 @@ namespace datalog { } virtual table_base * operator()(const table_base & tb) { - const sparse_table & t = static_cast(tb); + verbose_action _va("project"); + const sparse_table & t = get(tb); unsigned t_fact_size = t.m_fact_size; sparse_table_plugin & plugin = t.get_plugin(); - sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); + sparse_table * res = get(plugin.mk_empty(get_result_signature())); const sparse_table::column_layout & src_layout = t.m_column_layout; const sparse_table::column_layout & tgt_layout = res->m_column_layout; @@ -970,10 +988,11 @@ namespace datalog { } virtual table_base * operator()(const table_base & tb) { - const sparse_table & t = static_cast(tb); + verbose_action _va("select_equal_and_project"); + const sparse_table & t = get(tb); sparse_table_plugin & plugin = t.get_plugin(); - sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); + sparse_table * res = get(plugin.mk_empty(get_result_signature())); const sparse_table::column_layout & t_layout = t.m_column_layout; const sparse_table::column_layout & res_layout = res->m_column_layout; @@ -1056,13 +1075,14 @@ namespace datalog { } virtual table_base * operator()(const table_base & tb) { + verbose_action _va("rename"); - const sparse_table & t = static_cast(tb); + const sparse_table & t = get(tb); unsigned t_fact_size = t.m_fact_size; sparse_table_plugin & plugin = t.get_plugin(); - sparse_table * res = static_cast(plugin.mk_empty(get_result_signature())); + sparse_table * res = get(plugin.mk_empty(get_result_signature())); size_t res_fact_size = res->m_fact_size; size_t res_data_size = res_fact_size*t.row_count(); @@ -1117,12 +1137,12 @@ namespace datalog { negation_filter_fn(const table_base & tgt, const table_base & neg, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols) : convenient_table_negation_filter_fn(tgt, neg, joined_col_cnt, t_cols, negated_cols) { - unsigned neg_fisrt_func = neg.get_signature().first_functional(); + unsigned neg_first_func = neg.get_signature().first_functional(); counter ctr; ctr.count(m_cols2); m_joining_neg_non_functional = ctr.get_max_counter_value() == 1 - && ctr.get_positive_count() == neg_fisrt_func - && (neg_fisrt_func == 0 || ctr.get_max_positive() == neg_fisrt_func-1); + && ctr.get_positive_count() == neg_first_func + && (neg_first_func == 0 || ctr.get_max_positive() == neg_first_func-1); } /** @@ -1133,9 +1153,7 @@ namespace datalog { bool tgt_is_first, svector & res) { SASSERT(res.empty()); - if (!tgt_is_first) { - m_intersection_content.reset(); - } + m_intersection_content.reset(); unsigned joined_col_cnt = m_cols1.size(); unsigned t1_entry_size = t1.m_data.entry_size(); @@ -1194,8 +1212,10 @@ namespace datalog { } virtual void operator()(table_base & tgt0, const table_base & neg0) { - sparse_table & tgt = static_cast(tgt0); - const sparse_table & neg = static_cast(neg0); + sparse_table & tgt = get(tgt0); + const sparse_table & neg = get(neg0); + + verbose_action _va("filter_by_negation"); if (m_cols1.size() == 0) { if (!neg.empty()) { @@ -1215,12 +1235,9 @@ namespace datalog { collect_intersection_offsets(tgt, neg, true, to_remove); } - if (to_remove.empty()) { - return; - } //the largest offsets are at the end, so we can remove them one by one - while(!to_remove.empty()) { + while (!to_remove.empty()) { store_offset removed_ofs = to_remove.back(); to_remove.pop_back(); tgt.m_data.remove_offset(removed_ofs); @@ -1241,6 +1258,148 @@ namespace datalog { return alloc(negation_filter_fn, t, negated_obj, joined_col_cnt, t_cols, negated_cols); } + /** + T \ (S1 Join S2) + + t_cols - columns from T + s_cols - columns from (S1 Join S2) that are equated + src1_cols - columns from S1 equated with columns from S2 + src2_cols - columns from S2 equated with columns from S1 + + t1_cols - columns from T that map into S1 + s1_cols - matching columns from s_cols for t1_cols + t2s1_cols - columns from T that map into S2, and columns from src1 that join src2 + s2_cols - matching columns from t2s1_cols + + columns from s2 that are equal to a column from s1 that is in s_cols: + + - ... + + */ + + class sparse_table_plugin::negated_join_fn : public table_intersection_join_filter_fn { + typedef sparse_table::store_offset store_offset; + typedef sparse_table::key_value key_value; + typedef sparse_table::key_indexer key_indexer; + unsigned_vector m_t1_cols; + unsigned_vector m_s1_cols; + unsigned_vector m_t2_cols; + unsigned_vector m_s2_cols; + unsigned_vector m_src1_cols; + public: + negated_join_fn( + table_base const& src1, + unsigned_vector const& t_cols, + unsigned_vector const& src_cols, + unsigned_vector const& src1_cols, + unsigned_vector const& src2_cols): + m_src1_cols(src1_cols) { + + // split t_cols and src_cols according to src1, and src2 + + unsigned src1_size = src1.get_signature().size(); + for (unsigned i = 0; i < t_cols.size(); ++i) { + if (src_cols[i] < src1_size) { + m_t1_cols.push_back(t_cols[i]); + m_s1_cols.push_back(src_cols[i]); + } + else { + m_t2_cols.push_back(t_cols[i]); + m_s2_cols.push_back(src_cols[i]); + } + } + m_s2_cols.append(src2_cols); + } + + virtual void operator()(table_base & _t, const table_base & _s1, const table_base& _s2) { + + verbose_action _va("negated_join"); + sparse_table& t = get(_t); + svector to_remove; + collect_to_remove(t, get(_s1), get(_s2), to_remove); + for (unsigned i = 0; i < to_remove.size(); ++i) { + t.m_data.remove_offset(to_remove[i]); + } + t.reset_indexes(); + } + + private: + void collect_to_remove(sparse_table& t, sparse_table const& s1, sparse_table const& s2, svector& to_remove) { + key_value s1_key, s2_key; + SASSERT(&s1 != &s2); + SASSERT(m_s1_cols.size() == m_t1_cols.size()); + SASSERT(m_s2_cols.size() == m_t2_cols.size() + m_src1_cols.size()); + s1_key.resize(m_s1_cols.size()); + s2_key.resize(m_s2_cols.size()); + key_indexer & s1_indexer = s1.get_key_indexer(m_s1_cols.size(), m_s1_cols.c_ptr()); + key_indexer & s2_indexer = s2.get_key_indexer(m_s2_cols.size(), m_s2_cols.c_ptr()); + + store_offset t_after_last = t.m_data.after_last_offset(); + key_indexer::query_result s1_offsets, s2_offsets; + unsigned t_entry_size = t.m_data.entry_size(); + for (store_offset t_ofs = 0; t_ofs < t_after_last; t_ofs += t_entry_size) { + + if (update_key(s1_key, 0, t, t_ofs, m_t1_cols)) { + s1_offsets = s1_indexer.get_matching_offsets(s1_key); + } + key_indexer::offset_iterator it = s1_offsets.begin(); + key_indexer::offset_iterator end = s1_offsets.end(); + for (; it != end; ++it) { + store_offset s1_ofs = *it; + bool upd1 = update_key(s2_key, 0, t, t_ofs, m_t2_cols); + bool upd2 = update_key(s2_key, m_t2_cols.size(), s1, s1_ofs, m_src1_cols); + if (upd1 || upd2) { + s2_offsets = s2_indexer.get_matching_offsets(s2_key); + } + if (!s2_offsets.empty()) { + to_remove.push_back(t_ofs); + break; + } + } + } + } + + inline bool update_key(key_value& key, unsigned key_offset, sparse_table const& t, store_offset ofs, unsigned_vector const& cols) { + bool modified = false; + unsigned sz = cols.size(); + for (unsigned i = 0; i < sz; ++i) { + table_element val = t.get_cell(ofs, cols[i]); + modified = update_key(key[i+key_offset], val) || modified; + } + return modified; + } + + inline bool update_key(table_element& tgt, table_element src) { + if (tgt == src) { + return false; + } + else { + tgt = src; + return true; + } + } + + }; + + table_intersection_join_filter_fn* sparse_table_plugin::mk_filter_by_negated_join_fn( + const table_base & t, + + + const table_base & src1, + const table_base & src2, + unsigned_vector const& t_cols, + unsigned_vector const& src_cols, + unsigned_vector const& src1_cols, + unsigned_vector const& src2_cols) { + if (check_kind(t) && check_kind(src1) && check_kind(src2)) { + return alloc(negated_join_fn, src1, t_cols, src_cols, src1_cols, src2_cols); + } + else { + return 0; + } + } + + unsigned sparse_table::get_size_estimate_bytes() const { unsigned sz = 0; sz += m_data.get_size_estimate_bytes(); diff --git a/src/muz/rel/dl_sparse_table.h b/src/muz/rel/dl_sparse_table.h index 0a60c4e10..0222aa6e2 100644 --- a/src/muz/rel/dl_sparse_table.h +++ b/src/muz/rel/dl_sparse_table.h @@ -48,6 +48,7 @@ namespace datalog { class project_fn; class negation_filter_fn; class select_equal_and_project_fn; + class negated_join_fn; typedef ptr_vector sp_table_vector; typedef map "; tres->display(tout);); if(&tres->get_plugin()!=&plugin.m_table_plugin) { + IF_VERBOSE(1, verbose_stream() << "new type returned\n";); //Operation returned a table of different type than the one which is associated with //this plugin. We need to get a correct table_relation_plugin and create the relation //using it. diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index c57ef2606..b44f67644 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -31,6 +31,7 @@ Revision History: #include"dl_interval_relation.h" #include"karr_relation.h" #include"dl_finite_product_relation.h" +#include"dl_lazy_table.h" #include"dl_sparse_table.h" #include"dl_table.h" #include"dl_table_relation.h" @@ -45,6 +46,7 @@ Revision History: #include"dl_mk_rule_inliner.h" #include"dl_mk_interp_tail_simplifier.h" #include"dl_mk_bit_blast.h" +#include"fixedpoint_params.hpp" namespace datalog { @@ -96,17 +98,19 @@ namespace datalog { // register plugins for builtin tables - get_rmanager().register_plugin(alloc(sparse_table_plugin, get_rmanager())); - get_rmanager().register_plugin(alloc(hashtable_table_plugin, get_rmanager())); - get_rmanager().register_plugin(alloc(bitvector_table_plugin, get_rmanager())); - get_rmanager().register_plugin(alloc(equivalence_table_plugin, get_rmanager())); + relation_manager& rm = get_rmanager(); + rm.register_plugin(alloc(sparse_table_plugin, rm)); + rm.register_plugin(alloc(hashtable_table_plugin, rm)); + rm.register_plugin(alloc(bitvector_table_plugin, rm)); + rm.register_plugin(alloc(equivalence_table_plugin, rm)); + rm.register_plugin(lazy_table_plugin::mk_sparse(rm)); // register plugins for builtin relations - get_rmanager().register_plugin(alloc(bound_relation_plugin, get_rmanager())); - get_rmanager().register_plugin(alloc(interval_relation_plugin, get_rmanager())); - get_rmanager().register_plugin(alloc(karr_relation_plugin, get_rmanager())); + rm.register_plugin(alloc(bound_relation_plugin, rm)); + rm.register_plugin(alloc(interval_relation_plugin, rm)); + rm.register_plugin(alloc(karr_relation_plugin, rm)); } rel_context::~rel_context() { diff --git a/src/muz/tab/tab_context.cpp b/src/muz/tab/tab_context.cpp index 2201be73e..83842a68b 100644 --- a/src/muz/tab/tab_context.cpp +++ b/src/muz/tab/tab_context.cpp @@ -30,6 +30,7 @@ Revision History: #include "for_each_expr.h" #include "matcher.h" #include "scoped_proof.h" +#include "fixedpoint_params.hpp" namespace tb { diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 271003fff..08f295ff4 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -24,6 +24,7 @@ Revision History: #include "expr_safe_replace.h" #include "filter_model_converter.h" #include "dl_mk_interp_tail_simplifier.h" +#include "fixedpoint_params.hpp" namespace datalog { diff --git a/src/muz/transforms/dl_mk_coi_filter.cpp b/src/muz/transforms/dl_mk_coi_filter.cpp index 8583fbe45..31af7a53f 100644 --- a/src/muz/transforms/dl_mk_coi_filter.cpp +++ b/src/muz/transforms/dl_mk_coi_filter.cpp @@ -52,14 +52,10 @@ namespace datalog { ptr_vector todo; rule_set::decl2rules body2rules; // initialization for reachability - rel_context_base* rc = m_context.get_rel_context(); for (rule_set::iterator it = source.begin(); it != source.end(); ++it) { rule * r = *it; all.insert(r->get_decl()); - bool non_empty = - (rc && !rc->is_empty_relation(r->get_decl())) || - r->get_uninterpreted_tail_size() == 0; - if (non_empty) { + if (r->get_uninterpreted_tail_size() == 0) { if (!reached.contains(r->get_decl())) { reached.insert(r->get_decl()); todo.insert(r->get_decl()); @@ -77,6 +73,17 @@ namespace datalog { } } } + rel_context_base* rc = m_context.get_rel_context(); + if (rc) { + func_decl_set::iterator fit = all.begin(), fend = all.end(); + for (; fit != fend; ++fit) { + if (!rc->is_empty_relation(*fit) && + !reached.contains(*fit)) { + reached.insert(*fit); + todo.insert(*fit); + } + } + } // reachability computation while (!todo.empty()) { func_decl * d = todo.back(); diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp index 4c0a24b65..b4ab66bc2 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.cpp +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -39,6 +39,7 @@ Revision History: #include"dl_mk_karr_invariants.h" #include"dl_mk_backwards.h" #include"dl_mk_loop_counter.h" +#include"fixedpoint_params.hpp" namespace datalog { diff --git a/src/muz/transforms/dl_mk_magic_symbolic.cpp b/src/muz/transforms/dl_mk_magic_symbolic.cpp index a06a573ad..57490466c 100644 --- a/src/muz/transforms/dl_mk_magic_symbolic.cpp +++ b/src/muz/transforms/dl_mk_magic_symbolic.cpp @@ -54,6 +54,7 @@ Revision History: #include"dl_mk_magic_symbolic.h" #include"dl_context.h" +#include"fixedpoint_params.hpp" namespace datalog { diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index 68f5bc3a3..e686495e9 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -23,6 +23,8 @@ Revision History: #include "dl_context.h" #include "expr_safe_replace.h" #include "expr_abstract.h" +#include"fixedpoint_params.hpp" + namespace datalog { diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index b24e3e81c..ebb9310a4 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -26,6 +26,8 @@ Revision History: #include "dl_mk_quantifier_instantiation.h" #include "dl_context.h" #include "pattern_inference.h" +#include "fixedpoint_params.hpp" + namespace datalog { diff --git a/src/muz/transforms/dl_mk_rule_inliner.cpp b/src/muz/transforms/dl_mk_rule_inliner.cpp index 65ce44b8b..3e933b099 100644 --- a/src/muz/transforms/dl_mk_rule_inliner.cpp +++ b/src/muz/transforms/dl_mk_rule_inliner.cpp @@ -52,6 +52,7 @@ Subsumption transformation (remove rule): #include "rewriter.h" #include "rewriter_def.h" #include "dl_mk_rule_inliner.h" +#include "fixedpoint_params.hpp" namespace datalog { diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index d666d0ca8..9618db88e 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -18,6 +18,7 @@ Revision History: #include"dl_mk_scale.h" #include"dl_context.h" +#include"fixedpoint_params.hpp" namespace datalog { diff --git a/src/muz/transforms/dl_transforms.cpp b/src/muz/transforms/dl_transforms.cpp index 7c5707ccf..2cf48d46b 100644 --- a/src/muz/transforms/dl_transforms.cpp +++ b/src/muz/transforms/dl_transforms.cpp @@ -33,6 +33,7 @@ Revision History: #include"dl_mk_quantifier_instantiation.h" #include"dl_mk_subsumption_checker.h" #include"dl_mk_scale.h" +#include"fixedpoint_params.hpp" namespace datalog { diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 15681ea36..a487a99b4 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -232,10 +232,9 @@ unsigned read_datalog(char const * file) { TRACE("dl_compiler", ctx.display(tout); rules_code.display(*ctx.get_rel_context(), tout);); - if (ctx.get_params().output_tuples()) { + if (ctx.output_tuples()) { ctx.get_rel_context()->display_output_facts(ctx.get_rules(), std::cout); } - display_statistics( std::cout, ctx, From 93fd36b5da8c87ccc461bf1de79d100b396f3d36 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Sep 2013 11:52:00 -0700 Subject: [PATCH 265/281] revert wrong optimization for single-occurrence negative columns Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_compiler.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/muz/rel/dl_compiler.cpp b/src/muz/rel/dl_compiler.cpp index 1886563c2..276e7b836 100644 --- a/src/muz/rel/dl_compiler.cpp +++ b/src/muz/rel/dl_compiler.cpp @@ -869,7 +869,6 @@ namespace datalog { bool & dealloc, instruction_block & acc) { uint_set pos_vars; u_map neg_vars; - u_map occs; ast_manager& m = m_context.get_manager(); unsigned pt_len = r->get_positive_tail_size(); unsigned ut_len = r->get_uninterpreted_tail_size(); @@ -885,12 +884,6 @@ namespace datalog { if (is_var(e)) { unsigned idx = to_var(e)->get_idx(); neg_vars.insert(idx, e); - if (!occs.contains(idx)) { - occs.insert(idx, 1); - } - else { - occs.find(idx)++; - } } } } @@ -901,15 +894,11 @@ namespace datalog { pos_vars.insert(to_var(e)->get_idx()); } } - // add negative variables that are not in positive, but only - // for variables that occur more than once. + // add negative variables that are not in positive u_map::iterator it = neg_vars.begin(), end = neg_vars.end(); for (; it != end; ++it) { unsigned v = it->m_key; expr* e = it->m_value; - if (occs.find(v) == 1) { - continue; - } if (!pos_vars.contains(v)) { single_res_expr.push_back(e); reg_idx new_single_res; From 861a31f4581a664d297b87cc29d9a57329253d6e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Sep 2013 13:30:03 -0700 Subject: [PATCH 266/281] fix build warning from tptp example Signed-off-by: Nikolaj Bjorner --- examples/tptp/tptp5.cpp | 2 +- src/muz/rel/dl_sparse_table.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/tptp/tptp5.cpp b/examples/tptp/tptp5.cpp index 1f50bdfea..d0e174914 100644 --- a/examples/tptp/tptp5.cpp +++ b/examples/tptp/tptp5.cpp @@ -151,7 +151,7 @@ public: void set_index(int idx) { m_symbol_index = idx; } }; -TreeNode* MkToken(alloc_region& r, char* token, int symbolIndex) { +TreeNode* MkToken(alloc_region& r, char const* token, int symbolIndex) { TreeNode* ss; char* symbol = tptp_lval[symbolIndex]; ss = new (r) TreeNode(r, symbol, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); diff --git a/src/muz/rel/dl_sparse_table.cpp b/src/muz/rel/dl_sparse_table.cpp index 954fcad86..3b2dc333a 100644 --- a/src/muz/rel/dl_sparse_table.cpp +++ b/src/muz/rel/dl_sparse_table.cpp @@ -1132,6 +1132,7 @@ namespace datalog { If tgt_is_first is false, contains the same items as \c res. */ idx_set m_intersection_content; + public: negation_filter_fn(const table_base & tgt, const table_base & neg, From 1496333e5bafeaec1f6d3afba54a930915b74f0a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Sep 2013 09:22:45 -0700 Subject: [PATCH 267/281] fix mint64 build errors Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_util.cpp | 2 -- src/muz/rel/dl_lazy_table.cpp | 3 +-- src/muz/rel/dl_lazy_table.h | 20 ++++++++++---------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/muz/base/dl_util.cpp b/src/muz/base/dl_util.cpp index c23f222e5..218f9906a 100644 --- a/src/muz/base/dl_util.cpp +++ b/src/muz/base/dl_util.cpp @@ -34,8 +34,6 @@ Revision History: namespace datalog { - static unsigned verbose_action_inside = 0; - verbose_action::verbose_action(char const* msg, unsigned lvl): m_lvl(lvl), m_sw(0) { IF_VERBOSE(m_lvl, (verbose_stream() << msg << "...").flush(); diff --git a/src/muz/rel/dl_lazy_table.cpp b/src/muz/rel/dl_lazy_table.cpp index 16dbc2d21..ec97a4bf5 100644 --- a/src/muz/rel/dl_lazy_table.cpp +++ b/src/muz/rel/dl_lazy_table.cpp @@ -19,7 +19,7 @@ Revision History: #include "dl_lazy_table.h" #include "dl_relation_manager.h" -#include +#include namespace datalog { @@ -53,7 +53,6 @@ namespace datalog { virtual table_base* operator()(const table_base& _t1, const table_base& _t2) { lazy_table const& t1 = get(_t1); lazy_table const& t2 = get(_t2); - lazy_table_plugin& p = t1.get_lplugin(); lazy_table_ref* tr = alloc(lazy_table_join, m_cols1.size(), m_cols1.c_ptr(), m_cols2.c_ptr(), t1, t2, get_result_signature()); return alloc(lazy_table, tr); } diff --git a/src/muz/rel/dl_lazy_table.h b/src/muz/rel/dl_lazy_table.h index 34a8b6b92..3c0b47367 100644 --- a/src/muz/rel/dl_lazy_table.h +++ b/src/muz/rel/dl_lazy_table.h @@ -156,7 +156,7 @@ namespace datalog { virtual table_base::iterator begin() const; virtual table_base::iterator end() const; - lazy_table_ref* ref() const { return m_ref.get(); } + lazy_table_ref* get_ref() const { return m_ref.get(); } void set(lazy_table_ref* r) { m_ref = r; } }; @@ -184,8 +184,8 @@ namespace datalog { : lazy_table_ref(t1.get_lplugin(), sig), m_cols1(col_cnt, cols1), m_cols2(col_cnt, cols2), - m_t1(t1.ref()), - m_t2(t2.ref()) { } + m_t1(t1.get_ref()), + m_t2(t2.get_ref()) { } virtual ~lazy_table_join() {} virtual lazy_table_kind kind() const { return LAZY_TABLE_JOIN; } unsigned_vector const& cols1() const { return m_cols1; } @@ -203,7 +203,7 @@ namespace datalog { lazy_table_project(unsigned col_cnt, const unsigned * cols, lazy_table const& src, table_signature const& sig) : lazy_table_ref(src.get_lplugin(), sig), m_cols(col_cnt, cols), - m_src(src.ref()) {} + m_src(src.get_ref()) {} virtual ~lazy_table_project() {} virtual lazy_table_kind kind() const { return LAZY_TABLE_PROJECT; } @@ -219,7 +219,7 @@ namespace datalog { lazy_table_rename(unsigned col_cnt, const unsigned * cols, lazy_table const& src, table_signature const& sig) : lazy_table_ref(src.get_lplugin(), sig), m_cols(col_cnt, cols), - m_src(src.ref()) {} + m_src(src.get_ref()) {} virtual ~lazy_table_rename() {} virtual lazy_table_kind kind() const { return LAZY_TABLE_RENAME; } @@ -233,7 +233,7 @@ namespace datalog { ref m_src; public: lazy_table_filter_identical(unsigned col_cnt, const unsigned * cols, lazy_table const& src) - : lazy_table_ref(src.get_lplugin(), src.get_signature()), m_cols(col_cnt, cols), m_src(src.ref()) {} + : lazy_table_ref(src.get_lplugin(), src.get_signature()), m_cols(col_cnt, cols), m_src(src.get_ref()) {} virtual ~lazy_table_filter_identical() {} virtual lazy_table_kind kind() const { return LAZY_TABLE_FILTER_IDENTICAL; } @@ -251,7 +251,7 @@ namespace datalog { : lazy_table_ref(src.get_lplugin(), src.get_signature()), m_col(col), m_value(value), - m_src(src.ref()) {} + m_src(src.get_ref()) {} virtual ~lazy_table_filter_equal() {} virtual lazy_table_kind kind() const { return LAZY_TABLE_FILTER_EQUAL; } @@ -267,7 +267,7 @@ namespace datalog { public: lazy_table_filter_interpreted(lazy_table const& src, app* condition) : lazy_table_ref(src.get_lplugin(), src.get_signature()), - m_condition(condition, src.get_lplugin().get_ast_manager()), m_src(src.ref()) {} + m_condition(condition, src.get_lplugin().get_ast_manager()), m_src(src.get_ref()) {} virtual ~lazy_table_filter_interpreted() {} virtual lazy_table_kind kind() const { return LAZY_TABLE_FILTER_INTERPRETED; } @@ -286,8 +286,8 @@ namespace datalog { lazy_table_filter_by_negation(lazy_table const& tgt, lazy_table const& src, unsigned_vector const& c1, unsigned_vector const& c2) : lazy_table_ref(tgt.get_lplugin(), tgt.get_signature()), - m_tgt(tgt.ref()), - m_src(src.ref()), + m_tgt(tgt.get_ref()), + m_src(src.get_ref()), m_cols1(c1), m_cols2(c2) {} virtual ~lazy_table_filter_by_negation() {} From 4ad6660f3585c156e136747da08f4f8c97e45c4a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Sep 2013 09:24:35 -0700 Subject: [PATCH 268/281] add const qualifiers to fix warning messages Signed-off-by: Nikolaj Bjorner --- examples/tptp/tptp5.tab.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tptp/tptp5.tab.c b/examples/tptp/tptp5.tab.c index 7fcf7915b..c97225f4c 100644 --- a/examples/tptp/tptp5.tab.c +++ b/examples/tptp/tptp5.tab.c @@ -107,7 +107,7 @@ struct pTreeNode { pTree children[MAX_CHILDREN+1]; }; //----------------------------------------------------------------------------- -int yyerror( char *s ) { +int yyerror( char const *s ) { fprintf( stderr, "%s in line %d at item \"%s\".\n", s, yylineno, yytext); return 0; From c87ae1e99b64b8ad250076ae3d60fa0c5d6cf623 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Sep 2013 23:05:18 -0700 Subject: [PATCH 269/281] add transformation to reduce overhead of negation for predicates with free variables Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 1 + src/muz/rel/rel_context.cpp | 2 + .../dl_mk_separate_negated_tails.cpp | 119 ++++++++++++++++++ .../transforms/dl_mk_separate_negated_tails.h | 61 +++++++++ .../transforms/dl_mk_subsumption_checker.h | 2 +- 5 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 src/muz/transforms/dl_mk_separate_negated_tails.cpp create mode 100644 src/muz/transforms/dl_mk_separate_negated_tails.h diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 3a62a9b98..cc2dc02c5 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -232,6 +232,7 @@ namespace datalog { context::~context() { reset(); + dealloc(m_params); } void context::reset() { diff --git a/src/muz/rel/rel_context.cpp b/src/muz/rel/rel_context.cpp index b44f67644..02b00be39 100644 --- a/src/muz/rel/rel_context.cpp +++ b/src/muz/rel/rel_context.cpp @@ -46,6 +46,7 @@ Revision History: #include"dl_mk_rule_inliner.h" #include"dl_mk_interp_tail_simplifier.h" #include"dl_mk_bit_blast.h" +#include"dl_mk_separate_negated_tails.h" #include"fixedpoint_params.hpp" @@ -281,6 +282,7 @@ namespace datalog { transf.register_plugin(alloc(mk_partial_equivalence_transformer, m_context)); transf.register_plugin(alloc(mk_rule_inliner, m_context)); transf.register_plugin(alloc(mk_interp_tail_simplifier, m_context)); + transf.register_plugin(alloc(mk_separate_negated_tails, m_context)); if (m_context.get_params().bit_blast()) { transf.register_plugin(alloc(mk_bit_blast, m_context, 22000)); diff --git a/src/muz/transforms/dl_mk_separate_negated_tails.cpp b/src/muz/transforms/dl_mk_separate_negated_tails.cpp new file mode 100644 index 000000000..18e7feadf --- /dev/null +++ b/src/muz/transforms/dl_mk_separate_negated_tails.cpp @@ -0,0 +1,119 @@ + +#include "dl_mk_separate_negated_tails.h" +#include "dl_context.h" + +namespace datalog { + + mk_separate_negated_tails::mk_separate_negated_tails(context& ctx, unsigned priority): + plugin(priority), + m(ctx.get_manager()), + rm(ctx.get_rule_manager()), + m_ctx(ctx) + {} + + bool mk_separate_negated_tails::has_private_vars(rule const& r, unsigned j) { + get_private_vars(r, j); + return !m_vars.empty(); + } + + void mk_separate_negated_tails::get_private_vars(rule const& r, unsigned j) { + m_vars.reset(); + m_fv.reset(); + get_free_vars(r.get_head(), m_fv); + for (unsigned i = 0; i < r.get_tail_size(); ++i) { + if (i != j) { + get_free_vars(r.get_tail(i), m_fv); + } + } + + app* p = r.get_tail(j); + for (unsigned i = 0; i < p->get_num_args(); ++i) { + expr* v = p->get_arg(i); + if (is_var(v)) { + unsigned idx = to_var(v)->get_idx(); + if (idx >= m_fv.size() || !m_fv[idx]) { + m_vars.push_back(v); + } + } + } + } + + void mk_separate_negated_tails::abstract_predicate(app* p, app_ref& q, rule_set& rules) { + expr_ref_vector args(m); + sort_ref_vector sorts(m); + func_decl_ref fn(m); + for (unsigned i = 0; i < p->get_num_args(); ++i) { + expr* arg = p->get_arg(i); + if (!m_vars.contains(arg)) { + args.push_back(arg); + sorts.push_back(m.get_sort(arg)); + } + } + fn = m.mk_fresh_func_decl(p->get_decl()->get_name(), symbol("N"), sorts.size(), sorts.c_ptr(), m.mk_bool_sort()); + m_ctx.register_predicate(fn, false); + q = m.mk_app(fn, args.size(), args.c_ptr()); + bool is_neg = true; + rules.add_rule(rm.mk(q, 1, & p, &is_neg)); + } + + void mk_separate_negated_tails::create_rule(rule const&r, rule_set& rules) { + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned ptsz = r.get_positive_tail_size(); + unsigned tsz = r.get_tail_size(); + app_ref_vector tail(m); + app_ref p(m); + svector neg; + for (unsigned i = 0; i < ptsz; ++i) { + tail.push_back(r.get_tail(i)); + neg.push_back(false); + } + for (unsigned i = ptsz; i < utsz; ++i) { + get_private_vars(r, i); + if (!m_vars.empty()) { + abstract_predicate(r.get_tail(i), p, rules); + tail.push_back(p); + neg.push_back(false); + } + else { + neg.push_back(true); + tail.push_back(r.get_tail(i)); + } + } + for (unsigned i = utsz; i < tsz; ++i) { + tail.push_back(r.get_tail(i)); + neg.push_back(false); + } + rules.add_rule(rm.mk(r.get_head(), tail.size(), tail.c_ptr(), neg.c_ptr(), r.name())); + } + + rule_set * mk_separate_negated_tails::operator()(rule_set const& src) { + scoped_ptr result = alloc(rule_set, m_ctx); + bool has_new_rule = false; + unsigned sz = src.get_num_rules(); + for (unsigned i = 0; i < sz; ++i) { + bool change = false; + rule & r = *src.get_rule(i); + unsigned utsz = r.get_uninterpreted_tail_size(); + unsigned ptsz = r.get_positive_tail_size(); + for (unsigned j = ptsz; j < utsz; ++j) { + SASSERT(r.is_neg_tail(j)); + if (has_private_vars(r, j)) { + create_rule(r, *result); + has_new_rule = true; + change = true; + break; + } + } + if (!change) { + result->add_rule(&r); + } + } + if (!has_new_rule) { + return 0; + } + else { + result->inherit_predicates(src); + return result.detach(); + } + } +} diff --git a/src/muz/transforms/dl_mk_separate_negated_tails.h b/src/muz/transforms/dl_mk_separate_negated_tails.h new file mode 100644 index 000000000..4b1673307 --- /dev/null +++ b/src/muz/transforms/dl_mk_separate_negated_tails.h @@ -0,0 +1,61 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + mk_separate_negated_tails.h + +Abstract: + + Rule transformer which creates new rules for predicates + in negated tails that use free variables not used + elsewhere. These free variables incur an overhead + on the instructions compiled using dl_compiler. + + Consider the following transformations: + + P(x) :- Exists y, z, u . Q(x,y), !R(y,z), !T(z,u). + => + P(x) :- Exists y, z . Q(x,y), !R(y,z), Exists u . ! T(z,u). + => + P(x) :- Exists y, z . Q(x,y), !R(y,z), TN(z). + TN(z) :- !T(z,u). + + + + +Author: + + Nikolaj Bjorner (nbjorner) 2013-09-09 + +Revision History: + +--*/ + +#ifndef _DL_MK_SEPARAT_NEGATED_TAILS_H_ +#define _DL_MK_SEPARAT_NEGATED_TAILS_H_ + +#include "dl_rule_transformer.h" +#include "dl_context.h" + +namespace datalog { + + class mk_separate_negated_tails : public rule_transformer::plugin { + ast_manager & m; + rule_manager& rm; + context & m_ctx; + ptr_vector m_vars; + ptr_vector m_fv; + + bool has_private_vars(rule const& r, unsigned j); + void get_private_vars(rule const& r, unsigned j); + void abstract_predicate(app* p, app_ref& q, rule_set& rules); + void create_rule(rule const&r, rule_set& rules); + + public: + mk_separate_negated_tails(context& ctx, unsigned priority = 21000); + rule_set * operator()(rule_set const & source); + }; +} + +#endif diff --git a/src/muz/transforms/dl_mk_subsumption_checker.h b/src/muz/transforms/dl_mk_subsumption_checker.h index da42e4202..8d797a9e2 100644 --- a/src/muz/transforms/dl_mk_subsumption_checker.h +++ b/src/muz/transforms/dl_mk_subsumption_checker.h @@ -84,7 +84,7 @@ namespace datalog { reset_dealloc_values(m_ground_unconditional_rule_heads); } - rule_set * operator()(rule_set const & source); + virtual rule_set * operator()(rule_set const & source); }; }; From f4aae5e56adf838c6fe502245170c5b492f62671 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 9 Sep 2013 23:12:55 -0700 Subject: [PATCH 270/281] fix C(R) Signed-off-by: Nikolaj Bjorner --- .../dl_mk_separate_negated_tails.cpp | 18 ++++++++++++++++++ .../transforms/dl_mk_separate_negated_tails.h | 5 +---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/muz/transforms/dl_mk_separate_negated_tails.cpp b/src/muz/transforms/dl_mk_separate_negated_tails.cpp index 18e7feadf..782e1011d 100644 --- a/src/muz/transforms/dl_mk_separate_negated_tails.cpp +++ b/src/muz/transforms/dl_mk_separate_negated_tails.cpp @@ -1,3 +1,21 @@ +/*++ +Copyright (c) 2013 Microsoft Corporation + +Module Name: + + mk_separate_negated_tails.cpp + +Abstract: + + + +Author: + + Nikolaj Bjorner (nbjorner) 2013-09-09 + +Revision History: + +--*/ #include "dl_mk_separate_negated_tails.h" #include "dl_context.h" diff --git a/src/muz/transforms/dl_mk_separate_negated_tails.h b/src/muz/transforms/dl_mk_separate_negated_tails.h index 4b1673307..8cd806f43 100644 --- a/src/muz/transforms/dl_mk_separate_negated_tails.h +++ b/src/muz/transforms/dl_mk_separate_negated_tails.h @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2006 Microsoft Corporation +Copyright (c) 2013 Microsoft Corporation Module Name: @@ -21,9 +21,6 @@ Abstract: P(x) :- Exists y, z . Q(x,y), !R(y,z), TN(z). TN(z) :- !T(z,u). - - - Author: Nikolaj Bjorner (nbjorner) 2013-09-09 From f4e048c1e8ecb72e420f3989984112e185522a50 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Sep 2013 22:23:09 -0700 Subject: [PATCH 271/281] partition inequalities into conjuncts determined by equivalence classes of shared variables Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_farkas_learner.cpp | 138 +++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 7 deletions(-) diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index 3cd1932ba..d7ef01aaa 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -46,6 +46,9 @@ namespace pdr { app_ref_vector m_ineqs; vector m_coeffs; + unsigned m_time; + unsigned_vector m_roots, m_size, m_his, m_reps, m_ts; + void mk_coerce(expr*& e1, expr*& e2) { if (a.is_int(e1) && a.is_real(e2)) { e1 = a.mk_to_real(e1); @@ -146,7 +149,7 @@ namespace pdr { } public: - constr(ast_manager& m) : m(m), a(m), m_ineqs(m) {} + constr(ast_manager& m) : m(m), a(m), m_ineqs(m), m_time(0) {} /** add a multiple of constraint c to the current constr */ void add(rational const & coef, app * c) { @@ -180,12 +183,133 @@ namespace pdr { tout << m_coeffs[i] << ": " << mk_pp(m_ineqs[i].get(), m) << "\n"; } ); + + res = extract_consequence(0, m_coeffs.size()); + +#if 1 + // partition equalities into variable disjoint sets. + // take the conjunction of these instead of the + // linear combination. + partition_ineqs(); + expr_ref_vector lits(m); + unsigned lo = 0; + for (unsigned i = 0; i < m_his.size(); ++i) { + unsigned hi = m_his[i]; + lits.push_back(extract_consequence(lo, hi)); + lo = hi; + } + res = qe::mk_or(lits); + IF_VERBOSE(2, { if (lits.size() > 1) { verbose_stream() << "combined lemma: " << mk_pp(res, m) << "\n"; } }); +#endif + } + + private: + + // partition inequalities into variable disjoint sets. + void partition_ineqs() { + m_roots.reset(); + m_size.reset(); + m_reps.reset(); + m_his.reset(); + ++m_time; + for (unsigned i = 0; i < m_ineqs.size(); ++i) { + m_reps.push_back(process_term(m_ineqs[i].get())); + } + unsigned head = 0; + while (head < m_ineqs.size()) { + unsigned r = find(m_reps[head]); + unsigned tail = head; + for (unsigned i = head+1; i < m_ineqs.size(); ++i) { + if (find(m_reps[i]) == r) { + ++tail; + if (tail != i) { + SASSERT(tail < i); + std::swap(m_reps[tail], m_reps[i]); + app_ref tmp(m); + tmp = m_ineqs[i].get(); + m_ineqs[i] = m_ineqs[tail].get(); + m_ineqs[tail] = tmp; + std::swap(m_coeffs[tail], m_coeffs[i]); + } + } + } + head = tail + 1; + m_his.push_back(head); + } + } + + unsigned find(unsigned idx) { + if (m_ts.size() <= idx) { + m_roots.resize(idx+1); + m_size.resize(idx+1); + m_ts.resize(idx+1); + m_roots[idx] = idx; + m_ts[idx] = m_time; + m_size[idx] = 1; + return idx; + } + if (m_ts[idx] != m_time) { + m_size[idx] = 1; + m_ts[idx] = m_time; + m_roots[idx] = idx; + return idx; + } + while (true) { + if (m_roots[idx] == idx) { + return idx; + } + idx = m_roots[idx]; + } + } + + void merge(unsigned i, unsigned j) { + i = find(i); + j = find(j); + if (i == j) { + return; + } + if (m_size[i] > m_size[j]) { + std::swap(i, j); + } + m_roots[i] = j; + m_size[j] += m_size[i]; + } + + unsigned process_term(expr* e) { + unsigned r = e->get_id(); + ptr_vector todo; + ast_mark mark; + todo.push_back(e); + while (!todo.empty()) { + e = todo.back(); + todo.pop_back(); + if (mark.is_marked(e)) { + continue; + } + mark.mark(e, true); + if (is_uninterp(e)) { + merge(r, e->get_id()); + } + if (is_app(e)) { + app* a = to_app(e); + for (unsigned i = 0; i < a->get_num_args(); ++i) { + todo.push_back(a->get_arg(i)); + } + } + } + return r; + } + + + expr_ref extract_consequence(unsigned lo, unsigned hi) { + bool is_int = is_int_sort(); app_ref zero(a.mk_numeral(rational::zero(), is_int), m); + expr_ref res(m); res = zero; bool is_strict = false; bool is_eq = true; expr* x, *y; - for (unsigned i = 0; i < m_coeffs.size(); ++i) { + for (unsigned i = lo; i < hi; ++i) { app* c = m_ineqs[i].get(); if (m.is_eq(c, x, y)) { mul(m_coeffs[i], x, res); @@ -220,12 +344,12 @@ namespace pdr { params.set_bool("gcd_rounding", true); rw.updt_params(params); proof_ref pr(m); - expr_ref tmp(m); - rw(res, tmp, pr); - fix_dl(tmp); - res = tmp; + expr_ref result(m); + rw(res, result, pr); + fix_dl(result); + return result; } - + // patch: swap addends to make static // features recognize difference constraint. void fix_dl(expr_ref& r) { From 0aaa67fa7df67bddde88cd75796fedaa8c51aa0e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 10 Sep 2013 22:45:37 -0700 Subject: [PATCH 272/281] check for uninterpreted functions in tail for PDR Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 2 ++ src/muz/fp/dl_cmds.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index cc2dc02c5..7eed67ff0 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -675,9 +675,11 @@ namespace datalog { case PDR_ENGINE: check_existential_tail(r); check_positive_predicates(r); + check_uninterpreted_free(r); break; case QPDR_ENGINE: check_positive_predicates(r); + check_uninterpreted_free(r); break; case BMC_ENGINE: check_positive_predicates(r); diff --git a/src/muz/fp/dl_cmds.cpp b/src/muz/fp/dl_cmds.cpp index 35af38630..f6965b084 100644 --- a/src/muz/fp/dl_cmds.cpp +++ b/src/muz/fp/dl_cmds.cpp @@ -223,6 +223,7 @@ public: dlctx.updt_params(m_params); unsigned timeout = m_dl_ctx->get_params().timeout(); cancel_eh eh(dlctx); + bool query_exn = false; lbool status = l_undef; { scoped_ctrl_c ctrlc(eh); @@ -237,6 +238,7 @@ public: } catch (z3_exception& ex) { ctx.regular_stream() << "(error \"query failed: " << ex.msg() << "\")" << std::endl; + query_exn = true; } } switch (status) { @@ -269,7 +271,7 @@ public: break; case datalog::OK: - UNREACHABLE(); + SASSERT(query_exn); break; case datalog::CANCELED: From 4af4466821c1489da0427c6cb0db5171d84a1185 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Sep 2013 12:19:46 -0700 Subject: [PATCH 273/281] add qe_arith routine for LW projection on monomomes Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_farkas_learner.cpp | 22 +- src/muz/pdr/pdr_farkas_learner.h | 3 + src/muz/pdr/pdr_util.h | 2 - src/qe/qe_arith.cpp | 321 +++++++++++++++++++++++++++++ src/qe/qe_arith.h | 16 ++ src/test/main.cpp | 1 + src/test/qe_arith.cpp | 64 ++++++ 7 files changed, 422 insertions(+), 7 deletions(-) create mode 100644 src/qe/qe_arith.cpp create mode 100644 src/qe/qe_arith.h create mode 100644 src/test/qe_arith.cpp diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index d7ef01aaa..b54eb0117 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -151,6 +151,11 @@ namespace pdr { public: constr(ast_manager& m) : m(m), a(m), m_ineqs(m), m_time(0) {} + void reset() { + m_ineqs.reset(); + m_coeffs.reset(); + } + /** add a multiple of constraint c to the current constr */ void add(rational const & coef, app * c) { bool is_pos = true; @@ -300,7 +305,6 @@ namespace pdr { return r; } - expr_ref extract_consequence(unsigned lo, unsigned hi) { bool is_int = is_int_sort(); app_ref zero(a.mk_numeral(rational::zero(), is_int), m); @@ -373,6 +377,7 @@ namespace pdr { farkas_learner::farkas_learner(smt_params& params, ast_manager& outer_mgr) : m_proof_params(get_proof_params(params)), m_pr(PROOF_MODE), + m_constr(0), m_combine_farkas_coefficients(true), p2o(m_pr, outer_mgr), o2p(outer_mgr, m_pr) @@ -381,6 +386,10 @@ namespace pdr { m_ctx = alloc(smt::kernel, m_pr, m_proof_params); } + farkas_learner::~farkas_learner() { + dealloc(m_constr); + } + smt_params farkas_learner::get_proof_params(smt_params& orig_params) { smt_params res(orig_params); res.m_arith_bound_prop = BP_NONE; @@ -538,11 +547,14 @@ namespace pdr { { ast_manager& m = res.get_manager(); if (m_combine_farkas_coefficients) { - constr res_c(m); - for(unsigned i = 0; i < n; ++i) { - res_c.add(coeffs[i], lits[i]); + if (!m_constr) { + m_constr = alloc(constr, m); } - res_c.get(res); + m_constr->reset(); + for (unsigned i = 0; i < n; ++i) { + m_constr->add(coeffs[i], lits[i]); + } + m_constr->get(res); } else { bool_rewriter rw(m); diff --git a/src/muz/pdr/pdr_farkas_learner.h b/src/muz/pdr/pdr_farkas_learner.h index b623c2035..546759a33 100644 --- a/src/muz/pdr/pdr_farkas_learner.h +++ b/src/muz/pdr/pdr_farkas_learner.h @@ -42,6 +42,7 @@ class farkas_learner { smt_params m_proof_params; ast_manager m_pr; scoped_ptr m_ctx; + constr* m_constr; // // true: produce a combined constraint by applying Farkas coefficients. @@ -80,6 +81,8 @@ class farkas_learner { public: farkas_learner(smt_params& params, ast_manager& m); + ~farkas_learner(); + /** All ast objects have the ast_manager which was passed as an argument to the constructor (i.e. m_outer_mgr) diff --git a/src/muz/pdr/pdr_util.h b/src/muz/pdr/pdr_util.h index 67be6751b..446bde8aa 100644 --- a/src/muz/pdr/pdr_util.h +++ b/src/muz/pdr/pdr_util.h @@ -143,8 +143,6 @@ namespace pdr { */ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml); - - /** \brief hoist non-boolean if expressions. */ diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp new file mode 100644 index 000000000..85229de44 --- /dev/null +++ b/src/qe/qe_arith.cpp @@ -0,0 +1,321 @@ +/*++ +Copyright (c) 2010 Microsoft Corporation + +Module Name: + + qe_arith.cpp + +Abstract: + + Simple projection function for real arithmetic based on Loos-W. + +Author: + + Nikolaj Bjorner (nbjorner) 2013-09-12 + +Revision History: + + +--*/ + +#include "qe_arith.h" +#include "qe_util.h" +#include "arith_decl_plugin.h" +#include "ast_pp.h" +#include "th_rewriter.h" + +namespace qe { + + class arith_project_util { + ast_manager& m; + arith_util a; + th_rewriter m_rw; + expr_ref_vector m_ineq_terms; + vector m_ineq_coeffs; + svector m_ineq_strict; + + struct cant_project {}; + + // TBD: replace by "contains_x" class. + + bool contains(app* var, expr* t) const { + ast_mark mark; + ptr_vector todo; + todo.push_back(t); + while (!todo.empty()) { + t = todo.back(); + todo.pop_back(); + if (mark.is_marked(t)) { + continue; + } + mark.mark(t, true); + if (var == t) { + return true; + } + SASSERT(is_app(t)); + app* ap = to_app(t); + todo.append(ap->get_num_args(), ap->get_args()); + } + return false; + } + + void is_linear(app* var, rational const& mul, expr* t, rational& c, expr_ref_vector& ts) { + expr* t1, *t2; + rational mul1; + if (t == var) { + c += mul; + } + else if (a.is_mul(t, t1, t2) && a.is_numeral(t1, mul1)) { + is_linear(var, mul* mul1, t2, c, ts); + } + else if (a.is_mul(t, t1, t2) && a.is_numeral(t2, mul1)) { + is_linear(var, mul* mul1, t1, c, ts); + } + else if (a.is_add(t)) { + app* ap = to_app(t); + for (unsigned i = 0; i < ap->get_num_args(); ++i) { + is_linear(var, mul, ap->get_arg(i), c, ts); + } + } + else if (a.is_sub(t, t1, t2)) { + is_linear(var, mul, t1, c, ts); + is_linear(var, -mul, t2, c, ts); + } + else if (a.is_uminus(t, t1)) { + is_linear(var, -mul, t1, c, ts); + } + else if (a.is_numeral(t, mul1)) { + ts.push_back(a.mk_numeral(mul*mul1, m.get_sort(t))); + } + else if (contains(var, t)) { + IF_VERBOSE(1, verbose_stream() << mk_pp(t, m) << "\n";); + throw cant_project(); + } + else if (mul.is_one()) { + ts.push_back(t); + } + else { + ts.push_back(a.mk_mul(a.mk_numeral(mul, m.get_sort(t)), t)); + } + } + + bool is_linear(app* var, expr* lit, rational& c, expr_ref& t, bool& is_strict) { + if (!contains(var, lit)) { + return false; + } + expr* e1, *e2; + c.reset(); + sort* s; + expr_ref_vector ts(m); + bool is_not = m.is_not(lit, lit); + rational mul(1); + if (is_not) { + mul.neg(); + } + SASSERT(!m.is_not(lit)); + if (a.is_le(lit, e1, e2) || a.is_ge(lit, e2, e1)) { + is_linear(var, mul, e1, c, ts); + is_linear(var, -mul, e2, c, ts); + s = m.get_sort(e1); + is_strict = is_not; + } + else if (a.is_lt(lit, e1, e2) || a.is_gt(lit, e2, e1)) { + is_linear(var, mul, e1, c, ts); + is_linear(var, -mul, e2, c, ts); + s = m.get_sort(e1); + is_strict = !is_not; + } + else if (m.is_eq(lit, e1, e2) && !is_not) { + is_linear(var, mul, e1, c, ts); + is_linear(var, -mul, e2, c, ts); + s = m.get_sort(e1); + is_strict = false; + } + else { + throw cant_project(); + } + if (ts.empty()) { + t = a.mk_numeral(rational(0), s); + } + else { + t = a.mk_add(ts.size(), ts.c_ptr()); + } + return true; + } + + void project(model& model, app* var, expr_ref_vector& lits) { + unsigned num_pos = 0, num_neg = 0; + expr_ref_vector new_lits(m); + for (unsigned i = 0; i < lits.size(); ++i) { + rational c(0); + expr_ref t(m); + bool is_strict; + if (is_linear(var, lits[i].get(), c, t, is_strict)) { + m_ineq_coeffs.push_back(c); + m_ineq_terms.push_back(t); + m_ineq_strict.push_back(is_strict); + if (c.is_pos()) { + ++num_pos; + } + else { + --num_neg; + } + } + else { + new_lits.push_back(lits[i].get()); + } + } + lits.reset(); + lits.append(new_lits); + if (num_pos == 0 || num_neg == 0) { + return; + } + if (num_pos < num_neg) { + unsigned max_t = find_max(model); + for (unsigned i = 0; i < m_ineq_terms.size(); ++i) { + if (i != max_t) { + if (m_ineq_coeffs[i].is_pos()) { + lits.push_back(mk_le(i, max_t)); + } + else { + lits.push_back(mk_lt(i, max_t)); + } + } + } + } + else { + unsigned min_t = find_min(model); + for (unsigned i = 0; i < m_ineq_terms.size(); ++i) { + if (i != min_t) { + if (m_ineq_coeffs[i].is_neg()) { + lits.push_back(mk_le(min_t, i)); + } + else { + lits.push_back(mk_lt(min_t, i)); + } + } + } + } + } + + unsigned find_max(model& mdl) { + return find_min_max(mdl, true); + } + + unsigned find_min(model& mdl) { + return find_min_max(mdl, false); + } + + unsigned find_min_max(model& mdl, bool do_max) { + unsigned result; + bool found = false; + rational found_val(0), r; + expr_ref val(m); + for (unsigned i = 0; i < m_ineq_terms.size(); ++i) { + rational const& ac = m_ineq_coeffs[i]; + if (ac.is_pos() && do_max) { + VERIFY(mdl.eval(m_ineq_terms[i].get(), val)); + VERIFY(a.is_numeral(val, r)); + r /= ac; + if (!found || r > found_val) { + result = i; + found_val = r; + found = true; + } + } + else if (ac.is_neg() && !do_max) { + VERIFY(mdl.eval(m_ineq_terms[i].get(), val)); + VERIFY(a.is_numeral(val, r)); + r /= abs(ac); //// review. + if (!found || r < found_val) { + result = i; + found_val = r; + found = true; + } + } + } + SASSERT(found); + return result; + } + + // ax + t <= 0 + // bx + s <= 0 + // a and b have different signs. + // Infer: a|b|x + |b|t + |a|bx + |a|s <= 0 + // e.g. |b|t + |a|s <= 0 + expr_ref mk_lt(unsigned i, unsigned j) { + rational const& ac = m_ineq_coeffs[i]; + rational const& bc = m_ineq_coeffs[j]; + SASSERT(ac.is_pos() != bc.is_pos()); + SASSERT(ac.is_neg() != bc.is_neg()); + expr* t = m_ineq_terms[i].get(); + expr* s = m_ineq_terms[j].get(); + expr_ref bt = mk_mul(abs(bc), t); + expr_ref as = mk_mul(abs(ac), s); + expr_ref ts = mk_add(bt, as); + expr* z = a.mk_numeral(rational(0), m.get_sort(t)); + expr_ref result(m); + if (m_ineq_strict[i] || m_ineq_strict[j]) { + result = a.mk_lt(ts, z); + } + else { + result = a.mk_le(ts, z); + } + return result; + } + + // ax + t <= 0 + // bx + s <= 0 + // a and b have same signs. + // encode:// t/|a| <= s/|b| + // e.g. |b|t <= |a|s + expr_ref mk_le(unsigned i, unsigned j) { + rational const& ac = m_ineq_coeffs[i]; + rational const& bc = m_ineq_coeffs[j]; + SASSERT(ac.is_pos() == bc.is_pos()); + SASSERT(ac.is_neg() == bc.is_neg()); + expr* t = m_ineq_terms[i].get(); + expr* s = m_ineq_terms[j].get(); + expr_ref bt = mk_mul(abs(bc), t); + expr_ref as = mk_mul(abs(ac), s); + if (m_ineq_strict[j] && !m_ineq_strict[i]) { + return expr_ref(a.mk_lt(bt, as), m); + } + else { + return expr_ref(a.mk_le(bt, as), m); + } + } + + + expr_ref mk_add(expr* t1, expr* t2) { + return expr_ref(a.mk_add(t1, t2), m); + } + expr_ref mk_mul(rational const& r, expr* t2) { + expr* t1 = a.mk_numeral(r, m.get_sort(t2)); + return expr_ref(a.mk_mul(t1, t2), m); + } + + public: + arith_project_util(ast_manager& m): + m(m), a(m), m_rw(m), m_ineq_terms(m) {} + + expr_ref operator()(model& model, app_ref_vector& vars, expr_ref_vector const& lits) { + expr_ref_vector result(lits); + for (unsigned i = 0; i < vars.size(); ++i) { + project(model, vars[i].get(), result); + } + vars.reset(); + expr_ref res1(m); + expr_ref tmp = qe::mk_and(result); + m_rw(tmp, res1); + return res1; + } + }; + + expr_ref arith_project(model& model, app_ref_vector& vars, expr_ref_vector const& lits) { + ast_manager& m = vars.get_manager(); + arith_project_util ap(m); + return ap(model, vars, lits); + } + +} diff --git a/src/qe/qe_arith.h b/src/qe/qe_arith.h new file mode 100644 index 000000000..230cb36f6 --- /dev/null +++ b/src/qe/qe_arith.h @@ -0,0 +1,16 @@ + +#ifndef __QE_ARITH_H_ +#define __QE_ARITH_H_ + +#include "model.h" + +namespace qe { + /** + Loos-Weispfenning model-based projection for a basic conjunction. + Lits is a vector of literals. + return vector of variables that could not be projected. + */ + expr_ref arith_project(model& model, app_ref_vector& vars, expr_ref_vector const& lits); +}; + +#endif diff --git a/src/test/main.cpp b/src/test/main.cpp index b769b20fd..333456369 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -214,6 +214,7 @@ int main(int argc, char ** argv) { TST(quant_solve); TST(rcf); TST(polynorm); + TST(qe_arith); } void initialize_mam() {} diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp new file mode 100644 index 000000000..a2789ee80 --- /dev/null +++ b/src/test/qe_arith.cpp @@ -0,0 +1,64 @@ +#include "qe_arith.h" +#include "th_rewriter.h" +#include "smt2parser.h" +#include "arith_decl_plugin.h" +#include "reg_decl_plugins.h" +#include "arith_rewriter.h" +#include "ast_pp.h" +#include "qe_util.h" +#include "smt_context.h" + + +static expr_ref parse_fml(ast_manager& m, char const* str) { + expr_ref result(m); + cmd_context ctx(false, &m); + ctx.set_ignore_check(true); + std::ostringstream buffer; + buffer << "(declare-const x Real)\n" + << "(declare-const y Real)\n" + << "(declare-const z Real)\n" + << "(declare-const a Real)\n" + << "(declare-const b Real)\n" + << "(assert " << str << ")\n"; + std::istringstream is(buffer.str()); + VERIFY(parse_smt2_commands(ctx, is)); + SASSERT(ctx.begin_assertions() != ctx.end_assertions()); + result = *ctx.begin_assertions(); + return result; +} + +static char const* example1 = "(and (<= x 3.0) (<= (* 3.0 x) y) (<= z y))"; +static char const* example2 = "(and (<= z x) (<= x 3.0) (<= (* 3.0 x) y) (<= z y))"; +static char const* example3 = "(and (<= z x) (<= x 3.0) (< (* 3.0 x) y) (<= z y))"; +static char const* example4 = "(and (<= z x) (<= x 3.0) (not (>= (* 3.0 x) y)) (<= z y))"; + +static void test(char const *ex) { + smt_params params; + params.m_model = true; + ast_manager m; + reg_decl_plugins(m); + arith_util a(m); + expr_ref fml = parse_fml(m, ex); + app_ref_vector vars(m); + expr_ref_vector lits(m); + vars.push_back(m.mk_const(symbol("x"), a.mk_real())); + qe::flatten_and(fml, lits); + + smt::context ctx(m, params); + ctx.assert_expr(fml); + lbool result = ctx.check(); + SASSERT(result == l_true); + ref md; + ctx.get_model(md); + expr_ref pr = qe::arith_project(*md, vars, lits); + + std::cout << mk_pp(fml, m) << "\n"; + std::cout << mk_pp(pr, m) << "\n"; +} + +void tst_qe_arith() { + test(example1); + test(example2); + test(example3); + test(example4); +} From 196aed785e43861064d28461f94f0d97b522c6cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Sep 2013 13:27:31 -0700 Subject: [PATCH 274/281] fixes for qe_arith Signed-off-by: Nikolaj Bjorner --- src/qe/qe_arith.cpp | 134 +++++++++++++++--------------------------- src/test/qe_arith.cpp | 5 ++ 2 files changed, 51 insertions(+), 88 deletions(-) diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 85229de44..393467cc7 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -23,6 +23,7 @@ Revision History: #include "arith_decl_plugin.h" #include "ast_pp.h" #include "th_rewriter.h" +#include "expr_functors.h" namespace qe { @@ -33,61 +34,39 @@ namespace qe { expr_ref_vector m_ineq_terms; vector m_ineq_coeffs; svector m_ineq_strict; + scoped_ptr m_var; struct cant_project {}; - // TBD: replace by "contains_x" class. - - bool contains(app* var, expr* t) const { - ast_mark mark; - ptr_vector todo; - todo.push_back(t); - while (!todo.empty()) { - t = todo.back(); - todo.pop_back(); - if (mark.is_marked(t)) { - continue; - } - mark.mark(t, true); - if (var == t) { - return true; - } - SASSERT(is_app(t)); - app* ap = to_app(t); - todo.append(ap->get_num_args(), ap->get_args()); - } - return false; - } - - void is_linear(app* var, rational const& mul, expr* t, rational& c, expr_ref_vector& ts) { + void is_linear(rational const& mul, expr* t, rational& c, expr_ref_vector& ts) { expr* t1, *t2; rational mul1; - if (t == var) { + if (t == m_var->x()) { c += mul; } else if (a.is_mul(t, t1, t2) && a.is_numeral(t1, mul1)) { - is_linear(var, mul* mul1, t2, c, ts); + is_linear(mul* mul1, t2, c, ts); } else if (a.is_mul(t, t1, t2) && a.is_numeral(t2, mul1)) { - is_linear(var, mul* mul1, t1, c, ts); + is_linear(mul* mul1, t1, c, ts); } else if (a.is_add(t)) { app* ap = to_app(t); for (unsigned i = 0; i < ap->get_num_args(); ++i) { - is_linear(var, mul, ap->get_arg(i), c, ts); + is_linear(mul, ap->get_arg(i), c, ts); } } else if (a.is_sub(t, t1, t2)) { - is_linear(var, mul, t1, c, ts); - is_linear(var, -mul, t2, c, ts); + is_linear(mul, t1, c, ts); + is_linear(-mul, t2, c, ts); } else if (a.is_uminus(t, t1)) { - is_linear(var, -mul, t1, c, ts); + is_linear(-mul, t1, c, ts); } else if (a.is_numeral(t, mul1)) { ts.push_back(a.mk_numeral(mul*mul1, m.get_sort(t))); } - else if (contains(var, t)) { + else if ((*m_var)(t)) { IF_VERBOSE(1, verbose_stream() << mk_pp(t, m) << "\n";); throw cant_project(); } @@ -99,8 +78,8 @@ namespace qe { } } - bool is_linear(app* var, expr* lit, rational& c, expr_ref& t, bool& is_strict) { - if (!contains(var, lit)) { + bool is_linear(expr* lit, rational& c, expr_ref& t, bool& is_strict) { + if (!(*m_var)(lit)) { return false; } expr* e1, *e2; @@ -114,20 +93,20 @@ namespace qe { } SASSERT(!m.is_not(lit)); if (a.is_le(lit, e1, e2) || a.is_ge(lit, e2, e1)) { - is_linear(var, mul, e1, c, ts); - is_linear(var, -mul, e2, c, ts); + is_linear( mul, e1, c, ts); + is_linear(-mul, e2, c, ts); s = m.get_sort(e1); is_strict = is_not; } else if (a.is_lt(lit, e1, e2) || a.is_gt(lit, e2, e1)) { - is_linear(var, mul, e1, c, ts); - is_linear(var, -mul, e2, c, ts); + is_linear( mul, e1, c, ts); + is_linear(-mul, e2, c, ts); s = m.get_sort(e1); is_strict = !is_not; } else if (m.is_eq(lit, e1, e2) && !is_not) { - is_linear(var, mul, e1, c, ts); - is_linear(var, -mul, e2, c, ts); + is_linear( mul, e1, c, ts); + is_linear(-mul, e2, c, ts); s = m.get_sort(e1); is_strict = false; } @@ -143,14 +122,15 @@ namespace qe { return true; } - void project(model& model, app* var, expr_ref_vector& lits) { - unsigned num_pos = 0, num_neg = 0; + void project(model& model, expr_ref_vector& lits) { + unsigned num_pos = 0; + unsigned num_neg = 0; expr_ref_vector new_lits(m); for (unsigned i = 0; i < lits.size(); ++i) { rational c(0); expr_ref t(m); bool is_strict; - if (is_linear(var, lits[i].get(), c, t, is_strict)) { + if (is_linear(lits[i].get(), c, t, is_strict)) { m_ineq_coeffs.push_back(c); m_ineq_terms.push_back(t); m_ineq_strict.push_back(is_strict); @@ -158,7 +138,7 @@ namespace qe { ++num_pos; } else { - --num_neg; + ++num_neg; } } else { @@ -170,69 +150,39 @@ namespace qe { if (num_pos == 0 || num_neg == 0) { return; } - if (num_pos < num_neg) { - unsigned max_t = find_max(model); - for (unsigned i = 0; i < m_ineq_terms.size(); ++i) { - if (i != max_t) { - if (m_ineq_coeffs[i].is_pos()) { - lits.push_back(mk_le(i, max_t)); - } - else { - lits.push_back(mk_lt(i, max_t)); - } + bool use_pos = num_pos < num_neg; + unsigned max_t = find_max(model, use_pos); + + for (unsigned i = 0; i < m_ineq_terms.size(); ++i) { + if (i != max_t) { + if (m_ineq_coeffs[i].is_pos() == use_pos) { + lits.push_back(mk_le(i, max_t)); } - } - } - else { - unsigned min_t = find_min(model); - for (unsigned i = 0; i < m_ineq_terms.size(); ++i) { - if (i != min_t) { - if (m_ineq_coeffs[i].is_neg()) { - lits.push_back(mk_le(min_t, i)); - } - else { - lits.push_back(mk_lt(min_t, i)); - } + else { + lits.push_back(mk_lt(i, max_t)); } } } } - unsigned find_max(model& mdl) { - return find_min_max(mdl, true); - } - - unsigned find_min(model& mdl) { - return find_min_max(mdl, false); - } - - unsigned find_min_max(model& mdl, bool do_max) { + unsigned find_max(model& mdl, bool do_pos) { unsigned result; bool found = false; rational found_val(0), r; expr_ref val(m); for (unsigned i = 0; i < m_ineq_terms.size(); ++i) { rational const& ac = m_ineq_coeffs[i]; - if (ac.is_pos() && do_max) { + if (ac.is_pos() == do_pos) { VERIFY(mdl.eval(m_ineq_terms[i].get(), val)); VERIFY(a.is_numeral(val, r)); - r /= ac; + r /= abs(ac); + IF_VERBOSE(1, verbose_stream() << "max: " << mk_pp(m_ineq_terms[i].get(), m) << " " << r << " " << (!found || r > found_val) << "\n";); if (!found || r > found_val) { result = i; found_val = r; found = true; } } - else if (ac.is_neg() && !do_max) { - VERIFY(mdl.eval(m_ineq_terms[i].get(), val)); - VERIFY(a.is_numeral(val, r)); - r /= abs(ac); //// review. - if (!found || r < found_val) { - result = i; - found_val = r; - found = true; - } - } } SASSERT(found); return result; @@ -300,11 +250,19 @@ namespace qe { m(m), a(m), m_rw(m), m_ineq_terms(m) {} expr_ref operator()(model& model, app_ref_vector& vars, expr_ref_vector const& lits) { + app_ref_vector new_vars(m); expr_ref_vector result(lits); for (unsigned i = 0; i < vars.size(); ++i) { - project(model, vars[i].get(), result); + m_var = alloc(contains_app, m, vars[i].get()); + try { + project(model, result); + } + catch (cant_project) { + new_vars.push_back(vars[i].get()); + } } vars.reset(); + vars.append(new_vars); expr_ref res1(m); expr_ref tmp = qe::mk_and(result); m_rw(tmp, res1); diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index a2789ee80..8d04e2489 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -17,6 +17,9 @@ static expr_ref parse_fml(ast_manager& m, char const* str) { buffer << "(declare-const x Real)\n" << "(declare-const y Real)\n" << "(declare-const z Real)\n" + << "(declare-const u Real)\n" + << "(declare-const v Real)\n" + << "(declare-const t Real)\n" << "(declare-const a Real)\n" << "(declare-const b Real)\n" << "(assert " << str << ")\n"; @@ -31,6 +34,7 @@ static char const* example1 = "(and (<= x 3.0) (<= (* 3.0 x) y) (<= z y))"; static char const* example2 = "(and (<= z x) (<= x 3.0) (<= (* 3.0 x) y) (<= z y))"; static char const* example3 = "(and (<= z x) (<= x 3.0) (< (* 3.0 x) y) (<= z y))"; static char const* example4 = "(and (<= z x) (<= x 3.0) (not (>= (* 3.0 x) y)) (<= z y))"; +static char const* example5 = "(and (<= y x) (<= z x) (<= x u) (<= x v) (<= x t))"; static void test(char const *ex) { smt_params params; @@ -61,4 +65,5 @@ void tst_qe_arith() { test(example2); test(example3); test(example4); + test(example5); } From 1741671a9cacf7ccc195e5f4232bc6899f9f3c4e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Sep 2013 13:32:35 -0700 Subject: [PATCH 275/281] update test in qe_arith Signed-off-by: Nikolaj Bjorner --- src/qe/qe_arith.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index 393467cc7..b4f1a781a 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -168,7 +168,7 @@ namespace qe { unsigned find_max(model& mdl, bool do_pos) { unsigned result; bool found = false; - rational found_val(0), r; + rational found_val(0), r, found_c; expr_ref val(m); for (unsigned i = 0; i < m_ineq_terms.size(); ++i) { rational const& ac = m_ineq_coeffs[i]; @@ -180,11 +180,15 @@ namespace qe { if (!found || r > found_val) { result = i; found_val = r; + found_c = ac; found = true; } } } SASSERT(found); + if (a.is_int(m_var->x()) && !found_c.is_one()) { + throw cant_project(); + } return result; } From 8ab04fb05b85fbd35ddd75be6ec6bd616cf40c21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Sep 2013 15:27:09 -0700 Subject: [PATCH 276/281] testing qe_arith Signed-off-by: Nikolaj Bjorner --- src/qe/qe_arith.cpp | 53 +++++++++++++++++++++++---------- src/qe/qe_arith.h | 2 ++ src/test/qe_arith.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 107 insertions(+), 16 deletions(-) diff --git a/src/qe/qe_arith.cpp b/src/qe/qe_arith.cpp index b4f1a781a..360c2ac8c 100644 --- a/src/qe/qe_arith.cpp +++ b/src/qe/qe_arith.cpp @@ -67,7 +67,7 @@ namespace qe { ts.push_back(a.mk_numeral(mul*mul1, m.get_sort(t))); } else if ((*m_var)(t)) { - IF_VERBOSE(1, verbose_stream() << mk_pp(t, m) << "\n";); + IF_VERBOSE(1, verbose_stream() << "can't project:" << mk_pp(t, m) << "\n";); throw cant_project(); } else if (mul.is_one()) { @@ -111,6 +111,7 @@ namespace qe { is_strict = false; } else { + IF_VERBOSE(1, verbose_stream() << "can't project:" << mk_pp(lit, m) << "\n";); throw cant_project(); } if (ts.empty()) { @@ -125,6 +126,9 @@ namespace qe { void project(model& model, expr_ref_vector& lits) { unsigned num_pos = 0; unsigned num_neg = 0; + m_ineq_terms.reset(); + m_ineq_coeffs.reset(); + m_ineq_strict.reset(); expr_ref_vector new_lits(m); for (unsigned i = 0; i < lits.size(); ++i) { rational c(0); @@ -134,12 +138,16 @@ namespace qe { m_ineq_coeffs.push_back(c); m_ineq_terms.push_back(t); m_ineq_strict.push_back(is_strict); - if (c.is_pos()) { + if (c.is_zero()) { + m_rw(lits[i].get(), t); + new_lits.push_back(t); + } + else if (c.is_pos()) { ++num_pos; } else { ++num_neg; - } + } } else { new_lits.push_back(lits[i].get()); @@ -208,14 +216,15 @@ namespace qe { expr_ref as = mk_mul(abs(ac), s); expr_ref ts = mk_add(bt, as); expr* z = a.mk_numeral(rational(0), m.get_sort(t)); - expr_ref result(m); + expr_ref result1(m), result2(m); if (m_ineq_strict[i] || m_ineq_strict[j]) { - result = a.mk_lt(ts, z); + result1 = a.mk_lt(ts, z); } else { - result = a.mk_le(ts, z); + result1 = a.mk_le(ts, z); } - return result; + m_rw(result1, result2); + return result2; } // ax + t <= 0 @@ -232,12 +241,15 @@ namespace qe { expr* s = m_ineq_terms[j].get(); expr_ref bt = mk_mul(abs(bc), t); expr_ref as = mk_mul(abs(ac), s); + expr_ref result1(m), result2(m); if (m_ineq_strict[j] && !m_ineq_strict[i]) { - return expr_ref(a.mk_lt(bt, as), m); + result1 = a.mk_lt(bt, as); } else { - return expr_ref(a.mk_le(bt, as), m); + result1 = a.mk_le(bt, as); } + m_rw(result1, result2); + return result2; } @@ -257,20 +269,23 @@ namespace qe { app_ref_vector new_vars(m); expr_ref_vector result(lits); for (unsigned i = 0; i < vars.size(); ++i) { - m_var = alloc(contains_app, m, vars[i].get()); + app* v = vars[i].get(); + m_var = alloc(contains_app, m, v); try { project(model, result); + TRACE("qe", tout << "projected: " << mk_pp(v, m) << " "; + for (unsigned i = 0; i < result.size(); ++i) { + tout << mk_pp(result[i].get(), m) << "\n"; + }); } catch (cant_project) { - new_vars.push_back(vars[i].get()); + IF_VERBOSE(1, verbose_stream() << "can't project:" << mk_pp(v, m) << "\n";); + new_vars.push_back(v); } } vars.reset(); vars.append(new_vars); - expr_ref res1(m); - expr_ref tmp = qe::mk_and(result); - m_rw(tmp, res1); - return res1; + return qe::mk_and(result); } }; @@ -280,4 +295,12 @@ namespace qe { return ap(model, vars, lits); } + expr_ref arith_project(model& model, app_ref_vector& vars, expr* fml) { + ast_manager& m = vars.get_manager(); + arith_project_util ap(m); + expr_ref_vector lits(m); + qe::flatten_and(fml, lits); + return ap(model, vars, lits); + } + } diff --git a/src/qe/qe_arith.h b/src/qe/qe_arith.h index 230cb36f6..c8f7e8b8d 100644 --- a/src/qe/qe_arith.h +++ b/src/qe/qe_arith.h @@ -11,6 +11,8 @@ namespace qe { return vector of variables that could not be projected. */ expr_ref arith_project(model& model, app_ref_vector& vars, expr_ref_vector const& lits); + + expr_ref arith_project(model& model, app_ref_vector& vars, expr* fml); }; #endif diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index 8d04e2489..d54ac1ccf 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -1,4 +1,5 @@ #include "qe_arith.h" +#include "qe.h" #include "th_rewriter.h" #include "smt2parser.h" #include "arith_decl_plugin.h" @@ -7,7 +8,7 @@ #include "ast_pp.h" #include "qe_util.h" #include "smt_context.h" - +#include "expr_abstract.h" static expr_ref parse_fml(ast_manager& m, char const* str) { expr_ref result(m); @@ -36,6 +37,15 @@ static char const* example3 = "(and (<= z x) (<= x 3.0) (< (* 3.0 x) y) (<= z y) static char const* example4 = "(and (<= z x) (<= x 3.0) (not (>= (* 3.0 x) y)) (<= z y))"; static char const* example5 = "(and (<= y x) (<= z x) (<= x u) (<= x v) (<= x t))"; +static char const* example6 = "(and (<= 0 (+ x z))\ + (>= y x) \ + (<= y x)\ + (<= (- u y) 0.0)\ + (>= x (+ v z))\ + (>= x 0.0)\ + (<= x 1.0))"; + + static void test(char const *ex) { smt_params params; params.m_model = true; @@ -58,9 +68,65 @@ static void test(char const *ex) { std::cout << mk_pp(fml, m) << "\n"; std::cout << mk_pp(pr, m) << "\n"; + +} + +static void test2(char const *ex) { + smt_params params; + params.m_model = true; + ast_manager m; + reg_decl_plugins(m); + arith_util a(m); + expr_ref fml = parse_fml(m, ex); + app_ref_vector vars(m); + expr_ref_vector lits(m); + vars.push_back(m.mk_const(symbol("x"), a.mk_real())); + vars.push_back(m.mk_const(symbol("y"), a.mk_real())); + vars.push_back(m.mk_const(symbol("z"), a.mk_real())); + qe::flatten_and(fml, lits); + + smt::context ctx(m, params); + ctx.push(); + ctx.assert_expr(fml); + lbool result = ctx.check(); + SASSERT(result == l_true); + ref md; + ctx.get_model(md); + ctx.pop(1); + + std::cout << mk_pp(fml, m) << "\n"; + + expr_ref pr2(m), fml2(m); + expr_ref_vector bound(m); + ptr_vector sorts; + svector names; + for (unsigned i = 0; i < vars.size(); ++i) { + bound.push_back(vars[i].get()); + names.push_back(vars[i]->get_decl()->get_name()); + sorts.push_back(m.get_sort(vars[i].get())); + } + expr_abstract(m, 0, 3, bound.c_ptr(), fml, fml2); + fml2 = m.mk_exists(3, sorts.c_ptr(), names.c_ptr(), fml2); + qe::expr_quant_elim qe(m, params); + expr_ref pr1 = qe::arith_project(*md, vars, lits); + qe(m.mk_true(), fml2, pr2); + std::cout << mk_pp(pr1, m) << "\n"; + std::cout << mk_pp(pr2, m) << "\n"; + + expr_ref npr2(m); + npr2 = m.mk_not(pr2); + ctx.push(); + ctx.assert_expr(pr1); + ctx.assert_expr(npr2); + VERIFY(l_false == ctx.check()); + ctx.pop(1); + + } void tst_qe_arith() { + test2(example6); + return; test(example1); test(example2); test(example3); From 10e203da43ba94426e5448c2e1bb9cb90dffa678 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 12 Sep 2013 20:22:26 -0700 Subject: [PATCH 277/281] remove some dependencies on parameter file Signed-off-by: Nikolaj Bjorner --- src/muz/base/dl_context.cpp | 7 +++++++ src/muz/base/dl_context.h | 6 ++++++ src/muz/transforms/dl_mk_bit_blast.cpp | 2 +- src/muz/transforms/dl_mk_karr_invariants.cpp | 3 +-- src/muz/transforms/dl_mk_magic_symbolic.cpp | 3 +-- src/muz/transforms/dl_mk_quantifier_abstraction.cpp | 3 +-- src/muz/transforms/dl_mk_quantifier_instantiation.cpp | 4 +--- src/muz/transforms/dl_mk_scale.cpp | 2 +- 8 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 7eed67ff0..f08efb00a 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -289,6 +289,13 @@ namespace datalog { bool context::magic_sets_for_queries() const { return m_params->magic_sets_for_queries(); } bool context::eager_emptiness_checking() const { return m_params->eager_emptiness_checking(); } + bool context::bit_blast() const { return m_params->bit_blast(); } + bool context::karr() const { return m_params->karr(); } + bool context::scale() const { return m_params->scale(); } + bool context::magic() const { return m_params->magic(); } + bool context::quantify_arrays() const { return m_params->quantify_arrays(); } + bool context::instantiate_quantifiers() const { return m_params->instantiate_quantifiers(); } + void context::register_finite_sort(sort * s, sort_kind k) { m_pinned.push_back(s); diff --git a/src/muz/base/dl_context.h b/src/muz/base/dl_context.h index 2eb9e0652..5eef04202 100644 --- a/src/muz/base/dl_context.h +++ b/src/muz/base/dl_context.h @@ -262,6 +262,12 @@ namespace datalog { bool explanations_on_relation_level() const; bool magic_sets_for_queries() const; bool eager_emptiness_checking() const; + bool bit_blast() const; + bool karr() const; + bool scale() const; + bool magic() const; + bool quantify_arrays() const; + bool instantiate_quantifiers() const; void register_finite_sort(sort * s, sort_kind k); diff --git a/src/muz/transforms/dl_mk_bit_blast.cpp b/src/muz/transforms/dl_mk_bit_blast.cpp index 08f295ff4..91481ed5a 100644 --- a/src/muz/transforms/dl_mk_bit_blast.cpp +++ b/src/muz/transforms/dl_mk_bit_blast.cpp @@ -254,7 +254,7 @@ namespace datalog { rule_set * operator()(rule_set const & source) { // TODO pc - if (!m_context.get_params().bit_blast()) { + if (!m_context.bit_blast()) { return 0; } rule_manager& rm = m_context.get_rule_manager(); diff --git a/src/muz/transforms/dl_mk_karr_invariants.cpp b/src/muz/transforms/dl_mk_karr_invariants.cpp index b4ab66bc2..ced0d39f4 100644 --- a/src/muz/transforms/dl_mk_karr_invariants.cpp +++ b/src/muz/transforms/dl_mk_karr_invariants.cpp @@ -39,7 +39,6 @@ Revision History: #include"dl_mk_karr_invariants.h" #include"dl_mk_backwards.h" #include"dl_mk_loop_counter.h" -#include"fixedpoint_params.hpp" namespace datalog { @@ -197,7 +196,7 @@ namespace datalog { } rule_set * mk_karr_invariants::operator()(rule_set const & source) { - if (!m_ctx.get_params().karr()) { + if (!m_ctx.karr()) { return 0; } rule_set::iterator it = source.begin(), end = source.end(); diff --git a/src/muz/transforms/dl_mk_magic_symbolic.cpp b/src/muz/transforms/dl_mk_magic_symbolic.cpp index 57490466c..1d269cff0 100644 --- a/src/muz/transforms/dl_mk_magic_symbolic.cpp +++ b/src/muz/transforms/dl_mk_magic_symbolic.cpp @@ -54,7 +54,6 @@ Revision History: #include"dl_mk_magic_symbolic.h" #include"dl_context.h" -#include"fixedpoint_params.hpp" namespace datalog { @@ -68,7 +67,7 @@ namespace datalog { mk_magic_symbolic::~mk_magic_symbolic() { } rule_set * mk_magic_symbolic::operator()(rule_set const & source) { - if (!m_ctx.get_params().magic()) { + if (!m_ctx.magic()) { return 0; } context& ctx = source.get_context(); diff --git a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp index e686495e9..0ad4d61ab 100644 --- a/src/muz/transforms/dl_mk_quantifier_abstraction.cpp +++ b/src/muz/transforms/dl_mk_quantifier_abstraction.cpp @@ -300,8 +300,7 @@ namespace datalog { } rule_set * mk_quantifier_abstraction::operator()(rule_set const & source) { - TRACE("dl", tout << "quantify " << source.get_num_rules() << " " << m_ctx.get_params().quantify_arrays() << "\n";); - if (!m_ctx.get_params().quantify_arrays()) { + if (!m_ctx.quantify_arrays()) { return 0; } unsigned sz = source.get_num_rules(); diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index ebb9310a4..9c55ca658 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -26,7 +26,6 @@ Revision History: #include "dl_mk_quantifier_instantiation.h" #include "dl_context.h" #include "pattern_inference.h" -#include "fixedpoint_params.hpp" namespace datalog { @@ -251,8 +250,7 @@ namespace datalog { } rule_set * mk_quantifier_instantiation::operator()(rule_set const & source) { - TRACE("dl", tout << m_ctx.get_params().instantiate_quantifiers() << "\n";); - if (!m_ctx.get_params().instantiate_quantifiers()) { + if (!m_ctx.instantiate_quantifiers()) { return 0; } bool has_quantifiers = false; diff --git a/src/muz/transforms/dl_mk_scale.cpp b/src/muz/transforms/dl_mk_scale.cpp index 9618db88e..9ada7be20 100644 --- a/src/muz/transforms/dl_mk_scale.cpp +++ b/src/muz/transforms/dl_mk_scale.cpp @@ -115,7 +115,7 @@ namespace datalog { } rule_set * mk_scale::operator()(rule_set const & source) { - if (!m_ctx.get_params().scale()) { + if (!m_ctx.scale()) { return 0; } rule_manager& rm = source.get_rule_manager(); From 419f99c329dfcc628b05e53c6f5d463fe4701c26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Sep 2013 15:30:56 -0700 Subject: [PATCH 278/281] fix bug found by Ethan: fresh values for bit-vectors loops if the domain of bit-vectors is truly small Signed-off-by: Nikolaj Bjorner --- src/ast/datatype_decl_plugin.cpp | 3 ++- src/muz/pdr/pdr_farkas_learner.cpp | 2 -- src/smt/proto_model/value_factory.h | 14 ++++++++++++++ src/test/qe_arith.cpp | 4 ++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 0714af28b..ee3271b9b 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -84,7 +84,8 @@ class datatype_decl { ptr_vector m_constructors; public: datatype_decl(const symbol & n, unsigned num_constructors, constructor_decl * const * constructors): - m_name(n), m_constructors(num_constructors, constructors) {} + m_name(n), m_constructors(num_constructors, constructors) { + } ~datatype_decl() { std::for_each(m_constructors.begin(), m_constructors.end(), delete_proc()); } diff --git a/src/muz/pdr/pdr_farkas_learner.cpp b/src/muz/pdr/pdr_farkas_learner.cpp index b54eb0117..7c38bf86f 100644 --- a/src/muz/pdr/pdr_farkas_learner.cpp +++ b/src/muz/pdr/pdr_farkas_learner.cpp @@ -212,8 +212,6 @@ namespace pdr { // partition inequalities into variable disjoint sets. void partition_ineqs() { - m_roots.reset(); - m_size.reset(); m_reps.reset(); m_his.reset(); ++m_time; diff --git a/src/smt/proto_model/value_factory.h b/src/smt/proto_model/value_factory.h index b7df55f43..115a01345 100644 --- a/src/smt/proto_model/value_factory.h +++ b/src/smt/proto_model/value_factory.h @@ -180,10 +180,24 @@ public: value_set * set = get_value_set(s); bool is_new = false; expr * result = 0; + sort_info* s_info = s->get_info(); + sort_size const* sz = s_info?&s_info->get_num_elements():0; + bool has_max = false; + Number max_size; + if (sz && sz->is_finite()) { + if (sz->size() < UINT_MAX) { + unsigned usz = static_cast(sz->size()); + max_size = Number(usz); + has_max = true; + } + } Number & next = set->m_next; while (!is_new) { result = mk_value(next, s, is_new); next++; + if (has_max && next >= max_size) { + return 0; + } } SASSERT(result != 0); return result; diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index d54ac1ccf..e25abc48c 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -105,8 +105,8 @@ static void test2(char const *ex) { names.push_back(vars[i]->get_decl()->get_name()); sorts.push_back(m.get_sort(vars[i].get())); } - expr_abstract(m, 0, 3, bound.c_ptr(), fml, fml2); - fml2 = m.mk_exists(3, sorts.c_ptr(), names.c_ptr(), fml2); + expr_abstract(m, 0, bound.size(), bound.c_ptr(), fml, fml2); + fml2 = m.mk_exists(boud.size(), sorts.c_ptr(), names.c_ptr(), fml2); qe::expr_quant_elim qe(m, params); expr_ref pr1 = qe::arith_project(*md, vars, lits); qe(m.mk_true(), fml2, pr2); From be044f42c3e15614a809a1ac3064fe1a6ad70a4e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Sep 2013 04:24:20 -0700 Subject: [PATCH 279/281] Fix build of test Signed-off-by: Nikolaj Bjorner --- src/test/qe_arith.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/qe_arith.cpp b/src/test/qe_arith.cpp index e25abc48c..8b6577b3f 100644 --- a/src/test/qe_arith.cpp +++ b/src/test/qe_arith.cpp @@ -106,7 +106,7 @@ static void test2(char const *ex) { sorts.push_back(m.get_sort(vars[i].get())); } expr_abstract(m, 0, bound.size(), bound.c_ptr(), fml, fml2); - fml2 = m.mk_exists(boud.size(), sorts.c_ptr(), names.c_ptr(), fml2); + fml2 = m.mk_exists(bound.size(), sorts.c_ptr(), names.c_ptr(), fml2); qe::expr_quant_elim qe(m, params); expr_ref pr1 = qe::arith_project(*md, vars, lits); qe(m.mk_true(), fml2, pr2); From 21b27cd2d1322005292a055927e085e3d2deba92 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Sep 2013 04:37:05 -0700 Subject: [PATCH 280/281] patching crash in data-type factory when fresh values are not produced Signed-off-by: Nikolaj Bjorner --- src/smt/proto_model/datatype_factory.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/smt/proto_model/datatype_factory.cpp b/src/smt/proto_model/datatype_factory.cpp index 5be802714..a45b53155 100644 --- a/src/smt/proto_model/datatype_factory.cpp +++ b/src/smt/proto_model/datatype_factory.cpp @@ -67,6 +67,7 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) { value_set * set = get_value_set(s); if (set->empty()) { expr * val = get_some_value(s); + SASSERT(val); if (m_util.is_recursive(s)) m_last_fresh_value.insert(s, val); return val; @@ -185,10 +186,16 @@ expr * datatype_factory::get_fresh_value(sort * s) { if (!found_sibling && m_util.is_datatype(s_arg) && m_util.are_siblings(s, s_arg)) { found_sibling = true; expr * maybe_new_arg = get_almost_fresh_value(s_arg); + if (!maybe_new_arg) { + maybe_new_arg = m_model.get_some_value(s_arg); + found_sibling = false; + } + SASSERT(maybe_new_arg); args.push_back(maybe_new_arg); } else { expr * some_arg = m_model.get_some_value(s_arg); + SASSERT(some_arg); args.push_back(some_arg); } } From c54929e59f7cbeaaa25f64c47cb78e5f4a6d6906 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 15 Sep 2013 04:52:21 -0700 Subject: [PATCH 281/281] cycle through domain size before giving up Signed-off-by: Nikolaj Bjorner --- src/smt/proto_model/value_factory.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/smt/proto_model/value_factory.h b/src/smt/proto_model/value_factory.h index 115a01345..5bd0a1f75 100644 --- a/src/smt/proto_model/value_factory.h +++ b/src/smt/proto_model/value_factory.h @@ -184,18 +184,16 @@ public: sort_size const* sz = s_info?&s_info->get_num_elements():0; bool has_max = false; Number max_size; - if (sz && sz->is_finite()) { - if (sz->size() < UINT_MAX) { - unsigned usz = static_cast(sz->size()); - max_size = Number(usz); - has_max = true; - } + if (sz && sz->is_finite() && sz->size() < UINT_MAX) { + unsigned usz = static_cast(sz->size()); + max_size = Number(usz); + has_max = true; } Number & next = set->m_next; while (!is_new) { result = mk_value(next, s, is_new); next++; - if (has_max && next >= max_size) { + if (has_max && next > max_size + set->m_next) { return 0; } }