From c0895e5548adca97e50624d527f9a7a68a2dcb86 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 31 May 2013 17:48:19 -0700 Subject: [PATCH] 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();); }