From dbc1a84d6a4efd828368384917d4e3758d477ba7 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 15 Dec 2015 18:36:01 +0000 Subject: [PATCH 01/87] fix warning with MSVC++ 64 --- src/smt/theory_seq.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 63ac0fbe8..641d5e444 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -250,7 +250,7 @@ bool theory_seq::find_branch_candidate(expr* l, ptr_vector const& rs) { } zstring s; if (m_util.str.is_string(rs[j], s)) { - for (size_t k = 1; k < s.length(); ++k) { + for (unsigned k = 1; k < s.length(); ++k) { v = m_util.str.mk_string(s.extract(0, k)); if (v0) v = m_util.str.mk_concat(v0, v); if (assume_equality(l, v)) { From ee0dbf34f0d1bbded0512aef5168ea8c92e30df0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 16 Dec 2015 00:49:06 +0200 Subject: [PATCH 02/87] add completion (introducing negative root function symbols) to address regression introduced when fixing unsound handling of negative roots Signed-off-by: Nikolaj Bjorner --- src/muz/pdr/pdr_context.cpp | 1 - src/tactic/arith/purify_arith_tactic.cpp | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index ded7c14c2..b3648f38d 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -1158,7 +1158,6 @@ namespace pdr { while (!todo.empty()) { model_node* n = todo.back(); model* md = 0; - ast_manager& m = n->pt().get_manager(); if (!n->get_model_ptr()) { if (models.find(n->state(), md)) { TRACE("pdr", tout << n->state() << "\n";); diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 47f7a5576..a41c6939e 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -366,7 +366,7 @@ struct purify_arith_proc { push_cnstr(EQ(x, u().mk_power(k, u().mk_numeral(n, false)))); push_cnstr_pr(result_pr); } - else if (complete()) { + else { SASSERT(n.is_even()); // (^ x (/ 1 n)) --> k | x >= 0 implies (x = k^n and k >= 0), x < 0 implies k = neg-root(x, n) // when n is even @@ -379,9 +379,9 @@ struct purify_arith_proc { EQ(k, u().mk_neg_root(x, u().mk_numeral(n, false))))); push_cnstr_pr(result_pr); } - else { - return BR_FAILED; - } +// else { +// return BR_FAILED; +// } } else { // root not supported for integers. From 1cc2385fd2ce6ea5092c6374d0db4bfafa3610f2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 17 Dec 2015 12:33:45 +0000 Subject: [PATCH 03/87] typo --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index df8cae237..46e8b6826 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -720,7 +720,7 @@ def parse_options(): if not PYTHON_PACKAGE_DIR.startswith(PREFIX): print(("Warning: The detected Python package directory (%s)" " does not live under the installation prefix (%s)" - ". This would lead to a broken Python installation." + ". This would lead to a broken Python installation. " "Use --pypkgdir= to change the Python package directory") % (PYTHON_PACKAGE_DIR, PREFIX)) if IS_OSX and PYTHON_PACKAGE_DIR.startswith('/Library/'): From 0fe1e3248f02eb25b203229ca27e46e7d8aede6a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 17 Dec 2015 12:47:24 +0000 Subject: [PATCH 04/87] .NET build fix --- scripts/mk_util.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index df8cae237..ff45b32d8 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1568,7 +1568,6 @@ class DotNetDLLComponent(Component): def mk_win_dist(self, build_path, dist_path): if is_dotnet_enabled(): - # Assuming all .NET dlls should be in the distribution mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR)) shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name), '%s.dll' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) @@ -1578,11 +1577,13 @@ class DotNetDLLComponent(Component): shutil.copy('%s.pdb' % os.path.join(build_path, self.dll_name), '%s.pdb' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) - - def mk_unix_dist(self, build_path, dist_path): - # Do nothing - return + if is_dotnet_enabled(): + mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR)) + shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name), + '%s.dll' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) + shutil.copy('%s.xml' % os.path.join(build_path, self.dll_name), + '%s.xml' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name)) def mk_install_deps(self, out): if not is_dotnet_enabled(): From ed1e8b73edeb170fcdbf2eb751fe16ddc16de46d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 17 Dec 2015 17:39:23 +0000 Subject: [PATCH 05/87] formatting --- src/api/api_fpa.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index daef12d20..3987ca23d 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -939,7 +939,7 @@ extern "C" { } else if (!mpfm.is_regular(val)) { SET_ERROR_CODE(Z3_INVALID_ARG) - return ""; + return ""; } unsigned sbits = val.get().get_sbits(); scoped_mpq q(mpqm); @@ -992,7 +992,7 @@ extern "C" { } else if (!mpfm.is_normal(val) && !mpfm.is_denormal(val)) { SET_ERROR_CODE(Z3_INVALID_ARG) - return ""; + return ""; } mpf_exp_t exp = mpfm.exp_normalized(val); std::stringstream ss; From c2ab9b72dc7a30f9e8f2078d44d29f38771c9cfa Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 18 Dec 2015 18:43:38 +0000 Subject: [PATCH 06/87] resource-limit related fixes in src/test --- src/test/algebraic.cpp | 118 ++++++----- src/test/hilbert_basis.cpp | 102 +++++---- src/test/interval.cpp | 219 ++++++++++--------- src/test/karr.cpp | 30 +-- src/test/nlsat.cpp | 25 ++- src/test/polynomial.cpp | 295 ++++++++++++++------------ src/test/polynomial_factorization.cpp | 189 +++++++++-------- src/test/rcf.cpp | 13 +- src/test/simplex.cpp | 14 +- src/test/trigo.cpp | 34 +-- src/test/upolynomial.cpp | 202 ++++++++++-------- 11 files changed, 672 insertions(+), 569 deletions(-) diff --git a/src/test/algebraic.cpp b/src/test/algebraic.cpp index 7c0fb4a95..af7270825 100644 --- a/src/test/algebraic.cpp +++ b/src/test/algebraic.cpp @@ -19,35 +19,37 @@ Notes: #include"algebraic_numbers.h" #include"polynomial_var2value.h" #include"mpbq.h" +#include"rlimit.h" static void display_anums(std::ostream & out, scoped_anum_vector const & rs) { out << "numbers in decimal:\n"; algebraic_numbers::manager & m = rs.m(); for (unsigned i = 0; i < rs.size(); i++) { - m.display_decimal(out, rs[i], 10); + m.display_decimal(out, rs[i], 10); out << "\n"; } out << "numbers as root objects\n"; for (unsigned i = 0; i < rs.size(); i++) { - m.display_root(out, rs[i]); + m.display_root(out, rs[i]); out << "\n"; - } + } out << "numbers as intervals\n"; for (unsigned i = 0; i < rs.size(); i++) { - m.display_interval(out, rs[i]); + m.display_interval(out, rs[i]); out << "\n"; - } + } } static void tst1() { + reslimit rl; unsynch_mpq_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); polynomial_ref p(m); p = 3*x - 2; - algebraic_numbers::manager am(nm); + algebraic_numbers::manager am(rl, nm); scoped_anum_vector rs1(am); std::cout << "p: " << p << "\n"; am.isolate_roots(p, rs1); @@ -69,16 +71,16 @@ static void tst1() { nm.set(q, 1, 3); scoped_anum aq(am); am.set(aq, q); // create algebraic number representing 1/3 - + am.add(sqrt2, aq, aq); - std::cout << "sqrt(2) + 1/3: "; - am.display_decimal(std::cout, aq, 10); std::cout << " "; am.display_interval(std::cout, aq); + std::cout << "sqrt(2) + 1/3: "; + am.display_decimal(std::cout, aq, 10); std::cout << " "; am.display_interval(std::cout, aq); std::cout << " "; am.display_root(std::cout, aq); std::cout << "\n"; - am.set(aq, q); + am.set(aq, q); am.add(rs1[0], aq, aq); - std::cout << "-sqrt(2) + 1/3: "; - am.display_decimal(std::cout, aq, 10); std::cout << " "; am.display_interval(std::cout, aq); + std::cout << "-sqrt(2) + 1/3: "; + am.display_decimal(std::cout, aq, 10); std::cout << " "; am.display_interval(std::cout, aq); std::cout << " "; am.display_root(std::cout, aq); std::cout << "\n"; p = ((x^5) - x - 1)*(x-1)*(x-2); @@ -92,7 +94,7 @@ static void tst1() { am.set(gauss, rs1[1]); std::cout << "compare(" << sqrt2 << ", " << gauss << "): " << am.compare(sqrt2, gauss) << "\n"; - + statistics st; am.collect_statistics(st); st.display_smt2(std::cout); @@ -103,7 +105,7 @@ static void tst1() { am.isolate_roots(p, rs1); display_anums(std::cout, rs1); SASSERT(rs1.size() == 4); - + scoped_anum hidden_sqrt2(am); am.set(hidden_sqrt2, rs1[2]); @@ -116,7 +118,7 @@ static void tst1() { SASSERT(is_int(power(sqrt2, 4))); SASSERT(power(sqrt2, 4) == 4); - + scoped_anum sqrt2_gauss(am); am.add(sqrt2, gauss, sqrt2_gauss); std::cout << "sqrt2 + gauss: " << sqrt2_gauss << " "; am.display_root(std::cout, sqrt2_gauss); std::cout << "\n"; @@ -151,22 +153,22 @@ static void tst1() { am.mul(tmp, sqrt2, tmp); std::cout << "sqrt(2)*4*(1/sqrt2): " << tmp << " " << root_obj_pp(tmp) << "\n"; std::cout << "is_int(sqrt(2)*4*(1/sqrt2)): " << am.is_int(tmp) << ", after is-int: " << tmp << "\n"; - + p = (998*x - 1414)*((x^2) - 15); std::cout << "p: " << p << "\n"; rs1.reset(); am.isolate_roots(p, rs1); - + std::cout << "is-rational(sqrt2): " << am.is_rational(sqrt2) << "\n"; - + scoped_anum qr(am); am.set(qr, rs1[1]); - + std::cout << "qr: " << root_obj_pp(qr); std::cout << ", is-rational: " << am.is_rational(qr) << ", val: " << root_obj_pp(qr) << "\n"; return; - + std::cout << "compare(" << sqrt2 << ", " << gauss << "): " << am.compare(sqrt2, gauss) << "\n"; p = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225; @@ -216,25 +218,26 @@ void tst_mpbq_root() { mpbq_manager bqm(qm); // scoped_mpbq q(bqm); // q.set(q1, 1.4142135 , 7); - + } static void tst_wilkinson() { // Test Wilkinson Polynomial + reslimit rl; unsynch_mpq_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); polynomial_ref p(m); for (int i = 1; i <= 20; i++) { - if (i > 1) + if (i > 1) p = p*(x - i); - else + else p = (x - i); } std::cout << "Wilkinson's polynomial: " << p << "\n"; - algebraic_numbers::manager am(nm); + algebraic_numbers::manager am(rl, nm); scoped_anum_vector rs1(am); std::cout << "p: " << p << "\n"; am.isolate_roots(p, rs1); @@ -246,9 +249,10 @@ static void tst_wilkinson() { } static void tst_dejan() { + reslimit rl; unsynch_mpq_manager qm; - algebraic_numbers::manager am(qm); - + algebraic_numbers::manager am(rl, qm); + scoped_anum two101(am); am.set(two101, 2); am.root(two101, 11, two101); @@ -256,7 +260,7 @@ static void tst_dejan() { scoped_anum two103(am); am.set(two103, 2); am.root(two103, 7, two103); - + std::cout << "two101: " << two101 << " " << root_obj_pp(two101) << std::endl; std::cout << "two103: " << two103 << " " << root_obj_pp(two103) << std::endl; @@ -332,9 +336,10 @@ static void tst_eval_sign(polynomial_ref const & p, anum_manager & am, static void tst_eval_sign() { enable_trace("anum_eval_sign"); + reslimit rl; unsynch_mpq_manager qm; - polynomial::manager pm(qm); - algebraic_numbers::manager am(qm); + polynomial::manager pm(rl, qm); + algebraic_numbers::manager am(rl, qm); polynomial_ref x0(pm); polynomial_ref x1(pm); polynomial_ref x2(pm); @@ -351,7 +356,7 @@ static void tst_eval_sign() { am.set(v1, 1); am.set(v0, -3); tst_eval_sign(p, am, 0, v0, 1, v1, 2, v2, -1); - + am.set(v0, 2); am.root(v0, 2, v0); am.set(v1, 0); @@ -412,9 +417,10 @@ static void tst_isolate_roots(polynomial_ref const & p, anum_manager & am, static void tst_isolate_roots() { enable_trace("isolate_roots"); + reslimit rl; unsynch_mpq_manager qm; - polynomial::manager pm(qm); - algebraic_numbers::manager am(qm); + polynomial::manager pm(rl, qm); + algebraic_numbers::manager am(rl, qm); polynomial_ref x0(pm); polynomial_ref x1(pm); polynomial_ref x2(pm); @@ -423,7 +429,7 @@ static void tst_isolate_roots() { x1 = pm.mk_polynomial(pm.mk_var()); x2 = pm.mk_polynomial(pm.mk_var()); x3 = pm.mk_polynomial(pm.mk_var()); - + polynomial_ref p(pm); p = x3*x1 + 1; @@ -432,44 +438,44 @@ static void tst_isolate_roots() { tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); am.set(v1, 1); - tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); + tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); am.set(v1, 2); am.root(v1, 2, v1); - tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); - + tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); + p = (x1 + x2)*x3 + 1; am.set(v2, v1); - tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); - + tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); + p = (x1 + x2)*x3 + x1*x2 + 2; - tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); + tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); p = (x1 + x2)*(x3^3) + x1*x2 + 2; - tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); + tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); p = (x1 + x2)*(x3^2) - x1*x2 - 2; - tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); - + tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); + p = x0*(x1 + x2)*(x3^2) - x0*x1*x2 - 2; - tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); + tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); p = (x1 - x2)*x3 + x1*x2 - 2; - tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); + tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); p = (x1 - x2)*(x3^3) + x1*x2 - 2; - tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); - + tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); + p = (x3 - x0)*(x3 - x0 - x1); am.set(v0, 2); am.root(v0, 2, v0); // x2 -> sqrt(2) am.set(v1, 3); am.root(v1, 2, v1); // x1 -> sqrt(3) am.reset(v2); - tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); - + tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); + p = (x3 - x0)*((x3 - x0 - x1)^2); - tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); + tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); p = (x3 - x0)*(x3 - 2)*((x3 - 1)^2)*(x3 - x1); tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2); @@ -485,7 +491,8 @@ static void pp(polynomial_ref const & p, polynomial::var x) { static void ex1() { unsynch_mpq_manager qm; - polynomial::manager pm(qm); + reslimit rl; + polynomial::manager pm(rl, qm); polynomial_ref x(pm); polynomial_ref a(pm); polynomial_ref b(pm); @@ -508,7 +515,7 @@ static void ex1() { std::cout << "d: " << d << "\n"; std::cout << "h3: "; pp(h3, 0); std::cout << "\n"; - algebraic_numbers::manager am(qm); + algebraic_numbers::manager am(rl, qm); scoped_anum v1(am), v2(am); am.set(v1, 2); am.root(v1, 3, v1); @@ -542,8 +549,9 @@ static void ex1() { } static void tst_root() { + reslimit rl; unsynch_mpq_manager qm; - algebraic_numbers::manager am(qm); + algebraic_numbers::manager am(rl, qm); scoped_anum v1(am), v2(am); am.set(v1, 4); am.root(v1, 2, v2); @@ -551,7 +559,7 @@ static void tst_root() { am.set(v1, 4); am.root(v1, 4, v2); std::cout << "root: " << root_obj_pp(v2) << "\n"; - + } void tst_algebraic() { diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp index 57c8c5050..b46ede849 100644 --- a/src/test/hilbert_basis.cpp +++ b/src/test/hilbert_basis.cpp @@ -12,6 +12,7 @@ Copyright (c) 2015 Microsoft Corporation #include "tactic.h" #include "tactic2solver.h" #include "solver.h" +#include "rlimit.h" #include #include #include @@ -38,7 +39,7 @@ class hilbert_basis_validate { } public: - + hilbert_basis_validate(ast_manager& m); expr_ref mk_validate(hilbert_basis& hb); @@ -46,7 +47,7 @@ public: }; -hilbert_basis_validate::hilbert_basis_validate(ast_manager& m): +hilbert_basis_validate::hilbert_basis_validate(ast_manager& m): m(m) { } @@ -86,7 +87,7 @@ void hilbert_basis_validate::validate_solution(hilbert_basis& hb, vector v; - // check that claimed solution really satisfies inequalities: + // check that claimed solution really satisfies inequalities: for (unsigned i = 0; i < sz; ++i) { bool is_initial; hb.get_basis_solution(i, v, is_initial); @@ -111,7 +112,7 @@ expr_ref hilbert_basis_validate::mk_validate(hilbert_basis& hb) { sort_ref_vector sorts(m); #define mk_mul(_r,_x) (_r.is_one()?((expr*)_x):((expr*)a.mk_mul(a.mk_numeral(_r,true),_x))) - + for (unsigned i = 0; i < sz; ++i) { bool is_initial; @@ -169,7 +170,7 @@ expr_ref hilbert_basis_validate::mk_validate(hilbert_basis& hb) { } fml1 = m.mk_or(fmls.size(), fmls.c_ptr()); fmls.reset(); - + sz = hb.get_num_ineqs(); for (unsigned i = 0; i < sz; ++i) { bool is_eq; @@ -194,7 +195,7 @@ expr_ref hilbert_basis_validate::mk_validate(hilbert_basis& hb) { } fml2 = m.mk_and(fmls.size(), fmls.c_ptr()); fml = m.mk_eq(fml1, fml2); - + bounds.reset(); for (unsigned i = 0; i < xs.size(); ++i) { if (!hb.get_is_int(i)) { @@ -221,7 +222,7 @@ static void display_statistics(hilbert_basis& hb) { } static void on_ctrl_c(int) { - signal (SIGINT, SIG_DFL); + signal (SIGINT, SIG_DFL); display_statistics(*g_hb); raise(SIGINT); } @@ -258,17 +259,17 @@ static void saturate_basis(hilbert_basis& hb) { lbool is_sat = hb.saturate(); switch(is_sat) { - case l_true: - std::cout << "sat\n"; + case l_true: + std::cout << "sat\n"; hb.display(std::cout); //validate_sat(hb); break; - case l_false: - std::cout << "unsat\n"; + case l_false: + std::cout << "unsat\n"; + break; + case l_undef: + std::cout << "undef\n"; break; - case l_undef: - std::cout << "undef\n"; - break; } display_statistics(hb); } @@ -283,7 +284,8 @@ static void saturate_basis(hilbert_basis& hb) { static void gorrila_test(unsigned seed, unsigned n, unsigned k, unsigned bound, unsigned num_ineqs) { std::cout << "Gorrila test\n"; random_gen rand(seed); - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); SASSERT(0 < bound); SASSERT(k <= n); int ibound = static_cast(bound); @@ -303,7 +305,7 @@ static void gorrila_test(unsigned seed, unsigned n, unsigned k, unsigned bound, } a0 = rational(ibound - static_cast(rand(2*bound+1))); hb.add_ge(nv, a0); - } + } hb.display(std::cout << "Saturate\n"); saturate_basis(hb); } @@ -368,7 +370,8 @@ static vector vec(int i, int j, int k, int l, int x, int y, int z) { // -y + z <= 0 static void tst1() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_eq(vec(1,1,-2)); hb.add_eq(vec(1,0,-1)); hb.add_le(vec(0,1,-1)); @@ -380,7 +383,8 @@ static void tst1() { // 23x - 12y - 9z <= 0 // x - 8y - 8z <= 0 void tst2() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_eq(vec(-23,12,9)); hb.add_eq(vec(-1,8,8)); @@ -391,7 +395,8 @@ void tst2() { // example 6, Ajili, Contenjean // 3x + 2y - z - 2u <= 0 static void tst3() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_le(vec(3,2,-1,-2)); saturate_basis(hb); } @@ -400,7 +405,8 @@ static void tst3() { // Sigma_1, table 1, Ajili, Contejean static void tst4() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_le(vec( 0,-2, 1, 3, 2,-2, 3), R(3)); hb.add_le(vec(-1, 7, 0, 1, 3, 5,-4), R(2)); hb.add_le(vec( 0,-1, 1,-1,-1, 0, 0), R(2)); @@ -416,7 +422,8 @@ static void tst4() { // Sigma_2 table 1, Ajili, Contejean static void tst5() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_le(vec( 1, 2,-1, 1), R(3)); hb.add_le(vec( 2, 4, 1, 2), R(12)); hb.add_le(vec( 1, 4, 2, 1), R(9)); @@ -429,7 +436,8 @@ static void tst5() { // Sigma_3 table 1, Ajili, Contejean static void tst6() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_le(vec( 4, 3, 0), R(6)); hb.add_le(vec(-3,-4, 0), R(-1)); hb.add_le(vec( 4, 0,-3), R(3)); @@ -441,7 +449,8 @@ static void tst6() { // Sigma_4 table 1, Ajili, Contejean static void tst7() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_eq(vec( 1, 1, 1, 0), R(5)); hb.add_le(vec( 2, 1, 0, 1), R(6)); hb.add_le(vec( 1, 2, 1, 1), R(7)); @@ -454,7 +463,8 @@ static void tst7() { // Sigma_5 table 1, Ajili, Contejean static void tst8() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_le(vec( 2, 1, 1), R(2)); hb.add_le(vec( 1, 2, 3), R(5)); hb.add_le(vec( 2, 2, 3), R(6)); @@ -464,7 +474,8 @@ static void tst8() { // Sigma_6 table 1, Ajili, Contejean static void tst9() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_le(vec( 1, 2, 3), R(11)); hb.add_le(vec( 2, 2, 5), R(13)); hb.add_le(vec( 1,-1,-11), R(3)); @@ -473,7 +484,8 @@ static void tst9() { // Sigma_7 table 1, Ajili, Contejean static void tst10() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_le(vec( 1,-1,-1,-3), R(2)); hb.add_le(vec(-2, 3, 3,-5), R(3)); saturate_basis(hb); @@ -481,14 +493,16 @@ static void tst10() { // Sigma_8 table 1, Ajili, Contejean static void tst11() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_le(vec( 7,-2,11, 3, -5), R(5)); saturate_basis(hb); } // Sigma_9 table 1, Ajili, Contejean static void tst12() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_eq(vec( 1,-2,-3,4), R(0)); hb.add_le(vec(100,45,-78,-67), R(0)); saturate_basis(hb); @@ -496,34 +510,39 @@ static void tst12() { // Sigma_10 table 1, Ajili, Contejean static void tst13() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_le(vec( 23, -56, -34, 12, 11), R(0)); saturate_basis(hb); } // Sigma_11 table 1, Ajili, Contejean static void tst14() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_eq(vec(1, 0, -4, 8), R(2)); hb.add_le(vec(12,19,-11,-7), R(-7)); saturate_basis(hb); } static void tst15() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_le(vec(1, 0), R(1)); hb.add_le(vec(0, 1), R(1)); saturate_basis(hb); } static void tst16() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_le(vec(1, 0), R(100)); saturate_basis(hb); } static void tst17() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_eq(vec(1, 0), R(0)); hb.add_eq(vec(-1, 0), R(0)); hb.add_eq(vec(0, 2), R(0)); @@ -533,26 +552,29 @@ static void tst17() { } static void tst18() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_eq(vec(0, 1), R(0)); hb.add_eq(vec(1, -1), R(2)); - saturate_basis(hb); + saturate_basis(hb); } static void tst19() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); hb.add_eq(vec(0, 1, 0), R(0)); hb.add_eq(vec(1, -1, 0), R(2)); - saturate_basis(hb); + saturate_basis(hb); } static void test_A_5_5_3() { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); for (unsigned i = 0; i < 15; ++i) { vector v; for (unsigned j = 0; j < 5; ++j) { for (unsigned k = 0; k < 15; ++k) { - v.push_back(rational(k == i)); + v.push_back(rational(k == i)); } } hb.add_ge(v, R(0)); diff --git a/src/test/interval.cpp b/src/test/interval.cpp index ef733394b..ac242cc60 100644 --- a/src/test/interval.cpp +++ b/src/test/interval.cpp @@ -22,6 +22,7 @@ Revision History: #include"mpq.h" #include"ast.h" #include"debug.h" +#include"rlimit.h" template class interval_manager; typedef im_default_config::interval interval; @@ -61,7 +62,7 @@ static void display_smt2_numeral(std::ostream & out, unsynch_mpq_manager & m, mp } } -static void display_constraint(std::ostream & out, unsynch_mpq_manager & m, char const * a, interval const & i, +static void display_constraint(std::ostream & out, unsynch_mpq_manager & m, char const * a, interval const & i, bool include_lower = true, bool include_upper = true) { out << "(and true"; if (!i.m_lower_inf && include_lower) { @@ -77,7 +78,7 @@ static void display_constraint(std::ostream & out, unsynch_mpq_manager & m, char out << ")"; } -static void assert_hyp(std::ostream & out, unsynch_mpq_manager & m, char const * a, interval const & i, +static void assert_hyp(std::ostream & out, unsynch_mpq_manager & m, char const * a, interval const & i, bool include_lower = true, bool include_upper = true) { out << "(assert "; display_constraint(out, m, a, i, include_lower, include_upper); @@ -99,7 +100,7 @@ static bool mk_interval(im_default_config & cfg, interval & a, bool l_inf, bool if (l_val == u_val && (l_open || u_open)) return false; } - + if (l_inf) { a.m_lower_open = true; a.m_lower_inf = true; @@ -119,7 +120,7 @@ static bool mk_interval(im_default_config & cfg, interval & a, bool l_inf, bool a.m_upper_inf = false; cfg.m().set(a.m_upper, u_val); } - + return true; } #endif @@ -131,7 +132,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m if (rand()%4 == 0) { a.m_lower_open = true; a.m_lower_inf = true; - + a.m_upper_open = (rand()%2 == 0); a.m_upper_inf = false; cfg.m().set(a.m_upper, -static_cast((rand()%magnitude))); @@ -141,7 +142,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m a.m_upper_inf = false; int upper = -static_cast((rand()%magnitude)); cfg.m().set(a.m_upper, upper); - + a.m_lower_open = (rand()%2 == 0); a.m_lower_inf = false; cfg.m().set(a.m_lower, upper - static_cast(rand()%magnitude) - (a.m_lower_open || a.m_upper_open ? 1 : 0)); @@ -149,7 +150,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m break; case 1: // Neg, Pos - + if (rand()%4 == 0) { a.m_lower_open = true; a.m_lower_inf = true; @@ -159,7 +160,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m a.m_lower_inf = false; cfg.m().set(a.m_lower, -static_cast((rand()%magnitude)) - 1); } - + if (rand()%4 == 0) { a.m_upper_open = true; a.m_upper_inf = true; @@ -175,7 +176,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m if (rand()%4 == 0) { a.m_upper_open = true; a.m_upper_inf = true; - + a.m_lower_open = (rand()%2 == 0); a.m_lower_inf = false; cfg.m().set(a.m_lower, (rand()%magnitude)); @@ -185,7 +186,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m a.m_lower_inf = false; int lower = (rand()%magnitude); cfg.m().set(a.m_lower, lower); - + a.m_upper_open = (rand()%2 == 0); a.m_upper_inf = false; cfg.m().set(a.m_upper, lower + rand()%magnitude + (a.m_lower_open || a.m_upper_open ? 1 : 0)); @@ -235,9 +236,10 @@ static void display_lemmas(unsynch_mpq_manager & nm, char const * result_term, #define MK_BINARY(NAME, RES_TERM) \ static void tst_ ## NAME(unsigned N, unsigned magnitude) { \ + reslimit rl; \ unsynch_mpq_manager nm; \ im_default_config imc(nm); \ - interval_manager im(imc); \ + interval_manager im(rl, imc); \ interval a, b, r; \ \ for (unsigned i = 0; i < N; i++) { \ @@ -255,130 +257,137 @@ MK_BINARY(mul, "(* a b)"); MK_BINARY(add, "(+ a b)"); MK_BINARY(sub, "(- a b)"); -static void tst_neg(unsigned N, unsigned magnitude) { - unsynch_mpq_manager nm; +static void tst_neg(unsigned N, unsigned magnitude) { + reslimit rl; + unsynch_mpq_manager nm; im_default_config imc(nm); - interval_manager im(imc); - interval a, b, r; - - for (unsigned i = 0; i < N; i++) { - mk_random_interval(imc, a, magnitude); - interval_deps deps; - im.neg(a, r, deps); - display_lemmas(nm, "(- a)", a, b, r, deps); - } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); -} + interval_manager im(rl, imc); + interval a, b, r; -static void tst_pw_2(unsigned N, unsigned magnitude) { - unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(imc); - interval a, b, r; - - for (unsigned i = 0; i < N; i++) { - mk_random_interval(imc, a, magnitude); - interval_deps deps; - im.power(a, 2, r, deps); - display_lemmas(nm, "(* a a)", a, b, r, deps); - } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); -} - -static void tst_pw_3(unsigned N, unsigned magnitude) { - unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(imc); - interval a, b, r; - - for (unsigned i = 0; i < N; i++) { - mk_random_interval(imc, a, magnitude); - interval_deps deps; - im.power(a, 3, r, deps); - display_lemmas(nm, "(* a a a)", a, b, r, deps); + for (unsigned i = 0; i < N; i++) { + mk_random_interval(imc, a, magnitude); + interval_deps deps; + im.neg(a, r, deps); + display_lemmas(nm, "(- a)", a, b, r, deps); } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); } -static void tst_root_2(unsigned N, unsigned magnitude, unsigned precision) { - unsynch_mpq_manager nm; +static void tst_pw_2(unsigned N, unsigned magnitude) { + reslimit rl; + unsynch_mpq_manager nm; im_default_config imc(nm); - interval_manager im(imc); - interval a, b, r; + interval_manager im(rl, imc); + interval a, b, r; + + for (unsigned i = 0; i < N; i++) { + mk_random_interval(imc, a, magnitude); + interval_deps deps; + im.power(a, 2, r, deps); + display_lemmas(nm, "(* a a)", a, b, r, deps); + } + del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); +} + +static void tst_pw_3(unsigned N, unsigned magnitude) { + reslimit rl; + unsynch_mpq_manager nm; + im_default_config imc(nm); + interval_manager im(rl, imc); + interval a, b, r; + + for (unsigned i = 0; i < N; i++) { + mk_random_interval(imc, a, magnitude); + interval_deps deps; + im.power(a, 3, r, deps); + display_lemmas(nm, "(* a a a)", a, b, r, deps); + } + del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); +} + +static void tst_root_2(unsigned N, unsigned magnitude, unsigned precision) { + reslimit rl; + unsynch_mpq_manager nm; + im_default_config imc(nm); + interval_manager im(rl, imc); + interval a, b, r; scoped_mpq p(nm); p = precision; nm.inv(p); unsigned i = 0; while (i < N) { - mk_random_interval(imc, a, magnitude); + mk_random_interval(imc, a, magnitude); if (!im.lower_is_neg(a)) { i++; - interval_deps deps; - im.nth_root(a, 2, p, r, deps); - display_lemmas(nm, "(^ a (/ 1.0 2.0))", a, b, r, deps); - } - } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + interval_deps deps; + im.nth_root(a, 2, p, r, deps); + display_lemmas(nm, "(^ a (/ 1.0 2.0))", a, b, r, deps); + } + } + del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); } -static void tst_root_3(unsigned N, unsigned magnitude, unsigned precision) { - unsynch_mpq_manager nm; +static void tst_root_3(unsigned N, unsigned magnitude, unsigned precision) { + reslimit rl; + unsynch_mpq_manager nm; im_default_config imc(nm); - interval_manager im(imc); - interval a, b, r; + interval_manager im(rl, imc); + interval a, b, r; scoped_mpq p(nm); p = precision; nm.inv(p); unsigned i = 0; while (i < N) { - mk_random_interval(imc, a, magnitude); + mk_random_interval(imc, a, magnitude); i++; - interval_deps deps; - im.nth_root(a, 3, p, r, deps); - display_lemmas(nm, "(^ a (/ 1.0 3.0))", a, b, r, deps); - } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + interval_deps deps; + im.nth_root(a, 3, p, r, deps); + display_lemmas(nm, "(^ a (/ 1.0 3.0))", a, b, r, deps); + } + del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); } -static void tst_inv(unsigned N, unsigned magnitude) { - unsynch_mpq_manager nm; +static void tst_inv(unsigned N, unsigned magnitude) { + reslimit rl; + unsynch_mpq_manager nm; im_default_config imc(nm); - interval_manager im(imc); - interval a, b, r; - - for (unsigned i = 0; i < N; i++) { + interval_manager im(rl, imc); + interval a, b, r; + + for (unsigned i = 0; i < N; i++) { while (true) { - mk_random_interval(imc, a, magnitude); + mk_random_interval(imc, a, magnitude); if (!im.contains_zero(a)) break; } - interval_deps deps; - im.inv(a, r, deps); - display_lemmas(nm, "(/ 1 a)", a, b, r, deps); - } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + interval_deps deps; + im.inv(a, r, deps); + display_lemmas(nm, "(/ 1 a)", a, b, r, deps); + } + del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); } -static void tst_div(unsigned N, unsigned magnitude) { - unsynch_mpq_manager nm; - im_default_config imc(nm); - interval_manager im(imc); - interval a, b, r; +static void tst_div(unsigned N, unsigned magnitude) { + reslimit rl; + unsynch_mpq_manager nm; + im_default_config imc(nm); + interval_manager im(rl, imc); + interval a, b, r; - for (unsigned i = 0; i < N; i++) { - mk_random_interval(imc, a, magnitude); + for (unsigned i = 0; i < N; i++) { + mk_random_interval(imc, a, magnitude); while (true) { - mk_random_interval(imc, b, magnitude); + mk_random_interval(imc, b, magnitude); if (!im.contains_zero(b)) break; } - interval_deps deps; - im.div(a, b, r, deps); - display_lemmas(nm, "(/ a b)", a, b, r, deps); - } - del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); + interval_deps deps; + im.div(a, b, r, deps); + display_lemmas(nm, "(/ a b)", a, b, r, deps); + } + del_interval(imc, a); del_interval(imc, b); del_interval(imc, r); } #include"im_float_config.h" @@ -395,7 +404,7 @@ static void tst_float() { qm.set(one_third, 1, 3); qm.set(two_third, 2, 3); qm.set(minus_two_third, -2, 3); - + ifc.round_to_minus_inf(); ifc.m().set(a.m_lower, minus_one_third); ifc.round_to_plus_inf(); @@ -405,7 +414,7 @@ static void tst_float() { ifc.m().set(b.m_lower, minus_two_third); ifc.round_to_plus_inf(); ifc.m().set(b.m_upper, one_third); - + im.display(std::cout, a); std::cout << "\n"; im.display(std::cout, b); @@ -420,13 +429,14 @@ static void tst_float() { #endif void tst_pi() { - unsynch_mpq_manager nm; + reslimit rl; + unsynch_mpq_manager nm; im_default_config imc(nm); - interval_manager im(imc); + interval_manager im(rl, imc); interval r; for (unsigned i = 0; i < 8; i++) { im.pi(i, r); - nm.display_decimal(std::cout, im.lower(r), 32); std::cout << " "; + nm.display_decimal(std::cout, im.lower(r), 32); std::cout << " "; nm.display_decimal(std::cout, im.upper(r), 32); std::cout << "\n"; SASSERT(nm.lt(im.lower(r), im.upper(r))); } @@ -436,10 +446,11 @@ void tst_pi() { #if 0 static void tst_pi_float() { std::cout << "pi float...\n"; + reslimit rl; unsynch_mpq_manager qm; mpf_manager fm; im_float_config ifc(fm, 22, 106); - interval_manager > im(ifc); + interval_manager > im(rl, ifc); scoped_mpq q(qm); im_float_config::interval r; for (unsigned i = 0; i < 8; i++) { @@ -451,7 +462,7 @@ static void tst_pi_float() { } del_f_interval(ifc, r); } -#endif +#endif #define NUM_TESTS 1000 #define SMALL_MAG 3 diff --git a/src/test/karr.cpp b/src/test/karr.cpp index 4c0737230..c5581cc66 100644 --- a/src/test/karr.cpp +++ b/src/test/karr.cpp @@ -3,7 +3,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ - +#include"rlimit.h" #include "hilbert_basis.h" /* @@ -15,12 +15,12 @@ namespace karr { struct matrix { vector > A; vector b; - + unsigned size() const { return A.size(); } - void reset() { - A.reset(); - b.reset(); + void reset() { + A.reset(); + b.reset(); } matrix& operator=(matrix const& other) { @@ -46,7 +46,8 @@ namespace karr { // treat src as a homogeneous matrix. void dualizeH(matrix& dst, matrix const& src) { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); for (unsigned i = 0; i < src.size(); ++i) { vector v(src.A[i]); v.push_back(src.b[i]); @@ -74,7 +75,8 @@ namespace karr { // treat src as an inhomegeneous matrix. void dualizeI(matrix& dst, matrix const& src) { - hilbert_basis hb; + reslimit rl; + hilbert_basis hb(rl); for (unsigned i = 0; i < src.size(); ++i) { hb.add_eq(src.A[i], -src.b[i]); } @@ -136,7 +138,7 @@ namespace karr { } for (unsigned i = 0; i < src.size(); ++i) { T.A.push_back(src.A[i]); - T.A.back().append(zeros); + T.A.back().append(zeros); } T.b.append(src.b); T.append(Ab); @@ -146,7 +148,7 @@ namespace karr { dualizeI(TD, T); TD.display(std::cout << "TD:\n"); for (unsigned i = 0; i < TD.size(); ++i) { - vector v; + vector v; v.append(src.size(), TD.A[i].c_ptr() + src.size()); dst.A.push_back(v); dst.b.push_back(TD.b[i]); @@ -200,8 +202,8 @@ namespace karr { static void tst1() { matrix Theta; matrix Ab; - - // + + // Theta.A.push_back(V(1, 0)); Theta.b.push_back(R(0)); Theta.A.push_back(V(0, 1)); @@ -232,7 +234,7 @@ namespace karr { joinD(e2, t2D, ThetaD); t2D.display(std::cout << "t2D\n"); - e2.display(std::cout << "e2\n"); + e2.display(std::cout << "e2\n"); } void tst2() { @@ -264,7 +266,7 @@ namespace karr { N.display(std::cout << "N\n"); - + } void tst3() { @@ -288,7 +290,7 @@ namespace karr { N.display(std::cout << "N\n"); - + } }; diff --git a/src/test/nlsat.cpp b/src/test/nlsat.cpp index d1ece65fc..7777a6c42 100644 --- a/src/test/nlsat.cpp +++ b/src/test/nlsat.cpp @@ -21,6 +21,7 @@ Notes: #include"nlsat_evaluator.h" #include"nlsat_solver.h" #include"util.h" +#include"rlimit.h" nlsat::interval_set_ref tst_interval(nlsat::interval_set_ref const & s1, nlsat::interval_set_ref const & s2, @@ -57,8 +58,9 @@ nlsat::interval_set_ref tst_interval(nlsat::interval_set_ref const & s1, static void tst3() { enable_trace("nlsat_interval"); + reslimit rl; unsynch_mpq_manager qm; - anum_manager am(qm); + anum_manager am(rl, qm); small_object_allocator allocator; nlsat::interval_set_manager ism(am, allocator); @@ -70,13 +72,13 @@ static void tst3() { am.set(m_sqrt2, sqrt2); am.neg(m_sqrt2); am.set(three, 3); - + nlsat::literal p1(1, false); nlsat::literal p2(2, false); nlsat::literal p3(3, false); nlsat::literal p4(4, false); nlsat::literal np2(2, true); - + nlsat::interval_set_ref s1(ism), s2(ism), s3(ism), s4(ism); s1 = ism.mk_empty(); std::cout << "s1: " << s1 << "\n"; @@ -94,7 +96,7 @@ static void tst3() { s2 = ism.mk(false, false, zero, false, false, two, p2); tst_interval(s1, s2, 1); - // Case + // Case // s1: [ ... ] // s2: [ ... ] s1 = ism.mk(false, false, zero, false, false, two, p1); @@ -102,28 +104,28 @@ static void tst3() { s3 = ism.mk_union(s1, s2); tst_interval(s1, s2, 2); - // Case + // Case // s1: [ ... ] // s2: [ ... ] s1 = ism.mk(false, false, m_sqrt2, false, false, one, p1); s2 = ism.mk(false, false, zero, false, false, two, p2); tst_interval(s1, s2, 2); - // Case + // Case // s1: [ ... ] // s2: [ ... ] s1 = ism.mk(false, false, m_sqrt2, false, false, one, p1); s2 = ism.mk(false, false, two, false, false, three, p2); tst_interval(s1, s2, 2); - // Case + // Case // s1: [ ... ] // s2: [ ... ] s1 = ism.mk(false, false, m_sqrt2, false, false, three, p1); s2 = ism.mk(false, false, zero, false, false, two, p2); tst_interval(s1, s2, 1); - // Case + // Case // s1: [ ... ] // s2: [ ... ] [ ... ] s1 = ism.mk(false, false, m_two, false, false, two, p1); @@ -214,7 +216,7 @@ static nlsat::interval_set_ref mk_random(nlsat::interval_set_manager & ism, anum return r; } -static void check_subset_result(nlsat::interval_set_ref const & s1, +static void check_subset_result(nlsat::interval_set_ref const & s1, nlsat::interval_set_ref const & s2, nlsat::interval_set_ref const & r, nlsat::literal l1, @@ -241,15 +243,16 @@ static void check_subset_result(nlsat::interval_set_ref const & s1, static void tst4() { enable_trace("nlsat_interval"); + reslimit rl; unsynch_mpq_manager qm; - anum_manager am(qm); + anum_manager am(rl, qm); small_object_allocator allocator; nlsat::interval_set_manager ism(am, allocator); nlsat::interval_set_ref s1(ism), s2(ism), r(ism); nlsat::literal l1(1, false); nlsat::literal l2(2, false); - + for (unsigned i = 0; i < 100; i++) { s1 = mk_random(ism, am, 20, 3, 10, true, true, l1); s2 = mk_random(ism, am, 20, 3, 10, true, true, l2); diff --git a/src/test/polynomial.cpp b/src/test/polynomial.cpp index b51d14645..56eb61a11 100644 --- a/src/test/polynomial.cpp +++ b/src/test/polynomial.cpp @@ -22,11 +22,13 @@ Notes: #include"polynomial_var2value.h" #include"polynomial_cache.h" #include"linear_eq_solver.h" +#include"rlimit.h" static void tst1() { std::cout << "\n----- Basic testing -------\n"; + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -56,6 +58,7 @@ static void tst1() { } static void tst_pseudo_div(polynomial_ref const & A, polynomial_ref const & B, polynomial::var x) { + reslimit rl; polynomial::manager & m = A.m(); std::cout << "---- Pseudo-division test ----\n"; std::cout << "A: " << A << "\n"; @@ -81,8 +84,9 @@ static void tst_pseudo_div(polynomial_ref const & A, polynomial_ref const & B, p } static void tst2() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -98,8 +102,9 @@ static void tst2() { static void tst3() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); x0 = m.mk_polynomial(m.mk_var()); @@ -113,8 +118,9 @@ static void tst3() { static void tst4() { std::cout << "---- Testing renaming/reordering ----\n"; + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -141,8 +147,9 @@ static void tst_quasi_resultant(polynomial_ref const & p, polynomial_ref const & } static void tst5() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -158,8 +165,9 @@ static void tst5() { } static void tst6() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -176,8 +184,9 @@ static void tst6() { } static void tst7() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -198,8 +207,9 @@ static void tst7() { } static void tst8() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -220,8 +230,9 @@ static void tst8() { static void tst9() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -261,8 +272,9 @@ static void tst9() { } static void tst10() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -300,8 +312,9 @@ static void tst10() { } static void tst11() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -342,8 +355,9 @@ static void tst_discriminant(polynomial_ref const & p, polynomial_ref const & ex } static void tst_discriminant() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref a(m); polynomial_ref b(m); polynomial_ref c(m); @@ -354,13 +368,13 @@ static void tst_discriminant() { c = m.mk_polynomial(m.mk_var()); d = m.mk_polynomial(m.mk_var()); x = m.mk_polynomial(m.mk_var()); - tst_discriminant(a*(x^2) + b*x + c, + tst_discriminant(a*(x^2) + b*x + c, (b^2) - 4*a*c); - tst_discriminant(a*(x^3) + b*(x^2) + c*x + d, + tst_discriminant(a*(x^3) + b*(x^2) + c*x + d, (b^2)*(c^2) - 4*a*(c^3) - 4*(b^3)*d + 18*a*b*c*d - 27*(a^2)*(d^2)); - tst_discriminant(a*(x^3) + b*(x^2) + c*(x^2) + d, + tst_discriminant(a*(x^3) + b*(x^2) + c*(x^2) + d, -4*(b^3)*d - 12*(b^2)*c*d - 12*b*(c^2)*d - 4*(c^3)*d - 27*(a^2)*(d^2)); - tst_discriminant(a*(x^3) + b*(x^2) + c*(x^2) + d, + tst_discriminant(a*(x^3) + b*(x^2) + c*(x^2) + d, -4*(b^3)*d - 12*(b^2)*c*d - 12*b*(c^2)*d - 4*(c^3)*d - 27*(a^2)*(d^2)); tst_discriminant(a*(x^3) + (b^2)*d*(x^2) + c*(x^2) + d, -4*(b^6)*(d^4) - 12*(b^4)*c*(d^3) - 12*(b^2)*(c^2)*(d^2) - 4*(c^3)*d - 27*(a^2)*(d^2)); @@ -402,7 +416,7 @@ static void tst_discriminant() { tst_discriminant((x^4) + (a + b)*(x^2) + (a + c)*x, -4*(a^5) - 12*(a^4)*b - 12*(a^3)*(b^2) - 4*(a^2)*(b^3) - 8*(a^4)*c - 24*(a^3)*b*c - 24*(a^2)*(b^2)*c - 8*a*(b^3)*c - 4*(a^3)*(c^2) - 12*(a^2)*b*(c^2) - 12*a*(b^2)*(c^2) - - 4*(b^3)*(c^2) - 27*(a^4) - 108*(a^3)*c - 162*(a^2)*(c^2) - 108*a*(c^3) - 27*(c^4)); + 4*(b^3)*(c^2) - 27*(a^4) - 108*(a^3)*c - 162*(a^2)*(c^2) - 108*a*(c^3) - 27*(c^4)); tst_discriminant((x^4) + (a + c)*x + (c^2), 256*(c^6) - 27*(a^4) - 108*(a^3)*c - 162*(a^2)*(c^2) - 108*a*(c^3) - 27*(c^4) ); @@ -425,7 +439,7 @@ static void tst_discriminant() { max_var(b), 2048*(a^12) - 12288*(a^11) + 26112*(a^10) - 22528*(a^9) + 5664*(a^8) + 960*(a^7) + 32*(a^6)); - tst_discriminant((x^4) + a*(x^2) + b*x + c, + tst_discriminant((x^4) + a*(x^2) + b*x + c, -4*(a^3)*(b^2) + 16*(a^4)*c - 27*(b^4) + 144*a*(b^2)*c - 128*(a^2)*(c^2) + 256*(c^3)); tst_discriminant((((a-1)^2) + a*b + ((b-1)^2) - 1)*(x^3) + (a*b)*(x^2) + ((a^2) - (b^2))*x + c*a, -4*(a^8) - 4*(a^7)*b + 9*(a^6)*(b^2) + 12*(a^5)*(b^3) - 2*(a^4)*(b^4) - 12*(a^3)*(b^5) - @@ -460,8 +474,9 @@ static void tst_resultant(polynomial_ref const & p, polynomial_ref const & q, po } static void tst_resultant() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref a(m); polynomial_ref b(m); polynomial_ref c(m); @@ -485,13 +500,13 @@ static void tst_resultant() { 3*(a^2)*(b^4) - (b^6)); - tst_resultant(a*(x^5) + b, - c*x + d, + tst_resultant(a*(x^5) + b, + c*x + d, a*(d^5) - b*(c^5)); tst_resultant(a*(x^5) + 3*(c + d)*(x^2) + 2*b, - c*x + d, + c*x + d, -2*b*(c^5) - 3*(c^4)*(d^2) - 3*(c^3)*(d^3) + a*(d^5)); - tst_resultant(c*x + d, + tst_resultant(c*x + d, a*(x^5) + 3*(c + d)*(x^2) + 2*b, 2*b*(c^5) + 3*(c^4)*(d^2) + 3*(c^3)*(d^3) - a*(d^5)); tst_resultant((x^2) - (a^3)*(x^2) + b + 1, @@ -545,23 +560,25 @@ static void tst_resultant() { } static void tst_compose() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); x0 = m.mk_polynomial(m.mk_var()); x1 = m.mk_polynomial(m.mk_var()); polynomial_ref p(m); p = (x0^3) - x0 + 3; - std::cout << "p: " << p << "\np(x - y): " << compose_x_minus_y(p, 1) + std::cout << "p: " << p << "\np(x - y): " << compose_x_minus_y(p, 1) << "\np(x + y): " << compose_x_plus_y(p, 1) << "\np(x - x): " << compose_x_minus_y(p, 0) << "\np(x + x): " << compose_x_plus_y(p, 0) << "\n"; SASSERT(eq(compose_x_minus_y(p, 1), (x0^3) - 3*(x0^2)*x1 + 3*x0*(x1^2) - (x1^3) - x0 + x1 + 3)); SASSERT(eq(compose_x_plus_y(p, 1), (x0^3) + 3*(x0^2)*x1 + 3*x0*(x1^2) + (x1^3) - x0 - x1 + 3)); } void tst_prem() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); polynomial_ref y(m); x = m.mk_polynomial(m.mk_var()); @@ -572,13 +589,14 @@ void tst_prem() { q = y*(x^3); std::cout << "p: " << p << "\n"; std::cout << "q: " << q << "\n"; - // unsigned d; + // unsigned d; std::cout << "srem: " << exact_pseudo_remainder(q, p, 0) << "\n"; } void tst_sqrt() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); polynomial_ref y(m); x = m.mk_polynomial(m.mk_var()); @@ -622,8 +640,9 @@ static void tst_gcd(polynomial_ref const & p, polynomial_ref const & q, polynomi } static void tst_gcd() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -648,7 +667,7 @@ static void tst_gcd() { tst_gcd(((x0^2) + x0*x1 + 1)*(x2*x2 + x3 + 2)*(x3*x1 + 2)*(x3*x1*x1 + x1*x2 + 1), (-1)*((x0^2) + x0*x1 + 1)*(x3*x1*x1 + x1*x2 + 1)*(x3*x1 + x1*x2 + 17), ((x0^2) + x0*x1 + 1)*(x3*x1*x1 + x1*x2 + 1)); - + tst_gcd((-1)*((x0^2) + x0*x1 + 1)*(x2*x2 + x3 + 2)*(x3*x1 + 2)*(x3*x1*x1 + x1*x2 + 1), (-1)*((x0^2) + x0*x1 + 1)*(x3*x1*x1 + x1*x2 + 1)*(x3*x1 + x1*x2 + 17), ((x0^2) + x0*x1 + 1)*(x3*x1*x1 + x1*x2 + 1)); @@ -661,17 +680,17 @@ static void tst_gcd() { tst_primitive((x0 + 1)*(2*x1) + (x0^2)*(x0 + 1), 1, 2*x1 + (x0^2)); tst_primitive((x0 + 1)*(x2 + 1)*(x2^2)*(x0 + 1)*(x1^2) + (x0 + 1)*(x2^2)*x1 + (x0+1)*(x0+1), 1, (x2 + 1)*(x2^2)*(x0 + 1)*(x1^2) + (x2^2)*x1 + (x0+1)); - tst_primitive((x0 + (x3^2))*(x2 + x3 + 1)*(x2^2)*(x1^2) + + tst_primitive((x0 + (x3^2))*(x2 + x3 + 1)*(x2^2)*(x1^2) + (x0 + (x3^2))*(x2 + x3 + 1)*x1 + (x0 + (x3^2))*(x2 + x3 + 1)*(x3^2), 1, (x2^2)*(x1^2) + x1 + (x3^2)); - tst_content((x0 + (x3^2))*(x2 + x3 + 1)*(x2^2)*(x1^2) + + tst_content((x0 + (x3^2))*(x2 + x3 + 1)*(x2^2)*(x1^2) + (x0 + (x3^2))*(x2 + x3 + 1)*x1 + (x0 + (x3^2))*(x2 + x3 + 1)*(x3^2), 1, (x0 + (x3^2))*(x2 + x3 + 1)); - tst_primitive(4*(x0 + (x3^2))*(x2 + x3 + 1)*(x2^2)*(x1^2) + + tst_primitive(4*(x0 + (x3^2))*(x2 + x3 + 1)*(x2^2)*(x1^2) + 2*(x0 + (x3^2))*(x2 + x3 + 1)*x1 + 4*(x0 + (x3^2))*(x2 + x3 + 1)*(x3^2), 1, @@ -721,8 +740,9 @@ static void tst_psc_perf(polynomial_ref const & p, polynomial_ref const & q, pol #endif static void tst_psc() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -740,7 +760,7 @@ static void tst_psc() { x8 = m.mk_polynomial(m.mk_var()); x9 = m.mk_polynomial(m.mk_var()); x10 = m.mk_polynomial(m.mk_var()); - tst_psc(x0*(x1^2) + (x0 + 1)*x1 + 2, x0*x1 + 3, 1, + tst_psc(x0*(x1^2) + (x0 + 1)*x1 + 2, x0*x1 + 3, 1, 6*x0 - (x0^2), x0); tst_psc(x0*(x1^4) + (x0 + 1)*(x1^3) + 2, x0*(x1^3) + 3, 1, 72*(x0^3) - (x0^4) - 27*(x0^2) - 27*(x0), 9*(x0^3)); @@ -754,34 +774,34 @@ static void tst_psc() { tst_psc((x^4) + a*(x^2) + b*x + c, 4*(x^3) + 2*a*x + b, 9, 16*(a^4)*c - 4*(a^3)*(b^2) - 128*(a^2)*(c^2) + 144*a*(b^2)*c - 27*(b^4) + 256*(c^3), 8*(a^3) - 32*a*c + 36*(b^2)); polynomial_ref & y = x10; - + tst_psc(((y^2) + 6)*(x - 1) - y*((x^2) + 1), ((x^2) + 6)*(y - 1) - x*((y^2) + 1), 10, - 2*(x^6) - 22*(x^5) + 102*(x^4) - 274*(x^3) + 488*(x^2) - 552*x + 288, + 2*(x^6) - 22*(x^5) + 102*(x^4) - 274*(x^3) + 488*(x^2) - 552*x + 288, 5*x - (x^2) - 6 ); - + tst_psc(((y^3) + 6)*(x - 1) - y*((x^3) + 1), ((x^3) + 6)*(y - 1) - x*((y^3) + 1), 10, 3*(x^11) - 3*(x^10) - 37*(x^9) + 99*(x^8) + 51*(x^7) - 621*(x^6) + 1089*(x^5) - 39*(x^4) - 3106*(x^3) + 5868*(x^2) - 4968*x + 1728, (x^6) - 10*(x^4) + 12*(x^3) + 25*(x^2) - 60*x + 36); polynomial_ref p = (x^6) + a * (x^3) + b; polynomial_ref q = (x^6) + c * (x^3) + d; - - tst_psc(p, q, 9, - (b^6) - 3*a*(b^5)*c + 3*(a^2)*(b^4)*(c^2) + 3*(b^5)*(c^2) - (a^3)*(b^3)*(c^3) - - 6*a*(b^4)*(c^3) + 3*(a^2)*(b^3)*(c^4) + 3*(b^4)*(c^4) - 3*a*(b^3)*(c^5) + (b^3)*(c^6) + - 3*(a^2)*(b^4)*d - 6*(b^5)*d - 6*(a^3)*(b^3)*c*d + 9*a*(b^4)*c*d + - 3*(a^4)*(b^2)*(c^2)*d + 6*(a^2)*(b^3)*(c^2)*d - 12*(b^4)*(c^2)*d - 9*(a^3)*(b^2)*(c^3)*d + - 6*a*(b^3)*(c^3)*d + 9*(a^2)*(b^2)*(c^4)*d - 6*(b^3)*(c^4)*d - 3*a*(b^2)*(c^5)*d + - 3*(a^4)*(b^2)*(d^2) - 12*(a^2)*(b^3)*(d^2) + 15*(b^4)*(d^2) - 3*(a^5)*b*c*(d^2) + - 6*(a^3)*(b^2)*c*(d^2) - 6*a*(b^3)*c*(d^2) + 9*(a^4)*b*(c^2)*(d^2) - - 18*(a^2)*(b^2)*(c^2)*(d^2) + 18*(b^3)*(c^2)*(d^2) - 9*(a^3)*b*(c^3)*(d^2) + - 6*a*(b^2)*(c^3)*(d^2) + 3*(a^2)*b*(c^4)*(d^2) + 3*(b^2)*(c^4)*(d^2) + (a^6)*(d^3) - - 6*(a^4)*b*(d^3) + 18*(a^2)*(b^2)*(d^3) - 20*(b^3)*(d^3) - 3*(a^5)*c*(d^3) + - 6*(a^3)*b*c*(d^3) - 6*a*(b^2)*c*(d^3) + 3*(a^4)*(c^2)*(d^3) + 6*(a^2)*b*(c^2)*(d^3) - - 12*(b^2)*(c^2)*(d^3) - (a^3)*(c^3)*(d^3) - 6*a*b*(c^3)*(d^3) + 3*(a^4)*(d^4) - - 12*(a^2)*b*(d^4) + 15*(b^2)*(d^4) - 6*(a^3)*c*(d^4) + 9*a*b*c*(d^4) + - 3*(a^2)*(c^2)*(d^4) + 3*b*(c^2)*(d^4) + 3*(a^2)*(d^5) - 6*b*(d^5) - + + tst_psc(p, q, 9, + (b^6) - 3*a*(b^5)*c + 3*(a^2)*(b^4)*(c^2) + 3*(b^5)*(c^2) - (a^3)*(b^3)*(c^3) - + 6*a*(b^4)*(c^3) + 3*(a^2)*(b^3)*(c^4) + 3*(b^4)*(c^4) - 3*a*(b^3)*(c^5) + (b^3)*(c^6) + + 3*(a^2)*(b^4)*d - 6*(b^5)*d - 6*(a^3)*(b^3)*c*d + 9*a*(b^4)*c*d + + 3*(a^4)*(b^2)*(c^2)*d + 6*(a^2)*(b^3)*(c^2)*d - 12*(b^4)*(c^2)*d - 9*(a^3)*(b^2)*(c^3)*d + + 6*a*(b^3)*(c^3)*d + 9*(a^2)*(b^2)*(c^4)*d - 6*(b^3)*(c^4)*d - 3*a*(b^2)*(c^5)*d + + 3*(a^4)*(b^2)*(d^2) - 12*(a^2)*(b^3)*(d^2) + 15*(b^4)*(d^2) - 3*(a^5)*b*c*(d^2) + + 6*(a^3)*(b^2)*c*(d^2) - 6*a*(b^3)*c*(d^2) + 9*(a^4)*b*(c^2)*(d^2) - + 18*(a^2)*(b^2)*(c^2)*(d^2) + 18*(b^3)*(c^2)*(d^2) - 9*(a^3)*b*(c^3)*(d^2) + + 6*a*(b^2)*(c^3)*(d^2) + 3*(a^2)*b*(c^4)*(d^2) + 3*(b^2)*(c^4)*(d^2) + (a^6)*(d^3) - + 6*(a^4)*b*(d^3) + 18*(a^2)*(b^2)*(d^3) - 20*(b^3)*(d^3) - 3*(a^5)*c*(d^3) + + 6*(a^3)*b*c*(d^3) - 6*a*(b^2)*c*(d^3) + 3*(a^4)*(c^2)*(d^3) + 6*(a^2)*b*(c^2)*(d^3) - + 12*(b^2)*(c^2)*(d^3) - (a^3)*(c^3)*(d^3) - 6*a*b*(c^3)*(d^3) + 3*(a^4)*(d^4) - + 12*(a^2)*b*(d^4) + 15*(b^2)*(d^4) - 6*(a^3)*c*(d^4) + 9*a*b*c*(d^4) + + 3*(a^2)*(c^2)*(d^4) + 3*b*(c^2)*(d^4) + 3*(a^2)*(d^5) - 6*b*(d^5) - 3*a*c*(d^5) + (d^6), 3*(a^2)*c - (a^3) - 3*a*(c^2) + (c^3) ); @@ -796,9 +816,9 @@ static void tst_psc() { zero = m.mk_zero(); tst_psc( a*d*x + a*c*f + a*e - b*a, - d*x + c*f + e - b, + d*x + c*f + e - b, 9, zero, zero); - + #if 0 tst_psc_perf((x^7) + a*(x^3) + b*(x^2) + c*x + d, @@ -834,7 +854,7 @@ static void tst_vars(polynomial_ref const & p, unsigned sz, polynomial::var * xs static void tst_vars() { polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -850,7 +870,7 @@ static void tst_vars() { polynomial::var s012[3] = {0, 1, 2}; polynomial::var s3[1] = {3}; polynomial::var s01234[5] = {0, 1, 2, 3, 4}; - + tst_vars((x0 + 1)*((x0^2) + (x3^2))*(x2*x3), 3, s023); tst_vars((x0 + x2)*((x0^2) + (x3^2))*(x2*x3), 3, s023); tst_vars(((x1 + x4 + 1)^5), 2, s14); @@ -874,7 +894,7 @@ static void tst_sqf(polynomial_ref const & p, polynomial_ref const & expected) { static void tst_sqf() { polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -897,7 +917,7 @@ static void tst_sqf() { tst_sqf(((x0 + x1 + x2 + x3)^5) + 1, ((x0 + x1 + x2 + x3)^5) + 1); } -static void tst_substitute(polynomial_ref const & p, +static void tst_substitute(polynomial_ref const & p, polynomial::var x1, mpz const & v1, polynomial::var x2, mpz const & v2, polynomial_ref const & expected) { @@ -919,7 +939,7 @@ static void tst_substitute(polynomial_ref const & p, static void tst_substitute() { polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -960,7 +980,7 @@ static void tst_qsubstitute(polynomial_ref const & p, static void tst_qsubstitute() { unsynch_mpq_manager qm; - polynomial::manager m(qm); + reslimit rl; polynomial::manager m(rl, qm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -1013,7 +1033,7 @@ void tst_mfact(polynomial_ref const & p, unsigned num_distinct_factors) { static void tst_mfact() { polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -1083,7 +1103,7 @@ static void tst_mfact() { tst_mfact((x0^70) - 6*(x0^65) - (x0^60) + 60*(x0^55) - 54*(x0^50) - 230*(x0^45) + 274*(x0^40) + 542*(x0^35) - 615*(x0^30) - 1120*(x0^25) + 1500*(x0^20) - 160*(x0^15) - 395*(x0^10) + 76*(x0^5) + 34, 3); tst_mfact(((x0^4) - 8*(x0^2)), 2); tst_mfact((x0^5) - 2*(x0^3) + x0 - 1, 1); - tst_mfact( (x0^25) - 4*(x0^21) - 5*(x0^20) + 6*(x0^17) + 11*(x0^16) + 10*(x0^15) - 4*(x0^13) - 7*(x0^12) - 9*(x0^11) - 10*(x0^10) + + tst_mfact( (x0^25) - 4*(x0^21) - 5*(x0^20) + 6*(x0^17) + 11*(x0^16) + 10*(x0^15) - 4*(x0^13) - 7*(x0^12) - 9*(x0^11) - 10*(x0^10) + (x0^9) + (x0^8) + (x0^7) + (x0^6) + 3*(x0^5) + x0 - 1, 2); tst_mfact( (x0^25) - 10*(x0^21) - 10*(x0^20) - 95*(x0^17) - 470*(x0^16) - 585*(x0^15) - 40*(x0^13) - 1280*(x0^12) - 4190*(x0^11) - 3830*(x0^10) + 400*(x0^9)+ 1760*(x0^8) + 760*(x0^7) - 2280*(x0^6) + 449*(x0^5) + 640*(x0^3) - 640*(x0^2) + 240*x0 - 32, 2); tst_mfact( x0^10, 1); @@ -1099,7 +1119,7 @@ static void tst_mfact() { tst_mfact( (x0^50) - 10*(x0^40) + 38*(x0^30) - 2*(x0^25) - 100*(x0^20) - 40*(x0^15) + 121*(x0^10) - 38*(x0^5) - 17, 1); polynomial_ref & y = x0; tst_mfact( (((y^5) + 5*(y^4) + 10*(y^3) + 10*(y^2) + 5*y)^10) - + 10*(((y^5) + 5*(y^4) + 10*(y^3) + 10*(y^2) + 5*y)^9) + + 10*(((y^5) + 5*(y^4) + 10*(y^3) + 10*(y^2) + 5*y)^9) + 35*(((y^5) + 5*(y^4) + 10*(y^3) + 10*(y^2) + 5*y)^8) + 40*(((y^5) + 5*(y^4) + 10*(y^3) + 10*(y^2) + 5*y)^7) - 32*(((y^5) + 5*(y^4) + 10*(y^3) + 10*(y^2) + 5*y)^6) @@ -1113,32 +1133,32 @@ static void tst_mfact() { tst_mfact( ((y^5) - 15552)* ((y^20)- 15708*(y^15) + rational("138771724")*(y^10)- rational("432104148432")*(y^5) + rational("614198284585616")), 2); - tst_mfact( (y^25) - - rational("3125")*(y^21) - - rational("15630")*(y^20) + - rational("3888750")*(y^17) + - rational("38684375")*(y^16) + - rational("95765635")*(y^15) - - rational("2489846500")*(y^13) - - rational("37650481875")*(y^12) - - rational("190548065625")*(y^11) - - rational("323785250010")*(y^10) + - rational("750249453025")*(y^9) + - rational("14962295699875")*(y^8) + - rational("111775113235000")*(y^7) + - rational("370399286731250")*(y^6) + - rational("362903064503129")*(y^5) - - rational("2387239013984400")*(y^4) - - rational("23872390139844000")*(y^3) - - rational("119361950699220000")*(y^2) - - rational("298404876748050000")*y - + tst_mfact( (y^25) - + rational("3125")*(y^21) - + rational("15630")*(y^20) + + rational("3888750")*(y^17) + + rational("38684375")*(y^16) + + rational("95765635")*(y^15) - + rational("2489846500")*(y^13) - + rational("37650481875")*(y^12) - + rational("190548065625")*(y^11) - + rational("323785250010")*(y^10) + + rational("750249453025")*(y^9) + + rational("14962295699875")*(y^8) + + rational("111775113235000")*(y^7) + + rational("370399286731250")*(y^6) + + rational("362903064503129")*(y^5) - + rational("2387239013984400")*(y^4) - + rational("23872390139844000")*(y^3) - + rational("119361950699220000")*(y^2) - + rational("298404876748050000")*y - rational("298500366308609376"), 2); tst_mfact( rational("54")*(y^24) - (y^27) - 324*(y^21) + rational("17496")*(y^18) - 34992*(y^15)+ rational("1889568")*(y^12)- 1259712*(y^9) + rational("68024448")*(y^6), 3); tst_mfact( ((y^3)- 432)*(((y^3)+54)^2)*((y^6)+108)*((y^6)+6912)*((y^6)- 324*(y^3)+37044), 5); - + tst_mfact( ((y^6)- 6*(y^4) - 864*(y^3) + 12*(y^2) - 5184*y + 186616)* (((y^6) - 6*(y^4) + 108*(y^3) + 12*(y^2) + 648*y + 2908)^2)* ((y^12) - 12*(y^10) + 60*(y^8) + 56*(y^6) + 6720*(y^4) + 12768*(y^2) + 13456)* @@ -1175,13 +1195,13 @@ static void tst_mfact() { static void tst_zp() { unsynch_mpz_manager z; - polynomial::manager pm(z); - + reslimit rl; polynomial::manager pm(rl, z); + polynomial_ref x(pm); polynomial_ref y(pm); x = pm.mk_polynomial(pm.mk_var()); y = pm.mk_polynomial(pm.mk_var()); - + polynomial_ref p(pm); polynomial_ref q(pm); p = (x^4) + 2*(x^3) + 2*(x^2) + x; @@ -1200,11 +1220,11 @@ static void tst_zp() { std::cout << "q[Z_3]: " << q3 << "\n"; std::cout << "gcd[Z_3]: " << gcd(p3, q3) << "\n"; } - + std::cout << "back into Z[x,y]\ngcd: " << gcd(p, q) << "\n"; - + p = 5*(x^2)*(y^2) + 3*(x^3) + 7*(y^3) + 3; - { + { polynomial::scoped_set_zp setZ11(pm, 11); polynomial_ref p11(pm); @@ -1219,7 +1239,7 @@ static void tst_zp() { std::cout << "gcd: " << gcd(p, q) << "\n"; } -static void tst_translate(polynomial_ref const & p, polynomial::var x0, int v0, polynomial::var x1, int v1, polynomial::var x2, int v2, +static void tst_translate(polynomial_ref const & p, polynomial::var x0, int v0, polynomial::var x1, int v1, polynomial::var x2, int v2, polynomial_ref const & expected) { std::cout << "---------------\n"; std::cout << "p: " << p << std::endl; @@ -1233,7 +1253,7 @@ static void tst_translate(polynomial_ref const & p, polynomial::var x0, int v0, static void tst_translate() { unsynch_mpq_manager qm; - polynomial::manager m(qm); + reslimit rl; polynomial::manager m(rl, qm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -1254,7 +1274,7 @@ static void tst_translate() { tst_translate(x3 + 1, 0, 1, 1, 2, 3, 10, x3 + 11 ); - tst_translate((x0^3)*(x1^2) + (x0^2)*(x1^3) + 10, 0, -3, 1, -2, 3, 0, + tst_translate((x0^3)*(x1^2) + (x0^2)*(x1^3) + 10, 0, -3, 1, -2, 3, 0, (x0^3)*(x1^2) + (x0^2)*(x1^3) - 4*(x0^3)*x1 - 15*(x0^2)*(x1^2) - 6*x0*(x1^3) + 4*(x0^3) + 48*(x0^2)*x1 + 63*x0*(x1^2) + 9*(x1^3) - 44*(x0^2) - 180*x0*x1 - 81*(x1^2) + 156*x0 + 216*x1 - 170 @@ -1264,7 +1284,7 @@ static void tst_translate() { #if 0 static void tst_p25() { unsynch_mpq_manager qm; - polynomial::manager m(qm); + reslimit rl; polynomial::manager m(rl, qm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -1288,10 +1308,11 @@ static void tst_p25() { static void tst_mm() { unsynch_mpq_manager qm; // pm1 and pm2 share the same monomial manager - polynomial::manager * pm1_ptr = alloc(polynomial::manager, qm); + reslimit rl; + polynomial::manager * pm1_ptr = alloc(polynomial::manager, rl, qm); polynomial::manager & pm1 = *pm1_ptr; - polynomial::manager pm2(qm, &pm1.mm()); - polynomial::manager pm3(qm); // pm3 has its own manager + polynomial::manager pm2(rl, qm, &pm1.mm()); + polynomial::manager pm3(rl, qm); // pm3 has its own manager polynomial_ref p2(pm2); { polynomial_ref x0(pm1); @@ -1302,7 +1323,7 @@ static void tst_mm() { x2 = pm1.mk_polynomial(pm1.mk_var()); polynomial_ref p1(pm1); p1 = (x0 + x1 + x2)^2; - + std::cout << "p1: " << p1 << "\n"; p2 = convert(pm1, p1, pm2); std::cout << "p2: " << p2 << "\n"; @@ -1317,7 +1338,7 @@ static void tst_mm() { std::cout << "p2: " << p2 << "\n"; } -static void tst_eval(polynomial_ref const & p, polynomial::var x0, rational v0, polynomial::var x1, rational v1, polynomial::var x2, rational v2, +static void tst_eval(polynomial_ref const & p, polynomial::var x0, rational v0, polynomial::var x1, rational v1, polynomial::var x2, rational v2, rational expected) { TRACE("eval_bug", tout << "tst_eval, " << p << "\n";); std::cout << "p: " << p << "\nx" << x0 << " -> " << v0 << "\nx" << x1 << " -> " << v1 << "\nx" << x2 << " -> " << v2 << "\n"; @@ -1336,7 +1357,7 @@ static void tst_eval(polynomial_ref const & p, polynomial::var x0, rational v0, static void tst_eval() { polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -1369,7 +1390,7 @@ static void tst_eval() { static void tst_mk_unique() { polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -1380,7 +1401,7 @@ static void tst_mk_unique() { polynomial_ref p(m); polynomial_ref q(m); polynomial_ref r(m); - + p = (x0^3) + (x2^5) + x0*x1 + x0*x1*x1 + 3*x0*x0 + 5; q = x0*x1*x1 + (x0^3) + 3*x0*x0 + (x2^5) + 5 + x0*x1; r = x0*x1*x1 + (x0^3) + 3*x0*x0 + (x2^5) + 6 + x0*x1; @@ -1414,7 +1435,7 @@ static void tst_del_eh() { dummy_del_eh eh2; polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); x0 = m.mk_polynomial(m.mk_var()); @@ -1423,7 +1444,7 @@ static void tst_del_eh() { m.add_del_eh(&eh1); x1 = 0; SASSERT(eh1.m_counter == 1); - + m.add_del_eh(&eh2); x1 = m.mk_polynomial(m.mk_var()); x1 = 0; @@ -1444,7 +1465,7 @@ static void tst_del_eh() { static void tst_const_coeff() { polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); x0 = m.mk_polynomial(m.mk_var()); @@ -1453,7 +1474,7 @@ static void tst_const_coeff() { scoped_mpz c(nm); polynomial_ref p(m); - + p = (x0^2)*x1 + 3*x0 + x1; SASSERT(!m.const_coeff(p, 0, 2, c)); SASSERT(m.const_coeff(p, 0, 1, c) && c == 3); @@ -1490,7 +1511,7 @@ static void tst_const_coeff() { static void tst_gcd2() { // enable_trace("mgcd"); polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m); polynomial_ref x1(m); polynomial_ref x2(m); @@ -1525,11 +1546,11 @@ static void tst_gcd2() { (7*3*(x1^2) + 7*6*(x2^2) + 7*21*(x3^3))*(5*(x1^3) + 7*(x0^2) + 13), (3*(x1^2) + 6*(x2^2) + 21*(x3^3))); - tst_gcd((x2^6)*(x3^6) - 4*(x2^3)*(x3^6) + 2*(x2^6)*(x3^3) - 8*(x2^3)*(x3^3) + 4*(x1^3)*(x2^3)*(x3^3) - 8*(x1^3)*(x3^3) + + tst_gcd((x2^6)*(x3^6) - 4*(x2^3)*(x3^6) + 2*(x2^6)*(x3^3) - 8*(x2^3)*(x3^3) + 4*(x1^3)*(x2^3)*(x3^3) - 8*(x1^3)*(x3^3) + 4*(x3^6) + 8*(x3^3) + (x2^6) - 4*(x2^3) + 4*(x1^3)*(x2^3) - 8*(x1^3) + 4 + (x1^6), (-2)*(x2^3)*(x3^6) - 4*(x2^3)*(x3^3) + 4*(x3^6) + 8*(x3^3) - 2*(x1^3)*(x3^3) - 2*(x2^3) + 4 - 2*(x1^3), one); - + tst_gcd((x1^2) - 2*x0 + 1 + (x0^2) + x0*x1 - 2*x1, x0*x1, one); @@ -1541,7 +1562,7 @@ static void tst_gcd2() { p = 169*(x1^12)*(x2^16) - 468*x0*(x1^11)*(x2^16) + 428*(x0^2)*(x1^10)*(x2^16) - 92*(x0^3)*(x1^9)*(x2^16) - 82*(x0^4)*(x1^8)*(x2^16) + 52*(x0^5)*(x1^7)*(x2^16) - 4*(x0^6)*(x1^6)*(x2^16) - 4*(x0^7)*(x1^5)*(x2^16) + (x0^8)*(x1^4)*(x2^16) - 581*(x1^14)*(x2^14) + 1828*x0*(x1^13)*(x2^14) - 2452*(x0^2)*(x1^12)*(x2^14) + 548*(x0^3)*(x1^11)*(x2^14) + 1002*(x0^4)*(x1^10)*(x2^14) - 756*(x0^5)*(x1^9)*(x2^14) + 124*(x0^6)*(x1^8)*(x2^14) + 44*(x0^7)*(x1^7)*(x2^14) - 13*(x0^8)*(x1^6)*(x2^14) + 895*(x1^16)*(x2^12) - 1556*x0*(x1^15)*(x2^12) + 2864*(x0^2)*(x1^14)*(x2^12); tst_gcd(p, derivative(p, 2), (x1^4)*(x2^11)); - tst_gcd((11*5*3)*((x0^2) + 1)*(x1 + 3), + tst_gcd((11*5*3)*((x0^2) + 1)*(x1 + 3), (11*5*7)*((x0^2) + 1)*(x1 + 5), (11*5)*((x0^2) + 1)); @@ -1565,7 +1586,7 @@ static void tst_gcd2() { neg((-1)*(x0^2)*(x2^3)*(x3^6) + 2*x0*(x1^3)*(x2^3)*(x3^3) + (x0^3)*(x3^7) - (x1^6)*(x2^3) - 2*(x0^2)*(x1^3)*(x3^4) - (x0^3)*(x3^6) + x0*(x1^6)*x3 + 2*(x0^2)*(x1^3)*(x3^3) - 2*(x0^2)*(x2^3)*(x3^3) + 2*(x0^2)*(x3^6) - x0*(x1^6) + 2*x0*(x1^3)*(x2^3) - 4*x0*(x1^3)*(x3^3) + 2*(x0^3)*(x3^4) + 2*(x1^6) - 2*(x0^2)*(x1^3)*x3 - 2*(x0^3)*(x3^3) + 2*(x0^2)*(x1^3) - (x0^2)*(x2^3) + 4*(x0^2)*(x3^3) - 4*x0*(x1^3) + (x0^3)*x3 - (x0^3) + 2*(x0^2)) ); - tst_gcd(((11*5*3)*(x0^2) + 1)*(x1 + 3), + tst_gcd(((11*5*3)*(x0^2) + 1)*(x1 + 3), ((11*5*3)*(x0^2) + 1)*(x1 + 5), ((11*5*3)*(x0^2) + 1)); @@ -1582,7 +1603,7 @@ static void tst_gcd3() { enable_trace("polynomial_gcd_detail"); enable_trace("mpzzp"); polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); polynomial_ref p(m); @@ -1607,7 +1628,7 @@ static void tst_gcd4() { enable_trace("mgcd"); // enable_trace("CRA"); polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); polynomial_ref p(m); @@ -1626,12 +1647,12 @@ static void tst_gcd4() { (1000000*x + 1)*(333333333*x + 1)*(77777777*x + 1)*(11111111*x + 1)*(x + 128384747)*(x + 82837437)*(x + 22848481); tst_gcd(p, derivative(p, 0), (x + 3)^9); } -#endif +#endif static void tst_newton_interpolation() { // enable_trace("newton"); polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x(m); polynomial_ref y(m); x = m.mk_polynomial(m.mk_var()); @@ -1654,7 +1675,7 @@ static void tst_newton_interpolation() { static void tst_slow_mod_gcd() { polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m), x1(m), x2(m), x3(m), x4(m), x5(m); x0 = m.mk_polynomial(m.mk_var()); x1 = m.mk_polynomial(m.mk_var()); @@ -1675,17 +1696,17 @@ static void tst_slow_mod_gcd() { tst_gcd(p, q, b); return; - p = (x0^8) * - (((x0^3)*x1*x2*x3*x4*x5 + x0*(x1^3)*x2*x3*x4*x5 + x0*x1*(x2^3)*x3*x4*x5 + x0*x1*x2*(x3^3)*x4*x5 + + p = (x0^8) * + (((x0^3)*x1*x2*x3*x4*x5 + x0*(x1^3)*x2*x3*x4*x5 + x0*x1*(x2^3)*x3*x4*x5 + x0*x1*x2*(x3^3)*x4*x5 + x0*x1*x2*x3*(x4^3)*x5 + x0*x1*x2*x3*x4*(x5^3) - x0*x1*x2*x3*x4*x5 - 2)^2) * - (((x0^3)*x1*x2*x3*x4*x5 + x0*(x1^3)*x2*x3*x4*x5 + x0*x1*(x2^3)*x3*x4*x5 + x0*x1*x2*(x3^3)*x4*x5 + + (((x0^3)*x1*x2*x3*x4*x5 + x0*(x1^3)*x2*x3*x4*x5 + x0*x1*(x2^3)*x3*x4*x5 + x0*x1*x2*(x3^3)*x4*x5 + x0*x1*x2*x3*(x4^3)*x5 + x0*x1*x2*x3*x4*(x5^3) - x0*x1*x2*x3*x4*x5 + 2)^2); p_prime = derivative(p, 0); tst_gcd(p, p_prime, - (x0^7) * - ((x0^3)*x1*x2*x3*x4*x5 + x0*(x1^3)*x2*x3*x4*x5 + x0*x1*(x2^3)*x3*x4*x5 + x0*x1*x2*(x3^3)*x4*x5 + - x0*x1*x2*x3*(x4^3)*x5 + x0*x1*x2*x3*x4*(x5^3) - x0*x1*x2*x3*x4*x5 - 2) * - ((x0^3)*x1*x2*x3*x4*x5 + x0*(x1^3)*x2*x3*x4*x5 + x0*x1*(x2^3)*x3*x4*x5 + x0*x1*x2*(x3^3)*x4*x5 + + (x0^7) * + ((x0^3)*x1*x2*x3*x4*x5 + x0*(x1^3)*x2*x3*x4*x5 + x0*x1*(x2^3)*x3*x4*x5 + x0*x1*x2*(x3^3)*x4*x5 + + x0*x1*x2*x3*(x4^3)*x5 + x0*x1*x2*x3*x4*(x5^3) - x0*x1*x2*x3*x4*x5 - 2) * + ((x0^3)*x1*x2*x3*x4*x5 + x0*(x1^3)*x2*x3*x4*x5 + x0*x1*(x2^3)*x3*x4*x5 + x0*x1*x2*(x3^3)*x4*x5 + x0*x1*x2*x3*(x4^3)*x5 + x0*x1*x2*x3*x4*(x5^3) - x0*x1*x2*x3*x4*x5 + 2)); } @@ -1698,7 +1719,7 @@ void tst_linear_solver() { solver.resize(3); xs.resize(3); - + as.reset(); as.push_back(mpq(2)); as.push_back(mpq(1)); as.push_back(mpq(-1)); qm.set(b, 8); solver.add(0, as.c_ptr(), b); @@ -1710,7 +1731,7 @@ void tst_linear_solver() { as.reset(); as.push_back(mpq(-2)); as.push_back(mpq(1)); as.push_back(mpq(2)); qm.set(b, -3); solver.add(2, as.c_ptr(), b); - + VERIFY(solver.solve(xs.c_ptr())); SASSERT(qm.eq(xs[0], mpq(2))); SASSERT(qm.eq(xs[1], mpq(3))); @@ -1719,7 +1740,7 @@ void tst_linear_solver() { static void tst_lex(polynomial_ref const & p1, polynomial_ref const & p2, int lex_expected, polynomial::var min, int lex2_expected) { polynomial::manager & m = p1.m(); - std::cout << "compare "; + std::cout << "compare "; m.display(std::cout, m.get_monomial(p1, 0)); std::cout << " "; m.display(std::cout, m.get_monomial(p2, 0)); @@ -1735,7 +1756,7 @@ static void tst_lex(polynomial_ref const & p1, polynomial_ref const & p2, int le static void tst_lex() { polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m), x1(m), x2(m), x3(m), x4(m), x5(m); x0 = m.mk_polynomial(m.mk_var()); x1 = m.mk_polynomial(m.mk_var()); @@ -1743,13 +1764,13 @@ static void tst_lex() { x3 = m.mk_polynomial(m.mk_var()); x4 = m.mk_polynomial(m.mk_var()); x5 = m.mk_polynomial(m.mk_var()); - + polynomial_ref one(m); one = m.mk_const(mpz(1)); tst_lex(x0*x4*x1, (x0^10)*(x1^3), 1, 4, -1); tst_lex(x0*x3*(x1^2)*x4, x0*(x3^2)*(x1^2)*x4, -1, 3, -1); - tst_lex((x0^2)*x3*(x1^2)*x4, x0*(x3^2)*(x1^2)*x4, -1, 3, 1); + tst_lex((x0^2)*x3*(x1^2)*x4, x0*(x3^2)*(x1^2)*x4, -1, 3, 1); tst_lex(x0*x3*(x1^2)*x4, x0*x3*(x1^2)*x4, 0, 3, 0); tst_lex(x0*(x3^2)*(x1^2)*x4, x0*x3*(x1^2)*x4, 1, 3, 1); tst_lex((x1^2)*x4, x0*x2*x3*x4*x5, -1, 1, -1); @@ -1772,18 +1793,18 @@ static void tst_lex() { static void tst_divides() { polynomial::numeral_manager nm; - polynomial::manager m(nm); + reslimit rl; polynomial::manager m(rl, nm); polynomial_ref x0(m); x0 = m.mk_polynomial(m.mk_var()); polynomial_ref q(m); polynomial_ref p(m); - q = 16*(x0^27) - 1984*(x0^26) + 1762*(x0^25) + 17351*(x0^24) - 14165*(x0^23) + 16460*(x0^22) + 2919*(x0^21) - 16823*(x0^20) + 1530*(x0^19) + + q = 16*(x0^27) - 1984*(x0^26) + 1762*(x0^25) + 17351*(x0^24) - 14165*(x0^23) + 16460*(x0^22) + 2919*(x0^21) - 16823*(x0^20) + 1530*(x0^19) + 10646*(x0^18) + 19217*(x0^17); - p = 16*(x0^39) - 3648*(x0^38) + 338136*(x0^37) - 16037936*(x0^36) + 392334357*(x0^35) - rational("3851617443")*(x0^34) - - rational("14636221526")*(x0^33) + rational("377151717618")*(x0^32) + rational("677140776981")*(x0^31) - rational("4308280094419")*(x0^30) + - rational("312708087606")*(x0^29) + rational("8205543533730")*(x0^28) + rational("3331586202704")*(x0^27) - rational("15291636627072")*(x0^26) + - rational("433482645282")*(x0^25) + rational("7397104817486")*(x0^24) + rational("1021197979053")*(x0^23) - rational("1373737505247")*(x0^22) - + p = 16*(x0^39) - 3648*(x0^38) + 338136*(x0^37) - 16037936*(x0^36) + 392334357*(x0^35) - rational("3851617443")*(x0^34) - + rational("14636221526")*(x0^33) + rational("377151717618")*(x0^32) + rational("677140776981")*(x0^31) - rational("4308280094419")*(x0^30) + + rational("312708087606")*(x0^29) + rational("8205543533730")*(x0^28) + rational("3331586202704")*(x0^27) - rational("15291636627072")*(x0^26) + + rational("433482645282")*(x0^25) + rational("7397104817486")*(x0^24) + rational("1021197979053")*(x0^23) - rational("1373737505247")*(x0^22) - rational("639394669026")*(x0^21) - rational("118513560618")*(x0^20) - rational("10405319535")*(x0^19) - rational("358722675")*(x0^18); std::cout << "----------------------\n"; std::cout << "q: " << q << "\n"; @@ -1813,7 +1834,7 @@ void tst_polynomial() { tst_linear_solver(); tst_newton_interpolation(); tst_resultant(); - // + // // tst_gcd4(); // tst_gcd3(); tst_zp(); diff --git a/src/test/polynomial_factorization.cpp b/src/test/polynomial_factorization.cpp index 7af0742ef..361ca4630 100644 --- a/src/test/polynomial_factorization.cpp +++ b/src/test/polynomial_factorization.cpp @@ -19,7 +19,7 @@ Notes: #include"upolynomial_factorization_int.h" #include"timeit.h" #include"polynomial.h" - +#include"rlimit.h" #if 0 #include"polynomial_factorization.h" #endif @@ -41,30 +41,30 @@ unsigned knuth_factors[2][11] = { // [k,l,i]: how many factors the S_k has over p_i, when i = 0 it's Z, p_1 = 2, for l=0 distinct, for l = 1 total unsigned swinnerton_dyer_factors[5][2][11] = { - // S1 = (x^2) - 2 + // S1 = (x^2) - 2 { - // 2, 3, 5, 7,11,13,17,19,23,29, Z + // 2, 3, 5, 7,11,13,17,19,23,29, Z {1, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1}, {2, 1, 1, 2, 1, 1, 2, 1, 2, 1, 1} }, - // S2 = (x^4) - 10*(x^2) + 1 + // S2 = (x^4) - 10*(x^2) + 1 { {1, 1, 2, 2, 2, 2, 2, 2, 4, 2, 1}, {4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 1} }, - // S3 = (x^8) - 40*(x^6) + 352*(x^4) - 960*(x^2) + 576 + // S3 = (x^8) - 40*(x^6) + 352*(x^4) - 960*(x^2) + 576 { {1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 1}, {8, 6, 4, 4, 4, 4, 4, 4, 4, 4, 1} }, - // S4 = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225 + // S4 = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225 { {1, 4, 3, 4, 8, 8, 8, 8, 8, 8, 1}, {16, 12, 10, 8, 8, 8, 8, 8, 8, 8, 1} }, // SA = S1*S2*S3*S4 { - //p = 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, Z + //p = 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, Z { 2, 6, 3, 6, 15, 11, 16, 15, 18, 15, 1}, {30, 21, 17, 16, 15, 15, 16, 15, 18, 15, 1} } @@ -176,17 +176,17 @@ int random_polynomial[20][2][11] = { #if 0 static void tst_square_free_finite_1() { polynomial::numeral_manager nm; - polynomial::manager pm(nm); + reslimit rl; polynomial::manager pm(rl, nm); // example from Knuth, p. 442 polynomial_ref x(pm); x = pm.mk_polynomial(pm.mk_var()); // polynomials \prod_{i < p} (x - i)^i - for (unsigned prime_i = 0; prime_i < 5; ++ prime_i) + for (unsigned prime_i = 0; prime_i < 5; ++ prime_i) { int p = primes[prime_i]; - + // make the polynomial polynomial_ref f(pm); f = x - 1; @@ -222,19 +222,19 @@ static void tst_square_free_finite_1() { } static void tst_factor_finite_1() { - + polynomial::numeral_manager nm; - polynomial::manager pm(nm); + reslimit rl; polynomial::manager pm(rl, nm); // example from Knuth, p. 442 polynomial_ref x(pm); x = pm.mk_polynomial(pm.mk_var()); polynomial_ref K(pm); K = (x^8) + (x^6) + 10*(x^4) + 10*(x^3) + 8*(x^2) + 2*x + 8; - + // factor them for all the prime numbers - for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) - { + for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) + { // make the Z_p unsigned prime = primes[prime_i]; upolynomial::zp_manager upm(nm); @@ -246,35 +246,35 @@ static void tst_factor_finite_1() { cout << "Factoring " << K << "("; upm.display(cout, K_u); cout << ") in Z_" << prime << endl; cout << "Expecting " << knuth_factors[0][prime_i] << " distinct factors, " << knuth_factors[1][prime_i] << " total" << endl; - + // factor it - upolynomial::zp_factors factors(upm); + upolynomial::zp_factors factors(upm); /* bool factorized = */ upolynomial::zp_factor(upm, K_u, factors); - + // check the result unsigned distinct = factors.distinct_factors(); - unsigned total = factors.total_factors(); + unsigned total = factors.total_factors(); cout << "Got " << factors << endl; cout << "Thats " << distinct << " distinct factors, " << total << " total" << endl; SASSERT(knuth_factors[0][prime_i] == distinct); SASSERT(knuth_factors[1][prime_i] == total); - + upolynomial::numeral_vector multiplied; factors.multiply(multiplied); SASSERT(upm.eq(K_u, multiplied)); upm.reset(multiplied); - + // remove the temp upm.reset(K_u); - } + } } static void tst_factor_finite_2() { - + polynomial::numeral_manager nm; - polynomial::manager pm(nm); + reslimit rl; polynomial::manager pm(rl, nm); polynomial_ref x(pm); x = pm.mk_polynomial(pm.mk_var()); @@ -284,7 +284,7 @@ static void tst_factor_finite_2() { polynomial_ref S2 = (x^4) - 10*(x^2) + 1; polynomial_ref S3 = (x^8) - 40*(x^6) + 352*(x^4) - 960*(x^2) + 576; polynomial_ref S4 = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225; - + vector S; S.push_back(S1); S.push_back(S2); @@ -294,9 +294,9 @@ static void tst_factor_finite_2() { // factor all the S_i them for all the prime numbers for (unsigned S_i = 0; S_i < S.size(); ++ S_i) { - for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) { - unsigned prime = primes[prime_i]; - + for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) { + unsigned prime = primes[prime_i]; + upolynomial::zp_manager upm(nm); upm.set_zp(prime); @@ -308,22 +308,22 @@ static void tst_factor_finite_2() { upolynomial::zp_factors factors(upm); upolynomial::zp_factor(upm, S_i_u, factors); - + // check the result unsigned distinct = factors.distinct_factors(); - unsigned total = factors.total_factors(); + unsigned total = factors.total_factors(); cout << "Got " << factors << endl; cout << "Thats " << distinct << " distinct factors, " << total << " total" << endl; SASSERT(swinnerton_dyer_factors[S_i][0][prime_i] == distinct); SASSERT(swinnerton_dyer_factors[S_i][1][prime_i] == total); - + upolynomial::numeral_vector multiplied; factors.multiply(multiplied); SASSERT(upm.eq(S_i_u, multiplied)); upm.reset(multiplied); - + // remove the temp upm.reset(S_i_u); } @@ -331,9 +331,9 @@ static void tst_factor_finite_2() { } static void tst_factor_finite_3() { - + polynomial::numeral_manager nm; - polynomial::manager pm(nm); + reslimit rl; polynomial::manager pm(rl, nm); polynomial_ref x(pm); x = pm.mk_polynomial(pm.mk_var()); @@ -360,15 +360,15 @@ static void tst_factor_finite_3() { random_p.push_back( 3*(x^10) + 2*(x^8) + 1*(x^7) + 1*(x^6) + 3*(x^4) + 3*(x^3) + 4*(x^2) + 3*x + 0 ); random_p.push_back( 1*(x^10) + 2*(x^9) + 2*(x^6) + 4*(x^3) + 4*(x^2) + 0 ); random_p.push_back( 1*(x^10) + 2*(x^9) + 2*(x^8) + 4*(x^7) + 4*(x^6) + 1*(x^5) + 1*(x^3) + 1*(x^2) + 3*x + 0 ); - + // factor all the randoms them for all the prime numbers for (unsigned random_i = 0; random_i < random_p.size(); ++ random_i) { - for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) { - unsigned prime = primes[prime_i]; - + for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) { + unsigned prime = primes[prime_i]; + upolynomial::zp_manager upm(nm); upm.set_zp(prime); - + upolynomial::numeral_vector poly; upm.to_numeral_vector(random_p[random_i], poly); @@ -377,24 +377,24 @@ static void tst_factor_finite_3() { upolynomial::zp_factors factors(upm); upolynomial::zp_factor(upm, poly, factors); - + // check the result unsigned distinct = factors.distinct_factors(); - unsigned total = factors.total_factors(); + unsigned total = factors.total_factors(); cout << "Got " << factors << endl; cout << "Thats " << distinct << " distinct factors, " << total << " total" << endl; // SASSERT(random_polynomial[random_i][0][prime_i] == distinct); // SASSERT(random_polynomial[random_i][1][prime_i] == total); - + upolynomial::numeral_vector multiplied; factors.multiply(multiplied); bool equal = upm.eq(poly, multiplied); cout << (equal ? "equal" : "not equal") << endl; SASSERT(equal); upm.reset(multiplied); - + // remove the temp upm.reset(poly); } @@ -403,11 +403,11 @@ static void tst_factor_finite_3() { static void tst_factor_enumeration() { polynomial::numeral_manager nm; - polynomial::manager pm(nm); + reslimit rl; polynomial::manager pm(rl, nm); polynomial_ref x(pm); x = pm.mk_polynomial(pm.mk_var()); - + vector factors; for (int i = 0; i < 5; ++ i) { polynomial_ref factor(pm); @@ -419,12 +419,12 @@ static void tst_factor_enumeration() { upolynomial::zp_manager upm_13(nm); upm_13.set_zp(13); - upolynomial::zp_factors factors_13(upm_13); - + upolynomial::zp_factors factors_13(upm_13); + upolynomial::numeral constant; nm.set(constant, 10); factors_13.set_constant(constant); - + for (unsigned i = 0; i < 5; ++ i) { upolynomial::numeral_vector ufactor; upm_13.to_numeral_vector(factors[i], ufactor); @@ -463,7 +463,7 @@ static void tst_factor_enumeration() { factors_13.set_degree(i, factors_13.get_degree(i) + i); } cout << "Different: " << factors_13 << " of degree " << factors_13.get_degree() << endl; - upolynomial::factorization_degree_set degrees1(factors_13); + upolynomial::factorization_degree_set degrees1(factors_13); degrees1.display(cout); cout << endl; // [0, ..., 15] polynomial_ref tmp1 = (x^3) + 1; @@ -482,15 +482,15 @@ static void tst_factor_enumeration() { upm_13.reset(up3); cout << "Different: " << tmp << " of degree " << tmp.get_degree() << endl; - upolynomial::factorization_degree_set degrees2(tmp); - degrees2.display(cout); cout << endl; + upolynomial::factorization_degree_set degrees2(tmp); + degrees2.display(cout); cout << endl; tmp1 = (x^2) + 1; tmp2 = (x^10) + 2; - tmp3 = x + 3; + tmp3 = x + 3; upm_13.to_numeral_vector(tmp1, up1); upm_13.to_numeral_vector(tmp2, up2); - upm_13.to_numeral_vector(tmp3, up3); + upm_13.to_numeral_vector(tmp3, up3); tmp.clear(); tmp.push_back(up1, 2); tmp.push_back(up2, 1); @@ -499,23 +499,23 @@ static void tst_factor_enumeration() { upm_13.reset(up1); upm_13.reset(up2); upm_13.reset(up3); - upolynomial::factorization_degree_set degrees3(tmp); - degrees3.display(cout); cout << endl; + upolynomial::factorization_degree_set degrees3(tmp); + degrees3.display(cout); cout << endl; degrees1.intersect(degrees3); degrees1.display(cout); cout << endl; } static void tst_factor_square_free_univariate_1(unsigned max_length) { - - polynomial::numeral_manager nm; + + polynomial::numeral_manager nm; upolynomial::numeral test; upolynomial::numeral p; nm.set(test, -9); nm.set(p, 5); nm.mod(test, p, test); - polynomial::manager pm(nm); - + reslimit rl; polynomial::manager pm(rl, nm); + polynomial_ref x(pm); x = pm.mk_polynomial(pm.mk_var()); @@ -527,8 +527,8 @@ static void tst_factor_square_free_univariate_1(unsigned max_length) { for(unsigned length = 1; length < max_length; ++ length) { // starting from prime_i going for length - for(unsigned start_i = 0; start_i < n_primes; ++ start_i) { - + for(unsigned start_i = 0; start_i < n_primes; ++ start_i) { + polynomial_ref f(pm); bool first = true; @@ -541,18 +541,18 @@ static void tst_factor_square_free_univariate_1(unsigned max_length) { } else { f = f*(p1*(x^p2) - p2); } - } - + } + upolynomial::manager upm(nm); scoped_mpz_vector f_u(nm); upm.to_numeral_vector(f, f_u); - + cout << "factoring "; upm.display(cout, f_u); cout << endl; cout << "expecting " << length << " factors "; upolynomial::factors factors(upm); - /* bool ok = */ upolynomial::factor_square_free(upm, f_u, factors); + /* bool ok = */ upolynomial::factor_square_free(upm, f_u, factors); cout << "got " << factors << endl; - + SASSERT(factors.distinct_factors() == length); } } @@ -560,7 +560,7 @@ static void tst_factor_square_free_univariate_1(unsigned max_length) { static void tst_factor_square_free_univariate_2() { polynomial::numeral_manager nm; - polynomial::manager pm(nm); + reslimit rl; polynomial::manager pm(rl, nm); polynomial_ref x(pm); x = pm.mk_polynomial(pm.mk_var()); @@ -570,7 +570,7 @@ static void tst_factor_square_free_univariate_2() { polynomial_ref S2 = (x^4) - 10*(x^2) + 1; polynomial_ref S3 = (x^8) - 40*(x^6) + 352*(x^4) - 960*(x^2) + 576; polynomial_ref S4 = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225; - + vector S; S.push_back(S1); S.push_back(S2); @@ -580,17 +580,17 @@ static void tst_factor_square_free_univariate_2() { upolynomial::manager upm(nm); // factor all the S_i them for all the prime numbers - for (unsigned S_i = 0; S_i < S.size(); ++ S_i) { + for (unsigned S_i = 0; S_i < S.size(); ++ S_i) { upolynomial::numeral_vector S_i_u; upm.to_numeral_vector(S[S_i], S_i_u); cout << "Factoring "; upm.display(cout, S_i_u); cout << " over Z " << endl; upolynomial::factors factors(upm); upolynomial::factor_square_free(upm, S_i_u, factors); - + // check the result cout << "Got " << factors << endl; - + // remove the temp upm.reset(S_i_u); } @@ -598,31 +598,31 @@ static void tst_factor_square_free_univariate_2() { static void tst_factor_square_free_univariate_3() { polynomial::numeral_manager nm; - polynomial::manager pm(nm); + reslimit rl; polynomial::manager pm(rl, nm); polynomial_ref x(pm); x = pm.mk_polynomial(pm.mk_var()); polynomial_ref deg70 = (x^70) - 6*(x^65) - (x^60) + 60*(x^55) - 54*(x^50) - 230*(x^45) + 274*(x^40) + 542*(x^35) - 615*(x^30) - 1120*(x^25) + 1500*(x^20) - 160*(x^15) - 395*(x^10) + 76*(x^5) + 34; - + upolynomial::manager upm(nm); upolynomial::numeral_vector deg70_u; - + upm.to_numeral_vector(deg70, deg70_u); cout << "Factoring "; upm.display(cout, deg70_u); cout << " over Z " << endl; upolynomial::factors factors(upm); upolynomial::factor_square_free(upm, deg70_u, factors); - + cout << "Got " << factors << endl; - + upm.reset(deg70_u); } #endif void tst_factor_swinnerton_dyer_big(unsigned max) { polynomial::numeral_manager nm; - polynomial::manager pm(nm); + reslimit rl; polynomial::manager pm(rl, nm); polynomial_ref x(pm); x = pm.mk_polynomial(pm.mk_var()); @@ -631,8 +631,8 @@ void tst_factor_swinnerton_dyer_big(unsigned max) { vector vars; unsigned n = std::min(max, static_cast(sizeof(primes)/sizeof(unsigned))); - for(unsigned prime_i = 0; prime_i < n; ++ prime_i) { - + for(unsigned prime_i = 0; prime_i < n; ++ prime_i) { + int prime = primes[prime_i]; cout << "Computing Swinnerton-Dyer[" << prime_i + 1 << "]" << endl; @@ -643,7 +643,7 @@ void tst_factor_swinnerton_dyer_big(unsigned max) { polynomial_ref p(pm); p = (y^2) - prime; - roots.push_back(p); + roots.push_back(p); polynomial_ref computation = x; for (unsigned i = 0; i < roots.size(); ++ i) { @@ -663,17 +663,18 @@ void tst_factor_swinnerton_dyer_big(unsigned max) { } cout << "Computed Swinnerton-Dyer[" << prime_i + 1 << "], degree = " << pm.total_degree(computation) << ", size = " << pm.size(computation) << endl; - + cout << "Starting factoring " << endl; - + { timeit timer(true, "factoring swinnerton-dyer"); - upolynomial::manager upm(nm); - scoped_mpz_vector sd_u(nm); - upm.to_numeral_vector(computation, sd_u); + reslimit rl; + upolynomial::manager upm(rl, nm); + scoped_mpz_vector sd_u(nm); + upm.to_numeral_vector(computation, sd_u); upolynomial::factors factors(upm); - upolynomial::factor_square_free(upm, sd_u, factors); + upolynomial::factor_square_free(upm, sd_u, factors); cout << "Got " << factors.distinct_factors() << " factors" << endl; } @@ -681,16 +682,16 @@ void tst_factor_swinnerton_dyer_big(unsigned max) { } static void tst_factor_square_free_multivariate_1(unsigned max_n) { -#if 0 - polynomial::numeral_manager nm; +#if 0 + polynomial::numeral_manager nm; upolynomial::numeral test; upolynomial::numeral p; nm.set(test, -9); nm.set(p, 5); nm.mod(test, p, test); - polynomial::manager pm(nm); - + reslimit rl; polynomial::manager pm(rl, nm); + polynomial_ref x(pm); x = pm.mk_polynomial(pm.mk_var()); @@ -700,7 +701,7 @@ static void tst_factor_square_free_multivariate_1(unsigned max_n) { // lets start simple x^n - y^n for (unsigned prime_i = 0; prime_i < sizeof(primes)/sizeof(unsigned); ++ prime_i) { unsigned prime = primes[prime_i]; - + if (prime > max_n) { break; } @@ -719,7 +720,7 @@ static void tst_factor_square_free_multivariate_1(unsigned max_n) { void tst_polynomial_factorization() { - + enable_trace("polynomial::factorization"); // enable_trace("polynomial::factorization::bughunt"); enable_trace("polynomial::factorization::multivariate"); @@ -727,12 +728,12 @@ void tst_polynomial_factorization() { // Z_p square-free factorization tests // tst_square_free_finite_1(); - + // Z_p factorization tests // tst_factor_finite_1(); // tst_factor_finite_2(); // tst_factor_finite_3(); - + // Z factorization // tst_factor_enumeration(); // tst_factor_square_free_univariate_1(3); diff --git a/src/test/rcf.cpp b/src/test/rcf.cpp index 294a7df29..170c053f1 100644 --- a/src/test/rcf.cpp +++ b/src/test/rcf.cpp @@ -18,10 +18,12 @@ Notes: --*/ #include"realclosure.h" #include"mpz_matrix.h" +#include"rlimit.h" static void tst1() { unsynch_mpq_manager qm; - rcmanager m(qm); + reslimit rl; + rcmanager m(rl, qm); scoped_rcnumeral a(m); #if 0 a = 10; @@ -37,14 +39,14 @@ static void tst1() { qm.set(aux, 1, 3); m.set(a, aux); -#if 0 +#if 0 std::cout << interval_pp(a) << std::endl; std::cout << decimal_pp(eps, 4) << std::endl; std::cout << decimal_pp(a) << std::endl; std::cout << a + eps << std::endl; std::cout << a * eps << std::endl; std::cout << (a + eps)*eps - eps << std::endl; -#endif +#endif std::cout << interval_pp(a - eps*2) << std::endl; std::cout << interval_pp(eps + 1) << std::endl; scoped_rcnumeral t(m); @@ -80,7 +82,7 @@ static void tst2() { // 0 1 1 A.set(0, 0, 1); A.set(0, 1, 1); A.set(0, 2, 1); A.set(1, 0, 0); A.set(1, 1, 1); A.set(1, 2, -1); - A.set(2, 0, 0); A.set(2, 1, 1); A.set(2, 2, 1); + A.set(2, 0, 0); A.set(2, 1, 1); A.set(2, 2, 1); std::cout << A; { int b[3]; @@ -143,8 +145,9 @@ static void tst_lin_indep(unsigned m, unsigned n, int _A[], unsigned ex_sz, unsi } static void tst_denominators() { + reslimit rl; unsynch_mpq_manager qm; - rcmanager m(qm); + rcmanager m(rl, qm); scoped_rcnumeral a(m); scoped_rcnumeral t(m); scoped_rcnumeral eps(m); diff --git a/src/test/simplex.cpp b/src/test/simplex.cpp index 3a5e58a4b..6f08bd04d 100644 --- a/src/test/simplex.cpp +++ b/src/test/simplex.cpp @@ -11,6 +11,7 @@ Copyright (c) 2015 Microsoft Corporation #include "mpq_inf.h" #include "vector.h" #include "rational.h" +#include "rlimit.h" #define R rational typedef simplex::simplex Simplex; @@ -99,7 +100,8 @@ static void feas(Simplex& S) { } static void test1() { - Simplex S; + reslimit rl; + Simplex S(rl); add_row(S, vec(1,0), R(1)); add_row(S, vec(0,1), R(1)); add_row(S, vec(1,1), R(1)); @@ -107,7 +109,7 @@ static void test1() { } static void test2() { - Simplex S; + reslimit rl; Simplex S(rl); add_row(S, vec(1, 0), R(1)); add_row(S, vec(0, 1), R(1)); add_row(S, vec(1, 1), R(1), true); @@ -115,7 +117,7 @@ static void test2() { } static void test3() { - Simplex S; + reslimit rl; Simplex S(rl); add_row(S, vec(-1, 0), R(-1)); add_row(S, vec(0, -1), R(-1)); add_row(S, vec(1, 1), R(1), true); @@ -123,7 +125,7 @@ static void test3() { } static void test4() { - Simplex S; + reslimit rl; Simplex S(rl); add_row(S, vec(1, 0), R(1)); add_row(S, vec(0, -1), R(-1)); add_row(S, vec(1, 1), R(1), true); @@ -131,7 +133,7 @@ static void test4() { } void tst_simplex() { - Simplex S; + reslimit rl; Simplex S(rl); std::cout << "simplex\n"; @@ -152,7 +154,7 @@ void tst_simplex() { is_sat = S.make_feasible(); std::cout << "feasible: " << is_sat << "\n"; S.display(std::cout); - _scoped_numeral num(em); + _scoped_numeral num(em); num = std::make_pair(mpq(1), mpq(0)); S.set_lower(0, num); S.set_upper(0, num); diff --git a/src/test/trigo.cpp b/src/test/trigo.cpp index da26d0f39..809d94fc2 100644 --- a/src/test/trigo.cpp +++ b/src/test/trigo.cpp @@ -23,13 +23,14 @@ Revision History: #include"ast.h" #include"debug.h" #include"im_float_config.h" +#include"rlimit.h" #define PREC 100000 static void tst_sine_core(std::ostream & out, unsynch_mpq_manager & nm, interval_manager & im, mpq & a, unsigned k) { scoped_mpq lo(nm), hi(nm); im.sine(a, k, lo, hi); - nm.display(out, lo); + nm.display(out, lo); out << " <= Sin["; nm.display(out, a); out << "]\n"; out << "Sin["; nm.display(out, a); out << "] <= "; nm.display(out, hi); @@ -37,9 +38,10 @@ static void tst_sine_core(std::ostream & out, unsynch_mpq_manager & nm, interval } static void tst_sine(std::ostream & out, unsigned N, unsigned k) { - unsynch_mpq_manager nm; + unsynch_mpq_manager nm; im_default_config imc(nm); - interval_manager im(imc); + reslimit rl; + interval_manager im(rl, imc); scoped_mpq a(nm); nm.set(a, 0); tst_sine_core(out, nm, im, a, 1); @@ -55,7 +57,7 @@ static void tst_sine(std::ostream & out, unsigned N, unsigned k) { static void tst_cosine_core(std::ostream & out, unsynch_mpq_manager & nm, interval_manager & im, mpq & a, unsigned k) { scoped_mpq lo(nm), hi(nm); im.cosine(a, k, lo, hi); - nm.display(out, lo); + nm.display(out, lo); out << " <= Cos["; nm.display(out, a); out << "]\n"; out << "Cos["; nm.display(out, a); out << "] <= "; nm.display(out, hi); @@ -63,9 +65,10 @@ static void tst_cosine_core(std::ostream & out, unsynch_mpq_manager & nm, interv } static void tst_cosine(std::ostream & out, unsigned N, unsigned k) { - unsynch_mpq_manager nm; + reslimit rl; + unsynch_mpq_manager nm; im_default_config imc(nm); - interval_manager im(imc); + interval_manager im(rl, imc); scoped_mpq a(nm); nm.set(a, 0); tst_cosine_core(out, nm, im, a, 1); @@ -79,10 +82,10 @@ static void tst_cosine(std::ostream & out, unsigned N, unsigned k) { template -static void tst_float_sine_core(std::ostream & out, - fmanager & fm, - interval_manager > & im, - typename fmanager::numeral & a, +static void tst_float_sine_core(std::ostream & out, + fmanager & fm, + interval_manager > & im, + typename fmanager::numeral & a, unsigned k) { _scoped_numeral lo(fm), hi(fm); im.sine(a, k, lo, hi); @@ -95,9 +98,10 @@ const unsigned SBITS = 53; template static void tst_float_sine(std::ostream & out, unsigned N, unsigned k) { + reslimit rl; fmanager fm; im_float_config ifc(fm, EBITS, SBITS); - interval_manager > im(ifc); + interval_manager > im(rl, ifc); _scoped_numeral a(fm); fm.set(a, EBITS, SBITS, static_cast(0)); tst_float_sine_core(out, fm, im, a, 1); @@ -130,9 +134,10 @@ static void tst_mpf_bug() { #endif static void tst_e(std::ostream & out) { - unsynch_mpq_manager nm; + reslimit rl; + unsynch_mpq_manager nm; im_default_config imc(nm); - interval_manager im(imc); + interval_manager im(rl, imc); im_default_config::interval r; for (unsigned i = 0; i < 64; i++) { im.e(i, r); @@ -144,10 +149,11 @@ static void tst_e(std::ostream & out) { static void tst_e_float(std::ostream & out) { std::cout << "e float...\n"; + reslimit rl; unsynch_mpq_manager qm; mpf_manager fm; im_float_config ifc(fm); - interval_manager > im(ifc); + interval_manager > im(rl, ifc); scoped_mpq q(qm); im_float_config::interval r; for (unsigned i = 0; i < 64; i++) { diff --git a/src/test/upolynomial.cpp b/src/test/upolynomial.cpp index b38c3af34..e7dcf2719 100644 --- a/src/test/upolynomial.cpp +++ b/src/test/upolynomial.cpp @@ -18,11 +18,13 @@ Notes: --*/ #include"upolynomial.h" #include"timeit.h" +#include"rlimit.h" static void tst1() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); - upolynomial::manager um(nm); + polynomial::manager m(rl, nm); + upolynomial::manager um(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package @@ -36,7 +38,7 @@ static void tst1() { std::cout << "degree(q): " << um.degree(q) << "\n"; - // display coefficients of q + // display coefficients of q std::cout << "expanded q: "; for (unsigned i = 0; i < q.size(); i++) std::cout << nm.to_string(q[i]) << " "; @@ -50,7 +52,7 @@ static void tst1() { // So, if we perform destructive operations on these coefficients, we must execute the "trim" operation // before invoking another operation of upolynomial::manager um.trim(q); - + // q after adding 1 to all coefficients std::cout << "new q: "; um.display(std::cout, q); std::cout << "\n"; @@ -64,7 +66,8 @@ static void tst1() { } static void tst_isolate_roots(polynomial_ref const & p, unsigned prec, mpbq_manager & bqm, mpbq_vector & roots, mpbq_vector & lowers, mpbq_vector & uppers) { - upolynomial::manager um(p.m().m()); + reslimit rl; + upolynomial::manager um(rl, p.m().m()); upolynomial::scoped_numeral_vector q(um); um.to_numeral_vector(p, q); std::cout << "isolating roots of: "; um.display(std::cout, q); std::cout << "\n"; @@ -119,7 +122,7 @@ static void tst_isolate_roots(polynomial_ref const & p, unsigned prec, mpbq_mana um.eval_sign_at(q.size(), q.c_ptr(), uppers[i]) == 0 || um.sign_variations_at(sseq, lowers[i]) - um.sign_variations_at(sseq, uppers[i]) == 1); // Fourier sequence may also be used to check if the interval is isolating - TRACE("upolynomial", + TRACE("upolynomial", tout << "lowers[i]: " << bqm.to_string(lowers[i]) << "\n"; tout << "uppers[i]: " << bqm.to_string(uppers[i]) << "\n"; tout << "fourier lower: " << um.sign_variations_at(fseq, lowers[i]) << "\n"; @@ -132,7 +135,7 @@ static void tst_isolate_roots(polynomial_ref const & p, unsigned prec, mpbq_mana // fsv_upper - fsv_upper - num_roots is even // Recall that num_roots == 1 in the interval. (fsv_lower - fsv_upper >= 1 && (fsv_lower - fsv_upper - 1) % 2 == 0)); - + // Double checking using Descartes bounds for the interval // Must use square free component. unsigned dab = um.descartes_bound_a_b(q_sqf.size(), q_sqf.c_ptr(), bqm, lowers[i], uppers[i]); @@ -189,28 +192,29 @@ static void tst_isolate_roots(polynomial_ref const & p, unsigned expected_sz, ra } static void tst_isolate_roots() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package polynomial_ref p(m); - p = (x-1)*(x-2); - { + p = (x-1)*(x-2); + { rational ex[2] = { rational(1), rational(2) }; tst_isolate_roots(p, 2, ex); } p = (x-1)*(x-1)*x*x*x; - { + { rational ex[2] = { rational(1), rational(0) }; tst_isolate_roots(p, 2, ex); } p = (x^5) - x - 1; - { + { rational ex[1] = { rational(11673039, 10000000) }; // approximated root tst_isolate_roots(p, 1, ex); } - p = (x - 1)*(x + 1)*(x + 2)*(x + 3)*((x - 3)^2); + p = (x - 1)*(x + 1)*(x + 2)*(x + 3)*((x - 3)^2); { rational ex[5] = { rational(1), rational(-1), rational(-2), rational(-3), rational(3) }; tst_isolate_roots(p, 5, ex); @@ -271,19 +275,20 @@ static void tst_isolate_roots() { }; tst_isolate_roots(p, 3, ex, 10); } - + } static void tst_remove_one_half() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package polynomial_ref p(m), r(m); p = 4*(x^3) - 12*(x^2) - x + 3; r = 16*(x^2) - 40*x - 24; - upolynomial::manager um(nm); + upolynomial::manager um(rl, nm); upolynomial::scoped_numeral_vector _p(um), _q(um), _r(um); um.to_numeral_vector(p, _p); um.to_numeral_vector(r, _r); @@ -321,15 +326,16 @@ static void tst_gcd(polynomial_ref const & p, polynomial_ref const & q, pmanager static void tst_gcd() { std::cout << "\n\nTesting GCD\n"; + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package polynomial_ref p(m); polynomial_ref q(m); - upolynomial::manager um(nm); + upolynomial::manager um(rl, nm); p = 13*((x - 3)^6)*((x - 5)^5)*((x - 11)^7); q = derivative(p, 0); @@ -339,7 +345,7 @@ static void tst_gcd() { p = (x^8) + (x^6) - 3*(x^4) - 3*(x^3) + 8*(x^2) + 2*x - 5; q = 3*(x^6) + 5*(x^4) - 4*(x^2) - 9*x + 21; - + tst_gcd(p, q, um); p = ((x - 1)^2)*(x - 3)*(x + 2)*((x - 5)^3); @@ -351,8 +357,9 @@ static void tst_gcd() { static void tst_zp() { std::cout << "\n\nTesting Z_p\n"; + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package @@ -363,20 +370,21 @@ static void tst_zp() { // Computing GCD of p an q in Z[x] std::cout << "GCD in Z[x]\n"; - upolynomial::manager um(nm); + upolynomial::manager um(rl, nm); tst_gcd(p, q, um); // Computing GCD of p an q in Z_3[x] - std::cout << "GCD in Z_3[x]\n"; - upolynomial::zp_manager um3(nm); + std::cout << "GCD in Z_3[x]\n"; + upolynomial::zp_manager um3(rl, nm); um3.set_zp(3); tst_gcd(p, q, um3); -} +} static void tst_zp2() { std::cout << "\n\nTesting Z_p\n"; + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package @@ -387,20 +395,21 @@ static void tst_zp2() { // Computing GCD of p an q in Z[x] std::cout << "GCD in Z[x]\n"; - upolynomial::manager um(nm); + upolynomial::manager um(rl, nm); tst_gcd(u, v, um); // Computing GCD of p an q in Z_3[x] - std::cout << "GCD in Z_13[x]\n"; - upolynomial::zp_manager um13(nm); + std::cout << "GCD in Z_13[x]\n"; + upolynomial::zp_manager um13(rl, nm); um13.set_zp(13); tst_gcd(u, v, um13); -} +} static void tst_ext_gcd() { std::cout << "\nExtended GCD\n"; + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package @@ -410,8 +419,8 @@ static void tst_ext_gcd() { b = (x^8) + (x^6) + 10*(x^4) + 10*(x^3) + 8*(x^2) + 2*x + 8; // Computing GCD of p an q in Z_3[x] - std::cout << "GCD in Z_13[x]\n"; - upolynomial::zp_manager um(nm); + std::cout << "GCD in Z_13[x]\n"; + upolynomial::zp_manager um(rl, nm); um.set_zp(13); mpzzp_manager & z13 = um.m(); upolynomial::zp_manager::scoped_numeral_vector A(z13), B(z13), U(z13), V(z13), D(z13); @@ -423,12 +432,13 @@ static void tst_ext_gcd() { std::cout << "U: "; um.display(std::cout, U); std::cout << "\n"; std::cout << "V: "; um.display(std::cout, V); std::cout << "\n"; std::cout << "D: "; um.display(std::cout, D); std::cout << "\n"; -} +} static void tst_ext_gcd_z7() { std::cout << "\nExtended GCD in Z_7\n"; + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package @@ -440,8 +450,8 @@ static void tst_ext_gcd_z7() { // Computing GCD of a and b in Z_3[x] // expecting: D = 1, U = 3*x + 6, V = 3*x^2 + 6*x + 4 - std::cout << "GCD in Z_7[x]\n"; - upolynomial::zp_manager um(nm); + std::cout << "GCD in Z_7[x]\n"; + upolynomial::zp_manager um(rl, nm); um.set_zp(7); mpzzp_manager & z7 = um.m(); upolynomial::zp_manager::scoped_numeral_vector A(z7), B(z7), U(z7), V(z7), D(z7); @@ -453,12 +463,13 @@ static void tst_ext_gcd_z7() { std::cout << "U: "; um.display(std::cout, U); std::cout << "\n"; std::cout << "V: "; um.display(std::cout, V); std::cout << "\n"; std::cout << "D: "; um.display(std::cout, D); std::cout << "\n"; -} +} static void tst_sturm() { std::cout << "\nSturm Seq\n"; + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package @@ -467,7 +478,7 @@ static void tst_sturm() { // p = ((x^17) + 5*(x^16) + 3*(x^15) + 10*(x^13) + 13*(x^10) + (x^9) + 8*(x^5) + 3*(x^2) + 7)*(((x^5) - x - 1)^2)*(((x^3) - 2)^2); // p = ((x^17) + 5*(x^16) + 3*(x^15) + 10*(x^13) + 13*(x^10) + (x^9) + 8*(x^5) + 3*(x^2) + 7)*(((x^5) - x - 1))*(((x^3) - 2)); - upolynomial::manager um(nm); + upolynomial::manager um(rl, nm); upolynomial::scoped_numeral_vector _p(um); upolynomial::scoped_upolynomial_sequence seq2(um); um.to_numeral_vector(p, _p); @@ -478,7 +489,8 @@ static void tst_sturm() { static void tst_refinable(polynomial_ref const & p, mpbq_manager & bqm, mpbq & a, mpbq & b) { - upolynomial::manager um(p.m().m()); + reslimit rl; + upolynomial::manager um(rl, p.m().m()); upolynomial::scoped_numeral_vector _p(um); um.to_numeral_vector(p, _p); std::cout << "before (" << bqm.to_string(a) << ", " << bqm.to_string(b) << ")\n"; @@ -497,8 +509,9 @@ static void tst_refinable(polynomial_ref const & p, mpbq_manager & bqm, mpbq & a static void tst_refinable() { std::cout << "\nRefinable intervals\n"; + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package @@ -539,12 +552,12 @@ static void tst_refinable() { bqm.set(a, 1); bqm.set(b, 3); tst_refinable(p, bqm, a, b); - + bqm.del(a); bqm.del(b); } static void tst_refine(polynomial_ref const & p, mpbq_manager & bqm, mpbq & a, mpbq & b, unsigned prec_k=100) { - upolynomial::manager um(p.m().m()); + reslimit rl; upolynomial::manager um(rl, p.m().m()); upolynomial::scoped_numeral_vector _p(um); um.to_numeral_vector(p, _p); std::cout << "before (" << bqm.to_string(a) << ", " << bqm.to_string(b) << ")\n"; @@ -561,8 +574,9 @@ static void tst_refine(polynomial_ref const & p, mpbq_manager & bqm, mpbq & a, m static void tst_refine() { std::cout << "\nRefining intervals\n"; + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package @@ -574,7 +588,7 @@ static void tst_refine() { a = 1; b = 2; tst_refine(p, bqm, a, b, 20); - + p = (x^2) - 2; std::cout << "p: " << p << "\n"; a = 1; @@ -583,14 +597,15 @@ static void tst_refine() { } static void tst_translate_q() { + reslimit rl; unsynch_mpq_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package polynomial_ref p(m); p = (x-1)*(x-2)*(x-3)*(x-4); - upolynomial::manager um(nm); + upolynomial::manager um(rl, nm); upolynomial::scoped_numeral_vector _p(um), _q(um); um.to_numeral_vector(p, _p); SASSERT(um.eval_sign_at(_p.size(), _p.c_ptr(), mpq(1)) == 0); @@ -637,7 +652,8 @@ static void tst_translate_q() { } static void tst_convert_q2bq(unsynch_mpq_manager & m, polynomial_ref const & p, mpq const & a, mpq const & b) { - upolynomial::manager um(m); + reslimit rl; + upolynomial::manager um(rl, m); upolynomial::scoped_numeral_vector _p(um); um.to_numeral_vector(p, _p); std::cout << "\np: "; @@ -657,8 +673,9 @@ static void tst_convert_q2bq(unsynch_mpq_manager & m, polynomial_ref const & p, } static void tst_convert_q2bq() { + reslimit rl; unsynch_mpq_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package @@ -704,8 +721,9 @@ static void tst_convert_q2bq() { } static void tst_sturm2() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package @@ -715,7 +733,7 @@ static void tst_sturm2() { p = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225; q = ((x^8) - 40*(x^6) + 352*(x^4) - 960*(x^2) + 576)^2; - upolynomial::manager um(nm); + upolynomial::manager um(rl, nm); upolynomial::scoped_numeral_vector _p(um), _q(um); upolynomial::scoped_upolynomial_sequence seq2(um); um.to_numeral_vector(p, _p); @@ -735,7 +753,7 @@ static void tst_isolate_roots2() { // create univariate polynomial using multivariate polynomial package polynomial_ref p(m); p = (2*x - 1)*(x - 21)*(x + 12)*(x - 19)*(x + 11)*(x + 34)*(x - 9)*(x - 72)*(10000*x - 4999)*((x^5) - x - 1)*((x^2) - 2)*((x^2) - 3)*((x^7) - 3)*((x^101) - 3); - { + { tst_isolate_roots(p, 10); } } @@ -769,7 +787,7 @@ static void tst_isolate_roots3() { q = (x - x1 - x2 - x3 - x4 - x5 - x6); r = resultant(resultant(resultant(resultant(resultant(resultant(q, p1, 1), p2, 2), p3, 3), p4, 4), p5, 5), p6, 6); std::cout << "r: " << r << "\n"; - { + { timeit timer(true, "isolate"); tst_isolate_roots(r, 10); } @@ -784,7 +802,7 @@ static void tst_gcd2() { polynomial_ref p(m); p = ((x^1000) - x + 1)^5; - upolynomial::manager um(nm); + reslimit rl; upolynomial::manager um(rl, nm); upolynomial::scoped_numeral_vector _p(um); upolynomial::scoped_numeral_vector _p_sqf(um); um.to_numeral_vector(p, _p); @@ -794,24 +812,26 @@ static void tst_gcd2() { } um.display(std::cout, _p_sqf.size(), _p_sqf.c_ptr()); std::cout << "\n"; } -#endif +#endif static void tst_isolate_roots5() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package polynomial_ref p(m); p = (x^70) - 6*(x^65) - (x^60) + 60*(x^55) - 54*(x^50) - 230*(x^45) + 274*(x^40) + 542*(x^35) - 615*(x^30) - 1120*(x^25) + 1500*(x^20) - 160*(x^15) - 395*(x^10) + 76*(x^5) + 34; - { + { tst_isolate_roots(p, 10); } } static void tst_exact_div(polynomial_ref const & p1, polynomial_ref const & p2, bool expected, polynomial_ref const & expected_q) { - upolynomial::manager um(p1.m().m()); + reslimit rl; + upolynomial::manager um(rl, p1.m().m()); upolynomial::scoped_numeral_vector _p1(um), _p2(um), _q(um), _r(um); um.to_numeral_vector(p1, _p1); um.to_numeral_vector(p2, _p2); @@ -834,8 +854,9 @@ static void tst_exact_div(polynomial_ref const & p1, polynomial_ref const & p2, } static void tst_exact_div() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m); x = m.mk_polynomial(m.mk_var()); // create univariate polynomial using multivariate polynomial package @@ -860,7 +881,7 @@ static void tst_fact(polynomial_ref const & p, unsigned num_distinct_factors, up SASSERT(is_univariate(p)); std::cout << "---------------\n"; std::cout << "p: " << p << std::endl; - upolynomial::manager um(p.m().m()); + reslimit rl; upolynomial::manager um(rl, p.m().m()); upolynomial::scoped_numeral_vector _p(um); upolynomial::factors fs(um); um.to_numeral_vector(p, _p); @@ -878,8 +899,9 @@ static void tst_fact(polynomial_ref const & p, unsigned num_distinct_factors, up } static void tst_fact() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m); x0 = m.mk_polynomial(m.mk_var()); tst_fact((x0^4) + (x0^2) - 20, 3); @@ -899,7 +921,7 @@ static void tst_fact() { tst_fact((x0^70) - 6*(x0^65) - (x0^60) + 60*(x0^55) - 54*(x0^50) - 230*(x0^45) + 274*(x0^40) + 542*(x0^35) - 615*(x0^30) - 1120*(x0^25) + 1500*(x0^20) - 160*(x0^15) - 395*(x0^10) + 76*(x0^5) + 34, 3); tst_fact(((x0^4) - 8*(x0^2)), 2); tst_fact((x0^5) - 2*(x0^3) + x0 - 1, 1); - tst_fact( (x0^25) - 4*(x0^21) - 5*(x0^20) + 6*(x0^17) + 11*(x0^16) + 10*(x0^15) - 4*(x0^13) - 7*(x0^12) - 9*(x0^11) - 10*(x0^10) + + tst_fact( (x0^25) - 4*(x0^21) - 5*(x0^20) + 6*(x0^17) + 11*(x0^16) + 10*(x0^15) - 4*(x0^13) - 7*(x0^12) - 9*(x0^11) - 10*(x0^10) + (x0^9) + (x0^8) + (x0^7) + (x0^6) + 3*(x0^5) + x0 - 1, 2); tst_fact( (x0^25) - 10*(x0^21) - 10*(x0^20) - 95*(x0^17) - 470*(x0^16) - 585*(x0^15) - 40*(x0^13) - 1280*(x0^12) - 4190*(x0^11) - 3830*(x0^10) + 400*(x0^9)+ 1760*(x0^8) + 760*(x0^7) - 2280*(x0^6) + 449*(x0^5) + 640*(x0^3) - 640*(x0^2) + 240*x0 - 32, 2); tst_fact( x0^10, 1); @@ -919,7 +941,7 @@ static void tst_fact() { tst_fact( (x0^50) - 10*(x0^40) + 38*(x0^30) - 2*(x0^25) - 100*(x0^20) - 40*(x0^15) + 121*(x0^10) - 38*(x0^5) - 17, 1); tst_fact( (((x0^5) + 5*(x0^4) + 10*(x0^3) + 10*(x0^2) + 5*x0)^10) - + 10*(((x0^5) + 5*(x0^4) + 10*(x0^3) + 10*(x0^2) + 5*x0)^9) + + 10*(((x0^5) + 5*(x0^4) + 10*(x0^3) + 10*(x0^2) + 5*x0)^9) + 35*(((x0^5) + 5*(x0^4) + 10*(x0^3) + 10*(x0^2) + 5*x0)^8) + 40*(((x0^5) + 5*(x0^4) + 10*(x0^3) + 10*(x0^2) + 5*x0)^7) - 32*(((x0^5) + 5*(x0^4) + 10*(x0^3) + 10*(x0^2) + 5*x0)^6) @@ -934,37 +956,37 @@ static void tst_fact() { tst_fact( ((x0^5) - 15552)* ((x0^20)- 15708*(x0^15) + rational("138771724")*(x0^10)- rational("432104148432")*(x0^5) + rational("614198284585616")), 2); - tst_fact( (x0^25) - - rational("3125")*(x0^21) - - rational("15630")*(x0^20) + - rational("3888750")*(x0^17) + - rational("38684375")*(x0^16) + - rational("95765635")*(x0^15) - - rational("2489846500")*(x0^13) - - rational("37650481875")*(x0^12) - - rational("190548065625")*(x0^11) - - rational("323785250010")*(x0^10) + - rational("750249453025")*(x0^9) + - rational("14962295699875")*(x0^8) + - rational("111775113235000")*(x0^7) + - rational("370399286731250")*(x0^6) + - rational("362903064503129")*(x0^5) - - rational("2387239013984400")*(x0^4) - - rational("23872390139844000")*(x0^3) - - rational("119361950699220000")*(x0^2) - - rational("298404876748050000")*x0 - + tst_fact( (x0^25) - + rational("3125")*(x0^21) - + rational("15630")*(x0^20) + + rational("3888750")*(x0^17) + + rational("38684375")*(x0^16) + + rational("95765635")*(x0^15) - + rational("2489846500")*(x0^13) - + rational("37650481875")*(x0^12) - + rational("190548065625")*(x0^11) - + rational("323785250010")*(x0^10) + + rational("750249453025")*(x0^9) + + rational("14962295699875")*(x0^8) + + rational("111775113235000")*(x0^7) + + rational("370399286731250")*(x0^6) + + rational("362903064503129")*(x0^5) - + rational("2387239013984400")*(x0^4) - + rational("23872390139844000")*(x0^3) - + rational("119361950699220000")*(x0^2) - + rational("298404876748050000")*x0 - rational("298500366308609376"), 2); tst_fact( rational("54")*(x0^24) - (x0^27) - 324*(x0^21) + rational("17496")*(x0^18) - 34992*(x0^15)+ rational("1889568")*(x0^12)- 1259712*(x0^9) + rational("68024448")*(x0^6), 3); tst_fact( ((x0^3)- 432)*(((x0^3)+54)^2)*((x0^6)+108)*((x0^6)+6912)*((x0^6)- 324*(x0^3)+37044), 5); - + tst_fact( ((x0^6)- 6*(x0^4) - 864*(x0^3) + 12*(x0^2) - 5184*x0 + 186616)* (((x0^6) - 6*(x0^4) + 108*(x0^3) + 12*(x0^2) + 648*x0 + 2908)^2)* ((x0^12) - 12*(x0^10) + 60*(x0^8) + 56*(x0^6) + 6720*(x0^4) + 12768*(x0^2) + 13456)* ((x0^12) - 12*(x0^10) + 60*(x0^8) + 13664*(x0^6) + 414960*(x0^4) + 829248*(x0^2) + 47886400)* - ((x0^12) - 12*(x0^10) - 648*(x0^9)+ 60*(x0^8) + 178904*(x0^6) + 15552*(x0^5) + 1593024*(x0^4) - 24045984*(x0^3) + + ((x0^12) - 12*(x0^10) - 648*(x0^9)+ 60*(x0^8) + 178904*(x0^6) + 15552*(x0^5) + 1593024*(x0^4) - 24045984*(x0^3) + 5704800*(x0^2) - 143995968*x0 + 1372010896), 5); } @@ -975,7 +997,7 @@ static void tst_rem(polynomial_ref const & p, polynomial_ref const & q, polynomi std::cout << "---------------\n"; std::cout << "p: " << p << std::endl; std::cout << "q: " << q << std::endl; - upolynomial::manager um(p.m().m()); + reslimit rl; upolynomial::manager um(rl, p.m().m()); upolynomial::scoped_numeral_vector _p(um), _q(um), _r(um); um.to_numeral_vector(p, _p); um.to_numeral_vector(q, _q); @@ -987,8 +1009,9 @@ static void tst_rem(polynomial_ref const & p, polynomial_ref const & q, polynomi } static void tst_rem() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x0(m), zero(m), one(m); x0 = m.mk_polynomial(m.mk_var()); zero = m.mk_zero(); @@ -1002,7 +1025,7 @@ static void tst_lower_bound(polynomial_ref const & p) { SASSERT(is_univariate(p)); std::cout << "---------------\n"; std::cout << "p: " << p << std::endl; - upolynomial::manager um(p.m().m()); + reslimit rl; upolynomial::manager um(rl, p.m().m()); upolynomial::scoped_numeral_vector _p(um); um.to_numeral_vector(p, _p); std::cout << "_p: "; um.display(std::cout, _p); std::cout << "\n"; @@ -1012,8 +1035,9 @@ static void tst_lower_bound(polynomial_ref const & p) { } static void tst_lower_bound() { + reslimit rl; polynomial::numeral_manager nm; - polynomial::manager m(nm); + polynomial::manager m(rl, nm); polynomial_ref x(m), zero(m), one(m); x = m.mk_polynomial(m.mk_var()); zero = m.mk_zero(); @@ -1031,7 +1055,7 @@ static void tst_lower_bound() { tst_lower_bound(((x^17) + 5*(x^16) + 3*(x^15) + 10*(x^13) + 13*(x^10) + (x^9) + 8*(x^5) + 3*(x^2) + 7)*(((x^5) - x - 1)^2)*(((x^3) - 2)^2)); tst_lower_bound((((x^5) - 1000000000)^3)*((3*x - 10000000)^2)*((10*x - 632)^2)); } - + void tst_upolynomial() { set_verbosity_level(1000); enable_trace("mpz_gcd"); From 284fcc2c044dd3d7c23dfe0e8bd6056a81885c0b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 20 Dec 2015 09:43:56 +0200 Subject: [PATCH 07/87] seq Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 43 +++----- src/ast/rewriter/seq_rewriter.h | 4 +- src/ast/seq_decl_plugin.cpp | 2 +- src/ast/seq_decl_plugin.h | 2 +- src/smt/smt_setup.cpp | 2 +- src/smt/theory_seq.cpp | 176 +++++++++++++++++++++++++++--- src/smt/theory_seq.h | 139 ++++++++++++++++++++++- src/util/scoped_vector.h | 15 ++- 8 files changed, 334 insertions(+), 49 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 8a9ede35f..d7ac3ff67 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -156,17 +156,17 @@ br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) { unsigned len = 0; unsigned j = 0; for (unsigned i = 0; i < m_es.size(); ++i) { - if (m_util.str.is_string(m_es[i], b)) { + if (m_util.str.is_string(m_es[i].get(), b)) { len += b.length(); } - else if (m_util.str.is_unit(m_es[i])) { + else if (m_util.str.is_unit(m_es[i].get())) { len += 1; } - else if (m_util.str.is_empty(m_es[i])) { + else if (m_util.str.is_empty(m_es[i].get())) { // skip } else { - m_es[j] = m_es[i]; + m_es[j] = m_es[i].get(); ++j; } } @@ -177,7 +177,7 @@ br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) { if (j != m_es.size() || j != 1) { expr_ref_vector es(m()); for (unsigned i = 0; i < j; ++i) { - es.push_back(m_util.str.mk_length(m_es[i])); + es.push_back(m_util.str.mk_length(m_es[i].get())); } if (len != 0) { es.push_back(m_autil.mk_numeral(rational(len, rational::ui64()), true)); @@ -207,14 +207,14 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { return BR_DONE; } // check if subsequence of b is in a. - ptr_vector as, bs; + expr_ref_vector as(m()), bs(m()); m_util.str.get_concat(a, as); m_util.str.get_concat(b, bs); bool found = false; for (unsigned i = 0; !found && i < as.size(); ++i) { if (bs.size() > as.size() - i) break; unsigned j = 0; - for (; j < bs.size() && as[j+i] == bs[j]; ++j) {}; + for (; j < bs.size() && as[j+i].get() == bs[j].get(); ++j) {}; found = j == bs.size(); } if (found) { @@ -292,7 +292,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { expr* b1 = m_util.str.get_leftmost_concat(b); isc1 = m_util.str.is_string(a1, s1); isc2 = m_util.str.is_string(b1, s2); - ptr_vector as, bs; + expr_ref_vector as(m()), bs(m()); if (a1 != b1 && isc1 && isc2) { if (s1.length() <= s2.length()) { @@ -342,7 +342,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { m_util.str.get_concat(a, as); m_util.str.get_concat(b, bs); unsigned i = 0; - for (; i < as.size() && i < bs.size() && as[i] == bs[i]; ++i) {}; + for (; i < as.size() && i < bs.size() && as[i].get() == bs[i].get(); ++i) {}; if (i == as.size()) { result = m().mk_true(); return BR_DONE; @@ -350,7 +350,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { if (i == bs.size()) { expr_ref_vector es(m()); for (unsigned j = i; j < as.size(); ++j) { - es.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j])); + es.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j].get())); } result = mk_and(es); return BR_REWRITE3; @@ -522,7 +522,6 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve expr* a, *b; zstring s; bool change = false; - expr_ref_vector trail(m()); m_lhs.reset(); m_rhs.reset(); m_util.str.get_concat(l, m_lhs); @@ -545,7 +544,7 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve expr* r = m_rhs.back(); if (m_util.str.is_unit(r) && m_util.str.is_string(l)) { std::swap(l, r); - std::swap(m_lhs, m_rhs); + m_lhs.swap(m_rhs); } if (l == r) { m_lhs.pop_back(); @@ -575,7 +574,6 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve else { expr_ref s2(m_util.str.mk_string(s.extract(0, s.length()-2)), m()); m_rhs[m_rhs.size()-1] = s2; - trail.push_back(s2); } } else { @@ -587,10 +585,10 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve // solve from front unsigned head1 = 0, head2 = 0; while (true) { - while (head1 < m_lhs.size() && m_util.str.is_empty(m_lhs[head1])) { + while (head1 < m_lhs.size() && m_util.str.is_empty(m_lhs[head1].get())) { ++head1; } - while (head2 < m_rhs.size() && m_util.str.is_empty(m_rhs[head2])) { + while (head2 < m_rhs.size() && m_util.str.is_empty(m_rhs[head2].get())) { ++head2; } if (head1 == m_lhs.size() || head2 == m_rhs.size()) { @@ -598,11 +596,11 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve } SASSERT(head1 < m_lhs.size() && head2 < m_rhs.size()); - expr* l = m_lhs[head1]; - expr* r = m_rhs[head2]; + expr* l = m_lhs[head1].get(); + expr* r = m_rhs[head2].get(); if (m_util.str.is_unit(r) && m_util.str.is_string(l)) { std::swap(l, r); - std::swap(m_lhs, m_rhs); + m_lhs.swap(m_rhs); } if (l == r) { ++head1; @@ -631,7 +629,6 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve else { expr_ref s2(m_util.str.mk_string(s.extract(1, s.length()-1)), m()); m_rhs[m_rhs.size()-1] = s2; - trail.push_back(s2); } } else { @@ -643,8 +640,8 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve zstring s1, s2; while (head1 < m_lhs.size() && head2 < m_rhs.size() && - m_util.str.is_string(m_lhs[head1], s1) && - m_util.str.is_string(m_rhs[head2], s2)) { + m_util.str.is_string(m_lhs[head1].get(), s1) && + m_util.str.is_string(m_rhs[head2].get(), s2)) { unsigned l = std::min(s1.length(), s2.length()); for (unsigned i = 0; i < l; ++i) { if (s1[i] != s2[i]) { @@ -656,14 +653,12 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve } else { m_lhs[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l)); - trail.push_back(m_lhs[head1]); } if (l == s2.length()) { ++head2; } else { m_rhs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l)); - trail.push_back(m_rhs[head2]); } change = true; } @@ -681,11 +676,9 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve m_rhs.pop_back(); if (l < s1.length()) { m_lhs.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l))); - trail.push_back(m_lhs.back()); } if (l < s2.length()) { m_rhs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l))); - trail.push_back(m_rhs.back()); } change = true; } diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index de3634a51..c3e466585 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -32,7 +32,7 @@ Notes: class seq_rewriter { seq_util m_util; arith_util m_autil; - ptr_vector m_es, m_lhs, m_rhs; + expr_ref_vector m_es, m_lhs, m_rhs; br_status mk_seq_concat(expr* a, expr* b, expr_ref& result); br_status mk_seq_length(expr* a, expr_ref& result); @@ -63,7 +63,7 @@ class seq_rewriter { public: seq_rewriter(ast_manager & m, params_ref const & p = params_ref()): - m_util(m), m_autil(m) { + m_util(m), m_autil(m), m_es(m), m_lhs(m), m_rhs(m) { } ast_manager & m() const { return m_util.get_manager(); } family_id get_fid() const { return m_util.get_family_id(); } diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index cda154050..75e27c081 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -626,7 +626,7 @@ bool seq_util::str::is_string(expr const* n, zstring& s) const { } -void seq_util::str::get_concat(expr* e, ptr_vector& es) const { +void seq_util::str::get_concat(expr* e, expr_ref_vector& es) const { expr* e1, *e2; while (is_concat(e, e1, e2)) { get_concat(e1, es); diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 04161b08d..33d4de378 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -271,7 +271,7 @@ public: MATCH_BINARY(is_in_re); MATCH_UNARY(is_unit); - void get_concat(expr* e, ptr_vector& es) const; + void get_concat(expr* e, expr_ref_vector& es) const; expr* get_leftmost_concat(expr* e) const { expr* e1, *e2; while (is_concat(e, e1, e2)) e = e1; return e; } }; diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index 8ebfa2d71..8a40f9d7a 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -815,7 +815,7 @@ namespace smt { } void setup::setup_seq() { - m_context.register_plugin(alloc(theory_seq_empty, m_manager)); + m_context.register_plugin(alloc(theory_seq, m_manager)); } void setup::setup_card() { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 641d5e444..753ddabd2 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -145,6 +145,7 @@ theory_seq::theory_seq(ast_manager& m): } theory_seq::~theory_seq() { + m_trail_stack.reset(); } @@ -157,6 +158,9 @@ final_check_status theory_seq::final_check_eh() { if (simplify_and_solve_eqs()) { return FC_CONTINUE; } + if (solve_nqs()) { + return FC_CONTINUE; + } if (ctx.inconsistent()) { return FC_CONTINUE; } @@ -209,7 +213,7 @@ bool theory_seq::check_ineqs() { bool theory_seq::branch_variable() { context& ctx = get_context(); unsigned sz = m_eqs.size(); - ptr_vector ls, rs; + expr_ref_vector ls(m), rs(m); for (unsigned i = 0; i < sz; ++i) { unsigned k = (i + m_branch_variable_head) % sz; eq e = m_eqs[k]; @@ -218,11 +222,11 @@ bool theory_seq::branch_variable() { m_util.str.get_concat(e.m_lhs, ls); m_util.str.get_concat(e.m_rhs, rs); - if (!ls.empty() && find_branch_candidate(ls[0], rs)) { + if (!ls.empty() && find_branch_candidate(ls[0].get(), rs)) { m_branch_variable_head = k; return true; } - if (!rs.empty() && find_branch_candidate(rs[0], ls)) { + if (!rs.empty() && find_branch_candidate(rs[0].get(), ls)) { m_branch_variable_head = k; return true; } @@ -230,7 +234,7 @@ bool theory_seq::branch_variable() { return false; } -bool theory_seq::find_branch_candidate(expr* l, ptr_vector const& rs) { +bool theory_seq::find_branch_candidate(expr* l, expr_ref_vector const& rs) { TRACE("seq", tout << mk_pp(l, m) << " " << (is_var(l)?"var":"not var") << "\n";); @@ -434,8 +438,7 @@ bool theory_seq::simplify_eq(expr* l, expr* r, enode_pair_dependency* deps) { set_conflict(deps); return true; } - if (lhs.size() == 1 && l == lhs[0].get() && - rhs.size() == 1 && r == rhs[0].get()) { + if (unchanged(l, lhs) && unchanged(r, rhs)) { return false; } SASSERT(lhs.size() == rhs.size()); @@ -558,8 +561,115 @@ bool theory_seq::pre_process_eqs(bool simplify_or_solve) { return change; } +bool theory_seq::solve_nqs() { + bool change = false; + context & ctx = get_context(); + for (unsigned i = 0; !ctx.inconsistent() && i < m_nqs.size(); ++i) { + change = solve_ne(i) || change; + if (m_nqs[i].is_solved()) { + m_nqs.erase_and_swap(i); + --i; + } + } + return change; +} + +bool theory_seq::solve_ne(unsigned idx) { + context& ctx = get_context(); + seq_rewriter rw(m); + bool change = false; + ne const& n = m_nqs[idx]; + TRACE("seq", display_disequation(tout, n);); + + SASSERT(!n.is_solved()); + for (unsigned i = 0; i < n.m_lits.size(); ++i) { + switch (ctx.get_assignment(n.m_lits[i])) { + case l_true: + erase_lit(idx, i); + --i; + break; + case l_false: + // mark as solved in + mark_solved(idx); + return false; + case l_undef: + break; + } + } + for (unsigned i = 0; i < n.m_lhs.size(); ++i) { + expr_ref_vector lhs(m), rhs(m); + enode_pair_dependency* deps = 0; + expr* l = n.m_lhs[i]; + expr* r = n.m_rhs[i]; + expr_ref lh = canonize(l, deps); + expr_ref rh = canonize(r, deps); + if (!rw.reduce_eq(lh, rh, lhs, rhs)) { + mark_solved(idx); + return change; + } + else if (unchanged(l, lhs) && unchanged(r, rhs)) { + // continue + } + else if (unchanged(r, lhs) && unchanged(l, rhs)) { + // continue + } + else { + TRACE("seq", tout << lhs.size() << "\n"; + for (unsigned j = 0; j < lhs.size(); ++j) { + tout << mk_pp(lhs[j].get(), m) << " "; + } + tout << "\n"; + tout << mk_pp(l, m) << " != " << mk_pp(r, m) << "\n";); + + for (unsigned j = 0; j < lhs.size(); ++j) { + expr_ref nl(lhs[j].get(), m); + expr_ref nr(rhs[j].get(), m); + if (m_util.is_seq(nl) || m_util.is_re(nl)) { + //std::cout << "push_ne " << nl << " != " << nr << "\n"; + m_trail_stack.push(push_ne(*this, idx, nl, nr)); + } + else { + //std::cout << "push_lit\n"; + literal lit(mk_eq(nl, nr, false)); + m_trail_stack.push(push_lit(*this, idx, ~lit)); + ctx.mark_as_relevant(lit); + } + } + m_trail_stack.push(push_dep(*this, idx, deps)); + erase_index(idx, i); + --i; + } + } + if (n.m_lits.empty() && n.m_lhs.empty()) { + set_conflict(n.m_dep); + return true; + } + return change; +} + +void theory_seq::erase_lit(unsigned idx, unsigned i) { + ne const& n = m_nqs[idx]; + if (n.m_lits.size() < i + 1) { + m_trail_stack.push(set_lit(*this, idx, i, n.m_lits.back())); + } + m_trail_stack.push(pop_lit(*this, idx)); +} + +void theory_seq::mark_solved(unsigned idx) { + m_trail_stack.push(solved_ne(*this, idx)); +} + +void theory_seq::erase_index(unsigned idx, unsigned i) { + ne const& n = m_nqs[idx]; + unsigned sz = n.m_lhs.size(); + if (i + 1 != sz) { + m_trail_stack.push(set_ne(*this, idx, i, n.m_lhs[sz-1], n.m_rhs[sz-1])); + } + m_trail_stack.push(pop_ne(*this, idx)); +} + bool theory_seq::simplify_and_solve_eqs() { - context & ctx = get_context(); + context & ctx = get_context(); bool change = simplify_eqs(); while (!ctx.inconsistent() && solve_basic_eqs()) { simplify_eqs(); @@ -620,6 +730,7 @@ void theory_seq::apply_sort_cnstr(enode* n, sort* s) { void theory_seq::display(std::ostream & out) const { if (m_eqs.size() == 0 && + m_nqs.size() == 0 && m_ineqs.empty() && m_rep.empty() && m_exclude.empty()) { @@ -630,6 +741,10 @@ void theory_seq::display(std::ostream & out) const { out << "Equations:\n"; display_equations(out); } + if (m_nqs.size() > 0) { + out << "Disequations:\n"; + display_disequations(out); + } if (!m_ineqs.empty()) { out << "Negative constraints:\n"; for (unsigned i = 0; i < m_ineqs.size(); ++i) { @@ -654,6 +769,25 @@ void theory_seq::display_equations(std::ostream& out) const { } } +void theory_seq::display_disequations(std::ostream& out) const { + for (unsigned i = 0; i < m_nqs.size(); ++i) { + display_disequation(out, m_nqs[i]); + } +} + +void theory_seq::display_disequation(std::ostream& out, ne const& e) const { + for (unsigned j = 0; j < e.m_lits.size(); ++j) { + out << e.m_lits[j] << " "; + } + if (e.m_lits.size() > 0) { + out << "\n"; + } + for (unsigned j = 0; j < e.m_lhs.size(); ++j) { + out << mk_pp(e.m_lhs[j], m) << " != " << mk_pp(e.m_rhs[j], m) << "\n"; + } + display_deps(out, e.m_dep); +} + void theory_seq::display_deps(std::ostream& out, enode_pair_dependency* dep) const { vector _eqs; const_cast(m_dm).linearize(dep, _eqs); @@ -735,9 +869,6 @@ expr_ref theory_seq::expand(expr* e, enode_pair_dependency*& eqs) { else if (m_util.str.is_empty(e) || m_util.str.is_string(e)) { result = e; } - else if (m.is_eq(e, e1, e2)) { - result = m.mk_eq(expand(e1, deps), expand(e2, deps)); - } else if (m_util.str.is_prefix(e, e1, e2)) { result = m_util.str.mk_prefix(expand(e1, deps), expand(e2, deps)); } @@ -762,6 +893,9 @@ expr_ref theory_seq::expand(expr* e, enode_pair_dependency*& eqs) { else { result = e; } + if (result == e) { + deps = 0; + } expr_dep edr(result, deps); m_rep.add_cache(e, edr); eqs = m_dm.mk_join(eqs, deps); @@ -1164,6 +1298,13 @@ void theory_seq::assign_eq(bool_var v, bool is_true) { } } else { + //if (m_util.str.is_prefix(e, e1, e2)) { + // could add negative prefix axioms: + // len(e1) <= len(e2) => e2 = seq.prefix.left(e2)*seq.prefix.right(e2) + // & len(seq.prefix.left(e2)) = len(e1) + // & seq.prefix.left(e2) != e1 + // or could solve prefix/suffix disunification constraints. + //} m_trail_stack.push(push_back_vector(m_ineqs)); m_ineqs.push_back(e); } @@ -1181,15 +1322,15 @@ void theory_seq::new_eq_eh(theory_var v1, theory_var v2) { } void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { - expr* e1 = get_enode(v1)->get_owner(); - expr* e2 = get_enode(v2)->get_owner(); - m_trail_stack.push(push_back_vector(m_ineqs)); - m_ineqs.push_back(mk_eq_atom(e1, e2)); + enode* n1 = get_enode(v1); + enode* n2 = get_enode(v2); + expr_ref e1(n1->get_owner(), m); + expr_ref e2(n2->get_owner(), m); + m_nqs.push_back(ne(e1, e2, m_dm.mk_leaf(enode_pair(n1, n2)))); m_exclude.update(e1, e2); } void theory_seq::push_scope_eh() { - TRACE("seq", tout << "push " << m_eqs.size() << "\n";); theory::push_scope_eh(); m_rep.push_scope(); m_exclude.push_scope(); @@ -1197,16 +1338,17 @@ void theory_seq::push_scope_eh() { m_trail_stack.push_scope(); m_trail_stack.push(value_trail(m_axioms_head)); m_eqs.push_scope(); + m_nqs.push_scope(); } void theory_seq::pop_scope_eh(unsigned num_scopes) { - TRACE("seq", tout << "pop " << m_eqs.size() << "\n";); m_trail_stack.pop_scope(num_scopes); theory::pop_scope_eh(num_scopes); m_dm.pop_scope(num_scopes); m_rep.pop_scope(num_scopes); m_exclude.pop_scope(num_scopes); - m_eqs.pop_scopes(num_scopes); + m_eqs.pop_scope(num_scopes); + m_nqs.pop_scope(num_scopes); } void theory_seq::restart_eh() { diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index b2b45e77e..59ae5095a 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -104,6 +104,136 @@ namespace smt { eq& operator=(eq const& other) { m_lhs = other.m_lhs; m_rhs = other.m_rhs; m_dep = other.m_dep; return *this; } }; + + // asserted or derived disqequality with dependencies + struct ne { + bool m_solved; + expr_ref_vector m_lhs; + expr_ref_vector m_rhs; + literal_vector m_lits; + enode_pair_dependency* m_dep; + ne(expr_ref& l, expr_ref& r, enode_pair_dependency* d): + m_solved(false), m_lhs(l.get_manager()), m_rhs(r.get_manager()), m_dep(d) { + m_lhs.push_back(l); + m_rhs.push_back(r); + } + ne(ne const& other): + m_solved(other.m_solved), m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_lits(other.m_lits), m_dep(other.m_dep) {} + ne& operator=(ne const& other) { + m_solved = other.m_solved; + m_lhs.reset(); m_lhs.append(other.m_lhs); + m_rhs.reset(); m_rhs.append(other.m_rhs); + m_lits.reset(); m_lits.append(other.m_lits); + m_dep = other.m_dep; + return *this; + } + bool is_solved() const { return m_solved; } + }; + + class pop_lit : public trail { + unsigned m_idx; + literal m_lit; + public: + pop_lit(theory_seq& th, unsigned idx): m_idx(idx), m_lit(th.m_nqs[idx].m_lits.back()) { + th.m_nqs.ref(m_idx).m_lits.pop_back(); + } + virtual void undo(theory_seq & th) { th.m_nqs.ref(m_idx).m_lits.push_back(m_lit); } + }; + class push_lit : public trail { + unsigned m_idx; + public: + push_lit(theory_seq& th, unsigned idx, literal lit): m_idx(idx) { + th.m_nqs.ref(m_idx).m_lits.push_back(lit); + } + virtual void undo(theory_seq & th) { th.m_nqs.ref(m_idx).m_lits.pop_back(); } + }; + class set_lit : public trail { + unsigned m_idx; + unsigned m_i; + literal m_lit; + public: + set_lit(theory_seq& th, unsigned idx, unsigned i, literal lit): + m_idx(idx), m_i(i), m_lit(th.m_nqs[idx].m_lits[i]) { + th.m_nqs.ref(m_idx).m_lits[i] = lit; + } + virtual void undo(theory_seq & th) { th.m_nqs.ref(m_idx).m_lits[m_i] = m_lit; } + }; + void erase_lit(unsigned idx, unsigned i); + + class solved_ne : public trail { + unsigned m_idx; + public: + solved_ne(theory_seq& th, unsigned idx) : m_idx(idx) { th.m_nqs.ref(idx).m_solved = true; } + virtual void undo(theory_seq& th) { th.m_nqs.ref(m_idx).m_solved = false; } + }; + void mark_solved(unsigned idx); + + class push_ne : public trail { + unsigned m_idx; + public: + push_ne(theory_seq& th, unsigned idx, expr* l, expr* r) : m_idx(idx) { + th.m_nqs.ref(m_idx).m_lhs.push_back(l); + th.m_nqs.ref(m_idx).m_rhs.push_back(r); + } + virtual void undo(theory_seq& th) { th.m_nqs.ref(m_idx).m_lhs.pop_back(); th.m_nqs.ref(m_idx).m_rhs.pop_back(); } + }; + + class pop_ne : public trail { + expr_ref m_lhs; + expr_ref m_rhs; + unsigned m_idx; + public: + pop_ne(theory_seq& th, unsigned idx): + m_lhs(th.m_nqs[idx].m_lhs.back(), th.m), + m_rhs(th.m_nqs[idx].m_rhs.back(), th.m), + m_idx(idx) { + th.m_nqs.ref(idx).m_lhs.pop_back(); + th.m_nqs.ref(idx).m_rhs.pop_back(); + } + virtual void undo(theory_seq& th) { + th.m_nqs.ref(m_idx).m_lhs.push_back(m_lhs); + th.m_nqs.ref(m_idx).m_rhs.push_back(m_rhs); + m_lhs.reset(); + m_rhs.reset(); + } + }; + + class set_ne : public trail { + expr_ref m_lhs; + expr_ref m_rhs; + unsigned m_idx; + unsigned m_i; + public: + set_ne(theory_seq& th, unsigned idx, unsigned i, expr* l, expr* r): + m_lhs(th.m_nqs[idx].m_lhs[i], th.m), + m_rhs(th.m_nqs[idx].m_rhs[i], th.m), + m_idx(idx), + m_i(i) { + th.m_nqs.ref(idx).m_lhs[i] = l; + th.m_nqs.ref(idx).m_rhs[i] = r; + } + virtual void undo(theory_seq& th) { + th.m_nqs.ref(m_idx).m_lhs[m_i] = m_lhs; + th.m_nqs.ref(m_idx).m_rhs[m_i] = m_rhs; + m_lhs.reset(); + m_rhs.reset(); + } + }; + + class push_dep : public trail { + enode_pair_dependency* m_dep; + unsigned m_idx; + public: + push_dep(theory_seq& th, unsigned idx, enode_pair_dependency* d): m_dep(th.m_nqs[idx].m_dep), m_idx(idx) { + th.m_nqs.ref(idx).m_dep = d; + } + virtual void undo(theory_seq& th) { + th.m_nqs.ref(m_idx).m_dep = m_dep; + } + }; + + void erase_index(unsigned idx, unsigned i); + struct stats { stats() { reset(); } void reset() { memset(this, 0, sizeof(stats)); } @@ -114,6 +244,7 @@ namespace smt { enode_pair_dependency_manager m_dm; solution_map m_rep; // unification representative. scoped_vector m_eqs; // set of current equations. + scoped_vector m_nqs; // set of current disequalities. seq_factory* m_factory; // value factory expr_ref_vector m_ineqs; // inequalities to check solution against @@ -174,13 +305,17 @@ namespace smt { bool solve_unit_eq(expr* l, expr* r, enode_pair_dependency* dep); bool solve_basic_eqs(); + bool solve_nqs(); + bool solve_ne(unsigned i); + bool unchanged(expr* e, expr_ref_vector& es) const { return es.size() == 1 && es[0] == e; } + // asserting consequences void propagate_lit(enode_pair_dependency* dep, literal lit); void propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2); void propagate_eq(bool_var v, expr* e1, expr* e2); void set_conflict(enode_pair_dependency* dep); - bool find_branch_candidate(expr* l, ptr_vector const& rs); + bool find_branch_candidate(expr* l, expr_ref_vector const& rs); bool assume_equality(expr* l, expr* r); // variable solving utilities @@ -219,6 +354,8 @@ namespace smt { // diagnostics void display_equations(std::ostream& out) const; + void display_disequations(std::ostream& out) const; + void display_disequation(std::ostream& out, ne const& e) const; void display_deps(std::ostream& out, enode_pair_dependency* deps) const; public: theory_seq(ast_manager& m); diff --git a/src/util/scoped_vector.h b/src/util/scoped_vector.h index 917ecf2ab..a05b19487 100644 --- a/src/util/scoped_vector.h +++ b/src/util/scoped_vector.h @@ -46,7 +46,7 @@ public: m_elems_lim.push_back(m_elems_start); } - void pop_scopes(unsigned num_scopes) { + void pop_scope(unsigned num_scopes) { if (num_scopes == 0) return; unsigned new_size = m_sizes.size() - num_scopes; unsigned src_lim = m_src_lim[new_size]; @@ -72,6 +72,12 @@ public: return m_elems[m_index[idx]]; } + // breaks abstraction, caller must ensure backtracking. + T& ref(unsigned idx) { + SASSERT(idx < m_size); + return m_elems[m_index[idx]]; + } + void set(unsigned idx, T const& t) { SASSERT(idx < m_size); unsigned n = m_index[idx]; @@ -102,6 +108,13 @@ public: SASSERT(invariant()); } + void erase_and_swap(unsigned i) { + if (i + 1 < size()) { + set(i, m_elems[m_index[i]]); + } + pop_back(); + } + unsigned size() const { return m_size; } bool empty() const { return m_size == 0; } From 8e26c977824a0246617eb55a0d2f252f6a13624c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Dec 2015 13:09:03 +0200 Subject: [PATCH 08/87] tuning bit-vector operations Signed-off-by: Nikolaj Bjorner --- src/api/api_model.cpp | 4 +- .../rewriter/bit_blaster/bit_blaster_tpl.h | 5 +- .../bit_blaster/bit_blaster_tpl_def.h | 117 ++++++++++++----- src/ast/rewriter/bv_rewriter.cpp | 118 +++++++++++++----- src/ast/rewriter/bv_rewriter.h | 4 + src/smt/theory_bv.cpp | 45 ++++++- src/smt/theory_bv.h | 5 +- src/tactic/bv/bit_blaster_tactic.h | 47 +++---- src/tactic/core/solve_eqs_tactic.cpp | 20 +-- 9 files changed, 271 insertions(+), 94 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 370e639b9..63092b2cf 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -277,7 +277,9 @@ extern "C" { RESET_ERROR_CODE(); CHECK_NON_NULL(f, 0); expr * e = to_func_interp_ref(f)->get_else(); - mk_c(c)->save_ast_trail(e); + if (e) { + mk_c(c)->save_ast_trail(e); + } RETURN_Z3(of_expr(e)); Z3_CATCH_RETURN(0); } diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h index ea8209c61..b812de941 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h @@ -121,8 +121,11 @@ public: void mk_comp(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits); void mk_carry_save_adder(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr * const * c_bits, expr_ref_vector & sum_bits, expr_ref_vector & carry_bits); - void mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits); + bool mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits); + bool mk_const_case_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits); + void mk_const_case_multiplier(bool is_a, unsigned i, unsigned sz, ptr_buffer& a_bits, ptr_buffer& b_bits, expr_ref_vector & out_bits); + bool is_bool_const(expr* e) const { return m().is_true(e) || m().is_false(e); } void mk_abs(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits); }; diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index 38a608f5f..942f97e93 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -38,7 +38,7 @@ void bit_blaster_tpl::checkpoint() { template bool bit_blaster_tpl::is_numeral(unsigned sz, expr * const * bits) const { for (unsigned i = 0; i < sz; i++) - if (!m().is_true(bits[i]) && !m().is_false(bits[i])) + if (!is_bool_const(bits[i])) return false; return true; } @@ -158,30 +158,24 @@ void bit_blaster_tpl::mk_subtracter(unsigned sz, expr * const * a_bits, exp template void bit_blaster_tpl::mk_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) { SASSERT(sz > 0); - - if (!m_use_bcm) { - numeral n_a, n_b; - if (is_numeral(sz, a_bits, n_b)) - std::swap(a_bits, b_bits); - if (is_minus_one(sz, b_bits)) { - mk_neg(sz, a_bits, out_bits); - return; - } - if (is_numeral(sz, a_bits, n_a)) { - n_a *= n_b; - num2bits(n_a, sz, out_bits); - return; - } + numeral n_a, n_b; + if (is_numeral(sz, a_bits, n_b)) + std::swap(a_bits, b_bits); + if (is_minus_one(sz, b_bits)) { + mk_neg(sz, a_bits, out_bits); + return; } - else { - numeral n_a, n_b; - if (is_numeral(sz, a_bits, n_a)) { - mk_const_multiplier(sz, a_bits, b_bits, out_bits); - return; - } else if (is_numeral(sz, b_bits, n_b)) { - mk_const_multiplier(sz, b_bits, a_bits, out_bits); - return; - } + if (is_numeral(sz, a_bits, n_a)) { + n_a *= n_b; + num2bits(n_a, sz, out_bits); + return; + } + + if (mk_const_multiplier(sz, a_bits, b_bits, out_bits)) { + return; + } + if (mk_const_multiplier(sz, b_bits, a_bits, out_bits)) { + return; } if (!m_use_wtm) { @@ -1171,13 +1165,74 @@ void bit_blaster_tpl::mk_carry_save_adder(unsigned sz, expr * const * a_bit } template -void bit_blaster_tpl::mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) { - DEBUG_CODE({ - numeral x; - SASSERT(is_numeral(sz, a_bits, x)); - SASSERT(out_bits.empty()); - }); +bool bit_blaster_tpl::mk_const_case_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) { + unsigned nb = 0; + unsigned case_size = 1; + unsigned circuit_size = sz*sz*5; + for (unsigned i = 0; case_size < circuit_size && i < sz; ++i) { + if (!is_bool_const(a_bits[i])) { + case_size *= 2; + } + if (!is_bool_const(b_bits[i])) { + case_size *= 2; + } + } + if (case_size >= circuit_size) { + return false; + } + SASSERT(out_bits.empty()); + ptr_buffer na_bits; + na_bits.append(sz, a_bits); + ptr_buffer nb_bits; + nb_bits.append(sz, b_bits); + mk_const_case_multiplier(true, 0, sz, na_bits, nb_bits, out_bits); + return false; +} + +template +void bit_blaster_tpl::mk_const_case_multiplier(bool is_a, unsigned i, unsigned sz, ptr_buffer& a_bits, ptr_buffer& b_bits, expr_ref_vector & out_bits) { + while (is_a && i < sz && is_bool_const(a_bits[i])) ++i; + if (is_a && i == sz) { is_a = false; i = 0; } + while (!is_a && i < sz && is_bool_const(b_bits[i])) ++i; + if (i < sz) { + expr_ref_vector out1(m()), out2(m()); + expr_ref x(m()); + x = is_a?a_bits[i]:b_bits[i]; + if (is_a) a_bits[i] = m().mk_true(); else b_bits[i] = m().mk_true(); + mk_const_case_multiplier(is_a, i+1, sz, a_bits, b_bits, out1); + if (is_a) a_bits[i] = m().mk_false(); else b_bits[i] = m().mk_false(); + mk_const_case_multiplier(is_a, i+1, sz, a_bits, b_bits, out2); + if (is_a) a_bits[i] = x; else b_bits[i] = x; + SASSERT(out_bits.empty()); + for (unsigned j = 0; j < sz; ++j) { + out_bits.push_back(m().mk_ite(x, out1[j].get(), out2[j].get())); + } + } + else { + numeral n_a, n_b; + SASSERT(i == sz && !is_a); + VERIFY(is_numeral(sz, a_bits.c_ptr(), n_a)); + VERIFY(is_numeral(sz, b_bits.c_ptr(), n_b)); + n_a *= n_b; + num2bits(n_a, sz, out_bits); + } +} + +template +bool bit_blaster_tpl::mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) { + numeral n_a; + if (!is_numeral(sz, a_bits, n_a)) { + return false; + } + SASSERT(out_bits.empty()); + + if (mk_const_case_multiplier(sz, a_bits, b_bits, out_bits)) { + return true; + } + if (!m_use_bcm) { + return false; + } expr_ref_vector minus_b_bits(m()), tmp(m()); mk_neg(sz, b_bits, minus_b_bits); @@ -1255,4 +1310,6 @@ void bit_blaster_tpl::mk_const_multiplier(unsigned sz, expr * const * a_bit TRACE("bit_blaster_tpl_booth", for (unsigned i=0; iget_num_args(); + expr_ref t1(m()), t2(m()); + t1 = to_app(rhs)->get_arg(0); + if (sz > 2) { + t2 = m().mk_app(get_fid(), OP_BADD, sz-1, to_app(rhs)->get_args()+1); + } + else { + SASSERT(sz == 2); + t2 = to_app(rhs)->get_arg(1); + } + mk_t1_add_t2_eq_c(t1, t2, lhs, result); + return true; +} + +bool bv_rewriter::is_add_mul_const(expr* e) const { + if (!m_util.is_bv_add(e)) { + return false; + } + unsigned num = to_app(e)->get_num_args(); + for (unsigned i = 0; i < num; i++) { + expr * arg = to_app(e)->get_arg(i); + expr * c2, * x2; + if (m_util.is_numeral(arg)) + continue; + if (m_util.is_bv_mul(arg, c2, x2) && m_util.is_numeral(c2)) + continue; + return false; + } + return true; +} + +bool bv_rewriter::is_concat_target(expr* lhs, expr* rhs) const { + return + m_util.is_concat(lhs) && (is_concat_split_target(rhs) || has_numeral(to_app(lhs))) || + m_util.is_concat(rhs) && (is_concat_split_target(lhs) || has_numeral(to_app(rhs))); +} + +bool bv_rewriter::has_numeral(app* a) const { + for (unsigned i = 0; i < a->get_num_args(); ++i) { + if (is_numeral(a->get_arg(i))) { + return true; + } + } + return false; +} + br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) { + expr * c, * x; numeral c_val, c_inv_val; unsigned sz; @@ -2001,24 +2057,30 @@ br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) { // c * x = t_1 + ... + t_n // and t_i's have non-unary coefficients (this condition is used to make sure we are actually reducing the number of multipliers). - if (m_util.is_bv_add(rhs)) { + if (is_add_mul_const(rhs)) { // Potential problem: this simplification may increase the number of adders by reducing the amount of sharing. - unsigned num = to_app(rhs)->get_num_args(); - unsigned i; - for (i = 0; i < num; i++) { - expr * arg = to_app(rhs)->get_arg(i); - expr * c2, * x2; - if (m_util.is_numeral(arg)) - continue; - if (m_util.is_bv_mul(arg, c2, x2) && m_util.is_numeral(c2)) - continue; - break; - } - if (i == num) { - result = m().mk_eq(x, m_util.mk_bv_mul(m_util.mk_numeral(c_inv_val, sz), rhs)); - return BR_REWRITE2; + result = m().mk_eq(x, m_util.mk_bv_mul(m_util.mk_numeral(c_inv_val, sz), rhs)); + return BR_REWRITE2; + } + } + if (m_util.is_numeral(lhs, c_val, sz) && is_add_mul_const(rhs)) { + unsigned sz = to_app(rhs)->get_num_args(); + unsigned i = 0; + expr* c2, *x2; + numeral c2_val, c2_inv_val; + bool found = false; + for (; !found && i < sz; ++i) { + expr* arg = to_app(rhs)->get_arg(i); + if (m_util.is_bv_mul(arg, c2, x2) && m_util.is_numeral(c2, c2_val, sz) && + m_util.mult_inverse(c2_val, sz, c2_inv_val)) { + found = true; } } + if (found) { + result = m().mk_eq(m_util.mk_numeral(c2_inv_val*c_val, sz), + m_util.mk_bv_mul(m_util.mk_numeral(c2_inv_val, sz), rhs)); + return BR_REWRITE3; + } } return BR_FAILED; } @@ -2065,9 +2127,10 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { return st; } + expr_ref new_lhs(m()); + expr_ref new_rhs(m()); + if (m_util.is_bv_add(lhs) || m_util.is_bv_mul(lhs) || m_util.is_bv_add(rhs) || m_util.is_bv_mul(rhs)) { - expr_ref new_lhs(m()); - expr_ref new_rhs(m()); st = cancel_monomials(lhs, rhs, false, new_lhs, new_rhs); if (st != BR_FAILED) { if (is_numeral(new_lhs) && is_numeral(new_rhs)) { @@ -2080,28 +2143,27 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { new_rhs = rhs; } + lhs = new_lhs; + rhs = new_rhs; // Try to rewrite t1 + t2 = c --> t1 = c - t2 // Reason: it is much cheaper to bit-blast. - expr * t1, * t2; - if (m_util.is_bv_add(new_lhs, t1, t2) && is_numeral(new_rhs)) { - mk_t1_add_t2_eq_c(t1, t2, new_rhs, result); + if (isolate_term(lhs, rhs, result)) { return BR_REWRITE2; } - if (m_util.is_bv_add(new_rhs, t1, t2) && is_numeral(new_lhs)) { - mk_t1_add_t2_eq_c(t1, t2, new_lhs, result); - return BR_REWRITE2; + if (is_concat_target(lhs, rhs)) { + return mk_eq_concat(lhs, rhs, result); } - + if (st != BR_FAILED) { - result = m().mk_eq(new_lhs, new_rhs); + result = m().mk_eq(lhs, rhs); return BR_DONE; } } - if ((m_util.is_concat(lhs) && is_concat_split_target(rhs)) || - (m_util.is_concat(rhs) && is_concat_split_target(lhs))) + if (is_concat_target(lhs, rhs)) { return mk_eq_concat(lhs, rhs, result); - + } + if (swapped) { result = m().mk_eq(lhs, rhs); return BR_DONE; diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 1c9b44b52..78d3fb4f1 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -137,6 +137,10 @@ class bv_rewriter : public poly_rewriter { bool is_concat_split_target(expr * t) const; br_status mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result); + bool is_add_mul_const(expr* e) const; + bool isolate_term(expr* lhs, expr* rhs, expr_ref & result); + bool has_numeral(app* e) const; + bool is_concat_target(expr* lhs, expr* rhs) const; void updt_local_params(params_ref const & p); diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 51b2c1b59..cef8d5fc7 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -424,6 +424,39 @@ namespace smt { }; + void theory_bv::add_fixed_eq(theory_var v1, theory_var v2) { + ++m_stats.m_num_eq_dynamic; + if (v1 > v2) { + std::swap(v1, v2); + } + unsigned sz = get_bv_size(v1); + ast_manager& m = get_manager(); + context & ctx = get_context(); + app* o1 = get_enode(v1)->get_owner(); + app* o2 = get_enode(v2)->get_owner(); + literal oeq = mk_eq(o1, o2, true); + TRACE("bv", + tout << mk_pp(o1, m) << " = " << mk_pp(o2, m) << " " + << ctx.get_scope_level() << "\n";); + literal_vector eqs; + for (unsigned i = 0; i < sz; ++i) { + literal l1 = m_bits[v1][i]; + literal l2 = m_bits[v2][i]; + expr_ref e1(m), e2(m); + e1 = mk_bit2bool(o1, i); + e2 = mk_bit2bool(o2, i); + literal eq = mk_eq(e1, e2, true); + ctx.mk_th_axiom(get_id(), l1, ~l2, ~eq); + ctx.mk_th_axiom(get_id(), ~l1, l2, ~eq); + ctx.mk_th_axiom(get_id(), l1, l2, eq); + ctx.mk_th_axiom(get_id(), ~l1, ~l2, eq); + ctx.mk_th_axiom(get_id(), eq, ~oeq); + eqs.push_back(~eq); + } + eqs.push_back(oeq); + ctx.mk_th_axiom(get_id(), eqs.size(), eqs.c_ptr()); + } + void theory_bv::fixed_var_eh(theory_var v) { numeral val; bool r = get_fixed_value(v, val); @@ -443,7 +476,9 @@ namespace smt { display_var(tout, v); display_var(tout, v2);); m_stats.m_num_th2core_eq++; - ctx.assign_eq(get_enode(v), get_enode(v2), eq_justification(js)); + add_fixed_eq(v, v2); + ctx.assign_eq(get_enode(v), get_enode(v2), eq_justification(js)); + m_fixed_var_table.insert(key, v2); } } else { @@ -1177,6 +1212,7 @@ namespace smt { } void theory_bv::assign_bit(literal consequent, theory_var v1, theory_var v2, unsigned idx, literal antecedent, bool propagate_eqc) { + m_stats.m_num_bit2core++; context & ctx = get_context(); SASSERT(ctx.get_assignment(antecedent) == l_true); @@ -1192,6 +1228,12 @@ namespace smt { } else { ctx.assign(consequent, mk_bit_eq_justification(v1, v2, consequent, antecedent)); + literal_vector lits; + lits.push_back(~consequent); + lits.push_back(antecedent); + lits.push_back(~mk_eq(get_enode(v1)->get_owner(), get_enode(v2)->get_owner(), false)); + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + if (m_wpos[v2] == idx) find_wpos(v2); // REMARK: bit_eq_justification is marked as a theory_bv justification. @@ -1601,6 +1643,7 @@ namespace smt { st.update("bv dynamic diseqs", m_stats.m_num_diseq_dynamic); st.update("bv bit2core", m_stats.m_num_bit2core); st.update("bv->core eq", m_stats.m_num_th2core_eq); + st.update("bv dynamic eqs", m_stats.m_num_eq_dynamic); } #ifdef Z3DEBUG diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index bb0dcc907..17d03b412 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -34,6 +34,7 @@ namespace smt { struct theory_bv_stats { unsigned m_num_diseq_static, m_num_diseq_dynamic, m_num_bit2core, m_num_th2core_eq, m_num_conflicts; + unsigned m_num_eq_dynamic; void reset() { memset(this, 0, sizeof(theory_bv_stats)); } theory_bv_stats() { reset(); } }; @@ -124,8 +125,9 @@ namespace smt { typedef std::pair value_sort_pair; typedef pair_hash, unsigned_hash> value_sort_pair_hash; typedef map > value2var; - value2var m_fixed_var_table; + value2var m_fixed_var_table; + literal_vector m_tmp_literals; svector m_prop_queue; bool m_approximates_large_bvs; @@ -166,6 +168,7 @@ namespace smt { void find_wpos(theory_var v); friend class fixed_eq_justification; void fixed_var_eh(theory_var v); + void add_fixed_eq(theory_var v1, theory_var v2); bool get_fixed_value(theory_var v, numeral & result) const; void internalize_num(app * n); void internalize_add(app * n); diff --git a/src/tactic/bv/bit_blaster_tactic.h b/src/tactic/bv/bit_blaster_tactic.h index cb7f6f7a9..d840154b9 100644 --- a/src/tactic/bv/bit_blaster_tactic.h +++ b/src/tactic/bv/bit_blaster_tactic.h @@ -1,32 +1,33 @@ -/*++ + /*++ Copyright (c) 2011 Microsoft Corporation - -Module Name: - + + Module Name: + bit_blaster_tactic.h - -Abstract: - + + Abstract: + Apply bit-blasting to a given goal. - -Author: - + + Author: + Leonardo (leonardo) 2011-10-25 - -Notes: - ---*/ + + Notes: + + --*/ #ifndef BIT_BLASTER_TACTIC_H_ #define BIT_BLASTER_TACTIC_H_ - -#include"params.h" -#include"bit_blaster_rewriter.h" -class ast_manager; -class tactic; - + + #include"params.h" + #include"bit_blaster_rewriter.h" + class ast_manager; + class tactic; + tactic * mk_bit_blaster_tactic(ast_manager & m, params_ref const & p = params_ref()); tactic * mk_bit_blaster_tactic(ast_manager & m, bit_blaster_rewriter* rw, params_ref const & p = params_ref()); -/* + /* ADD_TACTIC("bit-blast", "reduce bit-vector expressions into SAT.", "mk_bit_blaster_tactic(m, p)") -*/ -#endif + */ + #endif + diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index f1ffe4b53..e436d19c4 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -22,7 +22,7 @@ Revision History: #include"occurs.h" #include"cooperate.h" #include"goal_shared_occs.h" -#include"ast_smt2_pp.h" +#include"ast_pp.h" class solve_eqs_tactic : public tactic { struct imp { @@ -92,21 +92,23 @@ class solve_eqs_tactic : public tactic { } // Use: (= x def) and (= def x) - bool trivial_solve(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) { + + bool trivial_solve1(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) { + if (is_uninterp_const(lhs) && !m_candidate_vars.is_marked(lhs) && !occurs(lhs, rhs) && check_occs(lhs)) { var = to_app(lhs); def = rhs; pr = 0; return true; } - else if (is_uninterp_const(rhs) && !m_candidate_vars.is_marked(rhs) && !occurs(rhs, lhs) && check_occs(rhs)) { - var = to_app(rhs); - def = lhs; - if (m_produce_proofs) - pr = m().mk_commutativity(m().mk_eq(lhs, rhs)); - return true; + else { + return false; } - return false; + } + bool trivial_solve(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) { + return + trivial_solve1(lhs, rhs, var, def, pr) || + trivial_solve1(rhs, lhs, var, def, pr); } // (ite c (= x t1) (= x t2)) --> (= x (ite c t1 t2)) From 65da0f9f3a8f901fd122670d725c6b9bca07b32c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 21 Dec 2015 06:07:50 -0800 Subject: [PATCH 09/87] updated seq Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 19 ++++++++----------- src/util/scoped_vector.h | 2 +- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 753ddabd2..db96f3d0c 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -318,7 +318,8 @@ bool theory_seq::check_length_coherence_tbd() { // each variable that canonizes to itself can have length 0. unsigned sz = get_num_vars(); for (unsigned i = 0; i < sz; ++i) { - enode* n = get_enode(i); + unsigned j = (i + m_branch_variable_head) % sz; + enode* n = get_enode(j); expr* e = n->get_owner(); if (m_util.is_re(e)) { continue; @@ -332,15 +333,14 @@ bool theory_seq::check_length_coherence_tbd() { TRACE("seq", tout << "Unsolved " << mk_pp(e, m) << "\n";); #if 0 if (!assume_equality(e, emp)) { - // e = emp \/ e = head*tail & head = unit(v) + // e = emp \/ e = unit(head.elem(e))*tail(e) sort* char_sort = 0; VERIFY(m_util.is_seq(m.get_sort(e), char_sort)); expr_ref tail(mk_skolem(symbol("seq.tail"), e), m); expr_ref v(mk_skolem(symbol("seq.head.elem"), e, 0, 0, char_sort), m); expr_ref head(m_util.str.mk_unit(v), m); expr_ref conc(m_util.str.mk_concat(head, tail), m); - literal e_eq_emp(mk_eq(e, emp, false)); - add_axiom(e_eq_emp, mk_eq(e, conc, false)); + add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false)); } #endif coherent = false; @@ -565,10 +565,9 @@ bool theory_seq::solve_nqs() { bool change = false; context & ctx = get_context(); for (unsigned i = 0; !ctx.inconsistent() && i < m_nqs.size(); ++i) { - change = solve_ne(i) || change; - if (m_nqs[i].is_solved()) { - m_nqs.erase_and_swap(i); - --i; + TRACE("seq", tout << i << " " << m_nqs.size() << "\n";); + if (!m_nqs[i].is_solved()) { + change = solve_ne(i) || change; } } return change; @@ -614,7 +613,7 @@ bool theory_seq::solve_ne(unsigned idx) { // continue } else { - TRACE("seq", tout << lhs.size() << "\n"; + TRACE("seq", for (unsigned j = 0; j < lhs.size(); ++j) { tout << mk_pp(lhs[j].get(), m) << " "; } @@ -625,11 +624,9 @@ bool theory_seq::solve_ne(unsigned idx) { expr_ref nl(lhs[j].get(), m); expr_ref nr(rhs[j].get(), m); if (m_util.is_seq(nl) || m_util.is_re(nl)) { - //std::cout << "push_ne " << nl << " != " << nr << "\n"; m_trail_stack.push(push_ne(*this, idx, nl, nr)); } else { - //std::cout << "push_lit\n"; literal lit(mk_eq(nl, nr, false)); m_trail_stack.push(push_lit(*this, idx, ~lit)); ctx.mark_as_relevant(lit); diff --git a/src/util/scoped_vector.h b/src/util/scoped_vector.h index a05b19487..bacfbac89 100644 --- a/src/util/scoped_vector.h +++ b/src/util/scoped_vector.h @@ -110,7 +110,7 @@ public: void erase_and_swap(unsigned i) { if (i + 1 < size()) { - set(i, m_elems[m_index[i]]); + set(i, m_elems[m_index[size()-1]]); } pop_back(); } From ea218da2c427087419628b8807b1a1c77a093476 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 22 Dec 2015 00:37:27 +0100 Subject: [PATCH 10/87] Bugfix in build scripts. Additional fix for #357, relates to #361. --- scripts/mk_util.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 2d1715655..e3f7d7107 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -715,6 +715,9 @@ def parse_options(): if IS_WINDOWS: # Installing under Windows doesn't make sense as the install prefix is used # but that doesn't make sense under Windows + # CMW: It makes perfectly good sense; the prefix is Python's sys.prefix, + # i.e., something along the lines of C:\Python\... At the moment we are not + # sure whether we would want to install libz3.dll into that directory though. PYTHON_INSTALL_ENABLED = False else: if not PYTHON_PACKAGE_DIR.startswith(PREFIX): @@ -1352,21 +1355,19 @@ class PythonInstallComponent(Component): if not PYTHON_INSTALL_ENABLED: return - if self.is_osx_hack(): - # Use full path that is outside of install prefix + if IS_WINDOWS or IS_OSX: + # Use full path that is possibly outside of install prefix self.pythonPkgDir = PYTHON_PACKAGE_DIR - self.in_prefix_install = False + self.in_prefix_install = PYTHON_PACKAGE_DIR.startswith(PREFIX) assert os.path.isabs(self.pythonPkgDir) else: - # Use path inside the prefix (should be the normal case) + # Use path inside the prefix (should be the normal case on Linux) + # CMW: Also normal on *BSD? assert PYTHON_PACKAGE_DIR.startswith(PREFIX) self.pythonPkgDir = strip_path_prefix(PYTHON_PACKAGE_DIR, PREFIX) assert not os.path.isabs(self.pythonPkgDir) assert self.in_prefix_install - def is_osx_hack(self): - return IS_OSX and not PYTHON_PACKAGE_DIR.startswith(PREFIX) - def main_component(self): return False From a30fe1e2ec28d503abbda5d448f1c6e0278ecbb8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 22 Dec 2015 00:52:37 +0100 Subject: [PATCH 11/87] Followup to previous build fix. Relates to #357 and #361 --- scripts/mk_util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index e3f7d7107..e76eaf0bb 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1348,6 +1348,7 @@ class DLLComponent(Component): class PythonInstallComponent(Component): def __init__(self, name, libz3Component): assert isinstance(libz3Component, DLLComponent) + global PYTHON_INSTALL_ENABLED Component.__init__(self, name, None, []) self.pythonPkgDir = None self.in_prefix_install = True From e98ee6ec061bcaf1de5fa4275765da78f8aa9d39 Mon Sep 17 00:00:00 2001 From: Tony Tiger Date: Tue, 22 Dec 2015 13:00:55 +0000 Subject: [PATCH 12/87] Fixing building under OS X Previous method is_osx_hack didn't exist, possibly wasn't cleaned up. This change has been tested and Z3 compiles successfully within a 2.7 virtualenv running on OS X 10.10.5. --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index e76eaf0bb..95a97ea83 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1378,7 +1378,7 @@ class PythonInstallComponent(Component): MakeRuleCmd.make_install_directory(out, self.pythonPkgDir, in_prefix=self.in_prefix_install) # Sym-link or copy libz3 into python package directory - if IS_WINDOWS or self.is_osx_hack(): + if IS_WINDOWS or IS_OSX: MakeRuleCmd.install_files(out, self.libz3Component.dll_file(), os.path.join(self.pythonPkgDir, From 9c6271ddeddab61d9d995926abb2e42717a5cd45 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Dec 2015 10:43:18 -0800 Subject: [PATCH 13/87] add debugging facilities for github issues #384 #367 Signed-off-by: Nikolaj Bjorner --- scripts/update_api.py | 2 +- src/api/api_ast.cpp | 2 + src/api/api_ast_vector.cpp | 1 + src/api/java/Context.java | 1 + src/api/ml/z3.ml | 912 ++++++++++++------------- src/api/z3_replayer.cpp | 10 +- src/api/z3_replayer.h | 2 +- src/ast/ast.cpp | 1 + src/ast/rewriter/expr_safe_replace.cpp | 16 +- src/ast/seq_decl_plugin.cpp | 23 +- src/ast/seq_decl_plugin.h | 9 +- src/smt/theory_seq.cpp | 6 +- src/smt/theory_seq_empty.h | 7 + src/util/mpf.cpp | 16 +- 14 files changed, 529 insertions(+), 479 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index febbf3eb2..fc0f1c939 100644 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -1079,7 +1079,7 @@ def def_API(name, result, params): def mk_bindings(): exe_c.write("void register_z3_replayer_cmds(z3_replayer & in) {\n") for key, val in API2Id.items(): - exe_c.write(" in.register_cmd(%s, exec_%s);\n" % (key, val)) + exe_c.write(" in.register_cmd(%s, exec_%s, \"%s\");\n" % (key, val, val)) exe_c.write("}\n") def ml_method_name(name): diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 9f0ddbaa8..944e447c6 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -776,6 +776,8 @@ extern "C" { SET_ERROR_CODE(Z3_SORT_ERROR); RETURN_Z3(of_expr(0)); } + SASSERT(from[i]->get_ref_count() > 0); + SASSERT(to[i]->get_ref_count() > 0); } expr_safe_replace subst(m); for (unsigned i = 0; i < num_exprs; i++) { diff --git a/src/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index e1d4d78ff..d6ff1bbb3 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.cpp @@ -26,6 +26,7 @@ Revision History: extern "C" { Z3_ast_vector Z3_API Z3_mk_ast_vector(Z3_context c) { + std::cout << "ast-vector\n"; Z3_TRY; LOG_Z3_mk_ast_vector(c); RESET_ERROR_CODE(); diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 4d8484ced..8d2bc5b50 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -3822,6 +3822,7 @@ public class Context extends IDisposable m_Params_DRQ.clear(this); m_Probe_DRQ.clear(this); m_Solver_DRQ.clear(this); + m_Optimize_DRQ.clear(this); m_Statistics_DRQ.clear(this); m_Tactic_DRQ.clear(this); m_Fixedpoint_DRQ.clear(this); diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 84c70001e..8fdc795fb 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -60,7 +60,7 @@ struct o.inc_ref (context_gno ctx) no ; ( if not (is_null o.m_n_obj) then - o.dec_ref (context_gno ctx) o.m_n_obj ; + o.dec_ref (context_gno ctx) o.m_n_obj ; (context_sub1 ctx) ) ; o.m_n_obj <- no @@ -68,8 +68,8 @@ struct let z3obj_dispose o = if not (is_null o.m_n_obj) then ( - o.dec_ref (z3obj_gnc o) o.m_n_obj ; - (context_sub1 (z3obj_gc o)) + o.dec_ref (z3obj_gnc o) o.m_n_obj ; + (context_sub1 (z3obj_gc o)) ) ; o.m_n_obj <- null @@ -81,12 +81,12 @@ struct let z3_native_object_of_ast_ptr : context -> Z3native.ptr -> z3_native_object = fun ctx no -> let res : z3_native_object = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.inc_ref ; - dec_ref = Z3native.dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.inc_ref ; + dec_ref = Z3native.dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; - res + res end open Internal @@ -137,18 +137,18 @@ struct let create_i ( ctx : context ) ( no : Z3native.ptr ) = let res : symbol = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = z3obj_nil_ref ; - dec_ref = z3obj_nil_ref } in + m_n_obj = null ; + inc_ref = z3obj_nil_ref ; + dec_ref = z3obj_nil_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res let create_s ( ctx : context ) ( no : Z3native.ptr ) = let res : symbol = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = z3obj_nil_ref ; - dec_ref = z3obj_nil_ref } in + m_n_obj = null ; + inc_ref = z3obj_nil_ref ; + dec_ref = z3obj_nil_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -156,7 +156,7 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = match (symbol_kind_of_int (Z3native.get_symbol_kind (context_gno ctx) no)) with | INT_SYMBOL -> (create_i ctx no) - | STRING_SYMBOL -> (create_s ctx no) + | STRING_SYMBOL -> (create_s ctx no) let gc ( x : symbol ) = (z3obj_gc x) let gnc ( x : symbol ) = (z3obj_gnc x) @@ -264,16 +264,16 @@ end = struct module ASTVector = struct type ast_vector = z3_native_object - + let create ( ctx : context ) ( no : Z3native.ptr ) = let res : ast_vector = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.ast_vector_inc_ref ; - dec_ref = Z3native.ast_vector_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.ast_vector_inc_ref ; + dec_ref = Z3native.ast_vector_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res - + let mk_ast_vector ( ctx : context ) = (create ctx (Z3native.mk_ast_vector (context_gno ctx))) let get_size ( x : ast_vector ) = @@ -287,69 +287,69 @@ end = struct let resize ( x : ast_vector ) ( new_size : int ) = Z3native.ast_vector_resize (z3obj_gnc x) (z3obj_gno x) new_size - + let push ( x : ast_vector ) ( a : ast ) = Z3native.ast_vector_push (z3obj_gnc x) (z3obj_gno x) (z3obj_gno a) - + let translate ( x : ast_vector ) ( to_ctx : context ) = create to_ctx (Z3native.ast_vector_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx)) let to_list ( x : ast_vector ) = - let xs = (get_size x) in + let xs = (get_size x) in let f i = (get x i) in mk_list f xs let to_expr_list ( x : ast_vector ) = - let xs = (get_size x) in + let xs = (get_size x) in let f i = (Expr.expr_of_ptr (z3obj_gc x) (z3obj_gno (get x i))) in mk_list f xs - + let to_string ( x : ast_vector ) = Z3native.ast_vector_to_string (z3obj_gnc x) (z3obj_gno x) end module ASTMap = - struct + struct type ast_map = z3_native_object - + let create ( ctx : context ) ( no : Z3native.ptr ) = let res : ast_map = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.ast_map_inc_ref ; - dec_ref = Z3native.ast_map_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.ast_map_inc_ref ; + dec_ref = Z3native.ast_map_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; - res - + res + let mk_ast_map ( ctx : context ) = (create ctx (Z3native.mk_ast_map (context_gno ctx))) let astmap_of_ptr ( ctx : context ) ( no : Z3native.ptr ) = let res : ast_map = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.ast_map_inc_ref ; - dec_ref = Z3native.ast_map_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.ast_map_inc_ref ; + dec_ref = Z3native.ast_map_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res - + let contains ( x : ast_map ) ( key : ast ) = Z3native.ast_map_contains (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key) - + let find ( x : ast_map ) ( key : ast ) = ast_of_ptr (z3obj_gc x) (Z3native.ast_map_find (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key)) - + let insert ( x : ast_map ) ( key : ast ) ( value : ast ) = Z3native.ast_map_insert (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key) (z3obj_gno value) let erase ( x : ast_map ) ( key : ast ) = Z3native.ast_map_erase (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key) - + let reset ( x : ast_map ) = Z3native.ast_map_reset (z3obj_gnc x) (z3obj_gno x) let get_size ( x : ast_map ) = Z3native.ast_map_size (z3obj_gnc x) (z3obj_gno x) - + let get_keys ( x : ast_map ) = let av = ASTVector.create (z3obj_gc x) (Z3native.ast_map_keys (z3obj_gnc x) (z3obj_gno x)) in (ASTVector.to_list av) @@ -369,7 +369,7 @@ end = struct | QUANTIFIER_AST | VAR_AST -> true | _ -> false - + let is_app ( x : ast ) = (get_ast_kind x) == APP_AST let is_var ( x : ast ) = (get_ast_kind x) == VAR_AST let is_quantifier ( x : ast ) = (get_ast_kind x) == QUANTIFIER_AST @@ -385,12 +385,12 @@ end = struct false else Z3native.is_eq_ast (z3obj_gnc a) (z3obj_gno a) (z3obj_gno b) - + let compare a b = if (get_id a) < (get_id b) then -1 else if (get_id a) > (get_id b) then 1 else - 0 - + 0 + let translate ( x : ast ) ( to_ctx : context ) = if (z3obj_gnc x) == (context_gno to_ctx) then x @@ -456,11 +456,11 @@ end = struct let equal : sort -> sort -> bool = fun a b -> (a == b) || if (gnc a) != (gnc b) then - false + false else - (Z3native.is_eq_sort (gnc a) (gno a) (gno b)) + (Z3native.is_eq_sort (gnc a) (gno a) (gno b)) - + let get_id ( x : sort ) = Z3native.get_sort_id (gnc x) (gno x) let get_sort_kind ( x : sort ) = (sort_kind_of_int (Z3native.get_sort_kind (gnc x) (gno x))) let get_name ( x : sort ) = (Symbol.create (gc x) (Z3native.get_sort_name (gnc x) (gno x))) @@ -468,9 +468,9 @@ end = struct let mk_uninterpreted ( ctx : context ) ( s : Symbol.symbol ) = let res = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.inc_ref ; - dec_ref = Z3native.dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.inc_ref ; + dec_ref = Z3native.dec_ref } in (z3obj_sno res ctx (Z3native.mk_uninterpreted_sort (context_gno ctx) (Symbol.gno s))) ; (z3obj_create res) ; Sort(res) @@ -490,14 +490,14 @@ sig module Parameter : sig type parameter = - P_Int of int + P_Int of int | P_Dbl of float | P_Sym of Symbol.symbol | P_Srt of Sort.sort | P_Ast of AST.ast | P_Fdl of func_decl | P_Rat of string - + val get_kind : parameter -> Z3enums.parameter_kind val get_int : parameter -> int val get_float : parameter -> float @@ -538,18 +538,18 @@ end = struct let create_ndr ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort list ) ( range : Sort.sort ) = let res = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.inc_ref ; - dec_ref = Z3native.dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.inc_ref ; + dec_ref = Z3native.dec_ref } in (z3obj_sno res ctx (Z3native.mk_func_decl (context_gno ctx) (Symbol.gno name) (List.length domain) (Sort.sort_lton domain) (Sort.gno range))) ; (z3obj_create res) ; FuncDecl(res) let create_pdr ( ctx : context) ( prefix : string ) ( domain : Sort.sort list ) ( range : Sort.sort ) = let res = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.inc_ref ; - dec_ref = Z3native.dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.inc_ref ; + dec_ref = Z3native.dec_ref } in (z3obj_sno res ctx (Z3native.mk_fresh_func_decl (context_gno ctx) prefix (List.length domain) (Sort.sort_lton domain) (Sort.gno range))) ; (z3obj_create res) ; FuncDecl(res) @@ -568,51 +568,51 @@ end = struct | P_Ast of AST.ast | P_Fdl of func_decl | P_Rat of string - + let get_kind ( x : parameter ) = (match x with - | P_Int(_) -> PARAMETER_INT - | P_Dbl(_) -> PARAMETER_DOUBLE - | P_Sym(_) -> PARAMETER_SYMBOL - | P_Srt(_) -> PARAMETER_SORT - | P_Ast(_) -> PARAMETER_AST - | P_Fdl(_) -> PARAMETER_FUNC_DECL - | P_Rat(_) -> PARAMETER_RATIONAL) - + | P_Int(_) -> PARAMETER_INT + | P_Dbl(_) -> PARAMETER_DOUBLE + | P_Sym(_) -> PARAMETER_SYMBOL + | P_Srt(_) -> PARAMETER_SORT + | P_Ast(_) -> PARAMETER_AST + | P_Fdl(_) -> PARAMETER_FUNC_DECL + | P_Rat(_) -> PARAMETER_RATIONAL) + let get_int ( x : parameter ) = match x with - | P_Int(x) -> x - | _ -> raise (Z3native.Exception "parameter is not an int") - + | P_Int(x) -> x + | _ -> raise (Z3native.Exception "parameter is not an int") + let get_float ( x : parameter ) = match x with - | P_Dbl(x) -> x - | _ -> raise (Z3native.Exception "parameter is not a float") + | P_Dbl(x) -> x + | _ -> raise (Z3native.Exception "parameter is not a float") let get_symbol ( x : parameter ) = match x with - | P_Sym(x) -> x - | _ -> raise (Z3native.Exception "parameter is not a symbol") - + | P_Sym(x) -> x + | _ -> raise (Z3native.Exception "parameter is not a symbol") + let get_sort ( x : parameter ) = match x with - | P_Srt(x) -> x - | _ -> raise (Z3native.Exception "parameter is not a sort") + | P_Srt(x) -> x + | _ -> raise (Z3native.Exception "parameter is not a sort") let get_ast ( x : parameter ) = match x with - | P_Ast(x) -> x - | _ -> raise (Z3native.Exception "parameter is not an ast") + | P_Ast(x) -> x + | _ -> raise (Z3native.Exception "parameter is not an ast") let get_func_decl ( x : parameter ) = match x with - | P_Fdl(x) -> x - | _ -> raise (Z3native.Exception "parameter is not a func_decl") + | P_Fdl(x) -> x + | _ -> raise (Z3native.Exception "parameter is not a func_decl") let get_rational ( x : parameter ) = match x with - | P_Rat(x) -> x - | _ -> raise (Z3native.Exception "parameter is not a rational string") + | P_Rat(x) -> x + | _ -> raise (Z3native.Exception "parameter is not a rational string") end let mk_func_decl ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort list ) ( range : Sort.sort ) = @@ -710,19 +710,19 @@ end = struct let param_descrs_of_ptr ( ctx : context ) ( no : Z3native.ptr ) = let res : param_descrs = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.param_descrs_inc_ref ; - dec_ref = Z3native.param_descrs_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.param_descrs_inc_ref ; + dec_ref = Z3native.param_descrs_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res - + let validate ( x : param_descrs ) ( p : params ) = Z3native.params_validate (z3obj_gnc x) (z3obj_gno p) (z3obj_gno x) - + let get_kind ( x : param_descrs ) ( name : Symbol.symbol ) = (param_kind_of_int (Z3native.param_descrs_get_kind (z3obj_gnc x) (z3obj_gno x) (Symbol.gno name))) - + let get_names ( x : param_descrs ) = let n = Z3native.param_descrs_size (z3obj_gnc x) (z3obj_gno x) in let f i = Symbol.create (z3obj_gc x) (Z3native.param_descrs_get_name (z3obj_gnc x) (z3obj_gno x) i) in @@ -746,9 +746,9 @@ end = struct let mk_params ( ctx : context ) = let res : params = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.params_inc_ref ; - dec_ref = Z3native.params_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.params_inc_ref ; + dec_ref = Z3native.params_dec_ref } in (z3obj_sno res ctx (Z3native.mk_params (context_gno ctx))) ; (z3obj_create res) ; res @@ -807,32 +807,30 @@ end = struct let gno e = match e with Expr(a) -> (z3obj_gno a) let expr_of_ptr : context -> Z3native.ptr -> expr = fun ctx no -> + let e = z3_native_object_of_ast_ptr ctx no in if ast_kind_of_int (Z3native.get_ast_kind (context_gno ctx) no) == QUANTIFIER_AST then - Expr(z3_native_object_of_ast_ptr ctx no) + Expr(e) else let s = Z3native.get_sort (context_gno ctx) no in let sk = (sort_kind_of_int (Z3native.get_sort_kind (context_gno ctx) s)) in if (Z3native.is_algebraic_number (context_gno ctx) no) then - Expr(z3_native_object_of_ast_ptr ctx no) - else - if (Z3native.is_numeral_ast (context_gno ctx) no) then - match sk with - | REAL_SORT - | BOOL_SORT - | ARRAY_SORT - | BV_SORT - | ROUNDING_MODE_SORT - | RELATION_SORT - | UNINTERPRETED_SORT - | FLOATING_POINT_SORT - | INT_SORT - | DATATYPE_SORT - | FINITE_DOMAIN_SORT -> - Expr(z3_native_object_of_ast_ptr ctx no) - | _ -> - raise (Z3native.Exception "Unsupported numeral object") - else - Expr(z3_native_object_of_ast_ptr ctx no) + Expr(e) + else if (Z3native.is_numeral_ast (context_gno ctx) no) then + match sk with + | REAL_SORT + | BOOL_SORT + | ARRAY_SORT + | BV_SORT + | ROUNDING_MODE_SORT + | RELATION_SORT + | UNINTERPRETED_SORT + | FLOATING_POINT_SORT + | INT_SORT + | DATATYPE_SORT + | FINITE_DOMAIN_SORT -> Expr(e) + | _ -> raise (Z3native.Exception "Unsupported numeral object") + else + Expr(e) let expr_of_ast a = let q = (Z3enums.ast_kind_of_int (Z3native.get_ast_kind (z3obj_gnc a) (z3obj_gno a))) in @@ -866,9 +864,9 @@ end = struct let get_num_args ( x : expr ) = Z3native.get_app_num_args (gnc x) (gno x) let get_args ( x : expr ) = let n = (get_num_args x) in - let f i = expr_of_ptr (Expr.gc x) (Z3native.get_app_arg (gnc x) (gno x) i) in - mk_list f n - + let f i = expr_of_ptr (Expr.gc x) (Z3native.get_app_arg (gnc x) (gno x) i) in + mk_list f n + let update ( x : expr ) ( args : expr list ) = if ((AST.is_app (ast_of_expr x)) && (List.length args <> (get_num_args x))) then raise (Z3native.Exception "Number of arguments does not match") @@ -880,7 +878,7 @@ end = struct raise (Z3native.Exception "Argument sizes do not match") else expr_of_ptr (Expr.gc x) (Z3native.substitute (gnc x) (gno x) (List.length from) (expr_lton from) (expr_lton to_)) - + let substitute_one ( x : expr ) from to_ = substitute ( x : expr ) [ from ] [ to_ ] @@ -1012,10 +1010,10 @@ struct match e with Expr.Expr(a) -> let q = (Z3enums.ast_kind_of_int (Z3native.get_ast_kind (z3obj_gnc a) (z3obj_gno a))) in if (q != Z3enums.QUANTIFIER_AST) then - raise (Z3native.Exception "Invalid coercion") + raise (Z3native.Exception "Invalid coercion") else - Quantifier(e) - + Quantifier(e) + let gc ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gc e) let gnc ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gnc e) let gno ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gno e) @@ -1023,25 +1021,25 @@ struct module Pattern = struct type pattern = Pattern of AST.ast - + let ast_of_pattern e = match e with Pattern(x) -> x let pattern_of_ast a = (* CMW: Unchecked ok? *) Pattern(a) - + let gc ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gc a) let gnc ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gnc a) let gno ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gno a) let get_num_terms ( x : pattern ) = - Z3native.get_pattern_num_terms (gnc x) (gno x) + Z3native.get_pattern_num_terms (gnc x) (gno x) let get_terms ( x : pattern ) = let n = (get_num_terms x) in let f i = (expr_of_ptr (gc x) (Z3native.get_pattern (gnc x) (gno x) i)) in mk_list f n - + let to_string ( x : pattern ) = Z3native.pattern_to_string (gnc x) (gno x) end @@ -1101,76 +1099,76 @@ struct raise (Z3native.Exception "Number of sorts does not match number of names") else if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier (context_gno ctx) true - (match weight with | None -> 1 | Some(x) -> x) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length sorts) (Sort.sort_lton sorts) - (Symbol.symbol_lton names) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length sorts) (Sort.sort_lton sorts) + (Symbol.symbol_lton names) + (Expr.gno body))) else Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_ex (context_gno ctx) true - (match weight with | None -> 1 | Some(x) -> x) - (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) - (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length nopatterns) (expr_lton nopatterns) - (List.length sorts) (Sort.sort_lton sorts) - (Symbol.symbol_lton names) - (Expr.gno body))) - + (match weight with | None -> 1 | Some(x) -> x) + (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) + (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length nopatterns) (expr_lton nopatterns) + (List.length sorts) (Sort.sort_lton sorts) + (Symbol.symbol_lton names) + (Expr.gno body))) + let mk_forall_const ( ctx : context ) ( bound_constants : expr list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const (context_gno ctx) true - (match weight with | None -> 1 | Some(x) -> x) - (List.length bound_constants) (expr_lton bound_constants) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (List.length bound_constants) (expr_lton bound_constants) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (Expr.gno body))) else Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const_ex (context_gno ctx) true - (match weight with | None -> 1 | Some(x) -> x) - (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) - (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) - (List.length bound_constants) (expr_lton bound_constants) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length nopatterns) (expr_lton nopatterns) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) + (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) + (List.length bound_constants) (expr_lton bound_constants) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length nopatterns) (expr_lton nopatterns) + (Expr.gno body))) let mk_exists ( ctx : context ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = if (List.length sorts) != (List.length names) then raise (Z3native.Exception "Number of sorts does not match number of names") else if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier (context_gno ctx) false - (match weight with | None -> 1 | Some(x) -> x) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length sorts) (Sort.sort_lton sorts) - (Symbol.symbol_lton names) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length sorts) (Sort.sort_lton sorts) + (Symbol.symbol_lton names) + (Expr.gno body))) else Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_ex (context_gno ctx) false - (match weight with | None -> 1 | Some(x) -> x) - (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) - (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length nopatterns) (expr_lton nopatterns) - (List.length sorts) (Sort.sort_lton sorts) - (Symbol.symbol_lton names) - (Expr.gno body))) - + (match weight with | None -> 1 | Some(x) -> x) + (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) + (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length nopatterns) (expr_lton nopatterns) + (List.length sorts) (Sort.sort_lton sorts) + (Symbol.symbol_lton names) + (Expr.gno body))) + let mk_exists_const ( ctx : context ) ( bound_constants : expr list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const (context_gno ctx) false - (match weight with | None -> 1 | Some(x) -> x) - (List.length bound_constants) (expr_lton bound_constants) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (List.length bound_constants) (expr_lton bound_constants) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (Expr.gno body))) else Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const_ex (context_gno ctx) false - (match weight with | None -> 1 | Some(x) -> x) - (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) - (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) - (List.length bound_constants) (expr_lton bound_constants) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length nopatterns) (expr_lton nopatterns) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) + (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) + (List.length bound_constants) (expr_lton bound_constants) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length nopatterns) (expr_lton nopatterns) + (Expr.gno body))) let mk_quantifier ( ctx : context ) ( universal : bool ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = if (universal) then @@ -1209,7 +1207,7 @@ struct let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort ) ( range : Sort.sort ) = (Expr.mk_const ctx name (mk_sort ctx domain range)) - let mk_const_s ( ctx : context ) ( name : string ) ( domain : Sort.sort ) ( range : Sort.sort ) = + let mk_const_s ( ctx : context ) ( name : string ) ( domain : Sort.sort ) ( range : Sort.sort ) = mk_const ctx (Symbol.mk_string ctx name) domain range let mk_select ( ctx : context ) ( a : expr ) ( i : expr ) = @@ -1229,7 +1227,7 @@ struct expr_of_ptr ctx (Z3native.mk_array_default (context_gno ctx) (Expr.gno arg)) let mk_array_ext ( ctx : context) ( arg1 : expr ) ( arg2 : expr ) = - expr_of_ptr ctx (Z3native.mk_array_ext (context_gno ctx) (Expr.gno arg1) (Expr.gno arg2)) + expr_of_ptr ctx (Z3native.mk_array_ext (context_gno ctx) (Expr.gno arg1) (Expr.gno arg2)) end @@ -1305,7 +1303,7 @@ struct let is_relation ( x : expr ) = let nc = (Expr.gnc x) in ((Z3native.is_app (Expr.gnc x) (Expr.gno x)) && - (sort_kind_of_int (Z3native.get_sort_kind nc (Z3native.get_sort nc (Expr.gno x))) == RELATION_SORT)) + (sort_kind_of_int (Z3native.get_sort_kind nc (Z3native.get_sort nc (Expr.gno x))) == RELATION_SORT)) let is_store ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_STORE) let is_empty ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_EMPTY) @@ -1335,7 +1333,7 @@ struct module Constructor = struct type constructor = z3_native_object - + module FieldNumTable = Hashtbl.Make(struct type t = AST.ast let equal x y = AST.compare x y = 0 @@ -1347,28 +1345,28 @@ struct let create ( ctx : context ) ( name : Symbol.symbol ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : Sort.sort option list ) ( sort_refs : int list ) = let n = (List.length field_names) in if n != (List.length sorts) then - raise (Z3native.Exception "Number of field names does not match number of sorts") + raise (Z3native.Exception "Number of field names does not match number of sorts") else - if n != (List.length sort_refs) then - raise (Z3native.Exception "Number of field names does not match number of sort refs") - else + if n != (List.length sort_refs) then + raise (Z3native.Exception "Number of field names does not match number of sort refs") + else let ptr = (Z3native.mk_constructor (context_gno ctx) (Symbol.gno name) - (Symbol.gno recognizer) - n - (Symbol.symbol_lton field_names) - (Sort.sort_option_lton sorts) - (Array.of_list sort_refs)) in - let no : constructor = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = z3obj_nil_ref ; - dec_ref = z3obj_nil_ref} in - (z3obj_sno no ctx ptr) ; - (z3obj_create no) ; - let f = fun o -> Z3native.del_constructor (z3obj_gnc o) (z3obj_gno o) in - Gc.finalise f no ; - FieldNumTable.add _field_nums no n ; - no - + (Symbol.gno recognizer) + n + (Symbol.symbol_lton field_names) + (Sort.sort_option_lton sorts) + (Array.of_list sort_refs)) in + let no : constructor = { m_ctx = ctx ; + m_n_obj = null ; + inc_ref = z3obj_nil_ref ; + dec_ref = z3obj_nil_ref} in + (z3obj_sno no ctx ptr) ; + (z3obj_create no) ; + let f = fun o -> Z3native.del_constructor (z3obj_gnc o) (z3obj_gno o) in + Gc.finalise f no ; + FieldNumTable.add _field_nums no n ; + no + let get_num_fields ( x : constructor ) = FieldNumTable.find _field_nums x let get_constructor_decl ( x : constructor ) = @@ -1377,13 +1375,13 @@ struct let get_tester_decl ( x : constructor ) = let (_, b, _) = (Z3native.query_constructor (z3obj_gnc x) (z3obj_gno x) (get_num_fields x)) in - func_decl_of_ptr (z3obj_gc x) b + func_decl_of_ptr (z3obj_gc x) b let get_accessor_decls ( x : constructor ) = let (_, _, c) = (Z3native.query_constructor (z3obj_gnc x) (z3obj_gno x) (get_num_fields x)) in let f i = func_decl_of_ptr (z3obj_gc x) (Array.get c i) in mk_list f (Array.length c) - + end module ConstructorList = @@ -1392,9 +1390,9 @@ struct let create ( ctx : context ) ( c : Constructor.constructor list ) = let res : constructor_list = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = z3obj_nil_ref ; - dec_ref = z3obj_nil_ref} in + m_n_obj = null ; + inc_ref = z3obj_nil_ref ; + dec_ref = z3obj_nil_ref} in let f x =(z3obj_gno x) in (z3obj_sno res ctx (Z3native.mk_constructor_list (context_gno ctx) (List.length c) (Array.of_list (List.map f c)))) ; (z3obj_create res) ; @@ -1429,8 +1427,8 @@ struct let mk_sorts_s ( ctx : context ) ( names : string list ) ( c : Constructor.constructor list list ) = mk_sorts ctx ( - let f e = (Symbol.mk_string ctx e) in - List.map f names + let f e = (Symbol.mk_string ctx e) in + List.map f names ) c @@ -1600,27 +1598,27 @@ struct let get_big_int ( x : expr ) = if (is_int_numeral x) then - let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in - (Big_int.big_int_of_string s) + let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in + (Big_int.big_int_of_string s) else raise (Z3native.Exception "Conversion failed.") - + let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) let mk_const ( ctx : context ) ( name : Symbol.symbol ) = Expr.mk_const ctx name (mk_sort ctx) - + let mk_const_s ( ctx : context ) ( name : string ) = mk_const ctx (Symbol.mk_string ctx name) - + let mk_mod ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = expr_of_ptr ctx (Z3native.mk_mod (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) - + let mk_rem ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = expr_of_ptr ctx (Z3native.mk_rem (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_numeral_s ( ctx : context ) ( v : string ) = expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx))) - + let mk_numeral_i ( ctx : context ) ( v : int ) = expr_of_ptr ctx (Z3native.mk_int (context_gno ctx) v (Sort.gno (mk_sort ctx))) @@ -1634,60 +1632,60 @@ struct module Real = struct let mk_sort ( ctx : context ) = - Sort.sort_of_ptr ctx (Z3native.mk_real_sort (context_gno ctx)) + Sort.sort_of_ptr ctx (Z3native.mk_real_sort (context_gno ctx)) let get_numerator ( x : expr ) = expr_of_ptr (Expr.gc x) (Z3native.get_numerator (Expr.gnc x) (Expr.gno x)) - + let get_denominator ( x : expr ) = expr_of_ptr (Expr.gc x) (Z3native.get_denominator (Expr.gnc x) (Expr.gno x)) - + let get_ratio ( x : expr ) = if (is_rat_numeral x) then - let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in - (Ratio.ratio_of_string s) + let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in + (Ratio.ratio_of_string s) else raise (Z3native.Exception "Conversion failed.") let to_decimal_string ( x : expr ) ( precision : int ) = Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision - + let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) let mk_const ( ctx : context ) ( name : Symbol.symbol ) = Expr.mk_const ctx name (mk_sort ctx) - + let mk_const_s ( ctx : context ) ( name : string ) = mk_const ctx (Symbol.mk_string ctx name) let mk_numeral_nd ( ctx : context ) ( num : int ) ( den : int ) = if (den == 0) then - raise (Z3native.Exception "Denominator is zero") + raise (Z3native.Exception "Denominator is zero") else - expr_of_ptr ctx (Z3native.mk_real (context_gno ctx) num den) - + expr_of_ptr ctx (Z3native.mk_real (context_gno ctx) num den) + let mk_numeral_s ( ctx : context ) ( v : string ) = expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx))) - + let mk_numeral_i ( ctx : context ) ( v : int ) = expr_of_ptr ctx (Z3native.mk_int (context_gno ctx) v (Sort.gno (mk_sort ctx))) - + let mk_is_integer ( ctx : context ) ( t : expr ) = (expr_of_ptr ctx (Z3native.mk_is_int (context_gno ctx) (Expr.gno t))) - + let mk_real2int ( ctx : context ) ( t : expr ) = (expr_of_ptr ctx (Z3native.mk_real2int (context_gno ctx) (Expr.gno t))) module AlgebraicNumber = struct let to_upper ( x : expr ) ( precision : int ) = - expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_upper (Expr.gnc x) (Expr.gno x) precision) - + expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_upper (Expr.gnc x) (Expr.gno x) precision) + let to_lower ( x : expr ) precision = - expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_lower (Expr.gnc x) (Expr.gno x) precision) - + expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_lower (Expr.gnc x) (Expr.gno x) precision) + let to_decimal_string ( x : expr ) ( precision : int ) = - Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision - + Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision + let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) end end @@ -1843,9 +1841,9 @@ struct let mk_sge ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = (expr_of_ptr ctx (Z3native.mk_bvsge (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_ugt ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - (expr_of_ptr ctx (Z3native.mk_bvugt (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) + (expr_of_ptr ctx (Z3native.mk_bvugt (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_sgt ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - (expr_of_ptr ctx (Z3native.mk_bvsgt (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) + (expr_of_ptr ctx (Z3native.mk_bvsgt (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_concat ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = expr_of_ptr ctx (Z3native.mk_concat (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_extract ( ctx : context ) ( high : int ) ( low : int ) ( t : expr ) = @@ -1857,7 +1855,7 @@ struct let mk_repeat ( ctx : context ) ( i : int ) ( t : expr ) = expr_of_ptr ctx (Z3native.mk_repeat (context_gno ctx) i (Expr.gno t)) let mk_shl ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - expr_of_ptr ctx (Z3native.mk_bvshl (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) + expr_of_ptr ctx (Z3native.mk_bvshl (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_lshr ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = expr_of_ptr ctx (Z3native.mk_bvlshr (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_ashr ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = @@ -1869,15 +1867,15 @@ struct let mk_ext_rotate_left ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = expr_of_ptr ctx (Z3native.mk_ext_rotate_left (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_ext_rotate_right ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - expr_of_ptr ctx (Z3native.mk_ext_rotate_right (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) + expr_of_ptr ctx (Z3native.mk_ext_rotate_right (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_bv2int ( ctx : context ) ( t : expr ) ( signed : bool ) = expr_of_ptr ctx (Z3native.mk_bv2int (context_gno ctx) (Expr.gno t) signed) let mk_add_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) = (expr_of_ptr ctx (Z3native.mk_bvadd_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed)) let mk_add_no_underflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - (expr_of_ptr ctx (Z3native.mk_bvadd_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) + (expr_of_ptr ctx (Z3native.mk_bvadd_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_sub_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - (expr_of_ptr ctx (Z3native.mk_bvsub_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) + (expr_of_ptr ctx (Z3native.mk_bvsub_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_sub_no_underflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) = (expr_of_ptr ctx (Z3native.mk_bvsub_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed)) let mk_sdiv_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = @@ -1887,7 +1885,7 @@ struct let mk_mul_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) = (expr_of_ptr ctx (Z3native.mk_bvmul_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed)) let mk_mul_no_underflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - (expr_of_ptr ctx (Z3native.mk_bvmul_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) + (expr_of_ptr ctx (Z3native.mk_bvmul_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_numeral ( ctx : context ) ( v : string ) ( size : int ) = expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx size))) end @@ -1897,66 +1895,66 @@ module FloatingPoint = struct module RoundingMode = struct - let mk_sort ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_rounding_mode_sort (context_gno ctx))) - let is_fprm ( x : expr ) = - (Sort.get_sort_kind (Expr.get_sort(x))) == ROUNDING_MODE_SORT - let mk_round_nearest_ties_to_even ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_even (context_gno ctx))) - let mk_rne ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_rne (context_gno ctx))) - let mk_round_nearest_ties_to_away ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_away (context_gno ctx))) - let mk_rna ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_rna (context_gno ctx))) - let mk_round_toward_positive ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_positive (context_gno ctx))) - let mk_rtp ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_rtp (context_gno ctx))) - let mk_round_toward_negative ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_negative (context_gno ctx))) - let mk_rtn ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_rtn (context_gno ctx))) - let mk_round_toward_zero ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_zero (context_gno ctx))) - let mk_rtz ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_rtz (context_gno ctx))) + let mk_sort ( ctx : context ) = + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_rounding_mode_sort (context_gno ctx))) + let is_fprm ( x : expr ) = + (Sort.get_sort_kind (Expr.get_sort(x))) == ROUNDING_MODE_SORT + let mk_round_nearest_ties_to_even ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_even (context_gno ctx))) + let mk_rne ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_rne (context_gno ctx))) + let mk_round_nearest_ties_to_away ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_away (context_gno ctx))) + let mk_rna ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_rna (context_gno ctx))) + let mk_round_toward_positive ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_positive (context_gno ctx))) + let mk_rtp ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_rtp (context_gno ctx))) + let mk_round_toward_negative ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_negative (context_gno ctx))) + let mk_rtn ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_rtn (context_gno ctx))) + let mk_round_toward_zero ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_zero (context_gno ctx))) + let mk_rtz ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_rtz (context_gno ctx))) end - + let mk_sort ( ctx : context ) ( ebits : int ) ( sbits : int ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort (context_gno ctx) ebits sbits)) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort (context_gno ctx) ebits sbits)) let mk_sort_half ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_half (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_half (context_gno ctx))) let mk_sort_16 ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_16 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_16 (context_gno ctx))) let mk_sort_single ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_single (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_single (context_gno ctx))) let mk_sort_32 ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_32 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_32 (context_gno ctx))) let mk_sort_double ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_double (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_double (context_gno ctx))) let mk_sort_64 ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_64 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_64 (context_gno ctx))) let mk_sort_quadruple ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_quadruple (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_quadruple (context_gno ctx))) let mk_sort_128 ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_128 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_128 (context_gno ctx))) let mk_nan ( ctx : context ) ( s : Sort.sort ) = - (expr_of_ptr ctx (Z3native.mk_fpa_nan (context_gno ctx) (Sort.gno s))) + (expr_of_ptr ctx (Z3native.mk_fpa_nan (context_gno ctx) (Sort.gno s))) let mk_inf ( ctx : context ) ( s : Sort.sort ) ( negative : bool ) = - (expr_of_ptr ctx (Z3native.mk_fpa_inf (context_gno ctx) (Sort.gno s) negative)) + (expr_of_ptr ctx (Z3native.mk_fpa_inf (context_gno ctx) (Sort.gno s) negative)) let mk_zero ( ctx : context ) ( s : Sort.sort ) ( negative : bool ) = - (expr_of_ptr ctx (Z3native.mk_fpa_zero (context_gno ctx) (Sort.gno s) negative)) + (expr_of_ptr ctx (Z3native.mk_fpa_zero (context_gno ctx) (Sort.gno s) negative)) let mk_fp ( ctx : context ) ( sign : expr ) ( exponent : expr ) ( significand : expr ) = - (expr_of_ptr ctx (Z3native.mk_fpa_fp (context_gno ctx) (Expr.gno sign) (Expr.gno exponent) (Expr.gno significand))) + (expr_of_ptr ctx (Z3native.mk_fpa_fp (context_gno ctx) (Expr.gno sign) (Expr.gno exponent) (Expr.gno significand))) let mk_numeral_f ( ctx : context ) ( value : float ) ( s : Sort.sort ) = - (expr_of_ptr ctx (Z3native.mk_fpa_numeral_double (context_gno ctx) value (Sort.gno s))) + (expr_of_ptr ctx (Z3native.mk_fpa_numeral_double (context_gno ctx) value (Sort.gno s))) let mk_numeral_i ( ctx : context ) ( value : int ) ( s : Sort.sort ) = - (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int (context_gno ctx) value (Sort.gno s))) + (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int (context_gno ctx) value (Sort.gno s))) let mk_numeral_i_u ( ctx : context ) ( sign : bool ) ( exponent : int ) ( significand : int ) ( s : Sort.sort ) = - (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int64_uint64 (context_gno ctx) sign exponent significand (Sort.gno s))) + (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int64_uint64 (context_gno ctx) sign exponent significand (Sort.gno s))) let mk_numeral_s ( ctx : context ) ( v : string ) ( s : Sort.sort ) = (expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno s))) @@ -1991,7 +1989,7 @@ struct let is_to_sbv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_SBV) let is_to_real ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_REAL) let is_to_ieee_bv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_IEEE_BV) - + let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( s : Sort.sort ) = Expr.mk_const ctx name s @@ -2064,24 +2062,24 @@ struct expr_of_ptr ctx (Z3native.mk_fpa_to_real (context_gno ctx) (Expr.gno t)) let get_ebits ( ctx : context ) ( s : Sort.sort ) = - (Z3native.fpa_get_ebits (context_gno ctx) (Sort.gno s)) + (Z3native.fpa_get_ebits (context_gno ctx) (Sort.gno s)) let get_sbits ( ctx : context ) ( s : Sort.sort ) = - (Z3native.fpa_get_sbits (context_gno ctx) (Sort.gno s)) + (Z3native.fpa_get_sbits (context_gno ctx) (Sort.gno s)) let get_numeral_sign ( ctx : context ) ( t : expr ) = - (Z3native.fpa_get_numeral_sign (context_gno ctx) (Expr.gno t)) + (Z3native.fpa_get_numeral_sign (context_gno ctx) (Expr.gno t)) let get_numeral_significand_string ( ctx : context ) ( t : expr ) = - (Z3native.fpa_get_numeral_significand_string (context_gno ctx) (Expr.gno t)) + (Z3native.fpa_get_numeral_significand_string (context_gno ctx) (Expr.gno t)) let get_numeral_significand_uint ( ctx : context ) ( t : expr ) = - (Z3native.fpa_get_numeral_significand_uint64 (context_gno ctx) (Expr.gno t)) + (Z3native.fpa_get_numeral_significand_uint64 (context_gno ctx) (Expr.gno t)) let get_numeral_exponent_string ( ctx : context ) ( t : expr ) = - (Z3native.fpa_get_numeral_exponent_string (context_gno ctx) (Expr.gno t)) + (Z3native.fpa_get_numeral_exponent_string (context_gno ctx) (Expr.gno t)) let get_numeral_exponent_int ( ctx : context ) ( t : expr ) = - (Z3native.fpa_get_numeral_exponent_int64 (context_gno ctx) (Expr.gno t)) + (Z3native.fpa_get_numeral_exponent_int64 (context_gno ctx) (Expr.gno t)) let mk_to_ieee_bv ( ctx : context ) ( t : expr ) = - (expr_of_ptr ctx (Z3native.mk_fpa_to_ieee_bv (context_gno ctx) (Expr.gno t))) + (expr_of_ptr ctx (Z3native.mk_fpa_to_ieee_bv (context_gno ctx) (Expr.gno t))) let mk_to_fp_int_real ( ctx : context ) ( rm : expr ) ( exponent : expr ) ( significand : expr ) ( s : Sort.sort ) = - (expr_of_ptr ctx (Z3native.mk_fpa_to_fp_int_real (context_gno ctx) (Expr.gno rm) (Expr.gno exponent) (Expr.gno significand) (Sort.gno s))) + (expr_of_ptr ctx (Z3native.mk_fpa_to_fp_int_real (context_gno ctx) (Expr.gno rm) (Expr.gno exponent) (Expr.gno significand) (Sort.gno s))) let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) end @@ -2137,9 +2135,9 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : goal = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.goal_inc_ref ; - dec_ref = Z3native.goal_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.goal_inc_ref ; + dec_ref = Z3native.goal_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2176,7 +2174,7 @@ struct let get_formulas ( x : goal ) = let n = get_size x in let f i = ((expr_of_ptr (z3obj_gc x) - (Z3native.goal_formula (z3obj_gnc x) (z3obj_gno x) i))) in + (Z3native.goal_formula (z3obj_gnc x) (z3obj_gno x) i))) in mk_list f n let get_num_exprs ( x : goal ) = Z3native.goal_num_exprs (z3obj_gnc x) (z3obj_gno x) @@ -2200,9 +2198,9 @@ struct Z3native.apply_result_inc_ref (z3obj_gnc x) arn ; let sg = Z3native.apply_result_get_num_subgoals (z3obj_gnc x) arn in let res = if sg == 0 then - raise (Z3native.Exception "No subgoals") + raise (Z3native.Exception "No subgoals") else - Z3native.apply_result_get_subgoal (z3obj_gnc x) arn 0 in + Z3native.apply_result_get_subgoal (z3obj_gnc x) arn 0 in Z3native.apply_result_dec_ref (z3obj_gnc x) arn ; Z3native.tactic_dec_ref (z3obj_gnc x) tn ; create (z3obj_gc x) res @@ -2213,13 +2211,13 @@ struct let to_string ( x : goal ) = Z3native.goal_to_string (z3obj_gnc x) (z3obj_gno x) let as_expr ( x : goal ) = - let n = get_size x in - if n = 0 then - (Boolean.mk_true (z3obj_gc x)) - else if n = 1 then - (List.hd (get_formulas x)) - else - (Boolean.mk_and (z3obj_gc x) (get_formulas x)) + let n = get_size x in + if n = 0 then + (Boolean.mk_true (z3obj_gc x)) + else if n = 1 then + (List.hd (get_formulas x)) + else + (Boolean.mk_and (z3obj_gc x) (get_formulas x)) end @@ -2229,9 +2227,9 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : model = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.model_inc_ref ; - dec_ref = Z3native.model_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.model_inc_ref ; + dec_ref = Z3native.model_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2242,40 +2240,40 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : func_interp = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.func_interp_inc_ref ; - dec_ref = Z3native.func_interp_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.func_interp_inc_ref ; + dec_ref = Z3native.func_interp_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res - + module FuncEntry = - struct + struct type func_entry = z3_native_object - + let create ( ctx : context ) ( no : Z3native.ptr ) = - let res : func_entry = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.func_entry_inc_ref ; - dec_ref = Z3native.func_entry_dec_ref } in - (z3obj_sno res ctx no) ; - (z3obj_create res) ; - res - + let res : func_entry = { m_ctx = ctx ; + m_n_obj = null ; + inc_ref = Z3native.func_entry_inc_ref ; + dec_ref = Z3native.func_entry_dec_ref } in + (z3obj_sno res ctx no) ; + (z3obj_create res) ; + res + let get_value ( x : func_entry ) = - expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_value (z3obj_gnc x) (z3obj_gno x)) + expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_value (z3obj_gnc x) (z3obj_gno x)) let get_num_args ( x : func_entry ) = Z3native.func_entry_get_num_args (z3obj_gnc x) (z3obj_gno x) - + let get_args ( x : func_entry ) = - let n = (get_num_args x) in - let f i = (expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_arg (z3obj_gnc x) (z3obj_gno x) i)) in - mk_list f n - + let n = (get_num_args x) in + let f i = (expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_arg (z3obj_gnc x) (z3obj_gno x) i)) in + mk_list f n + let to_string ( x : func_entry ) = - let a = (get_args x) in - let f c p = (p ^ (Expr.to_string c) ^ ", ") in - "[" ^ List.fold_right f a ((Expr.to_string (get_value x)) ^ "]") + let a = (get_args x) in + let f c p = (p ^ (Expr.to_string c) ^ ", ") in + "[" ^ List.fold_right f a ((Expr.to_string (get_value x)) ^ "]") end let get_num_entries ( x: func_interp ) = Z3native.func_interp_get_num_entries (z3obj_gnc x) (z3obj_gno x) @@ -2291,14 +2289,14 @@ struct let to_string ( x : func_interp ) = let f c p = ( - let n = (FuncEntry.get_num_args c) in - p ^ - let g c p = (p ^ (Expr.to_string c) ^ ", ") in - (if n > 1 then "[" else "") ^ - (List.fold_right - g - (FuncEntry.get_args c) - ((if n > 1 then "]" else "") ^ " -> " ^ (Expr.to_string (FuncEntry.get_value c)) ^ ", ")) + let n = (FuncEntry.get_num_args c) in + p ^ + let g c p = (p ^ (Expr.to_string c) ^ ", ") in + (if n > 1 then "[" else "") ^ + (List.fold_right + g + (FuncEntry.get_args c) + ((if n > 1 then "]" else "") ^ " -> " ^ (Expr.to_string (FuncEntry.get_value c)) ^ ", ")) ) in List.fold_right f (get_entries x) ("else -> " ^ (Expr.to_string (get_else x)) ^ "]") end @@ -2310,9 +2308,9 @@ struct else let np = Z3native.model_get_const_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f) in if (Z3native.is_null np) then - None + None else - Some (expr_of_ptr (z3obj_gc x) np) + Some (expr_of_ptr (z3obj_gc x) np) let get_const_interp_e ( x : model ) ( a : expr ) = get_const_interp x (Expr.get_func_decl a) @@ -2322,20 +2320,20 @@ struct if (FuncDecl.get_arity f) == 0 then let n = Z3native.model_get_const_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f) in if (Z3native.is_null n) then - None + None else - match sk with - | ARRAY_SORT -> - if not (Z3native.is_as_array (z3obj_gnc x) n) then - raise (Z3native.Exception "Argument was not an array constant") - else - let fd = Z3native.get_as_array_func_decl (z3obj_gnc x) n in + match sk with + | ARRAY_SORT -> + if not (Z3native.is_as_array (z3obj_gnc x) n) then + raise (Z3native.Exception "Argument was not an array constant") + else + let fd = Z3native.get_as_array_func_decl (z3obj_gnc x) n in get_func_interp x (func_decl_of_ptr (z3obj_gc x) fd) - | _ -> raise (Z3native.Exception "Constant functions do not have a function interpretation; use ConstInterp"); + | _ -> raise (Z3native.Exception "Constant functions do not have a function interpretation; use ConstInterp"); else let n = (Z3native.model_get_func_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f)) in if (Z3native.is_null n) then None else Some (FuncInterp.create (z3obj_gc x) n) - + (** The number of constants that have an interpretation in the model. *) let get_num_consts ( x : model ) = Z3native.model_get_num_consts (z3obj_gnc x) (z3obj_gno x) @@ -2389,9 +2387,9 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : probe = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.probe_inc_ref ; - dec_ref = Z3native.probe_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.probe_inc_ref ; + dec_ref = Z3native.probe_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2449,9 +2447,9 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : tactic = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.tactic_inc_ref ; - dec_ref = Z3native.tactic_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.tactic_inc_ref ; + dec_ref = Z3native.tactic_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2459,30 +2457,30 @@ struct module ApplyResult = struct type apply_result = z3_native_object - + let create ( ctx : context ) ( no : Z3native.ptr ) = let res : apply_result = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.apply_result_inc_ref ; - dec_ref = Z3native.apply_result_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.apply_result_inc_ref ; + dec_ref = Z3native.apply_result_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res - + let get_num_subgoals ( x : apply_result ) = Z3native.apply_result_get_num_subgoals (z3obj_gnc x) (z3obj_gno x) - + let get_subgoals ( x : apply_result ) = let n = (get_num_subgoals x) in let f i = Goal.create (z3obj_gc x) (Z3native.apply_result_get_subgoal (z3obj_gnc x) (z3obj_gno x) i) in mk_list f n - + let get_subgoal ( x : apply_result ) ( i : int ) = Goal.create (z3obj_gc x) (Z3native.apply_result_get_subgoal (z3obj_gnc x) (z3obj_gno x) i) - + let convert_model ( x : apply_result ) ( i : int ) ( m : Model.model ) = Model.create (z3obj_gc x) (Z3native.apply_result_convert_model (z3obj_gnc x) (z3obj_gno x) i (z3obj_gno m)) - + let to_string ( x : apply_result ) = Z3native.apply_result_to_string (z3obj_gnc x) (z3obj_gno x) end @@ -2515,10 +2513,10 @@ struct | Some(x) -> (Some (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno c) x))) in match (List.fold_left f None ts) with | None -> - create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2)) + create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2)) | Some(x) -> - let o = (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t2) x) in - create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) o) + let o = (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t2) x) in + create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) o) let or_else ( ctx : context ) ( t1 : tactic ) ( t2 : tactic ) = create ctx (Z3native.tactic_or_else (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2)) @@ -2566,14 +2564,14 @@ end module Statistics = -struct +struct type statistics = z3_native_object let create ( ctx : context ) ( no : Z3native.ptr ) = let res : statistics = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.stats_inc_ref ; - dec_ref = Z3native.stats_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.stats_inc_ref ; + dec_ref = Z3native.stats_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2582,44 +2580,44 @@ struct module Entry = struct type statistics_entry = { - mutable m_key : string; - mutable m_is_int : bool ; - mutable m_is_float : bool ; - mutable m_int : int ; - mutable m_float : float } - + mutable m_key : string; + mutable m_is_int : bool ; + mutable m_is_float : bool ; + mutable m_int : int ; + mutable m_float : float } + let create_si k v = - let res : statistics_entry = { - m_key = k ; - m_is_int = true ; - m_is_float = false ; - m_int = v ; - m_float = 0.0 - } in - res + let res : statistics_entry = { + m_key = k ; + m_is_int = true ; + m_is_float = false ; + m_int = v ; + m_float = 0.0 + } in + res let create_sd k v = - let res : statistics_entry = { - m_key = k ; - m_is_int = false ; - m_is_float = true ; - m_int = 0 ; - m_float = v - } in - res - + let res : statistics_entry = { + m_key = k ; + m_is_int = false ; + m_is_float = true ; + m_int = 0 ; + m_float = v + } in + res + let get_key (x : statistics_entry) = x.m_key - let get_int (x : statistics_entry) = x.m_int + let get_int (x : statistics_entry) = x.m_int let get_float (x : statistics_entry) = x.m_float let is_int (x : statistics_entry) = x.m_is_int let is_float (x : statistics_entry) = x.m_is_float let to_string_value (x : statistics_entry) = - if (is_int x) then - string_of_int (get_int x) - else if (is_float x) then - string_of_float (get_float x) - else + if (is_int x) then + string_of_int (get_int x) + else if (is_float x) then + string_of_float (get_float x) + else raise (Z3native.Exception "Unknown statistical entry type") let to_string ( x : statistics_entry ) = (get_key x) ^ ": " ^ (to_string_value x) end @@ -2631,11 +2629,11 @@ struct let get_entries ( x : statistics ) = let n = (get_size x ) in let f i = ( - let k = Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i in - if (Z3native.stats_is_uint (z3obj_gnc x) (z3obj_gno x) i) then - (Entry.create_si k (Z3native.stats_get_uint_value (z3obj_gnc x) (z3obj_gno x) i)) - else - (Entry.create_sd k (Z3native.stats_get_double_value (z3obj_gnc x) (z3obj_gno x) i)) + let k = Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i in + if (Z3native.stats_is_uint (z3obj_gnc x) (z3obj_gno x) i) then + (Entry.create_si k (Z3native.stats_get_uint_value (z3obj_gnc x) (z3obj_gno x) i)) + else + (Entry.create_sd k (Z3native.stats_get_double_value (z3obj_gnc x) (z3obj_gno x) i)) ) in mk_list f n @@ -2643,7 +2641,7 @@ struct let n = (get_size x) in let f i = (Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i) in mk_list f n - + let get ( x : statistics ) ( key : string ) = let f p c = (if ((Entry.get_key c) == key) then (Some c) else p) in List.fold_left f None (get_entries x) @@ -2657,9 +2655,9 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : solver = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.solver_inc_ref ; - dec_ref = Z3native.solver_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.solver_inc_ref ; + dec_ref = Z3native.solver_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2695,7 +2693,7 @@ struct else let f a b = (Z3native.solver_assert_and_track (z3obj_gnc x) (z3obj_gno x) (Expr.gno a) (Expr.gno b)) in ignore (List.iter2 f cs ps) - + let assert_and_track ( x : solver ) ( c : expr ) ( p : expr ) = Z3native.solver_assert_and_track (z3obj_gnc x) (z3obj_gno x) (Expr.gno c) (Expr.gno p) @@ -2710,30 +2708,30 @@ struct let check ( x : solver ) ( assumptions : expr list ) = let r = if ((List.length assumptions) == 0) then - lbool_of_int (Z3native.solver_check (z3obj_gnc x) (z3obj_gno x)) + lbool_of_int (Z3native.solver_check (z3obj_gnc x) (z3obj_gno x)) else - let f x = (Expr.gno x) in - lbool_of_int (Z3native.solver_check_assumptions (z3obj_gnc x) (z3obj_gno x) (List.length assumptions) (Array.of_list (List.map f assumptions))) + let f x = (Expr.gno x) in + lbool_of_int (Z3native.solver_check_assumptions (z3obj_gnc x) (z3obj_gno x) (List.length assumptions) (Array.of_list (List.map f assumptions))) in match r with | L_TRUE -> SATISFIABLE | L_FALSE -> UNSATISFIABLE | _ -> UNKNOWN - + let get_model ( x : solver ) = let q = Z3native.solver_get_model (z3obj_gnc x) (z3obj_gno x) in if (Z3native.is_null q) then None else Some (Model.create (z3obj_gc x) q) - + let get_proof ( x : solver ) = let q = Z3native.solver_get_proof (z3obj_gnc x) (z3obj_gno x) in if (Z3native.is_null q) then None else Some (expr_of_ptr (z3obj_gc x) q) - + let get_unsat_core ( x : solver ) = let av = AST.ASTVector.create (z3obj_gc x) (Z3native.solver_get_unsat_core (z3obj_gnc x) (z3obj_gno x)) in (AST.ASTVector.to_expr_list av) @@ -2758,7 +2756,7 @@ struct create ctx (Z3native.mk_solver_from_tactic (context_gno ctx) (z3obj_gno t)) let translate ( x : solver ) ( to_ctx : context ) = - create to_ctx (Z3native.solver_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx)) + create to_ctx (Z3native.solver_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx)) let to_string ( x : solver ) = Z3native.solver_to_string (z3obj_gnc x) (z3obj_gno x) end @@ -2770,9 +2768,9 @@ struct let create ( ctx : context ) = let res : fixedpoint = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.fixedpoint_inc_ref ; - dec_ref = Z3native.fixedpoint_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.fixedpoint_inc_ref ; + dec_ref = Z3native.fixedpoint_dec_ref } in (z3obj_sno res ctx (Z3native.mk_fixedpoint (context_gno ctx))) ; (z3obj_create res) ; res @@ -2815,7 +2813,7 @@ struct | L_TRUE -> Solver.SATISFIABLE | L_FALSE -> Solver.UNSATISFIABLE | _ -> Solver.UNKNOWN - + let push ( x : fixedpoint ) = Z3native.fixedpoint_push (z3obj_gnc x) (z3obj_gno x) @@ -2844,7 +2842,7 @@ struct None else Some (expr_of_ptr (z3obj_gc x) q) - + let add_cover ( x : fixedpoint ) ( level : int ) ( predicate : func_decl ) ( property : expr ) = Z3native.fixedpoint_add_cover (z3obj_gnc x) (z3obj_gno x) level (FuncDecl.gno predicate) (Expr.gno property) @@ -2980,13 +2978,13 @@ struct raise (Z3native.Exception "Argument size mismatch") else Z3native.parse_smtlib_string (context_gno ctx) str - cs - (Symbol.symbol_lton sort_names) - (Sort.sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) - + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) + let parse_smtlib_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = let csn = (List.length sort_names) in let cs = (List.length sorts) in @@ -2996,12 +2994,12 @@ struct raise (Z3native.Exception "Argument size mismatch") else Z3native.parse_smtlib_file (context_gno ctx) file_name - cs - (Symbol.symbol_lton sort_names) - (Sort.sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) let get_num_smtlib_formulas ( ctx : context ) = Z3native.get_smtlib_num_formulas (context_gno ctx) @@ -3040,13 +3038,13 @@ struct raise (Z3native.Exception "Argument size mismatch") else (expr_of_ptr ctx (Z3native.parse_smtlib2_string (context_gno ctx) str - cs - (Symbol.symbol_lton sort_names) - (Sort.sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) - + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) + let parse_smtlib2_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = let csn = (List.length sort_names) in let cs = (List.length sorts) in @@ -3056,12 +3054,12 @@ struct raise (Z3native.Exception "Argument size mismatch") else (expr_of_ptr ctx (Z3native.parse_smtlib2_string (context_gno ctx) file_name - cs - (Symbol.symbol_lton sort_names) - (Sort.sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) end module Interpolation = @@ -3102,21 +3100,21 @@ struct match r with | 0 -> raise (Z3native.Exception "Interpolation problem could not be read.") | _ -> - let f1 i = (expr_of_ptr ctx (Array.get cnsts i)) in - let f2 i = (Array.get parents i) in - let f3 i = (expr_of_ptr ctx (Array.get theory i)) in - ((mk_list f1 num), - (mk_list f2 num), - (mk_list f3 num_theory)) + let f1 i = (expr_of_ptr ctx (Array.get cnsts i)) in + let f2 i = (Array.get parents i) in + let f3 i = (expr_of_ptr ctx (Array.get theory i)) in + ((mk_list f1 num), + (mk_list f2 num), + (mk_list f3 num_theory)) let check_interpolant ( ctx : context ) ( num : int ) ( cnsts : Expr.expr list ) ( parents : int list ) ( interps : Expr.expr list ) ( num_theory : int ) ( theory : Expr.expr list ) = let (r, str) = (Z3native.check_interpolant (context_gno ctx) - num - (let f x = Expr.gno x in (Array.of_list (List.map f cnsts))) - (Array.of_list parents) - (let f x = Expr.gno x in (Array.of_list (List.map f interps))) - num_theory - (let f x = Expr.gno x in (Array.of_list (List.map f theory)))) in + num + (let f x = Expr.gno x in (Array.of_list (List.map f cnsts))) + (Array.of_list parents) + (let f x = Expr.gno x in (Array.of_list (List.map f interps))) + num_theory + (let f x = Expr.gno x in (Array.of_list (List.map f theory)))) in match (lbool_of_int r) with | L_UNDEF -> raise (Z3native.Exception "Interpolant could not be verified.") | L_FALSE -> raise (Z3native.Exception "Interpolant could not be verified.") diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp index 927521b65..8ce81ec31 100644 --- a/src/api/z3_replayer.cpp +++ b/src/api/z3_replayer.cpp @@ -46,6 +46,7 @@ struct z3_replayer::imp { size_t m_ptr; size_t_map m_heap; svector m_cmds; + vector m_cmds_names; enum value_kind { INT64, UINT64, DOUBLE, STRING, SYMBOL, OBJECT, UINT_ARRAY, INT_ARRAY, SYMBOL_ARRAY, OBJECT_ARRAY, FLOAT }; @@ -509,6 +510,7 @@ struct z3_replayer::imp { if (idx >= m_cmds.size()) throw z3_replayer_exception("invalid command"); try { + TRACE("z3_replayer_cmd", tout << m_cmds_names[idx] << "\n";); m_cmds[idx](m_owner); } catch (z3_error & ex) { @@ -672,9 +674,11 @@ struct z3_replayer::imp { m_result = obj; } - void register_cmd(unsigned id, z3_replayer_cmd cmd) { + void register_cmd(unsigned id, z3_replayer_cmd cmd, char const* name) { m_cmds.reserve(id+1, 0); + m_cmds_names.reserve(id+1, ""); m_cmds[id] = cmd; + m_cmds_names[id] = name; } void reset() { @@ -786,8 +790,8 @@ void z3_replayer::store_result(void * obj) { return m_imp->store_result(obj); } -void z3_replayer::register_cmd(unsigned id, z3_replayer_cmd cmd) { - return m_imp->register_cmd(id, cmd); +void z3_replayer::register_cmd(unsigned id, z3_replayer_cmd cmd, char const* name) { + return m_imp->register_cmd(id, cmd, name); } void z3_replayer::parse() { diff --git a/src/api/z3_replayer.h b/src/api/z3_replayer.h index 6c566d553..88654363d 100644 --- a/src/api/z3_replayer.h +++ b/src/api/z3_replayer.h @@ -62,7 +62,7 @@ public: void ** get_obj_addr(unsigned pos); void store_result(void * obj); - void register_cmd(unsigned id, z3_replayer_cmd cmd); + void register_cmd(unsigned id, z3_replayer_cmd cmd, char const* name); }; #endif diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 2ee6c7556..ab1a5a5af 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1656,6 +1656,7 @@ ast * ast_manager::register_node_core(ast * n) { n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk(); + TRACE("ast", tout << "Object " << n->m_id << " was created.\n";); TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";); // increment reference counters diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index b43577960..8ce40e49a 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -20,9 +20,11 @@ Revision History: #include "expr_safe_replace.h" #include "rewriter.h" +#include "ast_pp.h" void expr_safe_replace::insert(expr* src, expr* dst) { + SASSERT(m.get_sort(src) == m.get_sort(dst)); m_src.push_back(src); m_dst.push_back(dst); m_subst.insert(src, dst); @@ -30,7 +32,7 @@ void expr_safe_replace::insert(expr* src, expr* dst) { void expr_safe_replace::operator()(expr* e, expr_ref& res) { m_todo.push_back(e); - expr* a, *b, *d; + expr* a, *b; while (!m_todo.empty()) { a = m_todo.back(); @@ -39,7 +41,7 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { } else if (m_subst.find(a, b)) { m_cache.insert(a, b); - m_todo.pop_back(); + m_todo.pop_back(); } else if (is_var(a)) { m_cache.insert(a, a); @@ -51,18 +53,21 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { m_args.reset(); bool arg_differs = false; for (unsigned i = 0; i < n; ++i) { - if (m_cache.find(c->get_arg(i), d)) { + expr* d = 0, *arg = c->get_arg(i); + if (m_cache.find(arg, d)) { m_args.push_back(d); - arg_differs |= c->get_arg(i) != d; + arg_differs |= arg != d; + SASSERT(m.get_sort(arg) == m.get_sort(d)); } else { - m_todo.push_back(c->get_arg(i)); + m_todo.push_back(arg); } } if (m_args.size() == n) { if (arg_differs) { b = m.mk_app(c->get_decl(), m_args.size(), m_args.c_ptr()); m_refs.push_back(b); + SASSERT(m.get_sort(a) == m.get_sort(b)); } else { b = a; } @@ -71,6 +76,7 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { } } else { + (std::cout << "q\n").flush(); SASSERT(is_quantifier(a)); quantifier* q = to_quantifier(a); expr_safe_replace replace(m); diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 75e27c081..ea5bec231 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -163,6 +163,7 @@ std::ostream& zstring::operator<<(std::ostream& out) const { seq_decl_plugin::seq_decl_plugin(): m_init(false), m_stringc_sym("String"), + m_charc_sym("Char"), m_string(0), m_char(0) {} @@ -369,7 +370,8 @@ void seq_decl_plugin::init() { void seq_decl_plugin::set_manager(ast_manager* m, family_id id) { decl_plugin::set_manager(m, id); - m_char = m->mk_sort(symbol("Char"), sort_info(m_family_id, _CHAR_SORT, 0, (parameter const*)0)); + bv_util bv(*m); + m_char = bv.mk_sort(8); m->inc_ref(m_char); parameter param(m_char); m_string = m->mk_sort(symbol("String"), sort_info(m_family_id, SEQ_SORT, 1, ¶m)); @@ -401,8 +403,6 @@ sort * seq_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter return m.mk_sort(symbol("RegEx"), sort_info(m_family_id, RE_SORT, num_parameters, parameters)); case _STRING_SORT: return m_string; - case _CHAR_SORT: - return m_char; default: UNREACHABLE(); return 0; @@ -470,6 +470,8 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, } return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k, num_parameters, parameters)); + + case OP_STRING_CONST: if (!(num_parameters == 1 && arity == 0 && parameters[0].is_symbol())) { m.raise_exception("invalid string declaration"); @@ -583,7 +585,7 @@ void seq_decl_plugin::get_sort_names(svector & sort_names, symbol app* seq_decl_plugin::mk_string(symbol const& s) { parameter param(s); func_decl* f = m_manager->mk_const_decl(m_stringc_sym, m_string, - func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m)); + func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m)); return m_manager->mk_const(f); } @@ -591,10 +593,11 @@ app* seq_decl_plugin::mk_string(zstring const& s) { symbol sym(s.encode().c_str()); parameter param(sym); func_decl* f = m_manager->mk_const_decl(m_stringc_sym, m_string, - func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m)); + func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m)); return m_manager->mk_const(f); } + bool seq_decl_plugin::is_value(app* e) const { return is_app_of(e, m_family_id, OP_STRING_CONST); } @@ -609,11 +612,21 @@ app* seq_util::mk_skolem(symbol const& name, unsigned n, expr* const* args, sort app* seq_util::str::mk_string(zstring const& s) { return u.seq.mk_string(s); } + app* seq_util::str::mk_char(zstring const& s, unsigned idx) { bv_util bvu(m); return bvu.mk_numeral(s[idx], s.num_bits()); } +bool seq_util::str::is_char(expr* n, zstring& c) const { + if (u.is_char(n)) { + c = zstring(to_app(n)->get_decl()->get_parameter(0).get_symbol().bare_str()); + return true; + } + else { + return false; + } +} bool seq_util::str::is_string(expr const* n, zstring& s) const { if (is_string(n)) { diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 33d4de378..9a5f65d05 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -22,13 +22,13 @@ Revision History: #define SEQ_DECL_PLUGIN_H_ #include "ast.h" +#include "bv_decl_plugin.h" enum seq_sort_kind { SEQ_SORT, RE_SORT, - _STRING_SORT, // internal only - _CHAR_SORT // internal only + _STRING_SORT // internal only }; enum seq_op_kind { @@ -131,6 +131,7 @@ class seq_decl_plugin : public decl_plugin { ptr_vector m_sigs; bool m_init; symbol m_stringc_sym; + symbol m_charc_sym; sort* m_string; sort* m_char; @@ -187,6 +188,7 @@ public: ast_manager& get_manager() const { return m; } + bool is_char(sort* s) const { return seq.is_char(s); } bool is_string(sort* s) const { return is_seq(s) && seq.is_char(s->get_parameter(0).get_ast()); } bool is_seq(sort* s) const { return is_sort_of(s, m_fid, SEQ_SORT); } bool is_re(sort* s) const { return is_sort_of(s, m_fid, RE_SORT); } @@ -195,6 +197,7 @@ public: bool is_seq(sort* s, sort*& seq) { return is_seq(s) && (seq = to_sort(s->get_parameter(0).get_ast()), true); } bool is_re(expr* e) const { return is_re(m.get_sort(e)); } bool is_re(expr* e, sort*& seq) const { return is_re(m.get_sort(e), seq); } + bool is_char(expr* e) const { return is_char(m.get_sort(e)); } app* mk_skolem(symbol const& name, unsigned n, expr* const* args, sort* range); bool is_skolem(expr const* e) const { return is_app_of(e, m_fid, _OP_SEQ_SKOLEM); } @@ -215,6 +218,7 @@ public: app* mk_empty(sort* s) { return m.mk_const(m.mk_func_decl(m_fid, OP_SEQ_EMPTY, 0, 0, 0, (expr*const*)0, s)); } app* mk_string(zstring const& s); app* mk_string(symbol const& s) { return u.seq.mk_string(s); } + app* mk_char(char ch); app* mk_concat(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONCAT, 2, es); } app* mk_concat(expr* a, expr* b, expr* c) { return mk_concat(mk_concat(a, b), c); @@ -238,6 +242,7 @@ public: } bool is_string(expr const* n, zstring& s) const; + bool is_char(expr* n, zstring& s) const; bool is_empty(expr const* n) const { symbol s; return is_app_of(n, m_fid, OP_SEQ_EMPTY) || (is_string(n, s) && !s.is_numerical() && *s.bare_str() == 0); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index db96f3d0c..62e4f4338 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -331,7 +331,7 @@ bool theory_seq::check_length_coherence_tbd() { if (is_var(f) && f == e) { expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); TRACE("seq", tout << "Unsolved " << mk_pp(e, m) << "\n";); -#if 0 +#if 1 if (!assume_equality(e, emp)) { // e = emp \/ e = unit(head.elem(e))*tail(e) sort* char_sort = 0; @@ -341,9 +341,11 @@ bool theory_seq::check_length_coherence_tbd() { expr_ref head(m_util.str.mk_unit(v), m); expr_ref conc(m_util.str.mk_concat(head, tail), m); add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false)); + assume_equality(tail, emp); } #endif - coherent = false; + m_branch_variable_head = j + 1; + return false; } } return coherent; diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h index 04f38020c..5065c733d 100644 --- a/src/smt/theory_seq_empty.h +++ b/src/smt/theory_seq_empty.h @@ -30,6 +30,7 @@ namespace smt { seq_util u; symbol_set m_strings; unsigned m_next; + char m_char; std::string m_unique_prefix; obj_map m_unique_sequences; expr_ref_vector m_trail; @@ -41,6 +42,7 @@ namespace smt { m_model(md), u(m), m_next(0), + m_char(0), m_unique_prefix("#B"), m_trail(m) { @@ -99,6 +101,11 @@ namespace smt { expr* v0 = get_fresh_value(seq); return u.re.mk_to_re(v0); } + if (u.is_char(s)) { + //char s[2] = { ++m_char, 0 }; + //return u.str.mk_char(zstring(s), 0); + return u.str.mk_char(zstring("a"), 0); + } NOT_IMPLEMENTED_YET(); return 0; } diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 06a82b0d5..a22275043 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -239,16 +239,26 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode else { scoped_mpq sig(m_mpq_manager); scoped_mpz exp(m_mpq_manager); + scoped_mpq pow(m_mpq_manager); m_mpq_manager.set(sig, significand); m_mpq_manager.abs(sig); m_mpz_manager.set(exp, exponent); - + m_mpq_manager.set(pow, mpq(2)); + // Normalize - while (m_mpq_manager.ge(sig, 2)) { - m_mpq_manager.div(sig, mpq(2), sig); + unsigned loop = 0; + while (m_mpq_manager.ge(sig, pow)) { + m_mpq_manager.mul(pow, 2, pow); m_mpz_manager.inc(exp); + ++loop; + if (loop % 1000 == 0) std::cout << loop << "\n"; } + std::cout << loop << "\n"; + if (loop > 0) { + m_mpq_manager.div(sig, pow, sig); + } + std::cout << loop << "\n"; while (m_mpq_manager.lt(sig, 1)) { m_mpq_manager.mul(sig, 2, sig); From 995d66c6f2b8f10943e9406eb6035218ce5f7166 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Dec 2015 10:46:33 -0800 Subject: [PATCH 14/87] remove print statements Signed-off-by: Nikolaj Bjorner --- src/api/api_ast_vector.cpp | 1 - src/util/mpf.cpp | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/api/api_ast_vector.cpp b/src/api/api_ast_vector.cpp index d6ff1bbb3..e1d4d78ff 100644 --- a/src/api/api_ast_vector.cpp +++ b/src/api/api_ast_vector.cpp @@ -26,7 +26,6 @@ Revision History: extern "C" { Z3_ast_vector Z3_API Z3_mk_ast_vector(Z3_context c) { - std::cout << "ast-vector\n"; Z3_TRY; LOG_Z3_mk_ast_vector(c); RESET_ERROR_CODE(); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index a22275043..6cf8e3a4d 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -252,13 +252,10 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode m_mpq_manager.mul(pow, 2, pow); m_mpz_manager.inc(exp); ++loop; - if (loop % 1000 == 0) std::cout << loop << "\n"; } - std::cout << loop << "\n"; if (loop > 0) { m_mpq_manager.div(sig, pow, sig); } - std::cout << loop << "\n"; while (m_mpq_manager.lt(sig, 1)) { m_mpq_manager.mul(sig, 2, sig); From 4cf41c44f37214911e7d99fd5463298da8ab677f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Dec 2015 11:09:48 -0800 Subject: [PATCH 15/87] support else values that are null from models Signed-off-by: Nikolaj Bjorner --- src/api/api_model.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 370e639b9..63092b2cf 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -277,7 +277,9 @@ extern "C" { RESET_ERROR_CODE(); CHECK_NON_NULL(f, 0); expr * e = to_func_interp_ref(f)->get_else(); - mk_c(c)->save_ast_trail(e); + if (e) { + mk_c(c)->save_ast_trail(e); + } RETURN_Z3(of_expr(e)); Z3_CATCH_RETURN(0); } From 54e8612f4d8e11f256a64044f2b35af48a0f2bec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Dec 2015 12:26:38 -0800 Subject: [PATCH 16/87] fix bounds elimination bug for nested quantifiers. Codeplex post z3: A formula and its negation are unsatisfiable Signed-off-by: Nikolaj Bjorner --- src/ast/simplifier/elim_bounds.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ast/simplifier/elim_bounds.cpp b/src/ast/simplifier/elim_bounds.cpp index 41ce18549..a4e145e0a 100644 --- a/src/ast/simplifier/elim_bounds.cpp +++ b/src/ast/simplifier/elim_bounds.cpp @@ -110,6 +110,7 @@ void elim_bounds::operator()(quantifier * q, expr_ref & r) { return; } expr * n = q->get_expr(); + unsigned num_vars = q->get_num_decls(); ptr_buffer atoms; if (m_manager.is_or(n)) atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args()); @@ -138,11 +139,11 @@ void elim_bounds::operator()(quantifier * q, expr_ref & r) { var * lower = 0; var * upper = 0; if (is_bound(a, lower, upper)) { - if (lower != 0 && !m_used_vars.contains(lower->get_idx())) { + if (lower != 0 && !m_used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) { ADD_CANDIDATE(lower); m_lowers.insert(lower); } - if (upper != 0 && !m_used_vars.contains(upper->get_idx())) { + if (upper != 0 && !m_used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) { ADD_CANDIDATE(upper); m_uppers.insert(upper); } @@ -176,6 +177,7 @@ void elim_bounds::operator()(quantifier * q, expr_ref & r) { switch (atoms.size()) { case 0: r = m_manager.mk_false(); + TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";); return; case 1: new_body = atoms[0]; From 0f656047c785b30f88353b5fbf06f232e5a2387c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 22 Dec 2015 23:37:07 +0000 Subject: [PATCH 17/87] ML code simplification --- src/api/ml/z3.ml | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 84c70001e..87ed4fb0a 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -537,22 +537,10 @@ end = struct let ast_of_func_decl f = match f with FuncDecl(x) -> x let create_ndr ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort list ) ( range : Sort.sort ) = - let res = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.inc_ref ; - dec_ref = Z3native.dec_ref } in - (z3obj_sno res ctx (Z3native.mk_func_decl (context_gno ctx) (Symbol.gno name) (List.length domain) (Sort.sort_lton domain) (Sort.gno range))) ; - (z3obj_create res) ; - FuncDecl(res) + func_decl_of_ptr ctx (Z3native.mk_func_decl (context_gno ctx) (Symbol.gno name) (List.length domain) (Sort.sort_lton domain) (Sort.gno range)) let create_pdr ( ctx : context) ( prefix : string ) ( domain : Sort.sort list ) ( range : Sort.sort ) = - let res = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.inc_ref ; - dec_ref = Z3native.dec_ref } in - (z3obj_sno res ctx (Z3native.mk_fresh_func_decl (context_gno ctx) prefix (List.length domain) (Sort.sort_lton domain) (Sort.gno range))) ; - (z3obj_create res) ; - FuncDecl(res) + func_decl_of_ptr ctx (Z3native.mk_fresh_func_decl (context_gno ctx) prefix (List.length domain) (Sort.sort_lton domain) (Sort.gno range)) let gc ( x : func_decl ) = match x with FuncDecl(a) -> (z3obj_gc a) let gnc ( x : func_decl ) = match x with FuncDecl(a) -> (z3obj_gnc a) From ced4a430d11300d98d1323c100c8dbd39f940554 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 22 Dec 2015 23:40:27 +0000 Subject: [PATCH 18/87] ML code simplification --- src/api/ml/z3.ml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 87ed4fb0a..7bfee8686 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -467,13 +467,8 @@ end = struct let to_string ( x : sort ) = Z3native.sort_to_string (gnc x) (gno x) let mk_uninterpreted ( ctx : context ) ( s : Symbol.symbol ) = - let res = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.inc_ref ; - dec_ref = Z3native.dec_ref } in - (z3obj_sno res ctx (Z3native.mk_uninterpreted_sort (context_gno ctx) (Symbol.gno s))) ; - (z3obj_create res) ; - Sort(res) + let n = (Z3native.mk_uninterpreted_sort (context_gno ctx) (Symbol.gno s)) in + Sort(z3_native_object_of_ast_ptr ctx n) let mk_uninterpreted_s ( ctx : context ) ( s : string ) = mk_uninterpreted ctx (Symbol.mk_string ( ctx : context ) s) From 5262e1986cf99e26874a1f82d3a00aeb334ecc34 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Dec 2015 16:58:26 -0800 Subject: [PATCH 19/87] removing tabs Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 912 +++++++++++++++++++++++------------------------ 1 file changed, 455 insertions(+), 457 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 84c70001e..8fdc795fb 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -60,7 +60,7 @@ struct o.inc_ref (context_gno ctx) no ; ( if not (is_null o.m_n_obj) then - o.dec_ref (context_gno ctx) o.m_n_obj ; + o.dec_ref (context_gno ctx) o.m_n_obj ; (context_sub1 ctx) ) ; o.m_n_obj <- no @@ -68,8 +68,8 @@ struct let z3obj_dispose o = if not (is_null o.m_n_obj) then ( - o.dec_ref (z3obj_gnc o) o.m_n_obj ; - (context_sub1 (z3obj_gc o)) + o.dec_ref (z3obj_gnc o) o.m_n_obj ; + (context_sub1 (z3obj_gc o)) ) ; o.m_n_obj <- null @@ -81,12 +81,12 @@ struct let z3_native_object_of_ast_ptr : context -> Z3native.ptr -> z3_native_object = fun ctx no -> let res : z3_native_object = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.inc_ref ; - dec_ref = Z3native.dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.inc_ref ; + dec_ref = Z3native.dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; - res + res end open Internal @@ -137,18 +137,18 @@ struct let create_i ( ctx : context ) ( no : Z3native.ptr ) = let res : symbol = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = z3obj_nil_ref ; - dec_ref = z3obj_nil_ref } in + m_n_obj = null ; + inc_ref = z3obj_nil_ref ; + dec_ref = z3obj_nil_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res let create_s ( ctx : context ) ( no : Z3native.ptr ) = let res : symbol = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = z3obj_nil_ref ; - dec_ref = z3obj_nil_ref } in + m_n_obj = null ; + inc_ref = z3obj_nil_ref ; + dec_ref = z3obj_nil_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -156,7 +156,7 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = match (symbol_kind_of_int (Z3native.get_symbol_kind (context_gno ctx) no)) with | INT_SYMBOL -> (create_i ctx no) - | STRING_SYMBOL -> (create_s ctx no) + | STRING_SYMBOL -> (create_s ctx no) let gc ( x : symbol ) = (z3obj_gc x) let gnc ( x : symbol ) = (z3obj_gnc x) @@ -264,16 +264,16 @@ end = struct module ASTVector = struct type ast_vector = z3_native_object - + let create ( ctx : context ) ( no : Z3native.ptr ) = let res : ast_vector = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.ast_vector_inc_ref ; - dec_ref = Z3native.ast_vector_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.ast_vector_inc_ref ; + dec_ref = Z3native.ast_vector_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res - + let mk_ast_vector ( ctx : context ) = (create ctx (Z3native.mk_ast_vector (context_gno ctx))) let get_size ( x : ast_vector ) = @@ -287,69 +287,69 @@ end = struct let resize ( x : ast_vector ) ( new_size : int ) = Z3native.ast_vector_resize (z3obj_gnc x) (z3obj_gno x) new_size - + let push ( x : ast_vector ) ( a : ast ) = Z3native.ast_vector_push (z3obj_gnc x) (z3obj_gno x) (z3obj_gno a) - + let translate ( x : ast_vector ) ( to_ctx : context ) = create to_ctx (Z3native.ast_vector_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx)) let to_list ( x : ast_vector ) = - let xs = (get_size x) in + let xs = (get_size x) in let f i = (get x i) in mk_list f xs let to_expr_list ( x : ast_vector ) = - let xs = (get_size x) in + let xs = (get_size x) in let f i = (Expr.expr_of_ptr (z3obj_gc x) (z3obj_gno (get x i))) in mk_list f xs - + let to_string ( x : ast_vector ) = Z3native.ast_vector_to_string (z3obj_gnc x) (z3obj_gno x) end module ASTMap = - struct + struct type ast_map = z3_native_object - + let create ( ctx : context ) ( no : Z3native.ptr ) = let res : ast_map = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.ast_map_inc_ref ; - dec_ref = Z3native.ast_map_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.ast_map_inc_ref ; + dec_ref = Z3native.ast_map_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; - res - + res + let mk_ast_map ( ctx : context ) = (create ctx (Z3native.mk_ast_map (context_gno ctx))) let astmap_of_ptr ( ctx : context ) ( no : Z3native.ptr ) = let res : ast_map = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.ast_map_inc_ref ; - dec_ref = Z3native.ast_map_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.ast_map_inc_ref ; + dec_ref = Z3native.ast_map_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res - + let contains ( x : ast_map ) ( key : ast ) = Z3native.ast_map_contains (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key) - + let find ( x : ast_map ) ( key : ast ) = ast_of_ptr (z3obj_gc x) (Z3native.ast_map_find (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key)) - + let insert ( x : ast_map ) ( key : ast ) ( value : ast ) = Z3native.ast_map_insert (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key) (z3obj_gno value) let erase ( x : ast_map ) ( key : ast ) = Z3native.ast_map_erase (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key) - + let reset ( x : ast_map ) = Z3native.ast_map_reset (z3obj_gnc x) (z3obj_gno x) let get_size ( x : ast_map ) = Z3native.ast_map_size (z3obj_gnc x) (z3obj_gno x) - + let get_keys ( x : ast_map ) = let av = ASTVector.create (z3obj_gc x) (Z3native.ast_map_keys (z3obj_gnc x) (z3obj_gno x)) in (ASTVector.to_list av) @@ -369,7 +369,7 @@ end = struct | QUANTIFIER_AST | VAR_AST -> true | _ -> false - + let is_app ( x : ast ) = (get_ast_kind x) == APP_AST let is_var ( x : ast ) = (get_ast_kind x) == VAR_AST let is_quantifier ( x : ast ) = (get_ast_kind x) == QUANTIFIER_AST @@ -385,12 +385,12 @@ end = struct false else Z3native.is_eq_ast (z3obj_gnc a) (z3obj_gno a) (z3obj_gno b) - + let compare a b = if (get_id a) < (get_id b) then -1 else if (get_id a) > (get_id b) then 1 else - 0 - + 0 + let translate ( x : ast ) ( to_ctx : context ) = if (z3obj_gnc x) == (context_gno to_ctx) then x @@ -456,11 +456,11 @@ end = struct let equal : sort -> sort -> bool = fun a b -> (a == b) || if (gnc a) != (gnc b) then - false + false else - (Z3native.is_eq_sort (gnc a) (gno a) (gno b)) + (Z3native.is_eq_sort (gnc a) (gno a) (gno b)) - + let get_id ( x : sort ) = Z3native.get_sort_id (gnc x) (gno x) let get_sort_kind ( x : sort ) = (sort_kind_of_int (Z3native.get_sort_kind (gnc x) (gno x))) let get_name ( x : sort ) = (Symbol.create (gc x) (Z3native.get_sort_name (gnc x) (gno x))) @@ -468,9 +468,9 @@ end = struct let mk_uninterpreted ( ctx : context ) ( s : Symbol.symbol ) = let res = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.inc_ref ; - dec_ref = Z3native.dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.inc_ref ; + dec_ref = Z3native.dec_ref } in (z3obj_sno res ctx (Z3native.mk_uninterpreted_sort (context_gno ctx) (Symbol.gno s))) ; (z3obj_create res) ; Sort(res) @@ -490,14 +490,14 @@ sig module Parameter : sig type parameter = - P_Int of int + P_Int of int | P_Dbl of float | P_Sym of Symbol.symbol | P_Srt of Sort.sort | P_Ast of AST.ast | P_Fdl of func_decl | P_Rat of string - + val get_kind : parameter -> Z3enums.parameter_kind val get_int : parameter -> int val get_float : parameter -> float @@ -538,18 +538,18 @@ end = struct let create_ndr ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort list ) ( range : Sort.sort ) = let res = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.inc_ref ; - dec_ref = Z3native.dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.inc_ref ; + dec_ref = Z3native.dec_ref } in (z3obj_sno res ctx (Z3native.mk_func_decl (context_gno ctx) (Symbol.gno name) (List.length domain) (Sort.sort_lton domain) (Sort.gno range))) ; (z3obj_create res) ; FuncDecl(res) let create_pdr ( ctx : context) ( prefix : string ) ( domain : Sort.sort list ) ( range : Sort.sort ) = let res = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.inc_ref ; - dec_ref = Z3native.dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.inc_ref ; + dec_ref = Z3native.dec_ref } in (z3obj_sno res ctx (Z3native.mk_fresh_func_decl (context_gno ctx) prefix (List.length domain) (Sort.sort_lton domain) (Sort.gno range))) ; (z3obj_create res) ; FuncDecl(res) @@ -568,51 +568,51 @@ end = struct | P_Ast of AST.ast | P_Fdl of func_decl | P_Rat of string - + let get_kind ( x : parameter ) = (match x with - | P_Int(_) -> PARAMETER_INT - | P_Dbl(_) -> PARAMETER_DOUBLE - | P_Sym(_) -> PARAMETER_SYMBOL - | P_Srt(_) -> PARAMETER_SORT - | P_Ast(_) -> PARAMETER_AST - | P_Fdl(_) -> PARAMETER_FUNC_DECL - | P_Rat(_) -> PARAMETER_RATIONAL) - + | P_Int(_) -> PARAMETER_INT + | P_Dbl(_) -> PARAMETER_DOUBLE + | P_Sym(_) -> PARAMETER_SYMBOL + | P_Srt(_) -> PARAMETER_SORT + | P_Ast(_) -> PARAMETER_AST + | P_Fdl(_) -> PARAMETER_FUNC_DECL + | P_Rat(_) -> PARAMETER_RATIONAL) + let get_int ( x : parameter ) = match x with - | P_Int(x) -> x - | _ -> raise (Z3native.Exception "parameter is not an int") - + | P_Int(x) -> x + | _ -> raise (Z3native.Exception "parameter is not an int") + let get_float ( x : parameter ) = match x with - | P_Dbl(x) -> x - | _ -> raise (Z3native.Exception "parameter is not a float") + | P_Dbl(x) -> x + | _ -> raise (Z3native.Exception "parameter is not a float") let get_symbol ( x : parameter ) = match x with - | P_Sym(x) -> x - | _ -> raise (Z3native.Exception "parameter is not a symbol") - + | P_Sym(x) -> x + | _ -> raise (Z3native.Exception "parameter is not a symbol") + let get_sort ( x : parameter ) = match x with - | P_Srt(x) -> x - | _ -> raise (Z3native.Exception "parameter is not a sort") + | P_Srt(x) -> x + | _ -> raise (Z3native.Exception "parameter is not a sort") let get_ast ( x : parameter ) = match x with - | P_Ast(x) -> x - | _ -> raise (Z3native.Exception "parameter is not an ast") + | P_Ast(x) -> x + | _ -> raise (Z3native.Exception "parameter is not an ast") let get_func_decl ( x : parameter ) = match x with - | P_Fdl(x) -> x - | _ -> raise (Z3native.Exception "parameter is not a func_decl") + | P_Fdl(x) -> x + | _ -> raise (Z3native.Exception "parameter is not a func_decl") let get_rational ( x : parameter ) = match x with - | P_Rat(x) -> x - | _ -> raise (Z3native.Exception "parameter is not a rational string") + | P_Rat(x) -> x + | _ -> raise (Z3native.Exception "parameter is not a rational string") end let mk_func_decl ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort list ) ( range : Sort.sort ) = @@ -710,19 +710,19 @@ end = struct let param_descrs_of_ptr ( ctx : context ) ( no : Z3native.ptr ) = let res : param_descrs = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.param_descrs_inc_ref ; - dec_ref = Z3native.param_descrs_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.param_descrs_inc_ref ; + dec_ref = Z3native.param_descrs_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res - + let validate ( x : param_descrs ) ( p : params ) = Z3native.params_validate (z3obj_gnc x) (z3obj_gno p) (z3obj_gno x) - + let get_kind ( x : param_descrs ) ( name : Symbol.symbol ) = (param_kind_of_int (Z3native.param_descrs_get_kind (z3obj_gnc x) (z3obj_gno x) (Symbol.gno name))) - + let get_names ( x : param_descrs ) = let n = Z3native.param_descrs_size (z3obj_gnc x) (z3obj_gno x) in let f i = Symbol.create (z3obj_gc x) (Z3native.param_descrs_get_name (z3obj_gnc x) (z3obj_gno x) i) in @@ -746,9 +746,9 @@ end = struct let mk_params ( ctx : context ) = let res : params = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.params_inc_ref ; - dec_ref = Z3native.params_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.params_inc_ref ; + dec_ref = Z3native.params_dec_ref } in (z3obj_sno res ctx (Z3native.mk_params (context_gno ctx))) ; (z3obj_create res) ; res @@ -807,32 +807,30 @@ end = struct let gno e = match e with Expr(a) -> (z3obj_gno a) let expr_of_ptr : context -> Z3native.ptr -> expr = fun ctx no -> + let e = z3_native_object_of_ast_ptr ctx no in if ast_kind_of_int (Z3native.get_ast_kind (context_gno ctx) no) == QUANTIFIER_AST then - Expr(z3_native_object_of_ast_ptr ctx no) + Expr(e) else let s = Z3native.get_sort (context_gno ctx) no in let sk = (sort_kind_of_int (Z3native.get_sort_kind (context_gno ctx) s)) in if (Z3native.is_algebraic_number (context_gno ctx) no) then - Expr(z3_native_object_of_ast_ptr ctx no) - else - if (Z3native.is_numeral_ast (context_gno ctx) no) then - match sk with - | REAL_SORT - | BOOL_SORT - | ARRAY_SORT - | BV_SORT - | ROUNDING_MODE_SORT - | RELATION_SORT - | UNINTERPRETED_SORT - | FLOATING_POINT_SORT - | INT_SORT - | DATATYPE_SORT - | FINITE_DOMAIN_SORT -> - Expr(z3_native_object_of_ast_ptr ctx no) - | _ -> - raise (Z3native.Exception "Unsupported numeral object") - else - Expr(z3_native_object_of_ast_ptr ctx no) + Expr(e) + else if (Z3native.is_numeral_ast (context_gno ctx) no) then + match sk with + | REAL_SORT + | BOOL_SORT + | ARRAY_SORT + | BV_SORT + | ROUNDING_MODE_SORT + | RELATION_SORT + | UNINTERPRETED_SORT + | FLOATING_POINT_SORT + | INT_SORT + | DATATYPE_SORT + | FINITE_DOMAIN_SORT -> Expr(e) + | _ -> raise (Z3native.Exception "Unsupported numeral object") + else + Expr(e) let expr_of_ast a = let q = (Z3enums.ast_kind_of_int (Z3native.get_ast_kind (z3obj_gnc a) (z3obj_gno a))) in @@ -866,9 +864,9 @@ end = struct let get_num_args ( x : expr ) = Z3native.get_app_num_args (gnc x) (gno x) let get_args ( x : expr ) = let n = (get_num_args x) in - let f i = expr_of_ptr (Expr.gc x) (Z3native.get_app_arg (gnc x) (gno x) i) in - mk_list f n - + let f i = expr_of_ptr (Expr.gc x) (Z3native.get_app_arg (gnc x) (gno x) i) in + mk_list f n + let update ( x : expr ) ( args : expr list ) = if ((AST.is_app (ast_of_expr x)) && (List.length args <> (get_num_args x))) then raise (Z3native.Exception "Number of arguments does not match") @@ -880,7 +878,7 @@ end = struct raise (Z3native.Exception "Argument sizes do not match") else expr_of_ptr (Expr.gc x) (Z3native.substitute (gnc x) (gno x) (List.length from) (expr_lton from) (expr_lton to_)) - + let substitute_one ( x : expr ) from to_ = substitute ( x : expr ) [ from ] [ to_ ] @@ -1012,10 +1010,10 @@ struct match e with Expr.Expr(a) -> let q = (Z3enums.ast_kind_of_int (Z3native.get_ast_kind (z3obj_gnc a) (z3obj_gno a))) in if (q != Z3enums.QUANTIFIER_AST) then - raise (Z3native.Exception "Invalid coercion") + raise (Z3native.Exception "Invalid coercion") else - Quantifier(e) - + Quantifier(e) + let gc ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gc e) let gnc ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gnc e) let gno ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gno e) @@ -1023,25 +1021,25 @@ struct module Pattern = struct type pattern = Pattern of AST.ast - + let ast_of_pattern e = match e with Pattern(x) -> x let pattern_of_ast a = (* CMW: Unchecked ok? *) Pattern(a) - + let gc ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gc a) let gnc ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gnc a) let gno ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gno a) let get_num_terms ( x : pattern ) = - Z3native.get_pattern_num_terms (gnc x) (gno x) + Z3native.get_pattern_num_terms (gnc x) (gno x) let get_terms ( x : pattern ) = let n = (get_num_terms x) in let f i = (expr_of_ptr (gc x) (Z3native.get_pattern (gnc x) (gno x) i)) in mk_list f n - + let to_string ( x : pattern ) = Z3native.pattern_to_string (gnc x) (gno x) end @@ -1101,76 +1099,76 @@ struct raise (Z3native.Exception "Number of sorts does not match number of names") else if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier (context_gno ctx) true - (match weight with | None -> 1 | Some(x) -> x) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length sorts) (Sort.sort_lton sorts) - (Symbol.symbol_lton names) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length sorts) (Sort.sort_lton sorts) + (Symbol.symbol_lton names) + (Expr.gno body))) else Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_ex (context_gno ctx) true - (match weight with | None -> 1 | Some(x) -> x) - (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) - (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length nopatterns) (expr_lton nopatterns) - (List.length sorts) (Sort.sort_lton sorts) - (Symbol.symbol_lton names) - (Expr.gno body))) - + (match weight with | None -> 1 | Some(x) -> x) + (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) + (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length nopatterns) (expr_lton nopatterns) + (List.length sorts) (Sort.sort_lton sorts) + (Symbol.symbol_lton names) + (Expr.gno body))) + let mk_forall_const ( ctx : context ) ( bound_constants : expr list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const (context_gno ctx) true - (match weight with | None -> 1 | Some(x) -> x) - (List.length bound_constants) (expr_lton bound_constants) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (List.length bound_constants) (expr_lton bound_constants) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (Expr.gno body))) else Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const_ex (context_gno ctx) true - (match weight with | None -> 1 | Some(x) -> x) - (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) - (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) - (List.length bound_constants) (expr_lton bound_constants) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length nopatterns) (expr_lton nopatterns) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) + (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) + (List.length bound_constants) (expr_lton bound_constants) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length nopatterns) (expr_lton nopatterns) + (Expr.gno body))) let mk_exists ( ctx : context ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = if (List.length sorts) != (List.length names) then raise (Z3native.Exception "Number of sorts does not match number of names") else if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier (context_gno ctx) false - (match weight with | None -> 1 | Some(x) -> x) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length sorts) (Sort.sort_lton sorts) - (Symbol.symbol_lton names) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length sorts) (Sort.sort_lton sorts) + (Symbol.symbol_lton names) + (Expr.gno body))) else Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_ex (context_gno ctx) false - (match weight with | None -> 1 | Some(x) -> x) - (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) - (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length nopatterns) (expr_lton nopatterns) - (List.length sorts) (Sort.sort_lton sorts) - (Symbol.symbol_lton names) - (Expr.gno body))) - + (match weight with | None -> 1 | Some(x) -> x) + (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) + (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length nopatterns) (expr_lton nopatterns) + (List.length sorts) (Sort.sort_lton sorts) + (Symbol.symbol_lton names) + (Expr.gno body))) + let mk_exists_const ( ctx : context ) ( bound_constants : expr list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const (context_gno ctx) false - (match weight with | None -> 1 | Some(x) -> x) - (List.length bound_constants) (expr_lton bound_constants) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (List.length bound_constants) (expr_lton bound_constants) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (Expr.gno body))) else Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const_ex (context_gno ctx) false - (match weight with | None -> 1 | Some(x) -> x) - (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) - (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) - (List.length bound_constants) (expr_lton bound_constants) - (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) - (List.length nopatterns) (expr_lton nopatterns) - (Expr.gno body))) + (match weight with | None -> 1 | Some(x) -> x) + (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x)) + (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x)) + (List.length bound_constants) (expr_lton bound_constants) + (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns))) + (List.length nopatterns) (expr_lton nopatterns) + (Expr.gno body))) let mk_quantifier ( ctx : context ) ( universal : bool ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) = if (universal) then @@ -1209,7 +1207,7 @@ struct let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort ) ( range : Sort.sort ) = (Expr.mk_const ctx name (mk_sort ctx domain range)) - let mk_const_s ( ctx : context ) ( name : string ) ( domain : Sort.sort ) ( range : Sort.sort ) = + let mk_const_s ( ctx : context ) ( name : string ) ( domain : Sort.sort ) ( range : Sort.sort ) = mk_const ctx (Symbol.mk_string ctx name) domain range let mk_select ( ctx : context ) ( a : expr ) ( i : expr ) = @@ -1229,7 +1227,7 @@ struct expr_of_ptr ctx (Z3native.mk_array_default (context_gno ctx) (Expr.gno arg)) let mk_array_ext ( ctx : context) ( arg1 : expr ) ( arg2 : expr ) = - expr_of_ptr ctx (Z3native.mk_array_ext (context_gno ctx) (Expr.gno arg1) (Expr.gno arg2)) + expr_of_ptr ctx (Z3native.mk_array_ext (context_gno ctx) (Expr.gno arg1) (Expr.gno arg2)) end @@ -1305,7 +1303,7 @@ struct let is_relation ( x : expr ) = let nc = (Expr.gnc x) in ((Z3native.is_app (Expr.gnc x) (Expr.gno x)) && - (sort_kind_of_int (Z3native.get_sort_kind nc (Z3native.get_sort nc (Expr.gno x))) == RELATION_SORT)) + (sort_kind_of_int (Z3native.get_sort_kind nc (Z3native.get_sort nc (Expr.gno x))) == RELATION_SORT)) let is_store ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_STORE) let is_empty ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_EMPTY) @@ -1335,7 +1333,7 @@ struct module Constructor = struct type constructor = z3_native_object - + module FieldNumTable = Hashtbl.Make(struct type t = AST.ast let equal x y = AST.compare x y = 0 @@ -1347,28 +1345,28 @@ struct let create ( ctx : context ) ( name : Symbol.symbol ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : Sort.sort option list ) ( sort_refs : int list ) = let n = (List.length field_names) in if n != (List.length sorts) then - raise (Z3native.Exception "Number of field names does not match number of sorts") + raise (Z3native.Exception "Number of field names does not match number of sorts") else - if n != (List.length sort_refs) then - raise (Z3native.Exception "Number of field names does not match number of sort refs") - else + if n != (List.length sort_refs) then + raise (Z3native.Exception "Number of field names does not match number of sort refs") + else let ptr = (Z3native.mk_constructor (context_gno ctx) (Symbol.gno name) - (Symbol.gno recognizer) - n - (Symbol.symbol_lton field_names) - (Sort.sort_option_lton sorts) - (Array.of_list sort_refs)) in - let no : constructor = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = z3obj_nil_ref ; - dec_ref = z3obj_nil_ref} in - (z3obj_sno no ctx ptr) ; - (z3obj_create no) ; - let f = fun o -> Z3native.del_constructor (z3obj_gnc o) (z3obj_gno o) in - Gc.finalise f no ; - FieldNumTable.add _field_nums no n ; - no - + (Symbol.gno recognizer) + n + (Symbol.symbol_lton field_names) + (Sort.sort_option_lton sorts) + (Array.of_list sort_refs)) in + let no : constructor = { m_ctx = ctx ; + m_n_obj = null ; + inc_ref = z3obj_nil_ref ; + dec_ref = z3obj_nil_ref} in + (z3obj_sno no ctx ptr) ; + (z3obj_create no) ; + let f = fun o -> Z3native.del_constructor (z3obj_gnc o) (z3obj_gno o) in + Gc.finalise f no ; + FieldNumTable.add _field_nums no n ; + no + let get_num_fields ( x : constructor ) = FieldNumTable.find _field_nums x let get_constructor_decl ( x : constructor ) = @@ -1377,13 +1375,13 @@ struct let get_tester_decl ( x : constructor ) = let (_, b, _) = (Z3native.query_constructor (z3obj_gnc x) (z3obj_gno x) (get_num_fields x)) in - func_decl_of_ptr (z3obj_gc x) b + func_decl_of_ptr (z3obj_gc x) b let get_accessor_decls ( x : constructor ) = let (_, _, c) = (Z3native.query_constructor (z3obj_gnc x) (z3obj_gno x) (get_num_fields x)) in let f i = func_decl_of_ptr (z3obj_gc x) (Array.get c i) in mk_list f (Array.length c) - + end module ConstructorList = @@ -1392,9 +1390,9 @@ struct let create ( ctx : context ) ( c : Constructor.constructor list ) = let res : constructor_list = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = z3obj_nil_ref ; - dec_ref = z3obj_nil_ref} in + m_n_obj = null ; + inc_ref = z3obj_nil_ref ; + dec_ref = z3obj_nil_ref} in let f x =(z3obj_gno x) in (z3obj_sno res ctx (Z3native.mk_constructor_list (context_gno ctx) (List.length c) (Array.of_list (List.map f c)))) ; (z3obj_create res) ; @@ -1429,8 +1427,8 @@ struct let mk_sorts_s ( ctx : context ) ( names : string list ) ( c : Constructor.constructor list list ) = mk_sorts ctx ( - let f e = (Symbol.mk_string ctx e) in - List.map f names + let f e = (Symbol.mk_string ctx e) in + List.map f names ) c @@ -1600,27 +1598,27 @@ struct let get_big_int ( x : expr ) = if (is_int_numeral x) then - let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in - (Big_int.big_int_of_string s) + let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in + (Big_int.big_int_of_string s) else raise (Z3native.Exception "Conversion failed.") - + let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) let mk_const ( ctx : context ) ( name : Symbol.symbol ) = Expr.mk_const ctx name (mk_sort ctx) - + let mk_const_s ( ctx : context ) ( name : string ) = mk_const ctx (Symbol.mk_string ctx name) - + let mk_mod ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = expr_of_ptr ctx (Z3native.mk_mod (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) - + let mk_rem ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = expr_of_ptr ctx (Z3native.mk_rem (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_numeral_s ( ctx : context ) ( v : string ) = expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx))) - + let mk_numeral_i ( ctx : context ) ( v : int ) = expr_of_ptr ctx (Z3native.mk_int (context_gno ctx) v (Sort.gno (mk_sort ctx))) @@ -1634,60 +1632,60 @@ struct module Real = struct let mk_sort ( ctx : context ) = - Sort.sort_of_ptr ctx (Z3native.mk_real_sort (context_gno ctx)) + Sort.sort_of_ptr ctx (Z3native.mk_real_sort (context_gno ctx)) let get_numerator ( x : expr ) = expr_of_ptr (Expr.gc x) (Z3native.get_numerator (Expr.gnc x) (Expr.gno x)) - + let get_denominator ( x : expr ) = expr_of_ptr (Expr.gc x) (Z3native.get_denominator (Expr.gnc x) (Expr.gno x)) - + let get_ratio ( x : expr ) = if (is_rat_numeral x) then - let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in - (Ratio.ratio_of_string s) + let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in + (Ratio.ratio_of_string s) else raise (Z3native.Exception "Conversion failed.") let to_decimal_string ( x : expr ) ( precision : int ) = Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision - + let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) let mk_const ( ctx : context ) ( name : Symbol.symbol ) = Expr.mk_const ctx name (mk_sort ctx) - + let mk_const_s ( ctx : context ) ( name : string ) = mk_const ctx (Symbol.mk_string ctx name) let mk_numeral_nd ( ctx : context ) ( num : int ) ( den : int ) = if (den == 0) then - raise (Z3native.Exception "Denominator is zero") + raise (Z3native.Exception "Denominator is zero") else - expr_of_ptr ctx (Z3native.mk_real (context_gno ctx) num den) - + expr_of_ptr ctx (Z3native.mk_real (context_gno ctx) num den) + let mk_numeral_s ( ctx : context ) ( v : string ) = expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx))) - + let mk_numeral_i ( ctx : context ) ( v : int ) = expr_of_ptr ctx (Z3native.mk_int (context_gno ctx) v (Sort.gno (mk_sort ctx))) - + let mk_is_integer ( ctx : context ) ( t : expr ) = (expr_of_ptr ctx (Z3native.mk_is_int (context_gno ctx) (Expr.gno t))) - + let mk_real2int ( ctx : context ) ( t : expr ) = (expr_of_ptr ctx (Z3native.mk_real2int (context_gno ctx) (Expr.gno t))) module AlgebraicNumber = struct let to_upper ( x : expr ) ( precision : int ) = - expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_upper (Expr.gnc x) (Expr.gno x) precision) - + expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_upper (Expr.gnc x) (Expr.gno x) precision) + let to_lower ( x : expr ) precision = - expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_lower (Expr.gnc x) (Expr.gno x) precision) - + expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_lower (Expr.gnc x) (Expr.gno x) precision) + let to_decimal_string ( x : expr ) ( precision : int ) = - Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision - + Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision + let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) end end @@ -1843,9 +1841,9 @@ struct let mk_sge ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = (expr_of_ptr ctx (Z3native.mk_bvsge (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_ugt ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - (expr_of_ptr ctx (Z3native.mk_bvugt (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) + (expr_of_ptr ctx (Z3native.mk_bvugt (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_sgt ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - (expr_of_ptr ctx (Z3native.mk_bvsgt (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) + (expr_of_ptr ctx (Z3native.mk_bvsgt (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_concat ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = expr_of_ptr ctx (Z3native.mk_concat (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_extract ( ctx : context ) ( high : int ) ( low : int ) ( t : expr ) = @@ -1857,7 +1855,7 @@ struct let mk_repeat ( ctx : context ) ( i : int ) ( t : expr ) = expr_of_ptr ctx (Z3native.mk_repeat (context_gno ctx) i (Expr.gno t)) let mk_shl ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - expr_of_ptr ctx (Z3native.mk_bvshl (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) + expr_of_ptr ctx (Z3native.mk_bvshl (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_lshr ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = expr_of_ptr ctx (Z3native.mk_bvlshr (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_ashr ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = @@ -1869,15 +1867,15 @@ struct let mk_ext_rotate_left ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = expr_of_ptr ctx (Z3native.mk_ext_rotate_left (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_ext_rotate_right ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - expr_of_ptr ctx (Z3native.mk_ext_rotate_right (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) + expr_of_ptr ctx (Z3native.mk_ext_rotate_right (context_gno ctx) (Expr.gno t1) (Expr.gno t2)) let mk_bv2int ( ctx : context ) ( t : expr ) ( signed : bool ) = expr_of_ptr ctx (Z3native.mk_bv2int (context_gno ctx) (Expr.gno t) signed) let mk_add_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) = (expr_of_ptr ctx (Z3native.mk_bvadd_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed)) let mk_add_no_underflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - (expr_of_ptr ctx (Z3native.mk_bvadd_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) + (expr_of_ptr ctx (Z3native.mk_bvadd_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_sub_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - (expr_of_ptr ctx (Z3native.mk_bvsub_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) + (expr_of_ptr ctx (Z3native.mk_bvsub_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_sub_no_underflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) = (expr_of_ptr ctx (Z3native.mk_bvsub_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed)) let mk_sdiv_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = @@ -1887,7 +1885,7 @@ struct let mk_mul_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) = (expr_of_ptr ctx (Z3native.mk_bvmul_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed)) let mk_mul_no_underflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - (expr_of_ptr ctx (Z3native.mk_bvmul_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) + (expr_of_ptr ctx (Z3native.mk_bvmul_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2))) let mk_numeral ( ctx : context ) ( v : string ) ( size : int ) = expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx size))) end @@ -1897,66 +1895,66 @@ module FloatingPoint = struct module RoundingMode = struct - let mk_sort ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_rounding_mode_sort (context_gno ctx))) - let is_fprm ( x : expr ) = - (Sort.get_sort_kind (Expr.get_sort(x))) == ROUNDING_MODE_SORT - let mk_round_nearest_ties_to_even ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_even (context_gno ctx))) - let mk_rne ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_rne (context_gno ctx))) - let mk_round_nearest_ties_to_away ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_away (context_gno ctx))) - let mk_rna ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_rna (context_gno ctx))) - let mk_round_toward_positive ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_positive (context_gno ctx))) - let mk_rtp ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_rtp (context_gno ctx))) - let mk_round_toward_negative ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_negative (context_gno ctx))) - let mk_rtn ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_rtn (context_gno ctx))) - let mk_round_toward_zero ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_zero (context_gno ctx))) - let mk_rtz ( ctx : context ) = - (expr_of_ptr ctx (Z3native.mk_fpa_rtz (context_gno ctx))) + let mk_sort ( ctx : context ) = + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_rounding_mode_sort (context_gno ctx))) + let is_fprm ( x : expr ) = + (Sort.get_sort_kind (Expr.get_sort(x))) == ROUNDING_MODE_SORT + let mk_round_nearest_ties_to_even ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_even (context_gno ctx))) + let mk_rne ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_rne (context_gno ctx))) + let mk_round_nearest_ties_to_away ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_away (context_gno ctx))) + let mk_rna ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_rna (context_gno ctx))) + let mk_round_toward_positive ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_positive (context_gno ctx))) + let mk_rtp ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_rtp (context_gno ctx))) + let mk_round_toward_negative ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_negative (context_gno ctx))) + let mk_rtn ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_rtn (context_gno ctx))) + let mk_round_toward_zero ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_zero (context_gno ctx))) + let mk_rtz ( ctx : context ) = + (expr_of_ptr ctx (Z3native.mk_fpa_rtz (context_gno ctx))) end - + let mk_sort ( ctx : context ) ( ebits : int ) ( sbits : int ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort (context_gno ctx) ebits sbits)) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort (context_gno ctx) ebits sbits)) let mk_sort_half ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_half (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_half (context_gno ctx))) let mk_sort_16 ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_16 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_16 (context_gno ctx))) let mk_sort_single ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_single (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_single (context_gno ctx))) let mk_sort_32 ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_32 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_32 (context_gno ctx))) let mk_sort_double ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_double (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_double (context_gno ctx))) let mk_sort_64 ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_64 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_64 (context_gno ctx))) let mk_sort_quadruple ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_quadruple (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_quadruple (context_gno ctx))) let mk_sort_128 ( ctx : context ) = - (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_128 (context_gno ctx))) + (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_128 (context_gno ctx))) let mk_nan ( ctx : context ) ( s : Sort.sort ) = - (expr_of_ptr ctx (Z3native.mk_fpa_nan (context_gno ctx) (Sort.gno s))) + (expr_of_ptr ctx (Z3native.mk_fpa_nan (context_gno ctx) (Sort.gno s))) let mk_inf ( ctx : context ) ( s : Sort.sort ) ( negative : bool ) = - (expr_of_ptr ctx (Z3native.mk_fpa_inf (context_gno ctx) (Sort.gno s) negative)) + (expr_of_ptr ctx (Z3native.mk_fpa_inf (context_gno ctx) (Sort.gno s) negative)) let mk_zero ( ctx : context ) ( s : Sort.sort ) ( negative : bool ) = - (expr_of_ptr ctx (Z3native.mk_fpa_zero (context_gno ctx) (Sort.gno s) negative)) + (expr_of_ptr ctx (Z3native.mk_fpa_zero (context_gno ctx) (Sort.gno s) negative)) let mk_fp ( ctx : context ) ( sign : expr ) ( exponent : expr ) ( significand : expr ) = - (expr_of_ptr ctx (Z3native.mk_fpa_fp (context_gno ctx) (Expr.gno sign) (Expr.gno exponent) (Expr.gno significand))) + (expr_of_ptr ctx (Z3native.mk_fpa_fp (context_gno ctx) (Expr.gno sign) (Expr.gno exponent) (Expr.gno significand))) let mk_numeral_f ( ctx : context ) ( value : float ) ( s : Sort.sort ) = - (expr_of_ptr ctx (Z3native.mk_fpa_numeral_double (context_gno ctx) value (Sort.gno s))) + (expr_of_ptr ctx (Z3native.mk_fpa_numeral_double (context_gno ctx) value (Sort.gno s))) let mk_numeral_i ( ctx : context ) ( value : int ) ( s : Sort.sort ) = - (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int (context_gno ctx) value (Sort.gno s))) + (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int (context_gno ctx) value (Sort.gno s))) let mk_numeral_i_u ( ctx : context ) ( sign : bool ) ( exponent : int ) ( significand : int ) ( s : Sort.sort ) = - (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int64_uint64 (context_gno ctx) sign exponent significand (Sort.gno s))) + (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int64_uint64 (context_gno ctx) sign exponent significand (Sort.gno s))) let mk_numeral_s ( ctx : context ) ( v : string ) ( s : Sort.sort ) = (expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno s))) @@ -1991,7 +1989,7 @@ struct let is_to_sbv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_SBV) let is_to_real ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_REAL) let is_to_ieee_bv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_IEEE_BV) - + let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( s : Sort.sort ) = Expr.mk_const ctx name s @@ -2064,24 +2062,24 @@ struct expr_of_ptr ctx (Z3native.mk_fpa_to_real (context_gno ctx) (Expr.gno t)) let get_ebits ( ctx : context ) ( s : Sort.sort ) = - (Z3native.fpa_get_ebits (context_gno ctx) (Sort.gno s)) + (Z3native.fpa_get_ebits (context_gno ctx) (Sort.gno s)) let get_sbits ( ctx : context ) ( s : Sort.sort ) = - (Z3native.fpa_get_sbits (context_gno ctx) (Sort.gno s)) + (Z3native.fpa_get_sbits (context_gno ctx) (Sort.gno s)) let get_numeral_sign ( ctx : context ) ( t : expr ) = - (Z3native.fpa_get_numeral_sign (context_gno ctx) (Expr.gno t)) + (Z3native.fpa_get_numeral_sign (context_gno ctx) (Expr.gno t)) let get_numeral_significand_string ( ctx : context ) ( t : expr ) = - (Z3native.fpa_get_numeral_significand_string (context_gno ctx) (Expr.gno t)) + (Z3native.fpa_get_numeral_significand_string (context_gno ctx) (Expr.gno t)) let get_numeral_significand_uint ( ctx : context ) ( t : expr ) = - (Z3native.fpa_get_numeral_significand_uint64 (context_gno ctx) (Expr.gno t)) + (Z3native.fpa_get_numeral_significand_uint64 (context_gno ctx) (Expr.gno t)) let get_numeral_exponent_string ( ctx : context ) ( t : expr ) = - (Z3native.fpa_get_numeral_exponent_string (context_gno ctx) (Expr.gno t)) + (Z3native.fpa_get_numeral_exponent_string (context_gno ctx) (Expr.gno t)) let get_numeral_exponent_int ( ctx : context ) ( t : expr ) = - (Z3native.fpa_get_numeral_exponent_int64 (context_gno ctx) (Expr.gno t)) + (Z3native.fpa_get_numeral_exponent_int64 (context_gno ctx) (Expr.gno t)) let mk_to_ieee_bv ( ctx : context ) ( t : expr ) = - (expr_of_ptr ctx (Z3native.mk_fpa_to_ieee_bv (context_gno ctx) (Expr.gno t))) + (expr_of_ptr ctx (Z3native.mk_fpa_to_ieee_bv (context_gno ctx) (Expr.gno t))) let mk_to_fp_int_real ( ctx : context ) ( rm : expr ) ( exponent : expr ) ( significand : expr ) ( s : Sort.sort ) = - (expr_of_ptr ctx (Z3native.mk_fpa_to_fp_int_real (context_gno ctx) (Expr.gno rm) (Expr.gno exponent) (Expr.gno significand) (Sort.gno s))) + (expr_of_ptr ctx (Z3native.mk_fpa_to_fp_int_real (context_gno ctx) (Expr.gno rm) (Expr.gno exponent) (Expr.gno significand) (Sort.gno s))) let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x) end @@ -2137,9 +2135,9 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : goal = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.goal_inc_ref ; - dec_ref = Z3native.goal_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.goal_inc_ref ; + dec_ref = Z3native.goal_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2176,7 +2174,7 @@ struct let get_formulas ( x : goal ) = let n = get_size x in let f i = ((expr_of_ptr (z3obj_gc x) - (Z3native.goal_formula (z3obj_gnc x) (z3obj_gno x) i))) in + (Z3native.goal_formula (z3obj_gnc x) (z3obj_gno x) i))) in mk_list f n let get_num_exprs ( x : goal ) = Z3native.goal_num_exprs (z3obj_gnc x) (z3obj_gno x) @@ -2200,9 +2198,9 @@ struct Z3native.apply_result_inc_ref (z3obj_gnc x) arn ; let sg = Z3native.apply_result_get_num_subgoals (z3obj_gnc x) arn in let res = if sg == 0 then - raise (Z3native.Exception "No subgoals") + raise (Z3native.Exception "No subgoals") else - Z3native.apply_result_get_subgoal (z3obj_gnc x) arn 0 in + Z3native.apply_result_get_subgoal (z3obj_gnc x) arn 0 in Z3native.apply_result_dec_ref (z3obj_gnc x) arn ; Z3native.tactic_dec_ref (z3obj_gnc x) tn ; create (z3obj_gc x) res @@ -2213,13 +2211,13 @@ struct let to_string ( x : goal ) = Z3native.goal_to_string (z3obj_gnc x) (z3obj_gno x) let as_expr ( x : goal ) = - let n = get_size x in - if n = 0 then - (Boolean.mk_true (z3obj_gc x)) - else if n = 1 then - (List.hd (get_formulas x)) - else - (Boolean.mk_and (z3obj_gc x) (get_formulas x)) + let n = get_size x in + if n = 0 then + (Boolean.mk_true (z3obj_gc x)) + else if n = 1 then + (List.hd (get_formulas x)) + else + (Boolean.mk_and (z3obj_gc x) (get_formulas x)) end @@ -2229,9 +2227,9 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : model = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.model_inc_ref ; - dec_ref = Z3native.model_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.model_inc_ref ; + dec_ref = Z3native.model_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2242,40 +2240,40 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : func_interp = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.func_interp_inc_ref ; - dec_ref = Z3native.func_interp_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.func_interp_inc_ref ; + dec_ref = Z3native.func_interp_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res - + module FuncEntry = - struct + struct type func_entry = z3_native_object - + let create ( ctx : context ) ( no : Z3native.ptr ) = - let res : func_entry = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.func_entry_inc_ref ; - dec_ref = Z3native.func_entry_dec_ref } in - (z3obj_sno res ctx no) ; - (z3obj_create res) ; - res - + let res : func_entry = { m_ctx = ctx ; + m_n_obj = null ; + inc_ref = Z3native.func_entry_inc_ref ; + dec_ref = Z3native.func_entry_dec_ref } in + (z3obj_sno res ctx no) ; + (z3obj_create res) ; + res + let get_value ( x : func_entry ) = - expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_value (z3obj_gnc x) (z3obj_gno x)) + expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_value (z3obj_gnc x) (z3obj_gno x)) let get_num_args ( x : func_entry ) = Z3native.func_entry_get_num_args (z3obj_gnc x) (z3obj_gno x) - + let get_args ( x : func_entry ) = - let n = (get_num_args x) in - let f i = (expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_arg (z3obj_gnc x) (z3obj_gno x) i)) in - mk_list f n - + let n = (get_num_args x) in + let f i = (expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_arg (z3obj_gnc x) (z3obj_gno x) i)) in + mk_list f n + let to_string ( x : func_entry ) = - let a = (get_args x) in - let f c p = (p ^ (Expr.to_string c) ^ ", ") in - "[" ^ List.fold_right f a ((Expr.to_string (get_value x)) ^ "]") + let a = (get_args x) in + let f c p = (p ^ (Expr.to_string c) ^ ", ") in + "[" ^ List.fold_right f a ((Expr.to_string (get_value x)) ^ "]") end let get_num_entries ( x: func_interp ) = Z3native.func_interp_get_num_entries (z3obj_gnc x) (z3obj_gno x) @@ -2291,14 +2289,14 @@ struct let to_string ( x : func_interp ) = let f c p = ( - let n = (FuncEntry.get_num_args c) in - p ^ - let g c p = (p ^ (Expr.to_string c) ^ ", ") in - (if n > 1 then "[" else "") ^ - (List.fold_right - g - (FuncEntry.get_args c) - ((if n > 1 then "]" else "") ^ " -> " ^ (Expr.to_string (FuncEntry.get_value c)) ^ ", ")) + let n = (FuncEntry.get_num_args c) in + p ^ + let g c p = (p ^ (Expr.to_string c) ^ ", ") in + (if n > 1 then "[" else "") ^ + (List.fold_right + g + (FuncEntry.get_args c) + ((if n > 1 then "]" else "") ^ " -> " ^ (Expr.to_string (FuncEntry.get_value c)) ^ ", ")) ) in List.fold_right f (get_entries x) ("else -> " ^ (Expr.to_string (get_else x)) ^ "]") end @@ -2310,9 +2308,9 @@ struct else let np = Z3native.model_get_const_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f) in if (Z3native.is_null np) then - None + None else - Some (expr_of_ptr (z3obj_gc x) np) + Some (expr_of_ptr (z3obj_gc x) np) let get_const_interp_e ( x : model ) ( a : expr ) = get_const_interp x (Expr.get_func_decl a) @@ -2322,20 +2320,20 @@ struct if (FuncDecl.get_arity f) == 0 then let n = Z3native.model_get_const_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f) in if (Z3native.is_null n) then - None + None else - match sk with - | ARRAY_SORT -> - if not (Z3native.is_as_array (z3obj_gnc x) n) then - raise (Z3native.Exception "Argument was not an array constant") - else - let fd = Z3native.get_as_array_func_decl (z3obj_gnc x) n in + match sk with + | ARRAY_SORT -> + if not (Z3native.is_as_array (z3obj_gnc x) n) then + raise (Z3native.Exception "Argument was not an array constant") + else + let fd = Z3native.get_as_array_func_decl (z3obj_gnc x) n in get_func_interp x (func_decl_of_ptr (z3obj_gc x) fd) - | _ -> raise (Z3native.Exception "Constant functions do not have a function interpretation; use ConstInterp"); + | _ -> raise (Z3native.Exception "Constant functions do not have a function interpretation; use ConstInterp"); else let n = (Z3native.model_get_func_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f)) in if (Z3native.is_null n) then None else Some (FuncInterp.create (z3obj_gc x) n) - + (** The number of constants that have an interpretation in the model. *) let get_num_consts ( x : model ) = Z3native.model_get_num_consts (z3obj_gnc x) (z3obj_gno x) @@ -2389,9 +2387,9 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : probe = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.probe_inc_ref ; - dec_ref = Z3native.probe_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.probe_inc_ref ; + dec_ref = Z3native.probe_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2449,9 +2447,9 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : tactic = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.tactic_inc_ref ; - dec_ref = Z3native.tactic_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.tactic_inc_ref ; + dec_ref = Z3native.tactic_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2459,30 +2457,30 @@ struct module ApplyResult = struct type apply_result = z3_native_object - + let create ( ctx : context ) ( no : Z3native.ptr ) = let res : apply_result = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.apply_result_inc_ref ; - dec_ref = Z3native.apply_result_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.apply_result_inc_ref ; + dec_ref = Z3native.apply_result_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res - + let get_num_subgoals ( x : apply_result ) = Z3native.apply_result_get_num_subgoals (z3obj_gnc x) (z3obj_gno x) - + let get_subgoals ( x : apply_result ) = let n = (get_num_subgoals x) in let f i = Goal.create (z3obj_gc x) (Z3native.apply_result_get_subgoal (z3obj_gnc x) (z3obj_gno x) i) in mk_list f n - + let get_subgoal ( x : apply_result ) ( i : int ) = Goal.create (z3obj_gc x) (Z3native.apply_result_get_subgoal (z3obj_gnc x) (z3obj_gno x) i) - + let convert_model ( x : apply_result ) ( i : int ) ( m : Model.model ) = Model.create (z3obj_gc x) (Z3native.apply_result_convert_model (z3obj_gnc x) (z3obj_gno x) i (z3obj_gno m)) - + let to_string ( x : apply_result ) = Z3native.apply_result_to_string (z3obj_gnc x) (z3obj_gno x) end @@ -2515,10 +2513,10 @@ struct | Some(x) -> (Some (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno c) x))) in match (List.fold_left f None ts) with | None -> - create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2)) + create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2)) | Some(x) -> - let o = (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t2) x) in - create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) o) + let o = (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t2) x) in + create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) o) let or_else ( ctx : context ) ( t1 : tactic ) ( t2 : tactic ) = create ctx (Z3native.tactic_or_else (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2)) @@ -2566,14 +2564,14 @@ end module Statistics = -struct +struct type statistics = z3_native_object let create ( ctx : context ) ( no : Z3native.ptr ) = let res : statistics = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.stats_inc_ref ; - dec_ref = Z3native.stats_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.stats_inc_ref ; + dec_ref = Z3native.stats_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2582,44 +2580,44 @@ struct module Entry = struct type statistics_entry = { - mutable m_key : string; - mutable m_is_int : bool ; - mutable m_is_float : bool ; - mutable m_int : int ; - mutable m_float : float } - + mutable m_key : string; + mutable m_is_int : bool ; + mutable m_is_float : bool ; + mutable m_int : int ; + mutable m_float : float } + let create_si k v = - let res : statistics_entry = { - m_key = k ; - m_is_int = true ; - m_is_float = false ; - m_int = v ; - m_float = 0.0 - } in - res + let res : statistics_entry = { + m_key = k ; + m_is_int = true ; + m_is_float = false ; + m_int = v ; + m_float = 0.0 + } in + res let create_sd k v = - let res : statistics_entry = { - m_key = k ; - m_is_int = false ; - m_is_float = true ; - m_int = 0 ; - m_float = v - } in - res - + let res : statistics_entry = { + m_key = k ; + m_is_int = false ; + m_is_float = true ; + m_int = 0 ; + m_float = v + } in + res + let get_key (x : statistics_entry) = x.m_key - let get_int (x : statistics_entry) = x.m_int + let get_int (x : statistics_entry) = x.m_int let get_float (x : statistics_entry) = x.m_float let is_int (x : statistics_entry) = x.m_is_int let is_float (x : statistics_entry) = x.m_is_float let to_string_value (x : statistics_entry) = - if (is_int x) then - string_of_int (get_int x) - else if (is_float x) then - string_of_float (get_float x) - else + if (is_int x) then + string_of_int (get_int x) + else if (is_float x) then + string_of_float (get_float x) + else raise (Z3native.Exception "Unknown statistical entry type") let to_string ( x : statistics_entry ) = (get_key x) ^ ": " ^ (to_string_value x) end @@ -2631,11 +2629,11 @@ struct let get_entries ( x : statistics ) = let n = (get_size x ) in let f i = ( - let k = Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i in - if (Z3native.stats_is_uint (z3obj_gnc x) (z3obj_gno x) i) then - (Entry.create_si k (Z3native.stats_get_uint_value (z3obj_gnc x) (z3obj_gno x) i)) - else - (Entry.create_sd k (Z3native.stats_get_double_value (z3obj_gnc x) (z3obj_gno x) i)) + let k = Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i in + if (Z3native.stats_is_uint (z3obj_gnc x) (z3obj_gno x) i) then + (Entry.create_si k (Z3native.stats_get_uint_value (z3obj_gnc x) (z3obj_gno x) i)) + else + (Entry.create_sd k (Z3native.stats_get_double_value (z3obj_gnc x) (z3obj_gno x) i)) ) in mk_list f n @@ -2643,7 +2641,7 @@ struct let n = (get_size x) in let f i = (Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i) in mk_list f n - + let get ( x : statistics ) ( key : string ) = let f p c = (if ((Entry.get_key c) == key) then (Some c) else p) in List.fold_left f None (get_entries x) @@ -2657,9 +2655,9 @@ struct let create ( ctx : context ) ( no : Z3native.ptr ) = let res : solver = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.solver_inc_ref ; - dec_ref = Z3native.solver_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.solver_inc_ref ; + dec_ref = Z3native.solver_dec_ref } in (z3obj_sno res ctx no) ; (z3obj_create res) ; res @@ -2695,7 +2693,7 @@ struct else let f a b = (Z3native.solver_assert_and_track (z3obj_gnc x) (z3obj_gno x) (Expr.gno a) (Expr.gno b)) in ignore (List.iter2 f cs ps) - + let assert_and_track ( x : solver ) ( c : expr ) ( p : expr ) = Z3native.solver_assert_and_track (z3obj_gnc x) (z3obj_gno x) (Expr.gno c) (Expr.gno p) @@ -2710,30 +2708,30 @@ struct let check ( x : solver ) ( assumptions : expr list ) = let r = if ((List.length assumptions) == 0) then - lbool_of_int (Z3native.solver_check (z3obj_gnc x) (z3obj_gno x)) + lbool_of_int (Z3native.solver_check (z3obj_gnc x) (z3obj_gno x)) else - let f x = (Expr.gno x) in - lbool_of_int (Z3native.solver_check_assumptions (z3obj_gnc x) (z3obj_gno x) (List.length assumptions) (Array.of_list (List.map f assumptions))) + let f x = (Expr.gno x) in + lbool_of_int (Z3native.solver_check_assumptions (z3obj_gnc x) (z3obj_gno x) (List.length assumptions) (Array.of_list (List.map f assumptions))) in match r with | L_TRUE -> SATISFIABLE | L_FALSE -> UNSATISFIABLE | _ -> UNKNOWN - + let get_model ( x : solver ) = let q = Z3native.solver_get_model (z3obj_gnc x) (z3obj_gno x) in if (Z3native.is_null q) then None else Some (Model.create (z3obj_gc x) q) - + let get_proof ( x : solver ) = let q = Z3native.solver_get_proof (z3obj_gnc x) (z3obj_gno x) in if (Z3native.is_null q) then None else Some (expr_of_ptr (z3obj_gc x) q) - + let get_unsat_core ( x : solver ) = let av = AST.ASTVector.create (z3obj_gc x) (Z3native.solver_get_unsat_core (z3obj_gnc x) (z3obj_gno x)) in (AST.ASTVector.to_expr_list av) @@ -2758,7 +2756,7 @@ struct create ctx (Z3native.mk_solver_from_tactic (context_gno ctx) (z3obj_gno t)) let translate ( x : solver ) ( to_ctx : context ) = - create to_ctx (Z3native.solver_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx)) + create to_ctx (Z3native.solver_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx)) let to_string ( x : solver ) = Z3native.solver_to_string (z3obj_gnc x) (z3obj_gno x) end @@ -2770,9 +2768,9 @@ struct let create ( ctx : context ) = let res : fixedpoint = { m_ctx = ctx ; - m_n_obj = null ; - inc_ref = Z3native.fixedpoint_inc_ref ; - dec_ref = Z3native.fixedpoint_dec_ref } in + m_n_obj = null ; + inc_ref = Z3native.fixedpoint_inc_ref ; + dec_ref = Z3native.fixedpoint_dec_ref } in (z3obj_sno res ctx (Z3native.mk_fixedpoint (context_gno ctx))) ; (z3obj_create res) ; res @@ -2815,7 +2813,7 @@ struct | L_TRUE -> Solver.SATISFIABLE | L_FALSE -> Solver.UNSATISFIABLE | _ -> Solver.UNKNOWN - + let push ( x : fixedpoint ) = Z3native.fixedpoint_push (z3obj_gnc x) (z3obj_gno x) @@ -2844,7 +2842,7 @@ struct None else Some (expr_of_ptr (z3obj_gc x) q) - + let add_cover ( x : fixedpoint ) ( level : int ) ( predicate : func_decl ) ( property : expr ) = Z3native.fixedpoint_add_cover (z3obj_gnc x) (z3obj_gno x) level (FuncDecl.gno predicate) (Expr.gno property) @@ -2980,13 +2978,13 @@ struct raise (Z3native.Exception "Argument size mismatch") else Z3native.parse_smtlib_string (context_gno ctx) str - cs - (Symbol.symbol_lton sort_names) - (Sort.sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) - + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) + let parse_smtlib_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = let csn = (List.length sort_names) in let cs = (List.length sorts) in @@ -2996,12 +2994,12 @@ struct raise (Z3native.Exception "Argument size mismatch") else Z3native.parse_smtlib_file (context_gno ctx) file_name - cs - (Symbol.symbol_lton sort_names) - (Sort.sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))) let get_num_smtlib_formulas ( ctx : context ) = Z3native.get_smtlib_num_formulas (context_gno ctx) @@ -3040,13 +3038,13 @@ struct raise (Z3native.Exception "Argument size mismatch") else (expr_of_ptr ctx (Z3native.parse_smtlib2_string (context_gno ctx) str - cs - (Symbol.symbol_lton sort_names) - (Sort.sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) - + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) + let parse_smtlib2_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) = let csn = (List.length sort_names) in let cs = (List.length sorts) in @@ -3056,12 +3054,12 @@ struct raise (Z3native.Exception "Argument size mismatch") else (expr_of_ptr ctx (Z3native.parse_smtlib2_string (context_gno ctx) file_name - cs - (Symbol.symbol_lton sort_names) - (Sort.sort_lton sorts) - cd - (Symbol.symbol_lton decl_names) - (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) + cs + (Symbol.symbol_lton sort_names) + (Sort.sort_lton sorts) + cd + (Symbol.symbol_lton decl_names) + (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls))))) end module Interpolation = @@ -3102,21 +3100,21 @@ struct match r with | 0 -> raise (Z3native.Exception "Interpolation problem could not be read.") | _ -> - let f1 i = (expr_of_ptr ctx (Array.get cnsts i)) in - let f2 i = (Array.get parents i) in - let f3 i = (expr_of_ptr ctx (Array.get theory i)) in - ((mk_list f1 num), - (mk_list f2 num), - (mk_list f3 num_theory)) + let f1 i = (expr_of_ptr ctx (Array.get cnsts i)) in + let f2 i = (Array.get parents i) in + let f3 i = (expr_of_ptr ctx (Array.get theory i)) in + ((mk_list f1 num), + (mk_list f2 num), + (mk_list f3 num_theory)) let check_interpolant ( ctx : context ) ( num : int ) ( cnsts : Expr.expr list ) ( parents : int list ) ( interps : Expr.expr list ) ( num_theory : int ) ( theory : Expr.expr list ) = let (r, str) = (Z3native.check_interpolant (context_gno ctx) - num - (let f x = Expr.gno x in (Array.of_list (List.map f cnsts))) - (Array.of_list parents) - (let f x = Expr.gno x in (Array.of_list (List.map f interps))) - num_theory - (let f x = Expr.gno x in (Array.of_list (List.map f theory)))) in + num + (let f x = Expr.gno x in (Array.of_list (List.map f cnsts))) + (Array.of_list parents) + (let f x = Expr.gno x in (Array.of_list (List.map f interps))) + num_theory + (let f x = Expr.gno x in (Array.of_list (List.map f theory)))) in match (lbool_of_int r) with | L_UNDEF -> raise (Z3native.Exception "Interpolant could not be verified.") | L_FALSE -> raise (Z3native.Exception "Interpolant could not be verified.") From 72d2cd546eb0da474ae28d8a2933d219cb1f713e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 Dec 2015 17:48:02 -0800 Subject: [PATCH 20/87] elim_bounds bugfix Signed-off-by: Nikolaj Bjorner --- src/ast/simplifier/elim_bounds.cpp | 6 ++++-- src/tactic/smtlogics/quant_tactics.cpp | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ast/simplifier/elim_bounds.cpp b/src/ast/simplifier/elim_bounds.cpp index 41ce18549..a4e145e0a 100644 --- a/src/ast/simplifier/elim_bounds.cpp +++ b/src/ast/simplifier/elim_bounds.cpp @@ -110,6 +110,7 @@ void elim_bounds::operator()(quantifier * q, expr_ref & r) { return; } expr * n = q->get_expr(); + unsigned num_vars = q->get_num_decls(); ptr_buffer atoms; if (m_manager.is_or(n)) atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args()); @@ -138,11 +139,11 @@ void elim_bounds::operator()(quantifier * q, expr_ref & r) { var * lower = 0; var * upper = 0; if (is_bound(a, lower, upper)) { - if (lower != 0 && !m_used_vars.contains(lower->get_idx())) { + if (lower != 0 && !m_used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) { ADD_CANDIDATE(lower); m_lowers.insert(lower); } - if (upper != 0 && !m_used_vars.contains(upper->get_idx())) { + if (upper != 0 && !m_used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) { ADD_CANDIDATE(upper); m_uppers.insert(upper); } @@ -176,6 +177,7 @@ void elim_bounds::operator()(quantifier * q, expr_ref & r) { switch (atoms.size()) { case 0: r = m_manager.mk_false(); + TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";); return; case 1: new_body = atoms[0]; diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index 937b0229e..8714b055f 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -102,7 +102,8 @@ tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) { or_else(try_for(mk_smt_tactic(), 100), try_for(qe::mk_sat_tactic(m), 1000), try_for(mk_smt_tactic(), 1000), - and_then(mk_qe_tactic(m), mk_smt_tactic()))); + and_then(mk_qe_tactic(m), mk_smt_tactic()) + )); st->updt_params(p); return st; From 077e8015906b3dcfaab189c2fbf01e491233711f Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Wed, 23 Dec 2015 13:41:52 +0100 Subject: [PATCH 21/87] Assertion fix. Relates to #383. --- src/ast/rewriter/fpa_rewriter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 63af356c8..e4732f125 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -764,7 +764,6 @@ br_status fpa_rewriter::mk_fp(expr * arg1, expr * arg2, expr * arg3, expr_ref & bu.is_numeral(arg3, r3, bvs3)) { SASSERT(mpzm.is_one(r2.to_mpq().denominator())); SASSERT(mpzm.is_one(r3.to_mpq().denominator())); - SASSERT(mpzm.is_int64(r3.to_mpq().numerator())); scoped_mpf v(m_fm); mpf_exp_t biased_exp = mpzm.get_int64(r2.to_mpq().numerator()); m_fm.set(v, bvs2, bvs3 + 1, From 386399472dbfa6e78d0c4d77502b9cc025bbd51f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Dec 2015 11:02:34 -0800 Subject: [PATCH 22/87] seq Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 89 +++++++++++++++++++++--------- src/ast/seq_decl_plugin.cpp | 17 +++++- src/smt/smt_model_generator.cpp | 4 +- src/smt/theory_seq.cpp | 98 +++++++++++++++++++++++---------- src/smt/theory_seq.h | 17 ++++-- 5 files changed, 160 insertions(+), 65 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 09e4bd3a9..9a9b17500 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -87,6 +87,10 @@ struct (z3obj_sno res ctx no) ; (z3obj_create res) ; res + + let ignore2 a b c = ignore a; ignore b + let ignore3 a b c = ignore a; ignore2 b c + end open Internal @@ -833,6 +837,22 @@ end = struct let o = Z3native.mk_app (context_gno ctx) (AST.ptr_of_ast fa) (List.length args) (expr_lton args) in expr_of_ptr ctx o + let apply_un ctx f t = + let r = expr_of_ptr ctx (f (context_gno ctx) (gno t)) in + ignore t; + r + + let apply_bin ctx f t1 t2 = + let r = expr_of_ptr ctx (f (context_gno ctx) (gno t1) (gno t2)) in + ignore2 t1 t2; + r + + let apply_ter ctx f t1 t2 t3 = + let r = expr_of_ptr ctx (f (context_gno ctx) (gno t1) (gno t2) (gno t3)) in + ignore3 t1 t2 t3; + r + + let simplify ( x : expr ) ( p : Params.params option ) = match p with | None -> expr_of_ptr (Expr.gc x) (Z3native.simplify (gnc x) (gno x)) | Some pp -> expr_of_ptr (Expr.gc x) (Z3native.simplify_ex (gnc x) (gno x) (z3obj_gno pp)) @@ -854,13 +874,17 @@ end = struct if ((AST.is_app (ast_of_expr x)) && (List.length args <> (get_num_args x))) then raise (Z3native.Exception "Number of arguments does not match") else - expr_of_ptr (Expr.gc x) (Z3native.update_term (gnc x) (gno x) (List.length args) (expr_lton args)) + let r = expr_of_ptr (Expr.gc x) (Z3native.update_term (gnc x) (gno x) (List.length args) (expr_lton args)) in + ignore2 x args; + r let substitute ( x : expr ) from to_ = if (List.length from) <> (List.length to_) then raise (Z3native.Exception "Argument sizes do not match") else - expr_of_ptr (Expr.gc x) (Z3native.substitute (gnc x) (gno x) (List.length from) (expr_lton from) (expr_lton to_)) + let r = expr_of_ptr (Expr.gc x) (Z3native.substitute (gnc x) (gno x) (List.length from) (expr_lton from) (expr_lton to_)) in + ignore3 from to_ x; + r let substitute_one ( x : expr ) from to_ = substitute ( x : expr ) [ from ] [ to_ ] @@ -872,7 +896,9 @@ end = struct if (Expr.gc x) == to_ctx then x else - expr_of_ptr to_ctx (Z3native.translate (gnc x) (gno x) (context_gno to_ctx)) + let r = expr_of_ptr to_ctx (Z3native.translate (gnc x) (gno x) (context_gno to_ctx)) in + ignore2 x to_ctx; + r let to_string ( x : expr ) = Z3native.ast_to_string (gnc x) (gno x) @@ -933,34 +959,39 @@ struct let mk_val ( ctx : context ) ( value : bool ) = if value then mk_true ctx else mk_false ctx - let mk_not ( ctx : context ) ( a : expr ) = - expr_of_ptr ctx (Z3native.mk_not (context_gno ctx) (gno a)) + let mk_not ( ctx : context ) ( a : expr ) = apply_un ctx Z3native.mk_not a - let mk_ite ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( t3 : expr ) = - expr_of_ptr ctx (Z3native.mk_ite (context_gno ctx) (gno t1) (gno t2) (gno t3)) + let mk_ite ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( t3 : expr ) = + apply_ter ctx Z3native.mk_ite t1 t2 t3 let mk_iff ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - expr_of_ptr ctx (Z3native.mk_iff (context_gno ctx) (gno t1) (gno t2)) + apply_bin ctx Z3native.mk_iff t1 t2 let mk_implies ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - expr_of_ptr ctx (Z3native.mk_implies (context_gno ctx) (gno t1) (gno t2)) + apply_bin ctx Z3native.mk_implies t1 t2 let mk_xor ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - expr_of_ptr ctx (Z3native.mk_xor (context_gno ctx) (gno t1) (gno t2)) + apply_bin ctx Z3native.mk_xor t1 t2 let mk_and ( ctx : context ) ( args : expr list ) = let f x = (Expr.gno (x)) in - expr_of_ptr ctx (Z3native.mk_and (context_gno ctx) (List.length args) (Array.of_list (List.map f args))) + let r = expr_of_ptr ctx (Z3native.mk_and (context_gno ctx) (List.length args) (Array.of_list (List.map f args))) in + ignore args; + r let mk_or ( ctx : context ) ( args : expr list ) = let f x = (Expr.gno (x)) in - expr_of_ptr ctx (Z3native.mk_or (context_gno ctx) (List.length args) (Array.of_list(List.map f args))) + let r = expr_of_ptr ctx (Z3native.mk_or (context_gno ctx) (List.length args) (Array.of_list(List.map f args))) in + ignore args; + r let mk_eq ( ctx : context ) ( x : expr ) ( y : expr ) = - expr_of_ptr ctx (Z3native.mk_eq (context_gno ctx) (Expr.gno x) (Expr.gno y)) + apply_bin ctx Z3native.mk_eq x y let mk_distinct ( ctx : context ) ( args : expr list ) = - expr_of_ptr ctx (Z3native.mk_distinct (context_gno ctx) (List.length args) (expr_lton args)) + let r = expr_of_ptr ctx (Z3native.mk_distinct (context_gno ctx) (List.length args) (expr_lton args)) in + ignore args; + r let get_bool_value ( x : expr ) = lbool_of_int (Z3native.get_bool_value (gnc x) (gno x)) @@ -1066,10 +1097,12 @@ struct mk_list f n let get_body ( x : quantifier ) = - expr_of_ptr (gc x) (Z3native.get_quantifier_body (gnc x) (gno x)) + apply_un (gc x) Z3native.get_quantifier_body x let mk_bound ( ctx : context ) ( index : int ) ( ty : Sort.sort ) = - expr_of_ptr ctx (Z3native.mk_bound (context_gno ctx) index (Sort.gno ty)) + let r = expr_of_ptr ctx (Z3native.mk_bound (context_gno ctx) index (Sort.gno ty)) in + ignore ty; + r let mk_pattern ( ctx : context ) ( terms : expr list ) = if (List.length terms) == 0 then @@ -1194,23 +1227,27 @@ struct mk_const ctx (Symbol.mk_string ctx name) domain range let mk_select ( ctx : context ) ( a : expr ) ( i : expr ) = - expr_of_ptr ctx (Z3native.mk_select (context_gno ctx) (Expr.gno a) (Expr.gno i)) + apply_bin ctx Z3native.mk_select a i let mk_store ( ctx : context ) ( a : expr ) ( i : expr ) ( v : expr ) = - expr_of_ptr ctx (Z3native.mk_store (context_gno ctx) (Expr.gno a) (Expr.gno i) (Expr.gno v)) + apply_ter ctx Z3native.mk_store a i v let mk_const_array ( ctx : context ) ( domain : Sort.sort ) ( v : expr ) = - expr_of_ptr ctx (Z3native.mk_const_array (context_gno ctx) (Sort.gno domain) (Expr.gno v)) + let r = expr_of_ptr ctx (Z3native.mk_const_array (context_gno ctx) (Sort.gno domain) (Expr.gno v)) in + ignore2 domain v; + r let mk_map ( ctx : context ) ( f : func_decl ) ( args : expr list ) = let m x = (Expr.gno x) in - expr_of_ptr ctx (Z3native.mk_map (context_gno ctx) (FuncDecl.gno f) (List.length args) (Array.of_list (List.map m args))) + let r = expr_of_ptr ctx (Z3native.mk_map (context_gno ctx) (FuncDecl.gno f) (List.length args) (Array.of_list (List.map m args))) in + ignore2 f args; + r let mk_term_array ( ctx : context ) ( arg : expr ) = - expr_of_ptr ctx (Z3native.mk_array_default (context_gno ctx) (Expr.gno arg)) + apply_un ctx Z3native.mk_array_default arg let mk_array_ext ( ctx : context) ( arg1 : expr ) ( arg2 : expr ) = - expr_of_ptr ctx (Z3native.mk_array_ext (context_gno ctx) (Expr.gno arg1) (Expr.gno arg2)) + apply_bin ctx Z3native.mk_array_ext arg1 arg2 end @@ -1233,13 +1270,15 @@ struct expr_of_ptr ctx (Z3native.mk_full_set (context_gno ctx) (Sort.gno domain)) let mk_set_add ( ctx : context ) ( set : expr ) ( element : expr ) = - expr_of_ptr ctx (Z3native.mk_set_add (context_gno ctx) (Expr.gno set) (Expr.gno element)) + apply_bin ctx Z3native.mk_set_add set element let mk_del ( ctx : context ) ( set : expr ) ( element : expr ) = - expr_of_ptr ctx (Z3native.mk_set_del (context_gno ctx) (Expr.gno set) (Expr.gno element)) + apply_bin Z3native.mk_set_del set element let mk_union ( ctx : context ) ( args : expr list ) = - expr_of_ptr ctx (Z3native.mk_set_union (context_gno ctx) (List.length args) (expr_lton args)) + let r = expr_of_ptr ctx (Z3native.mk_set_union (context_gno ctx) (List.length args) (expr_lton args)) in + ignore r; + r let mk_intersection ( ctx : context ) ( args : expr list ) = expr_of_ptr ctx (Z3native.mk_set_intersect (context_gno ctx) (List.length args) (expr_lton args)) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index ea5bec231..5b5ed1c55 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -42,7 +42,7 @@ zstring::zstring(unsigned num_bits, bool const* ch) { m_encoding = (num_bits == 8)?ascii:unicode; unsigned n = 0; for (unsigned i = 0; i < num_bits; ++i) { - n |= (((unsigned)ch[i]) << num_bits); + n |= (((unsigned)ch[i]) << i); } m_buffer.push_back(n); } @@ -81,12 +81,23 @@ zstring zstring::replace(zstring const& src, zstring const& dst) const { return result; } +static char* esc_table[32] = { "\\0", "^A", "^B", "^C", "^D", "^E", "^F", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "^N", + "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V","^W","^X","^Y","^Z","\\e","^\\","^]","^^","^_"}; + std::string zstring::encode() const { - // TBD apply encodings. SASSERT(m_encoding == ascii); std::ostringstream strm; for (unsigned i = 0; i < m_buffer.size(); ++i) { - strm << (char)(m_buffer[i]); + unsigned char ch = m_buffer[i]; + if (0 <= ch && ch < 32) { + strm << esc_table[ch]; + } + else if (ch == 127) { + strm << "^?"; + } + else { + strm << (char)(ch); + } } return strm.str(); } diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 98d982b7a..16cf18d2e 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -90,7 +90,9 @@ namespace smt { sort * s = m_manager.get_sort(r->get_owner()); model_value_proc * proc = 0; if (m_manager.is_bool(s)) { - SASSERT(m_context->get_assignment(r) == l_true || m_context->get_assignment(r) == l_false); + CTRACE("func_interp_bug", m_context->get_assignment(r) == l_undef, + tout << mk_pp(r->get_owner(), m_manager) << "\n";); + SASSERT(m_context->get_assignment(r) != l_undef); if (m_context->get_assignment(r) == l_true) proc = alloc(expr_wrapper_proc, m_manager.mk_true()); else diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 62e4f4338..79779d088 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -132,6 +132,7 @@ theory_seq::theory_seq(ast_manager& m): m_incomplete(false), m_has_length(false), m_model_completion(false), + m_mg(0), m_rewrite(m), m_util(m), m_autil(m), @@ -181,7 +182,7 @@ final_check_status theory_seq::final_check_eh() { } if (!check_length_coherence_tbd()) { TRACE("seq", tout << "check_length_coherence\n";); - return FC_GIVEUP; + return FC_CONTINUE; } if (is_solved()) { TRACE("seq", tout << "is_solved\n";); @@ -400,15 +401,15 @@ void theory_seq::propagate_lit(enode_pair_dependency* dep, literal lit) { ctx.assign(lit, js); } -void theory_seq::set_conflict(enode_pair_dependency* dep) { +void theory_seq::set_conflict(enode_pair_dependency* dep, literal_vector const& lits) { context& ctx = get_context(); vector _eqs; m_dm.linearize(dep, _eqs); - TRACE("seq", display_deps(tout, dep);); + TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); display_deps(tout, dep); ;); ctx.set_conflict( ctx.mk_justification( ext_theory_conflict_justification( - get_id(), ctx.get_region(), 0, 0, _eqs.size(), _eqs.c_ptr(), 0, 0))); + get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), _eqs.size(), _eqs.c_ptr(), 0, 0))); } void theory_seq::propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2) { @@ -524,6 +525,10 @@ bool theory_seq::is_right_select(expr* a, expr*& b) { to_app(a)->get_decl()->get_parameter(0).get_symbol() == m_right_sym && (b = to_app(a)->get_arg(0), true); } +bool theory_seq::is_head_elem(expr* e) const { + return m_util.is_skolem(e) && to_app(e)->get_decl()->get_parameter(0).get_symbol() == symbol("seq.head.elem"); +} + void theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) { context& ctx = get_context(); m_rep.update(l, r, deps); @@ -583,17 +588,17 @@ bool theory_seq::solve_ne(unsigned idx) { TRACE("seq", display_disequation(tout, n);); SASSERT(!n.is_solved()); + unsigned num_undef_lits = 0; for (unsigned i = 0; i < n.m_lits.size(); ++i) { switch (ctx.get_assignment(n.m_lits[i])) { - case l_true: - erase_lit(idx, i); - --i; - break; case l_false: // mark as solved in mark_solved(idx); return false; + case l_true: + break; case l_undef: + ++num_undef_lits; break; } } @@ -630,29 +635,25 @@ bool theory_seq::solve_ne(unsigned idx) { } else { literal lit(mk_eq(nl, nr, false)); - m_trail_stack.push(push_lit(*this, idx, ~lit)); + m_trail_stack.push(push_lit(*this, idx, lit)); ctx.mark_as_relevant(lit); } } m_trail_stack.push(push_dep(*this, idx, deps)); erase_index(idx, i); --i; + change = true; } } - if (n.m_lits.empty() && n.m_lhs.empty()) { - set_conflict(n.m_dep); + if (num_undef_lits == 0 && n.m_lhs.empty()) { + literal_vector lits(n.m_lits); + lits.push_back(~mk_eq(n.m_l, n.m_r, false)); + set_conflict(n.m_dep, lits); return true; } return change; } -void theory_seq::erase_lit(unsigned idx, unsigned i) { - ne const& n = m_nqs[idx]; - if (n.m_lits.size() < i + 1) { - m_trail_stack.push(set_lit(*this, idx, i, n.m_lits.back())); - } - m_trail_stack.push(pop_lit(*this, idx)); -} void theory_seq::mark_solved(unsigned idx) { m_trail_stack.push(solved_ne(*this, idx)); @@ -810,8 +811,12 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { enode_pair_dependency* deps = 0; expr_ref e(n->get_owner(), m); flet _model_completion(m_model_completion, true); + m_rep.reset_cache(); + m_mg = &mg; e = canonize(e, deps); + m_mg = 0; SASSERT(is_app(e)); + TRACE("seq", tout << mk_pp(n->get_owner(), m) << " -> " << e << "\n";); m_factory->add_trail(e); return alloc(expr_wrapper_proc, to_app(e)); } @@ -852,15 +857,17 @@ expr_ref theory_seq::canonize(expr* e, enode_pair_dependency*& eqs) { return result; } -expr_ref theory_seq::expand(expr* e, enode_pair_dependency*& eqs) { +expr_ref theory_seq::expand(expr* e0, enode_pair_dependency*& eqs) { + expr_ref result(m); enode_pair_dependency* deps = 0; expr_dep ed; - if (m_rep.find_cache(e, ed)) { + if (m_rep.find_cache(e0, ed)) { eqs = m_dm.mk_join(eqs, ed.second); - return expr_ref(ed.first, m); + result = ed.first; + TRACE("seq", tout << mk_pp(e0, m) << " |-> " << result << " "; display_deps(tout, eqs);); + return result; } - e = m_rep.find(e, deps); - expr_ref result(m); + expr* e = m_rep.find(e0, deps); expr* e1, *e2; if (m_util.str.is_concat(e, e1, e2)) { result = m_util.str.mk_concat(expand(e1, deps), expand(e2, deps)); @@ -889,15 +896,43 @@ expr_ref theory_seq::expand(expr* e, enode_pair_dependency*& eqs) { result = e; } } + else if (m_model_completion && m_util.str.is_unit(e, e1)) { + result = expand(e1, deps); + bv_util bv(m); + rational val; + unsigned sz; + if (bv.is_numeral(result, val, sz) && sz == zstring().num_bits()) { + svector val_as_bits; + for (unsigned i = 0; i < sz; ++i) { + val_as_bits.push_back(!val.is_even()); + val = div(val, rational(2)); + } + result = m_util.str.mk_string(zstring(sz, val_as_bits.c_ptr())); + } + else { + result = m_util.str.mk_unit(result); + } + } + else if (m_model_completion && is_head_elem(e)) { + enode* n = get_context().get_enode(e)->get_root(); + result = n->get_owner(); + if (!m.is_model_value(result)) { + result = m_mg->get_some_value(m.get_sort(result)); + } + m_rep.update(e, result, 0); + TRACE("seq", tout << mk_pp(e, m) << " |-> " << result << "\n";); + } else { result = e; } - if (result == e) { + if (result == e0) { deps = 0; } expr_dep edr(result, deps); - m_rep.add_cache(e, edr); + m_rep.add_cache(e0, edr); eqs = m_dm.mk_join(eqs, deps); + TRACE("seq", tout << mk_pp(e0, m) << " |--> " << result << "\n"; + display_deps(tout, eqs);); return result; } @@ -1116,8 +1151,9 @@ void theory_seq::add_length_concat_axiom(expr* n) { expr_ref len(m_util.str.mk_length(n), m); expr_ref _a(m_util.str.mk_length(a), m); expr_ref _b(m_util.str.mk_length(b), m); - expr_ref a_p_b(m_autil.mk_add(_a, _b), m); - add_axiom(mk_eq(len, a_p_b, false)); + expr_ref ab(m_autil.mk_add(_a, _b), m); + m_rewrite(ab); + add_axiom(mk_eq(ab, len, false)); } /* @@ -1144,8 +1180,10 @@ void theory_seq::add_length_axiom(expr* n) { } } -expr* theory_seq::mk_sub(expr* a, expr* b) { - return m_autil.mk_add(a, m_autil.mk_mul(m_autil.mk_int(-1), b)); +expr_ref theory_seq::mk_sub(expr* a, expr* b) { + expr_ref result(m_autil.mk_sub(a, b), m); + m_rewrite(result); + return result; } enode* theory_seq::ensure_enode(expr* e) { @@ -1325,7 +1363,7 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { enode* n2 = get_enode(v2); expr_ref e1(n1->get_owner(), m); expr_ref e2(n2->get_owner(), m); - m_nqs.push_back(ne(e1, e2, m_dm.mk_leaf(enode_pair(n1, n2)))); + m_nqs.push_back(ne(e1, e2)); m_exclude.update(e1, e2); } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 59ae5095a..21aabb599 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -70,6 +70,7 @@ namespace smt { bool find_cache(expr* v, expr_dep& r) { return m_cache.find(v, r); } expr* find(expr* e, enode_pair_dependency*& d); void cache(expr* e, expr* r, enode_pair_dependency* d); + void reset_cache() { m_cache.reset(); } void push_scope() { m_limit.push_back(m_updates.size()); } void pop_scope(unsigned num_scopes); void display(std::ostream& out) const; @@ -108,19 +109,22 @@ namespace smt { // asserted or derived disqequality with dependencies struct ne { bool m_solved; + expr_ref m_l, m_r; expr_ref_vector m_lhs; expr_ref_vector m_rhs; literal_vector m_lits; enode_pair_dependency* m_dep; - ne(expr_ref& l, expr_ref& r, enode_pair_dependency* d): - m_solved(false), m_lhs(l.get_manager()), m_rhs(r.get_manager()), m_dep(d) { + ne(expr_ref& l, expr_ref& r): + m_solved(false), m_l(l), m_r(r), m_lhs(l.get_manager()), m_rhs(r.get_manager()), m_dep(0) { m_lhs.push_back(l); m_rhs.push_back(r); } ne(ne const& other): - m_solved(other.m_solved), m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_lits(other.m_lits), m_dep(other.m_dep) {} + m_solved(other.m_solved), m_l(other.m_l), m_r(other.m_r), m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_lits(other.m_lits), m_dep(other.m_dep) {} ne& operator=(ne const& other) { m_solved = other.m_solved; + m_l = other.m_l; + m_r = other.m_r; m_lhs.reset(); m_lhs.append(other.m_lhs); m_rhs.reset(); m_rhs.append(other.m_rhs); m_lits.reset(); m_lits.append(other.m_lits); @@ -158,7 +162,6 @@ namespace smt { } virtual void undo(theory_seq & th) { th.m_nqs.ref(m_idx).m_lits[m_i] = m_lit; } }; - void erase_lit(unsigned idx, unsigned i); class solved_ne : public trail { unsigned m_idx; @@ -255,6 +258,7 @@ namespace smt { bool m_incomplete; // is the solver (clearly) incomplete for the fragment. bool m_has_length; // is length applied bool m_model_completion; // during model construction, invent values in canonizer + model_generator* m_mg; th_rewriter m_rewrite; seq_util m_util; arith_util m_autil; @@ -313,7 +317,7 @@ namespace smt { void propagate_lit(enode_pair_dependency* dep, literal lit); void propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2); void propagate_eq(bool_var v, expr* e1, expr* e2); - void set_conflict(enode_pair_dependency* dep); + void set_conflict(enode_pair_dependency* dep, literal_vector const& lits = literal_vector()); bool find_branch_candidate(expr* l, expr_ref_vector const& rs); bool assume_equality(expr* l, expr* r); @@ -324,6 +328,7 @@ namespace smt { void add_solution(expr* l, expr* r, enode_pair_dependency* dep); bool is_left_select(expr* a, expr*& b); bool is_right_select(expr* a, expr*& b); + bool is_head_elem(expr* a) const; expr_ref canonize(expr* e, enode_pair_dependency*& eqs); expr_ref expand(expr* e, enode_pair_dependency*& eqs); void add_dependency(enode_pair_dependency*& dep, enode* a, enode* b); @@ -345,7 +350,7 @@ namespace smt { void add_at_axiom(expr* n); literal mk_literal(expr* n); void tightest_prefix(expr* s, expr* x, literal lit, literal lit2 = null_literal); - expr* mk_sub(expr* a, expr* b); + expr_ref mk_sub(expr* a, expr* b); enode* ensure_enode(expr* a); expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2 = 0, expr* e3 = 0, sort* range = 0); From f4148694563af27f27050fe34b7e0513a8dba98b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Dec 2015 19:46:10 -0800 Subject: [PATCH 23/87] add symbolic automaton Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 3 +- src/ast/rewriter/seq_rewriter.cpp | 59 ++++-- src/ast/seq_decl_plugin.cpp | 5 + src/math/automata/automaton.cpp | 23 +++ src/math/automata/automaton.h | 295 ++++++++++++++++++++++++++++++ src/smt/smt_context.cpp | 4 +- src/smt/theory_seq.cpp | 68 ++++++- src/smt/theory_seq.h | 3 +- 8 files changed, 428 insertions(+), 32 deletions(-) create mode 100644 src/math/automata/automaton.cpp create mode 100644 src/math/automata/automaton.h diff --git a/scripts/mk_project.py b/scripts/mk_project.py index eb7218d4b..08986d96b 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -16,11 +16,12 @@ def init_project_def(): add_lib('nlsat', ['polynomial', 'sat']) add_lib('hilbert', ['util'], 'math/hilbert') add_lib('simplex', ['util'], 'math/simplex') + add_lib('automata', ['util'], 'math/automata') add_lib('interval', ['util'], 'math/interval') add_lib('realclosure', ['interval'], 'math/realclosure') add_lib('subpaving', ['interval'], 'math/subpaving') add_lib('ast', ['util', 'polynomial']) - add_lib('rewriter', ['ast', 'polynomial'], 'ast/rewriter') + add_lib('rewriter', ['ast', 'polynomial', 'automata'], 'ast/rewriter') add_lib('normal_forms', ['rewriter'], 'ast/normal_forms') add_lib('model', ['rewriter']) add_lib('tactic', ['ast', 'model']) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index d7ac3ff67..41c20f599 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -22,6 +22,7 @@ Notes: #include"ast_pp.h" #include"ast_util.h" #include"uint_set.h" +#include"automaton.h" br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { @@ -30,22 +31,38 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con switch(f->get_decl_kind()) { case OP_SEQ_UNIT: - case OP_SEQ_EMPTY: - - case OP_RE_PLUS: - case OP_RE_STAR: - case OP_RE_OPTION: - case OP_RE_RANGE: - case OP_RE_CONCAT: - case OP_RE_UNION: - case OP_RE_INTERSECT: - case OP_RE_LOOP: - case OP_RE_EMPTY_SET: - case OP_RE_FULL_SET: - case OP_RE_OF_PRED: - case _OP_SEQ_SKOLEM: return BR_FAILED; - + case OP_SEQ_EMPTY: + return BR_FAILED; + case OP_RE_PLUS: + SASSERT(num_args == 1); + return mk_re_plus(args[0], result); + case OP_RE_STAR: + SASSERT(num_args == 1); + return mk_re_star(args[0], result); + case OP_RE_OPTION: + SASSERT(num_args == 1); + return mk_re_opt(args[0], result); + case OP_RE_CONCAT: + SASSERT(num_args == 2); + return mk_re_concat(args[0], args[1], result); + case OP_RE_UNION: + SASSERT(num_args == 2); + return mk_re_union(args[0], args[1], result); + case OP_RE_RANGE: + return BR_FAILED; + case OP_RE_INTERSECT: + return BR_FAILED; + case OP_RE_LOOP: + return BR_FAILED; + case OP_RE_EMPTY_SET: + return BR_FAILED; + case OP_RE_FULL_SET: + return BR_FAILED; + case OP_RE_OF_PRED: + return BR_FAILED; + case _OP_SEQ_SKOLEM: + return BR_FAILED; case OP_SEQ_CONCAT: if (num_args == 1) { result = args[0]; @@ -83,10 +100,11 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con SASSERT(num_args == 3); return mk_seq_replace(args[0], args[1], args[2], result); case OP_SEQ_TO_RE: - return BR_FAILED; + SASSERT(num_args == 1); + return mk_str_to_regexp(args[0], result); case OP_SEQ_IN_RE: - return BR_FAILED; - + SASSERT(num_args == 2); + return mk_str_in_regexp(args[0], args[1], result); case OP_STRING_CONST: return BR_FAILED; case OP_STRING_ITOS: @@ -499,7 +517,10 @@ br_status seq_rewriter::mk_re_plus(expr* a, expr_ref& result) { return BR_FAILED; } br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) { - return BR_FAILED; + sort* s; + VERIFY(m_util.is_re(a, s)); + result = m_util.re.mk_union(m_util.re.mk_to_re(m_util.str.mk_empty(s)), a); + return BR_REWRITE1; } br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) { diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 5b5ed1c55..10e9c00a5 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -629,6 +629,11 @@ app* seq_util::str::mk_char(zstring const& s, unsigned idx) { return bvu.mk_numeral(s[idx], s.num_bits()); } +app* seq_util::str::mk_char(char ch) { + zstring s(ch, zstring::ascii); + return mk_char(s, 0); +} + bool seq_util::str::is_char(expr* n, zstring& c) const { if (u.is_char(n)) { c = zstring(to_app(n)->get_decl()->get_parameter(0).get_symbol().bare_str()); diff --git a/src/math/automata/automaton.cpp b/src/math/automata/automaton.cpp new file mode 100644 index 000000000..ab908525e --- /dev/null +++ b/src/math/automata/automaton.cpp @@ -0,0 +1,23 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + automaton.cpp + +Abstract: + + Symbolic Automaton, a la Margus Veanes Automata library. + +Author: + + Nikolaj Bjorner (nbjorner) 2015-12-23. + +Revision History: + + +--*/ + +#include "automaton.h" + +template class automaton; diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h new file mode 100644 index 000000000..e28db8fa0 --- /dev/null +++ b/src/math/automata/automaton.h @@ -0,0 +1,295 @@ +/*++ +Copyright (c) 2015 Microsoft Corporation + +Module Name: + + automaton.h + +Abstract: + + Symbolic Automaton, a la Margus Veanes Automata library. + +Author: + + Nikolaj Bjorner (nbjorner) 2015-12-23. + +Revision History: + + +--*/ + +#ifndef AUTOMATON_H_ +#define AUTOMATON_H_ + + +#include "util.h" +#include "vector.h" +#include "uint_set.h" + +template +class automaton { + class move { + T* m_t; + unsigned m_src; + unsigned m_dst; + public: + move(unsigned s, unsigned d, T* t = 0): m_t(t), m_src(s), m_dst(d) {} + + unsigned dst() const { return m_dst; } + unsigned src() const { return m_src; } + T* t() const { return m_t; } + + bool is_epsilon() const { return m_t == 0; } + }; + typedef svector moves; + + + svector m_delta; + svector m_delta_inv; + unsigned m_init; + uint_set m_final_set; + unsigned_vector m_final_states; + bool m_is_epsilon_free; + bool m_is_deterministic; + + + // local data-structures + mutable uint_set m_visited; + mutable unsigned_vector m_todo; + + +public: + + // The empty automaton: + automaton(): + m_init(0), + m_is_epsilon_free(true), + m_is_deterministic(true) + { + m_delta.push_back(moves()); + m_delta_inv.push_back(moves()); + } + + + // create an automaton from initial state, final states, and moves + automaton(unsigned init, unsigned_vector const& final, moves const& mvs) { + m_is_epsilon_free = true; + m_is_deterministic = true; + m_init = init; + for (unsigned i = 0; i < final.size(); ++i) { + m_final_states.push_back(final[i]); + m_final_set.insert(final[i]); + } + for (unsigned i = 0; i < mvs.size(); ++i) { + move const& mv = mvs[i]; + unsigned n = std::max(mv.src(), mv.dst()); + if (n >= m_delta.size()) { + m_delta.resize(n+1, moves()); + m_delta_inv.resize(n+1, moves()); + } + m_delta[mv.src()].push_back(mv); + m_delta_inv[mv.dst()].push_back(mv); + m_is_deterministic &= m_delta[mv.src()].size() < 2; + m_is_epsilon_free &= !mv.is_epsilon(); + } + } + + // The automaton with a single state that is also final. + automaton(T* t, unsigned s = 0): + m_init(s) { + m_delta.resize(s+1, moves()); + m_delta_inv.resize(s+1, moves()); + m_final_set.insert(s); + m_final_states.push_back(s); + m_delta[s].push_back(move(s, s, t)); + m_delta_inv[s].push_back(move(s, s, t)); + } + + automaton(automaton const& other): + m_delta(other.m_delta), + m_delta_inv(other.m_delta_inv), + m_init(other.m_init), + m_final_set(other.m_final_set), + m_final_states(other.m_final_states), + m_is_epsilon_free(other.m_is_epsilon_free), + m_is_deterministic(other.m_is_deterministic) + {} + + // create the automaton that accepts the empty string only. + static automaton mk_epsilon() { + moves mvs; + unsigned_vector final; + final.push_back(0); + return automaton(0, final, mvs); + } + + // create the automaton with a single state on condition t. + static automaton mk_loop(T* t) { + moves mvs; + unsigned_vector final; + final.push_back(0); + mvs.push_back(move(0, 0, t)); + return automaton(0, final, mvs); + } + + // create the sum of disjoint automata + static automaton mk_union(automaton const& a, automaton const& b) { + moves mvs; + unsigned_vector final; + unsigned offset1 = 1; + unsigned offset2 = a.num_states() + 1; + mvs.push_back(move(0, a.init() + offset1, 0)); + mvs.push_back(move(0, b.init() + offset2, 0)); + append_moves(offset1, a, mvs); + append_moves(offset2, b, mvs); + append_final(offset1, a, final); + append_final(offset2, b, final); + return automaton(0, final, mvs); + } + + static automaton mk_reverse(automaton const& a) { + if (a.is_empty()) { + return automaton(); + } + moves mvs; + for (unsigned i = 0; i < a.m_delta.size(); ++i) { + moves const& mvs1 = a.m_delta[i]; + for (unsigned j = 0; j < mvs1.size(); ++j) { + move const& mv = mvs1[j]; + mvs.push_back(move(mv.dst(), mv.src(), mv.t())); + } + } + unsigned_vector final; + unsigned init; + final.push_back(a.init()); + if (a.m_final_states.size() == 1) { + init = a.m_final_states[0]; + } + else { + init = a.num_states(); + for (unsigned i = 0; i < a.m_final_states.size(); ++i) { + mvs.push_back(move(init, a.m_final_states[i])); + } + } + return automaton(init, final, mvs); + } + + bool is_sequence(unsigned& length) const { + if (is_final_state(m_init) && (out_degree(m_init) == 0 || (out_degree(m_init) == 1 && is_loop_state(m_init)))) { + length = 0; + return true; + } + if (is_empty() || in_degree(m_init) != 0 || out_degree(m_init) != 1) { + return false; + } + + length = 1; + unsigned s = get_move_from(m_init).dst(); + while (!is_final_state(s)) { + if (out_degree(s) != 1 || in_degree(s) != 1) { + return false; + } + s = get_move_from(s).dst(); + ++length; + } + return out_degree(s) == 0 || (out_degree(s) == 1 && is_loop_state(s)); + } + + unsigned init() const { return m_init; } + unsigned in_degree(unsigned state) const { return m_delta_inv[state].size(); } + unsigned out_degree(unsigned state) const { return m_delta[state].size(); } + move const& get_move_from(unsigned state) const { SASSERT(m_delta[state].size() == 1); return m_delta[state][0]; } + move const& get_move_to(unsigned state) const { SASSERT(m_delta_inv[state].size() == 1); return m_delta_inv[state][0]; } + moves const& get_moves_from(unsigned state) const { return m_delta[state]; } + moves const& get_moves_to(unsigned state) const { return m_delta_inv[state]; } + bool initial_state_is_source() const { return m_delta_inv[m_init].empty(); } + bool is_final_state(unsigned s) const { return m_final_set.contains(s); } + bool is_epsilon_free() const { return m_is_epsilon_free; } + bool is_deterministic() const { return m_is_deterministic; } + bool is_empty() const { return m_final_states.empty(); } + unsigned final_state() const { return m_final_states[0]; } + bool has_single_final_sink() const { return m_final_states.size() == 1 && m_delta[final_state()].empty(); } + unsigned num_states() const { return m_delta.size(); } + bool is_loop_state(unsigned s) const { + moves mvs; + get_moves_from(s, mvs); + for (unsigned i = 0; i < mvs.size(); ++i) { + if (s == mvs[i].dst()) return true; + } + return false; + } + + unsigned move_count() const { + unsigned result = 0; + for (unsigned i = 0; i < m_delta.size(); result += m_delta[i].size(), ++i) {} + return result; + } + void get_epsilon_closure(unsigned state, unsigned_vector& states) { + get_epsilon_closure(state, m_delta, states); + } + void get_inv_epsilon_closure(unsigned state, unsigned_vector& states) { + get_epsilon_closure(state, m_delta_inv, states); + } + void get_moves_from(unsigned state, moves& mvs) const { + get_moves(state, m_delta, mvs); + } + void get_moves_to(unsigned state, moves& mvs) { + get_moves(state, m_delta_inv, mvs); + } +private: + void get_moves(unsigned state, svector const& delta, moves& mvs) const { + unsigned_vector states; + get_epsilon_closure(state, delta, states); + for (unsigned i = 0; i < states.size(); ++i) { + state = states[i]; + moves const& mv1 = delta[state]; + for (unsigned j = 0; j < mv1.size(); ++j) { + if (!mv1[j].is_epsilon()) { + mvs.push_back(mv1[j]); + } + } + } + } + + void get_epsilon_closure(unsigned state, svector const& delta, unsigned_vector& states) const { + m_todo.push_back(state); + m_visited.insert(state); + while (!m_todo.empty()) { + state = m_todo.back(); + states.push_back(state); + m_todo.pop_back(); + moves const& mvs = delta[state]; + for (unsigned i = 0; i < mvs.size(); ++i) { + unsigned tgt = mvs[i].dst(); + if (mvs[i].is_epsilon() && !m_visited.contains(tgt)) { + m_visited.insert(tgt); + m_todo.push_back(tgt); + } + } + } + m_visited.reset(); + SASSERT(m_todo.empty()); + } + + static void append_moves(unsigned offset, automaton const& a, moves& mvs) { + for (unsigned i = 0; i < a.num_states(); ++i) { + moves const& mvs1 = a.m_delta[i]; + for (unsigned j = 0; j < mvs1.size(); ++j) { + move const& mv = mvs1[j]; + mvs.push_back(move(mv.src() + offset, mv.dst() + offset, mv.t())); + } + } + } + + static void append_final(unsigned offset, automaton const& a, unsigned_vector& final) { + for (unsigned i = 0; i < a.m_final_states.size(); ++i) { + final.push_back(a.m_final_states[i]+offset); + } + } + +}; + +typedef automaton uautomaton; + + +#endif diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 26ca2e68a..738763c88 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1382,7 +1382,8 @@ namespace smt { bool_var v = l.var(); bool_var_data & d = get_bdata(v); lbool val = get_assignment(v); - TRACE("propagate_atoms", tout << "propagating atom, #" << bool_var2expr(v)->get_id() << ", is_enode(): " << d.is_enode() << " " << l << "\n";); + TRACE("propagate_atoms", tout << "propagating atom, #" << bool_var2expr(v)->get_id() << ", is_enode(): " << d.is_enode() + << " tag: " << (d.is_eq()?"eq":"") << (d.is_theory_atom()?"th":"") << (d.is_quantifier()?"q":"") << " " << l << "\n";); SASSERT(val != l_undef); if (d.is_enode()) propagate_bool_var_enode(v); @@ -1404,6 +1405,7 @@ namespace smt { else if (d.is_theory_atom()) { theory * th = m_theories.get_plugin(d.get_theory()); SASSERT(th); + TRACE("seq", tout << d.get_theory() << "\n";); th->assign_eh(v, val == l_true); } else if (d.is_quantifier()) { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 79779d088..1cae448b2 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -125,6 +125,7 @@ theory_seq::theory_seq(ast_manager& m): m_rep(m, m_dm), m_factory(0), m_ineqs(m), + m_in_re(m), m_exclude(m), m_axioms(m), m_axioms_head(0), @@ -379,6 +380,9 @@ bool theory_seq::is_solved() { if (!check_ineq_coherence()) { return false; } + if (!m_in_re.empty()) { + return false; + } SASSERT(check_length_coherence()); @@ -572,7 +576,6 @@ bool theory_seq::solve_nqs() { bool change = false; context & ctx = get_context(); for (unsigned i = 0; !ctx.inconsistent() && i < m_nqs.size(); ++i) { - TRACE("seq", tout << i << " " << m_nqs.size() << "\n";); if (!m_nqs[i].is_solved()) { change = solve_ne(i) || change; } @@ -637,6 +640,16 @@ bool theory_seq::solve_ne(unsigned idx) { literal lit(mk_eq(nl, nr, false)); m_trail_stack.push(push_lit(*this, idx, lit)); ctx.mark_as_relevant(lit); + switch (ctx.get_assignment(lit)) { + case l_false: + mark_solved(idx); + return false; + case l_true: + break; + case l_undef: + ++num_undef_lits; + break; + } } } m_trail_stack.push(push_dep(*this, idx, deps)); @@ -696,6 +709,8 @@ bool theory_seq::internalize_term(app* term) { if (m.is_bool(term)) { bool_var bv = ctx.mk_bool_var(term); ctx.set_var_theory(bv, get_id()); + ctx.mark_as_relevant(bv); + TRACE("seq", tout << mk_pp(term, m) << ": " << bv << "\n";); } else { enode* e = 0; @@ -751,6 +766,12 @@ void theory_seq::display(std::ostream & out) const { out << mk_pp(m_ineqs[i], m) << "\n"; } } + if (!m_in_re.empty()) { + out << "Regex\n"; + for (unsigned i = 0; i < m_in_re.size(); ++i) { + out << mk_pp(m_in_re[i], m) << "\n"; + } + } if (!m_rep.empty()) { out << "Solved equations:\n"; m_rep.display(out); @@ -917,7 +938,12 @@ expr_ref theory_seq::expand(expr* e0, enode_pair_dependency*& eqs) { enode* n = get_context().get_enode(e)->get_root(); result = n->get_owner(); if (!m.is_model_value(result)) { - result = m_mg->get_some_value(m.get_sort(result)); + if (m_util.is_char(result)) { + result = m_util.str.mk_char('#'); + } + else { + result = m_mg->get_some_value(m.get_sort(result)); + } } m_rep.update(e, result, 0); TRACE("seq", tout << mk_pp(e, m) << " |-> " << result << "\n";); @@ -1288,13 +1314,16 @@ expr_ref theory_seq::mk_skolem(symbol const& name, expr* e1, void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) { context& ctx = get_context(); - TRACE("seq", - tout << mk_pp(ctx.bool_var2enode(v)->get_owner(), m) << " => " - << mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";); SASSERT(ctx.e_internalized(e2)); enode* n1 = ensure_enode(e1); enode* n2 = ensure_enode(e2); + if (n1->get_root() == n2->get_root()) { + return; + } + TRACE("seq", + tout << mk_pp(ctx.bool_var2enode(v)->get_owner(), m) << " => " + << mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";); literal lit(v); justification* js = ctx.mk_justification( @@ -1304,10 +1333,9 @@ void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) { ctx.assign_eq(n1, n2, eq_justification(js)); } -void theory_seq::assign_eq(bool_var v, bool is_true) { +void theory_seq::assign_eh(bool_var v, bool is_true) { context & ctx = get_context(); - enode* n = ctx.bool_var2enode(v); - app* e = n->get_owner(); + expr* e = ctx.bool_var2expr(v); if (is_true) { expr* e1, *e2; expr_ref f(m); @@ -1327,8 +1355,10 @@ void theory_seq::assign_eq(bool_var v, bool is_true) { f = m_util.str.mk_concat(m_util.str.mk_concat(f1, e2), f2); propagate_eq(v, f, e1); } - else if (m_util.str.is_in_re(e, e1, e2)) { - // TBD + else if (m_util.str.is_in_re(e)) { + TRACE("seq", tout << "in re: " << mk_pp(e, m) << "\n";); + m_trail_stack.push(push_back_vector(m_in_re)); + m_in_re.push_back(e); } else { UNREACHABLE(); @@ -1403,4 +1433,22 @@ void theory_seq::relevant_eh(app* n) { m_util.str.is_string(n)) { enque_axiom(n); } + if (m_util.str.is_in_re(n) || + m_util.str.is_contains(n) || + m_util.str.is_suffix(n) || + m_util.str.is_prefix(n)) { + context& ctx = get_context(); + TRACE("seq", tout << mk_pp(n, m) << "\n";); + bool_var bv = ctx.get_bool_var(n); + switch (ctx.get_assignment(bv)) { + case l_false: + assign_eh(bv, false); + break; + case l_true: + assign_eh(bv, true); + break; + case l_undef: + break; + } + } } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 21aabb599..43852a086 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -251,6 +251,7 @@ namespace smt { seq_factory* m_factory; // value factory expr_ref_vector m_ineqs; // inequalities to check solution against + expr_ref_vector m_in_re; // regular expression membership exclusion_table m_exclude; // set of asserted disequalities. expr_ref_vector m_axioms; // list of axioms to add. unsigned m_axioms_head; // index of first axiom to add. @@ -277,7 +278,7 @@ namespace smt { virtual void internalize_eq_eh(app * atom, bool_var v); virtual void new_eq_eh(theory_var, theory_var); virtual void new_diseq_eh(theory_var, theory_var); - virtual void assign_eq(bool_var v, bool is_true); + virtual void assign_eh(bool_var v, bool is_true); virtual bool can_propagate(); virtual void propagate(); virtual void push_scope_eh(); From 2a7f2ab7f8fbd060c2a8dd7dfb9e3ca11504596f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 Dec 2015 20:33:55 -0800 Subject: [PATCH 24/87] sequence automaton Signed-off-by: Nikolaj Bjorner --- src/math/automata/automaton.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index e28db8fa0..7a224b5d4 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -94,9 +94,25 @@ public: } } + // create an automaton that accepts a sequence. + automaton(ptr_vector const& seq): + m_init(0), + m_is_epsilon_free(true), + m_is_deterministic(true) { + m_delta.resize(seq.size()+1, moves()); + m_delta_inv.resize(seq.size()+1, moves()); + for (unsigned i = 0; i < seq.size(); ++i) { + m_delta[i].push_back(move(i, i + 1, seq[i])); + m_delta[i + 1].push_back(move(i, i + 1, seq[i])); + } + m_final_states.push_back(seq.size()); + m_final_set.insert(seq.size()); + } + // The automaton with a single state that is also final. - automaton(T* t, unsigned s = 0): - m_init(s) { + automaton(T* t): + m_init(0) { + unsigned s = 0; m_delta.resize(s+1, moves()); m_delta_inv.resize(s+1, moves()); m_final_set.insert(s); From 1bbf7813b04be6621b9f27c89d27d36c98ffd2da Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Dec 2015 03:30:02 -0800 Subject: [PATCH 25/87] automata Signed-off-by: Nikolaj Bjorner --- src/math/automata/automaton.h | 186 +++++++++++++++++++++++++++------- src/smt/theory_seq.cpp | 91 ++++++++++++++++- src/smt/theory_seq.h | 12 +++ 3 files changed, 250 insertions(+), 39 deletions(-) diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index 7a224b5d4..cc9fe2c02 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -27,13 +27,42 @@ Revision History: #include "uint_set.h" template +class default_value_manager { +public: + void inc_ref(T* t) {} + void dec_ref(T* t) {} +}; + +template > class automaton { +public: class move { + M& m; T* m_t; unsigned m_src; unsigned m_dst; public: - move(unsigned s, unsigned d, T* t = 0): m_t(t), m_src(s), m_dst(d) {} + move(M& m, unsigned s, unsigned d, T* t = 0): m(m), m_t(t), m_src(s), m_dst(d) { + if (t) m.inc_ref(t); + } + ~move() { + if (m_t) m.dec_ref(m_t); + } + + move(move const& other): m(other.m), m_t(other.m_t), m_src(other.m_src), m_dst(other.m_dst) { + if (m_t) m.inc_ref(m_t); + } + + move& operator=(move const& other) { + SASSERT(&m == &other.m); + T* t = other.m_t; + if (t) m.inc_ref(t); + if (m_t) m.dec_ref(m_t); + m_t = t; + m_src = other.m_src; + m_dst = other.m_dst; + return *this; + } unsigned dst() const { return m_dst; } unsigned src() const { return m_src; } @@ -41,11 +70,11 @@ class automaton { bool is_epsilon() const { return m_t == 0; } }; - typedef svector moves; - - - svector m_delta; - svector m_delta_inv; + typedef vector moves; +private: + M& m; + vector m_delta; + vector m_delta_inv; unsigned m_init; uint_set m_final_set; unsigned_vector m_final_states; @@ -57,11 +86,11 @@ class automaton { mutable uint_set m_visited; mutable unsigned_vector m_todo; - public: // The empty automaton: - automaton(): + automaton(M& m): + m(m), m_init(0), m_is_epsilon_free(true), m_is_deterministic(true) @@ -72,7 +101,7 @@ public: // create an automaton from initial state, final states, and moves - automaton(unsigned init, unsigned_vector const& final, moves const& mvs) { + automaton(M& m, unsigned init, unsigned_vector const& final, moves const& mvs): m(m) { m_is_epsilon_free = true; m_is_deterministic = true; m_init = init; @@ -95,33 +124,35 @@ public: } // create an automaton that accepts a sequence. - automaton(ptr_vector const& seq): + automaton(M& m, ptr_vector const& seq): + m(m), m_init(0), m_is_epsilon_free(true), m_is_deterministic(true) { m_delta.resize(seq.size()+1, moves()); m_delta_inv.resize(seq.size()+1, moves()); for (unsigned i = 0; i < seq.size(); ++i) { - m_delta[i].push_back(move(i, i + 1, seq[i])); - m_delta[i + 1].push_back(move(i, i + 1, seq[i])); + m_delta[i].push_back(move(m, i, i + 1, seq[i])); + m_delta[i + 1].push_back(move(m, i, i + 1, seq[i])); } m_final_states.push_back(seq.size()); m_final_set.insert(seq.size()); } - // The automaton with a single state that is also final. - automaton(T* t): + // The automaton that accepts t + automaton(M& m, T* t): + m(m), m_init(0) { - unsigned s = 0; - m_delta.resize(s+1, moves()); - m_delta_inv.resize(s+1, moves()); - m_final_set.insert(s); - m_final_states.push_back(s); - m_delta[s].push_back(move(s, s, t)); - m_delta_inv[s].push_back(move(s, s, t)); + m_delta.resize(2, moves()); + m_delta_inv.resize(2, moves()); + m_final_set.insert(1); + m_final_states.push_back(1); + m_delta[0].push_back(move(m, 0, 1, t)); + m_delta_inv[1].push_back(move(m, 0, 1, t)); } automaton(automaton const& other): + m(other.m), m_delta(other.m_delta), m_delta_inv(other.m_delta_inv), m_init(other.m_init), @@ -132,47 +163,78 @@ public: {} // create the automaton that accepts the empty string only. - static automaton mk_epsilon() { + static automaton* mk_epsilon(M& m) { moves mvs; unsigned_vector final; final.push_back(0); - return automaton(0, final, mvs); + return alloc(automaton, m, 0, final, mvs); } // create the automaton with a single state on condition t. - static automaton mk_loop(T* t) { + static automaton* mk_loop(M& m, T* t) { moves mvs; unsigned_vector final; final.push_back(0); - mvs.push_back(move(0, 0, t)); - return automaton(0, final, mvs); + mvs.push_back(move(m, 0, 0, t)); + return alloc(automaton, m, 0, final, mvs); } // create the sum of disjoint automata - static automaton mk_union(automaton const& a, automaton const& b) { + static automaton* mk_union(automaton const& a, automaton const& b) { + SASSERT(&a.m == &b.m); + M& m = a.m; moves mvs; unsigned_vector final; unsigned offset1 = 1; unsigned offset2 = a.num_states() + 1; - mvs.push_back(move(0, a.init() + offset1, 0)); - mvs.push_back(move(0, b.init() + offset2, 0)); + mvs.push_back(move(m, 0, a.init() + offset1, 0)); + mvs.push_back(move(m, 0, b.init() + offset2, 0)); append_moves(offset1, a, mvs); append_moves(offset2, b, mvs); append_final(offset1, a, final); append_final(offset2, b, final); - return automaton(0, final, mvs); + return alloc(automaton, m, 0, final, mvs); } - static automaton mk_reverse(automaton const& a) { + // concatenate accepting languages + static automaton* mk_concat(automaton const& a, automaton const& b) { + SASSERT(&a.m == &b.m); + M& m = a.m; + moves mvs; + unsigned_vector final; + unsigned init = 0; + if (a.has_single_final_sink() && b.initial_state_is_source() && b.init() == 0) { + unsigned offset2 = a.num_states(); + init = a.init(); + append_moves(0, a, mvs); + append_moves(offset2, b, mvs); + append_final(offset2, b, final); + } + else { + unsigned offset1 = 1; + unsigned offset2 = a.num_states() + offset1; + mvs.push_back(move(m, 0, a.init() + offset1)); + append_moves(offset1, a, mvs); + for (unsigned i = 0; i < a.m_final_states.size(); ++i) { + mvs.push_back(move(m, a.m_final_states[i], b.init())); + } + append_moves(offset2, b, mvs); + append_final(offset2, b, final); + } + return alloc(automaton, m, init, final, mvs); + } + + static automaton* mk_reverse(automaton const& a) { + M& m = a.m; if (a.is_empty()) { - return automaton(); + return alloc(automaton, m); } moves mvs; for (unsigned i = 0; i < a.m_delta.size(); ++i) { moves const& mvs1 = a.m_delta[i]; for (unsigned j = 0; j < mvs1.size(); ++j) { move const& mv = mvs1[j]; - mvs.push_back(move(mv.dst(), mv.src(), mv.t())); + mvs.push_back(move(m, mv.dst(), mv.src(), mv.t())); } } unsigned_vector final; @@ -184,10 +246,37 @@ public: else { init = a.num_states(); for (unsigned i = 0; i < a.m_final_states.size(); ++i) { - mvs.push_back(move(init, a.m_final_states[i])); + mvs.push_back(move(m, init, a.m_final_states[i])); } } - return automaton(init, final, mvs); + return alloc(automaton, m, init, final, mvs); + } + + void add_init_to_final() { + if (!m_final_set.contains(m_init)) { + m_final_set.insert(m_init); + m_final_states.push_back(m_init); + } + } + + void add_final_to_init_moves() { + for (unsigned i = 0; i < m_final_states.size(); ++i) { + unsigned state = m_final_states[i]; + bool found = false; + moves const& mvs = m_delta[state]; + for (unsigned j = 0; found && j < mvs.size(); ++j) { + found = (mvs[j].dst() == m_init) && mvs[j].is_epsilon(); + } + if (!found) { + m_delta[state].push_back(move(m, state, m_init)); + m_delta_inv[m_init].push_back(move(m, state, m_init)); + } + } + } + + // remove states that only have epsilon transitions. + void compress() { + // TBD } bool is_sequence(unsigned& length) const { @@ -252,8 +341,29 @@ public: void get_moves_to(unsigned state, moves& mvs) { get_moves(state, m_delta_inv, mvs); } + + template + std::ostream& display(std::ostream& out, D& displayer) const { + out << "init: " << init() << "\n"; + out << "final: "; + for (unsigned i = 0; i < m_final_states.size(); ++i) out << m_final_states[i] << " "; + out << "\n"; + for (unsigned i = 0; i < m_delta.size(); ++i) { + moves const& mvs = m_delta[i]; + for (unsigned j = 0; j < mvs.size(); ++j) { + move const& mv = mvs[j]; + out << i << " -> " << mv.dst() << " "; + if (mv.t()) { + out << "if "; + displayer.display(out, mv.t()); + } + out << "\n"; + } + } + return out; + } private: - void get_moves(unsigned state, svector const& delta, moves& mvs) const { + void get_moves(unsigned state, vector const& delta, moves& mvs) const { unsigned_vector states; get_epsilon_closure(state, delta, states); for (unsigned i = 0; i < states.size(); ++i) { @@ -267,7 +377,7 @@ private: } } - void get_epsilon_closure(unsigned state, svector const& delta, unsigned_vector& states) const { + void get_epsilon_closure(unsigned state, vector const& delta, unsigned_vector& states) const { m_todo.push_back(state); m_visited.insert(state); while (!m_todo.empty()) { @@ -292,7 +402,7 @@ private: moves const& mvs1 = a.m_delta[i]; for (unsigned j = 0; j < mvs1.size(); ++j) { move const& mv = mvs1[j]; - mvs.push_back(move(mv.src() + offset, mv.dst() + offset, mv.t())); + mvs.push_back(move(a.m, mv.src() + offset, mv.dst() + offset, mv.t())); } } } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 1cae448b2..b729ddebe 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -26,6 +26,81 @@ Revision History: using namespace smt; + +re2automaton::re2automaton(ast_manager& m): m(m), u(m) {} + +eautomaton* re2automaton::re2aut(expr* e) { + SASSERT(u.is_re(e)); + expr* e1, *e2; + scoped_ptr a, b; + if (u.re.is_to_re(e, e1)) { + return seq2aut(e1); + } + else if (u.re.is_concat(e, e1, e2) && (a = re2aut(e1)) && (b = re2aut(e2))) { + return eautomaton::mk_concat(*a, *b); + } + else if (u.re.is_union(e, e1, e2) && (a = re2aut(e1)) && (b = re2aut(e2))) { + return eautomaton::mk_union(*a, *b); + } + else if (u.re.is_star(e, e1) && (a = re2aut(e1))) { + a->add_final_to_init_moves(); + a->add_init_to_final(); + return a.detach(); + } + else if (u.re.is_plus(e, e1) && (a = re2aut(e1))) { + a->add_final_to_init_moves(); + return a.detach(); + } + else if (u.re.is_opt(e, e1) && (a = re2aut(e1))) { + a->add_init_to_final(); + return a.detach(); + } + else if (u.re.is_range(e)) { + + } + else if (u.re.is_loop(e)) { + + } +#if 0 + else if (u.re.is_intersect(e, e1, e2)) { + + } + else if (u.re.is_empty(e)) { + + } +#endif + + return 0; +} + +eautomaton* re2automaton::seq2aut(expr* e) { + SASSERT(u.is_seq(e)); + zstring s; + expr* e1, *e2; + scoped_ptr a, b; + if (u.str.is_concat(e, e1, e2) && (a = seq2aut(e1)) && (b = seq2aut(e2))) { + return eautomaton::mk_concat(*a, *b); + } + else if (u.str.is_unit(e, e1)) { + return alloc(eautomaton, m, e1); + } + else if (u.str.is_empty(e)) { + return eautomaton::mk_epsilon(m); + } + else if (u.str.is_string(e, s)) { + unsigned init = 0; + eautomaton::moves mvs; + unsigned_vector final; + final.push_back(s.length()); + for (unsigned k = 0; k < s.length(); ++k) { + // reference count? + mvs.push_back(eautomaton::move(m, k, k+1, u.str.mk_char(s, k))); + } + return alloc(eautomaton, m, init, final, mvs); + } + return 0; +} + void theory_seq::solution_map::update(expr* e, expr* r, enode_pair_dependency* d) { m_cache.reset(); std::pair value; @@ -1333,6 +1408,14 @@ void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) { ctx.assign_eq(n1, n2, eq_justification(js)); } +struct display_expr { + ast_manager& m; + display_expr(ast_manager& m): m(m) {} + std::ostream& display(std::ostream& out, expr* e) const { + return out << mk_pp(e, m); + } +}; + void theory_seq::assign_eh(bool_var v, bool is_true) { context & ctx = get_context(); expr* e = ctx.bool_var2expr(v); @@ -1355,10 +1438,16 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { f = m_util.str.mk_concat(m_util.str.mk_concat(f1, e2), f2); propagate_eq(v, f, e1); } - else if (m_util.str.is_in_re(e)) { + else if (m_util.str.is_in_re(e, e1, e2)) { TRACE("seq", tout << "in re: " << mk_pp(e, m) << "\n";); m_trail_stack.push(push_back_vector(m_in_re)); m_in_re.push_back(e); + + scoped_ptr a = re2automaton(m)(e2); + if (a) { + display_expr disp(m); + TRACE("seq", a->display(tout, disp);); + } } else { UNREACHABLE(); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 43852a086..23eac1c8b 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -25,9 +25,21 @@ Revision History: #include "th_rewriter.h" #include "ast_trail.h" #include "scoped_vector.h" +#include "automaton.h" namespace smt { + typedef automaton eautomaton; + class re2automaton { + ast_manager& m; + seq_util u; + eautomaton* re2aut(expr* e); + eautomaton* seq2aut(expr* e); + public: + re2automaton(ast_manager& m); + eautomaton* operator()(expr* e) { return re2aut(e); } + }; + class theory_seq : public theory { typedef scoped_dependency_manager enode_pair_dependency_manager; typedef enode_pair_dependency_manager::dependency enode_pair_dependency; From 65d147106e1ddcadc7b7772e1ec45c34b5a3eccf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 Dec 2015 12:01:59 -0800 Subject: [PATCH 26/87] automata Signed-off-by: Nikolaj Bjorner --- src/math/automata/automaton.h | 59 ++++++++++----- src/smt/theory_seq.cpp | 136 +++++++++++++++++++++++++++------- src/smt/theory_seq.h | 15 +++- src/util/scoped_ptr_vector.h | 1 + 4 files changed, 163 insertions(+), 48 deletions(-) diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index cc9fe2c02..606991f6a 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -78,8 +78,6 @@ private: unsigned m_init; uint_set m_final_set; unsigned_vector m_final_states; - bool m_is_epsilon_free; - bool m_is_deterministic; // local data-structures @@ -91,9 +89,7 @@ public: // The empty automaton: automaton(M& m): m(m), - m_init(0), - m_is_epsilon_free(true), - m_is_deterministic(true) + m_init(0) { m_delta.push_back(moves()); m_delta_inv.push_back(moves()); @@ -102,8 +98,6 @@ public: // create an automaton from initial state, final states, and moves automaton(M& m, unsigned init, unsigned_vector const& final, moves const& mvs): m(m) { - m_is_epsilon_free = true; - m_is_deterministic = true; m_init = init; for (unsigned i = 0; i < final.size(); ++i) { m_final_states.push_back(final[i]); @@ -118,17 +112,13 @@ public: } m_delta[mv.src()].push_back(mv); m_delta_inv[mv.dst()].push_back(mv); - m_is_deterministic &= m_delta[mv.src()].size() < 2; - m_is_epsilon_free &= !mv.is_epsilon(); } } // create an automaton that accepts a sequence. automaton(M& m, ptr_vector const& seq): m(m), - m_init(0), - m_is_epsilon_free(true), - m_is_deterministic(true) { + m_init(0) { m_delta.resize(seq.size()+1, moves()); m_delta_inv.resize(seq.size()+1, moves()); for (unsigned i = 0; i < seq.size(); ++i) { @@ -157,9 +147,7 @@ public: m_delta_inv(other.m_delta_inv), m_init(other.m_init), m_final_set(other.m_final_set), - m_final_states(other.m_final_states), - m_is_epsilon_free(other.m_is_epsilon_free), - m_is_deterministic(other.m_is_deterministic) + m_final_states(other.m_final_states) {} // create the automaton that accepts the empty string only. @@ -187,8 +175,8 @@ public: unsigned_vector final; unsigned offset1 = 1; unsigned offset2 = a.num_states() + 1; - mvs.push_back(move(m, 0, a.init() + offset1, 0)); - mvs.push_back(move(m, 0, b.init() + offset2, 0)); + mvs.push_back(move(m, 0, a.init() + offset1)); + mvs.push_back(move(m, 0, b.init() + offset2)); append_moves(offset1, a, mvs); append_moves(offset2, b, mvs); append_final(offset1, a, final); @@ -196,6 +184,23 @@ public: return alloc(automaton, m, 0, final, mvs); } + static automaton* mk_opt(automaton const& a) { + M& m = a.m; + moves mvs; + unsigned_vector final; + unsigned offset = 0; + unsigned init = a.init(); + if (!a.initial_state_is_source()) { + offset = 1; + init = 0; + mvs.push_back(move(m, 0, a.init() + offset)); + } + mvs.push_back(move(m, init, a.final_state() + offset)); + append_moves(offset, a, mvs); + append_final(offset, a, final); + return alloc(automaton, m, init, final, mvs); + } + // concatenate accepting languages static automaton* mk_concat(automaton const& a, automaton const& b) { SASSERT(&a.m == &b.m); @@ -276,6 +281,7 @@ public: // remove states that only have epsilon transitions. void compress() { + // TBD } @@ -309,8 +315,23 @@ public: moves const& get_moves_to(unsigned state) const { return m_delta_inv[state]; } bool initial_state_is_source() const { return m_delta_inv[m_init].empty(); } bool is_final_state(unsigned s) const { return m_final_set.contains(s); } - bool is_epsilon_free() const { return m_is_epsilon_free; } - bool is_deterministic() const { return m_is_deterministic; } + bool is_epsilon_free() const { + for (unsigned i = 0; i < m_delta.size(); ++i) { + moves const& mvs = m_delta[i]; + for (unsigned j = 0; j < mvs.size(); ++j) { + if (!mvs[j].t()) return false; + } + } + return true; + } + + bool is_deterministic() const { + for (unsigned i = 0; i < m_delta.size(); ++i) { + if (m_delta[i].size() >= 2) return false; + } + return true; + } + bool is_empty() const { return m_final_states.empty(); } unsigned final_state() const { return m_final_states[0]; } bool has_single_final_sink() const { return m_final_states.size() == 1 && m_delta[final_state()].empty(); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index b729ddebe..a379d9eed 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -26,6 +26,14 @@ Revision History: using namespace smt; +struct display_expr { + ast_manager& m; + display_expr(ast_manager& m): m(m) {} + std::ostream& display(std::ostream& out, expr* e) const { + return out << mk_pp(e, m); + } +}; + re2automaton::re2automaton(ast_manager& m): m(m), u(m) {} @@ -52,7 +60,7 @@ eautomaton* re2automaton::re2aut(expr* e) { return a.detach(); } else if (u.re.is_opt(e, e1) && (a = re2aut(e1))) { - a->add_init_to_final(); + a = eautomaton::mk_opt(*a); return a.detach(); } else if (u.re.is_range(e)) { @@ -200,7 +208,6 @@ theory_seq::theory_seq(ast_manager& m): m_rep(m, m_dm), m_factory(0), m_ineqs(m), - m_in_re(m), m_exclude(m), m_axioms(m), m_axioms_head(0), @@ -219,6 +226,7 @@ theory_seq::theory_seq(ast_manager& m): m_right_sym = "seq.right"; m_contains_left_sym = "seq.contains.left"; m_contains_right_sym = "seq.contains.right"; + m_accept_sym = "aut.accept"; } theory_seq::~theory_seq() { @@ -455,7 +463,7 @@ bool theory_seq::is_solved() { if (!check_ineq_coherence()) { return false; } - if (!m_in_re.empty()) { + if (!m_re2aut.empty()) { return false; } @@ -595,17 +603,15 @@ bool theory_seq::is_var(expr* a) { } bool theory_seq::is_left_select(expr* a, expr*& b) { - return m_util.is_skolem(a) && - to_app(a)->get_decl()->get_parameter(0).get_symbol() == m_left_sym && (b = to_app(a)->get_arg(0), true); + return is_skolem(m_left_sym, a) && (b = to_app(a)->get_arg(0), true); } bool theory_seq::is_right_select(expr* a, expr*& b) { - return m_util.is_skolem(a) && - to_app(a)->get_decl()->get_parameter(0).get_symbol() == m_right_sym && (b = to_app(a)->get_arg(0), true); + return is_skolem(m_right_sym, a) && (b = to_app(a)->get_arg(0), true); } bool theory_seq::is_head_elem(expr* e) const { - return m_util.is_skolem(e) && to_app(e)->get_decl()->get_parameter(0).get_symbol() == symbol("seq.head.elem"); + return is_skolem(symbol("seq.head.elem"), e); } void theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) { @@ -841,10 +847,13 @@ void theory_seq::display(std::ostream & out) const { out << mk_pp(m_ineqs[i], m) << "\n"; } } - if (!m_in_re.empty()) { + if (!m_re2aut.empty()) { out << "Regex\n"; - for (unsigned i = 0; i < m_in_re.size(); ++i) { - out << mk_pp(m_in_re[i], m) << "\n"; + obj_map::iterator it = m_re2aut.begin(), end = m_re2aut.end(); + for (; it != end; ++it) { + out << mk_pp(it->m_key, m) << "\n"; + display_expr disp(m); + it->m_value->display(out, disp); } } if (!m_rep.empty()) { @@ -1089,6 +1098,9 @@ void theory_seq::deque_axiom(expr* n) { add_elim_string_axiom(n); // add_length_string_axiom(n); } + else if (m_util.str.is_in_re(n)) { + add_in_re_axiom(n); + } } @@ -1281,6 +1293,76 @@ void theory_seq::add_length_axiom(expr* n) { } } +// the empty sequence is accepted only in the final states. +// membership holds iff the initial state holds. +void theory_seq::add_in_re_axiom(expr* n) { + expr* e1, *e2; + context& ctx = get_context(); + VERIFY(m_util.str.is_in_re(n, e1, e2)); + eautomaton* a = get_automaton(e2); + if (!a) return; + + expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); + for (unsigned i = 0; i < a->num_states(); ++i) { + expr_ref acc = mk_accept(emp, e2, m_autil.mk_int(i)); + literal lit = mk_literal(acc); + add_axiom(a->is_final_state(i)?lit:~lit); + } + unsigned_vector states; + a->get_epsilon_closure(a->init(), states); + literal_vector lits; + literal lit = mk_literal(n); + ctx.mark_as_relevant(lit); + lits.push_back(~lit); + for (unsigned i = 0; i < states.size(); ++i) { + expr_ref acc = mk_accept(e1, e2, m_autil.mk_int(a->init())); + literal lit2 = mk_literal(acc); + lits.push_back(lit2); + add_axiom(~lit2, lit); + } + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); +} + +eautomaton* theory_seq::get_automaton(expr* re) { + eautomaton* result = 0; + if (m_re2aut.find(re, result)) { + return result; + } + result = re2automaton(m)(re); + if (result) { + display_expr disp(m); + TRACE("seq", result->display(tout, disp);); + } + if (result) { + m_automata.push_back(result); + m_trail_stack.push(push_back_vector >(m_automata)); + } + m_re2aut.insert(re, result); + m_trail_stack.push(insert_obj_map(m_re2aut, re)); + return result; +} + +expr_ref theory_seq::mk_accept(expr* s, expr* re, expr* state) { + return expr_ref(mk_skolem(m_accept_sym, s, re, state, m.mk_bool_sort()), m); +} + + +bool theory_seq::is_accept(expr* acc, expr*& s, expr*& re, unsigned& i, eautomaton*& aut) { + if (is_accept(acc)) { + rational r; + s = to_app(acc)->get_arg(0); + re = to_app(acc)->get_arg(1); + VERIFY(m_autil.is_numeral(to_app(acc)->get_arg(2), r)); + SASSERT(r.is_unsigned()); + i = r.get_unsigned(); + aut = m_re2aut[re]; + return true; + } + else { + return false; + } +} + expr_ref theory_seq::mk_sub(expr* a, expr* b) { expr_ref result(m_autil.mk_sub(a, b), m); m_rewrite(result); @@ -1387,6 +1469,11 @@ expr_ref theory_seq::mk_skolem(symbol const& name, expr* e1, return expr_ref(m_util.mk_skolem(name, len, es, range), m); } +bool theory_seq::is_skolem(symbol const& s, expr* e) const { + return m_util.is_skolem(e) && to_app(e)->get_decl()->get_parameter(0).get_symbol() == s; +} + + void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) { context& ctx = get_context(); @@ -1408,18 +1495,14 @@ void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) { ctx.assign_eq(n1, n2, eq_justification(js)); } -struct display_expr { - ast_manager& m; - display_expr(ast_manager& m): m(m) {} - std::ostream& display(std::ostream& out, expr* e) const { - return out << mk_pp(e, m); - } -}; void theory_seq::assign_eh(bool_var v, bool is_true) { context & ctx = get_context(); expr* e = ctx.bool_var2expr(v); - if (is_true) { + if (is_accept(e)) { + // TBD + } + else if (is_true) { expr* e1, *e2; expr_ref f(m); if (m_util.str.is_prefix(e, e1, e2)) { @@ -1439,15 +1522,11 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { propagate_eq(v, f, e1); } else if (m_util.str.is_in_re(e, e1, e2)) { - TRACE("seq", tout << "in re: " << mk_pp(e, m) << "\n";); - m_trail_stack.push(push_back_vector(m_in_re)); - m_in_re.push_back(e); - scoped_ptr a = re2automaton(m)(e2); - if (a) { - display_expr disp(m); - TRACE("seq", a->display(tout, disp);); - } + // Predicate: accept(e1, e2, state) + // seq.in.re(e1,e2) <-> accept(e1, e2, init) + // accept("", e2, state) <-> state is final in a + // e = head.elem(e)*tail(e) -> accept(e, e2, state) <-> \/ accept(tail(e), e2, state') & label(t) = head.elem(e) for t : state->state' in a } else { UNREACHABLE(); @@ -1519,7 +1598,8 @@ void theory_seq::relevant_eh(app* n) { m_util.str.is_concat(n) || m_util.str.is_empty(n) || m_util.str.is_unit(n) || - m_util.str.is_string(n)) { + m_util.str.is_string(n) || + m_util.str.is_in_re(n)) { enque_axiom(n); } if (m_util.str.is_in_re(n) || diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 23eac1c8b..ab0038933 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -25,6 +25,7 @@ Revision History: #include "th_rewriter.h" #include "ast_trail.h" #include "scoped_vector.h" +#include "scoped_ptr_vector.h" #include "automaton.h" namespace smt { @@ -263,7 +264,6 @@ namespace smt { seq_factory* m_factory; // value factory expr_ref_vector m_ineqs; // inequalities to check solution against - expr_ref_vector m_in_re; // regular expression membership exclusion_table m_exclude; // set of asserted disequalities. expr_ref_vector m_axioms; // list of axioms to add. unsigned m_axioms_head; // index of first axiom to add. @@ -283,6 +283,11 @@ namespace smt { symbol m_contains_right_sym; symbol m_left_sym; // split variable left part symbol m_right_sym; // split variable right part + symbol m_accept_sym; + + // maintain automata with regular expressions. + scoped_ptr_vector m_automata; + obj_map m_re2aut; virtual final_check_status final_check_eh(); virtual bool internalize_atom(app*, bool); @@ -361,15 +366,23 @@ namespace smt { void add_length_string_axiom(expr* n); void add_elim_string_axiom(expr* n); void add_at_axiom(expr* n); + void add_in_re_axiom(expr* n); literal mk_literal(expr* n); void tightest_prefix(expr* s, expr* x, literal lit, literal lit2 = null_literal); expr_ref mk_sub(expr* a, expr* b); enode* ensure_enode(expr* a); expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2 = 0, expr* e3 = 0, sort* range = 0); + bool is_skolem(symbol const& s, expr* e) const; void set_incomplete(app* term); + // automata utilities + eautomaton* get_automaton(expr* e); + expr_ref mk_accept(expr* s, expr* re, expr* state); + bool is_accept(expr* acc) const { return is_skolem(m_accept_sym, acc); } + bool is_accept(expr* acc, expr*& s, expr*& re, unsigned& i, eautomaton*& aut); + // diagnostics void display_equations(std::ostream& out) const; void display_disequations(std::ostream& out) const; diff --git a/src/util/scoped_ptr_vector.h b/src/util/scoped_ptr_vector.h index 6e1c26f7d..d1ff89733 100644 --- a/src/util/scoped_ptr_vector.h +++ b/src/util/scoped_ptr_vector.h @@ -30,6 +30,7 @@ public: ~scoped_ptr_vector() { reset(); } void reset() { std::for_each(m_vector.begin(), m_vector.end(), delete_proc()); m_vector.reset(); } void push_back(T * ptr) { m_vector.push_back(ptr); } + void pop_back() { SASSERT(!empty()); set(size()-1, 0); m_vector.pop_back(); } T * operator[](unsigned idx) const { return m_vector[idx]; } void set(unsigned idx, T * ptr) { if (m_vector[idx] == ptr) From 659a7ede84454e3da91675e376bd8b2442f9c061 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Dec 2015 04:25:23 -0800 Subject: [PATCH 27/87] automata Signed-off-by: Nikolaj Bjorner --- src/math/automata/automaton.h | 20 +- src/smt/theory_seq.cpp | 391 ++++++++++++++++++++++++++-------- src/smt/theory_seq.h | 26 ++- 3 files changed, 338 insertions(+), 99 deletions(-) diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index 606991f6a..684082170 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -384,15 +384,23 @@ public: return out; } private: + mutable unsigned_vector m_states1, m_states2; + void get_moves(unsigned state, vector const& delta, moves& mvs) const { - unsigned_vector states; - get_epsilon_closure(state, delta, states); - for (unsigned i = 0; i < states.size(); ++i) { - state = states[i]; + m_states1.reset(); + m_states2.reset(); + get_epsilon_closure(state, delta, m_states1); + for (unsigned i = 0; i < m_states1.size(); ++i) { + state = m_states1[i]; moves const& mv1 = delta[state]; for (unsigned j = 0; j < mv1.size(); ++j) { - if (!mv1[j].is_epsilon()) { - mvs.push_back(mv1[j]); + move const& mv = mv1[j]; + if (!mv.is_epsilon()) { + m_states2.reset(); + get_epsilon_closure(mv.dst(), delta, m_states2); + for (unsigned k = 0; k < m_states2.size(); ++k) { + mvs.push_back(move(m, mv.src(), m_states2[k], mv.t())); + } } } } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index a379d9eed..ee2b3070e 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -219,7 +219,10 @@ theory_seq::theory_seq(ast_manager& m): m_rewrite(m), m_util(m), m_autil(m), - m_trail_stack(*this) { + m_trail_stack(*this), + m_accepts_qhead(0), + m_rejects_qhead(0), + m_steps_qhead(0) { m_prefix_sym = "seq.prefix.suffix"; m_suffix_sym = "seq.suffix.prefix"; m_left_sym = "seq.left"; @@ -249,6 +252,9 @@ final_check_status theory_seq::final_check_eh() { if (ctx.inconsistent()) { return FC_CONTINUE; } + if (propagate_automata()) { + return FC_CONTINUE; + } if (branch_variable()) { TRACE("seq", tout << "branch\n";); return FC_CONTINUE; @@ -416,19 +422,14 @@ bool theory_seq::check_length_coherence_tbd() { if (is_var(f) && f == e) { expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); TRACE("seq", tout << "Unsolved " << mk_pp(e, m) << "\n";); -#if 1 if (!assume_equality(e, emp)) { + expr_ref head(m), tail(m); + mk_decompose(e, emp, head, tail); // e = emp \/ e = unit(head.elem(e))*tail(e) - sort* char_sort = 0; - VERIFY(m_util.is_seq(m.get_sort(e), char_sort)); - expr_ref tail(mk_skolem(symbol("seq.tail"), e), m); - expr_ref v(mk_skolem(symbol("seq.head.elem"), e, 0, 0, char_sort), m); - expr_ref head(m_util.str.mk_unit(v), m); expr_ref conc(m_util.str.mk_concat(head, tail), m); add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false)); assume_equality(tail, emp); } -#endif m_branch_variable_head = j + 1; return false; } @@ -436,6 +437,15 @@ bool theory_seq::check_length_coherence_tbd() { return coherent; } +void theory_seq::mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& tail) { + sort* char_sort = 0; + VERIFY(m_util.is_seq(m.get_sort(e), char_sort)); + tail = mk_skolem(symbol("seq.tail"), e); + expr_ref v(mk_skolem(symbol("seq.head.elem"), e, 0, 0, char_sort), m); + head = m_util.str.mk_unit(v); + emp = m_util.str.mk_empty(m.get_sort(e)); +} + bool theory_seq::check_ineq_coherence() { bool all_false = true; for (unsigned i = 0; all_false && i < m_ineqs.size(); ++i) { @@ -473,7 +483,7 @@ bool theory_seq::is_solved() { } -void theory_seq::propagate_lit(enode_pair_dependency* dep, literal lit) { +void theory_seq::propagate_lit(enode_pair_dependency* dep, unsigned n, literal const* lits, literal lit) { context& ctx = get_context(); ctx.mark_as_relevant(lit); vector _eqs; @@ -483,7 +493,7 @@ void theory_seq::propagate_lit(enode_pair_dependency* dep, literal lit) { justification* js = ctx.mk_justification( ext_theory_propagation_justification( - get_id(), ctx.get_region(), 0, 0, _eqs.size(), _eqs.c_ptr(), lit)); + get_id(), ctx.get_region(), n, lits, _eqs.size(), _eqs.c_ptr(), lit)); ctx.assign(lit, js); } @@ -1293,11 +1303,12 @@ void theory_seq::add_length_axiom(expr* n) { } } +// // the empty sequence is accepted only in the final states. // membership holds iff the initial state holds. +// void theory_seq::add_in_re_axiom(expr* n) { expr* e1, *e2; - context& ctx = get_context(); VERIFY(m_util.str.is_in_re(n, e1, e2)); eautomaton* a = get_automaton(e2); if (!a) return; @@ -1305,64 +1316,52 @@ void theory_seq::add_in_re_axiom(expr* n) { expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); for (unsigned i = 0; i < a->num_states(); ++i) { expr_ref acc = mk_accept(emp, e2, m_autil.mk_int(i)); - literal lit = mk_literal(acc); - add_axiom(a->is_final_state(i)?lit:~lit); + expr_ref rej = mk_reject(emp, e2, m_autil.mk_int(i)); + literal alit = mk_literal(acc); + literal rlit = mk_literal(rej); + add_axiom(a->is_final_state(i)?alit:~alit); + add_axiom(a->is_final_state(i)?~rlit:rlit); } +} + + +void theory_seq::propagate_in_re(expr* n, bool is_true) { + expr* e1, *e2; + VERIFY(m_util.str.is_in_re(n, e1, e2)); + eautomaton* a = get_automaton(e2); + if (!a) return; + if (m_util.str.is_empty(e1)) return; + context& ctx = get_context(); unsigned_vector states; a->get_epsilon_closure(a->init(), states); literal_vector lits; - literal lit = mk_literal(n); - ctx.mark_as_relevant(lit); - lits.push_back(~lit); + literal lit = ctx.get_literal(n); + if (is_true) { + lits.push_back(~lit); + } for (unsigned i = 0; i < states.size(); ++i) { - expr_ref acc = mk_accept(e1, e2, m_autil.mk_int(a->init())); - literal lit2 = mk_literal(acc); - lits.push_back(lit2); - add_axiom(~lit2, lit); + if (is_true) { + expr_ref acc = mk_accept(e1, e2, m_autil.mk_int(a->init())); + lits.push_back(mk_literal(acc)); + } + else { + expr_ref rej = mk_reject(e1, e2, m_autil.mk_int(a->init())); + literal rlit = mk_literal(rej); + literal nlit = ~lit; + propagate_lit(0, 1, &nlit, rlit); + } } - ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); -} - -eautomaton* theory_seq::get_automaton(expr* re) { - eautomaton* result = 0; - if (m_re2aut.find(re, result)) { - return result; - } - result = re2automaton(m)(re); - if (result) { - display_expr disp(m); - TRACE("seq", result->display(tout, disp);); - } - if (result) { - m_automata.push_back(result); - m_trail_stack.push(push_back_vector >(m_automata)); - } - m_re2aut.insert(re, result); - m_trail_stack.push(insert_obj_map(m_re2aut, re)); - return result; -} - -expr_ref theory_seq::mk_accept(expr* s, expr* re, expr* state) { - return expr_ref(mk_skolem(m_accept_sym, s, re, state, m.mk_bool_sort()), m); -} - - -bool theory_seq::is_accept(expr* acc, expr*& s, expr*& re, unsigned& i, eautomaton*& aut) { - if (is_accept(acc)) { - rational r; - s = to_app(acc)->get_arg(0); - re = to_app(acc)->get_arg(1); - VERIFY(m_autil.is_numeral(to_app(acc)->get_arg(2), r)); - SASSERT(r.is_unsigned()); - i = r.get_unsigned(); - aut = m_re2aut[re]; - return true; - } - else { - return false; + if (is_true) { + if (lits.size() == 2) { + propagate_lit(0, 1, &lit, lits[1]); + } + else { + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + } } } + expr_ref theory_seq::mk_sub(expr* a, expr* b) { expr_ref result(m_autil.mk_sub(a, b), m); m_rewrite(result); @@ -1439,6 +1438,16 @@ void theory_seq::add_at_axiom(expr* e) { add_axiom(~i_ge_0, i_ge_len_s, mk_eq(i, len_x, false)); } +/** + step(s, tail, re, i, j, t) -> s = t ++ tail +*/ +void theory_seq::propagate_step(bool_var v, expr* step) { + expr* re, *t, *s, *tail, *i, *j; + VERIFY(is_step(step, s, tail, re, i, j, t)); + expr_ref conc(m_util.str.mk_concat(m_util.str.mk_unit(t), tail), m); + propagate_eq(v, s, conc); +} + literal theory_seq::mk_literal(expr* _e) { expr_ref e(_e, m); @@ -1499,40 +1508,45 @@ void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) { void theory_seq::assign_eh(bool_var v, bool is_true) { context & ctx = get_context(); expr* e = ctx.bool_var2expr(v); - if (is_accept(e)) { - // TBD + expr* e1, *e2; + expr_ref f(m); + + if (is_true && m_util.str.is_prefix(e, e1, e2)) { + f = mk_skolem(m_prefix_sym, e1, e2); + f = m_util.str.mk_concat(e1, f); + propagate_eq(v, f, e2); } - else if (is_true) { - expr* e1, *e2; - expr_ref f(m); - if (m_util.str.is_prefix(e, e1, e2)) { - f = mk_skolem(m_prefix_sym, e1, e2); - f = m_util.str.mk_concat(e1, f); - propagate_eq(v, f, e2); - } - else if (m_util.str.is_suffix(e, e1, e2)) { - f = mk_skolem(m_suffix_sym, e1, e2); - f = m_util.str.mk_concat(f, e1); - propagate_eq(v, f, e2); - } - else if (m_util.str.is_contains(e, e1, e2)) { - expr_ref f1 = mk_skolem(m_contains_left_sym, e1, e2); - expr_ref f2 = mk_skolem(m_contains_right_sym, e1, e2); - f = m_util.str.mk_concat(m_util.str.mk_concat(f1, e2), f2); - propagate_eq(v, f, e1); - } - else if (m_util.str.is_in_re(e, e1, e2)) { - - // Predicate: accept(e1, e2, state) - // seq.in.re(e1,e2) <-> accept(e1, e2, init) - // accept("", e2, state) <-> state is final in a - // e = head.elem(e)*tail(e) -> accept(e, e2, state) <-> \/ accept(tail(e), e2, state') & label(t) = head.elem(e) for t : state->state' in a - } - else { - UNREACHABLE(); + else if (is_true && m_util.str.is_suffix(e, e1, e2)) { + f = mk_skolem(m_suffix_sym, e1, e2); + f = m_util.str.mk_concat(f, e1); + propagate_eq(v, f, e2); + } + else if (is_true && m_util.str.is_contains(e, e1, e2)) { + expr_ref f1 = mk_skolem(m_contains_left_sym, e1, e2); + expr_ref f2 = mk_skolem(m_contains_right_sym, e1, e2); + f = m_util.str.mk_concat(m_util.str.mk_concat(f1, e2), f2); + propagate_eq(v, f, e1); + } + else if (is_accept(e)) { + m_trail_stack.push(push_back_vector >(m_accepts)); + m_accepts.push_back(e); + } + else if (is_reject(e)) { + m_trail_stack.push(push_back_vector >(m_rejects)); + m_rejects.push_back(e); + } + else if (is_step(e)) { + if (is_true) { + propagate_step(v, e); + m_trail_stack.push(push_back_vector >(m_steps)); + m_steps.push_back(e); } } + else if (m_util.str.is_in_re(e)) { + propagate_in_re(e, is_true); + } else { + SASSERT(!is_true); //if (m_util.str.is_prefix(e, e1, e2)) { // could add negative prefix axioms: // len(e1) <= len(e2) => e2 = seq.prefix.left(e2)*seq.prefix.right(e2) @@ -1599,9 +1613,11 @@ void theory_seq::relevant_eh(app* n) { m_util.str.is_empty(n) || m_util.str.is_unit(n) || m_util.str.is_string(n) || - m_util.str.is_in_re(n)) { + m_util.str.is_in_re(n) || + is_step(n)) { enque_axiom(n); } +#if 0 if (m_util.str.is_in_re(n) || m_util.str.is_contains(n) || m_util.str.is_suffix(n) || @@ -1620,4 +1636,197 @@ void theory_seq::relevant_eh(app* n) { break; } } +#endif +} + + +eautomaton* theory_seq::get_automaton(expr* re) { + eautomaton* result = 0; + if (m_re2aut.find(re, result)) { + return result; + } + result = re2automaton(m)(re); + if (result) { + display_expr disp(m); + TRACE("seq", result->display(tout, disp);); + } + if (result) { + m_automata.push_back(result); + m_trail_stack.push(push_back_vector >(m_automata)); + } + m_re2aut.insert(re, result); + m_trail_stack.push(insert_obj_map(m_re2aut, re)); + return result; +} + +expr_ref theory_seq::mk_accept(expr* s, expr* re, expr* state) { + return expr_ref(mk_skolem(m_accept_sym, s, re, state, m.mk_bool_sort()), m); +} +expr_ref theory_seq::mk_reject(expr* s, expr* re, expr* state) { + return expr_ref(mk_skolem(m_reject_sym, s, re, state, m.mk_bool_sort()), m); +} + +bool theory_seq::is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& re, unsigned& i, eautomaton*& aut) { + if (is_skolem(ar, e)) { + rational r; + s = to_app(e)->get_arg(0); + re = to_app(e)->get_arg(1); + VERIFY(m_autil.is_numeral(to_app(e)->get_arg(2), r)); + SASSERT(r.is_unsigned()); + i = r.get_unsigned(); + aut = m_re2aut[re]; + return true; + } + else { + return false; + } +} + +bool theory_seq::is_step(expr* e) const { + return is_skolem(symbol("aut.step"), e); +} + +bool theory_seq::is_step(expr* e, expr*& s, expr*& tail, expr*& re, expr*& i, expr*& j, expr*& t) const { + if (is_step(e)) { + s = to_app(e)->get_arg(0); + tail = to_app(e)->get_arg(1); + re = to_app(e)->get_arg(2); + i = to_app(e)->get_arg(3); + j = to_app(e)->get_arg(4); + t = to_app(e)->get_arg(5); + return true; + } + else { + return false; + } +} + +expr_ref theory_seq::mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned j, expr* t) { + expr_ref_vector args(m); + args.push_back(s); + args.push_back(tail); + args.push_back(re); + args.push_back(m_autil.mk_int(i)); + args.push_back(m_autil.mk_int(j)); + args.push_back(t); + return expr_ref(m_util.mk_skolem(symbol("aut.step"), args.size(), args.c_ptr(), m.mk_bool_sort()), m); +} + + +/** + acc & s != emp -> \/ step_i_t_j +*/ +void theory_seq::add_accept2step(expr* acc) { + context& ctx = get_context(); + expr* s, *re; + unsigned src; + eautomaton* aut = 0; + VERIFY(is_accept(acc, s, re, src, aut)); + if (!aut) return; + if (m_util.str.is_empty(s)) return; + eautomaton::moves mvs; + aut->get_moves_to(src, mvs); + expr_ref head(m), tail(m), emp(m), step(m); + mk_decompose(s, emp, head, tail); + literal_vector lits; + literal acc_lit = mk_literal(acc); + lits.push_back(~acc_lit); + lits.push_back(mk_eq(emp, s, false)); + for (unsigned i = 0; i < mvs.size(); ++i) { + eautomaton::move mv = mvs[i]; + step = mk_step(s, tail, re, src, mv.dst(), mv.t()); + lits.push_back(mk_literal(step)); + } + TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); +} + + +/** + acc(s, re, i) & step(head, tail, re, i, j, t) => acc(tail, re, j) +*/ + +void theory_seq::add_step2accept(expr* step) { + expr* re, *t, *s, *tail, *i, *j; + VERIFY(is_step(step, s, tail, re, i, j, t)); + expr_ref acc1 = mk_accept(s, re, i); + expr_ref acc2 = mk_accept(tail, re, j); + add_axiom(~mk_literal(acc1), ~mk_literal(step), mk_literal(acc2)); +} + + +/* + rej(s, re, i) & s = t ++ tail => rej(tail, re, j) +*/ +void theory_seq::add_reject2reject(expr* rej) { + expr* s, *re; + unsigned src; + eautomaton* aut = 0; + VERIFY(is_reject(rej, s, re, src, aut)); + if (!aut) return; + if (m_util.str.is_empty(s)) return; + eautomaton::moves mvs; + aut->get_moves_to(src, mvs); + expr_ref head(m), tail(m), emp(m), rej2(m), conc(m); + mk_decompose(s, emp, head, tail); + literal rej1 = mk_literal(rej); + for (unsigned i = 0; i < mvs.size(); ++i) { + eautomaton::move const& mv = mvs[i]; + conc = m_util.str.mk_concat(m_util.str.mk_unit(mv.t()), tail); + rej2 = mk_reject(tail, re, m_autil.mk_int(mv.dst())); + add_axiom(~rej1, ~mk_eq(s, conc, false), mk_literal(rej2)); + } +} + +bool theory_seq::propagate_automata() { + context& ctx = get_context(); + bool change = + (m_accepts_qhead < m_accepts.size()) || + (m_rejects_qhead < m_rejects.size()) || + (m_steps_qhead < m_steps.size()); + + if (change) { + m_trail_stack.push(value_trail(m_accepts_qhead)); + m_trail_stack.push(value_trail(m_rejects_qhead)); + m_trail_stack.push(value_trail(m_steps_qhead)); + } + while (m_accepts_qhead < m_accepts.size() && !ctx.inconsistent()) { + expr* acc = m_accepts[m_accepts_qhead]; + lbool r = ctx.get_assignment(acc); + SASSERT(l_undef != r); + if (r == l_true) { + add_accept2step(acc); + } + ++m_accepts_qhead; + } + while (m_rejects_qhead < m_rejects.size() && !ctx.inconsistent()) { + expr* rej = m_rejects[m_rejects_qhead]; + lbool r = ctx.get_assignment(rej); + SASSERT(l_undef != r); + if (r == l_true) { + add_reject2reject(rej); + } + ++m_rejects_qhead; + } + while (m_steps_qhead < m_steps.size() && !ctx.inconsistent()) { + expr* step = m_steps[m_steps_qhead]; + lbool r = ctx.get_assignment(step); + switch (r) { + case l_true: { + expr* re, *t, *s, *tail, *i, *j; + VERIFY(is_step(step, s, tail, re, i, j, t)); + expr_ref acc1 = mk_accept(s, re, i); + if (ctx.get_assignment(acc1) != l_false) { + add_step2accept(step); + } + break; + } + case l_false: + break; + default: + UNREACHABLE(); + } + ++m_steps_qhead; + } + return change || ctx.inconsistent(); } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index ab0038933..ce5da5cae 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -284,10 +284,13 @@ namespace smt { symbol m_left_sym; // split variable left part symbol m_right_sym; // split variable right part symbol m_accept_sym; + symbol m_reject_sym; // maintain automata with regular expressions. scoped_ptr_vector m_automata; obj_map m_re2aut; + ptr_vector m_accepts, m_rejects, m_steps; + unsigned m_accepts_qhead, m_rejects_qhead, m_steps_qhead; virtual final_check_status final_check_eh(); virtual bool internalize_atom(app*, bool); @@ -332,7 +335,8 @@ namespace smt { bool unchanged(expr* e, expr_ref_vector& es) const { return es.size() == 1 && es[0] == e; } // asserting consequences - void propagate_lit(enode_pair_dependency* dep, literal lit); + void propagate_lit(enode_pair_dependency* dep, literal lit) { propagate_lit(dep, 0, 0, lit); } + void propagate_lit(enode_pair_dependency* dep, unsigned n, literal const* lits, literal lit); void propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2); void propagate_eq(bool_var v, expr* e1, expr* e2); void set_conflict(enode_pair_dependency* dep, literal_vector const& lits = literal_vector()); @@ -372,16 +376,34 @@ namespace smt { expr_ref mk_sub(expr* a, expr* b); enode* ensure_enode(expr* a); + void mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& tail); expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2 = 0, expr* e3 = 0, sort* range = 0); bool is_skolem(symbol const& s, expr* e) const; void set_incomplete(app* term); // automata utilities + void propagate_in_re(expr* n, bool is_true); eautomaton* get_automaton(expr* e); expr_ref mk_accept(expr* s, expr* re, expr* state); bool is_accept(expr* acc) const { return is_skolem(m_accept_sym, acc); } - bool is_accept(expr* acc, expr*& s, expr*& re, unsigned& i, eautomaton*& aut); + bool is_accept(expr* acc, expr*& s, expr*& re, unsigned& i, eautomaton*& aut) { + return is_acc_rej(m_accept_sym, acc, s, re, i, aut); + } + expr_ref mk_reject(expr* s, expr* re, expr* state); + bool is_reject(expr* rej) const { return is_skolem(m_reject_sym, rej); } + bool is_reject(expr* rej, expr*& s, expr*& re, unsigned& i, eautomaton*& aut) { + return is_acc_rej(m_reject_sym, rej, s, re, i, aut); + } + bool is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& re, unsigned& i, eautomaton*& aut); + expr_ref mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned j, expr* t); + bool is_step(expr* e, expr*& s, expr*& tail, expr*& re, expr*& i, expr*& j, expr*& t) const; + bool is_step(expr* e) const; + void propagate_step(bool_var v, expr* n); + void add_reject2reject(expr* rej); + void add_accept2step(expr* acc); + void add_step2accept(expr* step); + bool propagate_automata(); // diagnostics void display_equations(std::ostream& out) const; From 4a5b645d88c68a7d446a7d7096c4fbaffb79681c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Dec 2015 05:37:24 -0800 Subject: [PATCH 28/87] automata Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 195 ++++++++++++++++++----------------------- src/smt/theory_seq.h | 33 ++++--- 2 files changed, 99 insertions(+), 129 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index ee2b3070e..0b8e71f1c 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -223,13 +223,24 @@ theory_seq::theory_seq(ast_manager& m): m_accepts_qhead(0), m_rejects_qhead(0), m_steps_qhead(0) { - m_prefix_sym = "seq.prefix.suffix"; - m_suffix_sym = "seq.suffix.prefix"; - m_left_sym = "seq.left"; - m_right_sym = "seq.right"; - m_contains_left_sym = "seq.contains.left"; - m_contains_right_sym = "seq.contains.right"; - m_accept_sym = "aut.accept"; + m_prefix = "seq.prefix.suffix"; + m_suffix = "seq.suffix.prefix"; + m_left = "seq.left"; + m_right = "seq.right"; + m_contains_left = "seq.contains.left"; + m_contains_right = "seq.contains.right"; + m_accept = "aut.accept"; + m_reject = "aut.reject"; + m_tail = "seq.tail"; + m_head_elem = "seq.head.elem"; + m_seq_first = "seq.first"; + m_seq_last = "seq.last"; + m_indexof_left = "seq.indexof.left"; + m_indexof_right = "seq.indexof.right"; + m_aut_step = "aut.step"; + m_extract_prefix = "seq.extract.prefix"; + m_at_left = "seq.at.left"; + m_at_right = "seq.at.right"; } theory_seq::~theory_seq() { @@ -252,9 +263,6 @@ final_check_status theory_seq::final_check_eh() { if (ctx.inconsistent()) { return FC_CONTINUE; } - if (propagate_automata()) { - return FC_CONTINUE; - } if (branch_variable()) { TRACE("seq", tout << "branch\n";); return FC_CONTINUE; @@ -274,6 +282,9 @@ final_check_status theory_seq::final_check_eh() { TRACE("seq", tout << "check_length_coherence\n";); return FC_CONTINUE; } + if (propagate_automata()) { + return FC_CONTINUE; + } if (is_solved()) { TRACE("seq", tout << "is_solved\n";); return FC_DONE; @@ -440,8 +451,8 @@ bool theory_seq::check_length_coherence_tbd() { void theory_seq::mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& tail) { sort* char_sort = 0; VERIFY(m_util.is_seq(m.get_sort(e), char_sort)); - tail = mk_skolem(symbol("seq.tail"), e); - expr_ref v(mk_skolem(symbol("seq.head.elem"), e, 0, 0, char_sort), m); + tail = mk_skolem(m_tail, e); + expr_ref v(mk_skolem(m_head_elem, e, 0, 0, char_sort), m); head = m_util.str.mk_unit(v); emp = m_util.str.mk_empty(m.get_sort(e)); } @@ -613,15 +624,15 @@ bool theory_seq::is_var(expr* a) { } bool theory_seq::is_left_select(expr* a, expr*& b) { - return is_skolem(m_left_sym, a) && (b = to_app(a)->get_arg(0), true); + return is_skolem(m_left, a) && (b = to_app(a)->get_arg(0), true); } bool theory_seq::is_right_select(expr* a, expr*& b) { - return is_skolem(m_right_sym, a) && (b = to_app(a)->get_arg(0), true); + return is_skolem(m_right, a) && (b = to_app(a)->get_arg(0), true); } bool theory_seq::is_head_elem(expr* e) const { - return is_skolem(symbol("seq.head.elem"), e); + return is_skolem(m_head_elem, e); } void theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) { @@ -633,13 +644,6 @@ void theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) { } } -bool theory_seq::simplify_eqs() { - return pre_process_eqs(true); -} - -bool theory_seq::solve_basic_eqs() { - return pre_process_eqs(false); -} bool theory_seq::pre_process_eqs(bool simplify_or_solve) { context& ctx = get_context(); @@ -782,12 +786,6 @@ bool theory_seq::simplify_and_solve_eqs() { return change; } -void theory_seq::internalize_eq_eh(app * atom, bool_var v) { -} - -bool theory_seq::internalize_atom(app* a, bool) { - return internalize_term(a); -} bool theory_seq::internalize_term(app* term) { TRACE("seq", tout << mk_pp(term, m) << "\n";); @@ -1123,8 +1121,8 @@ void theory_seq::deque_axiom(expr* n) { lit or s = "" or !prefix(s, x*s1) */ void theory_seq::tightest_prefix(expr* s, expr* x, literal lit1, literal lit2) { - expr_ref s1 = mk_skolem(symbol("seq.first"), s); - expr_ref c = mk_skolem(symbol("seq.last"), s); + expr_ref s1 = mk_skolem(m_seq_first, s); + expr_ref c = mk_skolem(m_seq_last, s); expr_ref s1c(m_util.str.mk_concat(s1, c), m); expr_ref lc(m_util.str.mk_length(c), m); expr_ref one(m_autil.mk_int(1), m); @@ -1178,8 +1176,8 @@ void theory_seq::add_indexof_axiom(expr* i) { offset_ne_zero = ~mk_eq(offset, zero, false); } if (!is_num || r.is_zero()) { - expr_ref x = mk_skolem(m_contains_left_sym, t, s); - expr_ref y = mk_skolem(m_contains_right_sym, t, s); + expr_ref x = mk_skolem(m_contains_left, t, s); + expr_ref y = mk_skolem(m_contains_right, t, s); xsy = m_util.str.mk_concat(x,s,y); literal cnt = mk_literal(m_util.str.mk_contains(t, s)); literal eq_empty = mk_eq(s, emp, false); @@ -1200,8 +1198,8 @@ void theory_seq::add_indexof_axiom(expr* i) { // 0 <= offset & offset < len(t) => len(x) = offset // 0 <= offset & offset < len(t) & ~contains(s, y) => indexof(t, s, offset) = -1 // 0 <= offset & offset < len(t) & contains(s, y) => index(t, s, offset) = indexof(y, s, 0) + len(t) - expr_ref x = mk_skolem(symbol("seq.indexof.left"), t, s, offset); - expr_ref y = mk_skolem(symbol("seq.indexof.right"), t, s, offset); + expr_ref x = mk_skolem(m_indexof_left, t, s, offset); + expr_ref y = mk_skolem(m_indexof_right, t, s, offset); expr_ref indexof(m_util.str.mk_index(y, s, zero), m); // TBD: //literal offset_ge_0 = mk_literal(m_autil.mk_ge(offset, zero)); @@ -1221,8 +1219,8 @@ void theory_seq::add_indexof_axiom(expr* i) { void theory_seq::add_replace_axiom(expr* r) { expr* a, *s, *t; VERIFY(m_util.str.is_replace(r, a, s, t)); - expr_ref x = mk_skolem(m_contains_left_sym, a, s); - expr_ref y = mk_skolem(m_contains_right_sym, a, s); + expr_ref x = mk_skolem(m_contains_left, a, s); + expr_ref y = mk_skolem(m_contains_right, a, s); expr_ref xty(m_util.str.mk_concat(x, t, y), m); expr_ref xsy(m_util.str.mk_concat(x, s, y), m); literal cnt = mk_literal(m_util.str.mk_contains(a ,s)); @@ -1315,12 +1313,10 @@ void theory_seq::add_in_re_axiom(expr* n) { expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); for (unsigned i = 0; i < a->num_states(); ++i) { - expr_ref acc = mk_accept(emp, e2, m_autil.mk_int(i)); - expr_ref rej = mk_reject(emp, e2, m_autil.mk_int(i)); - literal alit = mk_literal(acc); - literal rlit = mk_literal(rej); - add_axiom(a->is_final_state(i)?alit:~alit); - add_axiom(a->is_final_state(i)?~rlit:rlit); + literal acc = mk_accept(emp, e2, i); + literal rej = mk_reject(emp, e2, i); + add_axiom(a->is_final_state(i)?acc:~acc); + add_axiom(a->is_final_state(i)?~rej:rej); } } @@ -1341,14 +1337,11 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { } for (unsigned i = 0; i < states.size(); ++i) { if (is_true) { - expr_ref acc = mk_accept(e1, e2, m_autil.mk_int(a->init())); - lits.push_back(mk_literal(acc)); + lits.push_back(mk_accept(e1, e2, states[i])); } else { - expr_ref rej = mk_reject(e1, e2, m_autil.mk_int(a->init())); - literal rlit = mk_literal(rej); literal nlit = ~lit; - propagate_lit(0, 1, &nlit, rlit); + propagate_lit(0, 1, &nlit, mk_reject(e1, e2, states[i])); } } if (is_true) { @@ -1393,7 +1386,7 @@ enode* theory_seq::ensure_enode(expr* e) { void theory_seq::add_extract_axiom(expr* e) { expr* s, *i, *l; VERIFY(m_util.str.is_extract(e, s, i, l)); - expr_ref x(mk_skolem(symbol("seq.extract.prefix"), s, e), m); + expr_ref x(mk_skolem(m_extract_prefix, s, e), m); expr_ref ls(m_util.str.mk_length(s), m); expr_ref lx(m_util.str.mk_length(x), m); expr_ref le(m_util.str.mk_length(e), m); @@ -1422,8 +1415,8 @@ void theory_seq::add_at_axiom(expr* e) { expr* s, *i; VERIFY(m_util.str.is_at(e, s, i)); expr_ref x(m), y(m), lx(m), le(m), xey(m), zero(m), one(m), len_e(m), len_x(m); - x = mk_skolem(symbol("seq.at.left"), s); - y = mk_skolem(symbol("seq.at.right"), s); + x = mk_skolem(m_at_left, s); + y = mk_skolem(m_at_right, s); xey = m_util.str.mk_concat(x, e, y); zero = m_autil.mk_int(0); one = m_autil.mk_int(1); @@ -1512,28 +1505,32 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { expr_ref f(m); if (is_true && m_util.str.is_prefix(e, e1, e2)) { - f = mk_skolem(m_prefix_sym, e1, e2); + f = mk_skolem(m_prefix, e1, e2); f = m_util.str.mk_concat(e1, f); propagate_eq(v, f, e2); } else if (is_true && m_util.str.is_suffix(e, e1, e2)) { - f = mk_skolem(m_suffix_sym, e1, e2); + f = mk_skolem(m_suffix, e1, e2); f = m_util.str.mk_concat(f, e1); propagate_eq(v, f, e2); } else if (is_true && m_util.str.is_contains(e, e1, e2)) { - expr_ref f1 = mk_skolem(m_contains_left_sym, e1, e2); - expr_ref f2 = mk_skolem(m_contains_right_sym, e1, e2); + expr_ref f1 = mk_skolem(m_contains_left, e1, e2); + expr_ref f2 = mk_skolem(m_contains_right, e1, e2); f = m_util.str.mk_concat(m_util.str.mk_concat(f1, e2), f2); propagate_eq(v, f, e1); } else if (is_accept(e)) { - m_trail_stack.push(push_back_vector >(m_accepts)); - m_accepts.push_back(e); + if (is_true) { + m_trail_stack.push(push_back_vector >(m_accepts)); + m_accepts.push_back(e); + } } else if (is_reject(e)) { - m_trail_stack.push(push_back_vector >(m_rejects)); - m_rejects.push_back(e); + if (is_true) { + m_trail_stack.push(push_back_vector >(m_rejects)); + m_rejects.push_back(e); + } } else if (is_step(e)) { if (is_true) { @@ -1659,11 +1656,11 @@ eautomaton* theory_seq::get_automaton(expr* re) { return result; } -expr_ref theory_seq::mk_accept(expr* s, expr* re, expr* state) { - return expr_ref(mk_skolem(m_accept_sym, s, re, state, m.mk_bool_sort()), m); +literal theory_seq::mk_accept(expr* s, expr* re, expr* state) { + return mk_literal(mk_skolem(m_accept, s, re, state, m.mk_bool_sort())); } -expr_ref theory_seq::mk_reject(expr* s, expr* re, expr* state) { - return expr_ref(mk_skolem(m_reject_sym, s, re, state, m.mk_bool_sort()), m); +literal theory_seq::mk_reject(expr* s, expr* re, expr* state) { + return mk_literal(mk_skolem(m_reject, s, re, state, m.mk_bool_sort())); } bool theory_seq::is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& re, unsigned& i, eautomaton*& aut) { @@ -1683,7 +1680,7 @@ bool theory_seq::is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& re, unsi } bool theory_seq::is_step(expr* e) const { - return is_skolem(symbol("aut.step"), e); + return is_skolem(m_aut_step, e); } bool theory_seq::is_step(expr* e, expr*& s, expr*& tail, expr*& re, expr*& i, expr*& j, expr*& t) const { @@ -1709,7 +1706,7 @@ expr_ref theory_seq::mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned args.push_back(m_autil.mk_int(i)); args.push_back(m_autil.mk_int(j)); args.push_back(t); - return expr_ref(m_util.mk_skolem(symbol("aut.step"), args.size(), args.c_ptr(), m.mk_bool_sort()), m); + return expr_ref(m_util.mk_skolem(m_aut_step, args.size(), args.c_ptr(), m.mk_bool_sort()), m); } @@ -1718,6 +1715,7 @@ expr_ref theory_seq::mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned */ void theory_seq::add_accept2step(expr* acc) { context& ctx = get_context(); + SASSERT(ctx.get_assignment(acc) == l_true); expr* s, *re; unsigned src; eautomaton* aut = 0; @@ -1729,8 +1727,7 @@ void theory_seq::add_accept2step(expr* acc) { expr_ref head(m), tail(m), emp(m), step(m); mk_decompose(s, emp, head, tail); literal_vector lits; - literal acc_lit = mk_literal(acc); - lits.push_back(~acc_lit); + lits.push_back(~ctx.get_literal(acc)); lits.push_back(mk_eq(emp, s, false)); for (unsigned i = 0; i < mvs.size(); ++i) { eautomaton::move mv = mvs[i]; @@ -1747,11 +1744,13 @@ void theory_seq::add_accept2step(expr* acc) { */ void theory_seq::add_step2accept(expr* step) { + context& ctx = get_context(); + SASSERT(ctx.get_assignment(step) == l_true); expr* re, *t, *s, *tail, *i, *j; VERIFY(is_step(step, s, tail, re, i, j, t)); - expr_ref acc1 = mk_accept(s, re, i); - expr_ref acc2 = mk_accept(tail, re, j); - add_axiom(~mk_literal(acc1), ~mk_literal(step), mk_literal(acc2)); + literal acc1 = mk_accept(s, re, i); + literal acc2 = mk_accept(tail, re, j); + add_axiom(~acc1, ~ctx.get_literal(step), acc2); } @@ -1759,6 +1758,8 @@ void theory_seq::add_step2accept(expr* step) { rej(s, re, i) & s = t ++ tail => rej(tail, re, j) */ void theory_seq::add_reject2reject(expr* rej) { + context& ctx = get_context(); + SASSERT(ctx.get_assignment(rej) == l_true); expr* s, *re; unsigned src; eautomaton* aut = 0; @@ -1767,65 +1768,37 @@ void theory_seq::add_reject2reject(expr* rej) { if (m_util.str.is_empty(s)) return; eautomaton::moves mvs; aut->get_moves_to(src, mvs); - expr_ref head(m), tail(m), emp(m), rej2(m), conc(m); + expr_ref head(m), tail(m), emp(m), conc(m); mk_decompose(s, emp, head, tail); - literal rej1 = mk_literal(rej); + literal rej1 = ctx.get_literal(rej); for (unsigned i = 0; i < mvs.size(); ++i) { eautomaton::move const& mv = mvs[i]; conc = m_util.str.mk_concat(m_util.str.mk_unit(mv.t()), tail); - rej2 = mk_reject(tail, re, m_autil.mk_int(mv.dst())); - add_axiom(~rej1, ~mk_eq(s, conc, false), mk_literal(rej2)); + literal rej2 = mk_reject(tail, re, m_autil.mk_int(mv.dst())); + add_axiom(~rej1, ~mk_eq(s, conc, false), rej2); } } bool theory_seq::propagate_automata() { context& ctx = get_context(); - bool change = - (m_accepts_qhead < m_accepts.size()) || - (m_rejects_qhead < m_rejects.size()) || - (m_steps_qhead < m_steps.size()); + bool change = false; + if (m_accepts_qhead < m_accepts.size()) + m_trail_stack.push(value_trail(m_accepts_qhead)), change = true; + if (m_rejects_qhead < m_rejects.size()) + m_trail_stack.push(value_trail(m_rejects_qhead)), change = true; + if (m_steps_qhead < m_steps.size()) + m_trail_stack.push(value_trail(m_steps_qhead)), change = true; - if (change) { - m_trail_stack.push(value_trail(m_accepts_qhead)); - m_trail_stack.push(value_trail(m_rejects_qhead)); - m_trail_stack.push(value_trail(m_steps_qhead)); - } while (m_accepts_qhead < m_accepts.size() && !ctx.inconsistent()) { - expr* acc = m_accepts[m_accepts_qhead]; - lbool r = ctx.get_assignment(acc); - SASSERT(l_undef != r); - if (r == l_true) { - add_accept2step(acc); - } + add_accept2step(m_accepts[m_accepts_qhead]); ++m_accepts_qhead; } while (m_rejects_qhead < m_rejects.size() && !ctx.inconsistent()) { - expr* rej = m_rejects[m_rejects_qhead]; - lbool r = ctx.get_assignment(rej); - SASSERT(l_undef != r); - if (r == l_true) { - add_reject2reject(rej); - } + add_reject2reject(m_rejects[m_rejects_qhead]); ++m_rejects_qhead; } while (m_steps_qhead < m_steps.size() && !ctx.inconsistent()) { - expr* step = m_steps[m_steps_qhead]; - lbool r = ctx.get_assignment(step); - switch (r) { - case l_true: { - expr* re, *t, *s, *tail, *i, *j; - VERIFY(is_step(step, s, tail, re, i, j, t)); - expr_ref acc1 = mk_accept(s, re, i); - if (ctx.get_assignment(acc1) != l_false) { - add_step2accept(step); - } - break; - } - case l_false: - break; - default: - UNREACHABLE(); - } + add_step2accept(m_steps[m_steps_qhead]); ++m_steps_qhead; } return change || ctx.inconsistent(); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index ce5da5cae..f19599472 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -277,14 +277,9 @@ namespace smt { arith_util m_autil; th_trail_stack m_trail_stack; stats m_stats; - symbol m_prefix_sym; - symbol m_suffix_sym; - symbol m_contains_left_sym; - symbol m_contains_right_sym; - symbol m_left_sym; // split variable left part - symbol m_right_sym; // split variable right part - symbol m_accept_sym; - symbol m_reject_sym; + symbol m_prefix, m_suffix, m_contains_left, m_contains_right, m_left, m_right, m_accept, m_reject; + symbol m_tail, m_head_elem, m_seq_first, m_seq_last, m_indexof_left, m_indexof_right, m_aut_step; + symbol m_extract_prefix, m_at_left, m_at_right; // maintain automata with regular expressions. scoped_ptr_vector m_automata; @@ -293,9 +288,9 @@ namespace smt { unsigned m_accepts_qhead, m_rejects_qhead, m_steps_qhead; virtual final_check_status final_check_eh(); - virtual bool internalize_atom(app*, bool); + virtual bool internalize_atom(app* atom, bool) { return internalize_term(atom); } virtual bool internalize_term(app*); - virtual void internalize_eq_eh(app * atom, bool_var v); + virtual void internalize_eq_eh(app * atom, bool_var v) {} virtual void new_eq_eh(theory_var, theory_var); virtual void new_diseq_eh(theory_var, theory_var); virtual void assign_eh(bool_var v, bool is_true); @@ -325,10 +320,10 @@ namespace smt { bool check_ineq_coherence(); bool pre_process_eqs(bool simplify_or_solve); - bool simplify_eqs(); + bool simplify_eqs() { return pre_process_eqs(true); } + bool solve_basic_eqs() { return pre_process_eqs(false); } bool simplify_eq(expr* l, expr* r, enode_pair_dependency* dep); bool solve_unit_eq(expr* l, expr* r, enode_pair_dependency* dep); - bool solve_basic_eqs(); bool solve_nqs(); bool solve_ne(unsigned i); @@ -385,15 +380,17 @@ namespace smt { // automata utilities void propagate_in_re(expr* n, bool is_true); eautomaton* get_automaton(expr* e); - expr_ref mk_accept(expr* s, expr* re, expr* state); - bool is_accept(expr* acc) const { return is_skolem(m_accept_sym, acc); } + literal mk_accept(expr* s, expr* re, expr* state); + literal mk_accept(expr* s, expr* re, unsigned i) { return mk_accept(s, re, m_autil.mk_int(i)); } + bool is_accept(expr* acc) const { return is_skolem(m_accept, acc); } bool is_accept(expr* acc, expr*& s, expr*& re, unsigned& i, eautomaton*& aut) { - return is_acc_rej(m_accept_sym, acc, s, re, i, aut); + return is_acc_rej(m_accept, acc, s, re, i, aut); } - expr_ref mk_reject(expr* s, expr* re, expr* state); - bool is_reject(expr* rej) const { return is_skolem(m_reject_sym, rej); } + literal mk_reject(expr* s, expr* re, expr* state); + literal mk_reject(expr* s, expr* re, unsigned i) { return mk_reject(s, re, m_autil.mk_int(i)); } + bool is_reject(expr* rej) const { return is_skolem(m_reject, rej); } bool is_reject(expr* rej, expr*& s, expr*& re, unsigned& i, eautomaton*& aut) { - return is_acc_rej(m_reject_sym, rej, s, re, i, aut); + return is_acc_rej(m_reject, rej, s, re, i, aut); } bool is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& re, unsigned& i, eautomaton*& aut); expr_ref mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned j, expr* t); From 31302ec851204b1244df4bb0aca0fe502ebece39 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 Dec 2015 15:22:26 -0800 Subject: [PATCH 29/87] automata Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 194 +++++++++++++++++++++++++++++- src/ast/rewriter/seq_rewriter.h | 15 +++ src/ast/seq_decl_plugin.cpp | 8 +- src/ast/seq_decl_plugin.h | 5 +- src/math/automata/automaton.h | 152 ++++++++++++++++++----- src/smt/theory_seq.cpp | 134 ++++++++------------- src/smt/theory_seq.h | 12 +- 7 files changed, 386 insertions(+), 134 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 41c20f599..428c4b224 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -25,6 +25,89 @@ Notes: #include"automaton.h" + +re2automaton::re2automaton(ast_manager& m): m(m), u(m) {} + +eautomaton* re2automaton::operator()(expr* e) { + eautomaton* r = re2aut(e); + if (r) { + r->compress(); + } + return r; +} + +eautomaton* re2automaton::re2aut(expr* e) { + SASSERT(u.is_re(e)); + expr* e1, *e2; + scoped_ptr a, b; + if (u.re.is_to_re(e, e1)) { + return seq2aut(e1); + } + else if (u.re.is_concat(e, e1, e2) && (a = re2aut(e1)) && (b = re2aut(e2))) { + return eautomaton::mk_concat(*a, *b); + } + else if (u.re.is_union(e, e1, e2) && (a = re2aut(e1)) && (b = re2aut(e2))) { + return eautomaton::mk_union(*a, *b); + } + else if (u.re.is_star(e, e1) && (a = re2aut(e1))) { + a->add_final_to_init_moves(); + a->add_init_to_final_states(); + return a.detach(); + } + else if (u.re.is_plus(e, e1) && (a = re2aut(e1))) { + a->add_final_to_init_moves(); + return a.detach(); + } + else if (u.re.is_opt(e, e1) && (a = re2aut(e1))) { + a = eautomaton::mk_opt(*a); + return a.detach(); + } + else if (u.re.is_range(e)) { + + } + else if (u.re.is_loop(e)) { + + } +#if 0 + else if (u.re.is_intersect(e, e1, e2)) { + + } + else if (u.re.is_empty(e)) { + + } +#endif + + return 0; +} + +eautomaton* re2automaton::seq2aut(expr* e) { + SASSERT(u.is_seq(e)); + zstring s; + expr* e1, *e2; + scoped_ptr a, b; + if (u.str.is_concat(e, e1, e2) && (a = seq2aut(e1)) && (b = seq2aut(e2))) { + return eautomaton::mk_concat(*a, *b); + } + else if (u.str.is_unit(e, e1)) { + return alloc(eautomaton, m, e1); + } + else if (u.str.is_empty(e)) { + return eautomaton::mk_epsilon(m); + } + else if (u.str.is_string(e, s)) { + unsigned init = 0; + eautomaton::moves mvs; + unsigned_vector final; + final.push_back(s.length()); + for (unsigned k = 0; k < s.length(); ++k) { + // reference count? + mvs.push_back(eautomaton::move(m, k, k+1, u.str.mk_char(s, k))); + } + return alloc(eautomaton, m, init, final, mvs); + } + return 0; +} + br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { SASSERT(f->get_family_id() == get_fid()); @@ -159,11 +242,15 @@ br_status seq_rewriter::mk_seq_concat(expr* a, expr* b, expr_ref& result) { result = a; return BR_DONE; } - if (m_util.str.is_concat(a, c, d) && - m_util.str.is_string(d, s1) && isc2) { + // TBD concatenation is right-associative + if (isc2 && m_util.str.is_concat(a, c, d) && m_util.str.is_string(d, s1)) { result = m_util.str.mk_concat(c, m_util.str.mk_string(s1 + s2)); return BR_DONE; } + if (isc1 && m_util.str.is_concat(b, c, d) && m_util.str.is_string(c, s2)) { + result = m_util.str.mk_concat(m_util.str.mk_string(s1 + s2), d); + return BR_DONE; + } return BR_FAILED; } @@ -398,7 +485,7 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { result = m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), a); return BR_REWRITE3; } - // concatenation is left-associative, so a2, b2 are not concatenations + // TBD concatenation is right-associative expr* a1, *a2, *b1, *b2; if (m_util.str.is_concat(a, a1, a2) && m_util.str.is_concat(b, b1, b2) && a2 == b2) { @@ -498,7 +585,108 @@ br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) { } return BR_FAILED; } + +void seq_rewriter::add_next(u_map& next, unsigned idx, expr* cond) { + expr* acc; + if (m().is_true(cond) || !next.find(idx, acc)) { + next.insert(idx, cond); + } + else { + next.insert(idx, m().mk_or(cond, acc)); + } +} + +bool seq_rewriter::is_sequence(expr* e, expr_ref_vector& seq) { + zstring s; + ptr_vector todo; + expr *e1, *e2; + todo.push_back(e); + while (!todo.empty()) { + e = todo.back(); + todo.pop_back(); + if (m_util.str.is_string(e, s)) { + for (unsigned i = s.length(); i > 0; ) { + --i; + seq.push_back(m_util.str.mk_char(s, i)); + } + } + else if (m_util.str.is_empty(e)) { + continue; + } + else if (m_util.str.is_unit(e)) { + seq.push_back(e); + } + else if (m_util.str.is_concat(e, e1, e2)) { + todo.push_back(e1); + todo.push_back(e2); + } + else { + return false; + } + } + seq.reverse(); + return true; +} + br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) { + scoped_ptr aut; + expr_ref_vector seq(m()); + if (is_sequence(a, seq) && (aut = re2automaton(m())(b))) { + expr_ref_vector trail(m()); + u_map maps[2]; + bool select_map = false; + expr_ref ch(m()), cond(m()); + eautomaton::moves mvs; + maps[0].insert(aut->init(), m().mk_true()); + // is_accepted(a, aut) & some state in frontier is final. + + for (unsigned i = 0; i < seq.size(); ++i) { + u_map& frontier = maps[select_map]; + u_map& next = maps[!select_map]; + select_map = !select_map; + ch = seq[i].get(); + next.reset(); + u_map::iterator it = frontier.begin(), end = frontier.end(); + for (; it != end; ++it) { + mvs.reset(); + unsigned state = it->m_key; + expr* acc = it->m_value; + aut->get_moves_from(state, mvs, false); + for (unsigned j = 0; j < mvs.size(); ++j) { + eautomaton::move const& mv = mvs[j]; + if (m().is_value(mv.t()) && m().is_value(ch)) { + if (mv.t() == ch) { + add_next(next, mv.dst(), acc); + } + else { + continue; + } + } + else { + cond = m().mk_eq(mv.t(), ch); + if (!m().is_true(acc)) cond = m().mk_and(acc, cond); + add_next(next, mv.dst(), cond); + } + } + } + } + u_map const& frontier = maps[select_map]; + u_map::iterator it = frontier.begin(), end = frontier.end(); + expr_ref_vector ors(m()); + for (; it != end; ++it) { + unsigned_vector states; + bool has_final = false; + aut->get_epsilon_closure(it->m_key, states); + for (unsigned i = 0; i < states.size() && !has_final; ++i) { + has_final = aut->is_final_state(states[i]); + } + if (has_final) { + ors.push_back(it->m_value); + } + } + result = mk_or(ors); + return BR_REWRITE_FULL; + } return BR_FAILED; } br_status seq_rewriter::mk_str_to_regexp(expr* a, expr_ref& result) { diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index c3e466585..f6772bfe9 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -24,8 +24,20 @@ Notes: #include"rewriter_types.h" #include"params.h" #include"lbool.h" +#include"automaton.h" +typedef automaton eautomaton; +class re2automaton { + ast_manager& m; + seq_util u; + eautomaton* re2aut(expr* e); + eautomaton* seq2aut(expr* e); + public: + re2automaton(ast_manager& m); + eautomaton* operator()(expr* e); +}; + /** \brief Cheap rewrite rules for seq constraints */ @@ -61,6 +73,9 @@ class seq_rewriter { bool min_length(unsigned n, expr* const* es, unsigned& len); expr* concat_non_empty(unsigned n, expr* const* es); + void add_next(u_map& next, unsigned idx, expr* cond); + bool is_sequence(expr* e, expr_ref_vector& seq); + public: seq_rewriter(ast_manager & m, params_ref const & p = params_ref()): m_util(m), m_autil(m), m_es(m), m_lhs(m), m_rhs(m) { diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 10e9c00a5..e516d4ea5 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -223,9 +223,9 @@ bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) { } /* - \brief match left associative operator. + \brief match right associative operator. */ -void seq_decl_plugin::match_left_assoc(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) { +void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) { ptr_vector binding; ast_manager& m = *m_manager; TRACE("seq_verbose", @@ -441,9 +441,9 @@ func_decl* seq_decl_plugin::mk_assoc_fun(decl_kind k, unsigned arity, sort* cons if (arity == 0) { m.raise_exception("Invalid function application. At least one argument expected"); } - match_left_assoc(*m_sigs[k], arity, domain, range, rng); + match_right_assoc(*m_sigs[k], arity, domain, range, rng); func_decl_info info(m_family_id, k_seq); - info.set_left_associative(); + info.set_right_associative(); return m.mk_func_decl(m_sigs[(rng == m_string)?k_string:k_seq]->m_name, rng, rng, rng, info); } diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index 9a5f65d05..d0a475b25 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -137,7 +137,7 @@ class seq_decl_plugin : public decl_plugin { void match(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng); - void match_left_assoc(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng); + void match_right_assoc(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng); bool match(ptr_vector& binding, sort* s, sort* sP); @@ -221,7 +221,7 @@ public: app* mk_char(char ch); app* mk_concat(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONCAT, 2, es); } app* mk_concat(expr* a, expr* b, expr* c) { - return mk_concat(mk_concat(a, b), c); + return mk_concat(a, mk_concat(b, c)); } expr* mk_concat(unsigned n, expr* const* es) { if (n == 1) return es[0]; SASSERT(n > 1); return m.mk_app(m_fid, OP_SEQ_CONCAT, n, es); } app* mk_length(expr* a) { return m.mk_app(m_fid, OP_SEQ_LENGTH, 1, &a); } @@ -278,6 +278,7 @@ public: void get_concat(expr* e, expr_ref_vector& es) const; expr* get_leftmost_concat(expr* e) const { expr* e1, *e2; while (is_concat(e, e1, e2)) e = e1; return e; } + expr* get_rightmost_concat(expr* e) const { expr* e1, *e2; while (is_concat(e, e1, e2)) e = e2; return e; } }; class re { diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index 684082170..dabfa1417 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -100,8 +100,7 @@ public: automaton(M& m, unsigned init, unsigned_vector const& final, moves const& mvs): m(m) { m_init = init; for (unsigned i = 0; i < final.size(); ++i) { - m_final_states.push_back(final[i]); - m_final_set.insert(final[i]); + add_to_final_states(final[i]); } for (unsigned i = 0; i < mvs.size(); ++i) { move const& mv = mvs[i]; @@ -110,8 +109,7 @@ public: m_delta.resize(n+1, moves()); m_delta_inv.resize(n+1, moves()); } - m_delta[mv.src()].push_back(mv); - m_delta_inv[mv.dst()].push_back(mv); + add(mv); } } @@ -125,8 +123,7 @@ public: m_delta[i].push_back(move(m, i, i + 1, seq[i])); m_delta[i + 1].push_back(move(m, i, i + 1, seq[i])); } - m_final_states.push_back(seq.size()); - m_final_set.insert(seq.size()); + add_to_final_states(seq.size()); } // The automaton that accepts t @@ -135,10 +132,8 @@ public: m_init(0) { m_delta.resize(2, moves()); m_delta_inv.resize(2, moves()); - m_final_set.insert(1); - m_final_states.push_back(1); - m_delta[0].push_back(move(m, 0, 1, t)); - m_delta_inv[1].push_back(move(m, 0, 1, t)); + add_to_final_states(1); + add(move(m, 0, 1, t)); } automaton(automaton const& other): @@ -257,13 +252,24 @@ public: return alloc(automaton, m, init, final, mvs); } - void add_init_to_final() { - if (!m_final_set.contains(m_init)) { - m_final_set.insert(m_init); - m_final_states.push_back(m_init); + void add_to_final_states(unsigned s) { + if (!is_final_state(s)) { + m_final_set.insert(s); + m_final_states.push_back(s); } } + void remove_from_final_states(unsigned s) { + if (is_final_state(s)) { + m_final_set.remove(s); + m_final_states.erase(s); + } + } + + void add_init_to_final_states() { + add_to_final_states(init()); + } + void add_final_to_init_moves() { for (unsigned i = 0; i < m_final_states.size(); ++i) { unsigned state = m_final_states[i]; @@ -273,16 +279,69 @@ public: found = (mvs[j].dst() == m_init) && mvs[j].is_epsilon(); } if (!found) { - m_delta[state].push_back(move(m, state, m_init)); - m_delta_inv[m_init].push_back(move(m, state, m_init)); + add(move(m, state, m_init)); } } } - // remove states that only have epsilon transitions. + // remove epsilon transitions + // src - e -> dst + // in_degree(src) = 1, final(src) => final(dst), src0 != src + // src0 - t -> src - e -> dst => src0 - t -> dst + // out_degree(dst) = 1, final(dst) => final(src), dst != dst1 + // src - e -> dst - t -> dst1 => src - t -> dst1 void compress() { - - // TBD + for (unsigned i = 0; i < m_delta.size(); ++i) { + for (unsigned j = 0; j < m_delta[i].size(); ++j) { + move const& mv = m_delta[i][j]; + unsigned src = mv.src(); + unsigned dst = mv.dst(); + SASSERT(src == i); + if (mv.is_epsilon()) { + if (src == dst) { + // just remove this edge. + } + else if (1 == in_degree(src) && init() != src && (!is_final_state(src) || is_final_state(dst))) { + move const& mv0 = m_delta_inv[src][0]; + unsigned src0 = mv0.src(); + T* t = mv0.t(); + SASSERT(mv0.dst() == src); + if (src0 == src) { + continue; + } + add(move(m, src0, dst, t)); + remove(src0, src, t); + } + else if (1 == out_degree(dst) && init() != dst && (!is_final_state(dst) || is_final_state(src))) { + move const& mv1 = m_delta[dst][0]; + unsigned dst1 = mv1.dst(); + T* t = mv1.t(); + SASSERT(mv1.src() == dst); + if (dst1 == dst) { + continue; + } + add(move(m, src, dst1, t)); + remove(dst, dst1, t); + } + else { + continue; + } + remove(src, dst, 0); + --j; + } + } + } + while (true) { + SASSERT(!m_delta.empty()); + unsigned src = m_delta.size() - 1; + if (in_degree(src) == 0 && init() != src) { + remove_from_final_states(src); + m_delta.pop_back(); + } + else { + break; + } + } } bool is_sequence(unsigned& length) const { @@ -356,11 +415,11 @@ public: void get_inv_epsilon_closure(unsigned state, unsigned_vector& states) { get_epsilon_closure(state, m_delta_inv, states); } - void get_moves_from(unsigned state, moves& mvs) const { - get_moves(state, m_delta, mvs); + void get_moves_from(unsigned state, moves& mvs, bool epsilon_closure = true) const { + get_moves(state, m_delta, mvs, epsilon_closure); } - void get_moves_to(unsigned state, moves& mvs) { - get_moves(state, m_delta_inv, mvs); + void get_moves_to(unsigned state, moves& mvs, bool epsilon_closure = true) { + get_moves(state, m_delta_inv, mvs, epsilon_closure); } template @@ -384,9 +443,41 @@ public: return out; } private: + + void add(move const& mv) { + m_delta[mv.src()].push_back(mv); + m_delta_inv[mv.dst()].push_back(mv); + } + + + unsigned find_move(unsigned src, unsigned dst, T* t, moves const& mvs) { + for (unsigned i = 0; i < mvs.size(); ++i) { + move const& mv = mvs[i]; + if (mv.src() == src && mv.dst() == dst && t == mv.t()) { + return i; + } + } + UNREACHABLE(); + return UINT_MAX; + } + + void remove(unsigned src, unsigned dst, T* t, moves& mvs) { + remove(find_move(src, dst, t, mvs), mvs); + } + + void remove(unsigned src, unsigned dst, T* t) { + remove(src, dst, t, m_delta[src]); + remove(src, dst, t, m_delta_inv[dst]); + } + + void remove(unsigned index, moves& mvs) { + mvs[index] = mvs.back(); + mvs.pop_back(); + } + mutable unsigned_vector m_states1, m_states2; - void get_moves(unsigned state, vector const& delta, moves& mvs) const { + void get_moves(unsigned state, vector const& delta, moves& mvs, bool epsilon_closure) const { m_states1.reset(); m_states2.reset(); get_epsilon_closure(state, delta, m_states1); @@ -396,10 +487,15 @@ private: for (unsigned j = 0; j < mv1.size(); ++j) { move const& mv = mv1[j]; if (!mv.is_epsilon()) { - m_states2.reset(); - get_epsilon_closure(mv.dst(), delta, m_states2); - for (unsigned k = 0; k < m_states2.size(); ++k) { - mvs.push_back(move(m, mv.src(), m_states2[k], mv.t())); + if (epsilon_closure) { + m_states2.reset(); + get_epsilon_closure(mv.dst(), delta, m_states2); + for (unsigned k = 0; k < m_states2.size(); ++k) { + mvs.push_back(move(m, state, m_states2[k], mv.t())); + } + } + else { + mvs.push_back(move(m, state, mv.dst(), mv.t())); } } } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 0b8e71f1c..39ed71beb 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -35,79 +35,6 @@ struct display_expr { }; -re2automaton::re2automaton(ast_manager& m): m(m), u(m) {} - -eautomaton* re2automaton::re2aut(expr* e) { - SASSERT(u.is_re(e)); - expr* e1, *e2; - scoped_ptr a, b; - if (u.re.is_to_re(e, e1)) { - return seq2aut(e1); - } - else if (u.re.is_concat(e, e1, e2) && (a = re2aut(e1)) && (b = re2aut(e2))) { - return eautomaton::mk_concat(*a, *b); - } - else if (u.re.is_union(e, e1, e2) && (a = re2aut(e1)) && (b = re2aut(e2))) { - return eautomaton::mk_union(*a, *b); - } - else if (u.re.is_star(e, e1) && (a = re2aut(e1))) { - a->add_final_to_init_moves(); - a->add_init_to_final(); - return a.detach(); - } - else if (u.re.is_plus(e, e1) && (a = re2aut(e1))) { - a->add_final_to_init_moves(); - return a.detach(); - } - else if (u.re.is_opt(e, e1) && (a = re2aut(e1))) { - a = eautomaton::mk_opt(*a); - return a.detach(); - } - else if (u.re.is_range(e)) { - - } - else if (u.re.is_loop(e)) { - - } -#if 0 - else if (u.re.is_intersect(e, e1, e2)) { - - } - else if (u.re.is_empty(e)) { - - } -#endif - - return 0; -} - -eautomaton* re2automaton::seq2aut(expr* e) { - SASSERT(u.is_seq(e)); - zstring s; - expr* e1, *e2; - scoped_ptr a, b; - if (u.str.is_concat(e, e1, e2) && (a = seq2aut(e1)) && (b = seq2aut(e2))) { - return eautomaton::mk_concat(*a, *b); - } - else if (u.str.is_unit(e, e1)) { - return alloc(eautomaton, m, e1); - } - else if (u.str.is_empty(e)) { - return eautomaton::mk_epsilon(m); - } - else if (u.str.is_string(e, s)) { - unsigned init = 0; - eautomaton::moves mvs; - unsigned_vector final; - final.push_back(s.length()); - for (unsigned k = 0; k < s.length(); ++k) { - // reference count? - mvs.push_back(eautomaton::move(m, k, k+1, u.str.mk_char(s, k))); - } - return alloc(eautomaton, m, init, final, mvs); - } - return 0; -} void theory_seq::solution_map::update(expr* e, expr* r, enode_pair_dependency* d) { m_cache.reset(); @@ -449,12 +376,35 @@ bool theory_seq::check_length_coherence_tbd() { } void theory_seq::mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& tail) { + expr* e1, *e2; sort* char_sort = 0; + zstring s; VERIFY(m_util.is_seq(m.get_sort(e), char_sort)); - tail = mk_skolem(m_tail, e); - expr_ref v(mk_skolem(m_head_elem, e, 0, 0, char_sort), m); - head = m_util.str.mk_unit(v); emp = m_util.str.mk_empty(m.get_sort(e)); + if (m_util.str.is_empty(e)) { + head = m_util.str.mk_unit(mk_skolem(m_head_elem, e, 0, 0, char_sort)); + tail = mk_skolem(m_tail, e); + } + else if (m_util.str.is_string(e, s)) { + head = m_util.str.mk_unit(m_util.str.mk_char(s, 0)); + tail = m_util.str.mk_string(s.extract(1, s.length()-1)); + } + else if (m_util.str.is_unit(e)) { + head = e; + tail = emp; + } + else if (m_util.str.is_concat(e, e1, e2) && m_util.str.is_unit(e1)) { + head = e1; + tail = e2; + } + else { + head = m_util.str.mk_unit(mk_skolem(m_head_elem, e, 0, 0, char_sort)); + tail = mk_skolem(m_tail, e); + if (!m_util.is_skolem(e)) { + expr_ref conc(m_util.str.mk_concat(head, tail), m); + add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false)); + } + } } bool theory_seq::check_ineq_coherence() { @@ -484,8 +434,8 @@ bool theory_seq::is_solved() { if (!check_ineq_coherence()) { return false; } - if (!m_re2aut.empty()) { - return false; + for (unsigned i = 0; i < m_automata.size(); ++i) { + if (!m_automata[i]) return false; } SASSERT(check_length_coherence()); @@ -500,7 +450,7 @@ void theory_seq::propagate_lit(enode_pair_dependency* dep, unsigned n, literal c vector _eqs; m_dm.linearize(dep, _eqs); TRACE("seq", ctx.display_detailed_literal(tout, lit); - tout << " <- "; display_deps(tout, dep);); + tout << " <- "; ctx.display_literals_verbose(tout, n, lits); display_deps(tout, dep);); justification* js = ctx.mk_justification( ext_theory_propagation_justification( @@ -1248,9 +1198,10 @@ void theory_seq::add_elim_string_axiom(expr* n) { zstring s; VERIFY(m_util.str.is_string(n, s)); SASSERT(s.length() > 0); - expr_ref result(m_util.str.mk_unit(m_util.str.mk_char(s, 0)), m); - for (unsigned i = 1; i < s.length(); ++i) { - result = m_util.str.mk_concat(result, m_util.str.mk_unit(m_util.str.mk_char(s, i))); + expr_ref result(m_util.str.mk_unit(m_util.str.mk_char(s, s.length()-1)), m); + for (unsigned i = s.length()-1; i > 0; ) { + --i; + result = m_util.str.mk_concat(m_util.str.mk_unit(m_util.str.mk_char(s, i)), result); } add_axiom(mk_eq(n, result, false)); m_rep.update(n, result, 0); @@ -1322,6 +1273,7 @@ void theory_seq::add_in_re_axiom(expr* n) { void theory_seq::propagate_in_re(expr* n, bool is_true) { + TRACE("seq", tout << mk_pp(n, m) << " <- " << (is_true?"true":"false") << "\n";); expr* e1, *e2; VERIFY(m_util.str.is_in_re(n, e1, e2)); eautomaton* a = get_automaton(e2); @@ -1349,6 +1301,7 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { propagate_lit(0, 1, &lit, lits[1]); } else { + TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr());); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } } @@ -1435,10 +1388,15 @@ void theory_seq::add_at_axiom(expr* e) { step(s, tail, re, i, j, t) -> s = t ++ tail */ void theory_seq::propagate_step(bool_var v, expr* step) { + context& ctx = get_context(); expr* re, *t, *s, *tail, *i, *j; VERIFY(is_step(step, s, tail, re, i, j, t)); expr_ref conc(m_util.str.mk_concat(m_util.str.mk_unit(t), tail), m); + expr_ref sr(s, m); propagate_eq(v, s, conc); + enode* n1 = ensure_enode(step); + enode* n2 = ctx.get_enode(m.mk_true()); + m_eqs.push_back(eq(sr, conc, m_dm.mk_leaf(enode_pair(n1, n2)))); } @@ -1479,12 +1437,13 @@ bool theory_seq::is_skolem(symbol const& s, expr* e) const { void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) { context& ctx = get_context(); - SASSERT(ctx.e_internalized(e2)); enode* n1 = ensure_enode(e1); enode* n2 = ensure_enode(e2); if (n1->get_root() == n2->get_root()) { return; } + ctx.mark_as_relevant(n1); + ctx.mark_as_relevant(n2); TRACE("seq", tout << mk_pp(ctx.bool_var2enode(v)->get_owner(), m) << " => " << mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";); @@ -1517,7 +1476,7 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { else if (is_true && m_util.str.is_contains(e, e1, e2)) { expr_ref f1 = mk_skolem(m_contains_left, e1, e2); expr_ref f2 = mk_skolem(m_contains_right, e1, e2); - f = m_util.str.mk_concat(m_util.str.mk_concat(f1, e2), f2); + f = m_util.str.mk_concat(f1, m_util.str.mk_concat(e2, f2)); propagate_eq(v, f, e1); } else if (is_accept(e)) { @@ -1723,7 +1682,7 @@ void theory_seq::add_accept2step(expr* acc) { if (!aut) return; if (m_util.str.is_empty(s)) return; eautomaton::moves mvs; - aut->get_moves_to(src, mvs); + aut->get_moves_from(src, mvs); expr_ref head(m), tail(m), emp(m), step(m); mk_decompose(s, emp, head, tail); literal_vector lits; @@ -1735,6 +1694,9 @@ void theory_seq::add_accept2step(expr* acc) { lits.push_back(mk_literal(step)); } TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + for (unsigned i = 0; i < lits.size(); ++i) { // TBD + ctx.mark_as_relevant(lits[i]); + } ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } @@ -1767,7 +1729,7 @@ void theory_seq::add_reject2reject(expr* rej) { if (!aut) return; if (m_util.str.is_empty(s)) return; eautomaton::moves mvs; - aut->get_moves_to(src, mvs); + aut->get_moves_from(src, mvs); expr_ref head(m), tail(m), emp(m), conc(m); mk_decompose(s, emp, head, tail); literal rej1 = ctx.get_literal(rej); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index f19599472..59b721fa7 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -27,20 +27,10 @@ Revision History: #include "scoped_vector.h" #include "scoped_ptr_vector.h" #include "automaton.h" +#include "seq_rewriter.h" namespace smt { - typedef automaton eautomaton; - class re2automaton { - ast_manager& m; - seq_util u; - eautomaton* re2aut(expr* e); - eautomaton* seq2aut(expr* e); - public: - re2automaton(ast_manager& m); - eautomaton* operator()(expr* e) { return re2aut(e); } - }; - class theory_seq : public theory { typedef scoped_dependency_manager enode_pair_dependency_manager; typedef enode_pair_dependency_manager::dependency enode_pair_dependency; From 071a654a9a2c2d638813d94bd8c27e77f796fc28 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 27 Dec 2015 04:41:25 -0800 Subject: [PATCH 30/87] seq Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 64 +++++ src/ast/rewriter/seq_rewriter.h | 1 + src/smt/smt_context.cpp | 1 - src/smt/theory_arith.h | 6 + src/smt/theory_arith_aux.h | 1 + src/smt/theory_arith_core.h | 37 ++- src/smt/theory_seq.cpp | 432 +++++++++++++++++------------- src/smt/theory_seq.h | 30 ++- 8 files changed, 360 insertions(+), 212 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 428c4b224..ca471baa1 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -693,17 +693,76 @@ br_status seq_rewriter::mk_str_to_regexp(expr* a, expr_ref& result) { return BR_FAILED; } br_status seq_rewriter::mk_re_concat(expr* a, expr* b, expr_ref& result) { + if (is_epsilon(a)) { + result = b; + return BR_DONE; + } + if (is_epsilon(b)) { + result = a; + return BR_DONE; + } return BR_FAILED; } +/* + (a + a) = a + (a + eps) = a + (eps + a) = a +*/ br_status seq_rewriter::mk_re_union(expr* a, expr* b, expr_ref& result) { + if (a == b) { + result = a; + return BR_DONE; + } + if (m_util.re.is_star(a) && is_epsilon(b)) { + result = a; + return BR_DONE; + } + if (m_util.re.is_star(b) && is_epsilon(a)) { + result = b; + return BR_DONE; + } return BR_FAILED; } +/* + a** = a* + (a* + b)* = (a + b)* + (a + b*)* = (a + b)* + (a*b*)* = (a + b)* +*/ br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) { + expr* b, *c, *b1, *c1; + if (m_util.re.is_star(a)) { + result = a; + return BR_DONE; + } + if (m_util.re.is_union(a, b, c)) { + if (m_util.re.is_star(b, b1)) { + result = m_util.re.mk_star(m_util.re.mk_union(b1, c)); + return BR_REWRITE2; + } + if (m_util.re.is_star(c, c1)) { + result = m_util.re.mk_star(m_util.re.mk_union(b, c1)); + return BR_REWRITE2; + } + } + if (m_util.re.is_concat(a, b, c) && + m_util.re.is_star(b, b1) && m_util.re.is_star(c, c1)) { + result = m_util.re.mk_star(m_util.re.mk_union(b1, c1)); + return BR_REWRITE2; + } + return BR_FAILED; } + +/* + a+ = aa* +*/ br_status seq_rewriter::mk_re_plus(expr* a, expr_ref& result) { return BR_FAILED; +// result = m_util.re.mk_concat(a, m_util.re.mk_star(a)); +// return BR_REWRITE2; } + br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) { sort* s; VERIFY(m_util.is_re(a, s)); @@ -1014,6 +1073,11 @@ bool seq_rewriter::length_constrained(unsigned szl, expr* const* l, unsigned szr return false; } +bool seq_rewriter::is_epsilon(expr* e) const { + expr* e1; + return m_util.re.is_to_re(e, e1) && m_util.str.is_empty(e1); +} + bool seq_rewriter::is_subsequence(unsigned szl, expr* const* l, unsigned szr, expr* const* r, expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) { is_sat = true; diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index f6772bfe9..d5fac104b 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -75,6 +75,7 @@ class seq_rewriter { void add_next(u_map& next, unsigned idx, expr* cond); bool is_sequence(expr* e, expr_ref_vector& seq); + bool is_epsilon(expr* e) const; public: seq_rewriter(ast_manager & m, params_ref const & p = params_ref()): diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 738763c88..45dd7e3dc 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -1405,7 +1405,6 @@ namespace smt { else if (d.is_theory_atom()) { theory * th = m_theories.get_plugin(d.get_theory()); SASSERT(th); - TRACE("seq", tout << d.get_theory() << "\n";); th->assign_eh(v, val == l_true); } else if (d.is_quantifier()) { diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 1e0c7c5f4..2f5590e25 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -1056,6 +1056,10 @@ namespace smt { // ----------------------------------- virtual bool get_value(enode * n, expr_ref & r); + bool get_lower(enode* n, expr_ref& r); + bool get_upper(enode* n, expr_ref& r); + bool to_expr(inf_numeral const& val, bool is_int, expr_ref& r); + // ----------------------------------- // @@ -1071,6 +1075,8 @@ namespace smt { unsigned num_eqs, enode_pair const * eqs, unsigned num_params, parameter* params); inf_eps_rational conflict_minimize(); + + private: virtual expr_ref mk_gt(theory_var v); diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index e2a2d48a6..2473b32ab 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -2157,6 +2157,7 @@ namespace smt { enode * r = n->get_root(); enode_vector::const_iterator it = r->begin_parents(); enode_vector::const_iterator end = r->end_parents(); + TRACE("shared", tout << get_context().get_scope_level() << " " << v << " " << r->get_num_parents() << "\n";); for (; it != end; ++it) { enode * parent = *it; app * o = parent->get_owner(); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 96fe2d1f8..d6fe16089 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -3089,20 +3089,35 @@ namespace smt { // ----------------------------------- template - bool theory_arith::get_value(enode * n, expr_ref & r) { - theory_var v = n->get_th_var(get_id()); - if (v == null_theory_var) { - // TODO: generate fresh value different from other get_value(v) for all v. - return false; + bool theory_arith::to_expr(inf_numeral const& val, bool is_int, expr_ref & r) { + if (val.get_infinitesimal().is_zero()) { + numeral _val = val.get_rational(); + r = m_util.mk_numeral(_val.to_rational(), is_int); + return true; } - inf_numeral const & val = get_value(v); - if (!val.get_infinitesimal().is_zero()) { - // TODO: add support for infinitesimals + else { return false; } - numeral _val = val.get_rational(); - r = m_util.mk_numeral(_val.to_rational(), is_int(v)); - return true; + } + + template + bool theory_arith::get_value(enode * n, expr_ref & r) { + theory_var v = n->get_th_var(get_id()); + return v != null_theory_var && to_expr(get_value(v), is_int(v), r); + } + + template + bool theory_arith::get_lower(enode * n, expr_ref & r) { + theory_var v = n->get_th_var(get_id()); + bound* b = (v == null_theory_var) ? 0 : lower(v); + return b && to_expr(b->get_value(), is_int(v), r); + } + + template + bool theory_arith::get_upper(enode * n, expr_ref & r) { + theory_var v = n->get_th_var(get_id()); + bound* b = (v == null_theory_var) ? 0 : upper(v); + return b && to_expr(b->get_value(), is_int(v), r); } // ----------------------------------- diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 39ed71beb..d9e39c2ec 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -23,6 +23,7 @@ Revision History: #include "theory_seq.h" #include "seq_rewriter.h" #include "ast_trail.h" +#include "theory_arith.h" using namespace smt; @@ -37,6 +38,9 @@ struct display_expr { void theory_seq::solution_map::update(expr* e, expr* r, enode_pair_dependency* d) { + if (e == r) { + return; + } m_cache.reset(); std::pair value; if (m_map.find(e, value)) { @@ -61,6 +65,9 @@ expr* theory_seq::solution_map::find(expr* e, enode_pair_dependency*& d) { expr* result = e; while (m_map.find(result, value)) { d = m_dm.mk_join(d, value.second); + TRACE("seq", tout << mk_pp(result, m) << " -> " << mk_pp(value.first, m) << "\n";); + SASSERT(result != value.first); + SASSERT(e != value.first); result = value.first; } return result; @@ -139,8 +146,6 @@ theory_seq::theory_seq(ast_manager& m): m_axioms(m), m_axioms_head(0), m_branch_variable_head(0), - m_incomplete(false), - m_has_length(false), m_model_completion(false), m_mg(0), m_rewrite(m), @@ -179,37 +184,27 @@ final_check_status theory_seq::final_check_eh() { context & ctx = get_context(); TRACE("seq", display(tout);); if (!check_ineqs()) { + TRACE("seq", tout << "check_ineqs\n";); return FC_CONTINUE; } if (simplify_and_solve_eqs()) { + TRACE("seq", tout << "solve_eqs\n";); return FC_CONTINUE; } if (solve_nqs()) { - return FC_CONTINUE; - } - if (ctx.inconsistent()) { + TRACE("seq", tout << "solve_nqs\n";); return FC_CONTINUE; } if (branch_variable()) { TRACE("seq", tout << "branch\n";); return FC_CONTINUE; } - if (split_variable()) { - TRACE("seq", tout << "split_variable\n";); - return FC_CONTINUE; - } - if (ctx.inconsistent()) { - return FC_CONTINUE; - } if (!check_length_coherence()) { TRACE("seq", tout << "check_length_coherence\n";); return FC_CONTINUE; } - if (!check_length_coherence_tbd()) { - TRACE("seq", tout << "check_length_coherence\n";); - return FC_CONTINUE; - } if (propagate_automata()) { + TRACE("seq", tout << "propagate_automata\n";); return FC_CONTINUE; } if (is_solved()) { @@ -260,7 +255,7 @@ bool theory_seq::branch_variable() { return true; } } - return false; + return ctx.inconsistent(); } bool theory_seq::find_branch_candidate(expr* l, expr_ref_vector const& rs) { @@ -315,33 +310,9 @@ bool theory_seq::assume_equality(expr* l, expr* r) { } } -bool theory_seq::split_variable() { - - return false; -} bool theory_seq::check_length_coherence() { - if (!m_has_length) return true; - context& ctx = get_context(); - bool coherent = true; - for (unsigned i = 0; i < m_eqs.size(); ++i) { - m_eqs[i].m_dep; - expr_ref v1(m), v2(m), l(m_eqs[i].m_lhs), r(m_eqs[i].m_rhs); - expr_ref len1(m_util.str.mk_length(l), m); - expr_ref len2(m_util.str.mk_length(r), m); - enode* n1 = ensure_enode(len1); - enode* n2 = ensure_enode(len2); - if (n1->get_root() != n2->get_root()) { - TRACE("seq", tout << len1 << " = " << len2 << "\n";); - propagate_eq(m_eqs[i].m_dep, n1, n2); - coherent = false; - } - } - return coherent; -} - -bool theory_seq::check_length_coherence_tbd() { - if (!m_has_length) return true; + if (m_length.empty()) return true; context& ctx = get_context(); bool coherent = true; // each variable that canonizes to itself can have length 0. @@ -359,9 +330,36 @@ bool theory_seq::check_length_coherence_tbd() { expr* f = m_rep.find(e, dep); if (is_var(f) && f == e) { expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); + expr_ref head(m), tail(m); + rational lo, hi; TRACE("seq", tout << "Unsolved " << mk_pp(e, m) << "\n";); - if (!assume_equality(e, emp)) { - expr_ref head(m), tail(m); + if (lower_bound(e, lo) && lo.is_pos() && lo < rational(512)) { + TRACE("seq", tout << "lower bound: " << mk_pp(e, m) << " " << lo << "\n";); + expr_ref low(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)), m); + expr_ref seq(e, m); + expr_ref_vector elems(m); + unsigned _lo = lo.get_unsigned(); + for (unsigned j = 0; j < _lo; ++j) { + mk_decompose(seq, emp, head, tail); + elems.push_back(head); + seq = tail; + } + elems.push_back(seq); + tail = m_util.str.mk_concat(elems.size(), elems.c_ptr()); + // len(e) >= low => e = tail + add_axiom(~mk_literal(low), mk_eq(e, tail, false)); + assume_equality(tail, e); + if (upper_bound(e, hi) && hi == lo) { + expr_ref high(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)), m); + add_axiom(~mk_literal(high), mk_eq(seq, emp, false)); + } + } + else if (upper_bound(e, hi) && hi.is_zero()) { + expr_ref len(m_util.str.mk_length(e), m); + expr_ref zero(m_autil.mk_int(0), m); + add_axiom(~mk_eq(len, zero, false), mk_eq(e, emp, false)); + } + else if (!assume_equality(e, emp)) { mk_decompose(e, emp, head, tail); // e = emp \/ e = unit(head.elem(e))*tail(e) expr_ref conc(m_util.str.mk_concat(head, tail), m); @@ -438,8 +436,6 @@ bool theory_seq::is_solved() { if (!m_automata[i]) return false; } - SASSERT(check_length_coherence()); - return true; } @@ -487,7 +483,7 @@ void theory_seq::propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2) -bool theory_seq::simplify_eq(expr* l, expr* r, enode_pair_dependency* deps) { +bool theory_seq::simplify_eq(expr* l, expr* r, enode_pair_dependency* deps, bool& propagated) { context& ctx = get_context(); seq_rewriter rw(m); expr_ref_vector lhs(m), rhs(m); @@ -497,44 +493,47 @@ bool theory_seq::simplify_eq(expr* l, expr* r, enode_pair_dependency* deps) { // equality is inconsistent. TRACE("seq", tout << lh << " != " << rh << "\n";); set_conflict(deps); + propagated = true; return true; } if (unchanged(l, lhs) && unchanged(r, rhs)) { return false; } + if (unchanged(r, lhs) && unchanged(l, rhs)) { + return false; + } SASSERT(lhs.size() == rhs.size()); for (unsigned i = 0; i < lhs.size(); ++i) { - expr_ref l(lhs[i].get(), m); - expr_ref r(rhs[i].get(), m); - if (m_util.is_seq(l) || m_util.is_re(l)) { - m_eqs.push_back(eq(l, r, deps)); + expr_ref li(lhs[i].get(), m); + expr_ref ri(rhs[i].get(), m); + if (m_util.is_seq(li) || m_util.is_re(li)) { + m_eqs.push_back(eq(li, ri, deps)); } else { - propagate_eq(deps, ensure_enode(l), ensure_enode(r)); + propagate_eq(deps, ensure_enode(li), ensure_enode(ri)); + propagated = true; } - } + } TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " => "; - for (unsigned i = 0; i < m_eqs.size(); ++i) { - tout << m_eqs[i].m_lhs << " = " << m_eqs[i].m_rhs << "; "; + for (unsigned i = 0; i < lhs.size(); ++i) { + tout << mk_pp(lhs[i].get(), m) << " = " << mk_pp(rhs[i].get(), m) << "; "; } - tout << "\n"; - ); + tout << "\n";); return true; } -bool theory_seq::solve_unit_eq(expr* l, expr* r, enode_pair_dependency* deps) { +bool theory_seq::solve_unit_eq(expr* l, expr* r, enode_pair_dependency* deps, bool& propagated) { expr_ref lh = canonize(l, deps); expr_ref rh = canonize(r, deps); if (lh == rh) { return true; } if (is_var(lh) && !occurs(lh, rh)) { - add_solution(lh, rh, deps); - return true; + propagated = add_solution(lh, rh, deps) || propagated; } if (is_var(rh) && !occurs(rh, lh)) { - add_solution(rh, lh, deps); + propagated = add_solution(rh, lh, deps) || propagated; return true; } // Use instead reference counts for dependencies to GC? @@ -585,25 +584,32 @@ bool theory_seq::is_head_elem(expr* e) const { return is_skolem(m_head_elem, e); } -void theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) { +bool theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) { + if (l == r) { + return false; + } context& ctx = get_context(); m_rep.update(l, r, deps); // TBD: skip new equalities for non-internalized terms. - if (ctx.e_internalized(l) && ctx.e_internalized(r)) { + if (ctx.e_internalized(l) && ctx.e_internalized(r) && ctx.get_enode(l)->get_root() != ctx.get_enode(r)->get_root()) { propagate_eq(deps, ctx.get_enode(l), ctx.get_enode(r)); + return true; + } + else { + return false; } } -bool theory_seq::pre_process_eqs(bool simplify_or_solve) { +bool theory_seq::pre_process_eqs(bool simplify_or_solve, bool& propagated) { context& ctx = get_context(); bool change = false; for (unsigned i = 0; !ctx.inconsistent() && i < m_eqs.size(); ++i) { eq e = m_eqs[i]; if (simplify_or_solve? - simplify_eq(e.m_lhs, e.m_rhs, e.m_dep): - solve_unit_eq(e.m_lhs, e.m_rhs, e.m_dep)) { + simplify_eq(e.m_lhs, e.m_rhs, e.m_dep, propagated): + solve_unit_eq(e.m_lhs, e.m_rhs, e.m_dep, propagated)) { if (i + 1 != m_eqs.size()) { eq e1 = m_eqs[m_eqs.size()-1]; m_eqs.set(i, e1); @@ -625,7 +631,7 @@ bool theory_seq::solve_nqs() { change = solve_ne(i) || change; } } - return change; + return change || ctx.inconsistent(); } bool theory_seq::solve_ne(unsigned idx) { @@ -728,12 +734,12 @@ void theory_seq::erase_index(unsigned idx, unsigned i) { bool theory_seq::simplify_and_solve_eqs() { context & ctx = get_context(); - bool change = simplify_eqs(); - while (!ctx.inconsistent() && solve_basic_eqs()) { - simplify_eqs(); - change = true; + bool propagated = false; + simplify_eqs(propagated); + while (!ctx.inconsistent() && solve_basic_eqs(propagated)) { + simplify_eqs(propagated); } - return change; + return propagated || ctx.inconsistent(); } @@ -741,8 +747,9 @@ bool theory_seq::internalize_term(app* term) { TRACE("seq", tout << mk_pp(term, m) << "\n";); context & ctx = get_context(); unsigned num_args = term->get_num_args(); + expr* arg; for (unsigned i = 0; i < num_args; i++) { - expr* arg = term->get_arg(i); + arg = term->get_arg(i); mk_var(ensure_enode(arg)); } if (m.is_bool(term)) { @@ -761,23 +768,35 @@ bool theory_seq::internalize_term(app* term) { } mk_var(e); } - if (m_util.str.is_length(term) && !m_has_length) { - m_trail_stack.push(value_trail(m_has_length)); - m_has_length = true; - } - if (!m_util.str.is_concat(term) && - !m_util.str.is_string(term) && - !m_util.str.is_empty(term) && - !m_util.str.is_unit(term) && - !m_util.str.is_suffix(term) && - !m_util.str.is_prefix(term) && - !m_util.str.is_contains(term) && - !m_util.is_skolem(term)) { - set_incomplete(term); + if (m_util.str.is_length(term, arg) && !has_length(arg)) { + add_length(arg); } return true; } +void theory_seq::add_length(expr* e) { + SASSERT(!has_length(e)); + m_length.insert(e); + m_trail_stack.push(insert_obj_trail(m_length, e)); +} + +/* + ensure that all elements in equivalence class occur under an applicatin of 'length' +*/ +void theory_seq::enforce_length(enode* n) { + enode* n1 = n; + do { + expr* o = n->get_owner(); + if (!has_length(o)) { + expr_ref len(m_util.str.mk_length(o), m); + enque_axiom(len); + add_length(o); + } + n = n->get_next(); + } + while (n1 != n); +} + void theory_seq::apply_sort_cnstr(enode* n, sort* s) { mk_var(n); } @@ -886,14 +905,6 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { -void theory_seq::set_incomplete(app* term) { - if (!m_incomplete) { - TRACE("seq", tout << "Incomplete operator: " << mk_pp(term, m) << "\n";); - m_trail_stack.push(value_trail(m_incomplete)); - m_incomplete = true; - } -} - theory_var theory_seq::mk_var(enode* n) { if (!m_util.is_seq(n->get_owner()) && !m_util.is_re(n->get_owner())) { @@ -927,7 +938,6 @@ expr_ref theory_seq::expand(expr* e0, enode_pair_dependency*& eqs) { if (m_rep.find_cache(e0, ed)) { eqs = m_dm.mk_join(eqs, ed.second); result = ed.first; - TRACE("seq", tout << mk_pp(e0, m) << " |-> " << result << " "; display_deps(tout, eqs);); return result; } expr* e = m_rep.find(e0, deps); @@ -999,7 +1009,7 @@ expr_ref theory_seq::expand(expr* e0, enode_pair_dependency*& eqs) { expr_dep edr(result, deps); m_rep.add_cache(e0, edr); eqs = m_dm.mk_join(eqs, deps); - TRACE("seq", tout << mk_pp(e0, m) << " |--> " << result << "\n"; + TRACE("seq_verbose", tout << mk_pp(e0, m) << " |--> " << result << "\n"; display_deps(tout, eqs);); return result; } @@ -1043,21 +1053,8 @@ void theory_seq::deque_axiom(expr* n) { else if (m_util.str.is_at(n)) { add_at_axiom(n); } - else if (m_util.str.is_unit(n)) { - add_length_unit_axiom(n); - } - else if (m_util.str.is_empty(n)) { - add_length_empty_axiom(n); - } - else if (m_util.str.is_concat(n)) { - add_length_concat_axiom(n); - } else if (m_util.str.is_string(n)) { add_elim_string_axiom(n); - // add_length_string_axiom(n); - } - else if (m_util.str.is_in_re(n)) { - add_in_re_axiom(n); } } @@ -1180,24 +1177,12 @@ void theory_seq::add_replace_axiom(expr* r) { tightest_prefix(s, x, ~cnt); } -void theory_seq::add_length_unit_axiom(expr* n) { - if (!m_has_length) return; - SASSERT(m_util.str.is_unit(n)); - expr_ref one(m_autil.mk_int(1), m), len(m_util.str.mk_length(n), m); - add_axiom(mk_eq(len, one, false)); -} - -void theory_seq::add_length_empty_axiom(expr* n) { - if (!m_has_length) return; - SASSERT(m_util.str.is_empty(n)); - expr_ref zero(m_autil.mk_int(0), m), len(m_util.str.mk_length(n), m); - add_axiom(mk_eq(len, zero, false)); -} - void theory_seq::add_elim_string_axiom(expr* n) { zstring s; VERIFY(m_util.str.is_string(n, s)); - SASSERT(s.length() > 0); + if (s.length() == 0) { + return; + } expr_ref result(m_util.str.mk_unit(m_util.str.mk_char(s, s.length()-1)), m); for (unsigned i = s.length()-1; i > 0; ) { --i; @@ -1207,25 +1192,14 @@ void theory_seq::add_elim_string_axiom(expr* n) { m_rep.update(n, result, 0); } -void theory_seq::add_length_string_axiom(expr* n) { - if (!m_has_length) return; - zstring s; - VERIFY(m_util.str.is_string(n, s)); - expr_ref len(m_util.str.mk_length(n), m); - expr_ref ls(m_autil.mk_numeral(rational(s.length(), rational::ui64()), true), m); - add_axiom(mk_eq(len, ls, false)); -} -void theory_seq::add_length_concat_axiom(expr* n) { - if (!m_has_length) return; - expr* a, *b; - VERIFY(m_util.str.is_concat(n, a, b)); - expr_ref len(m_util.str.mk_length(n), m); - expr_ref _a(m_util.str.mk_length(a), m); - expr_ref _b(m_util.str.mk_length(b), m); - expr_ref ab(m_autil.mk_add(_a, _b), m); - m_rewrite(ab); - add_axiom(mk_eq(ab, len, false)); +void theory_seq::add_length_coherence_axiom(expr* n) { + expr_ref len(n, m); + m_rewrite(len); + if (n != len) { + TRACE("seq", tout << "Add length coherence for " << mk_pp(n, m) << "\n";); + add_axiom(mk_eq(n, len, false)); + } } /* @@ -1240,8 +1214,7 @@ void theory_seq::add_length_axiom(expr* n) { VERIFY(m_util.str.is_length(n, x)); if (!m_util.str.is_unit(x) && !m_util.str.is_empty(x) && - !m_util.str.is_string(x) && - !m_util.str.is_concat(x)) { + !m_util.str.is_string(x)) { expr_ref zero(m_autil.mk_int(0), m); expr_ref emp(m_util.str.mk_empty(m.get_sort(x)), m); literal eq1(mk_eq(zero, n, false)); @@ -1250,18 +1223,45 @@ void theory_seq::add_length_axiom(expr* n) { add_axiom(~eq1, eq2); add_axiom(~eq2, eq1); } + if (m_util.str.is_concat(x) || + m_util.str.is_unit(x) || + m_util.str.is_empty(x) || + m_util.str.is_string(x)) { + add_length_coherence_axiom(x); + } } -// -// the empty sequence is accepted only in the final states. -// membership holds iff the initial state holds. -// -void theory_seq::add_in_re_axiom(expr* n) { + + +void theory_seq::propagate_in_re(expr* n, bool is_true) { + TRACE("seq", tout << mk_pp(n, m) << " <- " << (is_true?"true":"false") << "\n";); expr* e1, *e2; VERIFY(m_util.str.is_in_re(n, e1, e2)); + + expr_ref tmp(n, m); + m_rewrite(tmp); + if (m.is_true(tmp)) { + if (!is_true) { + literal_vector lits; + lits.push_back(mk_literal(n)); + set_conflict(0, lits); + } + return; + } + else if (m.is_false(tmp)) { + if (is_true) { + literal_vector lits; + lits.push_back(~mk_literal(n)); + set_conflict(0, lits); + } + return; + } + eautomaton* a = get_automaton(e2); if (!a) return; - + if (m_util.str.is_empty(e1)) return; + context& ctx = get_context(); + expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); for (unsigned i = 0; i < a->num_states(); ++i) { literal acc = mk_accept(emp, e2, i); @@ -1269,17 +1269,7 @@ void theory_seq::add_in_re_axiom(expr* n) { add_axiom(a->is_final_state(i)?acc:~acc); add_axiom(a->is_final_state(i)?~rej:rej); } -} - -void theory_seq::propagate_in_re(expr* n, bool is_true) { - TRACE("seq", tout << mk_pp(n, m) << " <- " << (is_true?"true":"false") << "\n";); - expr* e1, *e2; - VERIFY(m_util.str.is_in_re(n, e1, e2)); - eautomaton* a = get_automaton(e2); - if (!a) return; - if (m_util.str.is_empty(e1)) return; - context& ctx = get_context(); unsigned_vector states; a->get_epsilon_closure(a->init(), states); literal_vector lits; @@ -1323,6 +1313,80 @@ enode* theory_seq::ensure_enode(expr* e) { return ctx.get_enode(e); } +static theory_mi_arith* get_th_arith(context& ctx, theory_id afid, expr* e) { + ast_manager& m = ctx.get_manager(); + theory* th = ctx.get_theory(afid); + if (th && ctx.e_internalized(e)) { + return dynamic_cast(th); + } + else { + return 0; + } +} + +bool theory_seq::lower_bound(expr* _e, rational& lo) { + context& ctx = get_context(); + expr_ref e(m_util.str.mk_length(_e), m); + theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); + expr_ref _lo(m); + if (!tha || !tha->get_lower(ctx.get_enode(e), _lo)) return false; + return m_autil.is_numeral(_lo, lo) && lo.is_int(); +} + +bool theory_seq::upper_bound(expr* _e, rational& hi) { + context& ctx = get_context(); + expr_ref e(m_util.str.mk_length(_e), m); + theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e); + expr_ref _hi(m); + if (!tha || !tha->get_upper(ctx.get_enode(e), _hi)) return false; + return m_autil.is_numeral(_hi, hi) && hi.is_int(); +} + +bool theory_seq::get_length(expr* e, rational& val) { + context& ctx = get_context(); + theory* th = ctx.get_theory(m_autil.get_family_id()); + if (!th) return false; + theory_mi_arith* tha = dynamic_cast(th); + if (!tha) return false; + rational val1; + expr_ref len(m), len_val(m); + expr* e1, *e2; + ptr_vector todo; + todo.push_back(e); + val.reset(); + zstring s; + while (!todo.empty()) { + expr* c = todo.back(); + todo.pop_back(); + if (m_util.str.is_concat(c, e1, e2)) { + todo.push_back(e1); + todo.push_back(e2); + } + else if (m_util.str.is_unit(c)) { + val += rational(1); + } + else if (m_util.str.is_empty(c)) { + continue; + } + else if (m_util.str.is_string(c, s)) { + val += rational(s.length()); + } + else { + len = m_util.str.mk_length(c); + if (ctx.e_internalized(len) && + tha->get_value(ctx.get_enode(len), len_val) && + m_autil.is_numeral(len_val, val1)) { + val += val1; + } + else { + TRACE("seq", tout << "No length provided for " << len << "\n";); + return false; + } + } + } + return val.is_int(); +} + /* TBD: check semantics of extract. @@ -1445,7 +1509,7 @@ void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) { ctx.mark_as_relevant(n1); ctx.mark_as_relevant(n2); TRACE("seq", - tout << mk_pp(ctx.bool_var2enode(v)->get_owner(), m) << " => " + tout << mk_pp(ctx.bool_var2expr(v), m) << " => " << mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";); literal lit(v); justification* js = @@ -1522,7 +1586,17 @@ void theory_seq::new_eq_eh(theory_var v1, theory_var v2) { expr_ref o1(n1->get_owner(), m); expr_ref o2(n2->get_owner(), m); TRACE("seq", tout << o1 << " = " << o2 << "\n";); - m_eqs.push_back(eq(o1, o2, m_dm.mk_leaf(enode_pair(n1, n2)))); + enode_pair_dependency* deps = m_dm.mk_leaf(enode_pair(n1, n2)); + bool propagated = false; + if (!simplify_eq(o1, o2, deps, propagated)) { + m_eqs.push_back(eq(o1, o2, deps)); + } + if (has_length(o1) && !has_length(o2)) { + enforce_length(n2); + } + else if (has_length(o2) && !has_length(o1)) { + enforce_length(n1); + } } } @@ -1531,8 +1605,12 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { enode* n2 = get_enode(v2); expr_ref e1(n1->get_owner(), m); expr_ref e2(n2->get_owner(), m); - m_nqs.push_back(ne(e1, e2)); m_exclude.update(e1, e2); + expr_ref eq(m.mk_eq(e1, e2), m); + m_rewrite(eq); + if (!m.is_false(eq)) { + m_nqs.push_back(ne(e1, e2)); + } } void theory_seq::push_scope_eh() { @@ -1565,34 +1643,10 @@ void theory_seq::relevant_eh(app* n) { m_util.str.is_replace(n) || m_util.str.is_extract(n) || m_util.str.is_at(n) || - m_util.str.is_concat(n) || - m_util.str.is_empty(n) || - m_util.str.is_unit(n) || m_util.str.is_string(n) || - m_util.str.is_in_re(n) || is_step(n)) { enque_axiom(n); } -#if 0 - if (m_util.str.is_in_re(n) || - m_util.str.is_contains(n) || - m_util.str.is_suffix(n) || - m_util.str.is_prefix(n)) { - context& ctx = get_context(); - TRACE("seq", tout << mk_pp(n, m) << "\n";); - bool_var bv = ctx.get_bool_var(n); - switch (ctx.get_assignment(bv)) { - case l_false: - assign_eh(bv, false); - break; - case l_true: - assign_eh(bv, true); - break; - case l_undef: - break; - } - } -#endif } @@ -1687,7 +1741,9 @@ void theory_seq::add_accept2step(expr* acc) { mk_decompose(s, emp, head, tail); literal_vector lits; lits.push_back(~ctx.get_literal(acc)); - lits.push_back(mk_eq(emp, s, false)); + if (aut->is_final_state(src)) { + lits.push_back(mk_eq(emp, s, false)); + } for (unsigned i = 0; i < mvs.size(); ++i) { eautomaton::move mv = mvs[i]; step = mk_step(s, tail, re, src, mv.dst(), mv.t()); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 59b721fa7..e7f610695 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -259,7 +259,7 @@ namespace smt { unsigned m_axioms_head; // index of first axiom to add. unsigned m_branch_variable_head; // index of first equation to examine. bool m_incomplete; // is the solver (clearly) incomplete for the fragment. - bool m_has_length; // is length applied + obj_hashtable m_length; // is length applied bool m_model_completion; // during model construction, invent values in canonizer model_generator* m_mg; th_rewriter m_rewrite; @@ -306,14 +306,13 @@ namespace smt { bool split_variable(); // split a variable bool is_solved(); bool check_length_coherence(); - bool check_length_coherence_tbd(); bool check_ineq_coherence(); - bool pre_process_eqs(bool simplify_or_solve); - bool simplify_eqs() { return pre_process_eqs(true); } - bool solve_basic_eqs() { return pre_process_eqs(false); } - bool simplify_eq(expr* l, expr* r, enode_pair_dependency* dep); - bool solve_unit_eq(expr* l, expr* r, enode_pair_dependency* dep); + bool pre_process_eqs(bool simplify_or_solve, bool& propagated); + bool simplify_eqs(bool& propagated) { return pre_process_eqs(true, propagated); } + bool solve_basic_eqs(bool& propagated) { return pre_process_eqs(false, propagated); } + bool simplify_eq(expr* l, expr* r, enode_pair_dependency* dep, bool& propagated); + bool solve_unit_eq(expr* l, expr* r, enode_pair_dependency* dep, bool& propagated); bool solve_nqs(); bool solve_ne(unsigned i); @@ -332,7 +331,7 @@ namespace smt { // variable solving utilities bool occurs(expr* a, expr* b); bool is_var(expr* b); - void add_solution(expr* l, expr* r, enode_pair_dependency* dep); + bool add_solution(expr* l, expr* r, enode_pair_dependency* dep); bool is_left_select(expr* a, expr*& b); bool is_right_select(expr* a, expr*& b); bool is_head_elem(expr* a) const; @@ -349,10 +348,12 @@ namespace smt { void add_replace_axiom(expr* e); void add_extract_axiom(expr* e); void add_length_axiom(expr* n); - void add_length_unit_axiom(expr* n); - void add_length_empty_axiom(expr* n); - void add_length_concat_axiom(expr* n); - void add_length_string_axiom(expr* n); + void add_length_coherence_axiom(expr* n); + + bool has_length(expr *e) const { return m_length.contains(e); } + void add_length(expr* e); + void enforce_length(enode* n); + void add_elim_string_axiom(expr* n); void add_at_axiom(expr* n); void add_in_re_axiom(expr* n); @@ -361,6 +362,11 @@ namespace smt { expr_ref mk_sub(expr* a, expr* b); enode* ensure_enode(expr* a); + // arithmetic integration + bool lower_bound(expr* s, rational& lo); + bool upper_bound(expr* s, rational& hi); + bool get_length(expr* s, rational& val); + void mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& tail); expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2 = 0, expr* e3 = 0, sort* range = 0); bool is_skolem(symbol const& s, expr* e) const; From 739043e2733414bc46f744ba5984daf7dbc19965 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Dec 2015 10:28:43 -0800 Subject: [PATCH 31/87] seq Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 13 +- src/math/automata/automaton.h | 20 +- src/smt/theory_seq.cpp | 325 +++++++++++++++++------------- src/smt/theory_seq.h | 12 +- 4 files changed, 213 insertions(+), 157 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index ca471baa1..aa27489ad 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -25,6 +25,14 @@ Notes: #include"automaton.h" +struct display_expr1 { + ast_manager& m; + display_expr1(ast_manager& m): m(m) {} + std::ostream& display(std::ostream& out, expr* e) const { + return out << mk_pp(e, m); + } +}; + re2automaton::re2automaton(ast_manager& m): m(m), u(m) {} @@ -36,6 +44,7 @@ eautomaton* re2automaton::operator()(expr* e) { return r; } + eautomaton* re2automaton::re2aut(expr* e) { SASSERT(u.is_re(e)); expr* e1, *e2; @@ -230,8 +239,8 @@ br_status seq_rewriter::mk_seq_concat(expr* a, expr* b, expr_ref& result) { result = m_util.str.mk_string(s1 + s2); return BR_DONE; } - if (m_util.str.is_concat(b, c, d)) { - result = m_util.str.mk_concat(m_util.str.mk_concat(a, c), d); + if (m_util.str.is_concat(a, c, d)) { + result = m_util.str.mk_concat(c, m_util.str.mk_concat(d, b)); return BR_REWRITE2; } if (m_util.str.is_empty(a)) { diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index dabfa1417..fb6bb31fd 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -84,6 +84,12 @@ private: mutable uint_set m_visited; mutable unsigned_vector m_todo; + struct default_display { + std::ostream& display(std::ostream& out, T* t) { + return out << t; + } + }; + public: // The empty automaton: @@ -216,7 +222,7 @@ public: mvs.push_back(move(m, 0, a.init() + offset1)); append_moves(offset1, a, mvs); for (unsigned i = 0; i < a.m_final_states.size(); ++i) { - mvs.push_back(move(m, a.m_final_states[i], b.init())); + mvs.push_back(move(m, a.m_final_states[i], b.init() + offset2)); } append_moves(offset2, b, mvs); append_final(offset2, b, final); @@ -278,7 +284,7 @@ public: for (unsigned j = 0; found && j < mvs.size(); ++j) { found = (mvs[j].dst() == m_init) && mvs[j].is_epsilon(); } - if (!found) { + if (!found && state != m_init) { add(move(m, state, m_init)); } } @@ -301,7 +307,7 @@ public: if (src == dst) { // just remove this edge. } - else if (1 == in_degree(src) && init() != src && (!is_final_state(src) || is_final_state(dst))) { + else if (1 == in_degree(src) && 1 == out_degree(src) && init() != src && (!is_final_state(src) || is_final_state(dst))) { move const& mv0 = m_delta_inv[src][0]; unsigned src0 = mv0.src(); T* t = mv0.t(); @@ -311,8 +317,9 @@ public: } add(move(m, src0, dst, t)); remove(src0, src, t); + } - else if (1 == out_degree(dst) && init() != dst && (!is_final_state(dst) || is_final_state(src))) { + else if (1 == out_degree(dst) && 1 == in_degree(dst) && init() != dst && (!is_final_state(dst) || is_final_state(src))) { move const& mv1 = m_delta[dst][0]; unsigned dst1 = mv1.dst(); T* t = mv1.t(); @@ -322,6 +329,7 @@ public: } add(move(m, src, dst1, t)); remove(dst, dst1, t); + } else { continue; @@ -422,8 +430,8 @@ public: get_moves(state, m_delta_inv, mvs, epsilon_closure); } - template - std::ostream& display(std::ostream& out, D& displayer) const { + template + std::ostream& display(std::ostream& out, D& displayer = D()) const { out << "init: " << init() << "\n"; out << "final: "; for (unsigned i = 0; i < m_final_states.size(); ++i) out << m_final_states[i] << " "; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index d9e39c2ec..983730158 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -146,7 +146,6 @@ theory_seq::theory_seq(ast_manager& m): m_axioms(m), m_axioms_head(0), m_branch_variable_head(0), - m_model_completion(false), m_mg(0), m_rewrite(m), m_util(m), @@ -157,14 +156,12 @@ theory_seq::theory_seq(ast_manager& m): m_steps_qhead(0) { m_prefix = "seq.prefix.suffix"; m_suffix = "seq.suffix.prefix"; - m_left = "seq.left"; - m_right = "seq.right"; m_contains_left = "seq.contains.left"; m_contains_right = "seq.contains.right"; m_accept = "aut.accept"; m_reject = "aut.reject"; m_tail = "seq.tail"; - m_head_elem = "seq.head.elem"; + m_nth = "seq.nth"; m_seq_first = "seq.first"; m_seq_last = "seq.last"; m_indexof_left = "seq.indexof.left"; @@ -196,7 +193,7 @@ final_check_status theory_seq::final_check_eh() { return FC_CONTINUE; } if (branch_variable()) { - TRACE("seq", tout << "branch\n";); + TRACE("seq", tout << "branch_variable\n";); return FC_CONTINUE; } if (!check_length_coherence()) { @@ -315,27 +312,27 @@ bool theory_seq::check_length_coherence() { if (m_length.empty()) return true; context& ctx = get_context(); bool coherent = true; - // each variable that canonizes to itself can have length 0. - unsigned sz = get_num_vars(); - for (unsigned i = 0; i < sz; ++i) { - unsigned j = (i + m_branch_variable_head) % sz; - enode* n = get_enode(j); - expr* e = n->get_owner(); - if (m_util.is_re(e)) { - continue; - } - SASSERT(m_util.is_seq(e)); - // extend length of variables. + obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); + for (; it != end; ++it) { + expr* e = *it; enode_pair_dependency* dep = 0; expr* f = m_rep.find(e, dep); if (is_var(f) && f == e) { expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); expr_ref head(m), tail(m); rational lo, hi; - TRACE("seq", tout << "Unsolved " << mk_pp(e, m) << "\n";); + TRACE("seq", tout << "Unsolved " << mk_pp(e, m); + if (!lower_bound(e, lo)) lo = -rational::one(); + if (!upper_bound(e, hi)) hi = -rational::one(); + tout << " lo: " << lo << " "; + tout << "hi: " << hi << " "; + tout << "\n"; + ctx.display(tout); + ); + + if (lower_bound(e, lo) && lo.is_pos() && lo < rational(512)) { - TRACE("seq", tout << "lower bound: " << mk_pp(e, m) << " " << lo << "\n";); - expr_ref low(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)), m); + literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)))); expr_ref seq(e, m); expr_ref_vector elems(m); unsigned _lo = lo.get_unsigned(); @@ -347,18 +344,14 @@ bool theory_seq::check_length_coherence() { elems.push_back(seq); tail = m_util.str.mk_concat(elems.size(), elems.c_ptr()); // len(e) >= low => e = tail - add_axiom(~mk_literal(low), mk_eq(e, tail, false)); + add_axiom(~low, mk_eq(e, tail, false)); assume_equality(tail, e); - if (upper_bound(e, hi) && hi == lo) { - expr_ref high(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)), m); - add_axiom(~mk_literal(high), mk_eq(seq, emp, false)); + if (upper_bound(e, hi)) { + expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m); + expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); + add_axiom(~mk_literal(high1), mk_literal(high2)); } } - else if (upper_bound(e, hi) && hi.is_zero()) { - expr_ref len(m_util.str.mk_length(e), m); - expr_ref zero(m_autil.mk_int(0), m); - add_axiom(~mk_eq(len, zero, false), mk_eq(e, emp, false)); - } else if (!assume_equality(e, emp)) { mk_decompose(e, emp, head, tail); // e = emp \/ e = unit(head.elem(e))*tail(e) @@ -366,7 +359,6 @@ bool theory_seq::check_length_coherence() { add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false)); assume_equality(tail, emp); } - m_branch_variable_head = j + 1; return false; } } @@ -380,8 +372,8 @@ void theory_seq::mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& VERIFY(m_util.is_seq(m.get_sort(e), char_sort)); emp = m_util.str.mk_empty(m.get_sort(e)); if (m_util.str.is_empty(e)) { - head = m_util.str.mk_unit(mk_skolem(m_head_elem, e, 0, 0, char_sort)); - tail = mk_skolem(m_tail, e); + head = m_util.str.mk_unit(mk_skolem(m_nth, e, m_autil.mk_int(0), 0, char_sort)); + tail = e; } else if (m_util.str.is_string(e, s)) { head = m_util.str.mk_unit(m_util.str.mk_char(s, 0)); @@ -395,13 +387,18 @@ void theory_seq::mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& head = e1; tail = e2; } + else if (is_skolem(m_tail, e)) { + rational r; + app* a = to_app(e); + expr* s = a->get_arg(0); + VERIFY (m_autil.is_numeral(a->get_arg(1), r)); + expr* idx = m_autil.mk_int(r.get_unsigned() + 1); + head = m_util.str.mk_unit(mk_skolem(m_nth, s, idx, 0, char_sort)); + tail = mk_skolem(m_tail, s, idx); + } else { - head = m_util.str.mk_unit(mk_skolem(m_head_elem, e, 0, 0, char_sort)); - tail = mk_skolem(m_tail, e); - if (!m_util.is_skolem(e)) { - expr_ref conc(m_util.str.mk_concat(head, tail), m); - add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false)); - } + head = m_util.str.mk_unit(mk_skolem(m_nth, e, m_autil.mk_int(0), 0, char_sort)); + tail = mk_skolem(m_tail, e, m_autil.mk_int(0)); } } @@ -531,6 +528,7 @@ bool theory_seq::solve_unit_eq(expr* l, expr* r, enode_pair_dependency* deps, bo } if (is_var(lh) && !occurs(lh, rh)) { propagated = add_solution(lh, rh, deps) || propagated; + return true; } if (is_var(rh) && !occurs(rh, lh)) { propagated = add_solution(rh, lh, deps) || propagated; @@ -547,19 +545,21 @@ bool theory_seq::solve_unit_eq(expr* l, expr* r, enode_pair_dependency* deps, bo bool theory_seq::occurs(expr* a, expr* b) { // true if a occurs under an interpreted function or under left/right selector. SASSERT(is_var(a)); + SASSERT(m_todo.empty()); expr* e1, *e2; - while (is_left_select(a, e1) || is_right_select(a, e1)) { - a = e1; + m_todo.push_back(b); + while (!m_todo.empty()) { + b = m_todo.back(); + if (a == b) { + m_todo.reset(); + return true; + } + m_todo.pop_back(); + if (m_util.str.is_concat(b, e1, e2)) { + m_todo.push_back(e1); + m_todo.push_back(e2); + } } - if (m_util.str.is_concat(b, e1, e2)) { - return occurs(a, e1) || occurs(a, e2); - } - while (is_left_select(b, e1) || is_right_select(b, e1)) { - b = e1; - } - if (a == b) { - return true; - } return false; } @@ -572,16 +572,9 @@ bool theory_seq::is_var(expr* a) { !m_util.str.is_unit(a); } -bool theory_seq::is_left_select(expr* a, expr*& b) { - return is_skolem(m_left, a) && (b = to_app(a)->get_arg(0), true); -} - -bool theory_seq::is_right_select(expr* a, expr*& b) { - return is_skolem(m_right, a) && (b = to_app(a)->get_arg(0), true); -} bool theory_seq::is_head_elem(expr* e) const { - return is_skolem(m_head_elem, e); + return is_skolem(m_nth, e); } bool theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) { @@ -589,6 +582,7 @@ bool theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) { return false; } context& ctx = get_context(); + TRACE("seq", tout << mk_pp(l, m) << " ==> " << mk_pp(r, m) << "\n";); m_rep.update(l, r, deps); // TBD: skip new equalities for non-internalized terms. if (ctx.e_internalized(l) && ctx.e_internalized(r) && ctx.get_enode(l)->get_root() != ctx.get_enode(r)->get_root()) { @@ -768,9 +762,6 @@ bool theory_seq::internalize_term(app* term) { } mk_var(e); } - if (m_util.str.is_length(term, arg) && !has_length(arg)) { - add_length(arg); - } return true; } @@ -889,20 +880,103 @@ void theory_seq::init_model(model_generator & mg) { mg.register_factory(m_factory); } + +class seq_value_proc : public model_value_proc { + theory_seq& th; + app* n; + svector m_dependencies; +public: + seq_value_proc(theory_seq& th, app* n): th(th), n(n) { + } + virtual ~seq_value_proc() {} + void add_dependency(enode* n) { m_dependencies.push_back(model_value_dependency(n)); } + virtual void get_dependencies(buffer & result) { + result.append(m_dependencies.size(), m_dependencies.c_ptr()); + } + virtual app * mk_value(model_generator & mg, ptr_vector & values) { + SASSERT(values.size() == m_dependencies.size()); + ast_manager& m = mg.get_manager(); + if (values.empty()) { + return th.mk_value(n); + } + SASSERT(values.size() == n->get_num_args()); + return th.mk_value(mg.get_manager().mk_app(n->get_decl(), values.size(), values.c_ptr())); + } +}; + + model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { - enode_pair_dependency* deps = 0; - expr_ref e(n->get_owner(), m); - flet _model_completion(m_model_completion, true); - m_rep.reset_cache(); - m_mg = &mg; - e = canonize(e, deps); - m_mg = 0; - SASSERT(is_app(e)); - TRACE("seq", tout << mk_pp(n->get_owner(), m) << " -> " << e << "\n";); - m_factory->add_trail(e); - return alloc(expr_wrapper_proc, to_app(e)); + context& ctx = get_context(); + enode_pair_dependency* dep = 0; + expr* e = m_rep.find(n->get_owner(), dep); + expr* e1, *e2; + seq_value_proc* sv = alloc(seq_value_proc, *this, to_app(e)); + if (m_util.str.is_concat(e, e1, e2)) { + sv->add_dependency(ctx.get_enode(e1)); + sv->add_dependency(ctx.get_enode(e2)); + } + else if (m_util.str.is_unit(e, e1)) { + sv->add_dependency(ctx.get_enode(e1)); + } + return sv; } +app* theory_seq::mk_value(app* e) { + expr* e1; + expr_ref result(e, m); + if (m_util.str.is_unit(e, e1)) { + enode_pair_dependency* deps = 0; + result = expand(e1, deps); + bv_util bv(m); + rational val; + unsigned sz; + if (bv.is_numeral(result, val, sz) && sz == zstring().num_bits()) { + svector val_as_bits; + for (unsigned i = 0; i < sz; ++i) { + val_as_bits.push_back(!val.is_even()); + val = div(val, rational(2)); + } + result = m_util.str.mk_string(zstring(sz, val_as_bits.c_ptr())); + } + else { + result = m_util.str.mk_unit(result); + } + } + else if (is_var(e)) { + SASSERT(m_factory); + expr_ref val(m); + val = m_factory->get_some_value(m.get_sort(e)); + if (val) { + result = val; + } + else { + result = e; + } + } + else if (is_head_elem(e)) { + enode* n = get_context().get_enode(e)->get_root(); + enode* n0 = n; + bool found_value = false; + do { + result = n->get_owner(); + found_value = m.is_model_value(result); + } + while (n0 != n && !found_value); + + if (!found_value) { + if (m_util.is_char(result)) { + result = m_util.str.mk_char('#'); + } + else { + result = m_mg->get_some_value(m.get_sort(result)); + } + } + } + m_rewrite(result); + m_factory->add_trail(result); + TRACE("seq", tout << mk_pp(e, m) << " -> " << result << "\n";); + return to_app(result); +} theory_var theory_seq::mk_var(enode* n) { @@ -957,49 +1031,6 @@ expr_ref theory_seq::expand(expr* e0, enode_pair_dependency*& eqs) { else if (m_util.str.is_contains(e, e1, e2)) { result = m_util.str.mk_contains(expand(e1, deps), expand(e2, deps)); } - else if (m_model_completion && is_var(e)) { - SASSERT(m_factory); - expr_ref val(m); - val = m_factory->get_some_value(m.get_sort(e)); - if (val) { - m_rep.update(e, val, 0); - result = val; - } - else { - result = e; - } - } - else if (m_model_completion && m_util.str.is_unit(e, e1)) { - result = expand(e1, deps); - bv_util bv(m); - rational val; - unsigned sz; - if (bv.is_numeral(result, val, sz) && sz == zstring().num_bits()) { - svector val_as_bits; - for (unsigned i = 0; i < sz; ++i) { - val_as_bits.push_back(!val.is_even()); - val = div(val, rational(2)); - } - result = m_util.str.mk_string(zstring(sz, val_as_bits.c_ptr())); - } - else { - result = m_util.str.mk_unit(result); - } - } - else if (m_model_completion && is_head_elem(e)) { - enode* n = get_context().get_enode(e)->get_root(); - result = n->get_owner(); - if (!m.is_model_value(result)) { - if (m_util.is_char(result)) { - result = m_util.str.mk_char('#'); - } - else { - result = m_mg->get_some_value(m.get_sort(result)); - } - } - m_rep.update(e, result, 0); - TRACE("seq", tout << mk_pp(e, m) << " |-> " << result << "\n";); - } else { result = e; } @@ -1193,15 +1224,6 @@ void theory_seq::add_elim_string_axiom(expr* n) { } -void theory_seq::add_length_coherence_axiom(expr* n) { - expr_ref len(n, m); - m_rewrite(len); - if (n != len) { - TRACE("seq", tout << "Add length coherence for " << mk_pp(n, m) << "\n";); - add_axiom(mk_eq(n, len, false)); - } -} - /* let n = len(x) @@ -1212,9 +1234,18 @@ void theory_seq::add_length_coherence_axiom(expr* n) { void theory_seq::add_length_axiom(expr* n) { expr* x; VERIFY(m_util.str.is_length(n, x)); - if (!m_util.str.is_unit(x) && - !m_util.str.is_empty(x) && - !m_util.str.is_string(x)) { + if (m_util.str.is_concat(x) || + m_util.str.is_unit(x) || + m_util.str.is_empty(x) || + m_util.str.is_string(x)) { + expr_ref len(n, m); + m_rewrite(len); + if (n != len) { + TRACE("seq", tout << "Add length coherence for " << mk_pp(n, m) << "\n";); + add_axiom(mk_eq(n, len, false)); + } + } + else { expr_ref zero(m_autil.mk_int(0), m); expr_ref emp(m_util.str.mk_empty(m.get_sort(x)), m); literal eq1(mk_eq(zero, n, false)); @@ -1223,12 +1254,6 @@ void theory_seq::add_length_axiom(expr* n) { add_axiom(~eq1, eq2); add_axiom(~eq2, eq1); } - if (m_util.str.is_concat(x) || - m_util.str.is_unit(x) || - m_util.str.is_empty(x) || - m_util.str.is_string(x)) { - add_length_coherence_axiom(x); - } } @@ -1638,8 +1663,7 @@ void theory_seq::restart_eh() { } void theory_seq::relevant_eh(app* n) { - if (m_util.str.is_length(n) || - m_util.str.is_index(n) || + if (m_util.str.is_index(n) || m_util.str.is_replace(n) || m_util.str.is_extract(n) || m_util.str.is_at(n) || @@ -1647,6 +1671,11 @@ void theory_seq::relevant_eh(app* n) { is_step(n)) { enque_axiom(n); } + + expr* arg; + if (m_util.str.is_length(n, arg) && !has_length(arg)) { + enforce_length(get_context().get_enode(arg)); + } } @@ -1729,24 +1758,28 @@ expr_ref theory_seq::mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned void theory_seq::add_accept2step(expr* acc) { context& ctx = get_context(); SASSERT(ctx.get_assignment(acc) == l_true); - expr* s, *re; + expr* e, *re; unsigned src; eautomaton* aut = 0; - VERIFY(is_accept(acc, s, re, src, aut)); + VERIFY(is_accept(acc, e, re, src, aut)); if (!aut) return; - if (m_util.str.is_empty(s)) return; + if (m_util.str.is_empty(e)) return; eautomaton::moves mvs; aut->get_moves_from(src, mvs); expr_ref head(m), tail(m), emp(m), step(m); - mk_decompose(s, emp, head, tail); + mk_decompose(e, emp, head, tail); + if (!m_util.is_skolem(e)) { + expr_ref conc(m_util.str.mk_concat(head, tail), m); + add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false)); + } literal_vector lits; lits.push_back(~ctx.get_literal(acc)); if (aut->is_final_state(src)) { - lits.push_back(mk_eq(emp, s, false)); + lits.push_back(mk_eq(emp, e, false)); } for (unsigned i = 0; i < mvs.size(); ++i) { eautomaton::move mv = mvs[i]; - step = mk_step(s, tail, re, src, mv.dst(), mv.t()); + step = mk_step(e, tail, re, src, mv.dst(), mv.t()); lits.push_back(mk_literal(step)); } TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); @@ -1778,22 +1811,26 @@ void theory_seq::add_step2accept(expr* step) { void theory_seq::add_reject2reject(expr* rej) { context& ctx = get_context(); SASSERT(ctx.get_assignment(rej) == l_true); - expr* s, *re; + expr* e, *re; unsigned src; eautomaton* aut = 0; - VERIFY(is_reject(rej, s, re, src, aut)); + VERIFY(is_reject(rej, e, re, src, aut)); if (!aut) return; - if (m_util.str.is_empty(s)) return; + if (m_util.str.is_empty(e)) return; eautomaton::moves mvs; aut->get_moves_from(src, mvs); expr_ref head(m), tail(m), emp(m), conc(m); - mk_decompose(s, emp, head, tail); + mk_decompose(e, emp, head, tail); + if (!m_util.is_skolem(e)) { + expr_ref conc(m_util.str.mk_concat(head, tail), m); + add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false)); + } literal rej1 = ctx.get_literal(rej); for (unsigned i = 0; i < mvs.size(); ++i) { eautomaton::move const& mv = mvs[i]; conc = m_util.str.mk_concat(m_util.str.mk_unit(mv.t()), tail); literal rej2 = mk_reject(tail, re, m_autil.mk_int(mv.dst())); - add_axiom(~rej1, ~mk_eq(s, conc, false), rej2); + add_axiom(~rej1, ~mk_eq(e, conc, false), rej2); } } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index e7f610695..3ecc66c58 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -259,17 +259,17 @@ namespace smt { unsigned m_axioms_head; // index of first axiom to add. unsigned m_branch_variable_head; // index of first equation to examine. bool m_incomplete; // is the solver (clearly) incomplete for the fragment. - obj_hashtable m_length; // is length applied - bool m_model_completion; // during model construction, invent values in canonizer + obj_hashtable m_length; // is length applied model_generator* m_mg; th_rewriter m_rewrite; seq_util m_util; arith_util m_autil; th_trail_stack m_trail_stack; stats m_stats; - symbol m_prefix, m_suffix, m_contains_left, m_contains_right, m_left, m_right, m_accept, m_reject; - symbol m_tail, m_head_elem, m_seq_first, m_seq_last, m_indexof_left, m_indexof_right, m_aut_step; + symbol m_prefix, m_suffix, m_contains_left, m_contains_right, m_accept, m_reject; + symbol m_tail, m_nth, m_seq_first, m_seq_last, m_indexof_left, m_indexof_right, m_aut_step; symbol m_extract_prefix, m_at_left, m_at_right; + ptr_vector m_todo; // maintain automata with regular expressions. scoped_ptr_vector m_automata; @@ -348,7 +348,6 @@ namespace smt { void add_replace_axiom(expr* e); void add_extract_axiom(expr* e); void add_length_axiom(expr* n); - void add_length_coherence_axiom(expr* n); bool has_length(expr *e) const { return m_length.contains(e); } void add_length(expr* e); @@ -407,6 +406,9 @@ namespace smt { theory_seq(ast_manager& m); virtual ~theory_seq(); + // model building + app* mk_value(app* a); + }; }; From e2fab0a555b0fee091c83107faf6f57799d69680 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 28 Dec 2015 18:15:48 -0800 Subject: [PATCH 32/87] seq Signed-off-by: Nikolaj Bjorner --- src/math/automata/automaton.h | 30 ++++- src/smt/theory_seq.cpp | 237 ++++++++++++++++++---------------- src/smt/theory_seq.h | 24 ++-- src/util/ref_vector.h | 3 +- 4 files changed, 170 insertions(+), 124 deletions(-) diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index fb6bb31fd..df1d37919 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -296,6 +296,10 @@ public: // src0 - t -> src - e -> dst => src0 - t -> dst // out_degree(dst) = 1, final(dst) => final(src), dst != dst1 // src - e -> dst - t -> dst1 => src - t -> dst1 + + // Generalized: + // Src - E -> dst - t -> dst1 => Src - t -> dst1 if dst is final => each Src is final + // void compress() { for (unsigned i = 0; i < m_delta.size(); ++i) { for (unsigned j = 0; j < m_delta[i].size(); ++j) { @@ -329,7 +333,24 @@ public: } add(move(m, src, dst1, t)); remove(dst, dst1, t); - + } + else if (false && 1 == out_degree(dst) && all_epsilon_in(dst) && init() != dst && !is_final_state(dst)) { + move const& mv = m_delta[dst][0]; + T* t = mv.t(); + unsigned dst1 = mv.dst(); + unsigned_vector src0s; + moves const& mvs = m_delta_inv[dst]; + for (unsigned k = 0; k < mvs.size(); ++k) { + SASSERT(mvs[k].is_epsilon()); + src0s.push_back(mvs[k].src()); + } + for (unsigned k = 0; k < src0s.size(); ++k) { + remove(src0s[k], dst, 0); + add(move(m, src0s[i], dst1, t)); + } + remove(dst, dst1, t); + --j; + continue; } else { continue; @@ -392,9 +413,10 @@ public: return true; } - bool is_deterministic() const { - for (unsigned i = 0; i < m_delta.size(); ++i) { - if (m_delta[i].size() >= 2) return false; + bool all_epsilon_in(unsigned s) { + moves const& mvs = m_delta_inv[s]; + for (unsigned j = 0; j < mvs.size(); ++j) { + if (mvs[j].t()) return false; } return true; } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 983730158..d4ae23203 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -59,6 +59,10 @@ void theory_seq::solution_map::add_trail(map_update op, expr* l, expr* r, enode_ m_deps.push_back(d); } +bool theory_seq::solution_map::is_root(expr* e) const { + return !m_map.contains(e); +} + expr* theory_seq::solution_map::find(expr* e, enode_pair_dependency*& d) { std::pair value; d = 0; @@ -181,31 +185,31 @@ final_check_status theory_seq::final_check_eh() { context & ctx = get_context(); TRACE("seq", display(tout);); if (!check_ineqs()) { - TRACE("seq", tout << "check_ineqs\n";); + TRACE("seq", tout << ">>check_ineqs\n";); return FC_CONTINUE; } if (simplify_and_solve_eqs()) { - TRACE("seq", tout << "solve_eqs\n";); + TRACE("seq", tout << ">>solve_eqs\n";); return FC_CONTINUE; } if (solve_nqs()) { - TRACE("seq", tout << "solve_nqs\n";); + TRACE("seq", tout << ">>solve_nqs\n";); return FC_CONTINUE; } if (branch_variable()) { - TRACE("seq", tout << "branch_variable\n";); + TRACE("seq", tout << ">>branch_variable\n";); return FC_CONTINUE; } if (!check_length_coherence()) { - TRACE("seq", tout << "check_length_coherence\n";); + TRACE("seq", tout << ">>check_length_coherence\n";); return FC_CONTINUE; } if (propagate_automata()) { - TRACE("seq", tout << "propagate_automata\n";); + TRACE("seq", tout << ">>propagate_automata\n";); return FC_CONTINUE; } if (is_solved()) { - TRACE("seq", tout << "is_solved\n";); + TRACE("seq", tout << ">>is_solved\n";); return FC_DONE; } @@ -307,6 +311,39 @@ bool theory_seq::assume_equality(expr* l, expr* r) { } } +bool theory_seq::propagate_length_coherence(expr* e) { + expr_ref head(m), tail(m), emp(m); + rational lo, hi; + TRACE("seq", tout << "Unsolved " << mk_pp(e, m); + if (!lower_bound(e, lo)) lo = -rational::one(); + if (!upper_bound(e, hi)) hi = -rational::one(); + tout << " lo: " << lo << " hi: " << hi << "\n"; + ); + + if (!lower_bound(e, lo) || !lo.is_pos() || lo >= rational(2048)) { + return false; + } + literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)))); + expr_ref seq(e, m); + expr_ref_vector elems(m); + unsigned _lo = lo.get_unsigned(); + for (unsigned j = 0; j < _lo; ++j) { + mk_decompose(seq, emp, head, tail); + elems.push_back(head); + seq = tail; + } + elems.push_back(seq); + tail = m_util.str.mk_concat(elems.size(), elems.c_ptr()); + // len(e) >= low => e = tail + add_axiom(~low, mk_eq(e, tail, false)); + assume_equality(tail, e); + if (upper_bound(e, hi)) { + expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m); + expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); + add_axiom(~mk_literal(high1), mk_literal(high2)); + } + return true; +} bool theory_seq::check_length_coherence() { if (m_length.empty()) return true; @@ -315,42 +352,13 @@ bool theory_seq::check_length_coherence() { obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); for (; it != end; ++it) { expr* e = *it; - enode_pair_dependency* dep = 0; - expr* f = m_rep.find(e, dep); - if (is_var(f) && f == e) { + if (is_var(e) && m_rep.is_root(e)) { expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); expr_ref head(m), tail(m); - rational lo, hi; - TRACE("seq", tout << "Unsolved " << mk_pp(e, m); - if (!lower_bound(e, lo)) lo = -rational::one(); - if (!upper_bound(e, hi)) hi = -rational::one(); - tout << " lo: " << lo << " "; - tout << "hi: " << hi << " "; - tout << "\n"; - ctx.display(tout); - ); - - if (lower_bound(e, lo) && lo.is_pos() && lo < rational(512)) { - literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)))); - expr_ref seq(e, m); - expr_ref_vector elems(m); - unsigned _lo = lo.get_unsigned(); - for (unsigned j = 0; j < _lo; ++j) { - mk_decompose(seq, emp, head, tail); - elems.push_back(head); - seq = tail; - } - elems.push_back(seq); - tail = m_util.str.mk_concat(elems.size(), elems.c_ptr()); - // len(e) >= low => e = tail - add_axiom(~low, mk_eq(e, tail, false)); - assume_equality(tail, e); - if (upper_bound(e, hi)) { - expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m); - expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); - add_axiom(~mk_literal(high1), mk_literal(high2)); - } + if (propagate_length_coherence(e)) { + //m_replay_length_coherence.push_back(e); + //m_replay_length_coherence_qhead = m_replay_length_coherence.size(); } else if (!assume_equality(e, emp)) { mk_decompose(e, emp, head, tail); @@ -365,14 +373,18 @@ bool theory_seq::check_length_coherence() { return coherent; } +expr_ref theory_seq::mk_nth(expr* s, expr* idx) { + sort* char_sort = 0; + VERIFY(m_util.is_seq(m.get_sort(s), char_sort)); + return mk_skolem(m_nth, s, idx, 0, char_sort); +} + void theory_seq::mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& tail) { expr* e1, *e2; - sort* char_sort = 0; zstring s; - VERIFY(m_util.is_seq(m.get_sort(e), char_sort)); emp = m_util.str.mk_empty(m.get_sort(e)); if (m_util.str.is_empty(e)) { - head = m_util.str.mk_unit(mk_skolem(m_nth, e, m_autil.mk_int(0), 0, char_sort)); + head = m_util.str.mk_unit(mk_nth(e, m_autil.mk_int(0))); tail = e; } else if (m_util.str.is_string(e, s)) { @@ -393,11 +405,11 @@ void theory_seq::mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& expr* s = a->get_arg(0); VERIFY (m_autil.is_numeral(a->get_arg(1), r)); expr* idx = m_autil.mk_int(r.get_unsigned() + 1); - head = m_util.str.mk_unit(mk_skolem(m_nth, s, idx, 0, char_sort)); + head = m_util.str.mk_unit(mk_nth(s, idx)); tail = mk_skolem(m_tail, s, idx); } else { - head = m_util.str.mk_unit(mk_skolem(m_nth, e, m_autil.mk_int(0), 0, char_sort)); + head = m_util.str.mk_unit(mk_nth(e, m_autil.mk_int(0))); tail = mk_skolem(m_tail, e, m_autil.mk_int(0)); } } @@ -750,7 +762,6 @@ bool theory_seq::internalize_term(app* term) { bool_var bv = ctx.mk_bool_var(term); ctx.set_var_theory(bv, get_id()); ctx.mark_as_relevant(bv); - TRACE("seq", tout << mk_pp(term, m) << ": " << bv << "\n";); } else { enode* e = 0; @@ -1064,8 +1075,13 @@ void theory_seq::propagate() { void theory_seq::enque_axiom(expr* e) { TRACE("seq", tout << "add axioms for: " << mk_pp(e, m) << "\n";); - m_trail_stack.push(push_back_vector(m_axioms)); - m_axioms.push_back(e); + if (!m_axiom_set.contains(e)) { + m_axioms.push_back(e); + m_axiom_set.insert(e); + m_trail_stack.push(push_back_vector(m_axioms)); + m_trail_stack.push(insert_obj_trail(m_axiom_set, e));; + + } } void theory_seq::deque_axiom(expr* n) { @@ -1284,17 +1300,19 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { eautomaton* a = get_automaton(e2); if (!a) return; - if (m_util.str.is_empty(e1)) return; + // if (m_util.str.is_empty(e1)) return; + context& ctx = get_context(); - expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); + expr_ref len(m_util.str.mk_length(e1), m); for (unsigned i = 0; i < a->num_states(); ++i) { - literal acc = mk_accept(emp, e2, i); - literal rej = mk_reject(emp, e2, i); + literal acc = mk_accept(e1, len, e2, i); + literal rej = mk_reject(e1, len, e2, i); add_axiom(a->is_final_state(i)?acc:~acc); add_axiom(a->is_final_state(i)?~rej:rej); } + expr_ref zero(m_autil.mk_int(0), m); unsigned_vector states; a->get_epsilon_closure(a->init(), states); literal_vector lits; @@ -1304,11 +1322,11 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { } for (unsigned i = 0; i < states.size(); ++i) { if (is_true) { - lits.push_back(mk_accept(e1, e2, states[i])); + lits.push_back(mk_accept(e1, zero, e2, states[i])); } else { literal nlit = ~lit; - propagate_lit(0, 1, &nlit, mk_reject(e1, e2, states[i])); + propagate_lit(0, 1, &nlit, mk_reject(e1, zero, e2, states[i])); } } if (is_true) { @@ -1316,7 +1334,7 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { propagate_lit(0, 1, &lit, lits[1]); } else { - TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr());); + TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } } @@ -1474,18 +1492,14 @@ void theory_seq::add_at_axiom(expr* e) { } /** - step(s, tail, re, i, j, t) -> s = t ++ tail + step(s, idx, re, i, j, t) -> nth(s, idx) == t */ void theory_seq::propagate_step(bool_var v, expr* step) { context& ctx = get_context(); - expr* re, *t, *s, *tail, *i, *j; - VERIFY(is_step(step, s, tail, re, i, j, t)); - expr_ref conc(m_util.str.mk_concat(m_util.str.mk_unit(t), tail), m); - expr_ref sr(s, m); - propagate_eq(v, s, conc); - enode* n1 = ensure_enode(step); - enode* n2 = ctx.get_enode(m.mk_true()); - m_eqs.push_back(eq(sr, conc, m_dm.mk_leaf(enode_pair(n1, n2)))); + expr* re, *t, *s, *idx, *i, *j; + VERIFY(is_step(step, s, idx, re, i, j, t)); + expr_ref nth = mk_nth(s, idx); + propagate_eq(v, t, nth); } @@ -1698,19 +1712,24 @@ eautomaton* theory_seq::get_automaton(expr* re) { return result; } -literal theory_seq::mk_accept(expr* s, expr* re, expr* state) { - return mk_literal(mk_skolem(m_accept, s, re, state, m.mk_bool_sort())); +literal theory_seq::mk_accept(expr* s, expr* idx, expr* re, expr* state) { + expr_ref_vector args(m); + args.push_back(s).push_back(idx).push_back(re).push_back(state); + return mk_literal(m_util.mk_skolem(m_accept, args.size(), args.c_ptr(), m.mk_bool_sort())); } -literal theory_seq::mk_reject(expr* s, expr* re, expr* state) { - return mk_literal(mk_skolem(m_reject, s, re, state, m.mk_bool_sort())); +literal theory_seq::mk_reject(expr* s, expr* idx, expr* re, expr* state) { + expr_ref_vector args(m); + args.push_back(s).push_back(idx).push_back(re).push_back(state); + return mk_literal(m_util.mk_skolem(m_reject, args.size(), args.c_ptr(), m.mk_bool_sort())); } -bool theory_seq::is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& re, unsigned& i, eautomaton*& aut) { +bool theory_seq::is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) { if (is_skolem(ar, e)) { rational r; s = to_app(e)->get_arg(0); - re = to_app(e)->get_arg(1); - VERIFY(m_autil.is_numeral(to_app(e)->get_arg(2), r)); + idx = to_app(e)->get_arg(1); + re = to_app(e)->get_arg(2); + VERIFY(m_autil.is_numeral(to_app(e)->get_arg(3), r)); SASSERT(r.is_unsigned()); i = r.get_unsigned(); aut = m_re2aut[re]; @@ -1725,10 +1744,10 @@ bool theory_seq::is_step(expr* e) const { return is_skolem(m_aut_step, e); } -bool theory_seq::is_step(expr* e, expr*& s, expr*& tail, expr*& re, expr*& i, expr*& j, expr*& t) const { +bool theory_seq::is_step(expr* e, expr*& s, expr*& idx, expr*& re, expr*& i, expr*& j, expr*& t) const { if (is_step(e)) { s = to_app(e)->get_arg(0); - tail = to_app(e)->get_arg(1); + idx = to_app(e)->get_arg(1); re = to_app(e)->get_arg(2); i = to_app(e)->get_arg(3); j = to_app(e)->get_arg(4); @@ -1740,11 +1759,9 @@ bool theory_seq::is_step(expr* e, expr*& s, expr*& tail, expr*& re, expr*& i, ex } } -expr_ref theory_seq::mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned j, expr* t) { +expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned j, expr* t) { expr_ref_vector args(m); - args.push_back(s); - args.push_back(tail); - args.push_back(re); + args.push_back(s).push_back(idx).push_back(re); args.push_back(m_autil.mk_int(i)); args.push_back(m_autil.mk_int(j)); args.push_back(t); @@ -1753,33 +1770,32 @@ expr_ref theory_seq::mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned /** - acc & s != emp -> \/ step_i_t_j + acc(s, idx, re, i) -> \/ step(s, idx, re, i, j, t) if i is non-final + acc(s, idx, re, i) -> len(s) <= idx \/ step(s, idx, re, i, j, t) if i is final + acc(s, idx, re, i) -> len(s) >= idx */ void theory_seq::add_accept2step(expr* acc) { context& ctx = get_context(); SASSERT(ctx.get_assignment(acc) == l_true); - expr* e, *re; + expr *e, * idx, *re; + expr_ref step(m); unsigned src; eautomaton* aut = 0; - VERIFY(is_accept(acc, e, re, src, aut)); - if (!aut) return; - if (m_util.str.is_empty(e)) return; + VERIFY(is_accept(acc, e, idx, re, src, aut)); + if (!aut || m_util.str.is_length(idx)) return; + SASSERT(m_autil.is_numeral(idx)); eautomaton::moves mvs; aut->get_moves_from(src, mvs); - expr_ref head(m), tail(m), emp(m), step(m); - mk_decompose(e, emp, head, tail); - if (!m_util.is_skolem(e)) { - expr_ref conc(m_util.str.mk_concat(head, tail), m); - add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false)); - } + + expr_ref len(m_util.str.mk_length(e), m); literal_vector lits; lits.push_back(~ctx.get_literal(acc)); if (aut->is_final_state(src)) { - lits.push_back(mk_eq(emp, e, false)); + lits.push_back(mk_literal(m_autil.mk_le(len, idx))); } for (unsigned i = 0; i < mvs.size(); ++i) { eautomaton::move mv = mvs[i]; - step = mk_step(e, tail, re, src, mv.dst(), mv.t()); + step = mk_step(e, idx, re, src, mv.dst(), mv.t()); lits.push_back(mk_literal(step)); } TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); @@ -1787,50 +1803,53 @@ void theory_seq::add_accept2step(expr* acc) { ctx.mark_as_relevant(lits[i]); } ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + add_axiom(~ctx.get_literal(acc), mk_literal(m_autil.mk_ge(len, idx))); } /** - acc(s, re, i) & step(head, tail, re, i, j, t) => acc(tail, re, j) + acc(s, idx, re, i) & step(s, idx, re, i, j, t) => acc(s, idx + 1, re, j) */ void theory_seq::add_step2accept(expr* step) { context& ctx = get_context(); SASSERT(ctx.get_assignment(step) == l_true); - expr* re, *t, *s, *tail, *i, *j; - VERIFY(is_step(step, s, tail, re, i, j, t)); - literal acc1 = mk_accept(s, re, i); - literal acc2 = mk_accept(tail, re, j); + rational r; + expr* re, *t, *s, *idx, *i, *j; + VERIFY(is_step(step, s, idx, re, i, j, t)); + VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); + expr_ref idx1(m_autil.mk_int(r.get_unsigned() + 1), m); + literal acc1 = mk_accept(s, idx, re, i); + literal acc2 = mk_accept(s, idx1, re, j); add_axiom(~acc1, ~ctx.get_literal(step), acc2); } /* - rej(s, re, i) & s = t ++ tail => rej(tail, re, j) + rej(s, idx, re, i) & nth(s,idx) = t & idx < len(s) => rej(s, idx + 1 re, j) + rej(s, idx, re, i) => idx <= len(s) */ void theory_seq::add_reject2reject(expr* rej) { context& ctx = get_context(); SASSERT(ctx.get_assignment(rej) == l_true); - expr* e, *re; + expr* e, *idx, *re; unsigned src; + rational r; eautomaton* aut = 0; - VERIFY(is_reject(rej, e, re, src, aut)); - if (!aut) return; - if (m_util.str.is_empty(e)) return; + VERIFY(is_reject(rej, e, idx, re, src, aut)); + if (!aut || m_util.str.is_length(idx)) return; + VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); + expr_ref idx1(m_autil.mk_int(r.get_unsigned() + 1), m); eautomaton::moves mvs; aut->get_moves_from(src, mvs); - expr_ref head(m), tail(m), emp(m), conc(m); - mk_decompose(e, emp, head, tail); - if (!m_util.is_skolem(e)) { - expr_ref conc(m_util.str.mk_concat(head, tail), m); - add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false)); - } literal rej1 = ctx.get_literal(rej); + expr_ref len(m_util.str.mk_length(e), m); + add_axiom(~rej1, mk_literal(m_autil.mk_ge(len, idx))); for (unsigned i = 0; i < mvs.size(); ++i) { eautomaton::move const& mv = mvs[i]; - conc = m_util.str.mk_concat(m_util.str.mk_unit(mv.t()), tail); - literal rej2 = mk_reject(tail, re, m_autil.mk_int(mv.dst())); - add_axiom(~rej1, ~mk_eq(e, conc, false), rej2); + expr_ref nth = mk_nth(e, idx); + literal rej2 = mk_reject(e, idx1, re, m_autil.mk_int(mv.dst())); + add_axiom(~rej1, ~mk_eq(nth, mv.t(), false), ~mk_literal(m_autil.mk_ge(len, idx)), rej2); } } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 3ecc66c58..024a5b8da 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -72,6 +72,7 @@ namespace smt { void add_cache(expr* v, expr_dep& r) { m_cache.insert(v, r); } bool find_cache(expr* v, expr_dep& r) { return m_cache.find(v, r); } expr* find(expr* e, enode_pair_dependency*& d); + bool is_root(expr* e) const; void cache(expr* e, expr* r, enode_pair_dependency* d); void reset_cache() { m_cache.reset(); } void push_scope() { m_limit.push_back(m_updates.size()); } @@ -256,6 +257,7 @@ namespace smt { expr_ref_vector m_ineqs; // inequalities to check solution against exclusion_table m_exclude; // set of asserted disequalities. expr_ref_vector m_axioms; // list of axioms to add. + obj_hashtable m_axiom_set; unsigned m_axioms_head; // index of first axiom to add. unsigned m_branch_variable_head; // index of first equation to examine. bool m_incomplete; // is the solver (clearly) incomplete for the fragment. @@ -305,7 +307,8 @@ namespace smt { bool branch_variable(); // branch on a variable bool split_variable(); // split a variable bool is_solved(); - bool check_length_coherence(); + bool check_length_coherence(); + bool propagate_length_coherence(expr* e); bool check_ineq_coherence(); bool pre_process_eqs(bool simplify_or_solve, bool& propagated); @@ -368,6 +371,7 @@ namespace smt { void mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& tail); expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2 = 0, expr* e3 = 0, sort* range = 0); + expr_ref mk_nth(expr* s, expr* idx); bool is_skolem(symbol const& s, expr* e) const; void set_incomplete(app* term); @@ -375,19 +379,19 @@ namespace smt { // automata utilities void propagate_in_re(expr* n, bool is_true); eautomaton* get_automaton(expr* e); - literal mk_accept(expr* s, expr* re, expr* state); - literal mk_accept(expr* s, expr* re, unsigned i) { return mk_accept(s, re, m_autil.mk_int(i)); } + literal mk_accept(expr* s, expr* idx, expr* re, expr* state); + literal mk_accept(expr* s, expr* idx, expr* re, unsigned i) { return mk_accept(s, idx, re, m_autil.mk_int(i)); } bool is_accept(expr* acc) const { return is_skolem(m_accept, acc); } - bool is_accept(expr* acc, expr*& s, expr*& re, unsigned& i, eautomaton*& aut) { - return is_acc_rej(m_accept, acc, s, re, i, aut); + bool is_accept(expr* acc, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) { + return is_acc_rej(m_accept, acc, s, idx, re, i, aut); } - literal mk_reject(expr* s, expr* re, expr* state); - literal mk_reject(expr* s, expr* re, unsigned i) { return mk_reject(s, re, m_autil.mk_int(i)); } + literal mk_reject(expr* s, expr* idx, expr* re, expr* state); + literal mk_reject(expr* s, expr* idx, expr* re, unsigned i) { return mk_reject(s, idx, re, m_autil.mk_int(i)); } bool is_reject(expr* rej) const { return is_skolem(m_reject, rej); } - bool is_reject(expr* rej, expr*& s, expr*& re, unsigned& i, eautomaton*& aut) { - return is_acc_rej(m_reject, rej, s, re, i, aut); + bool is_reject(expr* rej, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) { + return is_acc_rej(m_reject, rej, s, idx, re, i, aut); } - bool is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& re, unsigned& i, eautomaton*& aut); + bool is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut); expr_ref mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned j, expr* t); bool is_step(expr* e, expr*& s, expr*& tail, expr*& re, expr*& i, expr*& j, expr*& t) const; bool is_step(expr* e) const; diff --git a/src/util/ref_vector.h b/src/util/ref_vector.h index b651a555d..fdfb94d93 100644 --- a/src/util/ref_vector.h +++ b/src/util/ref_vector.h @@ -89,9 +89,10 @@ public: m_nodes.shrink(sz); } - void push_back(T * n) { + ref_vector_core& push_back(T * n) { inc_ref(n); m_nodes.push_back(n); + return *this; } void pop_back() { From b0781a14cd95c56f03e12bd1617cc6be45082033 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 29 Dec 2015 15:59:14 +0000 Subject: [PATCH 33/87] Fix for FP numeral construction in the Python API. Fixes #386. --- src/api/python/z3.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 864a92846..97f2d1ecc 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -8315,20 +8315,36 @@ def FPSort(ebits, sbits, ctx=None): ctx = z3._get_ctx(ctx) return FPSortRef(Z3_mk_fpa_sort(ctx.ref(), ebits, sbits), ctx) -def _to_float_str(val): +def _to_float_str(val, exp=0): if isinstance(val, float): - return str(val) + v = val.as_integer_ratio() + num = v[0] + den = v[1] + rvs = str(num) + '/' + str(den) + res = rvs + 'p' +_to_int_str(exp) elif isinstance(val, bool): if val: - return "1.0" + res = "1.0" else: - return "0.0" + res = "0.0" elif _is_int(val): - return str(val) + res = str(val) elif isinstance(val, str): - return val - if __debug__: - _z3_assert(False, "Python value cannot be used as a double") + inx = val.find('*(2**') + if inx == -1: + res = val + elif val[-1] == ')': + res = val[0:inx] + exp = str(int(val[inx+5:-1]) + int(exp)) + else: + _z3_assert(False, "String does not have floating-point numeral form.") + elif __debug__: + _z3_assert(False, "Python value cannot be used to create floating-point numerals.") + if exp == 0: + return res + else: + return res + 'p' + exp + def fpNaN(s): _z3_assert(isinstance(s, FPSortRef), "sort mismatch") @@ -8385,8 +8401,6 @@ def FPVal(sig, exp=None, fps=None, ctx=None): if exp == None: exp = 0 val = _to_float_str(sig) - val = val + 'p' - val = val + _to_int_str(exp) return FPNumRef(Z3_mk_numeral(ctx.ref(), val, fps.ast), ctx) def FP(name, fpsort, ctx=None): From 2f08040403ba4eaec74bdf0f3a52825b022780fc Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 29 Dec 2015 16:00:07 +0000 Subject: [PATCH 34/87] typo --- src/api/python/z3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 97f2d1ecc..17fa92af5 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -8321,7 +8321,7 @@ def _to_float_str(val, exp=0): num = v[0] den = v[1] rvs = str(num) + '/' + str(den) - res = rvs + 'p' +_to_int_str(exp) + res = rvs + 'p' + _to_int_str(exp) elif isinstance(val, bool): if val: res = "1.0" From bd9b5b57353dd518f7353b76deeedd5294c1d9bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Dec 2015 10:13:19 -0800 Subject: [PATCH 35/87] seq Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 4 + src/math/automata/automaton.h | 26 ++---- src/smt/smt_model_generator.cpp | 1 + src/smt/theory_seq.cpp | 139 +++++++++++++++++++++++------- src/smt/theory_seq.h | 17 ++-- 5 files changed, 133 insertions(+), 54 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index aa27489ad..a5c3fb403 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -39,7 +39,10 @@ re2automaton::re2automaton(ast_manager& m): m(m), u(m) {} eautomaton* re2automaton::operator()(expr* e) { eautomaton* r = re2aut(e); if (r) { + //display_expr1 disp(m); + //r->display(std::cout, disp); r->compress(); + //r->display(std::cout, disp); } return r; } @@ -61,6 +64,7 @@ eautomaton* re2automaton::re2aut(expr* e) { else if (u.re.is_star(e, e1) && (a = re2aut(e1))) { a->add_final_to_init_moves(); a->add_init_to_final_states(); + return a.detach(); } else if (u.re.is_plus(e, e1) && (a = re2aut(e1))) { diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index df1d37919..54cd02832 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -209,24 +209,16 @@ public: moves mvs; unsigned_vector final; unsigned init = 0; - if (a.has_single_final_sink() && b.initial_state_is_source() && b.init() == 0) { - unsigned offset2 = a.num_states(); - init = a.init(); - append_moves(0, a, mvs); - append_moves(offset2, b, mvs); - append_final(offset2, b, final); - } - else { - unsigned offset1 = 1; - unsigned offset2 = a.num_states() + offset1; - mvs.push_back(move(m, 0, a.init() + offset1)); - append_moves(offset1, a, mvs); - for (unsigned i = 0; i < a.m_final_states.size(); ++i) { - mvs.push_back(move(m, a.m_final_states[i], b.init() + offset2)); - } - append_moves(offset2, b, mvs); - append_final(offset2, b, final); + unsigned offset1 = 1; + unsigned offset2 = a.num_states() + offset1; + mvs.push_back(move(m, 0, a.init() + offset1)); + append_moves(offset1, a, mvs); + for (unsigned i = 0; i < a.m_final_states.size(); ++i) { + mvs.push_back(move(m, a.m_final_states[i] + offset1, b.init() + offset2)); } + append_moves(offset2, b, mvs); + append_final(offset2, b, final); + return alloc(automaton, m, init, final, mvs); } diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 16cf18d2e..88e9761b4 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -361,6 +361,7 @@ namespace smt { } else { enode * child = d.get_enode(); + TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << " (" << mk_pp(n->get_owner(), m_manager) << "): " << mk_pp(child->get_owner(), m_manager) << " " << mk_pp(child->get_root()->get_owner(), m_manager) << "\n";); child = child->get_root(); app * val = 0; m_root2value.find(child, val); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index d4ae23203..63bdedd1e 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -77,6 +77,14 @@ expr* theory_seq::solution_map::find(expr* e, enode_pair_dependency*& d) { return result; } +expr* theory_seq::solution_map::find(expr* e) { + std::pair value; + while (m_map.find(e, value)) { + e = value.first; + } + return e; +} + void theory_seq::solution_map::pop_scope(unsigned num_scopes) { if (num_scopes == 0) return; m_cache.reset(); @@ -185,26 +193,32 @@ final_check_status theory_seq::final_check_eh() { context & ctx = get_context(); TRACE("seq", display(tout);); if (!check_ineqs()) { + ++m_stats.m_check_ineqs; TRACE("seq", tout << ">>check_ineqs\n";); return FC_CONTINUE; } if (simplify_and_solve_eqs()) { + ++m_stats.m_solve_eqs; TRACE("seq", tout << ">>solve_eqs\n";); return FC_CONTINUE; } if (solve_nqs()) { + ++m_stats.m_solve_nqs; TRACE("seq", tout << ">>solve_nqs\n";); return FC_CONTINUE; } if (branch_variable()) { + ++m_stats.m_branch_variable; TRACE("seq", tout << ">>branch_variable\n";); return FC_CONTINUE; } if (!check_length_coherence()) { + ++m_stats.m_check_length_coherence; TRACE("seq", tout << ">>check_length_coherence\n";); return FC_CONTINUE; } if (propagate_automata()) { + ++m_stats.m_propagate_automata; TRACE("seq", tout << ">>propagate_automata\n";); return FC_CONTINUE; } @@ -312,23 +326,27 @@ bool theory_seq::assume_equality(expr* l, expr* r) { } bool theory_seq::propagate_length_coherence(expr* e) { - expr_ref head(m), tail(m), emp(m); + expr_ref head(m), tail(m); rational lo, hi; + + if (!is_var(e) || !m_rep.is_root(e)) { + return false; + } + if (!lower_bound(e, lo) || !lo.is_pos() || lo >= rational(2048)) { + return false; + } TRACE("seq", tout << "Unsolved " << mk_pp(e, m); if (!lower_bound(e, lo)) lo = -rational::one(); if (!upper_bound(e, hi)) hi = -rational::one(); tout << " lo: " << lo << " hi: " << hi << "\n"; ); - if (!lower_bound(e, lo) || !lo.is_pos() || lo >= rational(2048)) { - return false; - } literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)))); expr_ref seq(e, m); expr_ref_vector elems(m); unsigned _lo = lo.get_unsigned(); for (unsigned j = 0; j < _lo; ++j) { - mk_decompose(seq, emp, head, tail); + mk_decompose(seq, head, tail); elems.push_back(head); seq = tail; } @@ -342,6 +360,10 @@ bool theory_seq::propagate_length_coherence(expr* e) { expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); add_axiom(~mk_literal(high1), mk_literal(high2)); } + + //m_replay_length_coherence.push_back(e); + //m_replay_length_coherence_qhead = m_replay_length_coherence.size(); + return true; } @@ -357,14 +379,12 @@ bool theory_seq::check_length_coherence() { expr_ref head(m), tail(m); if (propagate_length_coherence(e)) { - //m_replay_length_coherence.push_back(e); - //m_replay_length_coherence_qhead = m_replay_length_coherence.size(); } else if (!assume_equality(e, emp)) { - mk_decompose(e, emp, head, tail); + mk_decompose(e, head, tail); // e = emp \/ e = unit(head.elem(e))*tail(e) expr_ref conc(m_util.str.mk_concat(head, tail), m); - add_axiom(mk_eq(e, emp, false), mk_eq(e, conc, false)); + add_axiom(mk_eq_empty(e), mk_eq(e, conc, false)); assume_equality(tail, emp); } return false; @@ -379,10 +399,9 @@ expr_ref theory_seq::mk_nth(expr* s, expr* idx) { return mk_skolem(m_nth, s, idx, 0, char_sort); } -void theory_seq::mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& tail) { +void theory_seq::mk_decompose(expr* e, expr_ref& head, expr_ref& tail) { expr* e1, *e2; zstring s; - emp = m_util.str.mk_empty(m.get_sort(e)); if (m_util.str.is_empty(e)) { head = m_util.str.mk_unit(mk_nth(e, m_autil.mk_int(0))); tail = e; @@ -393,7 +412,7 @@ void theory_seq::mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& } else if (m_util.str.is_unit(e)) { head = e; - tail = emp; + tail = m_util.str.mk_empty(m.get_sort(e)); } else if (m_util.str.is_concat(e, e1, e2) && m_util.str.is_unit(e1)) { head = e1; @@ -585,7 +604,7 @@ bool theory_seq::is_var(expr* a) { } -bool theory_seq::is_head_elem(expr* e) const { +bool theory_seq::is_nth(expr* e) const { return is_skolem(m_nth, e); } @@ -884,6 +903,13 @@ void theory_seq::display_deps(std::ostream& out, enode_pair_dependency* dep) con void theory_seq::collect_statistics(::statistics & st) const { st.update("seq num splits", m_stats.m_num_splits); st.update("seq num reductions", m_stats.m_num_reductions); + st.update("e", m_stats.m_propagate_automata); + st.update("seq length coherence", m_stats.m_check_length_coherence); + st.update("seq branch", m_stats.m_branch_variable); + st.update("seq solve !=", m_stats.m_solve_nqs); + st.update("seq solve =", m_stats.m_solve_eqs); + st.update("seq check negations", m_stats.m_check_ineqs); + } void theory_seq::init_model(model_generator & mg) { @@ -910,7 +936,6 @@ public: if (values.empty()) { return th.mk_value(n); } - SASSERT(values.size() == n->get_num_args()); return th.mk_value(mg.get_manager().mk_app(n->get_decl(), values.size(), values.c_ptr())); } }; @@ -918,13 +943,35 @@ public: model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { context& ctx = get_context(); - enode_pair_dependency* dep = 0; - expr* e = m_rep.find(n->get_owner(), dep); - expr* e1, *e2; + expr_ref e(m); + expr* e1; + ptr_vector concats; + get_concat(n->get_owner(), concats); + switch (concats.size()) { + case 0: + e = m_util.str.mk_empty(m.get_sort(n->get_owner())); + break; + case 1: + e = concats[0]; + SASSERT(!m_util.str.is_concat(e)); + break; + default: + e = m_rep.find(n->get_owner()); + SASSERT(m_util.str.is_concat(e)); + break; + } seq_value_proc* sv = alloc(seq_value_proc, *this, to_app(e)); - if (m_util.str.is_concat(e, e1, e2)) { - sv->add_dependency(ctx.get_enode(e1)); - sv->add_dependency(ctx.get_enode(e2)); + TRACE("seq", tout << mk_pp(n->get_owner(), m) << " "; + for (unsigned i = 0; i < concats.size(); ++i) { + tout << mk_pp(concats[i], m) << " "; + } + tout << "\n"; + ); + + if (concats.size() > 1) { + for (unsigned i = 0; i < concats.size(); ++i) { + sv->add_dependency(ctx.get_enode(concats[i])); + } } else if (m_util.str.is_unit(e, e1)) { sv->add_dependency(ctx.get_enode(e1)); @@ -932,6 +979,22 @@ model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) { return sv; } +void theory_seq::get_concat(expr* e, ptr_vector& concats) { + expr* e1, *e2; + while (true) { + e = m_rep.find(e); + if (m_util.str.is_concat(e, e1, e2)) { + get_concat(e1, concats); + e = e2; + continue; + } + if (!m_util.str.is_empty(e)) { + concats.push_back(e); + } + return; + } +} + app* theory_seq::mk_value(app* e) { expr* e1; expr_ref result(e, m); @@ -964,7 +1027,7 @@ app* theory_seq::mk_value(app* e) { result = e; } } - else if (is_head_elem(e)) { + else if (is_nth(e)) { enode* n = get_context().get_enode(e)->get_root(); enode* n0 = n; bool found_value = false; @@ -1088,6 +1151,9 @@ void theory_seq::deque_axiom(expr* n) { if (m_util.str.is_length(n)) { add_length_axiom(n); } + else if (m_util.str.is_empty(n) && !has_length(n)) { + enforce_length(get_context().get_enode(n)); + } else if (m_util.str.is_index(n)) { add_indexof_axiom(n); } @@ -1120,8 +1186,7 @@ void theory_seq::tightest_prefix(expr* s, expr* x, literal lit1, literal lit2) { expr_ref s1c(m_util.str.mk_concat(s1, c), m); expr_ref lc(m_util.str.mk_length(c), m); expr_ref one(m_autil.mk_int(1), m); - expr_ref emp(m_util.str.mk_empty(m.get_sort(s)), m); - literal s_eq_emp = mk_eq(s, emp, false); + literal s_eq_emp = mk_eq_empty(s); add_axiom(lit1, lit2, s_eq_emp, mk_eq(s, s1c, false)); add_axiom(lit1, lit2, s_eq_emp, mk_eq(lc, one, false)); add_axiom(lit1, lit2, s_eq_emp, ~mk_literal(m_util.str.mk_contains(s, m_util.str.mk_concat(x, s1)))); @@ -1160,7 +1225,6 @@ void theory_seq::add_indexof_axiom(expr* i) { expr_ref emp(m), minus_one(m), zero(m), xsy(m); minus_one = m_autil.mk_int(-1); zero = m_autil.mk_int(0); - emp = m_util.str.mk_empty(m.get_sort(s)); literal offset_ne_zero = null_literal; bool is_num = m_autil.is_numeral(offset, r); if (is_num && r.is_zero()) { @@ -1174,7 +1238,7 @@ void theory_seq::add_indexof_axiom(expr* i) { expr_ref y = mk_skolem(m_contains_right, t, s); xsy = m_util.str.mk_concat(x,s,y); literal cnt = mk_literal(m_util.str.mk_contains(t, s)); - literal eq_empty = mk_eq(s, emp, false); + literal eq_empty = mk_eq_empty(s); add_axiom(offset_ne_zero, cnt, mk_eq(i, minus_one, false)); add_axiom(offset_ne_zero, ~eq_empty, mk_eq(i, zero, false)); add_axiom(offset_ne_zero, ~cnt, eq_empty, mk_eq(t, xsy, false)); @@ -1263,12 +1327,12 @@ void theory_seq::add_length_axiom(expr* n) { } else { expr_ref zero(m_autil.mk_int(0), m); - expr_ref emp(m_util.str.mk_empty(m.get_sort(x)), m); - literal eq1(mk_eq(zero, n, false)); - literal eq2(mk_eq(x, emp, false)); add_axiom(mk_literal(m_autil.mk_ge(n, zero))); - add_axiom(~eq1, eq2); - add_axiom(~eq2, eq1); + + //expr_ref emp(m_util.str.mk_empty(m.get_sort(x)), m); + //literal eq1(mk_eq(zero, n, false)); + //literal eq2(mk_eq(x, emp, false)); + //add_axiom(~eq1, eq2); } } @@ -1510,6 +1574,17 @@ literal theory_seq::mk_literal(expr* _e) { return ctx.get_literal(e); } +literal theory_seq::mk_eq_empty(expr* _e) { + expr_ref e(_e, m); + context& ctx = get_context(); + SASSERT(m_util.is_seq(e)); + expr_ref emp(m); + emp = m_util.str.mk_empty(m.get_sort(e)); + literal lit = mk_eq(e, emp, false); + ctx.force_phase(lit); + return lit; +} + void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4) { context& ctx = get_context(); literal_vector lits; @@ -1681,8 +1756,8 @@ void theory_seq::relevant_eh(app* n) { m_util.str.is_replace(n) || m_util.str.is_extract(n) || m_util.str.is_at(n) || - m_util.str.is_string(n) || - is_step(n)) { + m_util.str.is_empty(n) || + m_util.str.is_string(n)) { enque_axiom(n); } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 024a5b8da..5760fb437 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -72,6 +72,7 @@ namespace smt { void add_cache(expr* v, expr_dep& r) { m_cache.insert(v, r); } bool find_cache(expr* v, expr_dep& r) { return m_cache.find(v, r); } expr* find(expr* e, enode_pair_dependency*& d); + expr* find(expr* e); bool is_root(expr* e) const; void cache(expr* e, expr* r, enode_pair_dependency* d); void reset_cache() { m_cache.reset(); } @@ -246,6 +247,12 @@ namespace smt { void reset() { memset(this, 0, sizeof(stats)); } unsigned m_num_splits; unsigned m_num_reductions; + unsigned m_propagate_automata; + unsigned m_check_length_coherence; + unsigned m_branch_variable; + unsigned m_solve_nqs; + unsigned m_solve_eqs; + unsigned m_check_ineqs; }; ast_manager& m; enode_pair_dependency_manager m_dm; @@ -335,13 +342,13 @@ namespace smt { bool occurs(expr* a, expr* b); bool is_var(expr* b); bool add_solution(expr* l, expr* r, enode_pair_dependency* dep); - bool is_left_select(expr* a, expr*& b); - bool is_right_select(expr* a, expr*& b); - bool is_head_elem(expr* a) const; + bool is_nth(expr* a) const; + expr_ref mk_nth(expr* s, expr* idx); expr_ref canonize(expr* e, enode_pair_dependency*& eqs); expr_ref expand(expr* e, enode_pair_dependency*& eqs); void add_dependency(enode_pair_dependency*& dep, enode* a, enode* b); + void get_concat(expr* e, ptr_vector& concats); // terms whose meaning are encoded using axioms. void enque_axiom(expr* e); @@ -360,6 +367,7 @@ namespace smt { void add_at_axiom(expr* n); void add_in_re_axiom(expr* n); literal mk_literal(expr* n); + literal mk_eq_empty(expr* n); void tightest_prefix(expr* s, expr* x, literal lit, literal lit2 = null_literal); expr_ref mk_sub(expr* a, expr* b); enode* ensure_enode(expr* a); @@ -369,9 +377,8 @@ namespace smt { bool upper_bound(expr* s, rational& hi); bool get_length(expr* s, rational& val); - void mk_decompose(expr* e, expr_ref& emp, expr_ref& head, expr_ref& tail); + void mk_decompose(expr* e, expr_ref& head, expr_ref& tail); expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2 = 0, expr* e3 = 0, sort* range = 0); - expr_ref mk_nth(expr* s, expr* idx); bool is_skolem(symbol const& s, expr* e) const; void set_incomplete(app* term); From e63724a22d445a46662f1333fa12b1fdd89ab27c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Dec 2015 15:30:42 -0800 Subject: [PATCH 36/87] replace assert by SASSERT in case of unsupported proof rule Signed-off-by: Nikolaj Bjorner --- src/interp/iz3interp.cpp | 1 - src/interp/iz3translate.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/interp/iz3interp.cpp b/src/interp/iz3interp.cpp index 58db2c3b5..87f782160 100755 --- a/src/interp/iz3interp.cpp +++ b/src/interp/iz3interp.cpp @@ -26,7 +26,6 @@ #pragma warning(disable:4101) #endif -#include #include #include #include diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index cc3fe70ac..0744ded49 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -2023,8 +2023,8 @@ public: break; } default: - pfgoto(proof); - assert(0 && "translate_main: unsupported proof rule"); + pfgoto(proof); + SASSERT(0 && "translate_main: unsupported proof rule"); throw unsupported(); } } From 746d26e744cadb5e0b64f66b9637b15d00ab6eab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 Dec 2015 21:14:52 -0800 Subject: [PATCH 37/87] seq Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 24 +- src/ast/seq_decl_plugin.cpp | 5 +- src/smt/theory_seq.cpp | 540 +++++++++++++++++++----------- src/smt/theory_seq.h | 20 +- 4 files changed, 385 insertions(+), 204 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index a5c3fb403..77baa36fc 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -328,9 +328,16 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { expr_ref_vector as(m()), bs(m()); m_util.str.get_concat(a, as); m_util.str.get_concat(b, bs); + bool all_values = true; + + for (unsigned i = 0; all_values && i < bs.size(); ++i) { + all_values = m().is_value(bs[i].get()); + } + bool found = false; for (unsigned i = 0; !found && i < as.size(); ++i) { if (bs.size() > as.size() - i) break; + all_values &= m().is_value(as[i].get()); unsigned j = 0; for (; j < bs.size() && as[j+i].get() == bs[j].get(); ++j) {}; found = j == bs.size(); @@ -339,6 +346,10 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) { result = m().mk_true(); return BR_DONE; } + if (all_values) { + result = m().mk_false(); + return BR_DONE; + } return BR_FAILED; } @@ -460,11 +471,22 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { m_util.str.get_concat(a, as); m_util.str.get_concat(b, bs); unsigned i = 0; - for (; i < as.size() && i < bs.size() && as[i].get() == bs[i].get(); ++i) {}; + bool all_values = true; + for (; i < as.size() && i < bs.size(); ++i) { + all_values &= m().is_value(as[i].get()) && m().is_value(bs[i].get()); + if (as[i].get() != bs[i].get()) { + break; + } + }; if (i == as.size()) { result = m().mk_true(); return BR_DONE; } + SASSERT(i < as.size()); + if (all_values && (i < bs.size() || m_util.str.is_unit(as[i+1].get()))) { + result = m().mk_false(); + return BR_DONE; + } if (i == bs.size()) { expr_ref_vector es(m()); for (unsigned j = i; j < as.size(); ++j) { diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index e516d4ea5..57ccd1a3e 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -610,7 +610,10 @@ app* seq_decl_plugin::mk_string(zstring const& s) { bool seq_decl_plugin::is_value(app* e) const { - return is_app_of(e, m_family_id, OP_STRING_CONST); + return + is_app_of(e, m_family_id, OP_STRING_CONST) || + (is_app_of(e, m_family_id, OP_SEQ_UNIT) && + m_manager->is_value(e->get_arg(0))); } app* seq_util::mk_skolem(symbol const& name, unsigned n, expr* const* args, sort* range) { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 63bdedd1e..b9886a609 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -15,6 +15,8 @@ Author: Revision History: + // Use instead reference counts for dependencies to GC? + --*/ #include "value_factory.h" @@ -153,7 +155,6 @@ theory_seq::theory_seq(ast_manager& m): m(m), m_rep(m, m_dm), m_factory(0), - m_ineqs(m), m_exclude(m), m_axioms(m), m_axioms_head(0), @@ -163,9 +164,7 @@ theory_seq::theory_seq(ast_manager& m): m_util(m), m_autil(m), m_trail_stack(*this), - m_accepts_qhead(0), - m_rejects_qhead(0), - m_steps_qhead(0) { + m_atoms_qhead(0) { m_prefix = "seq.prefix.suffix"; m_suffix = "seq.suffix.prefix"; m_contains_left = "seq.contains.left"; @@ -192,11 +191,6 @@ theory_seq::~theory_seq() { final_check_status theory_seq::final_check_eh() { context & ctx = get_context(); TRACE("seq", display(tout);); - if (!check_ineqs()) { - ++m_stats.m_check_ineqs; - TRACE("seq", tout << ">>check_ineqs\n";); - return FC_CONTINUE; - } if (simplify_and_solve_eqs()) { ++m_stats.m_solve_eqs; TRACE("seq", tout << ">>solve_eqs\n";); @@ -230,24 +224,6 @@ final_check_status theory_seq::final_check_eh() { return FC_GIVEUP; } -bool theory_seq::check_ineqs() { - context & ctx = get_context(); - for (unsigned i = 0; i < m_ineqs.size(); ++i) { - expr* a = m_ineqs[i].get(); - enode_pair_dependency* eqs = 0; - expr_ref b = canonize(a, eqs); - if (m.is_true(b)) { - TRACE("seq", tout << "Evaluates to false: " << mk_pp(a,m) << "\n";); - ctx.internalize(a, false); - propagate_lit(eqs, ctx.get_literal(a)); - return false; - } - else if (!m.is_false(b)) { - TRACE("seq", tout << "Disequality is undetermined: " << mk_pp(a, m) << " " << b << "\n";); - } - } - return true; -} bool theory_seq::branch_variable() { context& ctx = get_context(); @@ -284,7 +260,7 @@ bool theory_seq::find_branch_candidate(expr* l, expr_ref_vector const& rs) { expr_ref v0(m), v(m); v0 = m_util.str.mk_empty(m.get_sort(l)); - if (assume_equality(l, v0)) { + if (l_false != assume_equality(l, v0)) { return true; } for (unsigned j = 0; j < rs.size(); ++j) { @@ -296,33 +272,44 @@ bool theory_seq::find_branch_candidate(expr* l, expr_ref_vector const& rs) { for (unsigned k = 1; k < s.length(); ++k) { v = m_util.str.mk_string(s.extract(0, k)); if (v0) v = m_util.str.mk_concat(v0, v); - if (assume_equality(l, v)) { + if (l_false != assume_equality(l, v)) { return true; } } } v0 = (j == 0)? rs[0] : m_util.str.mk_concat(v0, rs[j]); - if (assume_equality(l, v0)) { + if (l_false != assume_equality(l, v0)) { return true; } } return false; } -bool theory_seq::assume_equality(expr* l, expr* r) { +lbool theory_seq::assume_equality(expr* l, expr* r) { context& ctx = get_context(); if (m_exclude.contains(l, r)) { - return false; + return l_false; } - else { - TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << "\n";); - enode* n1 = ensure_enode(l); - enode* n2 = ensure_enode(r); - ctx.mark_as_relevant(n1); - ctx.mark_as_relevant(n2); - ctx.assume_eq(n1, n2); - return true; + + expr_ref eq(m.mk_eq(l, r), m); + m_rewrite(eq); + if (m.is_true(eq)) { + return l_true; } + if (m.is_false(eq)) { + return l_false; + } + + TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << "\n";); + enode* n1 = ensure_enode(l); + enode* n2 = ensure_enode(r); + if (n1->get_root() == n2->get_root()) { + return l_true; + } + ctx.mark_as_relevant(n1); + ctx.mark_as_relevant(n2); + ctx.assume_eq(n1, n2); + return l_undef; } bool theory_seq::propagate_length_coherence(expr* e) { @@ -377,10 +364,8 @@ bool theory_seq::check_length_coherence() { if (is_var(e) && m_rep.is_root(e)) { expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); expr_ref head(m), tail(m); - - if (propagate_length_coherence(e)) { - } - else if (!assume_equality(e, emp)) { + if (!propagate_length_coherence(e) && + l_false == assume_equality(e, emp)) { mk_decompose(e, head, tail); // e = emp \/ e = unit(head.elem(e))*tail(e) expr_ref conc(m_util.str.mk_concat(head, tail), m); @@ -433,19 +418,6 @@ void theory_seq::mk_decompose(expr* e, expr_ref& head, expr_ref& tail) { } } -bool theory_seq::check_ineq_coherence() { - bool all_false = true; - for (unsigned i = 0; all_false && i < m_ineqs.size(); ++i) { - expr* a = m_ineqs[i].get(); - enode_pair_dependency* eqs = 0; - expr_ref b = canonize(a, eqs); - all_false = m.is_false(b); - if (all_false) { - TRACE("seq", tout << "equality is undetermined: " << mk_pp(a, m) << " " << b << "\n";); - } - } - return all_false; -} /* - Eqs = 0 @@ -457,15 +429,10 @@ bool theory_seq::is_solved() { if (!m_eqs.empty()) { return false; } - if (!check_ineq_coherence()) { - return false; - } for (unsigned i = 0; i < m_automata.size(); ++i) { if (!m_automata[i]) return false; - } - + } return true; - } void theory_seq::propagate_lit(enode_pair_dependency* dep, unsigned n, literal const* lits, literal lit) { @@ -565,10 +532,6 @@ bool theory_seq::solve_unit_eq(expr* l, expr* r, enode_pair_dependency* deps, bo propagated = add_solution(rh, lh, deps) || propagated; return true; } - // Use instead reference counts for dependencies to GC? - - // TBD: Solutions to units are not necessarily variables, but - // they may induce new equations. return false; } @@ -615,7 +578,6 @@ bool theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) { context& ctx = get_context(); TRACE("seq", tout << mk_pp(l, m) << " ==> " << mk_pp(r, m) << "\n";); m_rep.update(l, r, deps); - // TBD: skip new equalities for non-internalized terms. if (ctx.e_internalized(l) && ctx.e_internalized(r) && ctx.get_enode(l)->get_root() != ctx.get_enode(r)->get_root()) { propagate_eq(deps, ctx.get_enode(l), ctx.get_enode(r)); return true; @@ -825,7 +787,6 @@ void theory_seq::apply_sort_cnstr(enode* n, sort* s) { void theory_seq::display(std::ostream & out) const { if (m_eqs.size() == 0 && m_nqs.size() == 0 && - m_ineqs.empty() && m_rep.empty() && m_exclude.empty()) { return; @@ -839,12 +800,6 @@ void theory_seq::display(std::ostream & out) const { out << "Disequations:\n"; display_disequations(out); } - if (!m_ineqs.empty()) { - out << "Negative constraints:\n"; - for (unsigned i = 0; i < m_ineqs.size(); ++i) { - out << mk_pp(m_ineqs[i], m) << "\n"; - } - } if (!m_re2aut.empty()) { out << "Regex\n"; obj_map::iterator it = m_re2aut.begin(), end = m_re2aut.end(); @@ -908,7 +863,6 @@ void theory_seq::collect_statistics(::statistics & st) const { st.update("seq branch", m_stats.m_branch_variable); st.update("seq solve !=", m_stats.m_solve_nqs); st.update("seq solve =", m_stats.m_solve_eqs); - st.update("seq check negations", m_stats.m_check_ineqs); } @@ -1195,75 +1149,75 @@ void theory_seq::tightest_prefix(expr* s, expr* x, literal lit1, literal lit2) { /* // index of s in t starting at offset. - let i = Index(t, s, 0): + let i = Index(t, s, offset): - len(t) = 0 => i = -1 + offset >= len(t) => i = -1 + + offset fixed to 0: + len(t) != 0 & !contains(t, s) => i = -1 len(t) != 0 & contains(t, s) => t = xsy & i = len(x) len(t) != 0 & contains(t, s) & s != emp => tightest_prefix(x, s) - let i = Index(t, s, offset) + offset not fixed: - - 0 <= offset < len(t) => xy = t & len(x) = offset & (-1 = indexof(t, s, 0) => -1 = i) - & (indexof(t, s, 0) >= 0 => indexof(t, s, 0) + offset = i) - - - offset = len(t) => i = -1 - - if offset < 0 or offset >= len(t) + 0 <= offset < len(t) => xy = t & + len(x) = offset & + (-1 = indexof(y, s, 0) => -1 = i) & + (indexof(y, s, 0) >= 0 => indexof(t, s, 0) + offset = i) + + if offset < 0 under specified optional lemmas: - (len(s) > len(t) -> i = -1) - (len(s) <= len(t) -> i <= len(t)-len(s)) + (len(s) > len(t) -> i = -1) + (len(s) <= len(t) -> i <= len(t)-len(s)) */ void theory_seq::add_indexof_axiom(expr* i) { expr* s, *t, *offset; rational r; VERIFY(m_util.str.is_index(i, t, s, offset)); - expr_ref emp(m), minus_one(m), zero(m), xsy(m); - minus_one = m_autil.mk_int(-1); - zero = m_autil.mk_int(0); - literal offset_ne_zero = null_literal; - bool is_num = m_autil.is_numeral(offset, r); - if (is_num && r.is_zero()) { - offset_ne_zero = null_literal; - } - else { - offset_ne_zero = ~mk_eq(offset, zero, false); - } - if (!is_num || r.is_zero()) { - expr_ref x = mk_skolem(m_contains_left, t, s); - expr_ref y = mk_skolem(m_contains_right, t, s); - xsy = m_util.str.mk_concat(x,s,y); - literal cnt = mk_literal(m_util.str.mk_contains(t, s)); - literal eq_empty = mk_eq_empty(s); - add_axiom(offset_ne_zero, cnt, mk_eq(i, minus_one, false)); - add_axiom(offset_ne_zero, ~eq_empty, mk_eq(i, zero, false)); - add_axiom(offset_ne_zero, ~cnt, eq_empty, mk_eq(t, xsy, false)); - tightest_prefix(s, x, ~cnt, offset_ne_zero); - } - if (is_num && r.is_zero()) { - return; - } + expr_ref minus_one(m_autil.mk_int(-1), m); + expr_ref zero(m_autil.mk_int(0), m); + expr_ref xsy(m); + // offset >= len(t) => indexof(s, t, offset) = -1 expr_ref len_t(m_util.str.mk_length(t), m); literal offset_ge_len = mk_literal(m_autil.mk_ge(mk_sub(offset, len_t), zero)); add_axiom(offset_ge_len, mk_eq(i, minus_one, false)); - // 0 <= offset & offset < len(t) => t = xy - // 0 <= offset & offset < len(t) => len(x) = offset - // 0 <= offset & offset < len(t) & ~contains(s, y) => indexof(t, s, offset) = -1 - // 0 <= offset & offset < len(t) & contains(s, y) => index(t, s, offset) = indexof(y, s, 0) + len(t) - expr_ref x = mk_skolem(m_indexof_left, t, s, offset); - expr_ref y = mk_skolem(m_indexof_right, t, s, offset); - expr_ref indexof(m_util.str.mk_index(y, s, zero), m); - // TBD: - //literal offset_ge_0 = mk_literal(m_autil.mk_ge(offset, zero)); - //add_axiom(~offset_ge_0, offset_ge_len, mk_eq(indexof, i, false)); - //add_axiom(~offset_ge_0, offset_ge_len, mk_eq(m_util.str.mk_length(x), offset, false)); - //add_axiom(~offset_ge_0, offset_ge_len, mk_eq(t, m_util.str.mk_concat(x, y), false)); + if (m_autil.is_numeral(offset, r) && r.is_zero()) { + expr_ref x = mk_skolem(m_contains_left, t, s); + expr_ref y = mk_skolem(m_contains_right, t, s); + xsy = m_util.str.mk_concat(x,s,y); + literal cnt = mk_literal(m_util.str.mk_contains(t, s)); + literal eq_empty = mk_eq_empty(s); + add_axiom(cnt, mk_eq(i, minus_one, false)); + add_axiom(~eq_empty, mk_eq(i, zero, false)); + add_axiom(~cnt, eq_empty, mk_eq(t, xsy, false)); + tightest_prefix(s, x, ~cnt); + } + else { + expr_ref x = mk_skolem(m_indexof_left, t, s, offset); + expr_ref y = mk_skolem(m_indexof_right, t, s, offset); + expr_ref indexof0(m_util.str.mk_index(y, s, zero), m); + expr_ref offset_p_indexof0(m_autil.mk_add(offset, indexof0), m); + literal offset_ge_0 = mk_literal(m_autil.mk_ge(offset, zero)); + + // 0 <= offset & offset < len(t) => t = xy + // 0 <= offset & offset < len(t) => len(x) = offset + // 0 <= offset & offset < len(t) & -1 = indexof(y,s,0) = -1 => -1 = i + // 0 <= offset & offset < len(t) & indexof(y,s,0) >= 0 = -1 => + // -1 = indexof(y,s,0) + offset = indexof(t, s, offset) + + add_axiom(~offset_ge_0, offset_ge_len, mk_eq(t, m_util.str.mk_concat(x, y), false)); + add_axiom(~offset_ge_0, offset_ge_len, mk_eq(m_util.str.mk_length(x), offset, false)); + add_axiom(~offset_ge_0, offset_ge_len, + ~mk_eq(indexof0, minus_one, false), mk_eq(i, minus_one, false)); + add_axiom(~offset_ge_0, offset_ge_len, + ~mk_literal(m_autil.mk_ge(indexof0, zero)), + mk_eq(offset_p_indexof0, i, false)); + } } /* @@ -1306,10 +1260,11 @@ void theory_seq::add_elim_string_axiom(expr* n) { /* let n = len(x) - - len(x) >= 0 - len(x) = 0 => x = "" - x = "" => len(x) = 0 + - len(a ++ b) = len(a) + len(b) if x = a ++ b + - len(unit(u)) = 1 if x = unit(u) + - len(str) = str.length() if x = str + - len(empty) = 0 if x = empty + - len(x) >= 0 otherwise */ void theory_seq::add_length_axiom(expr* n) { expr* x; @@ -1326,13 +1281,7 @@ void theory_seq::add_length_axiom(expr* n) { } } else { - expr_ref zero(m_autil.mk_int(0), m); - add_axiom(mk_literal(m_autil.mk_ge(n, zero))); - - //expr_ref emp(m_util.str.mk_empty(m.get_sort(x)), m); - //literal eq1(mk_eq(zero, n, false)); - //literal eq2(mk_eq(x, emp, false)); - //add_axiom(~eq1, eq2); + add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0)))); } } @@ -1364,7 +1313,6 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { eautomaton* a = get_automaton(e2); if (!a) return; - // if (m_util.str.is_empty(e1)) return; context& ctx = get_context(); @@ -1564,8 +1512,17 @@ void theory_seq::propagate_step(bool_var v, expr* step) { VERIFY(is_step(step, s, idx, re, i, j, t)); expr_ref nth = mk_nth(s, idx); propagate_eq(v, t, nth); + literal lit(v); + SASSERT(ctx.get_assignment(lit) == l_true); + propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); } +/* + lit => len(s) > 0 +*/ +void theory_seq::propagate_non_empty(literal lit, expr* s) { + propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), m_autil.mk_int(0)))); +} literal theory_seq::mk_literal(expr* _e) { expr_ref e(_e, m); @@ -1574,15 +1531,18 @@ literal theory_seq::mk_literal(expr* _e) { return ctx.get_literal(e); } +literal theory_seq::mk_equals(expr* a, expr* b) { + literal lit = mk_eq(a, b, false); + get_context().force_phase(lit); + return lit; +} + literal theory_seq::mk_eq_empty(expr* _e) { expr_ref e(_e, m); - context& ctx = get_context(); SASSERT(m_util.is_seq(e)); expr_ref emp(m); emp = m_util.str.mk_empty(m.get_sort(e)); - literal lit = mk_eq(e, emp, false); - ctx.force_phase(lit); - return lit; + return mk_equals(e, emp); } void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4) { @@ -1612,7 +1572,7 @@ bool theory_seq::is_skolem(symbol const& s, expr* e) const { } -void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) { +void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2, bool add_to_eqs) { context& ctx = get_context(); enode* n1 = ensure_enode(e1); @@ -1622,10 +1582,18 @@ void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) { } ctx.mark_as_relevant(n1); ctx.mark_as_relevant(n2); + if (add_to_eqs) { + SASSERT(l_true == ctx.get_assignment(v)); + expr_ref l(e1, m), r(e2, m); + enode* m1 = ensure_enode(ctx.bool_var2expr(v)); + enode* m2 = ctx.get_enode(m.mk_true()); + enode_pair_dependency* deps = m_dm.mk_leaf(enode_pair(m1, m2)); + m_eqs.push_back(eq(l, r, deps)); + } + literal lit(v); TRACE("seq", tout << mk_pp(ctx.bool_var2expr(v), m) << " => " << mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";); - literal lit(v); justification* js = ctx.mk_justification( ext_theory_eq_propagation_justification( @@ -1641,58 +1609,74 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { expr* e1, *e2; expr_ref f(m); - if (is_true && m_util.str.is_prefix(e, e1, e2)) { - f = mk_skolem(m_prefix, e1, e2); - f = m_util.str.mk_concat(e1, f); - propagate_eq(v, f, e2); + if (m_util.str.is_prefix(e, e1, e2)) { + if (is_true) { + f = mk_skolem(m_prefix, e1, e2); + f = m_util.str.mk_concat(e1, f); + propagate_eq(v, f, e2, true); + } + else { + // !prefix(e1,e2) => len(e1) > 0; + propagate_non_empty(literal(v, true), e1); + add_atom(e); + } } - else if (is_true && m_util.str.is_suffix(e, e1, e2)) { - f = mk_skolem(m_suffix, e1, e2); - f = m_util.str.mk_concat(f, e1); - propagate_eq(v, f, e2); + else if (m_util.str.is_suffix(e, e1, e2)) { + if (is_true) { + f = mk_skolem(m_suffix, e1, e2); + f = m_util.str.mk_concat(f, e1); + propagate_eq(v, f, e2, true); + } + else { + propagate_non_empty(literal(v, true), e1); + add_atom(e); + } } - else if (is_true && m_util.str.is_contains(e, e1, e2)) { - expr_ref f1 = mk_skolem(m_contains_left, e1, e2); - expr_ref f2 = mk_skolem(m_contains_right, e1, e2); - f = m_util.str.mk_concat(f1, m_util.str.mk_concat(e2, f2)); - propagate_eq(v, f, e1); + else if (m_util.str.is_contains(e, e1, e2)) { + if (is_true) { + expr_ref f1 = mk_skolem(m_contains_left, e1, e2); + expr_ref f2 = mk_skolem(m_contains_right, e1, e2); + f = m_util.str.mk_concat(f1, e2, f2); + propagate_eq(v, f, e1, true); + } + else { + literal lit(v, true); + propagate_non_empty(lit, e2); + propagate_lit(0, 1, &lit, ~mk_literal(m_util.str.mk_prefix(e2, e1))); + add_atom(e); + } } else if (is_accept(e)) { if (is_true) { - m_trail_stack.push(push_back_vector >(m_accepts)); - m_accepts.push_back(e); + propagate_acc_rej_length(v, e); + add_atom(e); } } else if (is_reject(e)) { if (is_true) { - m_trail_stack.push(push_back_vector >(m_rejects)); - m_rejects.push_back(e); + propagate_acc_rej_length(v, e); + add_atom(e); } } else if (is_step(e)) { if (is_true) { propagate_step(v, e); - m_trail_stack.push(push_back_vector >(m_steps)); - m_steps.push_back(e); + add_atom(e); } } else if (m_util.str.is_in_re(e)) { propagate_in_re(e, is_true); } else { - SASSERT(!is_true); - //if (m_util.str.is_prefix(e, e1, e2)) { - // could add negative prefix axioms: - // len(e1) <= len(e2) => e2 = seq.prefix.left(e2)*seq.prefix.right(e2) - // & len(seq.prefix.left(e2)) = len(e1) - // & seq.prefix.left(e2) != e1 - // or could solve prefix/suffix disunification constraints. - //} - m_trail_stack.push(push_back_vector(m_ineqs)); - m_ineqs.push_back(e); + UNREACHABLE(); } } +void theory_seq::add_atom(expr* e) { + m_trail_stack.push(push_back_vector >(m_atoms)); + m_atoms.push_back(e); +} + void theory_seq::new_eq_eh(theory_var v1, theory_var v2) { enode* n1 = get_enode(v1); enode* n2 = get_enode(v2); @@ -1843,11 +1827,27 @@ expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned return expr_ref(m_util.mk_skolem(m_aut_step, args.size(), args.c_ptr(), m.mk_bool_sort()), m); } +/* + acc(s, idx, re, i) -> len(s) >= idx + rej(s, idx, re, i) => len(s) >= idx +*/ +void theory_seq::propagate_acc_rej_length(bool_var v, expr* e) { + context& ctx = get_context(); + expr *s, * idx, *re; + unsigned src; + eautomaton* aut = 0; + VERIFY(is_accept(e, s, idx, re, src, aut) || + is_reject(e, s, idx, re, src, aut)); + if (m_util.str.is_length(idx)) return; + SASSERT(m_autil.is_numeral(idx)); + literal lit(v); + SASSERT(ctx.get_assignment(lit) == l_true); + propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); +} /** acc(s, idx, re, i) -> \/ step(s, idx, re, i, j, t) if i is non-final acc(s, idx, re, i) -> len(s) <= idx \/ step(s, idx, re, i, j, t) if i is final - acc(s, idx, re, i) -> len(s) >= idx */ void theory_seq::add_accept2step(expr* acc) { context& ctx = get_context(); @@ -1902,7 +1902,6 @@ void theory_seq::add_step2accept(expr* step) { /* rej(s, idx, re, i) & nth(s,idx) = t & idx < len(s) => rej(s, idx + 1 re, j) - rej(s, idx, re, i) => idx <= len(s) */ void theory_seq::add_reject2reject(expr* rej) { context& ctx = get_context(); @@ -1928,27 +1927,180 @@ void theory_seq::add_reject2reject(expr* rej) { } } +/* + !prefix -> e2 = emp \/ nth(e1,0) != nth(e2,0) \/ !prefix(tail(e1),tail(e2)) +*/ +bool theory_seq::add_prefix2prefix(expr* e) { + context& ctx = get_context(); + expr* e1, *e2; + VERIFY(m_util.str.is_prefix(e, e1, e2)); + SASSERT(ctx.get_assignment(e) == l_false); + if (canonizes(false, e)) { + return false; + } + expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); + switch (assume_equality(e2, emp)) { + case l_true: + return false; // done + case l_undef: + return true; // retry + default: + break; + } + expr_ref head1(m), tail1(m), head2(m), tail2(m); + mk_decompose(e1, head1, tail1); + mk_decompose(e2, head2, tail2); + + literal lit = mk_eq(head1, head2, false); + switch (ctx.get_assignment(lit)) { + case l_true: { + literal_vector lits; + lits.push_back(~ctx.get_literal(e)); + lits.push_back(~mk_eq(e2, emp, false)); + lits.push_back(lit); + propagate_lit(0, lits.size(), lits.c_ptr(), ~mk_literal(m_util.str.mk_prefix(tail1, tail2))); + return false; + } + case l_false: + return false; + case l_undef: + ctx.force_phase(~lit); + return true; + } + return true; +} + +/* + !suffix(e1, e2) -> e2 = emp \/ nth(e1,len(e1)-1) != nth(e2,len(e2)-1) \/ !suffix(first(e1), first(e2)) + */ +bool theory_seq::add_suffix2suffix(expr* e) { + context& ctx = get_context(); + expr* e1, *e2; + VERIFY(m_util.str.is_suffix(e, e1, e2)); + SASSERT(ctx.get_assignment(e) == l_false); + if (canonizes(false, e)) { + return false; + } + + expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); + + switch (assume_equality(e2, emp)) { + case l_true: + return false; // done + case l_undef: + return true; // retry + case l_false: + break; + } + + NOT_IMPLEMENTED_YET(); + // TBD: + expr_ref head1(m), tail1(m), head2(m), tail2(m); + mk_decompose(e2, head2, tail2); + + literal lit = mk_eq(head1, head2, false); + switch (ctx.get_assignment(lit)) { + case l_true: { + literal_vector lits; + lits.push_back(~ctx.get_literal(e)); + lits.push_back(~mk_eq(e2, emp, false)); + lits.push_back(lit); + propagate_lit(0, lits.size(), lits.c_ptr(), mk_literal(m_util.str.mk_suffix(tail1, tail2))); + return false; + } + case l_false: + return false; + case l_undef: + ctx.force_phase(~lit); + return true; + } + return true; +} + +bool theory_seq::canonizes(bool sign, expr* e) { + context& ctx = get_context(); + enode_pair_dependency* deps = 0; + expr_ref cont = canonize(e, deps); + if ((m.is_true(cont) && !sign) || + (m.is_false(cont) && sign)) { + propagate_lit(deps, 0, 0, ctx.get_literal(e)); + return true; + } + if ((m.is_false(cont) && !sign) || + (m.is_true(cont) && sign)) { + return true; + } + return false; +} + +/* + !contains(e1, e2) -> !prefix(e2, e1) + !contains(e1, e2) -> e1 = emp \/ !contains(tail(e1), e2) + */ + +bool theory_seq::add_contains2contains(expr* e) { + context& ctx = get_context(); + expr* e1, *e2; + VERIFY(m_util.str.is_contains(e, e1, e2)); + SASSERT(ctx.get_assignment(e) == l_false); + if (canonizes(false, e)) { + return false; + } + expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m); + + switch (assume_equality(e1, emp)) { + case l_true: + return false; // done + case l_undef: + return true; // retry + default: + break; + } + expr_ref head(m), tail(m); + mk_decompose(e1, head, tail); + literal lits[2] = { ~ctx.get_literal(e), ~mk_eq(e1, emp, false) }; + propagate_lit(0, 2, lits, ~mk_literal(m_util.str.mk_contains(tail, e1))); + return false; +} + bool theory_seq::propagate_automata() { context& ctx = get_context(); - bool change = false; - if (m_accepts_qhead < m_accepts.size()) - m_trail_stack.push(value_trail(m_accepts_qhead)), change = true; - if (m_rejects_qhead < m_rejects.size()) - m_trail_stack.push(value_trail(m_rejects_qhead)), change = true; - if (m_steps_qhead < m_steps.size()) - m_trail_stack.push(value_trail(m_steps_qhead)), change = true; - - while (m_accepts_qhead < m_accepts.size() && !ctx.inconsistent()) { - add_accept2step(m_accepts[m_accepts_qhead]); - ++m_accepts_qhead; + if (m_atoms_qhead == m_atoms.size()) { + return false; } - while (m_rejects_qhead < m_rejects.size() && !ctx.inconsistent()) { - add_reject2reject(m_rejects[m_rejects_qhead]); - ++m_rejects_qhead; + m_trail_stack.push(value_trail(m_atoms_qhead)); + ptr_vector re_add; + while (m_atoms_qhead < m_atoms.size() && !ctx.inconsistent()) { + expr* e = m_atoms[m_atoms_qhead]; + TRACE("seq", tout << mk_pp(e, m) << "\n";); + bool reQ = false; + if (is_accept(e)) { + add_accept2step(e); + } + else if (is_reject(e)) { + add_reject2reject(e); + } + else if (is_step(e)) { + add_step2accept(e); + } + else if (m_util.str.is_prefix(e)) { + reQ = add_prefix2prefix(e); + } + else if (m_util.str.is_suffix(e)) { + reQ = add_suffix2suffix(e); + } + else if (m_util.str.is_contains(e)) { + reQ = add_contains2contains(e); + } + if (reQ) { + re_add.push_back(e); + m_atoms[m_atoms_qhead] = m_atoms.back(); + m_atoms.pop_back(); + } + else { + ++m_atoms_qhead; + } } - while (m_steps_qhead < m_steps.size() && !ctx.inconsistent()) { - add_step2accept(m_steps[m_steps_qhead]); - ++m_steps_qhead; - } - return change || ctx.inconsistent(); + m_atoms.append(re_add); + return true; } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 5760fb437..798dd1341 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -252,7 +252,6 @@ namespace smt { unsigned m_branch_variable; unsigned m_solve_nqs; unsigned m_solve_eqs; - unsigned m_check_ineqs; }; ast_manager& m; enode_pair_dependency_manager m_dm; @@ -261,7 +260,6 @@ namespace smt { scoped_vector m_nqs; // set of current disequalities. seq_factory* m_factory; // value factory - expr_ref_vector m_ineqs; // inequalities to check solution against exclusion_table m_exclude; // set of asserted disequalities. expr_ref_vector m_axioms; // list of axioms to add. obj_hashtable m_axiom_set; @@ -283,8 +281,8 @@ namespace smt { // maintain automata with regular expressions. scoped_ptr_vector m_automata; obj_map m_re2aut; - ptr_vector m_accepts, m_rejects, m_steps; - unsigned m_accepts_qhead, m_rejects_qhead, m_steps_qhead; + ptr_vector m_atoms; + unsigned m_atoms_qhead; virtual final_check_status final_check_eh(); virtual bool internalize_atom(app* atom, bool) { return internalize_term(atom); } @@ -309,14 +307,12 @@ namespace smt { virtual void init_model(model_generator & mg); // final check - bool check_ineqs(); // check if inequalities are violated. bool simplify_and_solve_eqs(); // solve unitary equalities bool branch_variable(); // branch on a variable bool split_variable(); // split a variable bool is_solved(); bool check_length_coherence(); bool propagate_length_coherence(expr* e); - bool check_ineq_coherence(); bool pre_process_eqs(bool simplify_or_solve, bool& propagated); bool simplify_eqs(bool& propagated) { return pre_process_eqs(true, propagated); } @@ -332,11 +328,11 @@ namespace smt { void propagate_lit(enode_pair_dependency* dep, literal lit) { propagate_lit(dep, 0, 0, lit); } void propagate_lit(enode_pair_dependency* dep, unsigned n, literal const* lits, literal lit); void propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2); - void propagate_eq(bool_var v, expr* e1, expr* e2); + void propagate_eq(bool_var v, expr* e1, expr* e2, bool add_to_eqs = false); void set_conflict(enode_pair_dependency* dep, literal_vector const& lits = literal_vector()); bool find_branch_candidate(expr* l, expr_ref_vector const& rs); - bool assume_equality(expr* l, expr* r); + lbool assume_equality(expr* l, expr* r); // variable solving utilities bool occurs(expr* a, expr* b); @@ -368,6 +364,7 @@ namespace smt { void add_in_re_axiom(expr* n); literal mk_literal(expr* n); literal mk_eq_empty(expr* n); + literal mk_equals(expr* a, expr* b); void tightest_prefix(expr* s, expr* x, literal lit, literal lit2 = null_literal); expr_ref mk_sub(expr* a, expr* b); enode* ensure_enode(expr* a); @@ -406,7 +403,14 @@ namespace smt { void add_reject2reject(expr* rej); void add_accept2step(expr* acc); void add_step2accept(expr* step); + bool add_prefix2prefix(expr* e); + bool add_suffix2suffix(expr* e); + bool add_contains2contains(expr* e); + bool canonizes(bool sign, expr* e); + void propagate_non_empty(literal lit, expr* s); + void propagate_acc_rej_length(bool_var v, expr* acc_rej); bool propagate_automata(); + void add_atom(expr* e); // diagnostics void display_equations(std::ostream& out) const; From 03afedafaf6a6e00def185481e32b0c44ff777d9 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 30 Dec 2015 13:54:01 +0000 Subject: [PATCH 38/87] expr_abstract: don't recreate an AST_APP if arguments didn't change gives ~30% speedup in some benchmarks with quantifiers Signed-off-by: Nuno Lopes --- src/ast/expr_abstract.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ast/expr_abstract.cpp b/src/ast/expr_abstract.cpp index 0569eb360..949168cad 100644 --- a/src/ast/expr_abstract.cpp +++ b/src/ast/expr_abstract.cpp @@ -49,6 +49,7 @@ void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* case AST_APP: { app* a = to_app(curr); bool all_visited = true; + bool changed = false; m_args.reset(); for (unsigned i = 0; i < a->get_num_args(); ++i) { if (!m_map.find(a->get_arg(i), b)) { @@ -56,12 +57,17 @@ void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* all_visited = false; } else { + changed |= b != a->get_arg(i); m_args.push_back(b); } } if (all_visited) { - b = m.mk_app(a->get_decl(), m_args.size(), m_args.c_ptr()); - m_pinned.push_back(b); + if (changed) { + b = m.mk_app(a->get_decl(), m_args.size(), m_args.c_ptr()); + m_pinned.push_back(b); + } else { + b = curr; + } m_map.insert(curr, b); m_stack.pop_back(); } From c8931a7bba6e9250e5c92d4c520ecfcf6a51f5d3 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 30 Dec 2015 15:50:46 +0000 Subject: [PATCH 39/87] remove unused decl Signed-off-by: Nuno Lopes --- src/shell/smtlib_frontend.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index 834fe4429..6c4c01ab0 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -33,7 +33,6 @@ Revision History: #include"smt_solver.h" extern bool g_display_statistics; -extern void display_config(); static clock_t g_start_time; static smtlib::solver* g_solver = 0; static cmd_context * g_cmd_context = 0; From 78550ec816129e9b8184618f09b6750b7107cf29 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Dec 2015 07:48:14 -0800 Subject: [PATCH 40/87] seq Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 8 +- src/ast/seq_decl_plugin.cpp | 2 +- src/smt/theory_seq.cpp | 177 +++++++++++++++++++----------- src/smt/theory_seq.h | 64 ++++++----- 4 files changed, 152 insertions(+), 99 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 77baa36fc..00b4371d9 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -475,6 +475,10 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { for (; i < as.size() && i < bs.size(); ++i) { all_values &= m().is_value(as[i].get()) && m().is_value(bs[i].get()); if (as[i].get() != bs[i].get()) { + if (all_values) { + result = m().mk_false(); + return BR_DONE; + } break; } }; @@ -483,10 +487,6 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) { return BR_DONE; } SASSERT(i < as.size()); - if (all_values && (i < bs.size() || m_util.str.is_unit(as[i+1].get()))) { - result = m().mk_false(); - return BR_DONE; - } if (i == bs.size()) { expr_ref_vector es(m()); for (unsigned j = i; j < as.size(); ++j) { diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 57ccd1a3e..70ee4298b 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -611,7 +611,7 @@ app* seq_decl_plugin::mk_string(zstring const& s) { bool seq_decl_plugin::is_value(app* e) const { return - is_app_of(e, m_family_id, OP_STRING_CONST) || + is_app_of(e, m_family_id, OP_SEQ_EMPTY) || (is_app_of(e, m_family_id, OP_SEQ_UNIT) && m_manager->is_value(e->get_arg(0))); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index b9886a609..4f9273322 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -39,12 +39,12 @@ struct display_expr { -void theory_seq::solution_map::update(expr* e, expr* r, enode_pair_dependency* d) { +void theory_seq::solution_map::update(expr* e, expr* r, dependency* d) { if (e == r) { return; } m_cache.reset(); - std::pair value; + std::pair value; if (m_map.find(e, value)) { add_trail(DEL, e, value.first, value.second); } @@ -54,7 +54,7 @@ void theory_seq::solution_map::update(expr* e, expr* r, enode_pair_dependency* d add_trail(INS, e, r, d); } -void theory_seq::solution_map::add_trail(map_update op, expr* l, expr* r, enode_pair_dependency* d) { +void theory_seq::solution_map::add_trail(map_update op, expr* l, expr* r, dependency* d) { m_updates.push_back(op); m_lhs.push_back(l); m_rhs.push_back(r); @@ -65,8 +65,8 @@ bool theory_seq::solution_map::is_root(expr* e) const { return !m_map.contains(e); } -expr* theory_seq::solution_map::find(expr* e, enode_pair_dependency*& d) { - std::pair value; +expr* theory_seq::solution_map::find(expr* e, dependency*& d) { + std::pair value; d = 0; expr* result = e; while (m_map.find(result, value)) { @@ -80,7 +80,7 @@ expr* theory_seq::solution_map::find(expr* e, enode_pair_dependency*& d) { } expr* theory_seq::solution_map::find(expr* e) { - std::pair value; + std::pair value; while (m_map.find(e, value)) { e = value.first; } @@ -258,11 +258,15 @@ bool theory_seq::find_branch_candidate(expr* l, expr_ref_vector const& rs) { return false; } + + bool all_units = true; + expr_ref_vector cases(m); expr_ref v0(m), v(m); v0 = m_util.str.mk_empty(m.get_sort(l)); if (l_false != assume_equality(l, v0)) { return true; } + cases.push_back(v0); for (unsigned j = 0; j < rs.size(); ++j) { if (occurs(l, rs[j])) { return false; @@ -276,12 +280,23 @@ bool theory_seq::find_branch_candidate(expr* l, expr_ref_vector const& rs) { return true; } } + all_units = false; } + all_units &= m_util.str.is_unit(rs[j]); v0 = (j == 0)? rs[0] : m_util.str.mk_concat(v0, rs[j]); + cases.push_back(v0); if (l_false != assume_equality(l, v0)) { return true; } } + if (all_units) { + literal_vector lits; + for (unsigned i = 0; i < cases.size(); ++i) { + lits.push_back(mk_eq(l, cases[i].get(), false)); + } + get_context().mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + return true; + } return false; } @@ -328,7 +343,6 @@ bool theory_seq::propagate_length_coherence(expr* e) { tout << " lo: " << lo << " hi: " << hi << "\n"; ); - literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)))); expr_ref seq(e, m); expr_ref_vector elems(m); unsigned _lo = lo.get_unsigned(); @@ -337,25 +351,24 @@ bool theory_seq::propagate_length_coherence(expr* e) { elems.push_back(head); seq = tail; } + expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); elems.push_back(seq); tail = m_util.str.mk_concat(elems.size(), elems.c_ptr()); // len(e) >= low => e = tail - add_axiom(~low, mk_eq(e, tail, false)); - assume_equality(tail, e); + literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)))); + add_axiom(~low, mk_eq(e, tail, false)); + assume_equality(seq, emp); if (upper_bound(e, hi)) { expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m); expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); add_axiom(~mk_literal(high1), mk_literal(high2)); } - //m_replay_length_coherence.push_back(e); - //m_replay_length_coherence_qhead = m_replay_length_coherence.size(); return true; } bool theory_seq::check_length_coherence() { - if (m_length.empty()) return true; context& ctx = get_context(); bool coherent = true; obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); @@ -366,10 +379,10 @@ bool theory_seq::check_length_coherence() { expr_ref head(m), tail(m); if (!propagate_length_coherence(e) && l_false == assume_equality(e, emp)) { - mk_decompose(e, head, tail); // e = emp \/ e = unit(head.elem(e))*tail(e) + mk_decompose(e, head, tail); expr_ref conc(m_util.str.mk_concat(head, tail), m); - add_axiom(mk_eq_empty(e), mk_eq(e, conc, false)); + propagate_is_conc(e, conc); assume_equality(tail, emp); } return false; @@ -378,6 +391,24 @@ bool theory_seq::check_length_coherence() { return coherent; } +/* + lit => s != "" +*/ +void theory_seq::propagate_non_empty(literal lit, expr* s) { + SASSERT(get_context().get_assignment(lit) == l_true); + propagate_lit(0, 1, &lit, ~mk_eq_empty(s)); +} + +void theory_seq::propagate_is_conc(expr* e, expr* conc) { + TRACE("seq", tout << mk_pp(conc, m) << " is non-empty\n";); + context& ctx = get_context(); + literal lit = ~mk_eq_empty(e); + SASSERT(ctx.get_assignment(lit) == l_true); + propagate_lit(0, 1, &lit, mk_eq(e, conc, false)); + expr_ref e1(e, m), e2(conc, m); + m_eqs.push_back(eq(e1, e2, m_dm.mk_leaf(assumption(lit)))); +} + expr_ref theory_seq::mk_nth(expr* s, expr* idx) { sort* char_sort = 0; VERIFY(m_util.is_seq(m.get_sort(s), char_sort)); @@ -435,36 +466,55 @@ bool theory_seq::is_solved() { return true; } -void theory_seq::propagate_lit(enode_pair_dependency* dep, unsigned n, literal const* lits, literal lit) { +void theory_seq::linearize(dependency* dep, enode_pair_vector& eqs, literal_vector& lits) const { + svector assumptions; + const_cast(m_dm).linearize(dep, assumptions); + for (unsigned i = 0; i < assumptions.size(); ++i) { + assumption const& a = assumptions[i]; + if (a.lit != null_literal) { + lits.push_back(a.lit); + } + if (a.n1 != 0) { + eqs.push_back(enode_pair(a.n1, a.n2)); + } + } +} + + + +void theory_seq::propagate_lit(dependency* dep, unsigned n, literal const* _lits, literal lit) { context& ctx = get_context(); ctx.mark_as_relevant(lit); - vector _eqs; - m_dm.linearize(dep, _eqs); + literal_vector lits(n, _lits); + enode_pair_vector eqs; + linearize(dep, eqs, lits); TRACE("seq", ctx.display_detailed_literal(tout, lit); - tout << " <- "; ctx.display_literals_verbose(tout, n, lits); display_deps(tout, dep);); + tout << " <- "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); display_deps(tout, dep);); justification* js = ctx.mk_justification( ext_theory_propagation_justification( - get_id(), ctx.get_region(), n, lits, _eqs.size(), _eqs.c_ptr(), lit)); + get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), lit)); ctx.assign(lit, js); } -void theory_seq::set_conflict(enode_pair_dependency* dep, literal_vector const& lits) { +void theory_seq::set_conflict(dependency* dep, literal_vector const& _lits) { context& ctx = get_context(); - vector _eqs; - m_dm.linearize(dep, _eqs); + enode_pair_vector eqs; + literal_vector lits(_lits); + linearize(dep, eqs, lits); TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); display_deps(tout, dep); ;); ctx.set_conflict( ctx.mk_justification( ext_theory_conflict_justification( - get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), _eqs.size(), _eqs.c_ptr(), 0, 0))); + get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), 0, 0))); } -void theory_seq::propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2) { +void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) { context& ctx = get_context(); - vector _eqs; - m_dm.linearize(dep, _eqs); + literal_vector lits; + enode_pair_vector eqs; + linearize(dep, eqs, lits); TRACE("seq", tout << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << " <- "; display_deps(tout, dep); @@ -472,13 +522,13 @@ void theory_seq::propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2) justification* js = ctx.mk_justification( ext_theory_eq_propagation_justification( - get_id(), ctx.get_region(), 0, 0, _eqs.size(), _eqs.c_ptr(), n1, n2)); + get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), n1, n2)); ctx.assign_eq(n1, n2, eq_justification(js)); } -bool theory_seq::simplify_eq(expr* l, expr* r, enode_pair_dependency* deps, bool& propagated) { +bool theory_seq::simplify_eq(expr* l, expr* r, dependency* deps, bool& propagated) { context& ctx = get_context(); seq_rewriter rw(m); expr_ref_vector lhs(m), rhs(m); @@ -518,7 +568,7 @@ bool theory_seq::simplify_eq(expr* l, expr* r, enode_pair_dependency* deps, bool return true; } -bool theory_seq::solve_unit_eq(expr* l, expr* r, enode_pair_dependency* deps, bool& propagated) { +bool theory_seq::solve_unit_eq(expr* l, expr* r, dependency* deps, bool& propagated) { expr_ref lh = canonize(l, deps); expr_ref rh = canonize(r, deps); if (lh == rh) { @@ -571,7 +621,7 @@ bool theory_seq::is_nth(expr* e) const { return is_skolem(m_nth, e); } -bool theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) { +bool theory_seq::add_solution(expr* l, expr* r, dependency* deps) { if (l == r) { return false; } @@ -645,7 +695,7 @@ bool theory_seq::solve_ne(unsigned idx) { } for (unsigned i = 0; i < n.m_lhs.size(); ++i) { expr_ref_vector lhs(m), rhs(m); - enode_pair_dependency* deps = 0; + dependency* deps = 0; expr* l = n.m_lhs[i]; expr* r = n.m_rhs[i]; expr_ref lh = canonize(l, deps); @@ -744,16 +794,15 @@ bool theory_seq::internalize_term(app* term) { ctx.set_var_theory(bv, get_id()); ctx.mark_as_relevant(bv); } - else { - enode* e = 0; - if (ctx.e_internalized(term)) { - e = ctx.get_enode(term); - } - else { - e = ctx.mk_enode(term, false, m.is_bool(term), true); - } - mk_var(e); + enode* e = 0; + if (ctx.e_internalized(term)) { + e = ctx.get_enode(term); } + else { + e = ctx.mk_enode(term, false, m.is_bool(term), true); + } + mk_var(e); + return true; } @@ -846,13 +895,15 @@ void theory_seq::display_disequation(std::ostream& out, ne const& e) const { display_deps(out, e.m_dep); } -void theory_seq::display_deps(std::ostream& out, enode_pair_dependency* dep) const { - vector _eqs; - const_cast(m_dm).linearize(dep, _eqs); - for (unsigned i = 0; i < _eqs.size(); ++i) { - out << " " << mk_pp(_eqs[i].first->get_owner(), m) << " = " << mk_pp(_eqs[i].second->get_owner(), m); +void theory_seq::display_deps(std::ostream& out, dependency* dep) const { + literal_vector lits; + enode_pair_vector eqs; + linearize(dep, eqs, lits); + for (unsigned i = 0; i < eqs.size(); ++i) { + out << " " << mk_pp(eqs[i].first->get_owner(), m) << " = " << mk_pp(eqs[i].second->get_owner(), m); } out << "\n"; + get_context().display_literals_verbose(tout, lits.size(), lits.c_ptr()); } void theory_seq::collect_statistics(::statistics & st) const { @@ -953,7 +1004,7 @@ app* theory_seq::mk_value(app* e) { expr* e1; expr_ref result(e, m); if (m_util.str.is_unit(e, e1)) { - enode_pair_dependency* deps = 0; + dependency* deps = 0; result = expand(e1, deps); bv_util bv(m); rational val; @@ -1027,15 +1078,15 @@ bool theory_seq::can_propagate() { return m_axioms_head < m_axioms.size(); } -expr_ref theory_seq::canonize(expr* e, enode_pair_dependency*& eqs) { +expr_ref theory_seq::canonize(expr* e, dependency*& eqs) { expr_ref result = expand(e, eqs); m_rewrite(result); return result; } -expr_ref theory_seq::expand(expr* e0, enode_pair_dependency*& eqs) { +expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { expr_ref result(m); - enode_pair_dependency* deps = 0; + dependency* deps = 0; expr_dep ed; if (m_rep.find_cache(e0, ed)) { eqs = m_dm.mk_join(eqs, ed.second); @@ -1073,9 +1124,9 @@ expr_ref theory_seq::expand(expr* e0, enode_pair_dependency*& eqs) { return result; } -void theory_seq::add_dependency(enode_pair_dependency*& dep, enode* a, enode* b) { +void theory_seq::add_dependency(dependency*& dep, enode* a, enode* b) { if (a != b) { - dep = m_dm.mk_join(dep, m_dm.mk_leaf(std::make_pair(a, b))); + dep = m_dm.mk_join(dep, m_dm.mk_leaf(assumption(a, b))); } } @@ -1517,12 +1568,6 @@ void theory_seq::propagate_step(bool_var v, expr* step) { propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); } -/* - lit => len(s) > 0 -*/ -void theory_seq::propagate_non_empty(literal lit, expr* s) { - propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), m_autil.mk_int(0)))); -} literal theory_seq::mk_literal(expr* _e) { expr_ref e(_e, m); @@ -1585,9 +1630,7 @@ void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2, bool add_to_eqs) { if (add_to_eqs) { SASSERT(l_true == ctx.get_assignment(v)); expr_ref l(e1, m), r(e2, m); - enode* m1 = ensure_enode(ctx.bool_var2expr(v)); - enode* m2 = ctx.get_enode(m.mk_true()); - enode_pair_dependency* deps = m_dm.mk_leaf(enode_pair(m1, m2)); + dependency* deps = m_dm.mk_leaf(assumption(literal(v))); m_eqs.push_back(eq(l, r, deps)); } literal lit(v); @@ -1616,7 +1659,7 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { propagate_eq(v, f, e2, true); } else { - // !prefix(e1,e2) => len(e1) > 0; + // !prefix(e1,e2) => e1 != "" propagate_non_empty(literal(v, true), e1); add_atom(e); } @@ -1639,9 +1682,9 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { f = m_util.str.mk_concat(f1, e2, f2); propagate_eq(v, f, e1, true); } - else { + else if (!canonizes(false, e)) { literal lit(v, true); - propagate_non_empty(lit, e2); + propagate_non_empty(literal(v, true), e2); propagate_lit(0, 1, &lit, ~mk_literal(m_util.str.mk_prefix(e2, e1))); add_atom(e); } @@ -1680,11 +1723,11 @@ void theory_seq::add_atom(expr* e) { void theory_seq::new_eq_eh(theory_var v1, theory_var v2) { enode* n1 = get_enode(v1); enode* n2 = get_enode(v2); - if (n1 != n2) { + if (n1 != n2 && m_util.is_seq(n1->get_owner())) { expr_ref o1(n1->get_owner(), m); expr_ref o2(n2->get_owner(), m); TRACE("seq", tout << o1 << " = " << o2 << "\n";); - enode_pair_dependency* deps = m_dm.mk_leaf(enode_pair(n1, n2)); + dependency* deps = m_dm.mk_leaf(assumption(n1, n2)); bool propagated = false; if (!simplify_eq(o1, o2, deps, propagated)) { m_eqs.push_back(eq(o1, o2, deps)); @@ -1709,6 +1752,7 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { if (!m.is_false(eq)) { m_nqs.push_back(ne(e1, e2)); } + // add solution for variable that is non-empty? } void theory_seq::push_scope_eh() { @@ -2019,8 +2063,9 @@ bool theory_seq::add_suffix2suffix(expr* e) { bool theory_seq::canonizes(bool sign, expr* e) { context& ctx = get_context(); - enode_pair_dependency* deps = 0; + dependency* deps = 0; expr_ref cont = canonize(e, deps); + TRACE("seq", tout << mk_pp(e, m) << " -> " << cont << "\n";); if ((m.is_true(cont) && !sign) || (m.is_false(cont) && sign)) { propagate_lit(deps, 0, 0, ctx.get_literal(e)); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 798dd1341..2de6a36d0 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -32,11 +32,17 @@ Revision History: namespace smt { class theory_seq : public theory { - typedef scoped_dependency_manager enode_pair_dependency_manager; - typedef enode_pair_dependency_manager::dependency enode_pair_dependency; - + struct assumption { + enode* n1, *n2; + literal lit; + assumption(enode* n1, enode* n2): n1(n1), n2(n2), lit(null_literal) {} + assumption(literal lit): n1(0), n2(0), lit(lit) {} + }; + typedef scoped_dependency_manager dependency_manager; + typedef dependency_manager::dependency dependency; + typedef trail_stack th_trail_stack; - typedef std::pair expr_dep; + typedef std::pair expr_dep; typedef obj_map eqdep_map_t; // cache to track evaluations under equalities @@ -55,26 +61,26 @@ namespace smt { class solution_map { enum map_update { INS, DEL }; ast_manager& m; - enode_pair_dependency_manager& m_dm; + dependency_manager& m_dm; eqdep_map_t m_map; eval_cache m_cache; expr_ref_vector m_lhs, m_rhs; - ptr_vector m_deps; + ptr_vector m_deps; svector m_updates; unsigned_vector m_limit; - void add_trail(map_update op, expr* l, expr* r, enode_pair_dependency* d); + void add_trail(map_update op, expr* l, expr* r, dependency* d); public: - solution_map(ast_manager& m, enode_pair_dependency_manager& dm): + solution_map(ast_manager& m, dependency_manager& dm): m(m), m_dm(dm), m_cache(m), m_lhs(m), m_rhs(m) {} bool empty() const { return m_map.empty(); } - void update(expr* e, expr* r, enode_pair_dependency* d); + void update(expr* e, expr* r, dependency* d); void add_cache(expr* v, expr_dep& r) { m_cache.insert(v, r); } bool find_cache(expr* v, expr_dep& r) { return m_cache.find(v, r); } - expr* find(expr* e, enode_pair_dependency*& d); + expr* find(expr* e, dependency*& d); expr* find(expr* e); bool is_root(expr* e) const; - void cache(expr* e, expr* r, enode_pair_dependency* d); + void cache(expr* e, expr* r, dependency* d); void reset_cache() { m_cache.reset(); } void push_scope() { m_limit.push_back(m_updates.size()); } void pop_scope(unsigned num_scopes); @@ -103,8 +109,8 @@ namespace smt { struct eq { expr_ref m_lhs; expr_ref m_rhs; - enode_pair_dependency* m_dep; - eq(expr_ref& l, expr_ref& r, enode_pair_dependency* d): + dependency* m_dep; + eq(expr_ref& l, expr_ref& r, dependency* d): m_lhs(l), m_rhs(r), m_dep(d) {} eq(eq const& other): m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_dep(other.m_dep) {} eq& operator=(eq const& other) { m_lhs = other.m_lhs; m_rhs = other.m_rhs; m_dep = other.m_dep; return *this; } @@ -118,7 +124,7 @@ namespace smt { expr_ref_vector m_lhs; expr_ref_vector m_rhs; literal_vector m_lits; - enode_pair_dependency* m_dep; + dependency* m_dep; ne(expr_ref& l, expr_ref& r): m_solved(false), m_l(l), m_r(r), m_lhs(l.get_manager()), m_rhs(r.get_manager()), m_dep(0) { m_lhs.push_back(l); @@ -229,10 +235,10 @@ namespace smt { }; class push_dep : public trail { - enode_pair_dependency* m_dep; + dependency* m_dep; unsigned m_idx; public: - push_dep(theory_seq& th, unsigned idx, enode_pair_dependency* d): m_dep(th.m_nqs[idx].m_dep), m_idx(idx) { + push_dep(theory_seq& th, unsigned idx, dependency* d): m_dep(th.m_nqs[idx].m_dep), m_idx(idx) { th.m_nqs.ref(idx).m_dep = d; } virtual void undo(theory_seq& th) { @@ -254,7 +260,7 @@ namespace smt { unsigned m_solve_eqs; }; ast_manager& m; - enode_pair_dependency_manager m_dm; + dependency_manager m_dm; solution_map m_rep; // unification representative. scoped_vector m_eqs; // set of current equations. scoped_vector m_nqs; // set of current disequalities. @@ -317,19 +323,20 @@ namespace smt { bool pre_process_eqs(bool simplify_or_solve, bool& propagated); bool simplify_eqs(bool& propagated) { return pre_process_eqs(true, propagated); } bool solve_basic_eqs(bool& propagated) { return pre_process_eqs(false, propagated); } - bool simplify_eq(expr* l, expr* r, enode_pair_dependency* dep, bool& propagated); - bool solve_unit_eq(expr* l, expr* r, enode_pair_dependency* dep, bool& propagated); + bool simplify_eq(expr* l, expr* r, dependency* dep, bool& propagated); + bool solve_unit_eq(expr* l, expr* r, dependency* dep, bool& propagated); bool solve_nqs(); bool solve_ne(unsigned i); bool unchanged(expr* e, expr_ref_vector& es) const { return es.size() == 1 && es[0] == e; } // asserting consequences - void propagate_lit(enode_pair_dependency* dep, literal lit) { propagate_lit(dep, 0, 0, lit); } - void propagate_lit(enode_pair_dependency* dep, unsigned n, literal const* lits, literal lit); - void propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2); + void linearize(dependency* dep, enode_pair_vector& eqs, literal_vector& lits) const; + void propagate_lit(dependency* dep, literal lit) { propagate_lit(dep, 0, 0, lit); } + void propagate_lit(dependency* dep, unsigned n, literal const* lits, literal lit); + void propagate_eq(dependency* dep, enode* n1, enode* n2); void propagate_eq(bool_var v, expr* e1, expr* e2, bool add_to_eqs = false); - void set_conflict(enode_pair_dependency* dep, literal_vector const& lits = literal_vector()); + void set_conflict(dependency* dep, literal_vector const& lits = literal_vector()); bool find_branch_candidate(expr* l, expr_ref_vector const& rs); lbool assume_equality(expr* l, expr* r); @@ -337,12 +344,12 @@ namespace smt { // variable solving utilities bool occurs(expr* a, expr* b); bool is_var(expr* b); - bool add_solution(expr* l, expr* r, enode_pair_dependency* dep); + bool add_solution(expr* l, expr* r, dependency* dep); bool is_nth(expr* a) const; expr_ref mk_nth(expr* s, expr* idx); - expr_ref canonize(expr* e, enode_pair_dependency*& eqs); - expr_ref expand(expr* e, enode_pair_dependency*& eqs); - void add_dependency(enode_pair_dependency*& dep, enode* a, enode* b); + expr_ref canonize(expr* e, dependency*& eqs); + expr_ref expand(expr* e, dependency*& eqs); + void add_dependency(dependency*& dep, enode* a, enode* b); void get_concat(expr* e, ptr_vector& concats); @@ -408,6 +415,7 @@ namespace smt { bool add_contains2contains(expr* e); bool canonizes(bool sign, expr* e); void propagate_non_empty(literal lit, expr* s); + void propagate_is_conc(expr* e, expr* conc); void propagate_acc_rej_length(bool_var v, expr* acc_rej); bool propagate_automata(); void add_atom(expr* e); @@ -416,7 +424,7 @@ namespace smt { void display_equations(std::ostream& out) const; void display_disequations(std::ostream& out) const; void display_disequation(std::ostream& out, ne const& e) const; - void display_deps(std::ostream& out, enode_pair_dependency* deps) const; + void display_deps(std::ostream& out, dependency* deps) const; public: theory_seq(ast_manager& m); virtual ~theory_seq(); From 60f866e2598f5dd85ae49e704d1decb41686ece2 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 31 Dec 2015 16:40:04 +0000 Subject: [PATCH 41/87] Bugfix for FP numeral construction and extraction. --- src/api/api_fpa.cpp | 71 +++++++++++++---- src/ast/fpa_decl_plugin.cpp | 150 ++++++++++++++++++------------------ 2 files changed, 130 insertions(+), 91 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 3987ca23d..a31fed7c2 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -931,13 +931,21 @@ extern "C" { mpf_manager & mpfm = mk_c(c)->fpautil().fm(); unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); - fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); - scoped_mpf val(mpfm); - if (!plugin->is_numeral(to_expr(t), val)) { + family_id fid = mk_c(c)->get_fpa_fid(); + fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); + SASSERT(plugin != 0); + expr * e = to_expr(t); + if (!is_app(e) || + is_app_of(e, fid, OP_FPA_NAN) || + is_app_of(e, fid, OP_FPA_PLUS_INF) || + is_app_of(e, fid, OP_FPA_MINUS_INF)) { SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } - else if (!mpfm.is_regular(val)) { + scoped_mpf val(mpfm); + app * a = to_app(e); + bool r = plugin->is_numeral(e, val); + if (!r || !mpfm.is_regular(val)) { SET_ERROR_CODE(Z3_INVALID_ARG) return ""; } @@ -960,16 +968,25 @@ extern "C" { ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); - fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); - scoped_mpf val(mpfm); - bool r = plugin->is_numeral(to_expr(t), val); - if (!r) { + family_id fid = mk_c(c)->get_fpa_fid(); + fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); + SASSERT(plugin != 0); + expr * e = to_expr(t); + if (!is_app(e) || + is_app_of(e, fid, OP_FPA_NAN) || + is_app_of(e, fid, OP_FPA_PLUS_INF) || + is_app_of(e, fid, OP_FPA_MINUS_INF)) { SET_ERROR_CODE(Z3_INVALID_ARG); + *n = 0; return 0; } + scoped_mpf val(mpfm); + app * a = to_app(e); + bool r = plugin->is_numeral(e, val); const mpz & z = mpfm.sig(val); - if (!mpzm.is_uint64(z)) { + if (!r || mpfm.is_regular(val)|| !mpzm.is_uint64(z)) { SET_ERROR_CODE(Z3_INVALID_ARG); + *n = 0; return 0; } *n = mpzm.get_uint64(z); @@ -983,15 +1000,22 @@ extern "C" { RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); - scoped_mpf val(mpfm); - bool r = plugin->is_numeral(to_expr(t), val); - if (!r) { + SASSERT(plugin != 0); + expr * e = to_expr(t); + if (!is_app(e) || + is_app_of(e, fid, OP_FPA_NAN) || + is_app_of(e, fid, OP_FPA_PLUS_INF) || + is_app_of(e, fid, OP_FPA_MINUS_INF)) { SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } - else if (!mpfm.is_normal(val) && !mpfm.is_denormal(val)) { - SET_ERROR_CODE(Z3_INVALID_ARG) + scoped_mpf val(mpfm); + app * a = to_app(e); + bool r = plugin->is_numeral(e, val); + if (!r || !mpfm.is_regular(val)) { + SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } mpf_exp_t exp = mpfm.exp_normalized(val); @@ -1007,11 +1031,24 @@ extern "C" { RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); - scoped_mpf val(mpfm); - bool r = plugin->is_numeral(to_expr(t), val); - if (!r) { + SASSERT(plugin != 0); + expr * e = to_expr(t); + if (!is_app(e) || + is_app_of(e, fid, OP_FPA_NAN) || + is_app_of(e, fid, OP_FPA_PLUS_INF) || + is_app_of(e, fid, OP_FPA_MINUS_INF)) { SET_ERROR_CODE(Z3_INVALID_ARG); + *n = 0; + return 0; + } + scoped_mpf val(mpfm); + app * a = to_app(e); + bool r = plugin->is_numeral(e, val); + if (!r || !mpfm.is_regular(val)) { + SET_ERROR_CODE(Z3_INVALID_ARG); + *n = 0; return 0; } *n = mpfm.exp(val); diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index d32aa5e6d..7833ae7d1 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -39,7 +39,7 @@ void fpa_decl_plugin::set_manager(ast_manager * m, family_id id) { m_int_sort = m_manager->mk_sort(m_arith_fid, INT_SORT); SASSERT(m_int_sort != 0); // arith_decl_plugin must be installed before fpa_decl_plugin. m_manager->inc_ref(m_int_sort); - + // BV is not optional anymore. SASSERT(m_manager->has_plugin(symbol("bv"))); m_bv_fid = m_manager->mk_family_id("bv"); @@ -69,28 +69,30 @@ void fpa_decl_plugin::recycled_id(unsigned id) { } func_decl * fpa_decl_plugin::mk_numeral_decl(mpf const & v) { - parameter p(mk_id(v), true); - SASSERT(p.is_external()); sort * s = mk_float_sort(v.get_ebits(), v.get_sbits()); - return m_manager->mk_const_decl(symbol("fp.numeral"), s, func_decl_info(m_family_id, OP_FPA_NUM, 1, &p)); + func_decl * r = 0; + if (m_fm.is_nan(v)) + r = m_manager->mk_const_decl(symbol("NaN"), s, func_decl_info(m_family_id, OP_FPA_NAN)); + else if (m_fm.is_pinf(v)) + r = m_manager->mk_const_decl(symbol("+oo"), s, func_decl_info(m_family_id, OP_FPA_PLUS_INF)); + else if (m_fm.is_ninf(v)) + r = m_manager->mk_const_decl(symbol("-oo"), s, func_decl_info(m_family_id, OP_FPA_MINUS_INF)); + else if (m_fm.is_pzero(v)) + r = m_manager->mk_const_decl(symbol("+zero"), s, func_decl_info(m_family_id, OP_FPA_PLUS_ZERO)); + else if (m_fm.is_nzero(v)) + r = m_manager->mk_const_decl(symbol("-zero"), s, func_decl_info(m_family_id, OP_FPA_MINUS_ZERO)); + else { + SASSERT(m_fm.is_regular(v)); + parameter p(mk_id(v), true); + SASSERT(p.is_external()); + sort * s = mk_float_sort(v.get_ebits(), v.get_sbits()); + r = m_manager->mk_const_decl(symbol("fp.numeral"), s, func_decl_info(m_family_id, OP_FPA_NUM, 1, &p)); + } + return r; } app * fpa_decl_plugin::mk_numeral(mpf const & v) { - sort * s = mk_float_sort(v.get_ebits(), v.get_sbits()); - func_decl * d; - if (m_fm.is_nan(v)) - d = m_manager->mk_const_decl(symbol("NaN"), s, func_decl_info(m_family_id, OP_FPA_NAN)); - else if (m_fm.is_pinf(v)) - d = m_manager->mk_const_decl(symbol("+oo"), s, func_decl_info(m_family_id, OP_FPA_PLUS_INF)); - else if (m_fm.is_ninf(v)) - d = m_manager->mk_const_decl(symbol("-oo"), s, func_decl_info(m_family_id, OP_FPA_MINUS_INF)); - else if (m_fm.is_pzero(v)) - d = m_manager->mk_const_decl(symbol("+zero"), s, func_decl_info(m_family_id, OP_FPA_PLUS_ZERO)); - else if (m_fm.is_nzero(v)) - d = m_manager->mk_const_decl(symbol("-zero"), s, func_decl_info(m_family_id, OP_FPA_MINUS_ZERO)); - else - d = mk_numeral_decl(v); - return m_manager->mk_const(d); + return m_manager->mk_const(mk_numeral_decl(v)); } bool fpa_decl_plugin::is_numeral(expr * n, mpf & val) { @@ -161,9 +163,9 @@ bool fpa_decl_plugin::is_rm_numeral(expr * n, mpf_rounding_mode & val) { return 0; } -bool fpa_decl_plugin::is_rm_numeral(expr * n) { - mpf_rounding_mode t; - return is_rm_numeral(n, t); +bool fpa_decl_plugin::is_rm_numeral(expr * n) { + mpf_rounding_mode t; + return is_rm_numeral(n, t); } void fpa_decl_plugin::del(parameter const & p) { @@ -182,8 +184,8 @@ void fpa_decl_plugin::finalize() { if (m_int_sort) { m_manager->dec_ref(m_int_sort); } } -decl_plugin * fpa_decl_plugin::mk_fresh() { - return alloc(fpa_decl_plugin); +decl_plugin * fpa_decl_plugin::mk_fresh() { + return alloc(fpa_decl_plugin); } sort * fpa_decl_plugin::mk_float_sort(unsigned ebits, unsigned sbits) { @@ -268,7 +270,7 @@ func_decl * fpa_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_param } SASSERT(is_sort_of(s, m_family_id, FLOATING_POINT_SORT)); - + unsigned ebits = s->get_parameter(0).get_int(); unsigned sbits = s->get_parameter(1).get_int(); scoped_mpf val(m_fm); @@ -297,9 +299,9 @@ func_decl * fpa_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_parameter switch (k) { case OP_FPA_EQ: name = "fp.eq"; break; case OP_FPA_LT: name = "fp.lt"; break; - case OP_FPA_GT: name = "fp.gt"; break; - case OP_FPA_LE: name = "fp.leq"; break; - case OP_FPA_GE: name = "fp.geq"; break; + case OP_FPA_GT: name = "fp.gt"; break; + case OP_FPA_LE: name = "fp.leq"; break; + case OP_FPA_GE: name = "fp.geq"; break; default: UNREACHABLE(); break; @@ -336,7 +338,7 @@ func_decl * fpa_decl_plugin::mk_unary_decl(decl_kind k, unsigned num_parameters, if (arity != 1) m_manager->raise_exception("invalid number of arguments to floating point operator"); if (!is_float_sort(domain[0])) - m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort"); + m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort"); symbol name; switch (k) { case OP_FPA_ABS: name = "fp.abs"; break; @@ -353,7 +355,7 @@ func_decl * fpa_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_parameters if (arity != 2) m_manager->raise_exception("invalid number of arguments to floating point operator"); if (domain[0] != domain[1] || !is_float_sort(domain[0])) - m_manager->raise_exception("sort mismatch, expected arguments of equal FloatingPoint sorts"); + m_manager->raise_exception("sort mismatch, expected arguments of equal FloatingPoint sorts"); symbol name; switch (k) { case OP_FPA_REM: name = "fp.rem"; break; @@ -377,7 +379,7 @@ func_decl * fpa_decl_plugin::mk_rm_binary_decl(decl_kind k, unsigned num_paramet if (!is_rm_sort(domain[0])) m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort"); if (domain[1] != domain[2] || !is_float_sort(domain[1])) - m_manager->raise_exception("sort mismatch, expected arguments 1 and 2 of equal FloatingPoint sorts"); + m_manager->raise_exception("sort mismatch, expected arguments 1 and 2 of equal FloatingPoint sorts"); symbol name; switch (k) { case OP_FPA_ADD: name = "fp.add"; break; @@ -398,7 +400,7 @@ func_decl * fpa_decl_plugin::mk_rm_unary_decl(decl_kind k, unsigned num_paramete if (!is_rm_sort(domain[0])) m_manager->raise_exception("sort mismatch, expected RoundingMode as first argument"); if (!is_float_sort(domain[1])) - m_manager->raise_exception("sort mismatch, expected FloatingPoint as second argument"); + m_manager->raise_exception("sort mismatch, expected FloatingPoint as second argument"); symbol name; switch (k) { case OP_FPA_SQRT: name = "fp.sqrt"; break; @@ -423,8 +425,8 @@ func_decl * fpa_decl_plugin::mk_fma(decl_kind k, unsigned num_parameters, parame } func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - if (m_bv_plugin && arity == 3 && + unsigned arity, sort * const * domain, sort * range) { + if (m_bv_plugin && arity == 3 && is_sort_of(domain[0], m_bv_fid, BV_SORT) && is_sort_of(domain[1], m_bv_fid, BV_SORT) && is_sort_of(domain[2], m_bv_fid, BV_SORT)) { @@ -445,7 +447,7 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para int ebits = parameters[0].get_int(); int sbits = parameters[1].get_int(); - + if (domain[0]->get_parameter(0).get_int() != (ebits + sbits)) m_manager->raise_exception("sort mismatch; invalid bit-vector size, expected bitvector of size (ebits+sbits)"); @@ -453,7 +455,7 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para symbol name("to_fp"); return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); } - else if (m_bv_plugin && arity == 2 && + else if (m_bv_plugin && arity == 2 && is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) && is_sort_of(domain[1], m_bv_fid, BV_SORT)) { // RoundingMode + 1 BV -> 1 FP @@ -477,16 +479,16 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para if (!parameters[0].is_int() || !parameters[1].is_int()) m_manager->raise_exception("invalid parameter type to to_fp"); int ebits = parameters[0].get_int(); - int sbits = parameters[1].get_int(); + int sbits = parameters[1].get_int(); if (!is_rm_sort(domain[0])) m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort"); if (!is_sort_of(domain[1], m_family_id, FLOATING_POINT_SORT)) m_manager->raise_exception("sort mismatch, expected second argument of FloatingPoint sort"); - + sort * fp = mk_float_sort(ebits, sbits); symbol name("to_fp"); return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); - } + } else if (arity == 3 && is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) && is_sort_of(domain[1], m_arith_fid, REAL_SORT) && @@ -494,7 +496,7 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para { // Rounding + 1 Real + 1 Int -> 1 FP if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) - m_manager->raise_exception("expecting two integer parameters to to_fp"); + m_manager->raise_exception("expecting two integer parameters to to_fp"); sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); symbol name("to_fp"); @@ -561,13 +563,13 @@ func_decl * fpa_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_paramet m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort"); if (!is_sort_of(domain[1], m_bv_fid, BV_SORT)) m_manager->raise_exception("sort mismatch, expected second argument of bit-vector sort"); - + // RoundingMode + 1 BV -> 1 FP if (num_parameters != 2) m_manager->raise_exception("invalid number of parameters to to_fp_unsigned"); if (!parameters[0].is_int() || !parameters[1].is_int()) m_manager->raise_exception("invalid parameter type to to_fp_unsigned"); - + int ebits = parameters[0].get_int(); int sbits = parameters[1].get_int(); @@ -579,16 +581,16 @@ func_decl * fpa_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_paramet func_decl * fpa_decl_plugin::mk_fp(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { if (arity != 3) - m_manager->raise_exception("invalid number of arguments to fp"); - if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) || + m_manager->raise_exception("invalid number of arguments to fp"); + if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) || (domain[0]->get_parameter(0).get_int() != 1) || !is_sort_of(domain[1], m_bv_fid, BV_SORT) || !is_sort_of(domain[2], m_bv_fid, BV_SORT)) m_manager->raise_exception("sort mismatch, expected three bit-vectors, the first one of size 1."); - + int eb = (domain[1])->get_parameter(0).get_int(); int sb = (domain[2])->get_parameter(0).get_int() + 1; - symbol name("fp"); + symbol name("fp"); sort * fp = mk_float_sort(eb, sb); return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k)); } @@ -636,12 +638,12 @@ func_decl * fpa_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, par } func_decl * fpa_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { + unsigned arity, sort * const * domain, sort * range) { if (arity != 1) m_manager->raise_exception("invalid number of arguments to fp.to_real"); if (!is_float_sort(domain[0])) m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort"); - + symbol name("fp.to_real"); return m_manager->mk_func_decl(name, 1, domain, m_real_sort, func_decl_info(m_family_id, k)); } @@ -668,7 +670,7 @@ func_decl * fpa_decl_plugin::mk_internal_rm(decl_kind k, unsigned num_parameters m_manager->raise_exception("sort mismatch, expected argument of sort bitvector, size 3"); if (!is_rm_sort(range)) m_manager->raise_exception("sort mismatch, expected range of RoundingMode sort"); - + parameter ps[] = { parameter(3) }; sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps); return m_manager->mk_func_decl(symbol("rm"), 1, &bv_srt, range, func_decl_info(m_family_id, k, num_parameters, parameters)); @@ -688,7 +690,7 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps); return m_manager->mk_func_decl(symbol("bv_wrap"), 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); } - else { + else { parameter ps[] = { parameter(3) }; sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps); return m_manager->mk_func_decl(symbol("bv_wrap"), 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); @@ -698,12 +700,12 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param func_decl * fpa_decl_plugin::mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { if (arity != 1) - m_manager->raise_exception("invalid number of arguments to internal_bv_unwrap"); + m_manager->raise_exception("invalid number of arguments to internal_bv_unwrap"); if (!is_sort_of(domain[0], m_bv_fid, BV_SORT)) m_manager->raise_exception("sort mismatch, expected argument of bitvector sort"); if (!is_float_sort(range) && !is_rm_sort(range)) m_manager->raise_exception("sort mismatch, expected range of FloatingPoint or RoundingMode sort"); - + return m_manager->mk_func_decl(symbol("bv_unwrap"), 1, domain, range, func_decl_info(m_family_id, k, num_parameters, parameters)); } @@ -716,7 +718,7 @@ func_decl * fpa_decl_plugin::mk_internal_to_ubv_unspecified( m_manager->raise_exception("invalid number of parameters to fp.to_ubv_unspecified; expecting 1"); if (!parameters[0].is_int()) m_manager->raise_exception("invalid parameters type provided to fp.to_ubv_unspecified; expecting an integer"); - + sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, parameters); return m_manager->mk_func_decl(symbol("fp.to_ubv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); } @@ -748,7 +750,7 @@ func_decl * fpa_decl_plugin::mk_internal_to_real_unspecified( func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { - switch (k) { + switch (k) { case OP_FPA_MINUS_INF: case OP_FPA_PLUS_INF: case OP_FPA_NAN: @@ -768,14 +770,14 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_GE: return mk_bin_rel_decl(k, num_parameters, parameters, arity, domain, range); case OP_FPA_IS_ZERO: - case OP_FPA_IS_NEGATIVE: + case OP_FPA_IS_NEGATIVE: case OP_FPA_IS_POSITIVE: case OP_FPA_IS_NAN: case OP_FPA_IS_INF: case OP_FPA_IS_NORMAL: case OP_FPA_IS_SUBNORMAL: return mk_unary_rel_decl(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_ABS: + case OP_FPA_ABS: case OP_FPA_NEG: return mk_unary_decl(k, num_parameters, parameters, arity, domain, range); case OP_FPA_REM: @@ -787,7 +789,7 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_DIV: return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range); case OP_FPA_SUB: - if (arity == 1) + if (arity == 1) return mk_unary_decl(OP_FPA_NEG, num_parameters, parameters, arity, domain, range); else return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range); @@ -797,7 +799,7 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_FMA: return mk_fma(k, num_parameters, parameters, arity, domain, range); case OP_FPA_FP: - return mk_fp(k, num_parameters, parameters, arity, domain, range); + return mk_fp(k, num_parameters, parameters, arity, domain, range); case OP_FPA_TO_UBV: return mk_to_ubv(k, num_parameters, parameters, arity, domain, range); case OP_FPA_TO_SBV: @@ -817,13 +819,13 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); case OP_FPA_INTERNAL_BVUNWRAP: return mk_internal_bv_unwrap(k, num_parameters, parameters, arity, domain, range); - + case OP_FPA_INTERNAL_MIN_I: case OP_FPA_INTERNAL_MAX_I: case OP_FPA_INTERNAL_MIN_UNSPECIFIED: case OP_FPA_INTERNAL_MAX_UNSPECIFIED: return mk_binary_decl(k, num_parameters, parameters, arity, domain, range); - + case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: return mk_internal_to_ubv_unspecified(k, num_parameters, parameters, arity, domain, range); case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: @@ -857,19 +859,19 @@ void fpa_decl_plugin::get_op_names(svector & op_names, symbol cons op_names.push_back(builtin_name("RTZ", OP_FPA_RM_TOWARD_ZERO)); op_names.push_back(builtin_name("fp.abs", OP_FPA_ABS)); - op_names.push_back(builtin_name("fp.neg", OP_FPA_NEG)); - op_names.push_back(builtin_name("fp.add", OP_FPA_ADD)); - op_names.push_back(builtin_name("fp.sub", OP_FPA_SUB)); - op_names.push_back(builtin_name("fp.mul", OP_FPA_MUL)); + op_names.push_back(builtin_name("fp.neg", OP_FPA_NEG)); + op_names.push_back(builtin_name("fp.add", OP_FPA_ADD)); + op_names.push_back(builtin_name("fp.sub", OP_FPA_SUB)); + op_names.push_back(builtin_name("fp.mul", OP_FPA_MUL)); op_names.push_back(builtin_name("fp.div", OP_FPA_DIV)); - op_names.push_back(builtin_name("fp.fma", OP_FPA_FMA)); - op_names.push_back(builtin_name("fp.sqrt", OP_FPA_SQRT)); + op_names.push_back(builtin_name("fp.fma", OP_FPA_FMA)); + op_names.push_back(builtin_name("fp.sqrt", OP_FPA_SQRT)); op_names.push_back(builtin_name("fp.rem", OP_FPA_REM)); op_names.push_back(builtin_name("fp.roundToIntegral", OP_FPA_ROUND_TO_INTEGRAL)); op_names.push_back(builtin_name("fp.min", OP_FPA_MIN)); - op_names.push_back(builtin_name("fp.max", OP_FPA_MAX)); + op_names.push_back(builtin_name("fp.max", OP_FPA_MAX)); op_names.push_back(builtin_name("fp.leq", OP_FPA_LE)); - op_names.push_back(builtin_name("fp.lt", OP_FPA_LT)); + op_names.push_back(builtin_name("fp.lt", OP_FPA_LT)); op_names.push_back(builtin_name("fp.geq", OP_FPA_GE)); op_names.push_back(builtin_name("fp.gt", OP_FPA_GT)); op_names.push_back(builtin_name("fp.eq", OP_FPA_EQ)); @@ -880,13 +882,13 @@ void fpa_decl_plugin::get_op_names(svector & op_names, symbol cons op_names.push_back(builtin_name("fp.isInfinite", OP_FPA_IS_INF)); op_names.push_back(builtin_name("fp.isNaN", OP_FPA_IS_NAN)); op_names.push_back(builtin_name("fp.isNegative", OP_FPA_IS_NEGATIVE)); - op_names.push_back(builtin_name("fp.isPositive", OP_FPA_IS_POSITIVE)); + op_names.push_back(builtin_name("fp.isPositive", OP_FPA_IS_POSITIVE)); op_names.push_back(builtin_name("fp", OP_FPA_FP)); op_names.push_back(builtin_name("fp.to_ubv", OP_FPA_TO_UBV)); op_names.push_back(builtin_name("fp.to_sbv", OP_FPA_TO_SBV)); op_names.push_back(builtin_name("fp.to_real", OP_FPA_TO_REAL)); - + op_names.push_back(builtin_name("to_fp", OP_FPA_TO_FP)); op_names.push_back(builtin_name("to_fp_unsigned", OP_FPA_TO_FP_UNSIGNED)); @@ -917,13 +919,13 @@ expr * fpa_decl_plugin::get_some_value(sort * s) { func_decl * f = mk_rm_const_decl(OP_FPA_RM_TOWARD_ZERO, 0, 0, 0, 0, s); return m_manager->mk_const(f); } - + UNREACHABLE(); return 0; } bool fpa_decl_plugin::is_value(app * e) const { - if (e->get_family_id() != m_family_id) + if (e->get_family_id() != m_family_id) return false; switch (e->get_decl_kind()) { case OP_FPA_RM_NEAREST_TIES_TO_EVEN: @@ -956,7 +958,7 @@ bool fpa_decl_plugin::is_unique_value(app* e) const { case OP_FPA_RM_TOWARD_POSITIVE: case OP_FPA_RM_TOWARD_NEGATIVE: case OP_FPA_RM_TOWARD_ZERO: - return true; + return true; case OP_FPA_PLUS_INF: /* No; +oo == fp(#b0 #b11 #b00) */ case OP_FPA_MINUS_INF: /* No; -oo == fp #b1 #b11 #b00) */ case OP_FPA_PLUS_ZERO: /* No; +zero == fp #b0 #b00 #b000) */ @@ -1029,7 +1031,7 @@ app * fpa_util::mk_nzero(unsigned ebits, unsigned sbits) { return mk_value(v); } -app * fpa_util::mk_internal_to_ubv_unspecified(unsigned width) { +app * fpa_util::mk_internal_to_ubv_unspecified(unsigned width) { parameter ps[] = { parameter(width) }; sort * range = m_bv_util.mk_sort(width); return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 1, ps, 0, 0, range); From 4286eb571ffc0540c74a56cea5c540e424b36e51 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 31 Dec 2015 16:40:04 +0000 Subject: [PATCH 42/87] Bugfix for FP numeral construction and extraction. Fixes #382. --- src/api/api_fpa.cpp | 71 +++++++++++++---- src/ast/fpa_decl_plugin.cpp | 150 ++++++++++++++++++------------------ 2 files changed, 130 insertions(+), 91 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 3987ca23d..a31fed7c2 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -931,13 +931,21 @@ extern "C" { mpf_manager & mpfm = mk_c(c)->fpautil().fm(); unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); unsynch_mpq_manager & mpqm = mpfm.mpq_manager(); - fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); - scoped_mpf val(mpfm); - if (!plugin->is_numeral(to_expr(t), val)) { + family_id fid = mk_c(c)->get_fpa_fid(); + fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); + SASSERT(plugin != 0); + expr * e = to_expr(t); + if (!is_app(e) || + is_app_of(e, fid, OP_FPA_NAN) || + is_app_of(e, fid, OP_FPA_PLUS_INF) || + is_app_of(e, fid, OP_FPA_MINUS_INF)) { SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } - else if (!mpfm.is_regular(val)) { + scoped_mpf val(mpfm); + app * a = to_app(e); + bool r = plugin->is_numeral(e, val); + if (!r || !mpfm.is_regular(val)) { SET_ERROR_CODE(Z3_INVALID_ARG) return ""; } @@ -960,16 +968,25 @@ extern "C" { ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); unsynch_mpz_manager & mpzm = mpfm.mpz_manager(); - fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); - scoped_mpf val(mpfm); - bool r = plugin->is_numeral(to_expr(t), val); - if (!r) { + family_id fid = mk_c(c)->get_fpa_fid(); + fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid); + SASSERT(plugin != 0); + expr * e = to_expr(t); + if (!is_app(e) || + is_app_of(e, fid, OP_FPA_NAN) || + is_app_of(e, fid, OP_FPA_PLUS_INF) || + is_app_of(e, fid, OP_FPA_MINUS_INF)) { SET_ERROR_CODE(Z3_INVALID_ARG); + *n = 0; return 0; } + scoped_mpf val(mpfm); + app * a = to_app(e); + bool r = plugin->is_numeral(e, val); const mpz & z = mpfm.sig(val); - if (!mpzm.is_uint64(z)) { + if (!r || mpfm.is_regular(val)|| !mpzm.is_uint64(z)) { SET_ERROR_CODE(Z3_INVALID_ARG); + *n = 0; return 0; } *n = mpzm.get_uint64(z); @@ -983,15 +1000,22 @@ extern "C" { RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); - scoped_mpf val(mpfm); - bool r = plugin->is_numeral(to_expr(t), val); - if (!r) { + SASSERT(plugin != 0); + expr * e = to_expr(t); + if (!is_app(e) || + is_app_of(e, fid, OP_FPA_NAN) || + is_app_of(e, fid, OP_FPA_PLUS_INF) || + is_app_of(e, fid, OP_FPA_MINUS_INF)) { SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } - else if (!mpfm.is_normal(val) && !mpfm.is_denormal(val)) { - SET_ERROR_CODE(Z3_INVALID_ARG) + scoped_mpf val(mpfm); + app * a = to_app(e); + bool r = plugin->is_numeral(e, val); + if (!r || !mpfm.is_regular(val)) { + SET_ERROR_CODE(Z3_INVALID_ARG); return ""; } mpf_exp_t exp = mpfm.exp_normalized(val); @@ -1007,11 +1031,24 @@ extern "C" { RESET_ERROR_CODE(); ast_manager & m = mk_c(c)->m(); mpf_manager & mpfm = mk_c(c)->fpautil().fm(); + family_id fid = mk_c(c)->get_fpa_fid(); fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid()); - scoped_mpf val(mpfm); - bool r = plugin->is_numeral(to_expr(t), val); - if (!r) { + SASSERT(plugin != 0); + expr * e = to_expr(t); + if (!is_app(e) || + is_app_of(e, fid, OP_FPA_NAN) || + is_app_of(e, fid, OP_FPA_PLUS_INF) || + is_app_of(e, fid, OP_FPA_MINUS_INF)) { SET_ERROR_CODE(Z3_INVALID_ARG); + *n = 0; + return 0; + } + scoped_mpf val(mpfm); + app * a = to_app(e); + bool r = plugin->is_numeral(e, val); + if (!r || !mpfm.is_regular(val)) { + SET_ERROR_CODE(Z3_INVALID_ARG); + *n = 0; return 0; } *n = mpfm.exp(val); diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index d32aa5e6d..7833ae7d1 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -39,7 +39,7 @@ void fpa_decl_plugin::set_manager(ast_manager * m, family_id id) { m_int_sort = m_manager->mk_sort(m_arith_fid, INT_SORT); SASSERT(m_int_sort != 0); // arith_decl_plugin must be installed before fpa_decl_plugin. m_manager->inc_ref(m_int_sort); - + // BV is not optional anymore. SASSERT(m_manager->has_plugin(symbol("bv"))); m_bv_fid = m_manager->mk_family_id("bv"); @@ -69,28 +69,30 @@ void fpa_decl_plugin::recycled_id(unsigned id) { } func_decl * fpa_decl_plugin::mk_numeral_decl(mpf const & v) { - parameter p(mk_id(v), true); - SASSERT(p.is_external()); sort * s = mk_float_sort(v.get_ebits(), v.get_sbits()); - return m_manager->mk_const_decl(symbol("fp.numeral"), s, func_decl_info(m_family_id, OP_FPA_NUM, 1, &p)); + func_decl * r = 0; + if (m_fm.is_nan(v)) + r = m_manager->mk_const_decl(symbol("NaN"), s, func_decl_info(m_family_id, OP_FPA_NAN)); + else if (m_fm.is_pinf(v)) + r = m_manager->mk_const_decl(symbol("+oo"), s, func_decl_info(m_family_id, OP_FPA_PLUS_INF)); + else if (m_fm.is_ninf(v)) + r = m_manager->mk_const_decl(symbol("-oo"), s, func_decl_info(m_family_id, OP_FPA_MINUS_INF)); + else if (m_fm.is_pzero(v)) + r = m_manager->mk_const_decl(symbol("+zero"), s, func_decl_info(m_family_id, OP_FPA_PLUS_ZERO)); + else if (m_fm.is_nzero(v)) + r = m_manager->mk_const_decl(symbol("-zero"), s, func_decl_info(m_family_id, OP_FPA_MINUS_ZERO)); + else { + SASSERT(m_fm.is_regular(v)); + parameter p(mk_id(v), true); + SASSERT(p.is_external()); + sort * s = mk_float_sort(v.get_ebits(), v.get_sbits()); + r = m_manager->mk_const_decl(symbol("fp.numeral"), s, func_decl_info(m_family_id, OP_FPA_NUM, 1, &p)); + } + return r; } app * fpa_decl_plugin::mk_numeral(mpf const & v) { - sort * s = mk_float_sort(v.get_ebits(), v.get_sbits()); - func_decl * d; - if (m_fm.is_nan(v)) - d = m_manager->mk_const_decl(symbol("NaN"), s, func_decl_info(m_family_id, OP_FPA_NAN)); - else if (m_fm.is_pinf(v)) - d = m_manager->mk_const_decl(symbol("+oo"), s, func_decl_info(m_family_id, OP_FPA_PLUS_INF)); - else if (m_fm.is_ninf(v)) - d = m_manager->mk_const_decl(symbol("-oo"), s, func_decl_info(m_family_id, OP_FPA_MINUS_INF)); - else if (m_fm.is_pzero(v)) - d = m_manager->mk_const_decl(symbol("+zero"), s, func_decl_info(m_family_id, OP_FPA_PLUS_ZERO)); - else if (m_fm.is_nzero(v)) - d = m_manager->mk_const_decl(symbol("-zero"), s, func_decl_info(m_family_id, OP_FPA_MINUS_ZERO)); - else - d = mk_numeral_decl(v); - return m_manager->mk_const(d); + return m_manager->mk_const(mk_numeral_decl(v)); } bool fpa_decl_plugin::is_numeral(expr * n, mpf & val) { @@ -161,9 +163,9 @@ bool fpa_decl_plugin::is_rm_numeral(expr * n, mpf_rounding_mode & val) { return 0; } -bool fpa_decl_plugin::is_rm_numeral(expr * n) { - mpf_rounding_mode t; - return is_rm_numeral(n, t); +bool fpa_decl_plugin::is_rm_numeral(expr * n) { + mpf_rounding_mode t; + return is_rm_numeral(n, t); } void fpa_decl_plugin::del(parameter const & p) { @@ -182,8 +184,8 @@ void fpa_decl_plugin::finalize() { if (m_int_sort) { m_manager->dec_ref(m_int_sort); } } -decl_plugin * fpa_decl_plugin::mk_fresh() { - return alloc(fpa_decl_plugin); +decl_plugin * fpa_decl_plugin::mk_fresh() { + return alloc(fpa_decl_plugin); } sort * fpa_decl_plugin::mk_float_sort(unsigned ebits, unsigned sbits) { @@ -268,7 +270,7 @@ func_decl * fpa_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_param } SASSERT(is_sort_of(s, m_family_id, FLOATING_POINT_SORT)); - + unsigned ebits = s->get_parameter(0).get_int(); unsigned sbits = s->get_parameter(1).get_int(); scoped_mpf val(m_fm); @@ -297,9 +299,9 @@ func_decl * fpa_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_parameter switch (k) { case OP_FPA_EQ: name = "fp.eq"; break; case OP_FPA_LT: name = "fp.lt"; break; - case OP_FPA_GT: name = "fp.gt"; break; - case OP_FPA_LE: name = "fp.leq"; break; - case OP_FPA_GE: name = "fp.geq"; break; + case OP_FPA_GT: name = "fp.gt"; break; + case OP_FPA_LE: name = "fp.leq"; break; + case OP_FPA_GE: name = "fp.geq"; break; default: UNREACHABLE(); break; @@ -336,7 +338,7 @@ func_decl * fpa_decl_plugin::mk_unary_decl(decl_kind k, unsigned num_parameters, if (arity != 1) m_manager->raise_exception("invalid number of arguments to floating point operator"); if (!is_float_sort(domain[0])) - m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort"); + m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort"); symbol name; switch (k) { case OP_FPA_ABS: name = "fp.abs"; break; @@ -353,7 +355,7 @@ func_decl * fpa_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_parameters if (arity != 2) m_manager->raise_exception("invalid number of arguments to floating point operator"); if (domain[0] != domain[1] || !is_float_sort(domain[0])) - m_manager->raise_exception("sort mismatch, expected arguments of equal FloatingPoint sorts"); + m_manager->raise_exception("sort mismatch, expected arguments of equal FloatingPoint sorts"); symbol name; switch (k) { case OP_FPA_REM: name = "fp.rem"; break; @@ -377,7 +379,7 @@ func_decl * fpa_decl_plugin::mk_rm_binary_decl(decl_kind k, unsigned num_paramet if (!is_rm_sort(domain[0])) m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort"); if (domain[1] != domain[2] || !is_float_sort(domain[1])) - m_manager->raise_exception("sort mismatch, expected arguments 1 and 2 of equal FloatingPoint sorts"); + m_manager->raise_exception("sort mismatch, expected arguments 1 and 2 of equal FloatingPoint sorts"); symbol name; switch (k) { case OP_FPA_ADD: name = "fp.add"; break; @@ -398,7 +400,7 @@ func_decl * fpa_decl_plugin::mk_rm_unary_decl(decl_kind k, unsigned num_paramete if (!is_rm_sort(domain[0])) m_manager->raise_exception("sort mismatch, expected RoundingMode as first argument"); if (!is_float_sort(domain[1])) - m_manager->raise_exception("sort mismatch, expected FloatingPoint as second argument"); + m_manager->raise_exception("sort mismatch, expected FloatingPoint as second argument"); symbol name; switch (k) { case OP_FPA_SQRT: name = "fp.sqrt"; break; @@ -423,8 +425,8 @@ func_decl * fpa_decl_plugin::mk_fma(decl_kind k, unsigned num_parameters, parame } func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - if (m_bv_plugin && arity == 3 && + unsigned arity, sort * const * domain, sort * range) { + if (m_bv_plugin && arity == 3 && is_sort_of(domain[0], m_bv_fid, BV_SORT) && is_sort_of(domain[1], m_bv_fid, BV_SORT) && is_sort_of(domain[2], m_bv_fid, BV_SORT)) { @@ -445,7 +447,7 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para int ebits = parameters[0].get_int(); int sbits = parameters[1].get_int(); - + if (domain[0]->get_parameter(0).get_int() != (ebits + sbits)) m_manager->raise_exception("sort mismatch; invalid bit-vector size, expected bitvector of size (ebits+sbits)"); @@ -453,7 +455,7 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para symbol name("to_fp"); return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); } - else if (m_bv_plugin && arity == 2 && + else if (m_bv_plugin && arity == 2 && is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) && is_sort_of(domain[1], m_bv_fid, BV_SORT)) { // RoundingMode + 1 BV -> 1 FP @@ -477,16 +479,16 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para if (!parameters[0].is_int() || !parameters[1].is_int()) m_manager->raise_exception("invalid parameter type to to_fp"); int ebits = parameters[0].get_int(); - int sbits = parameters[1].get_int(); + int sbits = parameters[1].get_int(); if (!is_rm_sort(domain[0])) m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort"); if (!is_sort_of(domain[1], m_family_id, FLOATING_POINT_SORT)) m_manager->raise_exception("sort mismatch, expected second argument of FloatingPoint sort"); - + sort * fp = mk_float_sort(ebits, sbits); symbol name("to_fp"); return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); - } + } else if (arity == 3 && is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) && is_sort_of(domain[1], m_arith_fid, REAL_SORT) && @@ -494,7 +496,7 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para { // Rounding + 1 Real + 1 Int -> 1 FP if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) - m_manager->raise_exception("expecting two integer parameters to to_fp"); + m_manager->raise_exception("expecting two integer parameters to to_fp"); sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); symbol name("to_fp"); @@ -561,13 +563,13 @@ func_decl * fpa_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_paramet m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort"); if (!is_sort_of(domain[1], m_bv_fid, BV_SORT)) m_manager->raise_exception("sort mismatch, expected second argument of bit-vector sort"); - + // RoundingMode + 1 BV -> 1 FP if (num_parameters != 2) m_manager->raise_exception("invalid number of parameters to to_fp_unsigned"); if (!parameters[0].is_int() || !parameters[1].is_int()) m_manager->raise_exception("invalid parameter type to to_fp_unsigned"); - + int ebits = parameters[0].get_int(); int sbits = parameters[1].get_int(); @@ -579,16 +581,16 @@ func_decl * fpa_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_paramet func_decl * fpa_decl_plugin::mk_fp(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { if (arity != 3) - m_manager->raise_exception("invalid number of arguments to fp"); - if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) || + m_manager->raise_exception("invalid number of arguments to fp"); + if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) || (domain[0]->get_parameter(0).get_int() != 1) || !is_sort_of(domain[1], m_bv_fid, BV_SORT) || !is_sort_of(domain[2], m_bv_fid, BV_SORT)) m_manager->raise_exception("sort mismatch, expected three bit-vectors, the first one of size 1."); - + int eb = (domain[1])->get_parameter(0).get_int(); int sb = (domain[2])->get_parameter(0).get_int() + 1; - symbol name("fp"); + symbol name("fp"); sort * fp = mk_float_sort(eb, sb); return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k)); } @@ -636,12 +638,12 @@ func_decl * fpa_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, par } func_decl * fpa_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { + unsigned arity, sort * const * domain, sort * range) { if (arity != 1) m_manager->raise_exception("invalid number of arguments to fp.to_real"); if (!is_float_sort(domain[0])) m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort"); - + symbol name("fp.to_real"); return m_manager->mk_func_decl(name, 1, domain, m_real_sort, func_decl_info(m_family_id, k)); } @@ -668,7 +670,7 @@ func_decl * fpa_decl_plugin::mk_internal_rm(decl_kind k, unsigned num_parameters m_manager->raise_exception("sort mismatch, expected argument of sort bitvector, size 3"); if (!is_rm_sort(range)) m_manager->raise_exception("sort mismatch, expected range of RoundingMode sort"); - + parameter ps[] = { parameter(3) }; sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps); return m_manager->mk_func_decl(symbol("rm"), 1, &bv_srt, range, func_decl_info(m_family_id, k, num_parameters, parameters)); @@ -688,7 +690,7 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps); return m_manager->mk_func_decl(symbol("bv_wrap"), 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); } - else { + else { parameter ps[] = { parameter(3) }; sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps); return m_manager->mk_func_decl(symbol("bv_wrap"), 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); @@ -698,12 +700,12 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param func_decl * fpa_decl_plugin::mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { if (arity != 1) - m_manager->raise_exception("invalid number of arguments to internal_bv_unwrap"); + m_manager->raise_exception("invalid number of arguments to internal_bv_unwrap"); if (!is_sort_of(domain[0], m_bv_fid, BV_SORT)) m_manager->raise_exception("sort mismatch, expected argument of bitvector sort"); if (!is_float_sort(range) && !is_rm_sort(range)) m_manager->raise_exception("sort mismatch, expected range of FloatingPoint or RoundingMode sort"); - + return m_manager->mk_func_decl(symbol("bv_unwrap"), 1, domain, range, func_decl_info(m_family_id, k, num_parameters, parameters)); } @@ -716,7 +718,7 @@ func_decl * fpa_decl_plugin::mk_internal_to_ubv_unspecified( m_manager->raise_exception("invalid number of parameters to fp.to_ubv_unspecified; expecting 1"); if (!parameters[0].is_int()) m_manager->raise_exception("invalid parameters type provided to fp.to_ubv_unspecified; expecting an integer"); - + sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, parameters); return m_manager->mk_func_decl(symbol("fp.to_ubv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters)); } @@ -748,7 +750,7 @@ func_decl * fpa_decl_plugin::mk_internal_to_real_unspecified( func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { - switch (k) { + switch (k) { case OP_FPA_MINUS_INF: case OP_FPA_PLUS_INF: case OP_FPA_NAN: @@ -768,14 +770,14 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_GE: return mk_bin_rel_decl(k, num_parameters, parameters, arity, domain, range); case OP_FPA_IS_ZERO: - case OP_FPA_IS_NEGATIVE: + case OP_FPA_IS_NEGATIVE: case OP_FPA_IS_POSITIVE: case OP_FPA_IS_NAN: case OP_FPA_IS_INF: case OP_FPA_IS_NORMAL: case OP_FPA_IS_SUBNORMAL: return mk_unary_rel_decl(k, num_parameters, parameters, arity, domain, range); - case OP_FPA_ABS: + case OP_FPA_ABS: case OP_FPA_NEG: return mk_unary_decl(k, num_parameters, parameters, arity, domain, range); case OP_FPA_REM: @@ -787,7 +789,7 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_DIV: return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range); case OP_FPA_SUB: - if (arity == 1) + if (arity == 1) return mk_unary_decl(OP_FPA_NEG, num_parameters, parameters, arity, domain, range); else return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range); @@ -797,7 +799,7 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, case OP_FPA_FMA: return mk_fma(k, num_parameters, parameters, arity, domain, range); case OP_FPA_FP: - return mk_fp(k, num_parameters, parameters, arity, domain, range); + return mk_fp(k, num_parameters, parameters, arity, domain, range); case OP_FPA_TO_UBV: return mk_to_ubv(k, num_parameters, parameters, arity, domain, range); case OP_FPA_TO_SBV: @@ -817,13 +819,13 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range); case OP_FPA_INTERNAL_BVUNWRAP: return mk_internal_bv_unwrap(k, num_parameters, parameters, arity, domain, range); - + case OP_FPA_INTERNAL_MIN_I: case OP_FPA_INTERNAL_MAX_I: case OP_FPA_INTERNAL_MIN_UNSPECIFIED: case OP_FPA_INTERNAL_MAX_UNSPECIFIED: return mk_binary_decl(k, num_parameters, parameters, arity, domain, range); - + case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: return mk_internal_to_ubv_unspecified(k, num_parameters, parameters, arity, domain, range); case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: @@ -857,19 +859,19 @@ void fpa_decl_plugin::get_op_names(svector & op_names, symbol cons op_names.push_back(builtin_name("RTZ", OP_FPA_RM_TOWARD_ZERO)); op_names.push_back(builtin_name("fp.abs", OP_FPA_ABS)); - op_names.push_back(builtin_name("fp.neg", OP_FPA_NEG)); - op_names.push_back(builtin_name("fp.add", OP_FPA_ADD)); - op_names.push_back(builtin_name("fp.sub", OP_FPA_SUB)); - op_names.push_back(builtin_name("fp.mul", OP_FPA_MUL)); + op_names.push_back(builtin_name("fp.neg", OP_FPA_NEG)); + op_names.push_back(builtin_name("fp.add", OP_FPA_ADD)); + op_names.push_back(builtin_name("fp.sub", OP_FPA_SUB)); + op_names.push_back(builtin_name("fp.mul", OP_FPA_MUL)); op_names.push_back(builtin_name("fp.div", OP_FPA_DIV)); - op_names.push_back(builtin_name("fp.fma", OP_FPA_FMA)); - op_names.push_back(builtin_name("fp.sqrt", OP_FPA_SQRT)); + op_names.push_back(builtin_name("fp.fma", OP_FPA_FMA)); + op_names.push_back(builtin_name("fp.sqrt", OP_FPA_SQRT)); op_names.push_back(builtin_name("fp.rem", OP_FPA_REM)); op_names.push_back(builtin_name("fp.roundToIntegral", OP_FPA_ROUND_TO_INTEGRAL)); op_names.push_back(builtin_name("fp.min", OP_FPA_MIN)); - op_names.push_back(builtin_name("fp.max", OP_FPA_MAX)); + op_names.push_back(builtin_name("fp.max", OP_FPA_MAX)); op_names.push_back(builtin_name("fp.leq", OP_FPA_LE)); - op_names.push_back(builtin_name("fp.lt", OP_FPA_LT)); + op_names.push_back(builtin_name("fp.lt", OP_FPA_LT)); op_names.push_back(builtin_name("fp.geq", OP_FPA_GE)); op_names.push_back(builtin_name("fp.gt", OP_FPA_GT)); op_names.push_back(builtin_name("fp.eq", OP_FPA_EQ)); @@ -880,13 +882,13 @@ void fpa_decl_plugin::get_op_names(svector & op_names, symbol cons op_names.push_back(builtin_name("fp.isInfinite", OP_FPA_IS_INF)); op_names.push_back(builtin_name("fp.isNaN", OP_FPA_IS_NAN)); op_names.push_back(builtin_name("fp.isNegative", OP_FPA_IS_NEGATIVE)); - op_names.push_back(builtin_name("fp.isPositive", OP_FPA_IS_POSITIVE)); + op_names.push_back(builtin_name("fp.isPositive", OP_FPA_IS_POSITIVE)); op_names.push_back(builtin_name("fp", OP_FPA_FP)); op_names.push_back(builtin_name("fp.to_ubv", OP_FPA_TO_UBV)); op_names.push_back(builtin_name("fp.to_sbv", OP_FPA_TO_SBV)); op_names.push_back(builtin_name("fp.to_real", OP_FPA_TO_REAL)); - + op_names.push_back(builtin_name("to_fp", OP_FPA_TO_FP)); op_names.push_back(builtin_name("to_fp_unsigned", OP_FPA_TO_FP_UNSIGNED)); @@ -917,13 +919,13 @@ expr * fpa_decl_plugin::get_some_value(sort * s) { func_decl * f = mk_rm_const_decl(OP_FPA_RM_TOWARD_ZERO, 0, 0, 0, 0, s); return m_manager->mk_const(f); } - + UNREACHABLE(); return 0; } bool fpa_decl_plugin::is_value(app * e) const { - if (e->get_family_id() != m_family_id) + if (e->get_family_id() != m_family_id) return false; switch (e->get_decl_kind()) { case OP_FPA_RM_NEAREST_TIES_TO_EVEN: @@ -956,7 +958,7 @@ bool fpa_decl_plugin::is_unique_value(app* e) const { case OP_FPA_RM_TOWARD_POSITIVE: case OP_FPA_RM_TOWARD_NEGATIVE: case OP_FPA_RM_TOWARD_ZERO: - return true; + return true; case OP_FPA_PLUS_INF: /* No; +oo == fp(#b0 #b11 #b00) */ case OP_FPA_MINUS_INF: /* No; -oo == fp #b1 #b11 #b00) */ case OP_FPA_PLUS_ZERO: /* No; +zero == fp #b0 #b00 #b000) */ @@ -1029,7 +1031,7 @@ app * fpa_util::mk_nzero(unsigned ebits, unsigned sbits) { return mk_value(v); } -app * fpa_util::mk_internal_to_ubv_unspecified(unsigned width) { +app * fpa_util::mk_internal_to_ubv_unspecified(unsigned width) { parameter ps[] = { parameter(width) }; sort * range = m_bv_util.mk_sort(width); return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 1, ps, 0, 0, range); From 38865ffe0daea832693046e928a9919cf88b2ed5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Dec 2015 10:42:41 -0800 Subject: [PATCH 43/87] program the simple joints a bit more defensively per bugs reported by Sean McLaughlin Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_mk_simple_joins.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index e76b3a25b..d3c92b08c 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -11,7 +11,7 @@ Abstract: Author: - Leonardo de Moura (leonardo) 2010-05-20. + Krystof Hoder 2010-05-20. Revision History: @@ -301,13 +301,12 @@ namespace datalog { } - pair_info & get_pair(app_pair key) const { - return *m_costs.find(key); - } - void remove_rule_from_pair(app_pair key, rule * r, unsigned original_len) { - pair_info * ptr = &get_pair(key); - if (ptr->remove_rule(r, original_len)) { + SASSERT(m_costs.contains(key)); + SASSERT(m_costs.find(key)); + pair_info * ptr = 0; + if (m_costs.find(key, ptr) && ptr && + ptr->remove_rule(r, original_len)) { SASSERT(ptr->m_rules.empty()); m_costs.remove(key); dealloc(ptr); @@ -362,7 +361,12 @@ namespace datalog { void join_pair(app_pair pair_key) { app * t1 = pair_key.first; app * t2 = pair_key.second; - pair_info & inf = get_pair(pair_key); + pair_info* infp = 0; + if (!m_costs.find(pair_key, infp) || !infp) { + UNREACHABLE(); + return; + } + pair_info & inf = *infp; SASSERT(!inf.m_rules.empty()); var_idx_set & output_vars = inf.m_all_nonlocal_vars; expr_ref_vector args(m); From 6c6d1d92c4d5cc7da5963abb7bf3142a72849f5f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 31 Dec 2015 16:10:41 -0800 Subject: [PATCH 44/87] seq Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 315 +++++++++++++++++++++++++++++------------ src/smt/theory_seq.h | 12 +- 2 files changed, 231 insertions(+), 96 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 4f9273322..954baa4c6 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -245,6 +245,14 @@ bool theory_seq::branch_variable() { m_branch_variable_head = k; return true; } +#if 0 + if (!has_length(e.m_lhs)) { + enforce_length(ensure_enode(e.m_lhs)); + } + if (!has_length(e.m_rhs)) { + enforce_length(ensure_enode(e.m_rhs)); + } +#endif } return ctx.inconsistent(); } @@ -258,7 +266,6 @@ bool theory_seq::find_branch_candidate(expr* l, expr_ref_vector const& rs) { return false; } - bool all_units = true; expr_ref_vector cases(m); expr_ref v0(m), v(m); @@ -280,7 +287,6 @@ bool theory_seq::find_branch_candidate(expr* l, expr_ref_vector const& rs) { return true; } } - all_units = false; } all_units &= m_util.str.is_unit(rs[j]); v0 = (j == 0)? rs[0] : m_util.str.mk_concat(v0, rs[j]); @@ -289,14 +295,18 @@ bool theory_seq::find_branch_candidate(expr* l, expr_ref_vector const& rs) { return true; } } +#if 0 if (all_units) { literal_vector lits; for (unsigned i = 0; i < cases.size(); ++i) { lits.push_back(mk_eq(l, cases[i].get(), false)); } + lits.push_back(~mk_eq(e1, e2, false)); get_context().mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); return true; } +#endif + return false; } @@ -354,22 +364,20 @@ bool theory_seq::propagate_length_coherence(expr* e) { expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); elems.push_back(seq); tail = m_util.str.mk_concat(elems.size(), elems.c_ptr()); - // len(e) >= low => e = tail + // len(e) >= low => e = tail; literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)))); add_axiom(~low, mk_eq(e, tail, false)); assume_equality(seq, emp); if (upper_bound(e, hi)) { - expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m); - expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); + expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m); + expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); add_axiom(~mk_literal(high1), mk_literal(high2)); } - return true; } bool theory_seq::check_length_coherence() { - context& ctx = get_context(); bool coherent = true; obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); for (; it != end; ++it) { @@ -406,7 +414,8 @@ void theory_seq::propagate_is_conc(expr* e, expr* conc) { SASSERT(ctx.get_assignment(lit) == l_true); propagate_lit(0, 1, &lit, mk_eq(e, conc, false)); expr_ref e1(e, m), e2(conc, m); - m_eqs.push_back(eq(e1, e2, m_dm.mk_leaf(assumption(lit)))); + new_eq_eh(m_dm.mk_leaf(assumption(lit)), ctx.get_enode(e1), ctx.get_enode(e2)); + } expr_ref theory_seq::mk_nth(expr* s, expr* idx) { @@ -415,6 +424,13 @@ expr_ref theory_seq::mk_nth(expr* s, expr* idx) { return mk_skolem(m_nth, s, idx, 0, char_sort); } +expr_ref theory_seq::mk_last(expr* s) { + sort* char_sort = 0; + VERIFY(m_util.is_seq(m.get_sort(s), char_sort)); + return mk_skolem(m_seq_last, s, 0, 0, char_sort); +} + + void theory_seq::mk_decompose(expr* e, expr_ref& head, expr_ref& tail) { expr* e1, *e2; zstring s; @@ -511,6 +527,9 @@ void theory_seq::set_conflict(dependency* dep, literal_vector const& _lits) { } void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) { + if (n1->get_root() == n2->get_root()) { + return; + } context& ctx = get_context(); literal_vector lits; enode_pair_vector eqs; @@ -524,6 +543,19 @@ void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) { ext_theory_eq_propagation_justification( get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), n1, n2)); ctx.assign_eq(n1, n2, eq_justification(js)); + + enforce_length_coherence(n1, n2); +} + +void theory_seq::enforce_length_coherence(enode* n1, enode* n2) { + expr* o1 = n1->get_owner(); + expr* o2 = n2->get_owner(); + if (has_length(o1) && !has_length(o2)) { + enforce_length(n2); + } + else if (has_length(o2) && !has_length(o1)) { + enforce_length(n1); + } } @@ -628,12 +660,14 @@ bool theory_seq::add_solution(expr* l, expr* r, dependency* deps) { context& ctx = get_context(); TRACE("seq", tout << mk_pp(l, m) << " ==> " << mk_pp(r, m) << "\n";); m_rep.update(l, r, deps); - if (ctx.e_internalized(l) && ctx.e_internalized(r) && ctx.get_enode(l)->get_root() != ctx.get_enode(r)->get_root()) { - propagate_eq(deps, ctx.get_enode(l), ctx.get_enode(r)); - return true; + enode* n1 = ensure_enode(l); + enode* n2 = ensure_enode(r); + if (n1->get_root() == n2->get_root()) { + return false; } else { - return false; + propagate_eq(deps, n1, n2); + return true; } } @@ -900,16 +934,20 @@ void theory_seq::display_deps(std::ostream& out, dependency* dep) const { enode_pair_vector eqs; linearize(dep, eqs, lits); for (unsigned i = 0; i < eqs.size(); ++i) { - out << " " << mk_pp(eqs[i].first->get_owner(), m) << " = " << mk_pp(eqs[i].second->get_owner(), m); + out << "\n " << mk_pp(eqs[i].first->get_owner(), m) << " = " << mk_pp(eqs[i].second->get_owner(), m); + } + for (unsigned i = 0; i < lits.size(); ++i) { + literal lit = lits[i]; + get_context().display_literals_verbose(out << "\n ", 1, &lit); } out << "\n"; - get_context().display_literals_verbose(tout, lits.size(), lits.c_ptr()); + } void theory_seq::collect_statistics(::statistics & st) const { st.update("seq num splits", m_stats.m_num_splits); st.update("seq num reductions", m_stats.m_num_reductions); - st.update("e", m_stats.m_propagate_automata); + st.update("seq unfold def", m_stats.m_propagate_automata); st.update("seq length coherence", m_stats.m_check_length_coherence); st.update("seq branch", m_stats.m_branch_variable); st.update("seq solve !=", m_stats.m_solve_nqs); @@ -1156,7 +1194,7 @@ void theory_seq::deque_axiom(expr* n) { if (m_util.str.is_length(n)) { add_length_axiom(n); } - else if (m_util.str.is_empty(n) && !has_length(n)) { + else if (m_util.str.is_empty(n) && !has_length(n) && !m_length.empty()) { enforce_length(get_context().get_enode(n)); } else if (m_util.str.is_index(n)) { @@ -1181,20 +1219,16 @@ void theory_seq::deque_axiom(expr* n) { encode that s is not a proper prefix of xs1 where s1 is all of s, except the last element. - lit or s = "" or s = s1*c - lit or s = "" or len(c) = 1 + lit or s = "" or s = s1*(unit c) lit or s = "" or !prefix(s, x*s1) */ void theory_seq::tightest_prefix(expr* s, expr* x, literal lit1, literal lit2) { expr_ref s1 = mk_skolem(m_seq_first, s); - expr_ref c = mk_skolem(m_seq_last, s); - expr_ref s1c(m_util.str.mk_concat(s1, c), m); - expr_ref lc(m_util.str.mk_length(c), m); - expr_ref one(m_autil.mk_int(1), m); + expr_ref c = mk_last(s); + expr_ref s1c(m_util.str.mk_concat(s1, m_util.str.mk_unit(c)), m); literal s_eq_emp = mk_eq_empty(s); add_axiom(lit1, lit2, s_eq_emp, mk_eq(s, s1c, false)); - add_axiom(lit1, lit2, s_eq_emp, mk_eq(lc, one, false)); - add_axiom(lit1, lit2, s_eq_emp, ~mk_literal(m_util.str.mk_contains(s, m_util.str.mk_concat(x, s1)))); + add_axiom(lit1, lit2, s_eq_emp, ~mk_literal(m_util.str.mk_prefix(s, m_util.str.mk_concat(x, s1)))); } /* @@ -1414,9 +1448,10 @@ enode* theory_seq::ensure_enode(expr* e) { context& ctx = get_context(); if (!ctx.e_internalized(e)) { ctx.internalize(e, false); - ctx.mark_as_relevant(ctx.get_enode(e)); } - return ctx.get_enode(e); + enode* n = ctx.get_enode(e); + ctx.mark_as_relevant(n); + return n; } static theory_mi_arith* get_th_arith(context& ctx, theory_id afid, expr* e) { @@ -1555,19 +1590,56 @@ void theory_seq::add_at_axiom(expr* e) { } /** - step(s, idx, re, i, j, t) -> nth(s, idx) == t + step(s, idx, re, i, j, t) -> nth(s, idx) == t & len(s) > idx */ -void theory_seq::propagate_step(bool_var v, expr* step) { +void theory_seq::propagate_step(literal lit, expr* step) { context& ctx = get_context(); expr* re, *t, *s, *idx, *i, *j; VERIFY(is_step(step, s, idx, re, i, j, t)); expr_ref nth = mk_nth(s, idx); - propagate_eq(v, t, nth); - literal lit(v); + propagate_eq(lit, t, nth); SASSERT(ctx.get_assignment(lit) == l_true); - propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); + propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx))); + ensure_nth(lit, s, idx); } +/* + lit => s = (nth s 0) ++ (nth s 1) ++ ... ++ (nth s idx) ++ (tail s idx) +*/ +void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) { + context& ctx = get_context(); + rational r; + VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); + unsigned _idx = r.get_unsigned(); + dependency* dep = 0; + expr_ref s1 = canonize(s, dep); + ptr_vector es; + expr* e1; + expr_ref nth = mk_nth(s, idx); + expr_ref head(m), tail(m), conc(m); + expr_ref_vector elems(m); + get_concat(s1, es); + unsigned i = 0; + for (; i < _idx && i < es.size() && m_util.str.is_unit(es[i]); ++i) {}; + if (i == _idx && i < es.size() && m_util.str.is_unit(es[i], e1)) { + dep = m_dm.mk_join(dep, m_dm.mk_leaf(assumption(lit))); + propagate_eq(dep, ensure_enode(nth), ensure_enode(e1)); + return; + } + // TBD could tune this aggregate quadratic overhead + expr* s2 = s; + for (unsigned j = 0; j <= _idx; ++j) { + mk_decompose(s2, head, tail); + elems.push_back(head); + s2 = tail; + } + elems.push_back(s2); + conc = m_util.str.mk_concat(elems.size(), elems.c_ptr()); + propagate_eq(lit, s, conc, true); + + // TBD: examine other places for enforcing constraints on tail + add_axiom(~lit, mk_eq(m_util.str.mk_length(s), m_util.str.mk_length(conc), false)); +} literal theory_seq::mk_literal(expr* _e) { expr_ref e(_e, m); @@ -1617,7 +1689,7 @@ bool theory_seq::is_skolem(symbol const& s, expr* e) const { } -void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2, bool add_to_eqs) { +void theory_seq::propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs) { context& ctx = get_context(); enode* n1 = ensure_enode(e1); @@ -1628,14 +1700,13 @@ void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2, bool add_to_eqs) { ctx.mark_as_relevant(n1); ctx.mark_as_relevant(n2); if (add_to_eqs) { - SASSERT(l_true == ctx.get_assignment(v)); - expr_ref l(e1, m), r(e2, m); - dependency* deps = m_dm.mk_leaf(assumption(literal(v))); - m_eqs.push_back(eq(l, r, deps)); + SASSERT(l_true == ctx.get_assignment(lit)); + dependency* deps = m_dm.mk_leaf(assumption(lit)); + new_eq_eh(deps, n1, n2); + } - literal lit(v); TRACE("seq", - tout << mk_pp(ctx.bool_var2expr(v), m) << " => " + tout << mk_pp(ctx.bool_var2expr(lit.var()), m) << " => " << mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";); justification* js = ctx.mk_justification( @@ -1651,16 +1722,17 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { expr* e = ctx.bool_var2expr(v); expr* e1, *e2; expr_ref f(m); + literal lit(v, !is_true); if (m_util.str.is_prefix(e, e1, e2)) { if (is_true) { f = mk_skolem(m_prefix, e1, e2); f = m_util.str.mk_concat(e1, f); - propagate_eq(v, f, e2, true); + propagate_eq(lit, f, e2, true); } else { // !prefix(e1,e2) => e1 != "" - propagate_non_empty(literal(v, true), e1); + propagate_non_empty(lit, e1); add_atom(e); } } @@ -1668,10 +1740,18 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { if (is_true) { f = mk_skolem(m_suffix, e1, e2); f = m_util.str.mk_concat(f, e1); - propagate_eq(v, f, e2, true); + propagate_eq(lit, f, e2, true); } else { - propagate_non_empty(literal(v, true), e1); + // lit => e1 != empty + propagate_non_empty(lit, e1); + + // lit => e1 = first ++ (unit last) + expr_ref f1 = mk_skolem(m_seq_first, e1); + expr_ref f2 = mk_last(e1); + f = m_util.str.mk_concat(f1, m_util.str.mk_unit(f2)); + propagate_eq(lit, e1, f, true); + add_atom(e); } } @@ -1680,30 +1760,29 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { expr_ref f1 = mk_skolem(m_contains_left, e1, e2); expr_ref f2 = mk_skolem(m_contains_right, e1, e2); f = m_util.str.mk_concat(f1, e2, f2); - propagate_eq(v, f, e1, true); + propagate_eq(lit, f, e1, true); } else if (!canonizes(false, e)) { - literal lit(v, true); - propagate_non_empty(literal(v, true), e2); + propagate_non_empty(lit, e2); propagate_lit(0, 1, &lit, ~mk_literal(m_util.str.mk_prefix(e2, e1))); add_atom(e); } } else if (is_accept(e)) { if (is_true) { - propagate_acc_rej_length(v, e); + propagate_acc_rej_length(lit, e); add_atom(e); } } else if (is_reject(e)) { if (is_true) { - propagate_acc_rej_length(v, e); + propagate_acc_rej_length(lit, e); add_atom(e); } } else if (is_step(e)) { if (is_true) { - propagate_step(v, e); + propagate_step(lit, e); add_atom(e); } } @@ -1723,21 +1802,20 @@ void theory_seq::add_atom(expr* e) { void theory_seq::new_eq_eh(theory_var v1, theory_var v2) { enode* n1 = get_enode(v1); enode* n2 = get_enode(v2); + dependency* deps = m_dm.mk_leaf(assumption(n1, n2)); + new_eq_eh(deps, n1, n2); +} + +void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) { if (n1 != n2 && m_util.is_seq(n1->get_owner())) { expr_ref o1(n1->get_owner(), m); expr_ref o2(n2->get_owner(), m); TRACE("seq", tout << o1 << " = " << o2 << "\n";); - dependency* deps = m_dm.mk_leaf(assumption(n1, n2)); bool propagated = false; if (!simplify_eq(o1, o2, deps, propagated)) { m_eqs.push_back(eq(o1, o2, deps)); } - if (has_length(o1) && !has_length(o2)) { - enforce_length(n2); - } - else if (has_length(o2) && !has_length(o1)) { - enforce_length(n1); - } + enforce_length_coherence(n1, n2); } } @@ -1872,21 +1950,32 @@ expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned } /* - acc(s, idx, re, i) -> len(s) >= idx - rej(s, idx, re, i) => len(s) >= idx + acc(s, idx, re, i) -> len(s) >= idx if i is final + rej(s, idx, re, i) -> len(s) >= idx if i is non-final + + acc(s, idx, re, i) -> len(s) > idx if i is non-final + rej(s, idx, re, i) -> len(s) > idx if i is final */ -void theory_seq::propagate_acc_rej_length(bool_var v, expr* e) { +void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { context& ctx = get_context(); expr *s, * idx, *re; unsigned src; eautomaton* aut = 0; - VERIFY(is_accept(e, s, idx, re, src, aut) || - is_reject(e, s, idx, re, src, aut)); + bool is_acc; + is_acc = is_accept(e, s, idx, re, src, aut); + if (!is_acc) { + VERIFY(is_reject(e, s, idx, re, src, aut)); + } if (m_util.str.is_length(idx)) return; SASSERT(m_autil.is_numeral(idx)); - literal lit(v); SASSERT(ctx.get_assignment(lit) == l_true); - propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); + bool is_final = aut->is_final_state(src); + if (is_final == is_acc) { + propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); + } + else { + propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx))); + } } /** @@ -1945,30 +2034,70 @@ void theory_seq::add_step2accept(expr* step) { /* - rej(s, idx, re, i) & nth(s,idx) = t & idx < len(s) => rej(s, idx + 1 re, j) + rej(s, idx, re, i) & nth(s, idx) = t & idx < len(s) => rej(s, idx + 1, re, j) + + len(s) > idx -> s = (nth 0 s) ++ .. ++ (nth idx s) ++ (tail idx s) + +Recall we also have: + rej(s, idx, re, i) -> len(s) >= idx if i is non-final + rej(s, idx, re, i) -> len(s) > idx if i is final + */ -void theory_seq::add_reject2reject(expr* rej) { +bool theory_seq::add_reject2reject(expr* rej) { context& ctx = get_context(); SASSERT(ctx.get_assignment(rej) == l_true); - expr* e, *idx, *re; + expr* s, *idx, *re; unsigned src; rational r; eautomaton* aut = 0; - VERIFY(is_reject(rej, e, idx, re, src, aut)); - if (!aut || m_util.str.is_length(idx)) return; + VERIFY(is_reject(rej, s, idx, re, src, aut)); + if (!aut || m_util.str.is_length(idx)) return false; VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); expr_ref idx1(m_autil.mk_int(r.get_unsigned() + 1), m); eautomaton::moves mvs; aut->get_moves_from(src, mvs); literal rej1 = ctx.get_literal(rej); - expr_ref len(m_util.str.mk_length(e), m); - add_axiom(~rej1, mk_literal(m_autil.mk_ge(len, idx))); + expr_ref len(m_util.str.mk_length(s), m); + literal len_le_idx = mk_literal(m_autil.mk_le(len, idx)); + switch (ctx.get_assignment(len_le_idx)) { + case l_true: + return false; + case l_undef: + ctx.force_phase(len_le_idx); + return true; + default: + break; + } + expr_ref nth = mk_nth(s, idx); + ensure_nth(~len_le_idx, s, idx); + literal_vector eqs; + bool has_undef = false; for (unsigned i = 0; i < mvs.size(); ++i) { eautomaton::move const& mv = mvs[i]; - expr_ref nth = mk_nth(e, idx); - literal rej2 = mk_reject(e, idx1, re, m_autil.mk_int(mv.dst())); - add_axiom(~rej1, ~mk_eq(nth, mv.t(), false), ~mk_literal(m_autil.mk_ge(len, idx)), rej2); + literal eq = mk_eq(nth, mv.t(), false); + switch (ctx.get_assignment(eq)) { + case l_false: + case l_true: + break; + case l_undef: + ctx.force_phase(~eq); + has_undef = true; + break; + } + eqs.push_back(eq); } + if (has_undef) { + return true; + } + for (unsigned i = 0; i < mvs.size(); ++i) { + eautomaton::move const& mv = mvs[i]; + literal eq = eqs[i]; + if (ctx.get_assignment(eq) == l_true) { + literal rej2 = mk_reject(s, idx1, re, m_autil.mk_int(mv.dst())); + add_axiom(~rej1, ~eq, len_le_idx, rej2); + } + } + return false; } /* @@ -2015,7 +2144,7 @@ bool theory_seq::add_prefix2prefix(expr* e) { } /* - !suffix(e1, e2) -> e2 = emp \/ nth(e1,len(e1)-1) != nth(e2,len(e2)-1) \/ !suffix(first(e1), first(e2)) + !suffix(e1, e2) -> e2 = emp \/ last(e1) != last(e2) \/ !suffix(first(e1), first(e2)) */ bool theory_seq::add_suffix2suffix(expr* e) { context& ctx = get_context(); @@ -2032,33 +2161,35 @@ bool theory_seq::add_suffix2suffix(expr* e) { case l_true: return false; // done case l_undef: + ctx.force_phase(mk_eq(e2, emp, false)); return true; // retry case l_false: break; } - - NOT_IMPLEMENTED_YET(); - // TBD: - expr_ref head1(m), tail1(m), head2(m), tail2(m); - mk_decompose(e2, head2, tail2); + expr_ref first2 = mk_skolem(m_seq_first, e2); + expr_ref last2 = mk_last(e2); + expr_ref first1 = mk_skolem(m_seq_first, e1); + expr_ref last1 = mk_last(e1); + expr_ref conc(m_util.str.mk_concat(first2, m_util.str.mk_unit(last2)), m); + propagate_eq(~mk_eq(e2, emp, false), e2, conc); - literal lit = mk_eq(head1, head2, false); - switch (ctx.get_assignment(lit)) { - case l_true: { - literal_vector lits; - lits.push_back(~ctx.get_literal(e)); - lits.push_back(~mk_eq(e2, emp, false)); - lits.push_back(lit); - propagate_lit(0, lits.size(), lits.c_ptr(), mk_literal(m_util.str.mk_suffix(tail1, tail2))); - return false; - } + literal last_eq = mk_eq(last1, last2, false); + switch (ctx.get_assignment(last_eq)) { case l_false: - return false; + return false; // done case l_undef: - ctx.force_phase(~lit); + ctx.force_phase(~last_eq); return true; + case l_true: + break; } - return true; + + literal_vector lits; + lits.push_back(~ctx.get_literal(e)); + lits.push_back(~mk_eq(e2, emp, false)); + lits.push_back(last_eq); + propagate_lit(0, lits.size(), lits.c_ptr(), ~mk_literal(m_util.str.mk_suffix(first1, first2))); + return false; } bool theory_seq::canonizes(bool sign, expr* e) { @@ -2123,7 +2254,7 @@ bool theory_seq::propagate_automata() { add_accept2step(e); } else if (is_reject(e)) { - add_reject2reject(e); + reQ = add_reject2reject(e); } else if (is_step(e)) { add_step2accept(e); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 2de6a36d0..92c2ebc05 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -335,7 +335,7 @@ namespace smt { void propagate_lit(dependency* dep, literal lit) { propagate_lit(dep, 0, 0, lit); } void propagate_lit(dependency* dep, unsigned n, literal const* lits, literal lit); void propagate_eq(dependency* dep, enode* n1, enode* n2); - void propagate_eq(bool_var v, expr* e1, expr* e2, bool add_to_eqs = false); + void propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs = false); void set_conflict(dependency* dep, literal_vector const& lits = literal_vector()); bool find_branch_candidate(expr* l, expr_ref_vector const& rs); @@ -347,6 +347,7 @@ namespace smt { bool add_solution(expr* l, expr* r, dependency* dep); bool is_nth(expr* a) const; expr_ref mk_nth(expr* s, expr* idx); + expr_ref mk_last(expr* e); expr_ref canonize(expr* e, dependency*& eqs); expr_ref expand(expr* e, dependency*& eqs); void add_dependency(dependency*& dep, enode* a, enode* b); @@ -365,6 +366,7 @@ namespace smt { bool has_length(expr *e) const { return m_length.contains(e); } void add_length(expr* e); void enforce_length(enode* n); + void enforce_length_coherence(enode* n1, enode* n2); void add_elim_string_axiom(expr* n); void add_at_axiom(expr* n); @@ -406,19 +408,21 @@ namespace smt { expr_ref mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned j, expr* t); bool is_step(expr* e, expr*& s, expr*& tail, expr*& re, expr*& i, expr*& j, expr*& t) const; bool is_step(expr* e) const; - void propagate_step(bool_var v, expr* n); - void add_reject2reject(expr* rej); + void propagate_step(literal lit, expr* n); + bool add_reject2reject(expr* rej); void add_accept2step(expr* acc); void add_step2accept(expr* step); bool add_prefix2prefix(expr* e); bool add_suffix2suffix(expr* e); bool add_contains2contains(expr* e); + void ensure_nth(literal lit, expr* s, expr* idx); bool canonizes(bool sign, expr* e); void propagate_non_empty(literal lit, expr* s); void propagate_is_conc(expr* e, expr* conc); - void propagate_acc_rej_length(bool_var v, expr* acc_rej); + void propagate_acc_rej_length(literal lit, expr* acc_rej); bool propagate_automata(); void add_atom(expr* e); + void new_eq_eh(dependency* dep, enode* n1, enode* n2); // diagnostics void display_equations(std::ostream& out) const; From d6330e157d33b6aa23a5de73c589068a0b832f13 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 1 Jan 2016 16:42:01 +0000 Subject: [PATCH 45/87] Refactored Python API installation build. --- scripts/mk_util.py | 102 ++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 52 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 95a97ea83..8f808bd45 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -643,7 +643,7 @@ def display_help(exit_code): def parse_options(): global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM global DOTNET_ENABLED, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH - global LINUX_X64, SLOW_OPTIMIZE, USE_OMP, PYTHON_INSTALL_ENABLED + global LINUX_X64, SLOW_OPTIMIZE, USE_OMP try: options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:df:sxhmcvtnp:gj', @@ -711,29 +711,7 @@ def parse_options(): else: print("ERROR: Invalid command line option '%s'" % opt) display_help(1) - # Handle the Python package directory - if IS_WINDOWS: - # Installing under Windows doesn't make sense as the install prefix is used - # but that doesn't make sense under Windows - # CMW: It makes perfectly good sense; the prefix is Python's sys.prefix, - # i.e., something along the lines of C:\Python\... At the moment we are not - # sure whether we would want to install libz3.dll into that directory though. - PYTHON_INSTALL_ENABLED = False - else: - if not PYTHON_PACKAGE_DIR.startswith(PREFIX): - print(("Warning: The detected Python package directory (%s)" - " does not live under the installation prefix (%s)" - ". This would lead to a broken Python installation. " - "Use --pypkgdir= to change the Python package directory") % - (PYTHON_PACKAGE_DIR, PREFIX)) - if IS_OSX and PYTHON_PACKAGE_DIR.startswith('/Library/'): - print("Using hack to install Python bindings, this might lead to a broken system") - PYTHON_INSTALL_ENABLED = True - else: - print("Disabling install of Python bindings") - PYTHON_INSTALL_ENABLED = False - else: - PYTHON_INSTALL_ENABLED = True + # Return a list containing a file names included using '#include' in # the given C/C++ file named fname. @@ -1039,6 +1017,11 @@ class Component: def mk_unix_dist(self, build_path, dist_path): return + # Used to print warnings or errors after mk_make.py is done, so that they + # are not quite as easy to miss. + def final_info(self): + pass + class LibComponent(Component): def __init__(self, name, path, deps, includes2install): Component.__init__(self, name, path, deps) @@ -1353,21 +1336,38 @@ class PythonInstallComponent(Component): self.pythonPkgDir = None self.in_prefix_install = True self.libz3Component = libz3Component - if not PYTHON_INSTALL_ENABLED: + + if IS_WINDOWS: + # Installing under Windows doesn't make sense as the install prefix is used + # but that doesn't make sense under Windows + # CMW: It makes perfectly good sense; the prefix is Python's sys.prefix, + # i.e., something along the lines of C:\Python\... At the moment we are not + # sure whether we would want to install libz3.dll into that directory though. + PYTHON_INSTALL_ENABLED = False return + else: + PYTHON_INSTALL_ENABLED = True if IS_WINDOWS or IS_OSX: # Use full path that is possibly outside of install prefix - self.pythonPkgDir = PYTHON_PACKAGE_DIR self.in_prefix_install = PYTHON_PACKAGE_DIR.startswith(PREFIX) - assert os.path.isabs(self.pythonPkgDir) + self.pythonPkgDir = strip_path_prefix(PYTHON_PACKAGE_DIR, PREFIX) else: # Use path inside the prefix (should be the normal case on Linux) # CMW: Also normal on *BSD? assert PYTHON_PACKAGE_DIR.startswith(PREFIX) self.pythonPkgDir = strip_path_prefix(PYTHON_PACKAGE_DIR, PREFIX) + self.in_prefix_install = True + + if self.in_prefix_install: assert not os.path.isabs(self.pythonPkgDir) - assert self.in_prefix_install + + def final_info(self): + if not PYTHON_PACKAGE_DIR.startswith(PREFIX): + print("Warning: The detected Python package directory (%s) is not " + "in the installation prefix (%s). This can lead to a broken " + "Python API installation. Use --pypkgdir= to change the " + "Python package directory." % (PYTHON_PACKAGE_DIR, PREFIX)) def main_component(self): return False @@ -2339,12 +2339,12 @@ def mk_makefile(): out.write(' %s' % c.name) out.write('\n\t@echo Z3 was successfully built.\n') out.write("\t@echo \"Z3Py scripts can already be executed in the \'%s\' directory.\"\n" % BUILD_DIR) - out.write("\t@echo \"Z3Py scripts stored in arbitrary directories can be also executed if \'%s\' directory is added to the PYTHONPATH environment variable.\"\n" % BUILD_DIR) + out.write("\t@echo \"Z3Py scripts stored in arbitrary directories can be executed if the \'%s\' directory is added to the PYTHONPATH environment variable.\"\n" % BUILD_DIR) if not IS_WINDOWS: out.write("\t@echo Use the following command to install Z3 at prefix $(PREFIX).\n") out.write('\t@echo " sudo make install"\n\n') - out.write("\t@echo If you are doing a staged install you can use DESTDIR.\n") - out.write('\t@echo " make DESTDIR=/some/temp/directory install"\n') + # out.write("\t@echo If you are doing a staged install you can use DESTDIR.\n") + # out.write('\t@echo " make DESTDIR=/some/temp/directory install"\n') # Generate :examples rule out.write('examples:') for c in get_components(): @@ -2358,6 +2358,8 @@ def mk_makefile(): if not IS_WINDOWS: mk_install(out) mk_uninstall(out) + for c in get_components(): + c.final_info() out.close() # Finalize if VERBOSE: @@ -3473,22 +3475,17 @@ class MakeRuleCmd(object): @classmethod def _install_root(cls, path, in_prefix, out, is_install=True): - if in_prefix: - assert not os.path.isabs(path) - install_root = cls.install_root() - else: - # This hack only exists for the Python bindings on OSX - # which are sometimes not installed inside the prefix. - # In all other cases installing outside the prefix is - # misleading and dangerous! - assert IS_OSX - assert os.path.isabs(path) + if not in_prefix: + # The Python bindings on OSX are sometimes not installed inside the prefix. install_root = "$(DESTDIR)" action_string = 'install' if is_install else 'uninstall' cls.write_cmd(out, 'echo "WARNING: {}ing files/directories ({}) that are not in the install prefix ($(PREFIX))."'.format( - action_string, path)) - print("WARNING: Generating makefile rule that {}s {} '{}' which is outside the installation prefix '{}'.".format( - action_string, 'to' if is_install else 'from', path, PREFIX)) + action_string, path)) + #print("WARNING: Generating makefile rule that {}s {} '{}' which is outside the installation prefix '{}'.".format( + # action_string, 'to' if is_install else 'from', path, PREFIX)) + else: + assert not os.path.isabs(path) + install_root = cls.install_root() return install_root @classmethod @@ -3608,14 +3605,15 @@ class MakeRuleCmd(object): out.write("\t@{}\n".format(line)) def strip_path_prefix(path, prefix): - assert path.startswith(prefix) - stripped_path = path[len(prefix):] - stripped_path.replace('//','/') - if stripped_path[0] == '/': - stripped_path = stripped_path[1:] - - assert not os.path.isabs(stripped_path) - return stripped_path + if path.startswith(prefix): + stripped_path = path[len(prefix):] + stripped_path.replace('//','/') + if stripped_path[0] == '/': + stripped_path = stripped_path[1:] + assert not os.path.isabs(stripped_path) + return stripped_path + else: + return path def configure_file(template_file_path, output_file_path, substitutions): """ From 876fd1f7bac46ff95ad0a3c059cad425579a76df Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Jan 2016 09:00:21 -0800 Subject: [PATCH 46/87] seq Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 45 ++++++++++---- src/ast/seq_decl_plugin.cpp | 2 +- src/muz/rel/dl_mk_simple_joins.cpp | 2 + src/smt/theory_seq.cpp | 99 +++++++++++++++++++++++------- src/smt/theory_seq.h | 29 ++++++++- 5 files changed, 140 insertions(+), 37 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 00b4371d9..2db2391d9 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -520,20 +520,10 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { result = m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), a); return BR_REWRITE3; } - // TBD concatenation is right-associative - expr* a1, *a2, *b1, *b2; - if (m_util.str.is_concat(a, a1, a2) && - m_util.str.is_concat(b, b1, b2) && a2 == b2) { - result = m_util.str.mk_suffix(a1, b1); - return BR_REWRITE1; - } - if (m_util.str.is_concat(b, b1, b2) && b2 == a) { - result = m().mk_true(); - return BR_DONE; - } + bool isc1 = false; bool isc2 = false; - + expr* a1, *a2, *b1, *b2; if (m_util.str.is_concat(a, a1, a2) && m_util.str.is_string(a2, s1)) { isc1 = true; } @@ -593,6 +583,37 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) { } } } + expr_ref_vector as(m()), bs(m()); + m_util.str.get_concat(a, as); + m_util.str.get_concat(b, bs); + bool change = false; + while (as.size() > 0 && bs.size() > 0 && as.back() == bs.back()) { + as.pop_back(); + bs.pop_back(); + change = true; + } + if (as.size() > 0 && bs.size() > 0 && m().is_value(as.back()) && m().is_value(bs.back())) { + result = m().mk_false(); + return BR_DONE; + } + if (change) { + // suffix("", bs) <- true + if (as.empty()) { + result = m().mk_true(); + return BR_DONE; + } + // suffix(as, "") iff as = "" + if (bs.empty()) { + for (unsigned j = 0; j < as.size(); ++j) { + bs.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j].get())); + } + result = mk_and(bs); + return BR_REWRITE3; + } + result = m_util.str.mk_suffix(m_util.str.mk_concat(as.size(), as.c_ptr()), + m_util.str.mk_concat(bs.size(), bs.c_ptr())); + return BR_DONE; + } return BR_FAILED; } diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 70ee4298b..c3f882e8d 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -25,7 +25,6 @@ Revision History: zstring::zstring(encoding enc): m_encoding(enc) {} zstring::zstring(char const* s, encoding enc): m_encoding(enc) { - // TBD: epply decoding while (*s) { m_buffer.push_back(*s); ++s; @@ -81,6 +80,7 @@ zstring zstring::replace(zstring const& src, zstring const& dst) const { return result; } +// TBD: SMT-LIB 2.5 strings don't have escape characters other than " static char* esc_table[32] = { "\\0", "^A", "^B", "^C", "^D", "^E", "^F", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V","^W","^X","^Y","^Z","\\e","^\\","^]","^^","^_"}; diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index e76b3a25b..3f5c2b78f 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -273,6 +273,7 @@ namespace datalog { */ void register_pair(app * t1, app * t2, rule * r, const var_idx_set & non_local_vars) { SASSERT(t1!=t2); + std::cout << "insert: " << mk_pp(t1, m) << " - " << mk_pp(t2, m) << "\n"; cost_map::entry * e = m_costs.insert_if_not_there2(get_key(t1, t2), 0); pair_info * & ptr_inf = e->get_data().m_value; if (ptr_inf==0) { @@ -306,6 +307,7 @@ namespace datalog { } void remove_rule_from_pair(app_pair key, rule * r, unsigned original_len) { + std::cout << "remove: " << mk_pp(key.first, m) << " - " << mk_pp(key.second, m) << "\n"; pair_info * ptr = &get_pair(key); if (ptr->remove_rule(r, original_len)) { SASSERT(ptr->m_rules.empty()); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 954baa4c6..69ae25aba 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -150,6 +150,7 @@ void theory_seq::exclusion_table::display(std::ostream& out) const { } } + theory_seq::theory_seq(ast_manager& m): theory(m.mk_family_id("seq")), m(m), @@ -372,6 +373,7 @@ bool theory_seq::propagate_length_coherence(expr* e) { expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m); expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); add_axiom(~mk_literal(high1), mk_literal(high2)); + m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e))); } return true; @@ -1048,12 +1050,18 @@ app* theory_seq::mk_value(app* e) { rational val; unsigned sz; if (bv.is_numeral(result, val, sz) && sz == zstring().num_bits()) { - svector val_as_bits; - for (unsigned i = 0; i < sz; ++i) { - val_as_bits.push_back(!val.is_even()); - val = div(val, rational(2)); + unsigned v = val.get_unsigned(); + if ((0 <= v && v < 32) || v == 127) { + result = m_util.str.mk_unit(result); + } + else { + svector val_as_bits; + for (unsigned i = 0; i < sz; ++i) { + val_as_bits.push_back(1 == v % 2); + v = v / 2; + } + result = m_util.str.mk_string(zstring(sz, val_as_bits.c_ptr())); } - result = m_util.str.mk_string(zstring(sz, val_as_bits.c_ptr())); } else { result = m_util.str.mk_unit(result); @@ -1113,7 +1121,7 @@ theory_var theory_seq::mk_var(enode* n) { } bool theory_seq::can_propagate() { - return m_axioms_head < m_axioms.size(); + return m_axioms_head < m_axioms.size() || !m_replay.empty(); } expr_ref theory_seq::canonize(expr* e, dependency*& eqs) { @@ -1177,6 +1185,11 @@ void theory_seq::propagate() { deque_axiom(e); ++m_axioms_head; } + while (!m_replay.empty() && !ctx.inconsistent()) { + (*m_replay[m_replay.size()-1])(*this); + TRACE("seq", tout << "replay: " << ctx.get_scope_level() << "\n";); + m_replay.pop_back(); + } } void theory_seq::enque_axiom(expr* e) { @@ -1733,7 +1746,9 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { else { // !prefix(e1,e2) => e1 != "" propagate_non_empty(lit, e1); - add_atom(e); + if (add_prefix2prefix(e)) { + add_atom(e); + } } } else if (m_util.str.is_suffix(e, e1, e2)) { @@ -1752,7 +1767,9 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { f = m_util.str.mk_concat(f1, m_util.str.mk_unit(f2)); propagate_eq(lit, e1, f, true); - add_atom(e); + if (add_suffix2suffix(e)) { + add_atom(e); + } } } else if (m_util.str.is_contains(e, e1, e2)) { @@ -1765,13 +1782,17 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { else if (!canonizes(false, e)) { propagate_non_empty(lit, e2); propagate_lit(0, 1, &lit, ~mk_literal(m_util.str.mk_prefix(e2, e1))); - add_atom(e); + if (add_contains2contains(e)) { + add_atom(e); + } } } else if (is_accept(e)) { if (is_true) { propagate_acc_rej_length(lit, e); - add_atom(e); + if (add_accept2step(e)) { + add_atom(e); + } } } else if (is_reject(e)) { @@ -1783,7 +1804,9 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { else if (is_step(e)) { if (is_true) { propagate_step(lit, e); - add_atom(e); + if (add_step2accept(e)) { + add_atom(e); + } } } else if (m_util.str.is_in_re(e)) { @@ -1979,10 +2002,10 @@ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { } /** - acc(s, idx, re, i) -> \/ step(s, idx, re, i, j, t) if i is non-final + acc(s, idx, re, i) -> \/ step(s, idx, re, i, j, t) if i is non-final acc(s, idx, re, i) -> len(s) <= idx \/ step(s, idx, re, i, j, t) if i is final */ -void theory_seq::add_accept2step(expr* acc) { +bool theory_seq::add_accept2step(expr* acc) { context& ctx = get_context(); SASSERT(ctx.get_assignment(acc) == l_true); expr *e, * idx, *re; @@ -1990,7 +2013,9 @@ void theory_seq::add_accept2step(expr* acc) { unsigned src; eautomaton* aut = 0; VERIFY(is_accept(acc, e, idx, re, src, aut)); - if (!aut || m_util.str.is_length(idx)) return; + if (!aut || m_util.str.is_length(idx)) { + return false; + } SASSERT(m_autil.is_numeral(idx)); eautomaton::moves mvs; aut->get_moves_from(src, mvs); @@ -2000,18 +2025,25 @@ void theory_seq::add_accept2step(expr* acc) { lits.push_back(~ctx.get_literal(acc)); if (aut->is_final_state(src)) { lits.push_back(mk_literal(m_autil.mk_le(len, idx))); + if (ctx.get_assignment(lits.back()) == l_true) { + return false; + } } for (unsigned i = 0; i < mvs.size(); ++i) { eautomaton::move mv = mvs[i]; step = mk_step(e, idx, re, src, mv.dst(), mv.t()); lits.push_back(mk_literal(step)); + if (ctx.get_assignment(lits.back()) == l_true) { + return false; + } } TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + //std::cout << lits << "\n"; for (unsigned i = 0; i < lits.size(); ++i) { // TBD ctx.mark_as_relevant(lits[i]); } ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - add_axiom(~ctx.get_literal(acc), mk_literal(m_autil.mk_ge(len, idx))); + return false; } @@ -2019,17 +2051,40 @@ void theory_seq::add_accept2step(expr* acc) { acc(s, idx, re, i) & step(s, idx, re, i, j, t) => acc(s, idx + 1, re, j) */ -void theory_seq::add_step2accept(expr* step) { +bool theory_seq::add_step2accept(expr* step) { context& ctx = get_context(); SASSERT(ctx.get_assignment(step) == l_true); - rational r; expr* re, *t, *s, *idx, *i, *j; VERIFY(is_step(step, s, idx, re, i, j, t)); - VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); - expr_ref idx1(m_autil.mk_int(r.get_unsigned() + 1), m); literal acc1 = mk_accept(s, idx, re, i); - literal acc2 = mk_accept(s, idx1, re, j); - add_axiom(~acc1, ~ctx.get_literal(step), acc2); + switch (ctx.get_assignment(acc1)) { + case l_false: + break; + case l_undef: + return true; + case l_true: { + rational r; + VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); + expr_ref idx1(m_autil.mk_int(r.get_unsigned() + 1), m); + literal acc2 = mk_accept(s, idx1, re, j); + literal_vector lits; + lits.push_back(acc1); + lits.push_back(ctx.get_literal(step)); + lits.push_back(~acc2); + switch (ctx.get_assignment(acc2)) { + case l_undef: + propagate_lit(0, 2, lits.c_ptr(), acc2); + break; + case l_true: + break; + case l_false: + set_conflict(0, lits); + break; + } + break; + } + } + return false; } @@ -2257,7 +2312,7 @@ bool theory_seq::propagate_automata() { reQ = add_reject2reject(e); } else if (is_step(e)) { - add_step2accept(e); + reQ = add_step2accept(e); } else if (m_util.str.is_prefix(e)) { reQ = add_prefix2prefix(e); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 92c2ebc05..341c1eb07 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -246,6 +246,30 @@ namespace smt { } }; + class apply { + public: + virtual ~apply() {} + virtual void operator()(theory_seq& th) = 0; + }; + + class replay_length_coherence : public apply { + expr_ref m_e; + public: + replay_length_coherence(ast_manager& m, expr* e) : m_e(e, m) {} + virtual void operator()(theory_seq& th) { + th.propagate_length_coherence(m_e); + } + }; + + class push_replay : public trail { + apply* m_apply; + public: + push_replay(apply* app): m_apply(app) {} + virtual void undo(theory_seq& th) { + th.m_replay.push_back(m_apply); + } + }; + void erase_index(unsigned idx, unsigned i); struct stats { @@ -273,6 +297,7 @@ namespace smt { unsigned m_branch_variable_head; // index of first equation to examine. bool m_incomplete; // is the solver (clearly) incomplete for the fragment. obj_hashtable m_length; // is length applied + scoped_ptr_vector m_replay; // set of actions to replay model_generator* m_mg; th_rewriter m_rewrite; seq_util m_util; @@ -410,8 +435,8 @@ namespace smt { bool is_step(expr* e) const; void propagate_step(literal lit, expr* n); bool add_reject2reject(expr* rej); - void add_accept2step(expr* acc); - void add_step2accept(expr* step); + bool add_accept2step(expr* acc); + bool add_step2accept(expr* step); bool add_prefix2prefix(expr* e); bool add_suffix2suffix(expr* e); bool add_contains2contains(expr* e); From 758c9cd7a0c6346abc11c6dfefbeaf092b23c01d Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Fri, 1 Jan 2016 17:02:31 +0000 Subject: [PATCH 47/87] Build fix for install dependencies --- scripts/mk_util.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 8f808bd45..8a92d832d 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1048,8 +1048,8 @@ class LibComponent(Component): out.write('\n') out.write('%s: %s\n\n' % (self.name, libfile)) - def mk_install_dep(self, out): - out.write('%s' % libfile) + def mk_install_deps(self, out): + return def mk_install(self, out): for include in self.includes2install: @@ -1137,8 +1137,10 @@ class ExeComponent(Component): def main_component(self): return self.install - def mk_install_dep(self, out): - out.write('%s' % exefile) + def mk_install_deps(self, out): + if self.install: + exefile = '%s$(EXE_EXT)' % self.exe_name + out.write('%s' % exefile) def mk_install(self, out): if self.install: @@ -1294,7 +1296,7 @@ class DLLComponent(Component): def require_def_file(self): return IS_WINDOWS and self.export_files - def mk_install_dep(self, out): + def mk_install_deps(self, out): out.write('%s$(SO_EXT)' % self.dll_name) if self.static: out.write(' %s$(LIB_EXT)' % self.dll_name) From 5e553a4dc163979f8f2effea1ae89d738b653051 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Jan 2016 13:32:44 -0800 Subject: [PATCH 48/87] seq Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 314 +++++++++++++++++++++++++++++------------ src/smt/theory_seq.h | 79 ++++++----- 2 files changed, 267 insertions(+), 126 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 69ae25aba..c271e405e 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -165,7 +165,9 @@ theory_seq::theory_seq(ast_manager& m): m_util(m), m_autil(m), m_trail_stack(*this), - m_atoms_qhead(0) { + m_atoms_qhead(0), + m_new_solution(false), + m_new_propagation(false) { m_prefix = "seq.prefix.suffix"; m_suffix = "seq.suffix.prefix"; m_contains_left = "seq.contains.left"; @@ -237,15 +239,26 @@ bool theory_seq::branch_variable() { ls.reset(); rs.reset(); m_util.str.get_concat(e.m_lhs, ls); m_util.str.get_concat(e.m_rhs, rs); - - if (!ls.empty() && find_branch_candidate(ls[0].get(), rs)) { + +#if 1 + if (!ls.empty() && find_branch_candidate(e.m_dep, ls[0].get(), rs)) { m_branch_variable_head = k; return true; } - if (!rs.empty() && find_branch_candidate(rs[0].get(), ls)) { + if (!rs.empty() && find_branch_candidate(e.m_dep, rs[0].get(), ls)) { m_branch_variable_head = k; return true; } +#else + if (ls.size() > 1 && find_branch_candidate(e.m_dep, ls.back(), rs)) { + m_branch_variable_head = k; + return true; + } + if (rs.size() > 1 && find_branch_candidate(e.m_dep, rs.back(), ls)) { + m_branch_variable_head = k; + return true; + } +#endif #if 0 if (!has_length(e.m_lhs)) { enforce_length(ensure_enode(e.m_lhs)); @@ -258,7 +271,7 @@ bool theory_seq::branch_variable() { return ctx.inconsistent(); } -bool theory_seq::find_branch_candidate(expr* l, expr_ref_vector const& rs) { +bool theory_seq::find_branch_candidate(dependency* dep, expr* l, expr_ref_vector const& rs) { TRACE("seq", tout << mk_pp(l, m) << " " << (is_var(l)?"var":"not var") << "\n";); @@ -274,40 +287,27 @@ bool theory_seq::find_branch_candidate(expr* l, expr_ref_vector const& rs) { if (l_false != assume_equality(l, v0)) { return true; } - cases.push_back(v0); for (unsigned j = 0; j < rs.size(); ++j) { if (occurs(l, rs[j])) { return false; } - zstring s; - if (m_util.str.is_string(rs[j], s)) { - for (unsigned k = 1; k < s.length(); ++k) { - v = m_util.str.mk_string(s.extract(0, k)); - if (v0) v = m_util.str.mk_concat(v0, v); - if (l_false != assume_equality(l, v)) { - return true; - } - } - } + SASSERT(!m_util.str.is_string(rs[j])); all_units &= m_util.str.is_unit(rs[j]); - v0 = (j == 0)? rs[0] : m_util.str.mk_concat(v0, rs[j]); - cases.push_back(v0); + v0 = m_util.str.mk_concat(j + 1, rs.c_ptr()); if (l_false != assume_equality(l, v0)) { return true; } } -#if 0 if (all_units) { literal_vector lits; - for (unsigned i = 0; i < cases.size(); ++i) { - lits.push_back(mk_eq(l, cases[i].get(), false)); + lits.push_back(~mk_eq_empty(l)); + for (unsigned i = 0; i < rs.size(); ++i) { + v0 = m_util.str.mk_concat(i + 1, rs.c_ptr()); + lits.push_back(~mk_eq(l, v0, false)); } - lits.push_back(~mk_eq(e1, e2, false)); - get_context().mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + set_conflict(dep, lits); return true; } -#endif - return false; } @@ -417,7 +417,10 @@ void theory_seq::propagate_is_conc(expr* e, expr* conc) { propagate_lit(0, 1, &lit, mk_eq(e, conc, false)); expr_ref e1(e, m), e2(conc, m); new_eq_eh(m_dm.mk_leaf(assumption(lit)), ctx.get_enode(e1), ctx.get_enode(e2)); +} +bool theory_seq::is_nth(expr* e) const { + return is_skolem(m_nth, e); } expr_ref theory_seq::mk_nth(expr* s, expr* idx) { @@ -476,10 +479,14 @@ void theory_seq::mk_decompose(expr* e, expr_ref& head, expr_ref& tail) { bool theory_seq::is_solved() { if (!m_eqs.empty()) { + IF_VERBOSE(10, verbose_stream() << "(seq.giveup " << m_eqs[0].m_lhs << " = " << m_eqs[0].m_rhs << " is unsolved)\n";); return false; } for (unsigned i = 0; i < m_automata.size(); ++i) { - if (!m_automata[i]) return false; + if (!m_automata[i]) { + IF_VERBOSE(10, verbose_stream() << "(seq.giveup regular expression did not compile to automaton)\n";); + return false; + } } return true; } @@ -513,6 +520,7 @@ void theory_seq::propagate_lit(dependency* dep, unsigned n, literal const* _lits ext_theory_propagation_justification( get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), lit)); + m_new_propagation = true; ctx.assign(lit, js); } @@ -522,6 +530,7 @@ void theory_seq::set_conflict(dependency* dep, literal_vector const& _lits) { literal_vector lits(_lits); linearize(dep, eqs, lits); TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); display_deps(tout, dep); ;); + m_new_propagation = true; ctx.set_conflict( ctx.mk_justification( ext_theory_conflict_justification( @@ -545,6 +554,7 @@ void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) { ext_theory_eq_propagation_justification( get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), n1, n2)); ctx.assign_eq(n1, n2, eq_justification(js)); + m_new_propagation = true; enforce_length_coherence(n1, n2); } @@ -562,23 +572,17 @@ void theory_seq::enforce_length_coherence(enode* n1, enode* n2) { -bool theory_seq::simplify_eq(expr* l, expr* r, dependency* deps, bool& propagated) { +bool theory_seq::simplify_eq(expr* l, expr* r, dependency* deps) { context& ctx = get_context(); seq_rewriter rw(m); expr_ref_vector lhs(m), rhs(m); - expr_ref lh = canonize(l, deps); - expr_ref rh = canonize(r, deps); - if (!rw.reduce_eq(lh, rh, lhs, rhs)) { + if (!rw.reduce_eq(l, r, lhs, rhs)) { // equality is inconsistent. - TRACE("seq", tout << lh << " != " << rh << "\n";); + TRACE("seq", tout << mk_pp(l, m) << " != " << mk_pp(r, m) << "\n";); set_conflict(deps); - propagated = true; return true; } - if (unchanged(l, lhs) && unchanged(r, rhs)) { - return false; - } - if (unchanged(r, lhs) && unchanged(l, rhs)) { + if (unchanged(l, lhs, r, rhs)) { return false; } SASSERT(lhs.size() == rhs.size()); @@ -590,7 +594,6 @@ bool theory_seq::simplify_eq(expr* l, expr* r, dependency* deps, bool& propagate } else { propagate_eq(deps, ensure_enode(li), ensure_enode(ri)); - propagated = true; } } TRACE("seq", @@ -602,18 +605,14 @@ bool theory_seq::simplify_eq(expr* l, expr* r, dependency* deps, bool& propagate return true; } -bool theory_seq::solve_unit_eq(expr* l, expr* r, dependency* deps, bool& propagated) { - expr_ref lh = canonize(l, deps); - expr_ref rh = canonize(r, deps); - if (lh == rh) { +bool theory_seq::solve_unit_eq(expr* l, expr* r, dependency* deps) { + if (l == r) { return true; } - if (is_var(lh) && !occurs(lh, rh)) { - propagated = add_solution(lh, rh, deps) || propagated; + if (is_var(l) && !occurs(l, r) && add_solution(l, r, deps)) { return true; } - if (is_var(rh) && !occurs(rh, lh)) { - propagated = add_solution(rh, lh, deps) || propagated; + if (is_var(r) && !occurs(r, l) && add_solution(r, l, deps)) { return true; } @@ -651,38 +650,29 @@ bool theory_seq::is_var(expr* a) { } -bool theory_seq::is_nth(expr* e) const { - return is_skolem(m_nth, e); -} -bool theory_seq::add_solution(expr* l, expr* r, dependency* deps) { +bool theory_seq::add_solution(expr* l, expr* r, dependency* deps) { if (l == r) { return false; } context& ctx = get_context(); TRACE("seq", tout << mk_pp(l, m) << " ==> " << mk_pp(r, m) << "\n";); + m_new_solution = true; m_rep.update(l, r, deps); enode* n1 = ensure_enode(l); enode* n2 = ensure_enode(r); - if (n1->get_root() == n2->get_root()) { - return false; - } - else { + if (n1->get_root() != n2->get_root()) { propagate_eq(deps, n1, n2); - return true; } + return true; } - -bool theory_seq::pre_process_eqs(bool simplify_or_solve, bool& propagated) { +bool theory_seq::solve_eqs(unsigned i) { context& ctx = get_context(); bool change = false; - for (unsigned i = 0; !ctx.inconsistent() && i < m_eqs.size(); ++i) { + for (; !ctx.inconsistent() && i < m_eqs.size(); ++i) { eq e = m_eqs[i]; - - if (simplify_or_solve? - simplify_eq(e.m_lhs, e.m_rhs, e.m_dep, propagated): - solve_unit_eq(e.m_lhs, e.m_rhs, e.m_dep, propagated)) { + if (solve_eq(e.m_lhs, e.m_rhs, e.m_dep)) { if (i + 1 != m_eqs.size()) { eq e1 = m_eqs[m_eqs.size()-1]; m_eqs.set(i, e1); @@ -693,7 +683,123 @@ bool theory_seq::pre_process_eqs(bool simplify_or_solve, bool& propagated) { change = true; } } - return change; + return change || ctx.inconsistent(); +} + +bool theory_seq::solve_eq(expr* _l, expr* _r, dependency* deps) { + context& ctx = get_context(); + expr_ref l = canonize(_l, deps); + expr_ref r = canonize(_r, deps); + TRACE("seq", tout << l << " = " << r << "\n";); + if (!ctx.inconsistent() && simplify_eq(l, r, deps)) { + return true; + } + if (!ctx.inconsistent() && solve_unit_eq(l, r, deps)) { + return true; + } + if (!ctx.inconsistent() && solve_binary_eq(l, r, deps)) { + return true; + } + if (!ctx.inconsistent() && (_l != l || _r != r)) { + m_eqs.push_back(eq(l, r, deps)); + return true; + } + return false; +} + +bool theory_seq::is_binary_eq(expr* l, expr* r, expr*& x, ptr_vector& xs, ptr_vector& ys, expr*& y) { + xs.reset(); + ys.reset(); + get_concat(l, xs); + if (xs.size() > 1 && is_var(xs[0])) { + get_concat(r, ys); + if (ys.size() > 1 && is_var(ys.back())) { + x = xs[0]; + y = ys.back(); + for (unsigned i = 1; i < xs.size(); ++i) { + if (!m_util.str.is_unit(xs[i])) return false; + xs[i-1] = xs[i]; + } + xs.pop_back(); + for (unsigned i = 0; i < ys.size()-1; ++i) { + if (!m_util.str.is_unit(ys[i])) return false; + } + ys.pop_back(); + return true; + } + } + return false; +} + +bool theory_seq::solve_binary_eq(expr* l, expr* r, dependency* dep) { + context& ctx = get_context(); + ptr_vector xs, ys; + expr* x, *y; + bool is_binary = is_binary_eq(l, r, x, xs, ys, y); + if (!is_binary) { + std::swap(l, r); + is_binary = is_binary_eq(l, r, x, xs, ys, y); + } + if (!is_binary) { + return false; + } + // Equation is of the form x ++ xs = ys ++ y + // where xs, ys are units. + if (x != y) { + return false; + } + if (xs.size() != ys.size()) { + set_conflict(dep); + return false; + } + if (xs.empty()) { + // this should have been solved already + UNREACHABLE(); + return false; + } + unsigned sz = xs.size(); + literal_vector conflict; + for (unsigned offset = 0; offset < sz; ++offset) { + bool has_conflict = false; + for (unsigned j = 0; !has_conflict && j < sz; ++j) { + unsigned j1 = (offset + j) % sz; + literal eq = mk_eq(xs[j], ys[j1], false); + switch (ctx.get_assignment(eq)) { + case l_false: + conflict.push_back(~eq); + has_conflict = true; + break; + case l_undef: { + enode* n1 = ensure_enode(xs[j]); + enode* n2 = ensure_enode(ys[j1]); + if (n1->get_root() == n2->get_root()) { + break; + } + ctx.mark_as_relevant(eq); + if (sz == 1) { + propagate_lit(dep, 0, 0, eq); + return true; + } + m_new_propagation = true; + break; + } + case l_true: + break; + } + } + if (!has_conflict) { + TRACE("seq", tout << "offset: " << offset << " equality "; + for (unsigned j = 0; j < sz; ++j) { + tout << mk_pp(xs[j], m) << " = " << mk_pp(ys[(offset+j) % sz], m) << "; "; + } + tout << "\n";); + // current equalities can work when solving x ++ xs = ys ++ y + return false; + } + } + TRACE("seq", tout << conflict << "\n";); + set_conflict(dep, conflict); + return false; } bool theory_seq::solve_nqs() { @@ -740,10 +846,7 @@ bool theory_seq::solve_ne(unsigned idx) { mark_solved(idx); return change; } - else if (unchanged(l, lhs) && unchanged(r, rhs)) { - // continue - } - else if (unchanged(r, lhs) && unchanged(l, rhs)) { + else if (unchanged(l, lhs, r, rhs) ) { // continue } else { @@ -807,12 +910,13 @@ void theory_seq::erase_index(unsigned idx, unsigned i) { bool theory_seq::simplify_and_solve_eqs() { context & ctx = get_context(); - bool propagated = false; - simplify_eqs(propagated); - while (!ctx.inconsistent() && solve_basic_eqs(propagated)) { - simplify_eqs(propagated); + m_new_propagation = false; + m_new_solution = true; + while (m_new_solution && !ctx.inconsistent()) { + m_new_solution = false; + solve_eqs(0); } - return propagated || ctx.inconsistent(); + return m_new_propagation || ctx.inconsistent(); } @@ -1121,7 +1225,7 @@ theory_var theory_seq::mk_var(enode* n) { } bool theory_seq::can_propagate() { - return m_axioms_head < m_axioms.size() || !m_replay.empty(); + return m_axioms_head < m_axioms.size() || !m_replay.empty() || m_new_solution; } expr_ref theory_seq::canonize(expr* e, dependency*& eqs) { @@ -1190,6 +1294,10 @@ void theory_seq::propagate() { TRACE("seq", tout << "replay: " << ctx.get_scope_level() << "\n";); m_replay.pop_back(); } + if (m_new_solution) { + simplify_and_solve_eqs(); + m_new_solution = false; + } } void theory_seq::enque_axiom(expr* e) { @@ -1199,7 +1307,6 @@ void theory_seq::enque_axiom(expr* e) { m_axiom_set.insert(e); m_trail_stack.push(push_back_vector(m_axioms)); m_trail_stack.push(insert_obj_trail(m_axiom_set, e));; - } } @@ -1353,6 +1460,7 @@ void theory_seq::add_elim_string_axiom(expr* n) { } add_axiom(mk_eq(n, result, false)); m_rep.update(n, result, 0); + m_new_solution = true; } @@ -1607,11 +1715,12 @@ void theory_seq::add_at_axiom(expr* e) { */ void theory_seq::propagate_step(literal lit, expr* step) { context& ctx = get_context(); + SASSERT(ctx.get_assignment(lit) == l_true); expr* re, *t, *s, *idx, *i, *j; VERIFY(is_step(step, s, idx, re, i, j, t)); expr_ref nth = mk_nth(s, idx); + TRACE("seq", tout << mk_pp(step, m) << " -> " << mk_pp(t, m) << " = " << nth << "\n";); propagate_eq(lit, t, nth); - SASSERT(ctx.get_assignment(lit) == l_true); propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx))); ensure_nth(lit, s, idx); } @@ -1683,6 +1792,7 @@ void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4) { if (l3 != null_literal) { ctx.mark_as_relevant(l3); lits.push_back(l3); } if (l4 != null_literal) { ctx.mark_as_relevant(l4); lits.push_back(l4); } TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + m_new_propagation = true; ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } @@ -1726,6 +1836,7 @@ void theory_seq::propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs) ext_theory_eq_propagation_justification( get_id(), ctx.get_region(), 1, &lit, 0, 0, n1, n2)); + m_new_propagation = true; ctx.assign_eq(n1, n2, eq_justification(js)); } @@ -1834,10 +1945,8 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) { expr_ref o1(n1->get_owner(), m); expr_ref o2(n2->get_owner(), m); TRACE("seq", tout << o1 << " = " << o2 << "\n";); - bool propagated = false; - if (!simplify_eq(o1, o2, deps, propagated)) { - m_eqs.push_back(eq(o1, o2, deps)); - } + m_eqs.push_back(eq(o1, o2, deps)); + solve_eqs(m_eqs.size()-1); enforce_length_coherence(n1, n2); } } @@ -1865,6 +1974,7 @@ void theory_seq::push_scope_eh() { m_trail_stack.push(value_trail(m_axioms_head)); m_eqs.push_scope(); m_nqs.push_scope(); + m_atoms_lim.push_back(m_atoms.size()); } void theory_seq::pop_scope_eh(unsigned num_scopes) { @@ -1875,6 +1985,8 @@ void theory_seq::pop_scope_eh(unsigned num_scopes) { m_exclude.pop_scope(num_scopes); m_eqs.pop_scope(num_scopes); m_nqs.pop_scope(num_scopes); + m_atoms.resize(m_atoms_lim[m_atoms_lim.size()-num_scopes]); + m_atoms_lim.shrink(m_atoms_lim.size()-num_scopes); } void theory_seq::restart_eh() { @@ -2007,6 +2119,8 @@ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { */ bool theory_seq::add_accept2step(expr* acc) { context& ctx = get_context(); + + TRACE("seq", tout << mk_pp(acc, m) << "\n";); SASSERT(ctx.get_assignment(acc) == l_true); expr *e, * idx, *re; expr_ref step(m); @@ -2025,24 +2139,44 @@ bool theory_seq::add_accept2step(expr* acc) { lits.push_back(~ctx.get_literal(acc)); if (aut->is_final_state(src)) { lits.push_back(mk_literal(m_autil.mk_le(len, idx))); - if (ctx.get_assignment(lits.back()) == l_true) { + switch (ctx.get_assignment(lits.back())) { + case l_true: return false; + case l_undef: + ctx.force_phase(lits.back()); + return true; + default: + break; } } + bool has_undef = false; + int start = ctx.get_random_value(); for (unsigned i = 0; i < mvs.size(); ++i) { - eautomaton::move mv = mvs[i]; + unsigned j = (i + start) % mvs.size(); + eautomaton::move mv = mvs[j]; step = mk_step(e, idx, re, src, mv.dst(), mv.t()); lits.push_back(mk_literal(step)); - if (ctx.get_assignment(lits.back()) == l_true) { + switch (ctx.get_assignment(lits.back())) { + case l_true: return false; + case l_undef: + //ctx.force_phase(lits.back()); + //return true; + has_undef = true; + break; + default: + break; } } + if (has_undef) { + return true; + } TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); - //std::cout << lits << "\n"; - for (unsigned i = 0; i < lits.size(); ++i) { // TBD - ctx.mark_as_relevant(lits[i]); + for (unsigned i = 0; i < lits.size(); ++i) { + SASSERT(ctx.get_assignment(lits[i]) == l_false); + lits[i].neg(); } - ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); + set_conflict(0, lits); return false; } @@ -2290,7 +2424,7 @@ bool theory_seq::add_contains2contains(expr* e) { expr_ref head(m), tail(m); mk_decompose(e1, head, tail); literal lits[2] = { ~ctx.get_literal(e), ~mk_eq(e1, emp, false) }; - propagate_lit(0, 2, lits, ~mk_literal(m_util.str.mk_contains(tail, e1))); + propagate_lit(0, 2, lits, ~mk_literal(m_util.str.mk_contains(tail, e2))); return false; } @@ -2306,7 +2440,7 @@ bool theory_seq::propagate_automata() { TRACE("seq", tout << mk_pp(e, m) << "\n";); bool reQ = false; if (is_accept(e)) { - add_accept2step(e); + reQ = add_accept2step(e); } else if (is_reject(e)) { reQ = add_reject2reject(e); @@ -2325,12 +2459,8 @@ bool theory_seq::propagate_automata() { } if (reQ) { re_add.push_back(e); - m_atoms[m_atoms_qhead] = m_atoms.back(); - m_atoms.pop_back(); - } - else { - ++m_atoms_qhead; } + ++m_atoms_qhead; } m_atoms.append(re_add); return true; diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 341c1eb07..78eebe301 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -73,7 +73,7 @@ namespace smt { public: solution_map(ast_manager& m, dependency_manager& dm): m(m), m_dm(dm), m_cache(m), m_lhs(m), m_rhs(m) {} - bool empty() const { return m_map.empty(); } + bool empty() const { return m_map.empty(); } void update(expr* e, expr* r, dependency* d); void add_cache(expr* v, expr_dep& r) { m_cache.insert(v, r); } bool find_cache(expr* v, expr_dep& r) { return m_cache.find(v, r); } @@ -81,10 +81,10 @@ namespace smt { expr* find(expr* e); bool is_root(expr* e) const; void cache(expr* e, expr* r, dependency* d); - void reset_cache() { m_cache.reset(); } - void push_scope() { m_limit.push_back(m_updates.size()); } - void pop_scope(unsigned num_scopes); - void display(std::ostream& out) const; + void reset_cache() { m_cache.reset(); } + void push_scope() { m_limit.push_back(m_updates.size()); } + void pop_scope(unsigned num_scopes); + void display(std::ostream& out) const; }; // Table of current disequalities @@ -109,7 +109,7 @@ namespace smt { struct eq { expr_ref m_lhs; expr_ref m_rhs; - dependency* m_dep; + dependency* m_dep; eq(expr_ref& l, expr_ref& r, dependency* d): m_lhs(l), m_rhs(r), m_dep(d) {} eq(eq const& other): m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_dep(other.m_dep) {} @@ -283,37 +283,42 @@ namespace smt { unsigned m_solve_nqs; unsigned m_solve_eqs; }; - ast_manager& m; - dependency_manager m_dm; - solution_map m_rep; // unification representative. - scoped_vector m_eqs; // set of current equations. - scoped_vector m_nqs; // set of current disequalities. + ast_manager& m; + dependency_manager m_dm; + solution_map m_rep; // unification representative. + scoped_vector m_eqs; // set of current equations. + scoped_vector m_nqs; // set of current disequalities. - seq_factory* m_factory; // value factory - exclusion_table m_exclude; // set of asserted disequalities. - expr_ref_vector m_axioms; // list of axioms to add. - obj_hashtable m_axiom_set; - unsigned m_axioms_head; // index of first axiom to add. - unsigned m_branch_variable_head; // index of first equation to examine. - bool m_incomplete; // is the solver (clearly) incomplete for the fragment. - obj_hashtable m_length; // is length applied - scoped_ptr_vector m_replay; // set of actions to replay + seq_factory* m_factory; // value factory + exclusion_table m_exclude; // set of asserted disequalities. + expr_ref_vector m_axioms; // list of axioms to add. + obj_hashtable m_axiom_set; + unsigned m_axioms_head; // index of first axiom to add. + unsigned m_branch_variable_head; // index of first equation to examine. + bool m_incomplete; // is the solver (clearly) incomplete for the fragment. + obj_hashtable m_length; // is length applied + scoped_ptr_vector m_replay; // set of actions to replay model_generator* m_mg; - th_rewriter m_rewrite; - seq_util m_util; - arith_util m_autil; - th_trail_stack m_trail_stack; - stats m_stats; - symbol m_prefix, m_suffix, m_contains_left, m_contains_right, m_accept, m_reject; - symbol m_tail, m_nth, m_seq_first, m_seq_last, m_indexof_left, m_indexof_right, m_aut_step; - symbol m_extract_prefix, m_at_left, m_at_right; + th_rewriter m_rewrite; + seq_util m_util; + arith_util m_autil; + th_trail_stack m_trail_stack; + stats m_stats; + symbol m_prefix, m_suffix, m_contains_left, m_contains_right, m_accept, m_reject; + symbol m_tail, m_nth, m_seq_first, m_seq_last, m_indexof_left, m_indexof_right, m_aut_step; + symbol m_extract_prefix, m_at_left, m_at_right; ptr_vector m_todo; // maintain automata with regular expressions. scoped_ptr_vector m_automata; obj_map m_re2aut; + + // queue of asserted atoms ptr_vector m_atoms; + unsigned_vector m_atoms_lim; unsigned m_atoms_qhead; + bool m_new_solution; // new solution added + bool m_new_propagation; // new propagation to core virtual final_check_status final_check_eh(); virtual bool internalize_atom(app* atom, bool) { return internalize_term(atom); } @@ -345,15 +350,21 @@ namespace smt { bool check_length_coherence(); bool propagate_length_coherence(expr* e); - bool pre_process_eqs(bool simplify_or_solve, bool& propagated); - bool simplify_eqs(bool& propagated) { return pre_process_eqs(true, propagated); } - bool solve_basic_eqs(bool& propagated) { return pre_process_eqs(false, propagated); } - bool simplify_eq(expr* l, expr* r, dependency* dep, bool& propagated); - bool solve_unit_eq(expr* l, expr* r, dependency* dep, bool& propagated); + bool solve_eqs(unsigned start); + bool solve_eq(expr* l, expr* r, dependency* dep); + bool simplify_eq(expr* l, expr* r, dependency* dep); + bool solve_unit_eq(expr* l, expr* r, dependency* dep); + bool is_binary_eq(expr* l, expr* r, expr*& x, ptr_vector& xunits, ptr_vector& yunits, expr*& y); + bool solve_binary_eq(expr* l, expr* r, dependency* dep); bool solve_nqs(); bool solve_ne(unsigned i); bool unchanged(expr* e, expr_ref_vector& es) const { return es.size() == 1 && es[0] == e; } + bool unchanged(expr* e, expr_ref_vector& es, expr* f, expr_ref_vector& fs) const { + return + (unchanged(e, es) && unchanged(f, fs)) || + (unchanged(e, fs) && unchanged(e, fs)); + } // asserting consequences void linearize(dependency* dep, enode_pair_vector& eqs, literal_vector& lits) const; @@ -363,7 +374,7 @@ namespace smt { void propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs = false); void set_conflict(dependency* dep, literal_vector const& lits = literal_vector()); - bool find_branch_candidate(expr* l, expr_ref_vector const& rs); + bool find_branch_candidate(dependency* dep, expr* l, expr_ref_vector const& rs); lbool assume_equality(expr* l, expr* r); // variable solving utilities From e10ecad5dc0158049f3b893d43773389170c4610 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Jan 2016 22:52:28 -0800 Subject: [PATCH 49/87] seq API Signed-off-by: Nikolaj Bjorner --- src/api/api_ast.cpp | 32 ++++ src/api/api_context.cpp | 2 + src/api/api_context.h | 5 + src/api/api_seq.cpp | 151 ++++++++++++++++++ src/api/api_util.h | 17 +++ src/api/python/z3.py | 252 ++++++++++++++++++++++++++++++- src/api/python/z3printer.py | 5 + src/api/z3_api.h | 233 +++++++++++++++++++++++++++- src/ast/seq_decl_plugin.cpp | 5 +- src/ast/seq_decl_plugin.h | 9 +- src/math/automata/automaton.h | 23 ++- src/parsers/smt2/smt2scanner.cpp | 16 +- src/smt/theory_seq.cpp | 35 +++-- src/smt/theory_seq.h | 4 +- 14 files changed, 745 insertions(+), 44 deletions(-) create mode 100644 src/api/api_seq.cpp diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 944e447c6..db10c8bb3 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -641,6 +641,12 @@ extern "C" { else if (fid == mk_c(c)->get_fpa_fid() && k == ROUNDING_MODE_SORT) { return Z3_ROUNDING_MODE_SORT; } + else if (fid == mk_c(c)->get_seq_fid() && k == SEQ_SORT) { + return Z3_SEQ_SORT; + } + else if (fid == mk_c(c)->get_seq_fid() && k == RE_SORT) { + return Z3_RE_SORT; + } else { return Z3_UNKNOWN_SORT; } @@ -1108,6 +1114,32 @@ extern "C" { } } + if (mk_c(c)->get_seq_fid() == _d->get_family_id()) { + switch (_d->get_decl_kind()) { + case Z3_OP_SEQ_UNIT: return Z3_OP_SEQ_UNIT; + case Z3_OP_SEQ_EMPTY: return Z3_OP_SEQ_EMPTY; + case Z3_OP_SEQ_CONCAT: return Z3_OP_SEQ_CONCAT; + case Z3_OP_SEQ_PREFIX: return Z3_OP_SEQ_PREFIX; + case Z3_OP_SEQ_SUFFIX: return Z3_OP_SEQ_SUFFIX; + case Z3_OP_SEQ_CONTAINS: return Z3_OP_SEQ_CONTAINS; + case Z3_OP_SEQ_EXTRACT: return Z3_OP_SEQ_EXTRACT; + case Z3_OP_SEQ_REPLACE: return Z3_OP_SEQ_REPLACE; + case Z3_OP_SEQ_AT: return Z3_OP_SEQ_AT; + case Z3_OP_SEQ_LENGTH: return Z3_OP_SEQ_LENGTH; + case Z3_OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX; + case Z3_OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE; + case Z3_OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE; + + case Z3_OP_RE_PLUS: return Z3_OP_RE_PLUS; + case Z3_OP_RE_STAR: return Z3_OP_RE_STAR; + case Z3_OP_RE_OPTION: return Z3_OP_RE_OPTION; + case Z3_OP_RE_CONCAT: return Z3_OP_RE_CONCAT; + case Z3_OP_RE_UNION: return Z3_OP_RE_UNION; + default: + return Z3_OP_UNINTERPRETED; + } + } + if (mk_c(c)->get_fpa_fid() == _d->get_family_id()) { switch (_d->get_decl_kind()) { case OP_FPA_RM_NEAREST_TIES_TO_EVEN: return Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN; diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 9d0abe3a7..75782a28d 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -73,6 +73,7 @@ namespace api { m_datalog_util(m()), m_fpa_util(m()), m_dtutil(m()), + m_sutil(m()), m_last_result(m()), m_ast_trail(m()), m_replay_stack(), @@ -97,6 +98,7 @@ namespace api { m_dt_fid = m().mk_family_id("datatype"); m_datalog_fid = m().mk_family_id("datalog_relation"); m_fpa_fid = m().mk_family_id("fpa"); + m_seq_fid = m().mk_family_id("seq"); m_dt_plugin = static_cast(m().get_plugin(m_dt_fid)); if (!m_user_ref_count) { diff --git a/src/api/api_context.h b/src/api/api_context.h index 40b59d1b2..23c8d3fd2 100644 --- a/src/api/api_context.h +++ b/src/api/api_context.h @@ -25,6 +25,7 @@ Revision History: #include"api_util.h" #include"arith_decl_plugin.h" #include"bv_decl_plugin.h" +#include"seq_decl_plugin.h" #include"datatype_decl_plugin.h" #include"dl_decl_plugin.h" #include"fpa_decl_plugin.h" @@ -58,6 +59,7 @@ namespace api { datalog::dl_decl_util m_datalog_util; fpa_util m_fpa_util; datatype_util m_dtutil; + seq_util m_sutil; // Support for old solver API smt_params m_fparams; @@ -78,6 +80,7 @@ namespace api { family_id m_datalog_fid; family_id m_pb_fid; family_id m_fpa_fid; + family_id m_seq_fid; datatype_decl_plugin * m_dt_plugin; std::string m_string_buffer; // temporary buffer used to cache strings sent to the "external" world. @@ -121,6 +124,7 @@ namespace api { datalog::dl_decl_util & datalog_util() { return m_datalog_util; } fpa_util & fpautil() { return m_fpa_util; } datatype_util& dtutil() { return m_dtutil; } + seq_util& sutil() { return m_sutil; } family_id get_basic_fid() const { return m_basic_fid; } family_id get_array_fid() const { return m_array_fid; } family_id get_arith_fid() const { return m_arith_fid; } @@ -129,6 +133,7 @@ namespace api { family_id get_datalog_fid() const { return m_datalog_fid; } family_id get_pb_fid() const { return m_pb_fid; } family_id get_fpa_fid() const { return m_fpa_fid; } + family_id get_seq_fid() const { return m_seq_fid; } datatype_decl_plugin * get_dt_plugin() const { return m_dt_plugin; } Z3_error_code get_error_code() const { return m_error_code; } diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp new file mode 100644 index 000000000..0949cc2e4 --- /dev/null +++ b/src/api/api_seq.cpp @@ -0,0 +1,151 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + api_seq.cpp + +Abstract: + + API for sequences and regular expressions. + +Author: + + Nikolaj Bjorner (nbjorner) 2016-01-02. + +Revision History: + +--*/ +#include +#include"z3.h" +#include"api_log_macros.h" +#include"api_context.h" +#include"api_util.h" +#include"ast_pp.h" + +extern "C" { + + Z3_sort Z3_API Z3_mk_seq_sort(Z3_context c, Z3_sort domain) { + Z3_TRY; + LOG_Z3_mk_seq_sort(c, domain); + RESET_ERROR_CODE(); + sort * ty = mk_c(c)->sutil().str.mk_seq(to_sort(domain)); + mk_c(c)->save_ast_trail(ty); + RETURN_Z3(of_sort(ty)); + Z3_CATCH_RETURN(0); + } + + Z3_sort Z3_API Z3_mk_re_sort(Z3_context c, Z3_sort domain) { + Z3_TRY; + LOG_Z3_mk_re_sort(c, domain); + RESET_ERROR_CODE(); + sort * ty = mk_c(c)->sutil().re.mk_re(to_sort(domain)); + mk_c(c)->save_ast_trail(ty); + RETURN_Z3(of_sort(ty)); + Z3_CATCH_RETURN(0); + } + + Z3_ast Z3_API Z3_mk_string(Z3_context c, Z3_string str) { + Z3_TRY; + LOG_Z3_mk_string(c, str); + RESET_ERROR_CODE(); + zstring s(str, zstring::ascii); + app* a = mk_c(c)->sutil().str.mk_string(s); + mk_c(c)->save_ast_trail(a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); + } + + Z3_sort Z3_API Z3_mk_string_sort(Z3_context c) { + Z3_TRY; + LOG_Z3_mk_string_sort(c); + RESET_ERROR_CODE(); + sort* ty = mk_c(c)->sutil().str.mk_string_sort(); + mk_c(c)->save_ast_trail(ty); + RETURN_Z3(of_sort(ty)); + Z3_CATCH_RETURN(0); + } + + Z3_bool Z3_API Z3_is_seq_sort(Z3_context c, Z3_sort s) { + Z3_TRY; + LOG_Z3_is_seq_sort(c, s); + RESET_ERROR_CODE(); + bool result = mk_c(c)->sutil().is_seq(to_sort(s)); + return result?Z3_TRUE:Z3_FALSE; + Z3_CATCH_RETURN(Z3_FALSE); + } + + Z3_bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s) { + Z3_TRY; + LOG_Z3_is_re_sort(c, s); + RESET_ERROR_CODE(); + bool result = mk_c(c)->sutil().is_re(to_sort(s)); + return result?Z3_TRUE:Z3_FALSE; + Z3_CATCH_RETURN(Z3_FALSE); + } + + Z3_bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s) { + Z3_TRY; + LOG_Z3_is_string_sort(c, s); + RESET_ERROR_CODE(); + bool result = mk_c(c)->sutil().is_string(to_sort(s)); + return result?Z3_TRUE:Z3_FALSE; + Z3_CATCH_RETURN(Z3_FALSE); + } + + Z3_bool Z3_API Z3_is_string(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_is_string(c, s); + RESET_ERROR_CODE(); + bool result = mk_c(c)->sutil().str.is_string(to_expr(s)); + return result?Z3_TRUE:Z3_FALSE; + Z3_CATCH_RETURN(Z3_FALSE); + } + + Z3_string Z3_API Z3_get_string(Z3_context c, Z3_ast s) { + Z3_TRY; + LOG_Z3_get_string(c, s); + RESET_ERROR_CODE(); + zstring str; + if (!mk_c(c)->sutil().str.is_string(to_expr(s), str)) { + SET_ERROR_CODE(Z3_INVALID_ARG); + return ""; + } + std::string result = str.encode(); + return mk_c(c)->mk_external_string(result); + Z3_CATCH_RETURN(""); + } + + Z3_ast Z3_API Z3_mk_seq_empty(Z3_context c, Z3_sort seq) { + Z3_TRY; + LOG_Z3_mk_seq_empty(c, seq); + RESET_ERROR_CODE(); + app* a = mk_c(c)->sutil().str.mk_empty(to_sort(seq)); + mk_c(c)->save_ast_trail(a); + RETURN_Z3(of_ast(a)); + Z3_CATCH_RETURN(0); + } + + MK_UNARY(Z3_mk_seq_unit, mk_c(c)->get_seq_fid(), OP_SEQ_UNIT, SKIP); + MK_NARY(Z3_mk_seq_concat, mk_c(c)->get_seq_fid(), OP_SEQ_CONCAT, SKIP); + MK_BINARY(Z3_mk_seq_prefix, mk_c(c)->get_seq_fid(), OP_SEQ_PREFIX, SKIP); + MK_BINARY(Z3_mk_seq_suffix, mk_c(c)->get_seq_fid(), OP_SEQ_SUFFIX, SKIP); + MK_BINARY(Z3_mk_seq_contains, mk_c(c)->get_seq_fid(), OP_SEQ_CONTAINS, SKIP); + MK_TERNARY(Z3_mk_seq_extract, mk_c(c)->get_seq_fid(), OP_SEQ_EXTRACT, SKIP); + MK_TERNARY(Z3_mk_seq_replace, mk_c(c)->get_seq_fid(), OP_SEQ_REPLACE, SKIP); + MK_BINARY(Z3_mk_seq_at, mk_c(c)->get_seq_fid(), OP_SEQ_AT, SKIP); + MK_UNARY(Z3_mk_seq_length, mk_c(c)->get_seq_fid(), OP_SEQ_LENGTH, SKIP); + //MK_BINARY(Z3_mk_seq_index, mk_c(c)->get_seq_fid(), OP_SEQ_INDEX, SKIP); + MK_UNARY(Z3_mk_seq_to_re, mk_c(c)->get_seq_fid(), OP_SEQ_TO_RE, SKIP); + MK_BINARY(Z3_mk_seq_in_re, mk_c(c)->get_seq_fid(), OP_SEQ_IN_RE, SKIP); + + + MK_UNARY(Z3_mk_re_plus, mk_c(c)->get_seq_fid(), OP_RE_PLUS, SKIP); + MK_UNARY(Z3_mk_re_star, mk_c(c)->get_seq_fid(), OP_RE_STAR, SKIP); + MK_UNARY(Z3_mk_re_option, mk_c(c)->get_seq_fid(), OP_RE_OPTION, SKIP); + MK_NARY(Z3_mk_re_union, mk_c(c)->get_seq_fid(), OP_RE_UNION, SKIP); + MK_NARY(Z3_mk_re_concat, mk_c(c)->get_seq_fid(), OP_RE_CONCAT, SKIP); + + + +}; diff --git a/src/api/api_util.h b/src/api/api_util.h index 9befd8849..3b7baeac0 100644 --- a/src/api/api_util.h +++ b/src/api/api_util.h @@ -135,6 +135,23 @@ Z3_ast Z3_API NAME(Z3_context c, Z3_ast n1, Z3_ast n2) { \ MK_BINARY_BODY(NAME, FID, OP, EXTRA_CODE); \ } +#define MK_TERNARY_BODY(NAME, FID, OP, EXTRA_CODE) \ + Z3_TRY; \ + RESET_ERROR_CODE(); \ + EXTRA_CODE; \ + expr * args[3] = { to_expr(n1), to_expr(n2), to_expr(n3) }; \ + ast* a = mk_c(c)->m().mk_app(FID, OP, 0, 0, 3, args); \ + mk_c(c)->save_ast_trail(a); \ + check_sorts(c, a); \ + RETURN_Z3(of_ast(a)); \ + Z3_CATCH_RETURN(0); + +#define MK_TERNARY(NAME, FID, OP, EXTRA_CODE) \ + Z3_ast Z3_API NAME(Z3_context c, Z3_ast n1, Z3_ast n2, Z3_ast n3) { \ + LOG_ ## NAME(c, n1, n2, n3); \ + MK_TERNARY_BODY(NAME, FID, OP, EXTRA_CODE); \ +} + #define MK_NARY(NAME, FID, OP, EXTRA_CODE) \ Z3_ast Z3_API NAME(Z3_context c, unsigned num_args, Z3_ast const* args) { \ Z3_TRY; \ diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 864a92846..507e9bfee 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -930,6 +930,10 @@ def _to_expr_ref(a, ctx): return FiniteDomainRef(a, ctx) if sk == Z3_ROUNDING_MODE_SORT: return FPRMRef(a, ctx) + if sk == Z3_SEQ_SORT: + return SeqRef(a, ctx) + if sk == Z3_RE_SORT: + return ReRef(a, ctx) return ExprRef(a, ctx) def _coerce_expr_merge(s, a): @@ -3562,12 +3566,32 @@ def Concat(*args): 121 """ args = _get_args(args) + sz = len(args) + if __debug__: + _z3_assert(sz >= 2, "At least two arguments expected.") + + ctx = args[0].ctx + + if is_seq(args[0]): + if __debug__: + _z3_assert(all([is_seq(a) for a in args]), "All arguments must be sequence expressions.") + v = (Ast * sz)() + for i in range(sz): + v[i] = args[i].as_ast() + return SeqRef(Z3_mk_seq_concat(ctx.ref(), sz, v), ctx) + + if is_re(args[0]): + if __debug__: + _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.") + v = (Ast * sz)() + for i in range(sz): + v[i] = args[i].as_ast() + return ReRef(Z3_mk_re_concat(ctx.ref(), sz, v), ctx) + if __debug__: _z3_assert(all([is_bv(a) for a in args]), "All arguments must be Z3 bit-vector expressions.") - _z3_assert(len(args) >= 2, "At least two arguments expected.") - ctx = args[0].ctx - r = args[0] - for i in range(len(args) - 1): + r = args[0] + for i in range(sz - 1): r = BitVecRef(Z3_mk_concat(ctx.ref(), r.as_ast(), args[i+1].as_ast()), ctx) return r @@ -7781,7 +7805,7 @@ def binary_interpolant(a,b,p=None,ctx=None): solver that determines satisfiability. x = Int('x') - print binary_interpolant(x<0,x>2) + print(binary_interpolant(x<0,x>2)) Not(x >= 0) """ f = And(Interpolant(a),b) @@ -7821,6 +7845,7 @@ def sequence_interpolant(v,p=None,ctx=None): f = And(Interpolant(f),v[i]) return tree_interpolant(f,p,ctx) + ######################################### # # Floating-Point Arithmetic @@ -8887,3 +8912,220 @@ def fpToIEEEBV(x): if __debug__: _z3_assert(is_fp(x), "First argument must be a Z3 floating-point expression") return BitVecRef(Z3_mk_fpa_to_ieee_bv(x.ctx_ref(), x.ast), x.ctx) + + + +######################################### +# +# Strings, Sequences and Regular expressions +# +######################################### + +class SeqSortRef(SortRef): + """Sequence sort.""" + + def is_string(self): + """Determine if sort is a string + >>> s = StringSort() + >>> s.is_string() + True + >>> s = SeqSort(IntSort()) + >>> s.is_string() + False + """ + return Z3_is_string_sort(self.ctx_ref(), self.ast) + +def StringSort(ctx=None): + """Create a string sort + >>> s = StringSort() + >>> print(s) + String + """ + ctx = _get_ctx(ctx) + return SeqSortRef(Z3_mk_string_sort(ctx.ref()), ctx) + + +def SeqSort(s): + """Create a sequence sort over elements provided in the argument + >>> s = SeqSort(IntSort()) + >>> s == Unit(IntVal(1)).sort() + True + """ + return SeqSortRef(Z3_mk_seq_sort(s.ctx_ref(), s.ast), s.ctx) + +class SeqRef(ExprRef): + """Sequence expression.""" + + def sort(self): + return SeqSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx) + + def __add__(self, other): + v = (Ast * 2)() + v[0] = self.as_ast() + v[1] = other.as_ast() + return SeqRef(Z3_mk_seq_concat(self.ctx_ref(), 2, v), self.ctx) + + def __getitem__(self, i): + return SeqRef(Z3_mk_seq_at(self.ctx_ref(), self.as_ast(), i.as_ast()), self.ctx) + + def is_string_sort(self): + return Z3_is_string_sort(self.ctx_ref(), Z3_get_sort(self.ctx_ref(), self.as_ast())) + + def is_string_value(self): + return Z3_is_string(self.ctx_ref(), self.as_ast()) + + def as_string(self): + """Return a string representation of sequence expression.""" + return Z3_ast_to_string(self.ctx_ref(), self.as_ast()) + + +def _coerce_seq(s, ctx=None): + if isinstance(s, str): + ctx = _get_ctx(ctx) + s = String(s, ctx) + return s + +def _get_ctx2(a, b): + if is_expr(a): + return a.ctx + if is_expr(b): + return b.ctx + return None + +def is_seq(a): + """Return `True` if `a` is a Z3 sequence expression.""" + return isinstance(a, SeqRef) + +def is_string_sort(a): + """Return `True` if `a` is a Z3 string expression.""" + return isinstance(a, SeqRef) and a.is_string_sort() + +def is_string_value(a): + """return 'True' if 'a' is a Z3 string constant expression.""" + return isinstance(a, SeqRef) and a.is_string_value() + +def String(s, ctx=None): + """create a string expression""" + ctx = _get_ctx(ctx) + return SeqRef(Z3_mk_string(ctx.ref(), s), ctx) + +def Empty(s): + """Create the empty sequence of the given sort + >>> e = Empty(StringSort()) + >>> print(e) + "" + >>> e2 = String("") + >>> print(e == e2) + True + >>> e3 = Empty(SeqSort(IntSort())) + >>> print(e3) + """ + return SeqRef(Z3_mk_seq_empty(s.ctx_ref(), s.as_ast()), s.ctx) + +def Unit(a): + """Create a singleton sequence""" + return SeqRef(Z3_mk_seq_unit(a.ctx_ref(), a.as_ast()), a.ctx) + +def PrefixOf(a, b): + """Check if 'a' is a prefix of 'b'""" + ctx = _get_ctx2(a, b) + a = _coerce_seq(a, ctx) + b = _coerce_seq(b, ctx) + return BoolRef(Z3_mk_seq_prefix(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + +def SuffixOf(a, b): + """Check if 'a' is a suffix of 'b'""" + ctx = _get_ctx2(a, b) + a = _coerce_seq(a, ctx) + b = _coerce_seq(b, ctx) + return BoolRef(Z3_mk_seq_suffix(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + +def Contains(a, b): + """Check if 'a' contains 'b'""" + ctx = _get_ctx2(a, b) + a = _coerce_seq(a, ctx) + b = _coerce_seq(b, ctx) + return BoolRef(Z3_mk_seq_contains(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + +#def Extract(a, offset, length): +# """Extract a sequence at offset with indicated length""" +# return SeqRef(Z3_mk_seq_extract(a.ctx_ref(), a.as_ast(), offset.as_ast()), length.ctx) + +def Replace(src, dst, s): + """Replace the first occurrence of 'src' by 'dst' in 's'""" + ctx = _get_ctx2(src, _get_ctx2(dst, s)) + src = _coerce_seq(src, ctx) + dst = _coerce_seq(dst, ctx) + s = _coerce_seq(s, ctx) + return SeqRef(Z3_mk_seq_replace(src.ctx_ref(), src.as_ast(), dst.as_ast()), s.ctx) + +def Length(s): + """Obtain the length of a sequence 's'""" + return ArithRef(Z3_mk_seq_length(s.ctx_ref(), s.as_ast(), s.ctx)) + +def Re(s, ctx=None): + """The regular expression that accepts sequence 's'""" + s = _coerce_seq(s, ctx) + return ReRef(Z3_mk_seq_to_re(s.ctx_ref(), s.as_ast()), s.ctx) + + + + +## Regular expressions + +class ReSortRef(SortRef): + """Regular expression sort.""" + + +def ReSort(s): + if is_ast(s): + return ReSortRef(Z3_mk_re_sort(s.ctx.ref(), s.as_ast()), ctx) + if s is None or isinstance(s, Context): + ctx = _get_ctx(s) + return ReSortRef(Z3_mk_re_sort(ctx.ref(), Z3_mk_string_sort(ctx.ref())), ctx) + raise Z3Exception("Regular expression sort constructor expects either a string or a context or no argument") + + +class ReRef(ExprRef): + """Regular expressions.""" + + def __add__(self, other): + v = (Ast * 2)() + v[0] = self.as_ast() + v[1] = other.as_ast() + return SeqRef(Z3_mk_re_union(self.ctx_ref(), 2, v), self.ctx) + + +def is_re(s): + return isinstance(s, ReRef) + +def InRe(s, re): + s = _coerce_seq(s, re.ctx) + return BoolRef(Z3_mk_seq_in_re(s.ctx_ref(), s.as_ast(), re.as_ast()), s.ctx) + +def Plus(re): + """Create the regular expression accepting one or more repetitions of argument. + >>> re = Plus(Re("a")) + >>> print(simplify(InRe("aa", re))) + True + >>> print(simplify(InRe("ab", re))) + False + >>> print(simplify(InRe("", re))) + False + """ + return ReRef(Z3_mk_re_plus(re.ctx_ref(), re.as_ast()), re.ctx) + +def Option(re): + return ReRef(Z3_mk_re_option(re.ctx_ref(), re.as_ast()), re.ctx) + +def Star(re): + """Create the regular expression accepting zero or more repetitions of argument. + >>> re = Star(Re("a")) + >>> print(simplify(InRe("aa", re))) + True + >>> print(simplify(InRe("ab", re))) + False + >>> print(simplify(InRe("", re))) + True + """ + return ReRef(Z3_mk_re_star(re.ctx_ref(), re.as_ast()), re.ctx) diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py index adc203436..24d0359c9 100644 --- a/src/api/python/z3printer.py +++ b/src/api/python/z3printer.py @@ -570,6 +570,9 @@ class Formatter: def pp_algebraic(self, a): return to_format(a.as_decimal(self.precision)) + def pp_string(self, a): + return to_format(a.as_string()) + def pp_bv(self, a): return to_format(a.as_string()) @@ -875,6 +878,8 @@ class Formatter: return self.pp_fp_value(a) elif z3.is_fp(a): return self.pp_fp(a, d, xs) + elif z3.is_string_value(a): + return self.pp_string(a) elif z3.is_const(a): return self.pp_const(a) else: diff --git a/src/api/z3_api.h b/src/api/z3_api.h index a4a10bb85..e00134c06 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -161,6 +161,8 @@ typedef enum Z3_FINITE_DOMAIN_SORT, Z3_FLOATING_POINT_SORT, Z3_ROUNDING_MODE_SORT, + Z3_SEQ_SORT, + Z3_RE_SORT, Z3_UNKNOWN_SORT = 1000 } Z3_sort_kind; @@ -1098,7 +1100,7 @@ typedef enum { Z3_OP_PR_TH_LEMMA, Z3_OP_PR_HYPER_RESOLVE, - // Sequences + // Relational algebra Z3_OP_RA_STORE = 0x600, Z3_OP_RA_EMPTY, Z3_OP_RA_IS_EMPTY, @@ -1115,6 +1117,28 @@ typedef enum { Z3_OP_FD_CONSTANT, Z3_OP_FD_LT, + // Sequences + Z3_OP_SEQ_UNIT, + Z3_OP_SEQ_EMPTY, + Z3_OP_SEQ_CONCAT, + Z3_OP_SEQ_PREFIX, + Z3_OP_SEQ_SUFFIX, + Z3_OP_SEQ_CONTAINS, + Z3_OP_SEQ_EXTRACT, + Z3_OP_SEQ_REPLACE, + Z3_OP_SEQ_AT, + Z3_OP_SEQ_LENGTH, + Z3_OP_SEQ_INDEX, + Z3_OP_SEQ_TO_RE, + Z3_OP_SEQ_IN_RE, + + // regular expressions + Z3_OP_RE_PLUS, + Z3_OP_RE_STAR, + Z3_OP_RE_OPTION, + Z3_OP_RE_CONCAT, + Z3_OP_RE_UNION, + // Auxiliary Z3_OP_LABEL = 0x700, Z3_OP_LABEL_LIT, @@ -3093,6 +3117,213 @@ extern "C" { /*@}*/ + /** @name Sequences and regular expressions */ + /*@{*/ + + /** + \brief Create a sequence sort out of the sort for the elements. + + def_API('Z3_mk_seq_sort', SORT, (_in(CONTEXT), _in(SORT))) + */ + Z3_sort Z3_API Z3_mk_seq_sort(Z3_context c, Z3_sort s); + + /** + \brief Check if \c s is a sequence sort. + + def_API('Z3_is_seq_sort', BOOL, (_in(CONTEXT), _in(SORT))) + */ + Z3_bool Z3_API Z3_is_seq_sort(Z3_context c, Z3_sort s); + + /** + \brief Create a regular expression sort out of a sequence sort. + + def_API('Z3_mk_re_sort', SORT, (_in(CONTEXT), _in(SORT))) + */ + Z3_sort Z3_API Z3_mk_re_sort(Z3_context c, Z3_sort seq); + + /** + \brief Check if \c s is a regular expression sort. + + def_API('Z3_is_re_sort', BOOL, (_in(CONTEXT), _in(SORT))) + */ + Z3_bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s); + + /** + \brief Create a sort for 8 bit strings. + + This function creates a sort for ASCII strings. + Each character is 8 bits. + + def_API('Z3_mk_string_sort', SORT ,(_in(CONTEXT), )) + */ + Z3_sort Z3_API Z3_mk_string_sort(Z3_context c); + + /** + \brief Check if \c s is a string sort. + + def_API('Z3_is_string_sort', BOOL, (_in(CONTEXT), _in(SORT))) + */ + Z3_bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s); + + /** + \brief Create a string constant out of the string that is passed in + def_API('Z3_mk_string' ,AST ,(_in(CONTEXT), _in(STRING))) + */ + Z3_ast Z3_API Z3_mk_string(Z3_context c, Z3_string s); + + /** + \brief Determine if \c s is a string constant. + + def_API('Z3_is_string', BOOL, (_in(CONTEXT), _in(AST))) + */ + Z3_bool Z3_API Z3_is_string(Z3_context c, Z3_ast s); + + /** + \brief Retrieve the string constant stored in \c s. + + \pre Z3_is_string(c, s) + + def_API('Z3_get_string' ,STRING ,(_in(CONTEXT), _in(AST))) + */ + Z3_string Z3_API Z3_get_string(Z3_context c, Z3_ast s); + + /** + \brief Create an empty sequence of the sequence sort \c seq. + + \pre s is a sequence sort. + + def_API('Z3_mk_seq_empty' ,AST ,(_in(CONTEXT), _in(SORT))) + */ + Z3_ast Z3_API Z3_mk_seq_empty(Z3_context c, Z3_sort seq); + + /** + \brief Create a unit sequence of \c a. + + def_API('Z3_mk_seq_unit' ,AST ,(_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_unit(Z3_context c, Z3_ast a); + + /** + \brief Concatenate sequences. + + \pre n > 0 + + def_API('Z3_mk_seq_concat' ,AST ,(_in(CONTEXT), _in(UINT), _in_array(1, AST))) + */ + Z3_ast Z3_API Z3_mk_seq_concat(Z3_context c, unsigned n, Z3_ast const args[]); + + /** + \brief Check if \c prefix is a prefix of \c s. + + \pre prefix and s are the same sequence sorts. + + def_API('Z3_mk_seq_prefix' ,AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_prefix(Z3_context c, Z3_ast prefix, Z3_ast s); + + /** + \brief Check if \c suffix is a suffix of \c s. + + \pre \c suffix and \c s are the same sequence sorts. + + def_API('Z3_mk_seq_suffix' ,AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_suffix(Z3_context c, Z3_ast suffix, Z3_ast s); + + /** + \brief Check if \c container contains \c containee. + + \pre \c container and \c containee are the same sequence sorts. + + def_API('Z3_mk_seq_contains' ,AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_contains(Z3_context c, Z3_ast container, Z3_ast containee); + + /** + \brief Extract subsequence starting at \c offset of \c length. + + def_API('Z3_mk_seq_extract' ,AST ,(_in(CONTEXT), _in(AST), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_extract(Z3_context c, Z3_ast s, Z3_ast offset, Z3_ast length); + + /** + \brief Replace the first occurrence of \c src with \c dst in \c s. + + def_API('Z3_mk_seq_replace' ,AST ,(_in(CONTEXT), _in(AST), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_replace(Z3_context c, Z3_ast src, Z3_ast dst, Z3_ast s); + + /** + \brief Retrieve from \s the unit sequence positioned at position \c index. + + def_API('Z3_mk_seq_at' ,AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_at(Z3_context c, Z3_ast s, Z3_ast index); + + /** + \brief Return the length of the sequence \c s. + + def_API('Z3_mk_seq_length' ,AST ,(_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_length(Z3_context c, Z3_ast s); + + + /** + \brief Create a regular expression that accepts the sequence \c seq. + + def_API('Z3_mk_seq_to_re' ,AST ,(_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_to_re(Z3_context c, Z3_ast seq); + + /** + \brief Check if \c seq is in the language generated by the regular expression \c re. + + def_API('Z3_mk_seq_in_re' ,AST ,(_in(CONTEXT), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_in_re(Z3_context c, Z3_ast seq, Z3_ast re); + + /** + \brief Create the regular language \c re+. + + def_API('Z3_mk_re_plus' ,AST ,(_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_re_plus(Z3_context c, Z3_ast re); + + /** + \brief Create the regular language \c re*. + + def_API('Z3_mk_re_star' ,AST ,(_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_re_star(Z3_context c, Z3_ast re); + + /** + \brief Create the regular language \c [re]. + + def_API('Z3_mk_re_option' ,AST ,(_in(CONTEXT), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_re_option(Z3_context c, Z3_ast re); + + /** + \brief Create the union of the regular languages. + + \pre n > 0 + + def_API('Z3_mk_re_union' ,AST ,(_in(CONTEXT), _in(UINT), _in_array(1, AST))) + */ + Z3_ast Z3_API Z3_mk_re_union(Z3_context c, unsigned n, Z3_ast const args[]); + + /** + \brief Create the concatenation of the regular languages. + + \pre n > 0 + + def_API('Z3_mk_re_concat' ,AST ,(_in(CONTEXT), _in(UINT), _in_array(1, AST))) + */ + Z3_ast Z3_API Z3_mk_re_concat(Z3_context c, unsigned n, Z3_ast const args[]); + + /*@}*/ + + /** @name Quantifiers */ /*@{*/ /** diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index c3f882e8d..44901b506 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -80,7 +80,6 @@ zstring zstring::replace(zstring const& src, zstring const& dst) const { return result; } -// TBD: SMT-LIB 2.5 strings don't have escape characters other than " static char* esc_table[32] = { "\\0", "^A", "^B", "^C", "^D", "^E", "^F", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V","^W","^X","^Y","^Z","\\e","^\\","^]","^^","^_"}; @@ -404,14 +403,16 @@ sort * seq_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter return m_string; } return m.mk_sort(symbol("Seq"), sort_info(m_family_id, SEQ_SORT, num_parameters, parameters)); - case RE_SORT: + case RE_SORT: { if (num_parameters != 1) { m.raise_exception("Invalid regex sort, expecting one parameter"); } if (!parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) { m.raise_exception("invalid regex sort, parameter is not a sort"); } + sort * s = to_sort(parameters[0].get_ast()); return m.mk_sort(symbol("RegEx"), sort_info(m_family_id, RE_SORT, num_parameters, parameters)); + } case _STRING_SORT: return m_string; default: diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h index d0a475b25..8cd67a406 100644 --- a/src/ast/seq_decl_plugin.h +++ b/src/ast/seq_decl_plugin.h @@ -215,14 +215,13 @@ public: str(seq_util& u): u(u), m(u.m), m_fid(u.m_fid) {} sort* mk_seq(sort* s) { parameter param(s); return m.mk_sort(m_fid, SEQ_SORT, 1, ¶m); } + sort* mk_string_sort() { return m.mk_sort(m_fid, _STRING_SORT, 0, 0); } app* mk_empty(sort* s) { return m.mk_const(m.mk_func_decl(m_fid, OP_SEQ_EMPTY, 0, 0, 0, (expr*const*)0, s)); } app* mk_string(zstring const& s); app* mk_string(symbol const& s) { return u.seq.mk_string(s); } app* mk_char(char ch); app* mk_concat(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONCAT, 2, es); } - app* mk_concat(expr* a, expr* b, expr* c) { - return mk_concat(a, mk_concat(b, c)); - } + app* mk_concat(expr* a, expr* b, expr* c) { return mk_concat(a, mk_concat(b, c)); } expr* mk_concat(unsigned n, expr* const* es) { if (n == 1) return es[0]; SASSERT(n > 1); return m.mk_app(m_fid, OP_SEQ_CONCAT, n, es); } app* mk_length(expr* a) { return m.mk_app(m_fid, OP_SEQ_LENGTH, 1, &a); } app* mk_substr(expr* a, expr* b, expr* c) { expr* es[3] = { a, b, c }; return m.mk_app(m_fid, OP_SEQ_EXTRACT, 3, es); } @@ -233,8 +232,6 @@ public: app* mk_unit(expr* u) { return m.mk_app(m_fid, OP_SEQ_UNIT, 1, &u); } app* mk_char(zstring const& s, unsigned idx); - - bool is_string(expr const * n) const { return is_app_of(n, m_fid, OP_STRING_CONST); } bool is_string(expr const* n, symbol& s) const { @@ -287,6 +284,8 @@ public: public: re(seq_util& u): m(u.m), m_fid(u.m_fid) {} + sort* mk_re(sort* seq) { parameter param(seq); return m.mk_sort(m_fid, RE_SORT, 1, ¶m); } + app* mk_to_re(expr* s) { return m.mk_app(m_fid, OP_SEQ_TO_RE, 1, &s); } app* mk_in_re(expr* s, expr* r) { return m.mk_app(m_fid, OP_SEQ_IN_RE, s, r); } app* mk_concat(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_CONCAT, r1, r2); } diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index 54cd02832..f64dfd205 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -292,6 +292,8 @@ public: // Generalized: // Src - E -> dst - t -> dst1 => Src - t -> dst1 if dst is final => each Src is final // + // src - e -> dst - ET -> dst1 => src - ET - dst1 if in_degree(dst) = 1, src != dst + // void compress() { for (unsigned i = 0; i < m_delta.size(); ++i) { for (unsigned j = 0; j < m_delta[i].size(); ++j) { @@ -326,6 +328,17 @@ public: add(move(m, src, dst1, t)); remove(dst, dst1, t); } + else if (1 == in_degree(dst) && (!is_final_state(dst) || is_final_state(src)) && init() != dst) { + moves const& mvs = m_delta[dst]; + moves mvs1; + for (unsigned k = 0; k < mvs.size(); ++k) { + mvs1.push_back(move(m, src, mvs[k].dst(), mvs[k].t())); + } + for (unsigned k = 0; k < mvs1.size(); ++k) { + remove(dst, mvs1[k].dst(), mvs1[k].t()); + add(mvs1[k]); + } + } else if (false && 1 == out_degree(dst) && all_epsilon_in(dst) && init() != dst && !is_final_state(dst)) { move const& mv = m_delta[dst][0]; T* t = mv.t(); @@ -364,7 +377,7 @@ public: } } } - + bool is_sequence(unsigned& length) const { if (is_final_state(m_init) && (out_degree(m_init) == 0 || (out_degree(m_init) == 1 && is_loop_state(m_init)))) { length = 0; @@ -466,6 +479,14 @@ public: } private: + void remove_dead_states() { + unsigned_vector remap; + for (unsigned i = 0; i < m_delta.size(); ++i) { + + } + } + + void add(move const& mv) { m_delta[mv.src()].push_back(mv); m_delta_inv[mv.dst()].push_back(mv); diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp index ed16003c2..3664ed903 100644 --- a/src/parsers/smt2/smt2scanner.cpp +++ b/src/parsers/smt2/smt2scanner.cpp @@ -169,24 +169,16 @@ namespace smt2 { char c = curr(); if (c == EOF) throw scanner_exception("unexpected end of string", m_line, m_spos); - if (c == '\"') { + if (c == '\n') { + new_line(); + } + else if (c == '\"') { next(); if (curr() != '\"') { m_string.push_back(0); return STRING_TOKEN; } } - else if (c == '\n') { - new_line(); - } - else if (c == '\\') { - next(); - c = curr(); - if (c == EOF) - throw scanner_exception("unexpected end of string", m_line, m_spos); - if (c != '\\' && c != '\"') - throw scanner_exception("invalid escape sequence", m_line, m_spos); - } m_string.push_back(c); next(); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index c271e405e..1f3afa672 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -199,7 +199,7 @@ final_check_status theory_seq::final_check_eh() { TRACE("seq", tout << ">>solve_eqs\n";); return FC_CONTINUE; } - if (solve_nqs()) { + if (solve_nqs(0)) { ++m_stats.m_solve_nqs; TRACE("seq", tout << ">>solve_nqs\n";); return FC_CONTINUE; @@ -802,21 +802,20 @@ bool theory_seq::solve_binary_eq(expr* l, expr* r, dependency* dep) { return false; } -bool theory_seq::solve_nqs() { +bool theory_seq::solve_nqs(unsigned i) { bool change = false; context & ctx = get_context(); - for (unsigned i = 0; !ctx.inconsistent() && i < m_nqs.size(); ++i) { + for (; !ctx.inconsistent() && i < m_nqs.size(); ++i) { if (!m_nqs[i].is_solved()) { - change = solve_ne(i) || change; + solve_ne(i); } } - return change || ctx.inconsistent(); + return m_new_propagation || ctx.inconsistent(); } -bool theory_seq::solve_ne(unsigned idx) { +void theory_seq::solve_ne(unsigned idx) { context& ctx = get_context(); seq_rewriter rw(m); - bool change = false; ne const& n = m_nqs[idx]; TRACE("seq", display_disequation(tout, n);); @@ -827,7 +826,7 @@ bool theory_seq::solve_ne(unsigned idx) { case l_false: // mark as solved in mark_solved(idx); - return false; + return; case l_true: break; case l_undef: @@ -844,7 +843,7 @@ bool theory_seq::solve_ne(unsigned idx) { expr_ref rh = canonize(r, deps); if (!rw.reduce_eq(lh, rh, lhs, rhs)) { mark_solved(idx); - return change; + return; } else if (unchanged(l, lhs, r, rhs) ) { // continue @@ -870,11 +869,12 @@ bool theory_seq::solve_ne(unsigned idx) { switch (ctx.get_assignment(lit)) { case l_false: mark_solved(idx); - return false; + return; case l_true: break; case l_undef: ++num_undef_lits; + m_new_propagation = true; break; } } @@ -882,16 +882,14 @@ bool theory_seq::solve_ne(unsigned idx) { m_trail_stack.push(push_dep(*this, idx, deps)); erase_index(idx, i); --i; - change = true; } } if (num_undef_lits == 0 && n.m_lhs.empty()) { literal_vector lits(n.m_lits); lits.push_back(~mk_eq(n.m_l, n.m_r, false)); set_conflict(n.m_dep, lits); - return true; + SASSERT(m_new_propagation); } - return change; } @@ -986,7 +984,6 @@ void theory_seq::display(std::ostream & out) const { display_equations(out); } if (m_nqs.size() > 0) { - out << "Disequations:\n"; display_disequations(out); } if (!m_re2aut.empty()) { @@ -1017,8 +1014,13 @@ void theory_seq::display_equations(std::ostream& out) const { } void theory_seq::display_disequations(std::ostream& out) const { + bool first = true; for (unsigned i = 0; i < m_nqs.size(); ++i) { - display_disequation(out, m_nqs[i]); + if (!m_nqs[i].is_solved()) { + if (first) out << "Disequations:\n"; + first = false; + display_disequation(out, m_nqs[i]); + } } } @@ -1155,7 +1157,7 @@ app* theory_seq::mk_value(app* e) { unsigned sz; if (bv.is_numeral(result, val, sz) && sz == zstring().num_bits()) { unsigned v = val.get_unsigned(); - if ((0 <= v && v < 32) || v == 127) { + if ((0 <= v && v < 7) || (14 <= v && v < 32) || v == 127) { result = m_util.str.mk_unit(result); } else { @@ -1961,6 +1963,7 @@ void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) { m_rewrite(eq); if (!m.is_false(eq)) { m_nqs.push_back(ne(e1, e2)); + solve_nqs(m_nqs.size() - 1); } // add solution for variable that is non-empty? } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 78eebe301..db5fa0f8b 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -357,8 +357,8 @@ namespace smt { bool is_binary_eq(expr* l, expr* r, expr*& x, ptr_vector& xunits, ptr_vector& yunits, expr*& y); bool solve_binary_eq(expr* l, expr* r, dependency* dep); - bool solve_nqs(); - bool solve_ne(unsigned i); + bool solve_nqs(unsigned i); + void solve_ne(unsigned i); bool unchanged(expr* e, expr_ref_vector& es) const { return es.size() == 1 && es[0] == e; } bool unchanged(expr* e, expr_ref_vector& es, expr* f, expr_ref_vector& fs) const { return From 1147037a990022ee8e1e962facae67153d565765 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Jan 2016 22:54:49 -0800 Subject: [PATCH 50/87] seq API Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 507e9bfee..802108163 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -9015,12 +9015,13 @@ def Empty(s): >>> print(e) "" >>> e2 = String("") - >>> print(e == e2) + >>> print(e.eq(e2)) True >>> e3 = Empty(SeqSort(IntSort())) >>> print(e3) + seq.empty """ - return SeqRef(Z3_mk_seq_empty(s.ctx_ref(), s.as_ast()), s.ctx) + return SeqRef(Z3_mk_seq_empty(s.ctx_ref(), s.ast), s.ctx) def Unit(a): """Create a singleton sequence""" From b5969326bc5a771f9739ac6a8087e41fd6eb7b87 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 2 Jan 2016 23:31:36 -0800 Subject: [PATCH 51/87] seq API Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 129 ++++++++++++++++++++++++------ src/api/z3_api.h | 2 +- src/ast/rewriter/seq_rewriter.cpp | 3 +- 3 files changed, 107 insertions(+), 27 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 802108163..409d511ef 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -8959,11 +8959,8 @@ class SeqRef(ExprRef): def sort(self): return SeqSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx) - def __add__(self, other): - v = (Ast * 2)() - v[0] = self.as_ast() - v[1] = other.as_ast() - return SeqRef(Z3_mk_seq_concat(self.ctx_ref(), 2, v), self.ctx) + def __add__(self, other): + return Concat(self, other) def __getitem__(self, i): return SeqRef(Z3_mk_seq_at(self.ctx_ref(), self.as_ast(), i.as_ast()), self.ctx) @@ -8985,23 +8982,36 @@ def _coerce_seq(s, ctx=None): s = String(s, ctx) return s -def _get_ctx2(a, b): +def _get_ctx2(a, b, ctx=None): if is_expr(a): return a.ctx if is_expr(b): return b.ctx - return None + return ctx def is_seq(a): - """Return `True` if `a` is a Z3 sequence expression.""" + """Return `True` if `a` is a Z3 sequence expression. + >>> print (is_seq(Unit(IntVal(0)))) + True + >>> print (is_seq(String("abc"))) + True + """ return isinstance(a, SeqRef) def is_string_sort(a): - """Return `True` if `a` is a Z3 string expression.""" + """Return `True` if `a` is a Z3 string expression. + >>> print (is_string_sort(String("ab"))) + True + """ return isinstance(a, SeqRef) and a.is_string_sort() def is_string_value(a): - """return 'True' if 'a' is a Z3 string constant expression.""" + """return 'True' if 'a' is a Z3 string constant expression. + >>> print (is_string_value(String("a"))) + True + >>> print (is_string_value(String("a") + String("b"))) + False + """ return isinstance(a, SeqRef) and a.is_string_value() def String(s, ctx=None): @@ -9028,21 +9038,42 @@ def Unit(a): return SeqRef(Z3_mk_seq_unit(a.ctx_ref(), a.as_ast()), a.ctx) def PrefixOf(a, b): - """Check if 'a' is a prefix of 'b'""" + """Check if 'a' is a prefix of 'b' + >>> s1 = PrefixOf("ab", "abc") + >>> print (simplify(s1)) + True + >>> s2 = PrefixOf("bc", "abc") + >>> print (simplify(s2)) + False + """ ctx = _get_ctx2(a, b) a = _coerce_seq(a, ctx) b = _coerce_seq(b, ctx) return BoolRef(Z3_mk_seq_prefix(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) def SuffixOf(a, b): - """Check if 'a' is a suffix of 'b'""" + """Check if 'a' is a suffix of 'b' + >>> s1 = SuffixOf("ab", "abc") + >>> print (simplify(s1)) + False + >>> s2 = SuffixOf("bc", "abc") + >>> print (simplify(s2)) + True + """ ctx = _get_ctx2(a, b) a = _coerce_seq(a, ctx) b = _coerce_seq(b, ctx) return BoolRef(Z3_mk_seq_suffix(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) def Contains(a, b): - """Check if 'a' contains 'b'""" + """Check if 'a' contains 'b' + >>> s1 = Contains("abc", "ab") + >>> print (simplify(s1)) + True + >>> s2 = SuffixOf("abc", "bc") + >>> print (simplify(s2)) + True + """ ctx = _get_ctx2(a, b) a = _coerce_seq(a, ctx) b = _coerce_seq(b, ctx) @@ -9052,20 +9083,34 @@ def Contains(a, b): # """Extract a sequence at offset with indicated length""" # return SeqRef(Z3_mk_seq_extract(a.ctx_ref(), a.as_ast(), offset.as_ast()), length.ctx) -def Replace(src, dst, s): - """Replace the first occurrence of 'src' by 'dst' in 's'""" - ctx = _get_ctx2(src, _get_ctx2(dst, s)) +def Replace(s, src, dst): + """Replace the first occurrence of 'src' by 'dst' in 's' + >>> r = Replace("aaa", "a", "b") + >>> print (simplify(r)) + "baa" + """ + ctx = _get_ctx2(dst, s) + if ctx is None and is_expr(src): + ctx = src.ctx src = _coerce_seq(src, ctx) dst = _coerce_seq(dst, ctx) s = _coerce_seq(s, ctx) - return SeqRef(Z3_mk_seq_replace(src.ctx_ref(), src.as_ast(), dst.as_ast()), s.ctx) + return SeqRef(Z3_mk_seq_replace(src.ctx_ref(), s.as_ast(), src.as_ast(), dst.as_ast()), s.ctx) def Length(s): - """Obtain the length of a sequence 's'""" - return ArithRef(Z3_mk_seq_length(s.ctx_ref(), s.as_ast(), s.ctx)) + """Obtain the length of a sequence 's' + >>> l = Length(String("abc")) + >>> print (simplify(l)) + 3 + """ + return ArithRef(Z3_mk_seq_length(s.ctx_ref(), s.as_ast()), s.ctx) def Re(s, ctx=None): - """The regular expression that accepts sequence 's'""" + """The regular expression that accepts sequence 's' + >>> s1 = Re("ab") + >>> s2 = Re(String("ab")) + >>> s3 = Re(Unit(BoolVal(True))) + """ s = _coerce_seq(s, ctx) return ReRef(Z3_mk_seq_to_re(s.ctx_ref(), s.as_ast()), s.ctx) @@ -9090,20 +9135,45 @@ def ReSort(s): class ReRef(ExprRef): """Regular expressions.""" - def __add__(self, other): - v = (Ast * 2)() - v[0] = self.as_ast() - v[1] = other.as_ast() - return SeqRef(Z3_mk_re_union(self.ctx_ref(), 2, v), self.ctx) + def __add__(self, other): + return Union(self, other) def is_re(s): return isinstance(s, ReRef) + def InRe(s, re): + """Create regular expression membership test + >>> re = Union(Re("a"),Re("b")) + >>> print (simplify(InRe("a", re))) + True + >>> print (simplify(InRe("b", re))) + True + >>> print (simplify(InRe("c", re))) + False + """ s = _coerce_seq(s, re.ctx) return BoolRef(Z3_mk_seq_in_re(s.ctx_ref(), s.as_ast(), re.as_ast()), s.ctx) +def Union(*args): + """Create union of regular expressions. + >>> re = Union(Re("a"), Re("b"), Re("c")) + >>> print (simplify(InRe("d", re))) + False + """ + args = _get_args(args) + sz = len(args) + if __debug__: + _z3_assert(sz >= 2, "At least two arguments expected.") + _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.") + ctx = args[0].ctx + v = (Ast * sz)() + for i in range(sz): + v[i] = args[i].as_ast() + return ReRef(Z3_mk_re_union(ctx.ref(), sz, v), ctx) + + def Plus(re): """Create the regular expression accepting one or more repetitions of argument. >>> re = Plus(Re("a")) @@ -9117,6 +9187,15 @@ def Plus(re): return ReRef(Z3_mk_re_plus(re.ctx_ref(), re.as_ast()), re.ctx) def Option(re): + """Create the regular expression that optionally accepts the argument. + >>> re = Option(Re("a")) + >>> print(simplify(InRe("a", re))) + True + >>> print(simplify(InRe("", re))) + True + >>> print(simplify(InRe("aa", re))) + False + """ return ReRef(Z3_mk_re_option(re.ctx_ref(), re.as_ast()), re.ctx) def Star(re): diff --git a/src/api/z3_api.h b/src/api/z3_api.h index e00134c06..fab272499 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3251,7 +3251,7 @@ extern "C" { def_API('Z3_mk_seq_replace' ,AST ,(_in(CONTEXT), _in(AST), _in(AST), _in(AST))) */ - Z3_ast Z3_API Z3_mk_seq_replace(Z3_context c, Z3_ast src, Z3_ast dst, Z3_ast s); + Z3_ast Z3_API Z3_mk_seq_replace(Z3_context c, Z3_ast s, Z3_ast src, Z3_ast dst); /** \brief Retrieve from \s the unit sequence positioned at position \c index. diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 2db2391d9..8f6aa6fca 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -822,7 +822,8 @@ br_status seq_rewriter::mk_re_plus(expr* a, expr_ref& result) { br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) { sort* s; VERIFY(m_util.is_re(a, s)); - result = m_util.re.mk_union(m_util.re.mk_to_re(m_util.str.mk_empty(s)), a); + sort_ref seq(m_util.str.mk_seq(s), m()); + result = m_util.re.mk_union(m_util.re.mk_to_re(m_util.str.mk_empty(seq)), a); return BR_REWRITE1; } From 532ec6f8dc2a60d2f468218eacf69983ce3e5b09 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Jan 2016 14:07:34 -0800 Subject: [PATCH 52/87] seq API Signed-off-by: Nikolaj Bjorner --- src/api/api_seq.cpp | 2 +- src/api/python/z3.py | 76 +++++++++++++++++++++++++++++++------------- src/api/z3_api.h | 9 ++++++ 3 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp index 0949cc2e4..5704ffdb0 100644 --- a/src/api/api_seq.cpp +++ b/src/api/api_seq.cpp @@ -135,7 +135,7 @@ extern "C" { MK_TERNARY(Z3_mk_seq_replace, mk_c(c)->get_seq_fid(), OP_SEQ_REPLACE, SKIP); MK_BINARY(Z3_mk_seq_at, mk_c(c)->get_seq_fid(), OP_SEQ_AT, SKIP); MK_UNARY(Z3_mk_seq_length, mk_c(c)->get_seq_fid(), OP_SEQ_LENGTH, SKIP); - //MK_BINARY(Z3_mk_seq_index, mk_c(c)->get_seq_fid(), OP_SEQ_INDEX, SKIP); + MK_TERNARY(Z3_mk_seq_index, mk_c(c)->get_seq_fid(), OP_SEQ_INDEX, SKIP); MK_UNARY(Z3_mk_seq_to_re, mk_c(c)->get_seq_fid(), OP_SEQ_TO_RE, SKIP); MK_BINARY(Z3_mk_seq_in_re, mk_c(c)->get_seq_fid(), OP_SEQ_IN_RE, SKIP); diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 409d511ef..367f8ea0f 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -3596,14 +3596,26 @@ def Concat(*args): return r def Extract(high, low, a): - """Create a Z3 bit-vector extraction expression. + """Create a Z3 bit-vector extraction expression, or create a string extraction expression. >>> x = BitVec('x', 8) >>> Extract(6, 2, x) Extract(6, 2, x) >>> Extract(6, 2, x).sort() BitVec(5) + >>> simplify(Extract(StringVal("abcd"),2,1)) + "c" """ + if isinstance(high, str): + high = StringVal(high) + if is_seq(high): + s = high + offset = _py2expr(low, high.ctx) + length = _py2expr(a, high.ctx) + + if __debug__: + _z3_assert(is_int(offset) and is_int(length), "Second and third arguments must be integers") + return SeqRef(Z3_mk_seq_extract(s.ctx_ref(), s.as_ast(), offset.as_ast(), length.as_ast()), s.ctx) if __debug__: _z3_assert(low <= high, "First argument must be greater than or equal to second argument") _z3_assert(isinstance(high, int) and high >= 0 and isinstance(low, int) and low >= 0, "First and second arguments must be non negative integers") @@ -8979,7 +8991,7 @@ class SeqRef(ExprRef): def _coerce_seq(s, ctx=None): if isinstance(s, str): ctx = _get_ctx(ctx) - s = String(s, ctx) + s = StringVal(s, ctx) return s def _get_ctx2(a, b, ctx=None): @@ -8987,34 +8999,36 @@ def _get_ctx2(a, b, ctx=None): return a.ctx if is_expr(b): return b.ctx + if ctx is None: + ctx = main_ctx() return ctx def is_seq(a): """Return `True` if `a` is a Z3 sequence expression. >>> print (is_seq(Unit(IntVal(0)))) True - >>> print (is_seq(String("abc"))) + >>> print (is_seq(StringVal("abc"))) True """ return isinstance(a, SeqRef) def is_string_sort(a): """Return `True` if `a` is a Z3 string expression. - >>> print (is_string_sort(String("ab"))) + >>> print (is_string_sort(StringVal("ab"))) True """ return isinstance(a, SeqRef) and a.is_string_sort() def is_string_value(a): """return 'True' if 'a' is a Z3 string constant expression. - >>> print (is_string_value(String("a"))) + >>> print (is_string_value(StringVal("a"))) True - >>> print (is_string_value(String("a") + String("b"))) + >>> print (is_string_value(StringVal("a") + StringVal("b"))) False """ return isinstance(a, SeqRef) and a.is_string_value() -def String(s, ctx=None): +def StringVal(s, ctx=None): """create a string expression""" ctx = _get_ctx(ctx) return SeqRef(Z3_mk_string(ctx.ref(), s), ctx) @@ -9024,7 +9038,7 @@ def Empty(s): >>> e = Empty(StringSort()) >>> print(e) "" - >>> e2 = String("") + >>> e2 = StringVal("") >>> print(e.eq(e2)) True >>> e3 = Empty(SeqSort(IntSort())) @@ -9040,10 +9054,10 @@ def Unit(a): def PrefixOf(a, b): """Check if 'a' is a prefix of 'b' >>> s1 = PrefixOf("ab", "abc") - >>> print (simplify(s1)) + >>> simplify(s1) True >>> s2 = PrefixOf("bc", "abc") - >>> print (simplify(s2)) + >>> simplify(s2) False """ ctx = _get_ctx2(a, b) @@ -9054,10 +9068,10 @@ def PrefixOf(a, b): def SuffixOf(a, b): """Check if 'a' is a suffix of 'b' >>> s1 = SuffixOf("ab", "abc") - >>> print (simplify(s1)) + >>> simplify(s1) False >>> s2 = SuffixOf("bc", "abc") - >>> print (simplify(s2)) + >>> simplify(s2) True """ ctx = _get_ctx2(a, b) @@ -9068,10 +9082,10 @@ def SuffixOf(a, b): def Contains(a, b): """Check if 'a' contains 'b' >>> s1 = Contains("abc", "ab") - >>> print (simplify(s1)) + >>> simplify(s1) True - >>> s2 = SuffixOf("abc", "bc") - >>> print (simplify(s2)) + >>> s2 = Contains("abc", "bc") + >>> simplify(s2) True """ ctx = _get_ctx2(a, b) @@ -9079,14 +9093,11 @@ def Contains(a, b): b = _coerce_seq(b, ctx) return BoolRef(Z3_mk_seq_contains(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) -#def Extract(a, offset, length): -# """Extract a sequence at offset with indicated length""" -# return SeqRef(Z3_mk_seq_extract(a.ctx_ref(), a.as_ast(), offset.as_ast()), length.ctx) def Replace(s, src, dst): """Replace the first occurrence of 'src' by 'dst' in 's' >>> r = Replace("aaa", "a", "b") - >>> print (simplify(r)) + >>> simplify(r) "baa" """ ctx = _get_ctx2(dst, s) @@ -9097,18 +9108,39 @@ def Replace(s, src, dst): s = _coerce_seq(s, ctx) return SeqRef(Z3_mk_seq_replace(src.ctx_ref(), s.as_ast(), src.as_ast(), dst.as_ast()), s.ctx) +def IndexOf(s, substr): + return IndexOf(s, substr, IntVal(0)) + +def IndexOf(s, substr, offset): + """Retrieve the index of substring within a string starting at a specified offset. + >>> simplify(IndexOf("abcabc", "bc", 0)) + 1 + >>> simplify(IndexOf("abcabc", "bc", 2)) + 4 + """ + ctx = None + if is_expr(offset): + ctx = offset.ctx + ctx = _get_ctx2(s, substr, ctx) + s = _coerce_seq(s, ctx) + substr = _coerce_seq(substr, ctx) + if isinstance(offset, int): + offset = IntVal(offset, ctx) + return SeqRef(Z3_mk_seq_index(s.ctx_ref(), s.as_ast(), substr.as_ast(), offset.as_ast()), s.ctx) + def Length(s): """Obtain the length of a sequence 's' - >>> l = Length(String("abc")) - >>> print (simplify(l)) + >>> l = Length(StringVal("abc")) + >>> simplify(l) 3 """ + s = _coerce_seq(s) return ArithRef(Z3_mk_seq_length(s.ctx_ref(), s.as_ast()), s.ctx) def Re(s, ctx=None): """The regular expression that accepts sequence 's' >>> s1 = Re("ab") - >>> s2 = Re(String("ab")) + >>> s2 = Re(StringVal("ab")) >>> s3 = Re(Unit(BoolVal(True))) """ s = _coerce_seq(s, ctx) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index fab272499..528399394 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3268,6 +3268,15 @@ extern "C" { Z3_ast Z3_API Z3_mk_seq_length(Z3_context c, Z3_ast s); + /** + \brief Return index of first occurrence of \c substr in \c s starting from offset \c offset. + If \c s does not contain \c substr, then the value is -1, if \c offset is the length of \c s, then the value is -1 as well. + The function is under-specified if \c offset is negative or larger than the length of \c s. + + def_API('Z3_mk_seq_index' ,AST ,(_in(CONTEXT), _in(AST), _in(AST), _in(AST))) + */ + Z3_ast Z3_API Z3_mk_seq_index(Z3_context c, Z3_ast s, Z3_ast substr, Z3_ast offset); + /** \brief Create a regular expression that accepts the sequence \c seq. From 8e80fb830bc81b50da43d3257f0ac43f7d048994 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Jan 2016 14:12:45 -0800 Subject: [PATCH 53/87] merge fixes Signed-off-by: Nikolaj Bjorner --- src/util/mpf.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 6cf8e3a4d..06a82b0d5 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -239,22 +239,15 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode else { scoped_mpq sig(m_mpq_manager); scoped_mpz exp(m_mpq_manager); - scoped_mpq pow(m_mpq_manager); m_mpq_manager.set(sig, significand); m_mpq_manager.abs(sig); m_mpz_manager.set(exp, exponent); - m_mpq_manager.set(pow, mpq(2)); - + // Normalize - unsigned loop = 0; - while (m_mpq_manager.ge(sig, pow)) { - m_mpq_manager.mul(pow, 2, pow); + while (m_mpq_manager.ge(sig, 2)) { + m_mpq_manager.div(sig, mpq(2), sig); m_mpz_manager.inc(exp); - ++loop; - } - if (loop > 0) { - m_mpq_manager.div(sig, pow, sig); } while (m_mpq_manager.lt(sig, 1)) { From a3c4972c85b33cd124b4a487eaa10e6e06a853e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Jan 2016 17:16:13 -0800 Subject: [PATCH 54/87] seq API, tuning Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 184 +++++++++++++++++++++++++++++++++- src/math/automata/automaton.h | 35 +++++-- src/smt/theory_seq.cpp | 32 +++++- 3 files changed, 237 insertions(+), 14 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 1635ea7bb..b353499ad 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -205,6 +205,18 @@ namespace z3 { \brief Return the Bit-vector sort of size \c sz. That is, the sort for bit-vectors of size \c sz. */ sort bv_sort(unsigned sz); + /** + \brief Return the sort for ASCII strings. + */ + sort string_sort(); + /** + \brief Return a sequence sort over base sort \c s. + */ + sort seq_sort(sort& s); + /** + \brief Return a regular expression sort over sequences \c seq_sort. + */ + sort re_sort(sort& seq_sort); /** \brief Return an array sort for arrays from \c d to \c r. @@ -261,6 +273,9 @@ namespace z3 { expr bv_val(__uint64 n, unsigned sz); expr bv_val(char const * n, unsigned sz); + expr string_val(char const* s); + expr string_val(std::string const& s); + expr num_val(int n, sort const & s); /** @@ -425,6 +440,14 @@ namespace z3 { \brief Return true if this sort is a Relation sort. */ bool is_relation() const { return sort_kind() == Z3_RELATION_SORT; } + /** + \brief Return true if this sort is a Sequence sort. + */ + bool is_seq() const { return sort_kind() == Z3_SEQ_SORT; } + /** + \brief Return true if this sort is a regular expression sort. + */ + bool is_re() const { return sort_kind() == Z3_RE_SORT; } /** \brief Return true if this sort is a Finite domain sort. */ @@ -532,6 +555,15 @@ namespace z3 { \brief Return true if this is a Relation expression. */ bool is_relation() const { return get_sort().is_relation(); } + /** + \brief Return true if this is a sequence expression. + */ + bool is_seq() const { return get_sort().is_seq(); } + /** + \brief Return true if this is a regular expression. + */ + bool is_re() const { return get_sort().is_re(); } + /** \brief Return true if this is a Finite-domain expression. @@ -663,6 +695,7 @@ namespace z3 { friend expr distinct(expr_vector const& args); friend expr concat(expr const& a, expr const& b); + friend expr concat(expr_vector const& args); friend expr operator==(expr const & a, expr const & b); friend expr operator==(expr const & a, int b); @@ -728,10 +761,50 @@ namespace z3 { friend expr operator|(int a, expr const & b); friend expr operator~(expr const & a); - expr extract(unsigned hi, unsigned lo) const { Z3_ast r = Z3_mk_extract(ctx(), hi, lo, *this); return expr(ctx(), r); } + expr extract(unsigned hi, unsigned lo) const { Z3_ast r = Z3_mk_extract(ctx(), hi, lo, *this); ctx().check_error(); return expr(ctx(), r); } unsigned lo() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast(Z3_get_decl_int_parameter(ctx(), decl(), 1)); } unsigned hi() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast(Z3_get_decl_int_parameter(ctx(), decl(), 0)); } + /** + \brief sequence and regular expression operations. + + is overloaeded as sequence concatenation and regular expression union. + concat is overloaded to handle sequences and regular expressions + */ + expr extract(expr const& offset, expr const& length) const { + check_context(*this, offset); check_context(offset, length); + Z3_ast r = Z3_mk_seq_extract(ctx(), *this, offset, length); check_error(); return expr(ctx(), r); + } + expr replace(expr const& src, expr const& dst) const { + check_context(*this, src); check_context(src, dst); + Z3_ast r = Z3_mk_seq_replace(ctx(), *this, src, dst); + check_error(); + return expr(ctx(), r); + } + expr unit() const { + Z3_ast r = Z3_mk_seq_unit(ctx(), *this); + check_error(); + return expr(ctx(), r); + } + expr contains(expr const& s) { + check_context(*this, s); + Z3_ast r = Z3_mk_seq_contains(ctx(), *this, s); + check_error(); + return expr(ctx(), r); + } + expr at(expr const& index) const { + check_context(*this, index); + Z3_ast r = Z3_mk_seq_at(ctx(), *this, index); + check_error(); + return expr(ctx(), r); + } + expr length() const { + Z3_ast r = Z3_mk_seq_length(ctx(), *this); + check_error(); + return expr(ctx(), r); + } + + + /** \brief Return a simplified version of this expression. */ @@ -835,6 +908,13 @@ namespace z3 { else if (a.is_bv() && b.is_bv()) { r = Z3_mk_bvadd(a.ctx(), a, b); } + else if (a.is_seq() && b.is_seq()) { + return concat(a, b); + } + else if (a.is_re() && b.is_re()) { + Z3_ast _args[2] = { a, b }; + r = Z3_mk_re_union(a.ctx(), 2, _args); + } else { // operator is not supported by given arguments. assert(false); @@ -1219,11 +1299,48 @@ namespace z3 { inline expr concat(expr const& a, expr const& b) { check_context(a, b); - Z3_ast r = Z3_mk_concat(a.ctx(), a, b); + Z3_ast r; + if (Z3_is_seq_sort(a.ctx(), a.get_sort())) { + Z3_ast _args[2] = { a, b }; + r = Z3_mk_seq_concat(a.ctx(), 2, _args); + } + else if (Z3_is_re_sort(a.ctx(), a.get_sort())) { + Z3_ast _args[2] = { a, b }; + r = Z3_mk_re_concat(a.ctx(), 2, _args); + } + else { + r = Z3_mk_concat(a.ctx(), a, b); + } a.ctx().check_error(); return expr(a.ctx(), r); } + inline expr concat(expr_vector const& args) { + Z3_ast r; + assert(args.size() > 0); + if (args.size() == 1) { + return args[0]; + } + context& ctx = args[0].ctx(); + array _args(args); + if (Z3_is_seq_sort(ctx, args[0].get_sort())) { + r = Z3_mk_seq_concat(ctx, _args.size(), _args.ptr()); + } + else if (Z3_is_re_sort(ctx, args[0].get_sort())) { + r = Z3_mk_re_concat(ctx, _args.size(), _args.ptr()); + } + else { + r = _args[args.size()-1]; + for (unsigned i = args.size()-1; i > 0; ) { + --i; + r = Z3_mk_concat(ctx, _args[i], r); + ctx.check_error(); + } + } + ctx.check_error(); + return expr(ctx, r); + } + class func_entry : public object { Z3_func_entry m_entry; void init(Z3_func_entry e) { @@ -1762,6 +1879,10 @@ namespace z3 { inline sort context::int_sort() { Z3_sort s = Z3_mk_int_sort(m_ctx); check_error(); return sort(*this, s); } inline sort context::real_sort() { Z3_sort s = Z3_mk_real_sort(m_ctx); check_error(); return sort(*this, s); } inline sort context::bv_sort(unsigned sz) { Z3_sort s = Z3_mk_bv_sort(m_ctx, sz); check_error(); return sort(*this, s); } + inline sort context::string_sort() { Z3_sort s = Z3_mk_string_sort(m_ctx); check_error(); return sort(*this, s); } + inline sort context::seq_sort(sort& s) { Z3_sort r = Z3_mk_seq_sort(m_ctx, s); check_error(); return sort(*this, r); } + inline sort context::re_sort(sort& s) { Z3_sort r = Z3_mk_re_sort(m_ctx, s); check_error(); return sort(*this, r); } + inline sort context::array_sort(sort d, sort r) { Z3_sort s = Z3_mk_array_sort(m_ctx, d, r); check_error(); return sort(*this, s); } inline sort context::enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts) { array _enum_names(n); @@ -1885,6 +2006,9 @@ namespace z3 { inline expr context::bv_val(__uint64 n, unsigned sz) { Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, bv_sort(sz)); check_error(); return expr(*this, r); } inline expr context::bv_val(char const * n, unsigned sz) { Z3_ast r = Z3_mk_numeral(m_ctx, n, bv_sort(sz)); check_error(); return expr(*this, r); } + inline expr context::string_val(char const* s) { Z3_ast r = Z3_mk_string(m_ctx, s); check_error(); return expr(*this, r); } + inline expr context::string_val(std::string const& s) { Z3_ast r = Z3_mk_string(m_ctx, s.c_str()); check_error(); return expr(*this, r); } + inline expr context::num_val(int n, sort const & s) { Z3_ast r = Z3_mk_int(m_ctx, n, s); check_error(); return expr(*this, r); } inline expr func_decl::operator()(unsigned n, expr const * args) const { @@ -2017,6 +2141,62 @@ namespace z3 { d.check_error(); return expr(d.ctx(), r); } + + // sequence and regular expression operations. + // union is + + // concat is overloaded to handle sequences and regular expressions + + inline expr empty(sort const& s) { + Z3_ast r = Z3_mk_seq_empty(s.ctx(), s); + s.check_error(); + return expr(s.ctx(), r); + } + inline expr suffixof(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_seq_suffix(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + inline expr prefixof(expr const& a, expr const& b) { + check_context(a, b); + Z3_ast r = Z3_mk_seq_prefix(a.ctx(), a, b); + a.check_error(); + return expr(a.ctx(), r); + } + inline expr indexof(expr const& s, expr const& substr, expr const& offset) { + check_context(s, substr); check_context(s, offset); + Z3_ast r = Z3_mk_seq_index(s.ctx(), s, substr, offset); + s.check_error(); + return expr(s.ctx(), r); + } + inline expr to_re(expr const& s) { + Z3_ast r = Z3_mk_seq_to_re(s.ctx(), s); + s.check_error(); + return expr(s.ctx(), r); + } + inline expr in_re(expr const& s, expr const& re) { + check_context(s, re); + Z3_ast r = Z3_mk_seq_in_re(s.ctx(), s, re); + s.check_error(); + return expr(s.ctx(), r); + } + inline expr plus(expr const& re) { + Z3_ast r = Z3_mk_re_plus(re.ctx(), re); + re.check_error(); + return expr(re.ctx(), r); + } + inline expr option(expr const& re) { + Z3_ast r = Z3_mk_re_option(re.ctx(), re); + re.check_error(); + return expr(re.ctx(), r); + } + inline expr star(expr const& re) { + Z3_ast r = Z3_mk_re_star(re.ctx(), re); + re.check_error(); + return expr(re.ctx(), r); + } + + inline expr interpolant(expr const& a) { return expr(a.ctx(), Z3_mk_interpolant(a.ctx(), a)); } diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index f64dfd205..2a4c964f9 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -292,7 +292,8 @@ public: // Generalized: // Src - E -> dst - t -> dst1 => Src - t -> dst1 if dst is final => each Src is final // - // src - e -> dst - ET -> dst1 => src - ET - dst1 if in_degree(dst) = 1, src != dst + // src - e -> dst - ET -> Dst1 => src - ET -> Dst1 if in_degree(dst) = 1, src != dst + // Src - E -> dst - et -> dst1 => Src - et -> dst1 if out_degree(dst) = 1, src != dst // void compress() { for (unsigned i = 0; i < m_delta.size(); ++i) { @@ -339,24 +340,42 @@ public: add(mvs1[k]); } } - else if (false && 1 == out_degree(dst) && all_epsilon_in(dst) && init() != dst && !is_final_state(dst)) { + // + // Src - E -> dst - et -> dst1 => Src - et -> dst1 if out_degree(dst) = 1, src != dst + // + else if (1 == out_degree(dst) && all_epsilon_in(dst) && init() != dst && !is_final_state(dst)) { move const& mv = m_delta[dst][0]; - T* t = mv.t(); unsigned dst1 = mv.dst(); + T* t = mv.t(); unsigned_vector src0s; moves const& mvs = m_delta_inv[dst]; + moves mvs1; for (unsigned k = 0; k < mvs.size(); ++k) { SASSERT(mvs[k].is_epsilon()); - src0s.push_back(mvs[k].src()); + mvs1.push_back(move(m, mvs[k].src(), dst1, t)); } - for (unsigned k = 0; k < src0s.size(); ++k) { - remove(src0s[k], dst, 0); - add(move(m, src0s[i], dst1, t)); + for (unsigned k = 0; k < mvs1.size(); ++k) { + remove(mvs1[k].src(), dst, 0); + add(mvs1[k]); } remove(dst, dst1, t); --j; continue; } + // + // Src1 - ET -> src - e -> dst => Src1 - ET -> dst if out_degree(src) = 1, src != init() + // + else if (1 == out_degree(src) && init() != src && (!is_final_state(src) || is_final_state(dst))) { + moves const& mvs = m_delta_inv[src]; + moves mvs1; + for (unsigned k = 0; k < mvs.size(); ++k) { + mvs1.push_back(move(m, mvs[k].src(), dst, mvs[k].t())); + } + for (unsigned k = 0; k < mvs1.size(); ++k) { + remove(mvs1[k].src(), src, mvs1[k].t()); + add(mvs1[k]); + } + } else { continue; } @@ -482,7 +501,7 @@ private: void remove_dead_states() { unsigned_vector remap; for (unsigned i = 0; i < m_delta.size(); ++i) { - + } } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 1f3afa672..88988d2b4 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -373,14 +373,12 @@ bool theory_seq::propagate_length_coherence(expr* e) { expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m); expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); add_axiom(~mk_literal(high1), mk_literal(high2)); - m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e))); } - + m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e))); return true; } bool theory_seq::check_length_coherence() { - bool coherent = true; obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); for (; it != end; ++it) { expr* e = *it; @@ -398,7 +396,7 @@ bool theory_seq::check_length_coherence() { return false; } } - return coherent; + return true; } /* @@ -890,6 +888,23 @@ void theory_seq::solve_ne(unsigned idx) { set_conflict(n.m_dep, lits); SASSERT(m_new_propagation); } + if (num_undef_lits == 0 && n.m_lhs.size() == 1) { + expr* l = n.m_lhs[0]; + expr* r = n.m_rhs[0]; + if (m_util.str.is_empty(r)) { + std::swap(l, r); + } + if (m_util.str.is_empty(l) && is_var(r)) { + literal lit = ~mk_eq_empty(r); + if (ctx.get_assignment(lit) == l_true) { + expr_ref head(m), tail(m); + mk_decompose(r, head, tail); + expr_ref conc(m_util.str.mk_concat(head, tail), m); + propagate_is_conc(r, conc); + } + m_new_propagation = true; + } + } } @@ -2171,6 +2186,15 @@ bool theory_seq::add_accept2step(expr* acc) { break; } } + if (has_undef && mvs.size() == 1) { + literal lit = lits.back(); + lits.pop_back(); + for (unsigned i = 0; i < lits.size(); ++i) { + lits[i].neg(); + } + propagate_lit(0, lits.size(), lits.c_ptr(), lit); + return false; + } if (has_undef) { return true; } From 68a532d066f411789721f2f61dd8ad3273594c82 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 3 Jan 2016 20:53:06 -0800 Subject: [PATCH 55/87] seq, API Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 244 ++++++++++++++++++++++++++++++++++++++ src/api/dotnet/Expr.cs | 2 + src/api/dotnet/ReExpr.cs | 42 +++++++ src/api/dotnet/ReSort.cs | 43 +++++++ src/api/dotnet/SeqExpr.cs | 42 +++++++ src/api/dotnet/SeqSort.cs | 43 +++++++ src/api/dotnet/Sort.cs | 2 + src/smt/theory_seq.cpp | 53 ++++++--- src/smt/theory_seq.h | 3 +- 9 files changed, 454 insertions(+), 20 deletions(-) create mode 100644 src/api/dotnet/ReExpr.cs create mode 100644 src/api/dotnet/ReSort.cs create mode 100644 src/api/dotnet/SeqExpr.cs create mode 100644 src/api/dotnet/SeqSort.cs diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index 2e08d3dab..cc81160fb 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2286,6 +2286,230 @@ namespace Microsoft.Z3 #endregion + #region Sequence, string and regular expresions + + /// + /// Create the empty sequence. + /// + public SeqExpr MkEmptySeq(Sort s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return new SeqExpr(this, Native.Z3_mk_seq_empty(nCtx, s.NativeObject)); + } + + /// + /// Create the singleton sequence. + /// + public SeqExpr MkUnit(Expr elem) + { + Contract.Requires(elem != null); + Contract.Ensures(Contract.Result() != null); + return new SeqExpr(this, Native.Z3_mk_seq_unit(nCtx, elem.NativeObject)); + } + + /// + /// Create a string constant. + /// + public SeqExpr MkString(string s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return new SeqExpr(this, Native.Z3_mk_string(nCtx, s)); + } + + /// + /// Concatentate sequences. + /// + public SeqExpr MkConcat(params SeqExpr[] t) + { + Contract.Requires(t != null); + Contract.Requires(Contract.ForAll(t, a => a != null)); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(t); + return new SeqExpr(this, Native.Z3_mk_seq_concat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + } + + + /// + /// Retrieve the length of a given sequence. + /// + public IntExpr MkLength(SeqExpr s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return (IntExpr) Expr.Create(this, Native.Z3_mk_seq_length(nCtx, s.NativeObject)); + } + + /// + /// Check for sequence prefix. + /// + public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2) + { + Contract.Requires(s1 != null); + Contract.Requires(s2 != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s1, s2); + return new BoolExpr(this, Native.Z3_mk_seq_prefix(nCtx, s1.NativeObject, s2.NativeObject)); + } + + /// + /// Check for sequence suffix. + /// + public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2) + { + Contract.Requires(s1 != null); + Contract.Requires(s2 != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s1, s2); + return new BoolExpr(this, Native.Z3_mk_seq_suffix(nCtx, s1.NativeObject, s2.NativeObject)); + } + + /// + /// Check for sequence containment of s2 in s1. + /// + public BoolExpr MkContains(SeqExpr s1, SeqExpr s2) + { + Contract.Requires(s1 != null); + Contract.Requires(s2 != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s1, s2); + return new BoolExpr(this, Native.Z3_mk_seq_contains(nCtx, s1.NativeObject, s2.NativeObject)); + } + + /// + /// Retrieve sequence of length one at index. + /// + public SeqExpr MkAt(SeqExpr s, IntExpr index) + { + Contract.Requires(s != null); + Contract.Requires(index != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s, index); + return new SeqExpr(this, Native.Z3_mk_seq_at(nCtx, s.NativeObject, index.NativeObject)); + } + + /// + /// Extract subsequence. + /// + public SeqExpr MkExtract(SeqExpr s, IntExpr offset, IntExpr length) + { + Contract.Requires(s != null); + Contract.Requires(offset != null); + Contract.Requires(length != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s, offset, length); + return new SeqExpr(this, Native.Z3_mk_seq_extract(nCtx, s.NativeObject, offset.NativeObject, length.NativeObject)); + } + + /// + /// Extract index of sub-string starting at offset. + /// + public IntExpr MkIndexOf(SeqExpr s, SeqExpr substr, ArithExpr offset) + { + Contract.Requires(s != null); + Contract.Requires(offset != null); + Contract.Requires(substr != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s, substr, offset); + return new IntExpr(this, Native.Z3_mk_seq_index(nCtx, s.NativeObject, substr.NativeObject, offset.NativeObject)); + } + + /// + /// Replace the first occurrence of src by dst in s. + /// + public SeqExpr MkReplace(SeqExpr s, SeqExpr src, SeqExpr dst) + { + Contract.Requires(s != null); + Contract.Requires(src != null); + Contract.Requires(dst != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s, src, dst); + return new SeqExpr(this, Native.Z3_mk_seq_replace(nCtx, s.NativeObject, src.NativeObject, dst.NativeObject)); + } + + /// + /// Convert a regular expression that accepts sequence s. + /// + public ReExpr MkToRe(SeqExpr s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_seq_to_re(nCtx, s.NativeObject)); + } + + + /// + /// Check for regular expression membership. + /// + public BoolExpr MkInRe(SeqExpr s, ReExpr re) + { + Contract.Requires(s != null); + Contract.Requires(re != null); + Contract.Ensures(Contract.Result() != null); + CheckContextMatch(s, re); + return new BoolExpr(this, Native.Z3_mk_seq_in_re(nCtx, s.NativeObject, re.NativeObject)); + } + + /// + /// Take the Kleene star of a regular expression. + /// + public ReExpr MkStar(ReExpr re) + { + Contract.Requires(re != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_re_star(nCtx, re.NativeObject)); + } + + /// + /// Take the Kleene plus of a regular expression. + /// + public ReExpr MPlus(ReExpr re) + { + Contract.Requires(re != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_re_plus(nCtx, re.NativeObject)); + } + + /// + /// Create the optional regular expression. + /// + public ReExpr MOption(ReExpr re) + { + Contract.Requires(re != null); + Contract.Ensures(Contract.Result() != null); + return new ReExpr(this, Native.Z3_mk_re_option(nCtx, re.NativeObject)); + } + + /// + /// Create the concatenation of regular languages. + /// + public ReExpr MkConcat(params ReExpr[] t) + { + Contract.Requires(t != null); + Contract.Requires(Contract.ForAll(t, a => a != null)); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(t); + return new ReExpr(this, Native.Z3_mk_re_concat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + } + + /// + /// Create the union of regular languages. + /// + public ReExpr MkUnion(params ReExpr[] t) + { + Contract.Requires(t != null); + Contract.Requires(Contract.ForAll(t, a => a != null)); + Contract.Ensures(Contract.Result() != null); + + CheckContextMatch(t); + return new ReExpr(this, Native.Z3_mk_re_union(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + } + + #endregion + #region Pseudo-Boolean constraints /// @@ -4448,6 +4672,26 @@ namespace Microsoft.Z3 throw new Z3Exception("Context mismatch"); } + [Pure] + internal void CheckContextMatch(Z3Object other1, Z3Object other2) + { + Contract.Requires(other1 != null); + Contract.Requires(other2 != null); + CheckContextMatch(other1); + CheckContextMatch(other2); + } + + [Pure] + internal void CheckContextMatch(Z3Object other1, Z3Object other2, Z3Object other3) + { + Contract.Requires(other1 != null); + Contract.Requires(other2 != null); + Contract.Requires(other3 != null); + CheckContextMatch(other1); + CheckContextMatch(other2); + CheckContextMatch(other3); + } + [Pure] internal void CheckContextMatch(Z3Object[] arr) { diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 599cbf756..c995a12bd 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -1826,6 +1826,8 @@ namespace Microsoft.Z3 case Z3_sort_kind.Z3_FLOATING_POINT_SORT: return new FPExpr(ctx, obj); case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMExpr(ctx, obj); case Z3_sort_kind.Z3_FINITE_DOMAIN_SORT: return new FiniteDomainExpr(ctx, obj); + case Z3_sort_kind.Z3_RE_SORT: return new ReExpr(ctx, obj); + case Z3_sort_kind.Z3_SEQ_SORT: return new SeqExpr(ctx, obj); } return new Expr(ctx, obj); diff --git a/src/api/dotnet/ReExpr.cs b/src/api/dotnet/ReExpr.cs new file mode 100644 index 000000000..6a10d535f --- /dev/null +++ b/src/api/dotnet/ReExpr.cs @@ -0,0 +1,42 @@ +/*++ +Copyright () 2016 Microsoft Corporation + +Module Name: + + ReExpr.cs + +Abstract: + + Z3 Managed API: Regular Expressions + +Author: + + Christoph Wintersteiger (cwinter) 2012-11-23 + +Notes: + +--*/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// Regular expression expressions + /// + public class ReExpr : Expr + { + #region Internal + /// Constructor for ReExpr + internal ReExpr(Context ctx, IntPtr obj) + : base(ctx, obj) + { + Contract.Requires(ctx != null); + } + #endregion + } +} diff --git a/src/api/dotnet/ReSort.cs b/src/api/dotnet/ReSort.cs new file mode 100644 index 000000000..bc420603d --- /dev/null +++ b/src/api/dotnet/ReSort.cs @@ -0,0 +1,43 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + ReSort.cs + +Abstract: + + Z3 Managed API: Regular expression Sorts + +Author: + + Christoph Wintersteiger (cwinter) 2012-11-23 + +Notes: + +--*/ + +using System; +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// A regular expression sort + /// + public class ReSort : Sort + { + #region Internal + internal ReSort(Context ctx, IntPtr obj) + : base(ctx, obj) + { + Contract.Requires(ctx != null); + } + internal ReSort(Context ctx) + : base(ctx, Native.Z3_mk_int_sort(ctx.nCtx)) + { + Contract.Requires(ctx != null); + } + #endregion + } +} diff --git a/src/api/dotnet/SeqExpr.cs b/src/api/dotnet/SeqExpr.cs new file mode 100644 index 000000000..c9fdd03a8 --- /dev/null +++ b/src/api/dotnet/SeqExpr.cs @@ -0,0 +1,42 @@ +/*++ +Copyright () 2016 Microsoft Corporation + +Module Name: + + SeqExpr.cs + +Abstract: + + Z3 Managed API: Sequence Expressions + +Author: + + Christoph Wintersteiger (cwinter) 2012-11-23 + +Notes: + +--*/ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// Sequence expressions + /// + public class SeqExpr : Expr + { + #region Internal + /// Constructor for SeqExpr + internal SeqExpr(Context ctx, IntPtr obj) + : base(ctx, obj) + { + Contract.Requires(ctx != null); + } + #endregion + } +} diff --git a/src/api/dotnet/SeqSort.cs b/src/api/dotnet/SeqSort.cs new file mode 100644 index 000000000..b2be11291 --- /dev/null +++ b/src/api/dotnet/SeqSort.cs @@ -0,0 +1,43 @@ +/*++ +Copyright (c) 2016 Microsoft Corporation + +Module Name: + + SeqSort.cs + +Abstract: + + Z3 Managed API: Sequence Sorts + +Author: + + Christoph Wintersteiger (cwinter) 2012-11-23 + +Notes: + +--*/ + +using System; +using System.Diagnostics.Contracts; + +namespace Microsoft.Z3 +{ + /// + /// A Sequence sort + /// + public class SeqSort : Sort + { + #region Internal + internal SeqSort(Context ctx, IntPtr obj) + : base(ctx, obj) + { + Contract.Requires(ctx != null); + } + internal SeqSort(Context ctx) + : base(ctx, Native.Z3_mk_int_sort(ctx.nCtx)) + { + Contract.Requires(ctx != null); + } + #endregion + } +} diff --git a/src/api/dotnet/Sort.cs b/src/api/dotnet/Sort.cs index 412398ddd..e1b8ca1b7 100644 --- a/src/api/dotnet/Sort.cs +++ b/src/api/dotnet/Sort.cs @@ -147,6 +147,8 @@ namespace Microsoft.Z3 case Z3_sort_kind.Z3_RELATION_SORT: return new RelationSort(ctx, obj); case Z3_sort_kind.Z3_FLOATING_POINT_SORT: return new FPSort(ctx, obj); case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMSort(ctx, obj); + case Z3_sort_kind.Z3_SEQ_SORT: return new SeqSort(ctx, obj); + case Z3_sort_kind.Z3_RE_SORT: return new ReSort(ctx, obj); default: throw new Z3Exception("Unknown sort kind"); } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 88988d2b4..1d640fe78 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -209,7 +209,7 @@ final_check_status theory_seq::final_check_eh() { TRACE("seq", tout << ">>branch_variable\n";); return FC_CONTINUE; } - if (!check_length_coherence()) { + if (check_length_coherence()) { ++m_stats.m_check_length_coherence; TRACE("seq", tout << ">>check_length_coherence\n";); return FC_CONTINUE; @@ -374,29 +374,36 @@ bool theory_seq::propagate_length_coherence(expr* e) { expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); add_axiom(~mk_literal(high1), mk_literal(high2)); } - m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e))); return true; } +bool theory_seq::check_length_coherence(expr* e) { + if (is_var(e) && m_rep.is_root(e)) { + expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); + expr_ref head(m), tail(m); + if (!propagate_length_coherence(e) && + l_false == assume_equality(e, emp)) { + // e = emp \/ e = unit(head.elem(e))*tail(e) + mk_decompose(e, head, tail); + expr_ref conc(m_util.str.mk_concat(head, tail), m); + propagate_is_conc(e, conc); + assume_equality(tail, emp); + } + m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e))); + return true; + } + return false; +} + bool theory_seq::check_length_coherence() { obj_hashtable::iterator it = m_length.begin(), end = m_length.end(); for (; it != end; ++it) { expr* e = *it; - if (is_var(e) && m_rep.is_root(e)) { - expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); - expr_ref head(m), tail(m); - if (!propagate_length_coherence(e) && - l_false == assume_equality(e, emp)) { - // e = emp \/ e = unit(head.elem(e))*tail(e) - mk_decompose(e, head, tail); - expr_ref conc(m_util.str.mk_concat(head, tail), m); - propagate_is_conc(e, conc); - assume_equality(tail, emp); - } - return false; + if (check_length_coherence(e)) { + return true; } } - return true; + return false; } /* @@ -936,6 +943,12 @@ bool theory_seq::simplify_and_solve_eqs() { bool theory_seq::internalize_term(app* term) { TRACE("seq", tout << mk_pp(term, m) << "\n";); context & ctx = get_context(); + if (ctx.e_internalized(term)) { + enode* e = ctx.get_enode(term); + mk_var(e); + return true; + } + unsigned num_args = term->get_num_args(); expr* arg; for (unsigned i = 0; i < num_args; i++) { @@ -947,6 +960,7 @@ bool theory_seq::internalize_term(app* term) { ctx.set_var_theory(bv, get_id()); ctx.mark_as_relevant(bv); } + enode* e = 0; if (ctx.e_internalized(term)) { e = ctx.get_enode(term); @@ -1049,7 +1063,9 @@ void theory_seq::display_disequation(std::ostream& out, ne const& e) const { for (unsigned j = 0; j < e.m_lhs.size(); ++j) { out << mk_pp(e.m_lhs[j], m) << " != " << mk_pp(e.m_rhs[j], m) << "\n"; } - display_deps(out, e.m_dep); + if (e.m_dep) { + display_deps(out, e.m_dep); + } } void theory_seq::display_deps(std::ostream& out, dependency* dep) const { @@ -1063,8 +1079,7 @@ void theory_seq::display_deps(std::ostream& out, dependency* dep) const { literal lit = lits[i]; get_context().display_literals_verbose(out << "\n ", 1, &lit); } - out << "\n"; - + out << "\n"; } void theory_seq::collect_statistics(::statistics & st) const { @@ -1287,7 +1302,7 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { m_rep.add_cache(e0, edr); eqs = m_dm.mk_join(eqs, deps); TRACE("seq_verbose", tout << mk_pp(e0, m) << " |--> " << result << "\n"; - display_deps(tout, eqs);); + if (eqs) display_deps(tout, eqs);); return result; } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index db5fa0f8b..40fce2695 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -257,7 +257,7 @@ namespace smt { public: replay_length_coherence(ast_manager& m, expr* e) : m_e(e, m) {} virtual void operator()(theory_seq& th) { - th.propagate_length_coherence(m_e); + th.check_length_coherence(m_e); } }; @@ -348,6 +348,7 @@ namespace smt { bool split_variable(); // split a variable bool is_solved(); bool check_length_coherence(); + bool check_length_coherence(expr* e); bool propagate_length_coherence(expr* e); bool solve_eqs(unsigned start); From 677ff221f80f74162386ddf8267d0f9343cb63f9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 4 Jan 2016 18:57:15 +0000 Subject: [PATCH 56/87] Internal consistency: FP exponents are always passed before significands. --- src/api/api_fpa.cpp | 6 +- src/ast/fpa/fpa2bv_converter.cpp | 10 +- src/ast/fpa_decl_plugin.h | 44 +-- src/ast/rewriter/fpa_rewriter.cpp | 34 +- src/ast/rewriter/fpa_rewriter.h | 2 +- src/smt/theory_fpa.cpp | 2 +- src/tactic/fpa/fpa2bv_model_converter.cpp | 2 +- src/util/mpf.cpp | 358 +++++++++++----------- src/util/mpf.h | 54 ++-- 9 files changed, 256 insertions(+), 256 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index a31fed7c2..012661081 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -275,7 +275,7 @@ extern "C" { RETURN_Z3(0); } api::context * ctx = mk_c(c); - expr * a = ctx->fpautil().mk_fp(to_expr(sgn), to_expr(sig), to_expr(exp)); + expr * a = ctx->fpautil().mk_fp(to_expr(sgn), to_expr(exp), to_expr(sig)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); Z3_CATCH_RETURN(0); @@ -351,7 +351,7 @@ extern "C" { ctx->fpautil().fm().set(tmp, ctx->fpautil().get_ebits(to_sort(ty)), ctx->fpautil().get_sbits(to_sort(ty)), - sgn != 0, sig, exp); + sgn != 0, exp, sig); expr * a = ctx->fpautil().mk_value(tmp); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); @@ -371,7 +371,7 @@ extern "C" { ctx->fpautil().fm().set(tmp, ctx->fpautil().get_ebits(to_sort(ty)), ctx->fpautil().get_sbits(to_sort(ty)), - sgn != 0, sig, exp); + sgn != 0, exp, sig); expr * a = ctx->fpautil().mk_value(tmp); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index c4ca4c03d..2cce08697 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2505,11 +2505,11 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con return mk_pzero(f, result); else { scoped_mpf nte(m_mpf_manager), nta(m_mpf_manager), tp(m_mpf_manager), tn(m_mpf_manager), tz(m_mpf_manager); - m_mpf_manager.set(nte, ebits, sbits, MPF_ROUND_NEAREST_TEVEN, q.to_mpq(), e.to_mpq().numerator()); - m_mpf_manager.set(nta, ebits, sbits, MPF_ROUND_NEAREST_TAWAY, q.to_mpq(), e.to_mpq().numerator()); - m_mpf_manager.set(tp, ebits, sbits, MPF_ROUND_TOWARD_POSITIVE, q.to_mpq(), e.to_mpq().numerator()); - m_mpf_manager.set(tn, ebits, sbits, MPF_ROUND_TOWARD_NEGATIVE, q.to_mpq(), e.to_mpq().numerator()); - m_mpf_manager.set(tz, ebits, sbits, MPF_ROUND_TOWARD_ZERO, q.to_mpq(), e.to_mpq().numerator()); + m_mpf_manager.set(nte, ebits, sbits, MPF_ROUND_NEAREST_TEVEN, e.to_mpq().numerator(), q.to_mpq()); + m_mpf_manager.set(nta, ebits, sbits, MPF_ROUND_NEAREST_TAWAY, e.to_mpq().numerator(), q.to_mpq()); + m_mpf_manager.set(tp, ebits, sbits, MPF_ROUND_TOWARD_POSITIVE, e.to_mpq().numerator(), q.to_mpq()); + m_mpf_manager.set(tn, ebits, sbits, MPF_ROUND_TOWARD_NEGATIVE, e.to_mpq().numerator(), q.to_mpq()); + m_mpf_manager.set(tz, ebits, sbits, MPF_ROUND_TOWARD_ZERO, e.to_mpq().numerator(), q.to_mpq()); app_ref a_nte(m), a_nta(m), a_tp(m), a_tn(m), a_tz(m); a_nte = m_plugin->mk_numeral(nte); diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index bf82aa487..90e50d8c3 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -24,7 +24,7 @@ Revision History: #include"arith_decl_plugin.h" #include"bv_decl_plugin.h" #include"mpf.h" - + enum fpa_sort_kind { FLOATING_POINT_SORT, ROUNDING_MODE_SORT, @@ -89,16 +89,16 @@ enum fpa_op_kind { /* Internal use only */ OP_FPA_INTERNAL_RM, // Internal conversion from (_ BitVec 3) to RoundingMode OP_FPA_INTERNAL_BVWRAP, - OP_FPA_INTERNAL_BVUNWRAP, - + OP_FPA_INTERNAL_BVUNWRAP, + OP_FPA_INTERNAL_MIN_I, OP_FPA_INTERNAL_MAX_I, OP_FPA_INTERNAL_MIN_UNSPECIFIED, OP_FPA_INTERNAL_MAX_UNSPECIFIED, OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, - OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, + OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED, OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED, - OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, + OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED, LAST_FLOAT_OP }; @@ -115,7 +115,7 @@ class fpa_decl_plugin : public decl_plugin { mpf_eq_proc(scoped_mpf_vector const & values):m_values(values) {} bool operator()(unsigned id1, unsigned id2) const { return m_values.m().eq_core(m_values[id1], m_values[id2]); } }; - + typedef chashtable value_table; @@ -149,7 +149,7 @@ class fpa_decl_plugin : public decl_plugin { func_decl * mk_rm_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); func_decl * mk_fma(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); + unsigned arity, sort * const * domain, sort * range); func_decl * mk_fp(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); func_decl * mk_to_fp(decl_kind k, unsigned num_parameters, parameter const * parameters, @@ -184,23 +184,23 @@ class fpa_decl_plugin : public decl_plugin { public: fpa_decl_plugin(); - + bool is_float_sort(sort * s) const { return is_sort_of(s, m_family_id, FLOATING_POINT_SORT); } bool is_rm_sort(sort * s) const { return is_sort_of(s, m_family_id, ROUNDING_MODE_SORT); } virtual ~fpa_decl_plugin(); virtual void finalize(); - + virtual decl_plugin * mk_fresh(); virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range); virtual void get_op_names(svector & op_names, symbol const & logic); virtual void get_sort_names(svector & sort_names, symbol const & logic); virtual expr * get_some_value(sort * s); virtual bool is_value(app* e) const; virtual bool is_unique_value(app* e) const; - + mpf_manager & fm() { return m_fm; } func_decl * mk_numeral_decl(mpf const & v); app * mk_numeral(mpf const & v); @@ -209,7 +209,7 @@ public: bool is_rm_numeral(expr * n, mpf_rounding_mode & val); bool is_rm_numeral(expr * n); - mpf const & get_value(unsigned id) const { + mpf const & get_value(unsigned id) const { SASSERT(m_value_table.contains(id)); return m_values[id]; } @@ -222,7 +222,7 @@ class fpa_util { ast_manager & m_manager; fpa_decl_plugin * m_plugin; family_id m_fid; - arith_util m_a_util; + arith_util m_a_util; bv_util m_bv_util; public: @@ -269,19 +269,19 @@ public: app * mk_pzero(sort * s) { return mk_pzero(get_ebits(s), get_sbits(s)); } app * mk_nzero(sort * s) { return mk_nzero(get_ebits(s), get_sbits(s)); } - bool is_nan(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nan(v); } + bool is_nan(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nan(v); } bool is_pinf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pinf(v); } bool is_ninf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_ninf(v); } bool is_zero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_zero(v); } bool is_pzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pzero(v); } bool is_nzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nzero(v); } - - app * mk_fp(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FPA_FP, arg1, arg2, arg3); } + + app * mk_fp(expr * sgn, expr * exp, expr * sig) { return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig); } app * mk_to_fp(sort * s, expr * bv_t) { SASSERT(is_float(s) && s->get_num_parameters() == 2); - return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 1, &bv_t); + return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 1, &bv_t); } - app * mk_to_fp(sort * s, expr * rm, expr * t) { + app * mk_to_fp(sort * s, expr * rm, expr * t) { SASSERT(is_float(s) && s->get_num_parameters() == 2); expr * args[] = { rm, t }; return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 2, args); @@ -291,7 +291,7 @@ public: expr * args[] = { rm, sig, exp }; return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 3, args); } - app * mk_to_fp_unsigned(sort * s, expr * rm, expr * t) { + app * mk_to_fp_unsigned(sort * s, expr * rm, expr * t) { SASSERT(is_float(s) && s->get_num_parameters() == 2); expr * args[] = { rm, t }; return m().mk_app(m_fid, OP_FPA_TO_FP_UNSIGNED, 2, s->get_parameters(), 2, args); @@ -299,11 +299,11 @@ public: bool is_to_fp(expr * n) { return is_app_of(n, m_fid, OP_FPA_TO_FP); } - app * mk_to_ubv(expr * rm, expr * t, unsigned sz) { + app * mk_to_ubv(expr * rm, expr * t, unsigned sz) { parameter ps[] = { parameter(sz) }; expr * args[] = { rm, t }; return m().mk_app(m_fid, OP_FPA_TO_UBV, 1, ps, 2, args); } - app * mk_to_sbv(expr * rm, expr * t, unsigned sz) { + app * mk_to_sbv(expr * rm, expr * t, unsigned sz) { parameter ps[] = { parameter(sz) }; expr * args[] = { rm, t }; return m().mk_app(m_fid, OP_FPA_TO_SBV, 1, ps, 2, args); @@ -336,7 +336,7 @@ public: app * mk_is_inf(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_INF, arg1); } app * mk_is_zero(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_ZERO, arg1); } app * mk_is_normal(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NORMAL, arg1); } - app * mk_is_subnormal(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_SUBNORMAL, arg1); } + app * mk_is_subnormal(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_SUBNORMAL, arg1); } app * mk_is_positive(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_POSITIVE, arg1); } app * mk_is_negative(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NEGATIVE, arg1); } diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index e4732f125..2d1166ee8 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -213,7 +213,7 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const mpf_exp_t mpf_exp = mpzm.get_int64(exp); mpf_exp = m_fm.unbias_exp(ebits, mpf_exp); - m_fm.set(v, ebits, sbits, !mpzm.is_zero(z), sig, mpf_exp); + m_fm.set(v, ebits, sbits, !mpzm.is_zero(z), mpf_exp, sig); TRACE("fp_rewriter", tout << "sgn: " << !mpzm.is_zero(z) << std::endl; tout << "sig: " << mpzm.to_string(sig) << std::endl; @@ -267,7 +267,7 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const return BR_FAILED; TRACE("fp_rewriter", tout << "r1: " << r1 << ", r2: " << r2 << "\n";); - m_fm.set(v, ebits, sbits, rmv, r1.to_mpq(), r2.to_mpq().numerator()); + m_fm.set(v, ebits, sbits, rmv, r2.to_mpq().numerator(), r1.to_mpq()); result = m_util.mk_value(v); return BR_DONE; } @@ -281,8 +281,8 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const mpf_exp_t biased_exp = m_fm.mpz_manager().get_int64(r2.to_mpq().numerator()); m_fm.set(v, bvs2, bvs3 + 1, r1.is_one(), - r3.to_mpq().numerator(), - m_fm.unbias_exp(bvs2, biased_exp)); + m_fm.unbias_exp(bvs2, biased_exp), + r3.to_mpq().numerator()); TRACE("fp_rewriter", tout << "v = " << m_fm.to_string(v) << std::endl;); result = m_util.mk_value(v); return BR_DONE; @@ -753,23 +753,23 @@ br_status fpa_rewriter::mk_rm(expr * arg, expr_ref & result) { return BR_FAILED; } -br_status fpa_rewriter::mk_fp(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { +br_status fpa_rewriter::mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result) { unsynch_mpz_manager & mpzm = m_fm.mpz_manager(); bv_util bu(m()); - rational r1, r2, r3; - unsigned bvs1, bvs2, bvs3; + rational rsgn, rexp, rsig; + unsigned bvsz_sgn, bvsz_exp, bvsz_sig; - if (bu.is_numeral(arg1, r1, bvs1) && - bu.is_numeral(arg2, r2, bvs2) && - bu.is_numeral(arg3, r3, bvs3)) { - SASSERT(mpzm.is_one(r2.to_mpq().denominator())); - SASSERT(mpzm.is_one(r3.to_mpq().denominator())); + if (bu.is_numeral(sgn, rsgn, bvsz_sgn) && + bu.is_numeral(sig, rsig, bvsz_exp) && + bu.is_numeral(exp, rexp, bvsz_sig)) { + SASSERT(mpzm.is_one(rexp.to_mpq().denominator())); + SASSERT(mpzm.is_one(rsig.to_mpq().denominator())); scoped_mpf v(m_fm); - mpf_exp_t biased_exp = mpzm.get_int64(r2.to_mpq().numerator()); - m_fm.set(v, bvs2, bvs3 + 1, - r1.is_one(), - r3.to_mpq().numerator(), - m_fm.unbias_exp(bvs2, biased_exp)); + mpf_exp_t biased_exp = mpzm.get_int64(rexp.to_mpq().numerator()); + m_fm.set(v, bvsz_exp, bvsz_sig + 1, + rsgn.is_one(), + m_fm.unbias_exp(bvsz_exp, biased_exp), + rsig.to_mpq().numerator()); TRACE("fp_rewriter", tout << "simplified (fp ...) to " << m_fm.to_string(v) << std::endl;); result = m_util.mk_value(v); return BR_DONE; diff --git a/src/ast/rewriter/fpa_rewriter.h b/src/ast/rewriter/fpa_rewriter.h index 43d138cad..0889bba72 100644 --- a/src/ast/rewriter/fpa_rewriter.h +++ b/src/ast/rewriter/fpa_rewriter.h @@ -79,7 +79,7 @@ public: br_status mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); br_status mk_rm(expr * arg, expr_ref & result); - br_status mk_fp(expr * arg1, expr * arg2, expr * arg3, expr_ref & result); + br_status mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result); br_status mk_to_fp_unsigned(expr * arg1, expr * arg2, expr_ref & result); br_status mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); br_status mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result); diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 3e43cc4ce..a06ee723c 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -235,7 +235,7 @@ namespace smt { SASSERT(mpzm.is_int64(exp_u)); scoped_mpf f(mpfm); - mpfm.set(f, m_ebits, m_sbits, mpzm.is_one(sgn_z), sig_z, mpzm.get_int64(exp_u)); + mpfm.set(f, m_ebits, m_sbits, mpzm.is_one(sgn_z), mpzm.get_int64(exp_u), sig_z); result = m_fu.mk_value(f); TRACE("t_fpa", tout << "fpa_value_proc::mk_value [" << diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp index fdbe54c4d..799083a5f 100644 --- a/src/tactic/fpa/fpa2bv_model_converter.cpp +++ b/src/tactic/fpa/fpa2bv_model_converter.cpp @@ -132,7 +132,7 @@ expr_ref fpa2bv_model_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp, mpzm.set(sig_z, sig_q.to_mpq().numerator()); exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator()); - fu.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), sig_z, exp_z); + fu.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z); mpzm.del(sig_z); diff --git a/src/util/mpf.cpp b/src/util/mpf.cpp index 06a82b0d5..1601d7fe3 100644 --- a/src/util/mpf.cpp +++ b/src/util/mpf.cpp @@ -19,7 +19,7 @@ Revision History: #include #include"mpf.h" -mpf::mpf() : +mpf::mpf() : ebits(0), sbits(0), sign(false), @@ -45,7 +45,7 @@ mpf::mpf(mpf const & other) { // UNREACHABLE(); } -mpf::~mpf() { +mpf::~mpf() { } void mpf::swap(mpf & other) { @@ -68,15 +68,15 @@ mpf_manager::mpf_manager() : m_powers2(m_mpz_manager) { } -mpf_manager::~mpf_manager() { +mpf_manager::~mpf_manager() { } -void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, int value) { +void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, int value) { COMPILE_TIME_ASSERT(sizeof(int) == 4); o.sign = false; o.ebits = ebits; - o.sbits = sbits; + o.sbits = sbits; TRACE("mpf_dbg", tout << "set: value = " << value << std::endl;); if (value == 0) { @@ -91,7 +91,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, int value) { else uval = -value; } - + o.exponent = 31; while ((uval & 0x80000000) == 0) { uval <<= 1; @@ -99,12 +99,12 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, int value) { } m_mpz_manager.set(o.significand, uval & 0x7FFFFFFF); // remove the "1." part - + // align with sbits. if (sbits > 31) - m_mpz_manager.mul2k(o.significand, sbits-32); + m_mpz_manager.mul2k(o.significand, sbits-32); else - m_mpz_manager.machine_div2k(o.significand, 32-sbits); + m_mpz_manager.machine_div2k(o.significand, 32-sbits); } TRACE("mpf_dbg", tout << "set: res = " << to_string(o) << std::endl;); @@ -133,7 +133,7 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, double value) { o.ebits = ebits; o.sbits = sbits; - o.sign = sign; + o.sign = sign; if (e <= -((0x01ll<<(ebits-1))-1)) o.exponent = mk_bot_exp(ebits); @@ -192,11 +192,11 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode TRACE("mpf_dbg", tout << "set: " << m_mpq_manager.to_string(value) << " [" << ebits << "/" << sbits << "]"<< std::endl;); scoped_mpz exp(m_mpz_manager); m_mpz_manager.set(exp, 0); - set(o, ebits, sbits, rm, value, exp); + set(o, ebits, sbits, rm, exp, value); TRACE("mpf_dbg", tout << "set: res = " << to_string(o) << std::endl;); } -void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, char const * value) { +void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, char const * value) { TRACE("mpf_dbg", tout << "set: " << value << " [" << ebits << "/" << sbits << "]"<< std::endl;); o.ebits = ebits; @@ -211,45 +211,45 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode std::string f, e; f = (e_pos != std::string::npos) ? v.substr(0, e_pos) : v; - e = (e_pos != std::string::npos) ? v.substr(e_pos+1) : "0"; + e = (e_pos != std::string::npos) ? v.substr(e_pos+1) : "0"; - TRACE("mpf_dbg", tout << " f = " << f << " e = " << e << std::endl;); + TRACE("mpf_dbg", tout << " f = " << f << " e = " << e << std::endl;); - scoped_mpq q(m_mpq_manager); + scoped_mpq q(m_mpq_manager); m_mpq_manager.set(q, f.c_str()); scoped_mpz ex(m_mpq_manager); m_mpz_manager.set(ex, e.c_str()); - set(o, ebits, sbits, rm, q, ex); + set(o, ebits, sbits, rm, ex, q); TRACE("mpf_dbg", tout << "set: res = " << to_string(o) << std::endl;); } -void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpq const & significand, mpz const & exponent) { +void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpz const & exponent, mpq const & significand) { // Assumption: this represents significand * 2^exponent. TRACE("mpf_dbg", tout << "set: sig = " << m_mpq_manager.to_string(significand) << " exp = " << m_mpz_manager.to_string(exponent) << std::endl;); o.ebits = ebits; o.sbits = sbits; - o.sign = m_mpq_manager.is_neg(significand); - + o.sign = m_mpq_manager.is_neg(significand); + if (m_mpq_manager.is_zero(significand)) mk_zero(ebits, sbits, o.sign, o); - else { + else { scoped_mpq sig(m_mpq_manager); scoped_mpz exp(m_mpq_manager); m_mpq_manager.set(sig, significand); m_mpq_manager.abs(sig); - m_mpz_manager.set(exp, exponent); - + m_mpz_manager.set(exp, exponent); + // Normalize while (m_mpq_manager.ge(sig, 2)) { m_mpq_manager.div(sig, mpq(2), sig); m_mpz_manager.inc(exp); } - + while (m_mpq_manager.lt(sig, 1)) { m_mpq_manager.mul(sig, 2, sig); m_mpz_manager.dec(exp); @@ -257,9 +257,9 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode // 1.0 <= sig < 2.0 SASSERT((m_mpq_manager.le(1, sig) && m_mpq_manager.lt(sig, 2))); - - TRACE("mpf_dbg", tout << "sig = " << m_mpq_manager.to_string(sig) << - " exp = " << m_mpz_manager.to_string(exp) << std::endl;); + + TRACE("mpf_dbg", tout << "sig = " << m_mpq_manager.to_string(sig) << + " exp = " << m_mpz_manager.to_string(exp) << std::endl;); m_mpz_manager.set(o.significand, 0); for (unsigned i = 0; i < (sbits+3); i++) { @@ -273,11 +273,11 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode // sticky if (!m_mpq_manager.is_zero(sig) && m_mpz_manager.is_even(o.significand)) - m_mpz_manager.inc(o.significand); + m_mpz_manager.inc(o.significand); - TRACE("mpf_dbg", tout << "sig = " << m_mpz_manager.to_string(o.significand) << + TRACE("mpf_dbg", tout << "sig = " << m_mpz_manager.to_string(o.significand) << " exp = " << o.exponent << std::endl;); - + if (m_mpz_manager.is_small(exp)) { o.exponent = m_mpz_manager.get_int64(exp); round(rm, o); @@ -285,26 +285,26 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode else mk_inf(ebits, sbits, o.sign, o); } - + TRACE("mpf_dbg", tout << "set: res = " << to_string(o) << std::endl;); } -void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, bool sign, uint64 significand, mpf_exp_t exponent) { +void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exponent, uint64 significand) { // Assumption: this represents (sign * -1) * (significand/2^sbits) * 2^exponent. o.ebits = ebits; o.sbits = sbits; o.sign = sign; - m_mpz_manager.set(o.significand, significand); + m_mpz_manager.set(o.significand, significand); o.exponent = exponent; - DEBUG_CODE({ + DEBUG_CODE({ SASSERT(m_mpz_manager.lt(o.significand, m_powers2(sbits-1))); SASSERT(o.exponent <= mk_top_exp(ebits)); SASSERT(o.exponent >= mk_bot_exp(ebits)); }); } -void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpz const & significand, mpf_exp_t exponent) { +void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exponent, mpz const & significand) { // Assumption: this represents (sign * -1) * (significand/2^sbits) * 2^exponent. o.ebits = ebits; o.sbits = sbits; @@ -328,14 +328,14 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode mk_inf(ebits, sbits, x.sign, o); else if (is_zero(x)) mk_zero(ebits, sbits, x.sign, o); - else if (x.ebits == ebits && x.sbits == sbits) + else if (x.ebits == ebits && x.sbits == sbits) set(o, x); else { set(o, x); unpack(o, true); o.ebits = ebits; - o.sbits = sbits; + o.sbits = sbits; signed ds = sbits - x.sbits + 3; // plus rounding bits if (ds > 0) @@ -349,12 +349,12 @@ void mpf_manager::set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode while (ds < 0) { sticky |= m_mpz_manager.is_odd(o.significand); - m_mpz_manager.machine_div2k(o.significand, 1); + m_mpz_manager.machine_div2k(o.significand, 1); ds++; } if (sticky && m_mpz_manager.is_even(o.significand)) m_mpz_manager.inc(o.significand); - round(rm, o); + round(rm, o); } } } @@ -374,7 +374,7 @@ void mpf_manager::neg(mpf & o) { } void mpf_manager::neg(mpf const & x, mpf & o) { - set(o, x); + set(o, x); neg(o); } @@ -391,9 +391,9 @@ bool mpf_manager::is_neg(mpf const & x) { } bool mpf_manager::is_pos(mpf const & x) { - return !x.sign && !is_nan(x); + return !x.sign && !is_nan(x); } - + bool mpf_manager::is_nzero(mpf const & x) { return x.sign && is_zero(x); } @@ -423,17 +423,17 @@ bool mpf_manager::lt(mpf const & x, mpf const & y) { else if (sgn(x)) { if (!sgn(y)) return true; - else - return exp(y) < exp(x) || + else + return exp(y) < exp(x) || (exp(y) == exp(x) && m_mpz_manager.lt(sig(y), sig(x))); } else { // !sgn(x) if (sgn(y)) return false; - else - return exp(x) < exp(y) || + else + return exp(x) < exp(y) || (exp(x)==exp(y) && m_mpz_manager.lt(sig(x), sig(y))); - } + } } bool mpf_manager::lte(mpf const & x, mpf const & y) { @@ -466,7 +466,7 @@ void mpf_manager::sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & void mpf_manager::add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o, bool sub) { SASSERT(x.sbits == y.sbits && x.ebits == y.ebits); - + bool sgn_y = sgn(y) ^ sub; if (is_nan(x)) @@ -486,9 +486,9 @@ void mpf_manager::add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mp set(o, y); o.sign = sgn_y; } - } + } else if (is_zero(x) && is_zero(y)) { - if ((x.sign && sgn_y) || + if ((x.sign && sgn_y) || ((rm == MPF_ROUND_TOWARD_NEGATIVE) && (x.sign != sgn_y))) mk_nzero(x.ebits, x.sbits, o); else @@ -506,7 +506,7 @@ void mpf_manager::add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mp SASSERT(is_normal(x) || is_denormal(x)); SASSERT(is_normal(y) || is_denormal(y)); - + scoped_mpf a(*this), b(*this); set(a, x); set(b, y); @@ -515,21 +515,21 @@ void mpf_manager::add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mp // Unpack a/b, this inserts the hidden bit and adjusts the exponent. unpack(a, false); unpack(b, false); - + if (exp(b) > exp(a)) a.swap(b); - mpf_exp_t exp_delta = exp(a) - exp(b); + mpf_exp_t exp_delta = exp(a) - exp(b); SASSERT(exp(a) >= exp(b)); SASSERT(exp_delta >= 0); if (exp_delta > x.sbits+2) exp_delta = x.sbits+2; - + TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); TRACE("mpf_dbg", tout << "B = " << to_string(b) << std::endl;); - TRACE("mpf_dbg", tout << "d = " << exp_delta << std::endl;); + TRACE("mpf_dbg", tout << "d = " << exp_delta << std::endl;); // Introduce 3 extra bits into both numbers. m_mpz_manager.mul2k(a.significand(), 3, a.significand()); @@ -553,14 +553,14 @@ void mpf_manager::add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mp else { TRACE("mpf_dbg", tout << "ADDING" << std::endl;); m_mpz_manager.add(a.significand(), b.significand(), o.significand); - } - - TRACE("mpf_dbg", tout << "sum[-2:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl;); + } + + TRACE("mpf_dbg", tout << "sum[-2:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl;); if (m_mpz_manager.is_zero(o.significand)) mk_zero(o.ebits, o.sbits, rm == MPF_ROUND_TOWARD_NEGATIVE, o); else { - bool neg = m_mpz_manager.is_neg(o.significand); + bool neg = m_mpz_manager.is_neg(o.significand); TRACE("mpf_dbg", tout << "NEG=" << neg << std::endl;); m_mpz_manager.abs(o.significand); TRACE("mpf_dbg", tout << "fs[-1:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl;); @@ -589,7 +589,7 @@ void mpf_manager::mul(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & else if (is_pinf(x)) { if (is_zero(y)) mk_nan(x.ebits, x.sbits, o); - else + else mk_inf(x.ebits, x.sbits, y.sign, o); } else if (is_pinf(y)) { @@ -601,7 +601,7 @@ void mpf_manager::mul(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & else if (is_ninf(x)) { if (is_zero(y)) mk_nan(x.ebits, x.sbits, o); - else + else mk_inf(x.ebits, x.sbits, !y.sign, o); } else if (is_ninf(y)) { @@ -626,7 +626,7 @@ void mpf_manager::mul(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); TRACE("mpf_dbg", tout << "B = " << to_string(b) << std::endl;); - + o.exponent = a.exponent() + b.exponent(); TRACE("mpf_dbg", tout << "A' = " << m_mpz_manager.to_string(a.significand()) << std::endl;); @@ -670,8 +670,8 @@ void mpf_manager::div(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & else if (is_pinf(y)) { if (is_inf(x)) mk_nan(x.ebits, x.sbits, o); - else - mk_zero(x.ebits, x.sbits, x.sign != y.sign, o); + else + mk_zero(x.ebits, x.sbits, x.sign != y.sign, o); } else if (is_ninf(x)) { if (is_inf(y)) @@ -682,7 +682,7 @@ void mpf_manager::div(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & else if (is_ninf(y)) { if (is_inf(x)) mk_nan(x.ebits, x.sbits, o); - else + else mk_zero(x.ebits, x.sbits, x.sign != y.sign, o); } else if (is_zero(y)) { @@ -699,7 +699,7 @@ void mpf_manager::div(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o.ebits = x.ebits; o.sbits = x.sbits; o.sign = x.sign ^ y.sign; - + scoped_mpf a(*this), b(*this); set(a, x); set(b, y); @@ -708,12 +708,12 @@ void mpf_manager::div(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); TRACE("mpf_dbg", tout << "B = " << to_string(b) << std::endl;); - + o.exponent = a.exponent() - b.exponent(); TRACE("mpf_dbg", tout << "A' = " << m_mpz_manager.to_string(a.significand()) << std::endl;); TRACE("mpf_dbg", tout << "B' = " << m_mpz_manager.to_string(b.significand()) << std::endl;); - + unsigned extra_bits = x.sbits + 2; m_mpz_manager.mul2k(a.significand(), x.sbits + extra_bits); m_mpz_manager.machine_div(a.significand(), b.significand(), o.significand); @@ -741,7 +741,7 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co TRACE("mpf_dbg", tout << "Z = " << to_string(z) << std::endl;); if (is_nan(x) || is_nan(y) || is_nan(z)) - mk_nan(x.ebits, x.sbits, o); + mk_nan(x.ebits, x.sbits, o); else if (is_pinf(x)) { if (is_zero(y)) mk_nan(x.ebits, x.sbits, o); @@ -773,7 +773,7 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co mk_nan(x.ebits, x.sbits, o); else mk_inf(x.ebits, x.sbits, !x.sign, o); - } + } else if (is_inf(z)) { set(o, z); } @@ -785,7 +785,7 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co } else { o.ebits = x.ebits; - o.sbits = x.sbits; + o.sbits = x.sbits; scoped_mpf mul_res(*this, x.ebits+2, 2*x.sbits); scoped_mpf a(*this, x.ebits, x.sbits), b(*this, x.ebits, x.sbits), c(*this, x.ebits, x.sbits); @@ -794,7 +794,7 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co set(c, z); unpack(a, true); unpack(b, true); - unpack(c, true); + unpack(c, true); TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); TRACE("mpf_dbg", tout << "B = " << to_string(b) << std::endl;); @@ -804,13 +804,13 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co SASSERT(m_mpz_manager.lt(b.significand(), m_powers2(x.sbits))); SASSERT(m_mpz_manager.lt(c.significand(), m_powers2(x.sbits))); SASSERT(m_mpz_manager.ge(a.significand(), m_powers2(x.sbits-1))); - SASSERT(m_mpz_manager.ge(b.significand(), m_powers2(x.sbits-1))); + SASSERT(m_mpz_manager.ge(b.significand(), m_powers2(x.sbits-1))); mul_res.get().sign = (a.sign() != b.sign()); mul_res.get().exponent = a.exponent() + b.exponent(); m_mpz_manager.mul(a.significand(), b.significand(), mul_res.get().significand); - TRACE("mpf_dbg", tout << "PRODUCT = " << to_string(mul_res) << std::endl;); + TRACE("mpf_dbg", tout << "PRODUCT = " << to_string(mul_res) << std::endl;); // mul_res is [-1][0].[2*sbits - 2], i.e., between 2*sbits-1 and 2*sbits. SASSERT(m_mpz_manager.lt(mul_res.significand(), m_powers2(2*x.sbits))); @@ -820,7 +820,7 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co m_mpz_manager.mul2k(c.significand(), x.sbits-1, c.significand()); SASSERT(m_mpz_manager.lt(c.significand(), m_powers2(2 * x.sbits - 1))); - SASSERT(m_mpz_manager.is_zero(c.significand()) || + SASSERT(m_mpz_manager.is_zero(c.significand()) || m_mpz_manager.ge(c.significand(), m_powers2(2 * x.sbits - 2))); TRACE("mpf_dbg", tout << "C = " << to_string(c) << std::endl;); @@ -839,7 +839,7 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co // Alignment shift with sticky bit computation. scoped_mpz sticky_rem(m_mpz_manager); m_mpz_manager.machine_div_rem(c.significand(), m_powers2((int)exp_delta), c.significand(), sticky_rem); - TRACE("mpf_dbg", tout << "alignment shift -> sig = " << m_mpz_manager.to_string(c.significand()) << + TRACE("mpf_dbg", tout << "alignment shift -> sig = " << m_mpz_manager.to_string(c.significand()) << " sticky_rem = " << m_mpz_manager.to_string(sticky_rem) << std::endl;); if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(c.significand())) m_mpz_manager.inc(c.significand()); @@ -855,51 +855,51 @@ void mpf_manager::fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf co else { TRACE("mpf_dbg", tout << "ADDING" << std::endl;); m_mpz_manager.add(mul_res.significand(), c.significand(), o.significand); - } + } TRACE("mpf_dbg", tout << "sum[-1:] = " << m_mpz_manager.to_string(o.significand) << std::endl;); bool neg = m_mpz_manager.is_neg(o.significand); TRACE("mpf_dbg", tout << "NEG=" << neg << std::endl;); if (neg) m_mpz_manager.abs(o.significand); - + o.exponent = mul_res.exponent(); - + unsigned extra = 0; // Result could overflow into 4.xxx ... SASSERT(m_mpz_manager.lt(o.significand, m_powers2(2 * x.sbits + 2))); - if(m_mpz_manager.ge(o.significand, m_powers2(2 * x.sbits + 1))) + if(m_mpz_manager.ge(o.significand, m_powers2(2 * x.sbits + 1))) { extra++; o.exponent++; TRACE("mpf_dbg", tout << "Addition overflew!" << std::endl;); - } + } - // Remove the extra bits, keeping a sticky bit. + // Remove the extra bits, keeping a sticky bit. m_mpz_manager.set(sticky_rem, 0); unsigned minbits = (4 + extra); if (o.sbits >= minbits) m_mpz_manager.machine_div_rem(o.significand, m_powers2(o.sbits - minbits), o.significand, sticky_rem); else m_mpz_manager.mul2k(o.significand, minbits - o.sbits, o.significand); - + if (!m_mpz_manager.is_zero(sticky_rem) && m_mpz_manager.is_even(o.significand)) m_mpz_manager.inc(o.significand); - + TRACE("mpf_dbg", tout << "sum[-1:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl;); if (m_mpz_manager.is_zero(o.significand)) mk_zero(x.ebits, x.sbits, rm == MPF_ROUND_TOWARD_NEGATIVE, o); - else { + else { o.sign = ((!mul_res.sign() && c.sign() && neg) || ( mul_res.sign() && !c.sign() && !neg) || - ( mul_res.sign() && c.sign())); + ( mul_res.sign() && c.sign())); TRACE("mpf_dbg", tout << "before round = " << to_string(o) << std::endl << "fs[-1:sbits+2] = " << m_mpz_manager.to_string(o.significand) << std::endl;); round(rm, o); } } - + } void my_mpz_sqrt(unsynch_mpz_manager & m, unsigned sbits, bool odd_exp, mpz & in, mpz & o) { @@ -907,10 +907,10 @@ void my_mpz_sqrt(unsynch_mpz_manager & m, unsigned sbits, bool odd_exp, mpz & in scoped_mpz mid(m), product(m), diff(m); // we have lower <= a.significand <= upper and we need 1.[52+3 bits] in the bounds. // since we comapre upper*upper to a.significand further down, we need a.significand - // to be of twice the size. + // to be of twice the size. m.set(lower, 1); m.mul2k(lower, sbits+2-1); - + if (odd_exp) m.mul2k(in, 4, upper); else @@ -920,7 +920,7 @@ void my_mpz_sqrt(unsynch_mpz_manager & m, unsigned sbits, bool odd_exp, mpz & in m.set(o, lower); while (m.neq(lower, upper)) { - STRACE("mpf_dbg", tout << "SIG = " << m.to_string(in) << + STRACE("mpf_dbg", tout << "SIG = " << m.to_string(in) << " LOWER = " << m.to_string(lower) << " UPPER = " << m.to_string(upper) << std::endl;); m.sub(upper, lower, diff); @@ -934,14 +934,14 @@ void my_mpz_sqrt(unsynch_mpz_manager & m, unsigned sbits, bool odd_exp, mpz & in STRACE("mpf_dbg", tout << "choosing upper" << std::endl;); m.set(o, upper); // chosing upper is like a sticky bit here. } - break; + break; } m.add(lower, upper, mid); m.machine_div2k(mid, 1); m.mul(mid, mid, product); - STRACE("mpf_dbg", tout << "MID = " << m.to_string(mid) << + STRACE("mpf_dbg", tout << "MID = " << m.to_string(mid) << " PROD = " << m.to_string(product) << std::endl;); if (m.lt(product, in)) @@ -953,7 +953,7 @@ void my_mpz_sqrt(unsynch_mpz_manager & m, unsigned sbits, bool odd_exp, mpz & in m.set(o, mid); break; } - } + } } void mpf_manager::sqrt(mpf_rounding_mode rm, mpf const & x, mpf & o) { @@ -980,13 +980,13 @@ void mpf_manager::sqrt(mpf_rounding_mode rm, mpf const & x, mpf & o) { TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); - m_mpz_manager.mul2k(a.significand(), x.sbits + ((a.exponent() % 2)?6:7)); + m_mpz_manager.mul2k(a.significand(), x.sbits + ((a.exponent() % 2)?6:7)); if (!m_mpz_manager.root(a.significand(), 2, o.significand)) { // If the result is inexact, it is 1 too large. // We need a sticky bit in the last position here, so we fix that. if (m_mpz_manager.is_even(o.significand)) - m_mpz_manager.dec(o.significand); + m_mpz_manager.dec(o.significand); TRACE("mpf_dbg", tout << "dec'ed " << m_mpz_manager.to_string(o.significand) << std::endl;); } o.exponent = a.exponent() >> 1; @@ -1058,21 +1058,21 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o o.exponent = a.exponent(); m_mpz_manager.set(o.significand, a.significand()); - + unsigned shift = (o.sbits - 1) - ((unsigned)o.exponent); const mpz & shift_p = m_powers2(shift); TRACE("mpf_dbg", tout << "shift=" << shift << std::endl;); - + scoped_mpz div(m_mpz_manager), rem(m_mpz_manager); m_mpz_manager.machine_div_rem(o.significand, shift_p, div, rem); - TRACE("mpf_dbg", tout << "div=" << m_mpz_manager.to_string(div) << " rem=" << m_mpz_manager.to_string(rem) << std::endl;); + TRACE("mpf_dbg", tout << "div=" << m_mpz_manager.to_string(div) << " rem=" << m_mpz_manager.to_string(rem) << std::endl;); const mpz & shift_p1 = m_powers2(shift-1); TRACE("mpf_dbg", tout << "shift_p1=" << m_mpz_manager.to_string(shift_p1) << std::endl;); switch (rm) { case MPF_ROUND_NEAREST_TEVEN: - case MPF_ROUND_NEAREST_TAWAY: { + case MPF_ROUND_NEAREST_TAWAY: { bool tie = m_mpz_manager.eq(rem, shift_p1); bool less_than_tie = m_mpz_manager.lt(rem, shift_p1); bool more_than_tie = m_mpz_manager.gt(rem, shift_p1); @@ -1085,7 +1085,7 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o } } else { - SASSERT(less_than_tie || more_than_tie); + SASSERT(less_than_tie || more_than_tie); if (more_than_tie) { m_mpz_manager.inc(div); TRACE("mpf_dbg", tout << "div++ (2)" << std::endl;); @@ -1105,7 +1105,7 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o default: /* nothing */; } - + m_mpz_manager.mul2k(div, shift, o.significand); SASSERT(m_mpz_manager.ge(o.significand, m_powers2(o.sbits - 1))); @@ -1122,7 +1122,7 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o } void mpf_manager::to_mpz(mpf const & x, unsynch_mpz_manager & zm, mpz & o) { - // x is assumed to be unpacked. + // x is assumed to be unpacked. SASSERT(x.exponent < INT_MAX); zm.set(o, x.significand); @@ -1145,11 +1145,11 @@ void mpf_manager::to_sbv_mpq(mpf_rounding_mode rm, const mpf & x, scoped_mpq & o SASSERT(t.exponent() < INT_MAX); - m_mpz_manager.set(z, t.significand()); + m_mpz_manager.set(z, t.significand()); mpf_exp_t e = (mpf_exp_t)t.exponent() - t.sbits() + 1; if (e < 0) { bool last = false, round = false, sticky = m_mpz_manager.is_odd(z); - for (; e != 0; e++) { + for (; e != 0; e++) { m_mpz_manager.machine_div2k(z, 1); sticky |= round; round = last; @@ -1176,7 +1176,7 @@ void mpf_manager::to_sbv_mpq(mpf_rounding_mode rm, const mpf & x, scoped_mpq & o void mpf_manager::to_ieee_bv_mpz(const mpf & x, scoped_mpz & o) { SASSERT(!is_nan(x) && !is_inf(x)); SASSERT(exp(x) < INT_MAX); - + unsigned sbits = x.get_sbits(); unsigned ebits = x.get_ebits(); scoped_mpz biased_exp(m_mpz_manager); @@ -1196,15 +1196,15 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { if (is_nan(x) || is_nan(y)) mk_nan(x.ebits, x.sbits, o); - else if (is_inf(x)) + else if (is_inf(x)) mk_nan(x.ebits, x.sbits, o); else if (is_inf(y)) set(o, x); else if (is_zero(y)) mk_nan(x.ebits, x.sbits, o); - else if (is_zero(x)) - set(o, x); - else { + else if (is_zero(x)) + set(o, x); + else { o.ebits = x.ebits; o.sbits = x.sbits; o.sign = x.sign; @@ -1217,20 +1217,20 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) { TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;); TRACE("mpf_dbg", tout << "B = " << to_string(b) << std::endl;); - + if (a.exponent() < b.exponent()) set(o, x); - else { + else { mpf_exp_t exp_diff = a.exponent() - b.exponent(); SASSERT(exp_diff >= 0); TRACE("mpf_dbg", tout << "exp_diff = " << exp_diff << std::endl;); SASSERT(exp_diff < INT_MAX); // CMW: This requires rather a lot of memory. There are algorithms that trade space for time by - // computing only a small chunk of the remainder bits at a time. + // computing only a small chunk of the remainder bits at a time. unsigned extra_bits = (unsigned) exp_diff; m_mpz_manager.mul2k(a.significand(), extra_bits); - m_mpz_manager.rem(a.significand(), b.significand(), o.significand); + m_mpz_manager.rem(a.significand(), b.significand(), o.significand); TRACE("mpf_dbg", tout << "REM' = " << to_string(o) << std::endl;); @@ -1252,11 +1252,11 @@ void mpf_manager::maximum(mpf const & x, mpf const & y, mpf & o) { set(o, y); else if (is_nan(y)) set(o, x); - else if (is_zero(x) && is_zero(y) && sgn(x) != sgn(y)) { - UNREACHABLE(); // max(+0, -0) and max(-0, +0) are unspecified. + else if (is_zero(x) && is_zero(y) && sgn(x) != sgn(y)) { + UNREACHABLE(); // max(+0, -0) and max(-0, +0) are unspecified. } else if (is_zero(x) && is_zero(y)) - set(o, y); + set(o, y); else if (gt(x, y)) set(o, x); else @@ -1269,10 +1269,10 @@ void mpf_manager::minimum(mpf const & x, mpf const & y, mpf & o) { else if (is_nan(y)) set(o, x); else if (is_zero(x) && is_zero(y) && sgn(x) != sgn(y)) { - UNREACHABLE(); // min(+0, -0) and min(-0, +0) are unspecified. - } + UNREACHABLE(); // min(+0, -0) and min(-0, +0) are unspecified. + } else if (is_zero(x) && is_zero(y)) - set(o, y); + set(o, y); else if (lt(x, y)) set(o, x); else @@ -1282,12 +1282,12 @@ void mpf_manager::minimum(mpf const & x, mpf const & y, mpf & o) { std::string mpf_manager::to_string(mpf const & x) { std::string res; - if (is_nan(x)) + if (is_nan(x)) res = "NaN"; - else { + else { if (is_inf(x)) res = sgn(x) ? "-oo" : "+oo"; - else if (is_zero(x)) + else if (is_zero(x)) res = sgn(x) ? "-zero" : "+zero"; else { res = sgn(x) ? "-" : ""; @@ -1295,8 +1295,8 @@ std::string mpf_manager::to_string(mpf const & x) { num = 0; denom = 1; mpf_exp_t exponent; - - if (is_denormal(x)) + + if (is_denormal(x)) exponent = mk_min_exp(x.ebits); else { m_mpz_manager.set(num, 1); @@ -1306,7 +1306,7 @@ std::string mpf_manager::to_string(mpf const & x) { m_mpz_manager.add(num, sig(x), num); m_mpz_manager.mul2k(denom, x.sbits-1, denom); - + //TRACE("mpf_dbg", tout << "SIG=" << m_mpq_manager.to_string(sig(x)) << std::endl; ); //TRACE("mpf_dbg", tout << "NUM=" << m_mpq_manager.to_string(num) << std::endl;); //TRACE("mpf_dbg", tout << "DEN=" << m_mpq_manager.to_string(denom) << std::endl;); @@ -1321,7 +1321,7 @@ std::string mpf_manager::to_string(mpf const & x) { if (m_mpq_manager.is_int(r)) ss << ".0"; ss << " " << exponent; - res += ss.str(); + res += ss.str(); } } @@ -1354,7 +1354,7 @@ std::string mpf_manager::to_string_raw(mpf const & x) { std::string res; res += "["; res += (x.sign?"-":"+"); - res += " "; + res += " "; res += m_mpz_manager.to_string(sig(x)); res += " "; std::stringstream ss(""); @@ -1362,7 +1362,7 @@ std::string mpf_manager::to_string_raw(mpf const & x) { res += ss.str(); if (is_normal(x)) res += " N"; - else + else res += " D"; res += "]"; return res; @@ -1373,21 +1373,21 @@ void mpf_manager::to_rational(mpf const & x, unsynch_mpq_manager & qm, mpq & o) scoped_mpz n(m_mpq_manager), d(m_mpq_manager); set(a, x); unpack(a, true); - - m_mpz_manager.set(n, a.significand()); + + m_mpz_manager.set(n, a.significand()); if (a.sign()) m_mpz_manager.neg(n); m_mpz_manager.power(2, a.sbits() - 1, d); if (a.exponent() >= 0) m_mpz_manager.mul2k(n, (unsigned)a.exponent()); - else + else m_mpz_manager.mul2k(d, (unsigned)-a.exponent()); - qm.set(o, n, d); + qm.set(o, n, d); } double mpf_manager::to_double(mpf const & x) { SASSERT(x.ebits <= 11 && x.sbits <= 53); - uint64 raw = 0; + uint64 raw = 0; int64 sig = 0, exp = 0; sig = m_mpz_manager.get_uint64(x.significand); @@ -1397,14 +1397,14 @@ double mpf_manager::to_double(mpf const & x) { exp = 1024; else if (has_bot_exp(x)) exp = -1023; - else + else exp = x.exponent; - + exp += 1023; raw = (exp << 52) | sig; - if (x.sign) + if (x.sign) raw = raw | 0x8000000000000000ull; double ret; @@ -1431,8 +1431,8 @@ float mpf_manager::to_float(mpf const & x) { SASSERT(q < 4294967296ll); exp = q & 0x00000000FFFFFFFF; } - - exp += 127; + + exp += 127; raw = (exp << 23) | sig; @@ -1482,7 +1482,7 @@ bool mpf_manager::is_int(mpf const & x) { scoped_mpz t(m_mpz_manager); m_mpz_manager.set(t, sig(x)); - unsigned shift = x.sbits - ((unsigned)exp(x)) - 1; + unsigned shift = x.sbits - ((unsigned)exp(x)) - 1; do { if (m_mpz_manager.is_odd(t)) return false; @@ -1508,7 +1508,7 @@ mpf_exp_t mpf_manager::mk_bot_exp(unsigned ebits) { } mpf_exp_t mpf_manager::mk_top_exp(unsigned ebits) { - SASSERT(ebits >= 2); + SASSERT(ebits >= 2); return m_mpz_manager.get_int64(m_powers2(ebits-1)); } @@ -1519,7 +1519,7 @@ mpf_exp_t mpf_manager::mk_min_exp(unsigned ebits) { } mpf_exp_t mpf_manager::mk_max_exp(unsigned ebits) { - SASSERT(ebits > 0); + SASSERT(ebits > 0); return m_mpz_manager.get_int64(m_powers2.m1(ebits-1, false)); } @@ -1547,8 +1547,8 @@ void mpf_manager::mk_pzero(unsigned ebits, unsigned sbits, mpf & o) { } void mpf_manager::mk_zero(unsigned ebits, unsigned sbits, bool sign, mpf & o) { - if (sign) - mk_nzero(ebits, sbits, o); + if (sign) + mk_nzero(ebits, sbits, o); else mk_pzero(ebits, sbits, o); } @@ -1557,7 +1557,7 @@ void mpf_manager::mk_nan(unsigned ebits, unsigned sbits, mpf & o) { o.sbits = sbits; o.ebits = ebits; o.exponent = mk_top_exp(ebits); - // This is a quiet NaN, i.e., the first bit should be 1. + // This is a quiet NaN, i.e., the first bit should be 1. m_mpz_manager.set(o.significand, m_powers2(sbits-1)); m_mpz_manager.dec(o.significand); o.sign = false; @@ -1574,7 +1574,7 @@ void mpf_manager::mk_one(unsigned ebits, unsigned sbits, bool sign, mpf & o) con void mpf_manager::mk_max_value(unsigned ebits, unsigned sbits, bool sign, mpf & o) { o.sbits = sbits; o.ebits = ebits; - o.sign = sign; + o.sign = sign; o.exponent = mk_top_exp(ebits) - 1; m_mpz_manager.set(o.significand, m_powers2.m1(sbits-1, false)); } @@ -1584,7 +1584,7 @@ void mpf_manager::mk_inf(unsigned ebits, unsigned sbits, bool sign, mpf & o) { o.ebits = ebits; o.sign = sign; o.exponent = mk_top_exp(ebits); - m_mpz_manager.set(o.significand, 0); + m_mpz_manager.set(o.significand, 0); } void mpf_manager::mk_pinf(unsigned ebits, unsigned sbits, mpf & o) { @@ -1596,14 +1596,14 @@ void mpf_manager::mk_ninf(unsigned ebits, unsigned sbits, mpf & o) { } void mpf_manager::unpack(mpf & o, bool normalize) { - TRACE("mpf_dbg", tout << "unpack " << to_string(o) << ": ebits=" << - o.ebits << " sbits=" << o.sbits << - " normalize=" << normalize << - " has_top_exp=" << has_top_exp(o) << " (" << mk_top_exp(o.ebits) << ")" << + TRACE("mpf_dbg", tout << "unpack " << to_string(o) << ": ebits=" << + o.ebits << " sbits=" << o.sbits << + " normalize=" << normalize << + " has_top_exp=" << has_top_exp(o) << " (" << mk_top_exp(o.ebits) << ")" << " has_bot_exp=" << has_bot_exp(o) << " (" << mk_bot_exp(o.ebits) << ")" << " is_zero=" << is_zero(o) << std::endl;); - // Insert the hidden bit or adjust the exponent of denormal numbers. + // Insert the hidden bit or adjust the exponent of denormal numbers. if (is_zero(o)) return; @@ -1612,13 +1612,13 @@ void mpf_manager::unpack(mpf & o, bool normalize) { else { o.exponent = mk_bot_exp(o.ebits) + 1; if (normalize && !m_mpz_manager.is_zero(o.significand)) { - const mpz & p = m_powers2(o.sbits-1); + const mpz & p = m_powers2(o.sbits-1); while (m_mpz_manager.gt(p, o.significand)) { o.exponent--; m_mpz_manager.mul2k(o.significand, 1, o.significand); } } - } + } } void mpf_manager::mk_round_inf(mpf_rounding_mode rm, mpf & o) { @@ -1632,12 +1632,12 @@ void mpf_manager::mk_round_inf(mpf_rounding_mode rm, mpf & o) { if (rm == MPF_ROUND_TOWARD_ZERO || rm == MPF_ROUND_TOWARD_POSITIVE) mk_max_value(o.ebits, o.sbits, o.sign, o); else - mk_inf(o.ebits, o.sbits, o.sign, o); + mk_inf(o.ebits, o.sbits, o.sign, o); } } void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { - // Assumptions: o.significand is of the form f[-1:0] . f[1:sbits-1] [guard,round,sticky], + // Assumptions: o.significand is of the form f[-1:0] . f[1:sbits-1] [guard,round,sticky], // i.e., it has 2 + (sbits-1) + 3 = sbits + 4 bits. TRACE("mpf_dbg", tout << "RND: " << to_string(o) << std::endl;); @@ -1655,16 +1655,16 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { mpf_exp_t e_max_norm = mk_max_exp(o.ebits); mpf_exp_t e_min_norm = mk_min_exp(o.ebits); - scoped_mpz temporary(m_mpq_manager); + scoped_mpz temporary(m_mpq_manager); TRACE("mpf_dbg", tout << "e_min_norm = " << e_min_norm << std::endl << - "e_max_norm = " << e_max_norm << std::endl;); + "e_max_norm = " << e_max_norm << std::endl;); const mpz & p_m1 = m_powers2(o.sbits+2); - const mpz & p_m2 = m_powers2(o.sbits+3); - + const mpz & p_m2 = m_powers2(o.sbits+3); + TRACE("mpf_dbg", tout << "p_m1 = " << m_mpz_manager.to_string(p_m1) << std::endl << - "p_m2 = " << m_mpz_manager.to_string(p_m2) << std::endl;); + "p_m2 = " << m_mpz_manager.to_string(p_m2) << std::endl;); bool OVF1 = o.exponent > e_max_norm || // Exponent OVF (o.exponent == e_max_norm && m_mpz_manager.ge(o.significand, p_m2)); @@ -1672,7 +1672,7 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { TRACE("mpf_dbg", tout << "OVF1 = " << OVF1 << std::endl;); int lz = 0; - scoped_mpz t(m_mpq_manager); + scoped_mpz t(m_mpq_manager); m_mpz_manager.set(t, p_m2); while (m_mpz_manager.gt(t, o.significand)) { m_mpz_manager.machine_div2k(t, 1); @@ -1713,14 +1713,14 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { if (m_mpz_manager.lt(sigma, limit)) { m_mpz_manager.set(sigma, limit); } - - // Normalization shift + + // Normalization shift TRACE("mpf_dbg", tout << "Shift distance: " << m_mpz_manager.to_string(sigma) << " " << ((m_mpz_manager.is_nonneg(sigma))?"(LEFT)":"(RIGHT)") << std::endl;); bool sticky = !m_mpz_manager.is_even(o.significand); m_mpz_manager.machine_div2k(o.significand, 1); // Let f' = f_r/2 - + if (!m_mpz_manager.is_zero(sigma)) { if (m_mpz_manager.is_neg(sigma)) { // Right shift unsigned sigma_uint = (unsigned) -m_mpz_manager.get_int64(sigma); // sigma is capped, this is safe. @@ -1728,7 +1728,7 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { m_mpz_manager.machine_div2k(o.significand, sigma_uint); else { - scoped_mpz sticky_rem(m_mpz_manager); + scoped_mpz sticky_rem(m_mpz_manager); m_mpz_manager.machine_div_rem(o.significand, m_powers2(sigma_uint), o.significand, sticky_rem); sticky = !m_mpz_manager.is_zero(sticky_rem); } @@ -1744,7 +1744,7 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { // Make sure o.significand is a [sbits+2] bit number (i.e. f1[0:sbits+1] == f1[0:sbits-1][round][sticky]) sticky = sticky || !m_mpz_manager.is_even(o.significand); - m_mpz_manager.machine_div2k(o.significand, 1); + m_mpz_manager.machine_div2k(o.significand, 1); if (sticky && m_mpz_manager.is_even(o.significand)) m_mpz_manager.inc(o.significand); @@ -1762,12 +1762,12 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { o.exponent = beta; TRACE("mpf_dbg", tout << "Shifted: " << to_string(o) << std::endl;); - - const mpz & p_sig = m_powers2(o.sbits); + + const mpz & p_sig = m_powers2(o.sbits); SASSERT(TINY || (m_mpz_manager.ge(o.significand, p_sig))); // Significand rounding (sigrd) - + sticky = !m_mpz_manager.is_even(o.significand); // new sticky bit! m_mpz_manager.machine_div2k(o.significand, 1); bool round = !m_mpz_manager.is_even(o.significand); @@ -1778,7 +1778,7 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { TRACE("mpf_dbg", tout << "sign=" << o.sign << " last=" << last << " round=" << round << " sticky=" << sticky << std::endl;); TRACE("mpf_dbg", tout << "before rounding decision: " << to_string(o) << std::endl;); - // The significand has the right size now, but we might have to increment it + // The significand has the right size now, but we might have to increment it // depending on the sign, the last/round/sticky bits, and the rounding mode. bool inc = false; switch (rm) { @@ -1803,8 +1803,8 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { bool SIGovf = false; // Post normalization (post) - - if (m_mpz_manager.ge(o.significand, p_sig)) { + + if (m_mpz_manager.ge(o.significand, p_sig)) { m_mpz_manager.machine_div2k(o.significand, 1); o.exponent++; } @@ -1815,20 +1815,20 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { TRACE("mpf_dbg", tout << "Post-normalized: " << to_string(o) << std::endl;); TRACE("mpf_dbg", tout << "SIGovf = " << SIGovf << std::endl;); - + // Exponent rounding (exprd) bool o_has_max_exp = (o.exponent > e_max_norm); - bool OVF2 = SIGovf && o_has_max_exp; + bool OVF2 = SIGovf && o_has_max_exp; TRACE("mpf_dbg", tout << "OVF2 = " << OVF2 << std::endl;); TRACE("mpf_dbg", tout << "o_has_max_exp = " << o_has_max_exp << std::endl;); if (!OVFen && OVF2) mk_round_inf(rm, o); - else { + else { const mpz & p = m_powers2(o.sbits-1); - TRACE("mpf_dbg", tout << "P: " << m_mpz_manager.to_string(p_m1) << std::endl;); + TRACE("mpf_dbg", tout << "P: " << m_mpz_manager.to_string(p_m1) << std::endl;); if (m_mpz_manager.ge(o.significand, p)) { TRACE("mpf_dbg", tout << "NORMAL: " << m_mpz_manager.to_string(o.significand) << std::endl;); @@ -1838,13 +1838,13 @@ void mpf_manager::round(mpf_rounding_mode rm, mpf & o) { TRACE("mpf_dbg", tout << "DENORMAL: " << m_mpz_manager.to_string(o.significand) << std::endl;); o.exponent = mk_bot_exp(o.ebits); } - } + } TRACE("mpf_dbg", tout << "ROUNDED = " << to_string(o) << std::endl;); } -void mpf_manager::round_sqrt(mpf_rounding_mode rm, mpf & o) { - TRACE("mpf_dbg", tout << "RND-SQRT: " << to_string(o) << std::endl;); +void mpf_manager::round_sqrt(mpf_rounding_mode rm, mpf & o) { + TRACE("mpf_dbg", tout << "RND-SQRT: " << to_string(o) << std::endl;); bool sticky = !m_mpz_manager.is_even(o.significand); m_mpz_manager.machine_div2k(o.significand, 1); @@ -1858,7 +1858,7 @@ void mpf_manager::round_sqrt(mpf_rounding_mode rm, mpf & o) { // Specialized rounding for sqrt, as there are no negative cases (or half-way cases?) switch(rm) { - case MPF_ROUND_NEAREST_TEVEN: + case MPF_ROUND_NEAREST_TEVEN: case MPF_ROUND_NEAREST_TAWAY: inc = (round && sticky); break; case MPF_ROUND_TOWARD_NEGATIVE: break; case MPF_ROUND_TOWARD_ZERO: break; diff --git a/src/util/mpf.h b/src/util/mpf.h index 0e9d3e89c..80d3f4b47 100644 --- a/src/util/mpf.h +++ b/src/util/mpf.h @@ -37,7 +37,7 @@ typedef enum { typedef int64 mpf_exp_t; -class mpf { +class mpf { friend class mpf_manager; friend class scoped_mpf; unsigned ebits:15; @@ -47,11 +47,11 @@ class mpf { mpf_exp_t exponent; mpf & operator=(mpf const & other) { UNREACHABLE(); return *this; } void set(unsigned _ebits, unsigned _sbits); -public: +public: mpf(); mpf(unsigned ebits, unsigned sbits); mpf(mpf const & other); - ~mpf(); + ~mpf(); unsigned get_ebits() const { return ebits; } unsigned get_sbits() const { return sbits; } void swap(mpf & other); @@ -74,14 +74,14 @@ public: void set(mpf & o, unsigned ebits, unsigned sbits, double value); void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpq const & value); void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, char const * value); - void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpq const & significand, mpz const & exponent); - void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, uint64 significand, mpf_exp_t exponent); - void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpz const & significand, mpf_exp_t exponent); + void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpz const & exponent, mpq const & significand); + void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exponent, uint64 significand); + void set(mpf & o, unsigned ebits, unsigned sbits, bool sign, mpf_exp_t exponent, mpz const & significand); void set(mpf & o, mpf const & x); void set(mpf & o, unsigned ebits, unsigned sbits, mpf_rounding_mode rm, mpf const & x); void del(mpf & x) { - m_mpz_manager.del(x.significand); + m_mpz_manager.del(x.significand); } void abs(mpf & o); @@ -97,14 +97,14 @@ public: bool is_nzero(mpf const & x); bool is_pzero(mpf const & x); - + // structural eq bool eq_core(mpf const & x, mpf const & y) { - return - x.ebits == y.ebits && - x.sbits == y.sbits && - x.sign == y.sign && - m_mpz_manager.eq(x.significand, y.significand) && + return + x.ebits == y.ebits && + x.sbits == y.sbits && + x.sign == y.sign && + m_mpz_manager.eq(x.significand, y.significand) && x.exponent == y.exponent; } @@ -119,7 +119,7 @@ public: void add(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o); void sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o); void mul(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o); - void div(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o); + void div(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o); void fma(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf const &z, mpf & o); @@ -143,10 +143,10 @@ public: double to_double(mpf const & x); float to_float(mpf const & x); - + bool sgn(mpf const & x) const { return x.sign; } const mpz & sig(mpf const & x) const { return x.significand; } - void sig_normalized(mpf const & x, mpz & res) { + void sig_normalized(mpf const & x, mpz & res) { mpf t; set(t, x); unpack(t, true); @@ -154,7 +154,7 @@ public: del(t); } const mpf_exp_t & exp(mpf const & x) const { return x.exponent; } - mpf_exp_t exp_normalized(mpf const & x) { + mpf_exp_t exp_normalized(mpf const & x) { mpf t; set(t, x); unpack(t, true); @@ -186,9 +186,9 @@ public: unsynch_mpz_manager & mpz_manager(void) { return m_mpz_manager; } unsynch_mpq_manager & mpq_manager(void) { return m_mpq_manager; } - unsigned hash(mpf const & a) { - return hash_u_u(m_mpz_manager.hash(a.significand), - m_mpz_manager.hash(hash_ull(a.exponent))); + unsigned hash(mpf const & a) { + return hash_u_u(m_mpz_manager.hash(a.significand), + m_mpz_manager.hash(hash_ull(a.exponent))); } void mk_max_value(unsigned ebits, unsigned sbits, bool sign, mpf & o); @@ -202,7 +202,7 @@ public: /** \brief Return the biggest k s.t. 2^k <= a. - + \remark Return 0 if a is not positive. */ unsigned prev_power_of_two(mpf const & a); @@ -216,16 +216,16 @@ protected: bool has_bot_exp(mpf const & x); bool has_top_exp(mpf const & x); - void unpack(mpf & o, bool normalize); + void unpack(mpf & o, bool normalize); void add_sub(mpf_rounding_mode rm, mpf const & x, mpf const & y, mpf & o, bool sub); void round(mpf_rounding_mode rm, mpf & o); - void round_sqrt(mpf_rounding_mode rm, mpf & o); + void round_sqrt(mpf_rounding_mode rm, mpf & o); - void mk_round_inf(mpf_rounding_mode rm, mpf & o); + void mk_round_inf(mpf_rounding_mode rm, mpf & o); // Convert x into a mpz numeral. zm is the manager that owns o. void to_mpz(mpf const & x, unsynch_mpz_manager & zm, mpz & o); - void to_mpz(mpf const & x, scoped_mpz & o) { to_mpz(x, o.m(), o); } + void to_mpz(mpf const & x, scoped_mpz & o) { to_mpz(x, o.m(), o); } class powers2 { unsynch_mpz_manager & m; @@ -239,7 +239,7 @@ protected: dispose(m_p); dispose(m_pn); dispose(m_pm1); - dispose(m_pm1n); + dispose(m_pm1n); } void dispose(u_map & map) { @@ -275,7 +275,7 @@ protected: m.dec(*new_obj); if (negated) m.neg(*new_obj); return *new_obj; - } + } } }; From e6e6a6c5b3e1a2c397effa9b27df4ffcb9e2bacb Mon Sep 17 00:00:00 2001 From: Ken McMillan Date: Mon, 4 Jan 2016 12:53:46 -0800 Subject: [PATCH 57/87] issue #393 -- removed debugging assert --- src/interp/iz3translate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp index 0744ded49..ebb5e00c8 100755 --- a/src/interp/iz3translate.cpp +++ b/src/interp/iz3translate.cpp @@ -2023,8 +2023,8 @@ public: break; } default: - pfgoto(proof); - SASSERT(0 && "translate_main: unsupported proof rule"); + // pfgoto(proof); + // SASSERT(0 && "translate_main: unsupported proof rule"); throw unsupported(); } } From 05b29df2cb64ee388e0812d195b7a445f729a2b5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 4 Jan 2016 21:01:01 +0000 Subject: [PATCH 58/87] Bugfix for FP API --- src/api/api_fpa.cpp | 6 +++--- src/ast/rewriter/fpa_rewriter.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index 012661081..c910b3f99 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -268,7 +268,7 @@ extern "C" { Z3_ast Z3_API Z3_mk_fpa_fp(Z3_context c, Z3_ast sgn, Z3_ast exp, Z3_ast sig) { Z3_TRY; - LOG_Z3_mk_fpa_fp(c, sgn, sig, exp); + LOG_Z3_mk_fpa_fp(c, sgn, exp, sig); RESET_ERROR_CODE(); if (!is_bv(c, sgn) || !is_bv(c, exp) || !is_bv(c, sig)) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -1072,7 +1072,7 @@ extern "C" { Z3_ast Z3_API Z3_mk_fpa_to_fp_int_real(Z3_context c, Z3_ast rm, Z3_ast exp, Z3_ast sig, Z3_sort s) { Z3_TRY; - LOG_Z3_mk_fpa_to_fp_int_real(c, rm, sig, exp, s); + LOG_Z3_mk_fpa_to_fp_int_real(c, rm, exp, sig, s); RESET_ERROR_CODE(); api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); @@ -1083,7 +1083,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(sig), to_expr(exp)); + expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(exp), to_expr(sig)); ctx->save_ast_trail(a); RETURN_Z3(of_expr(a)); Z3_CATCH_RETURN(0); diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index 2d1166ee8..cd096d6a5 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -760,8 +760,8 @@ br_status fpa_rewriter::mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & res unsigned bvsz_sgn, bvsz_exp, bvsz_sig; if (bu.is_numeral(sgn, rsgn, bvsz_sgn) && - bu.is_numeral(sig, rsig, bvsz_exp) && - bu.is_numeral(exp, rexp, bvsz_sig)) { + bu.is_numeral(sig, rsig, bvsz_sig) && + bu.is_numeral(exp, rexp, bvsz_exp)) { SASSERT(mpzm.is_one(rexp.to_mpq().denominator())); SASSERT(mpzm.is_one(rsig.to_mpq().denominator())); scoped_mpf v(m_fm); From 25af97fb8b668d05c9f8fff70afe3ed0321633bb Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 4 Jan 2016 21:04:07 +0000 Subject: [PATCH 59/87] tabs --- scripts/mk_copyright.py | 36 +++++++------- scripts/update_header_guards.py | 88 ++++++++++++++++----------------- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/scripts/mk_copyright.py b/scripts/mk_copyright.py index 730020a38..3651e3819 100644 --- a/scripts/mk_copyright.py +++ b/scripts/mk_copyright.py @@ -19,15 +19,15 @@ def has_cr(file): lines = 0 line = ins.readline() while line and lines < 20: - m = cr.search(line) - if m: - ins.close() - return True - m = aut.search(line) - if m: - ins.close() - return True - line = ins.readline() + m = cr.search(line) + if m: + ins.close() + return True + m = aut.search(line) + if m: + ins.close() + return True + line = ins.readline() ins.close() return False @@ -38,20 +38,20 @@ def add_cr(file): ous.write(cr_notice) line = ins.readline() while line: - ous.write(line) - line = ins.readline() + ous.write(line) + line = ins.readline() ins.close() ous.close() os.system("move %s %s" % (tmp, file)) - + def add_missing_cr(dir): for root, dirs, files in os.walk(dir): - for f in files: - if f.endswith('.cpp') or f.endswith('.h') or f.endswith('.c') or f.endswith('.cs'): - path = "%s\\%s" % (root, f) - if not has_cr(path): - print("Missing CR for %s" % path) - add_cr(path) + for f in files: + if f.endswith('.cpp') or f.endswith('.h') or f.endswith('.c') or f.endswith('.cs'): + path = "%s\\%s" % (root, f) + if not has_cr(path): + print("Missing CR for %s" % path) + add_cr(path) add_missing_cr('src') add_missing_cr('examples') diff --git a/scripts/update_header_guards.py b/scripts/update_header_guards.py index 1010f1899..815196ef3 100644 --- a/scripts/update_header_guards.py +++ b/scripts/update_header_guards.py @@ -17,55 +17,55 @@ def fix_hdr(file): line = ins.readline() found = False while line: - m = doubleu.search(line) - if m: - ous.write("#") - ous.write(m.group(1)) - ous.write(" ") - ous.write(m.group(2)) - ous.write("_H_\n") - line = ins.readline() - found = True - continue - m = ifndef.search(line) - if m: - print(m.group(1)) - ous.write("#ifndef ") - ous.write(m.group(1)) - ous.write("_H_\n") - line = ins.readline() - found = True - continue - m = defn.search(line) - if m: - ous.write("#define ") - ous.write(m.group(1)) - ous.write("_H_\n") - line = ins.readline() - found = True - continue - m = endif.search(line) - if m: - ous.write("#endif /* ") - ous.write(m.group(1)) - ous.write("_H_ */\n") - line = ins.readline() - found = True - continue - ous.write(line) - line = ins.readline() + m = doubleu.search(line) + if m: + ous.write("#") + ous.write(m.group(1)) + ous.write(" ") + ous.write(m.group(2)) + ous.write("_H_\n") + line = ins.readline() + found = True + continue + m = ifndef.search(line) + if m: + print(m.group(1)) + ous.write("#ifndef ") + ous.write(m.group(1)) + ous.write("_H_\n") + line = ins.readline() + found = True + continue + m = defn.search(line) + if m: + ous.write("#define ") + ous.write(m.group(1)) + ous.write("_H_\n") + line = ins.readline() + found = True + continue + m = endif.search(line) + if m: + ous.write("#endif /* ") + ous.write(m.group(1)) + ous.write("_H_ */\n") + line = ins.readline() + found = True + continue + ous.write(line) + line = ins.readline() ins.close() ous.close() if found: - os.system("move %s %s" % (tmp, file)) + os.system("move %s %s" % (tmp, file)) else: - os.system("del %s" % tmp) - + os.system("del %s" % tmp) + def fixup(dir): for root, dirs, files in os.walk(dir): - for f in files: - if f.endswith('.h'): - path = "%s\\%s" % (root, f) - fix_hdr(path) + for f in files: + if f.endswith('.h'): + path = "%s\\%s" % (root, f) + fix_hdr(path) fixup('src') From 4915f2da0403e608d9ea3965bb55f54d5f652984 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 4 Jan 2016 21:53:24 +0000 Subject: [PATCH 60/87] Added facilities for generating a libz3.vcxproj next to z3.vcxproj for simplified DLL build in VS. --- scripts/mk_make.py | 5 +- scripts/mk_util.py | 206 ++++++++++++++++++++++++++------------------- 2 files changed, 123 insertions(+), 88 deletions(-) diff --git a/scripts/mk_make.py b/scripts/mk_make.py index ecf70a8c5..813cd3a66 100644 --- a/scripts/mk_make.py +++ b/scripts/mk_make.py @@ -1,7 +1,7 @@ ############################################ # Copyright (c) 2012 Microsoft Corporation -# -# Scripts for generating Makefiles and Visual +# +# Scripts for generating Makefiles and Visual # Studio project files. # # Author: Leonardo de Moura (leonardo) @@ -17,6 +17,7 @@ update_version() mk_auto_src() mk_bindings(API_files) mk_vs_proj('z3', ['shell']) +mk_vs_proj_dll('libz3', ['api_dll']) mk_makefile() diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 8a92d832d..89634c952 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -559,7 +559,7 @@ def dos2unix_tree(): for root, dirs, files in os.walk('src'): for f in files: dos2unix(os.path.join(root, f)) - + def check_eol(): if not IS_WINDOWS: @@ -1372,8 +1372,8 @@ class PythonInstallComponent(Component): "Python package directory." % (PYTHON_PACKAGE_DIR, PREFIX)) def main_component(self): - return False - + return False + def mk_install(self, out): if not is_python_install_enabled(): return @@ -1729,7 +1729,7 @@ class JavaDLLComponent(Component): MakeRuleCmd.remove_installed_files(out, os.path.join(INSTALL_LIB_DIR, jarfile)) class MLComponent(Component): - + def __init__(self, name, lib_name, path, deps): Component.__init__(self, name, path, deps) if lib_name is None: @@ -1747,14 +1747,14 @@ class MLComponent(Component): out.write('CXXFLAGS_OCAML=$(CXXFLAGS:/GL=)\n') # remove /GL; the ocaml tools don't like it. if IS_WINDOWS: - prefix_lib = '-L' + os.path.abspath(BUILD_DIR).replace('\\', '\\\\') + prefix_lib = '-L' + os.path.abspath(BUILD_DIR).replace('\\', '\\\\') else: prefix_lib = '-L' + PREFIX + '/lib' substitutions = { 'LEXTRA': prefix_lib, 'VERSION': "{}.{}.{}.{}".format(VER_MAJOR, VER_MINOR, VER_BUILD, VER_REVISION) } - + configure_file(os.path.join(self.src_dir, 'META.in'), - os.path.join(BUILD_DIR, self.sub_dir, 'META'), + os.path.join(BUILD_DIR, self.sub_dir, 'META'), substitutions) mlis = '' @@ -1766,7 +1766,7 @@ class MLComponent(Component): z3dllso = get_component(Z3_DLL_COMPONENT).dll_name + '$(SO_EXT)' out.write('%s: %s %s\n' % (stubso, stubsc, z3dllso)) out.write('\t%s -ccopt "$(CXXFLAGS_OCAML) -I %s -I %s -I %s $(CXX_OUT_FLAG)%s" -c %s\n' % - (OCAMLC, OCAML_LIB, api_src, src_dir, stubso, stubsc)) + (OCAMLC, OCAML_LIB, api_src, src_dir, stubso, stubsc)) cmis = '' for m in self.modules: @@ -1776,7 +1776,7 @@ class MLComponent(Component): out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLC, self.sub_dir, ft, ff)) cmis = cmis + ' ' + ft - cmos = '' + cmos = '' for m in self.modules: ff = os.path.join(src_dir, m + '.ml') ft = os.path.join(self.sub_dir, m + '.cmo') @@ -1802,7 +1802,7 @@ class MLComponent(Component): out.write('\tocamlmklib -o %s -I %s %s %s -L. -lz3\n' % (z3mls, self.sub_dir, stubso, cmxs)) out.write('%s.cmxs: %s.cmxa\n' % (z3mls, z3mls)) out.write('\t%s -shared -o %s.cmxs -I %s %s.cmxa\n' % (OCAMLOPT, z3mls, self.sub_dir, z3mls)) - + out.write('\n') out.write('ml: %s.cma %s.cmxa %s.cmxs\n' % (z3mls, z3mls, z3mls)) out.write('\n') @@ -1816,7 +1816,7 @@ class MLComponent(Component): out.write('ocamlfind_uninstall:\n') self.mk_uninstall(out) out.write('\n') - + def mk_install_deps(self, out): if is_ml_enabled() and OCAMLFIND != '': out.write(get_component(Z3_DLL_COMPONENT).dll_name + '$(SO_EXT) ') @@ -1885,8 +1885,8 @@ class CppExampleComponent(ExampleComponent): out.write(' -I%s' % get_component(API_COMPONENT).to_src_dir) out.write(' -I%s' % get_component(CPP_COMPONENT).to_src_dir) out.write(' %s' % os.path.join(self.to_ex_dir, cppfile)) - out.write('\n') - + out.write('\n') + exefile = '%s$(EXE_EXT)' % self.name out.write('%s: %s %s\n' % (exefile, dll, objfiles)) out.write('\t$(LINK) $(LINK_OUT_FLAG)%s $(LINK_FLAGS) %s ' % (exefile, objfiles)) @@ -3305,15 +3305,7 @@ def mk_z3consts_ml(api_files): def mk_gui_str(id): return '4D2F40D8-E5F9-473B-B548-%012d' % id -def mk_vs_proj(name, components): - if not VS_PROJ: - return - proj_name = '%s.vcxproj' % os.path.join(BUILD_DIR, name) - modes=['Debug', 'Release'] - PLATFORMS=['Win32'] - f = open(proj_name, 'w') - f.write('\n') - f.write('\n') +def mk_vs_proj_property_groups(f, name, type): f.write(' \n') f.write(' \n') f.write(' Debug\n') @@ -3324,35 +3316,45 @@ def mk_vs_proj(name, components): f.write(' Win32\n') f.write(' \n') f.write(' \n') - f.write(' \n') + f.write(' \n') f.write(' {%s}\n' % mk_gui_str(0)) f.write(' %s\n' % name) f.write(' Win32Proj\n') f.write(' \n') f.write(' \n') f.write(' \n') - f.write(' Application\n') + f.write(' %s\n' % type) f.write(' Unicode\n') f.write(' false\n') f.write(' \n') f.write(' \n') - f.write(' \n') - f.write(' \n') + f.write(' \n') f.write(' \n') f.write(' \n') f.write(' \n') f.write(' \n') - f.write(' $(SolutionDir)$(Configuration)\\n') + f.write(' $(SolutionDir)\$(ProjectName)\$(Configuration)\\n') f.write(' %s\n' % name) - f.write(' .exe\n') - f.write(' $(SolutionDir)$(Configuration)\\n') + f.write(' .dll\n') + f.write(' $(SolutionDir)\$(ProjectName)\$(Configuration)\\n') f.write(' %s\n' % name) - f.write(' .exe\n') + f.write(' .dll\n') f.write(' \n') - f.write(' \n') + f.write(' \n') + f.write(' $(ProjectName)\$(Configuration)\\n') + f.write(' \n') + f.write(' \n') + f.write(' $(ProjectName)\$(Configuration)\\n') + f.write(' \n') + + +def mk_vs_proj_cl_compile(f, name, components, debug): f.write(' \n') f.write(' Disabled\n') - f.write(' WIN32;_DEBUG;Z3DEBUG;_TRACE;_MP_INTERNAL;_WINDOWS;%(PreprocessorDefinitions)\n') + if debug: + f.write(' WIN32;_DEBUG;Z3DEBUG;_TRACE;_MP_INTERNAL;_WINDOWS;%(PreprocessorDefinitions)\n') + else: + f.write(' WIN32;_NDEBUG;_MP_INTERNAL;_WINDOWS;%(PreprocessorDefinitions)\n') if VS_PAR: f.write(' false\n') f.write(' true\n') @@ -3360,8 +3362,14 @@ def mk_vs_proj(name, components): f.write(' true\n') f.write(' EnableFastChecks\n') f.write(' Level3\n') - f.write(' MultiThreadedDebugDLL\n') - f.write(' true\n') + if debug: + f.write(' MultiThreadedDebugDLL\n') + else: + f.write(' MultiThreadedDLL\n') + if USE_OMP: + f.write(' true\n') + else: + f.write(' false\n') f.write(' ProgramDatabase\n') f.write(' ') deps = find_all_deps(name, components) @@ -3374,63 +3382,89 @@ def mk_vs_proj(name, components): f.write(get_component(dep).to_src_dir) f.write('\n') f.write(' \n') - f.write(' \n') - f.write(' $(OutDir)%s.exe\n' % name) - f.write(' true\n') - f.write(' Console\n') - f.write(' 8388608\n') - f.write(' false\n') - f.write(' \n') - f.write(' \n') - f.write(' MachineX86\n') - f.write(' %(AdditionalLibraryDirectories)\n') - f.write('psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)\n') - f.write(' \n') - f.write(' \n') - f.write(' \n') - f.write(' \n') - f.write(' Disabled\n') - f.write(' WIN32;_NDEBUG;_MP_INTERNAL;_WINDOWS;%(PreprocessorDefinitions)\n') - if VS_PAR: - f.write(' false\n') - f.write(' true\n') - else: - f.write(' true\n') - f.write(' EnableFastChecks\n') - f.write(' Level3\n') - f.write(' MultiThreadedDLL\n') - f.write(' true\n') - f.write(' ProgramDatabase\n') - f.write(' ') - deps = find_all_deps(name, components) - first = True - for dep in deps: - if first: - first = False - else: - f.write(';') - f.write(get_component(dep).to_src_dir) - f.write('\n') - f.write(' \n') - f.write(' \n') - f.write(' $(OutDir)%s.exe\n' % name) - f.write(' true\n') - f.write(' Console\n') - f.write(' 8388608\n') - f.write(' false\n') - f.write(' \n') - f.write(' \n') - f.write(' MachineX86\n') - f.write(' %(AdditionalLibraryDirectories)\n') - f.write('psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)\n') - f.write(' \n') - f.write(' \n') + +def mk_vs_proj_dep_groups(f, name, components): f.write(' \n') + deps = find_all_deps(name, components) for dep in deps: dep = get_component(dep) for cpp in filter(lambda f: f.endswith('.cpp'), os.listdir(dep.src_dir)): f.write(' \n' % os.path.join(dep.to_src_dir, cpp)) f.write(' \n') + +def mk_vs_proj_link_exe(f, name, debug): + f.write(' \n') + f.write(' $(OutDir)%s.exe\n' % name) + f.write(' true\n') + f.write(' Console\n') + f.write(' 8388608\n') + f.write(' false\n') + f.write(' \n') + f.write(' MachineX86\n') + f.write(' %(AdditionalLibraryDirectories)\n') + f.write(' psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)\n') + f.write(' \n') + +def mk_vs_proj(name, components): + if not VS_PROJ: + return + proj_name = '%s.vcxproj' % os.path.join(BUILD_DIR, name) + modes=['Debug', 'Release'] + PLATFORMS=['Win32'] + f = open(proj_name, 'w') + f.write('\n') + f.write('\n') + mk_vs_proj_property_groups(f, name, 'Application') + f.write(' \n') + mk_vs_proj_cl_compile(f, name, components, debug=True) + mk_vs_proj_link_exe(f, name, debug=True) + f.write(' \n') + f.write(' \n') + mk_vs_proj_cl_compile(f, name, components, debug=False) + mk_vs_proj_link_exe(f, name, debug=False) + f.write(' \n') + mk_vs_proj_dep_groups(f, name, components) + f.write(' \n') + f.write(' \n') + f.write(' \n') + f.write('\n') + f.close() + if is_verbose(): + print("Generated '%s'" % proj_name) + +def mk_vs_proj_link_dll(f, name, debug): + f.write(' \n') + f.write(' $(OutDir)%s.dll\n' % name) + f.write(' true\n') + f.write(' Console\n') + f.write(' 8388608\n') + f.write(' false\n') + f.write(' \n') + f.write(' MachineX86\n') + f.write(' %(AdditionalLibraryDirectories)\n') + f.write(' psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)\n') + f.write(' %s' % os.path.join(get_component('api_dll').to_src_dir, 'api_dll.def')) + f.write(' \n') + +def mk_vs_proj_dll(name, components): + if not VS_PROJ: + return + proj_name = '%s.vcxproj' % os.path.join(BUILD_DIR, name) + modes=['Debug', 'Release'] + PLATFORMS=['Win32'] + f = open(proj_name, 'w') + f.write('\n') + f.write('\n') + mk_vs_proj_property_groups(f, name, 'DynamicLibrary') + f.write(' \n') + mk_vs_proj_cl_compile(f, name, components, debug=True) + mk_vs_proj_link_dll(f, name, debug=True) + f.write(' \n') + f.write(' \n') + mk_vs_proj_cl_compile(f, name, components, debug=False) + mk_vs_proj_link_dll(f, name, debug=False) + f.write(' \n') + mk_vs_proj_dep_groups(f, name, components) f.write(' \n') f.write(' \n') f.write(' \n') @@ -3478,7 +3512,7 @@ class MakeRuleCmd(object): @classmethod def _install_root(cls, path, in_prefix, out, is_install=True): if not in_prefix: - # The Python bindings on OSX are sometimes not installed inside the prefix. + # The Python bindings on OSX are sometimes not installed inside the prefix. install_root = "$(DESTDIR)" action_string = 'install' if is_install else 'uninstall' cls.write_cmd(out, 'echo "WARNING: {}ing files/directories ({}) that are not in the install prefix ($(PREFIX))."'.format( From c1ebf6b4fca2e980ef1c44cfafe3fb4f4f839a9c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Jan 2016 18:01:48 -0800 Subject: [PATCH 61/87] seq + API Signed-off-by: Nikolaj Bjorner --- src/api/dotnet/Context.cs | 37 ++++++ src/api/java/Context.java | 191 ++++++++++++++++++++++++++++++ src/api/java/Expr.java | 4 + src/api/java/Sort.java | 4 + src/api/python/z3.py | 28 ++++- src/ast/rewriter/seq_rewriter.cpp | 150 ++++++++++++++--------- src/ast/rewriter/seq_rewriter.h | 2 + src/smt/theory_seq.cpp | 132 ++++++++++++++++++--- src/smt/theory_seq.h | 13 ++ 9 files changed, 484 insertions(+), 77 deletions(-) diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index cc81160fb..a97036897 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -125,6 +125,7 @@ namespace Microsoft.Z3 private BoolSort m_boolSort = null; private IntSort m_intSort = null; private RealSort m_realSort = null; + private SeqSort m_stringSort = null; /// /// Retrieves the Boolean sort of the context. @@ -163,6 +164,20 @@ namespace Microsoft.Z3 } } + /// + /// Retrieves the String sort of the context. + /// + public SeqSort StringSort + { + get + { + Contract.Ensures(Contract.Result() != null); + if (m_stringSort == null) m_stringSort = new SeqSort(this, Native.Z3_mk_string_sort(nCtx)); + return m_stringSort; + } + } + + /// /// Create a new Boolean sort. /// @@ -223,6 +238,27 @@ namespace Microsoft.Z3 return new BitVecSort(this, Native.Z3_mk_bv_sort(nCtx, size)); } + + /// + /// Create a new sequence sort. + /// + public SeqSort MkSeqSort(Sort s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return new SeqSort(this, Native.Z3_mk_seq_sort(nCtx, s.NativeObject)); + } + + /// + /// Create a new regular expression sort. + /// + public ReSort MkReSort(SeqSort s) + { + Contract.Requires(s != null); + Contract.Ensures(Contract.Result() != null); + return new ReSort(this, Native.Z3_mk_re_sort(nCtx, s.NativeObject)); + } + /// /// Create a new array sort. /// @@ -4872,6 +4908,7 @@ namespace Microsoft.Z3 m_boolSort = null; m_intSort = null; m_realSort = null; + m_stringSort = null; } #endregion } diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 8d2bc5b50..f27402e91 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -1849,6 +1849,184 @@ public class Context extends IDisposable arg2.getNativeObject())); } + + /** + * Sequences, Strings and regular expressions. + */ + + /** + * Create the empty sequence. + */ + public SeqExpr MkEmptySeq(Sort s) + { + checkContextMatch(s); + return new SeqExpr(this, Native.mkSeqEmpty(nCtx, s.NativeObject)); + } + + /** + * Create the singleton sequence. + */ + public SeqExpr MkUnit(Expr elem) + { + checkContextMatch(elem); + return new SeqExpr(this, Native.mkSeqUnit(nCtx, elem.NativeObject)); + } + + /** + * Create a string constant. + */ + public SeqExpr MkString(string s) + { + return new SeqExpr(this, Native.mkString(nCtx, s)); + } + + /** + * Concatentate sequences. + */ + public SeqExpr MkConcat(params SeqExpr[] t) + { + checkContextMatch(t); + return new SeqExpr(this, Native.mkSeqConcat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + } + + + /** + * Retrieve the length of a given sequence. + */ + public IntExpr MkLength(SeqExpr s) + { + checkContextMatch(s); + return (IntExpr) Expr.Create(this, Native.mkSeqLength(nCtx, s.NativeObject)); + } + + /** + * Check for sequence prefix. + */ + public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2) + { + checkContextMatch(s1, s2); + return new BoolExpr(this, Native.mkSeqPrefix(nCtx, s1.NativeObject, s2.NativeObject)); + } + + /** + * Check for sequence suffix. + */ + public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2) + { + checkContextMatch(s1, s2); + return new BoolExpr(this, Native.mkSeqSuffix(nCtx, s1.NativeObject, s2.NativeObject)); + } + + /** + * Check for sequence containment of s2 in s1. + */ + public BoolExpr MkContains(SeqExpr s1, SeqExpr s2) + { + checkContextMatch(s1, s2); + return new BoolExpr(this, Native.mkSeqContains(nCtx, s1.NativeObject, s2.NativeObject)); + } + + /** + * Retrieve sequence of length one at index. + */ + public SeqExpr MkAt(SeqExpr s, IntExpr index) + { + checkContextMatch(s, index); + return new SeqExpr(this, Native.mkSeqAt(nCtx, s.NativeObject, index.NativeObject)); + } + + /** + * Extract subsequence. + */ + public SeqExpr MkExtract(SeqExpr s, IntExpr offset, IntExpr length) + { + checkContextMatch(s, offset, length); + return new SeqExpr(this, Native.mkSeqExtract(nCtx, s.NativeObject, offset.NativeObject, length.NativeObject)); + } + + /** + * Extract index of sub-string starting at offset. + */ + public IntExpr MkIndexOf(SeqExpr s, SeqExpr substr, ArithExpr offset) + { + checkContextMatch(s, substr, offset); + return new IntExpr(this, Native.mkSeqIndex(nCtx, s.NativeObject, substr.NativeObject, offset.NativeObject)); + } + + /** + * Replace the first occurrence of src by dst in s. + */ + public SeqExpr MkReplace(SeqExpr s, SeqExpr src, SeqExpr dst) + { + checkContextMatch(s, src, dst); + return new SeqExpr(this, Native.mkSeqReplace(nCtx, s.NativeObject, src.NativeObject, dst.NativeObject)); + } + + /** + * Convert a regular expression that accepts sequence s. + */ + public ReExpr MkToRe(SeqExpr s) + { + checkContextMatch(s); + return new ReExpr(this, Native.mkSeqToRe(nCtx, s.NativeObject)); + } + + + /** + * Check for regular expression membership. + */ + public BoolExpr MkInRe(SeqExpr s, ReExpr re) + { + checkContextMatch(s, re); + return new BoolExpr(this, Native.mkSeqInRe(nCtx, s.NativeObject, re.NativeObject)); + } + + /** + * Take the Kleene star of a regular expression. + */ + public ReExpr MkStar(ReExpr re) + { + checkContextMatch(re); + return new ReExpr(this, Native.mkReStar(nCtx, re.NativeObject)); + } + + /** + * Take the Kleene plus of a regular expression. + */ + public ReExpr MPlus(ReExpr re) + { + checkContextMatch(re); + return new ReExpr(this, Native.mkRePlus(nCtx, re.NativeObject)); + } + + /** + * Create the optional regular expression. + */ + public ReExpr MOption(ReExpr re) + { + checkContextMatch(re); + return new ReExpr(this, Native.mkReOption(nCtx, re.NativeObject)); + } + + /** + * Create the concatenation of regular languages. + */ + public ReExpr MkConcat(ReExpr[] t) + { + checkContextMatch(t); + return new ReExpr(this, Native.mkReConcat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + } + + /** + * Create the union of regular languages. + */ + public ReExpr MkUnion(ReExpr[] t) + { + checkContextMatch(t); + return new ReExpr(this, Native.mkReUnion(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + } + + /** * Create a Term of a given sort. * @param v A string representing the term value in decimal notation. If the given sort is a real, then the @@ -3683,6 +3861,19 @@ public class Context extends IDisposable throw new Z3Exception("Context mismatch"); } + void checkContextMatch(Z3Object other1, Z3Object other2) + { + checkContextMatch(other1); + checkContextMatch(other2); + } + + void checkContextMatch(Z3Object other1, Z3Object other2, Z3Object other3) + { + checkContextMatch(other1); + checkContextMatch(other2); + checkContextMatch(other3); + } + void checkContextMatch(Z3Object[] arr) { if (arr != null) diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index b0b95d4b7..e03d5b1c9 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -2186,6 +2186,10 @@ public class Expr extends AST return new FPRMExpr(ctx, obj); case Z3_FINITE_DOMAIN_SORT: return new FiniteDomainExpr(ctx, obj); + case Z3_SEQ_SORT: + return new SeqExpr(ctx, obj); + case Z3_RE_SORT: + return new ReExpr(ctx, obj); default: ; } diff --git a/src/api/java/Sort.java b/src/api/java/Sort.java index db6bee80e..1481a44e2 100644 --- a/src/api/java/Sort.java +++ b/src/api/java/Sort.java @@ -141,6 +141,10 @@ public class Sort extends AST return new FPSort(ctx, obj); case Z3_ROUNDING_MODE_SORT: return new FPRMSort(ctx, obj); + case Z3_SEQ_SORT: + return new SeqSort(ctx, obj); + case Z3_RE_SORT: + return new ReSort(ctx, obj); default: throw new Z3Exception("Unknown sort kind"); } diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 0bef54a53..9129cb854 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -8991,7 +8991,7 @@ class SeqRef(ExprRef): def __getitem__(self, i): return SeqRef(Z3_mk_seq_at(self.ctx_ref(), self.as_ast(), i.as_ast()), self.ctx) - def is_string_sort(self): + def is_string(self): return Z3_is_string_sort(self.ctx_ref(), Z3_get_sort(self.ctx_ref(), self.as_ast())) def is_string_value(self): @@ -9026,12 +9026,12 @@ def is_seq(a): """ return isinstance(a, SeqRef) -def is_string_sort(a): +def is_string(a): """Return `True` if `a` is a Z3 string expression. - >>> print (is_string_sort(StringVal("ab"))) + >>> print (is_string(StringVal("ab"))) True """ - return isinstance(a, SeqRef) and a.is_string_sort() + return isinstance(a, SeqRef) and a.is_string() def is_string_value(a): """return 'True' if 'a' is a Z3 string constant expression. @@ -9042,11 +9042,27 @@ def is_string_value(a): """ return isinstance(a, SeqRef) and a.is_string_value() + def StringVal(s, ctx=None): """create a string expression""" ctx = _get_ctx(ctx) return SeqRef(Z3_mk_string(ctx.ref(), s), ctx) +def String(name, ctx=None): + """Return a string constant named `name`. If `ctx=None`, then the global context is used. + + >>> x = String('x') + """ + ctx = _get_ctx(ctx) + return SeqRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), StringSort(ctx).ast), ctx) + +def Strings(names, ctx=None): + """Return a tuple of String constants. """ + ctx = _get_ctx(ctx) + if isinstance(names, str): + names = names.split(" ") + return [String(name, ctx) for name in names] + def Empty(s): """Create the empty sequence of the given sort >>> e = Empty(StringSort()) @@ -9101,6 +9117,10 @@ def Contains(a, b): >>> s2 = Contains("abc", "bc") >>> simplify(s2) True + >>> x, y, z = Strings('x y z') + >>> s3 = Contains(Concat(x,y,z), y) + >>> simplify(s3) + True """ ctx = _get_ctx2(a, b) a = _coerce_seq(a, ctx) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 8f6aa6fca..1231369c7 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -23,6 +23,7 @@ Notes: #include"ast_util.h" #include"uint_set.h" #include"automaton.h" +#include"well_sorted.h" struct display_expr1 { @@ -843,37 +844,33 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) { return BR_REWRITE3; } -bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs) { +bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs) { expr* a, *b; zstring s; bool change = false; - m_lhs.reset(); - m_rhs.reset(); - m_util.str.get_concat(l, m_lhs); - m_util.str.get_concat(r, m_rhs); // solve from back while (true) { - while (!m_rhs.empty() && m_util.str.is_empty(m_rhs.back())) { - m_rhs.pop_back(); + while (!rs.empty() && m_util.str.is_empty(rs.back())) { + rs.pop_back(); change = true; } - while (!m_lhs.empty() && m_util.str.is_empty(m_lhs.back())) { - m_lhs.pop_back(); + while (!ls.empty() && m_util.str.is_empty(ls.back())) { + ls.pop_back(); change = true; } - if (m_lhs.empty() || m_rhs.empty()) { + if (ls.empty() || rs.empty()) { break; } - expr* l = m_lhs.back(); - expr* r = m_rhs.back(); + expr* l = ls.back(); + expr* r = rs.back(); if (m_util.str.is_unit(r) && m_util.str.is_string(l)) { std::swap(l, r); - m_lhs.swap(m_rhs); + ls.swap(rs); } if (l == r) { - m_lhs.pop_back(); - m_rhs.pop_back(); + ls.pop_back(); + rs.pop_back(); } else if(m_util.str.is_unit(l, a) && m_util.str.is_unit(r, b)) { @@ -882,8 +879,8 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve } lhs.push_back(a); rhs.push_back(b); - m_lhs.pop_back(); - m_rhs.pop_back(); + ls.pop_back(); + rs.pop_back(); } else if (m_util.str.is_unit(l, a) && m_util.str.is_string(r, s)) { SASSERT(s.length() > 0); @@ -892,13 +889,13 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve SASSERT(m().get_sort(ch) == m().get_sort(a)); lhs.push_back(ch); rhs.push_back(a); - m_lhs.pop_back(); + ls.pop_back(); if (s.length() == 1) { - m_rhs.pop_back(); + rs.pop_back(); } else { expr_ref s2(m_util.str.mk_string(s.extract(0, s.length()-2)), m()); - m_rhs[m_rhs.size()-1] = s2; + rs[rs.size()-1] = s2; } } else { @@ -910,22 +907,22 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve // solve from front unsigned head1 = 0, head2 = 0; while (true) { - while (head1 < m_lhs.size() && m_util.str.is_empty(m_lhs[head1].get())) { + while (head1 < ls.size() && m_util.str.is_empty(ls[head1].get())) { ++head1; } - while (head2 < m_rhs.size() && m_util.str.is_empty(m_rhs[head2].get())) { + while (head2 < rs.size() && m_util.str.is_empty(rs[head2].get())) { ++head2; } - if (head1 == m_lhs.size() || head2 == m_rhs.size()) { + if (head1 == ls.size() || head2 == rs.size()) { break; } - SASSERT(head1 < m_lhs.size() && head2 < m_rhs.size()); + SASSERT(head1 < ls.size() && head2 < rs.size()); - expr* l = m_lhs[head1].get(); - expr* r = m_rhs[head2].get(); + expr* l = ls[head1].get(); + expr* r = rs[head2].get(); if (m_util.str.is_unit(r) && m_util.str.is_string(l)) { std::swap(l, r); - m_lhs.swap(m_rhs); + ls.swap(rs); } if (l == r) { ++head1; @@ -947,13 +944,13 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve SASSERT(m().get_sort(ch) == m().get_sort(a)); lhs.push_back(ch); rhs.push_back(a); - m_lhs.pop_back(); + ls.pop_back(); if (s.length() == 1) { - m_rhs.pop_back(); + rs.pop_back(); } else { expr_ref s2(m_util.str.mk_string(s.extract(1, s.length()-1)), m()); - m_rhs[m_rhs.size()-1] = s2; + rs[rs.size()-1] = s2; } } else { @@ -963,10 +960,10 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve } // reduce strings zstring s1, s2; - while (head1 < m_lhs.size() && - head2 < m_rhs.size() && - m_util.str.is_string(m_lhs[head1].get(), s1) && - m_util.str.is_string(m_rhs[head2].get(), s2)) { + while (head1 < ls.size() && + head2 < rs.size() && + m_util.str.is_string(ls[head1].get(), s1) && + m_util.str.is_string(rs[head2].get(), s2)) { unsigned l = std::min(s1.length(), s2.length()); for (unsigned i = 0; i < l; ++i) { if (s1[i] != s2[i]) { @@ -977,64 +974,105 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve ++head1; } else { - m_lhs[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l)); + ls[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l)); } if (l == s2.length()) { ++head2; } else { - m_rhs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l)); + rs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l)); } change = true; } - while (head1 < m_lhs.size() && - head2 < m_rhs.size() && - m_util.str.is_string(m_lhs.back(), s1) && - m_util.str.is_string(m_rhs.back(), s2)) { + while (head1 < ls.size() && + head2 < rs.size() && + m_util.str.is_string(ls.back(), s1) && + m_util.str.is_string(rs.back(), s2)) { unsigned l = std::min(s1.length(), s2.length()); for (unsigned i = 0; i < l; ++i) { if (s1[s1.length()-i-1] != s2[s2.length()-i-1]) { return false; } } - m_lhs.pop_back(); - m_rhs.pop_back(); + ls.pop_back(); + rs.pop_back(); if (l < s1.length()) { - m_lhs.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l))); + ls.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l))); } if (l < s2.length()) { - m_rhs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l))); + rs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l))); } change = true; } bool is_sat; - unsigned szl = m_lhs.size() - head1, szr = m_rhs.size() - head2; - expr* const* ls = m_lhs.c_ptr() + head1, * const*rs = m_rhs.c_ptr() + head2; - if (length_constrained(szl, ls, szr, rs, lhs, rhs, is_sat)) { + unsigned szl = ls.size() - head1, szr = rs.size() - head2; + expr* const* _ls = ls.c_ptr() + head1, * const* _rs = rs.c_ptr() + head2; + if (length_constrained(szl, _ls, szr, _rs, lhs, rhs, is_sat)) { + ls.reset(); rs.reset(); return is_sat; } - if (is_subsequence(szl, ls, szr, rs, lhs, rhs, is_sat)) { + if (is_subsequence(szl, _ls, szr, _rs, lhs, rhs, is_sat)) { + ls.reset(); rs.reset(); return is_sat; } - if (szl == 0 && szr == 0) { - return true; - } + if (szl == 0 && szr == 0) { + ls.reset(); rs.reset(); + return true; + } else if (!change) { - lhs.push_back(l); - rhs.push_back(r); + // skip } else { // could solve if either side is fixed size. SASSERT(szl > 0 && szr > 0); - - lhs.push_back(m_util.str.mk_concat(szl, ls)); - rhs.push_back(m_util.str.mk_concat(szr, rs)); + if (head1 > 0) { + for (unsigned i = 0; i < szl; ++i) { + ls[i] = ls[i + head1]; + } + } + ls.shrink(szl); + if (head2 > 0) { + for (unsigned i = 0; i < szr; ++i) { + rs[i] = rs[i + head2]; + } + } + rs.shrink(szr); + lhs.push_back(m_util.str.mk_concat(ls.size(), ls.c_ptr())); + rhs.push_back(m_util.str.mk_concat(rs.size(), rs.c_ptr())); + ls.reset(); + rs.reset(); } return true; } +bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs) { + m_lhs.reset(); + m_rhs.reset(); + m_util.str.get_concat(l, m_lhs); + m_util.str.get_concat(r, m_rhs); + if (reduce_eq(m_lhs, m_rhs, lhs, rhs)) { + SASSERT(lhs.size() == rhs.size()); + if (!m_lhs.empty()) { + SASSERT(!m_rhs.empty()); + lhs.push_back(m_util.str.mk_concat(m_lhs.size(), m_lhs.c_ptr())); + rhs.push_back(m_util.str.mk_concat(m_rhs.size(), m_rhs.c_ptr())); + } + for (unsigned i = 0; i < lhs.size(); ++i) { + SASSERT(is_well_sorted(m(), lhs[i].get())); + SASSERT(is_well_sorted(m(), rhs[i].get())); + SASSERT(m().get_sort(lhs[i].get()) == m().get_sort(rhs[i].get())); + TRACE("seq", tout << mk_pp(lhs[i].get(), m()) << " = " << mk_pp(rhs[i].get(), m()) << "\n";); + } + return true; + } + else { + TRACE("seq", tout << mk_pp(l, m()) << " != " << mk_pp(r, m()) << "\n";); + return false; + } +} + expr* seq_rewriter::concat_non_empty(unsigned n, expr* const* as) { SASSERT(n > 0); ptr_vector bs; diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index d5fac104b..9d4dbb14f 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -92,6 +92,8 @@ public: bool reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs); + bool reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs); + }; #endif diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 1d640fe78..7aa434661 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -368,11 +368,19 @@ bool theory_seq::propagate_length_coherence(expr* e) { // len(e) >= low => e = tail; literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)))); add_axiom(~low, mk_eq(e, tail, false)); - assume_equality(seq, emp); if (upper_bound(e, hi)) { - expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m); - expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); - add_axiom(~mk_literal(high1), mk_literal(high2)); + // len(e) <= hi => len(tail) <= hi - lo + expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m); + if (hi == lo) { + add_axiom(~mk_literal(high1), mk_eq(seq, emp, false)); + } + else { + expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m); + add_axiom(~mk_literal(high1), mk_literal(high2)); + } + } + else { + assume_equality(seq, emp); } return true; } @@ -428,6 +436,15 @@ bool theory_seq::is_nth(expr* e) const { return is_skolem(m_nth, e); } +bool theory_seq::is_tail(expr* e, expr*& s, unsigned& idx) const { + rational r; + return + is_skolem(m_tail, e) && + m_autil.is_numeral(to_app(e)->get_arg(1), r) && + (idx = r.get_unsigned(), s = to_app(e)->get_arg(0), true); +} + + expr_ref theory_seq::mk_nth(expr* s, expr* idx) { sort* char_sort = 0; VERIFY(m_util.is_seq(m.get_sort(s), char_sort)); @@ -602,9 +619,9 @@ bool theory_seq::simplify_eq(expr* l, expr* r, dependency* deps) { } } TRACE("seq", - tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " => "; + tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " => \n"; for (unsigned i = 0; i < lhs.size(); ++i) { - tout << mk_pp(lhs[i].get(), m) << " = " << mk_pp(rhs[i].get(), m) << "; "; + tout << mk_pp(lhs[i].get(), m) << "\n = \n" << mk_pp(rhs[i].get(), m) << "; \n"; } tout << "\n";); return true; @@ -614,6 +631,8 @@ bool theory_seq::solve_unit_eq(expr* l, expr* r, dependency* deps) { if (l == r) { return true; } + //propagate_max_length(l, r, deps); + if (is_var(l) && !occurs(l, r) && add_solution(l, r, deps)) { return true; } @@ -712,6 +731,21 @@ bool theory_seq::solve_eq(expr* _l, expr* _r, dependency* deps) { return false; } +bool theory_seq::propagate_max_length(expr* l, expr* r, dependency* deps) { + unsigned idx; + expr* s; + if (m_util.str.is_empty(l)) { + std::swap(l, r); + } + rational hi; + if (is_tail(l, s, idx) && has_length(s) && m_util.str.is_empty(r) && !upper_bound(s, hi)) { + std::cout << "max length " << mk_pp(s, m) << " " << idx << "\n"; + propagate_lit(deps, 0, 0, mk_literal(m_autil.mk_le(m_util.str.mk_length(s), m_autil.mk_int(idx+1)))); + return true; + } + return false; +} + bool theory_seq::is_binary_eq(expr* l, expr* r, expr*& x, ptr_vector& xs, ptr_vector& ys, expr*& y) { xs.reset(); ys.reset(); @@ -889,13 +923,35 @@ void theory_seq::solve_ne(unsigned idx) { --i; } } - if (num_undef_lits == 0 && n.m_lhs.empty()) { + if (num_undef_lits == 1 && n.m_lhs.empty()) { + literal_vector lits; + literal undef_lit = null_literal; + for (unsigned i = 0; i < n.m_lits.size(); ++i) { + literal lit = n.m_lits[i]; + switch (ctx.get_assignment(lit)) { + case l_true: + lits.push_back(lit); + break; + case l_false: + UNREACHABLE(); + break; + case l_undef: + SASSERT(undef_lit == null_literal); + undef_lit = lit; + break; + } + } + TRACE("seq", tout << "propagate: " << undef_lit << "\n";); + SASSERT(undef_lit != null_literal); + propagate_lit(n.m_dep, lits.size(), lits.c_ptr(), ~undef_lit); + } + else if (num_undef_lits == 0 && n.m_lhs.empty()) { literal_vector lits(n.m_lits); lits.push_back(~mk_eq(n.m_l, n.m_r, false)); set_conflict(n.m_dep, lits); SASSERT(m_new_propagation); } - if (num_undef_lits == 0 && n.m_lhs.size() == 1) { + else if (false && num_undef_lits == 0 && n.m_lhs.size() == 1) { expr* l = n.m_lhs[0]; expr* r = n.m_rhs[0]; if (m_util.str.is_empty(r)) { @@ -903,13 +959,21 @@ void theory_seq::solve_ne(unsigned idx) { } if (m_util.str.is_empty(l) && is_var(r)) { literal lit = ~mk_eq_empty(r); - if (ctx.get_assignment(lit) == l_true) { + switch (ctx.get_assignment(lit)) { + case l_true: { expr_ref head(m), tail(m); mk_decompose(r, head, tail); expr_ref conc(m_util.str.mk_concat(head, tail), m); propagate_is_conc(r, conc); + m_new_propagation = true; + break; + } + case l_undef: + m_new_propagation = true; + break; + case l_false: + break; } - m_new_propagation = true; } } } @@ -941,14 +1005,13 @@ bool theory_seq::simplify_and_solve_eqs() { bool theory_seq::internalize_term(app* term) { - TRACE("seq", tout << mk_pp(term, m) << "\n";); context & ctx = get_context(); if (ctx.e_internalized(term)) { enode* e = ctx.get_enode(term); mk_var(e); return true; } - + TRACE("seq", tout << mk_pp(term, m) << "\n";); unsigned num_args = term->get_num_args(); expr* arg; for (unsigned i = 0; i < num_args; i++) { @@ -1090,7 +1153,7 @@ void theory_seq::collect_statistics(::statistics & st) const { st.update("seq branch", m_stats.m_branch_variable); st.update("seq solve !=", m_stats.m_solve_nqs); st.update("seq solve =", m_stats.m_solve_eqs); - + st.update("seq add axiom", m_stats.m_add_axiom); } void theory_seq::init_model(model_generator & mg) { @@ -1266,6 +1329,29 @@ expr_ref theory_seq::canonize(expr* e, dependency*& eqs) { return result; } +void theory_seq::canonize(expr* e0, expr_ref_vector& es, dependency*& eqs) { + dependency* dep = 0; + expr* e = m_rep.find(e0, dep); + expr* e1, *e2; + if (m_util.str.is_concat(e, e1, e2)) { + canonize(e1, es, eqs); + canonize(e2, es, eqs); + } + else if (m_util.str.is_empty(e)) { + // skip + } + else { + expr_ref e3 = expand(e, eqs); + if (m_util.str.is_concat(e3) || m_util.str.is_empty(e3)) { + canonize(e3, es, eqs); + } + else { + es.push_back(e3); + } + } + eqs = m_dm.mk_join(eqs, dep); +} + expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { expr_ref result(m); dependency* deps = 0; @@ -1516,10 +1602,12 @@ void theory_seq::add_length_axiom(expr* n) { if (n != len) { TRACE("seq", tout << "Add length coherence for " << mk_pp(n, m) << "\n";); add_axiom(mk_eq(n, len, false)); + m_trail_stack.push(push_replay(alloc(replay_axiom, m, n))); } } else { add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0)))); + m_trail_stack.push(push_replay(alloc(replay_axiom, m, n))); } } @@ -1753,7 +1841,14 @@ void theory_seq::propagate_step(literal lit, expr* step) { expr_ref nth = mk_nth(s, idx); TRACE("seq", tout << mk_pp(step, m) << " -> " << mk_pp(t, m) << " = " << nth << "\n";); propagate_eq(lit, t, nth); - propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx))); + rational lo; + rational _idx; + if (lower_bound(s, lo) && lo.is_unsigned() && m_autil.is_numeral(idx, _idx) && lo >= _idx) { + // skip + } + else { + propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx))); + } ensure_nth(lit, s, idx); } @@ -1774,7 +1869,7 @@ void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) { expr_ref_vector elems(m); get_concat(s1, es); unsigned i = 0; - for (; i < _idx && i < es.size() && m_util.str.is_unit(es[i]); ++i) {}; + for (; i <= _idx && i < es.size() && m_util.str.is_unit(es[i]); ++i) {}; if (i == _idx && i < es.size() && m_util.str.is_unit(es[i], e1)) { dep = m_dm.mk_join(dep, m_dm.mk_leaf(assumption(lit))); propagate_eq(dep, ensure_enode(nth), ensure_enode(e1)); @@ -1792,7 +1887,9 @@ void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) { propagate_eq(lit, s, conc, true); // TBD: examine other places for enforcing constraints on tail - add_axiom(~lit, mk_eq(m_util.str.mk_length(s), m_util.str.mk_length(conc), false)); + conc = m_autil.mk_add(m_autil.mk_int(_idx+1), m_util.str.mk_length(s2)); + add_axiom(~lit, mk_eq(m_util.str.mk_length(s), conc, false)); + //add_axiom(~lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), m_autil.mk_int(_idx + 1)))); } literal theory_seq::mk_literal(expr* _e) { @@ -1823,8 +1920,9 @@ void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4) { if (l2 != null_literal) { ctx.mark_as_relevant(l2); lits.push_back(l2); } if (l3 != null_literal) { ctx.mark_as_relevant(l3); lits.push_back(l3); } if (l4 != null_literal) { ctx.mark_as_relevant(l4); lits.push_back(l4); } - TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";); + TRACE("seq", ctx.display_literals_verbose(tout << "axiom: ", lits.size(), lits.c_ptr()); tout << "\n";); m_new_propagation = true; + ++m_stats.m_add_axiom; ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 40fce2695..511c6917c 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -261,6 +261,15 @@ namespace smt { } }; + class replay_axiom : public apply { + expr_ref m_e; + public: + replay_axiom(ast_manager& m, expr* e) : m_e(e, m) {} + virtual void operator()(theory_seq& th) { + th.enque_axiom(m_e); + } + }; + class push_replay : public trail { apply* m_apply; public: @@ -282,6 +291,7 @@ namespace smt { unsigned m_branch_variable; unsigned m_solve_nqs; unsigned m_solve_eqs; + unsigned m_add_axiom; }; ast_manager& m; dependency_manager m_dm; @@ -357,6 +367,7 @@ namespace smt { bool solve_unit_eq(expr* l, expr* r, dependency* dep); bool is_binary_eq(expr* l, expr* r, expr*& x, ptr_vector& xunits, ptr_vector& yunits, expr*& y); bool solve_binary_eq(expr* l, expr* r, dependency* dep); + bool propagate_max_length(expr* l, expr* r, dependency* dep); bool solve_nqs(unsigned i); void solve_ne(unsigned i); @@ -383,9 +394,11 @@ namespace smt { bool is_var(expr* b); bool add_solution(expr* l, expr* r, dependency* dep); bool is_nth(expr* a) const; + bool is_tail(expr* a, expr*& s, unsigned& idx) const; expr_ref mk_nth(expr* s, expr* idx); expr_ref mk_last(expr* e); expr_ref canonize(expr* e, dependency*& eqs); + void canonize(expr* e, expr_ref_vector& es, dependency*& eqs); expr_ref expand(expr* e, dependency*& eqs); void add_dependency(dependency*& dep, enode* a, enode* b); From d7dcd022b997de6c7577b04005f16eb2207d1adc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Jan 2016 18:49:21 -0800 Subject: [PATCH 62/87] seq, API Signed-off-by: Nikolaj Bjorner --- src/api/java/Context.java | 83 ++++++++++++++++++++++++++++----------- src/api/ml/z3.ml | 82 ++++++++++++-------------------------- 2 files changed, 86 insertions(+), 79 deletions(-) diff --git a/src/api/java/Context.java b/src/api/java/Context.java index f27402e91..40b597be4 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -103,6 +103,7 @@ public class Context extends IDisposable private BoolSort m_boolSort = null; private IntSort m_intSort = null; private RealSort m_realSort = null; + private SeqSort m_stringSort = null; /** * Retrieves the Boolean sort of the context. @@ -142,6 +143,16 @@ public class Context extends IDisposable return new BoolSort(this); } + /** + * Retrieves the Integer sort of the context. + **/ + public SeqSort getStringSort() + { + if (m_stringSort == null) + m_stringSort = mkStringSort(); + return m_stringSort; + } + /** * Create a new uninterpreted sort. **/ @@ -193,6 +204,31 @@ public class Context extends IDisposable return new ArraySort(this, domain, range); } + /** + * Create a new string sort + **/ + public SeqSort mkStringSort() + { + return new SeqSort(this, Native.mkStringSort(nCtx())); + } + + /** + * Create a new sequence sort + **/ + public SeqSort mkSeqSort(Sort s) + { + return new SeqSort(this, Native.mkSeqSort(nCtx(), s.getNativeObject())); + } + + /** + * Create a new regular expression sort + **/ + public ReSort mkReSort(Sort s) + { + return new ReSort(this, Native.mkReSort(nCtx(), s.getNativeObject())); + } + + /** * Create a new tuple sort. **/ @@ -1860,7 +1896,7 @@ public class Context extends IDisposable public SeqExpr MkEmptySeq(Sort s) { checkContextMatch(s); - return new SeqExpr(this, Native.mkSeqEmpty(nCtx, s.NativeObject)); + return new SeqExpr(this, Native.mkSeqEmpty(nCtx(), s.getNativeObject())); } /** @@ -1869,24 +1905,24 @@ public class Context extends IDisposable public SeqExpr MkUnit(Expr elem) { checkContextMatch(elem); - return new SeqExpr(this, Native.mkSeqUnit(nCtx, elem.NativeObject)); + return new SeqExpr(this, Native.mkSeqUnit(nCtx(), elem.getNativeObject())); } /** * Create a string constant. */ - public SeqExpr MkString(string s) + public SeqExpr MkString(String s) { - return new SeqExpr(this, Native.mkString(nCtx, s)); + return new SeqExpr(this, Native.mkString(nCtx(), s)); } /** * Concatentate sequences. */ - public SeqExpr MkConcat(params SeqExpr[] t) + public SeqExpr MkConcat(SeqExpr... t) { checkContextMatch(t); - return new SeqExpr(this, Native.mkSeqConcat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + return new SeqExpr(this, Native.mkSeqConcat(nCtx(), (int)t.length, AST.arrayToNative(t))); } @@ -1896,7 +1932,7 @@ public class Context extends IDisposable public IntExpr MkLength(SeqExpr s) { checkContextMatch(s); - return (IntExpr) Expr.Create(this, Native.mkSeqLength(nCtx, s.NativeObject)); + return (IntExpr) Expr.create(this, Native.mkSeqLength(nCtx(), s.getNativeObject())); } /** @@ -1905,7 +1941,7 @@ public class Context extends IDisposable public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2) { checkContextMatch(s1, s2); - return new BoolExpr(this, Native.mkSeqPrefix(nCtx, s1.NativeObject, s2.NativeObject)); + return new BoolExpr(this, Native.mkSeqPrefix(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } /** @@ -1914,7 +1950,7 @@ public class Context extends IDisposable public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2) { checkContextMatch(s1, s2); - return new BoolExpr(this, Native.mkSeqSuffix(nCtx, s1.NativeObject, s2.NativeObject)); + return new BoolExpr(this, Native.mkSeqSuffix(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } /** @@ -1923,7 +1959,7 @@ public class Context extends IDisposable public BoolExpr MkContains(SeqExpr s1, SeqExpr s2) { checkContextMatch(s1, s2); - return new BoolExpr(this, Native.mkSeqContains(nCtx, s1.NativeObject, s2.NativeObject)); + return new BoolExpr(this, Native.mkSeqContains(nCtx(), s1.getNativeObject(), s2.getNativeObject())); } /** @@ -1932,7 +1968,7 @@ public class Context extends IDisposable public SeqExpr MkAt(SeqExpr s, IntExpr index) { checkContextMatch(s, index); - return new SeqExpr(this, Native.mkSeqAt(nCtx, s.NativeObject, index.NativeObject)); + return new SeqExpr(this, Native.mkSeqAt(nCtx(), s.getNativeObject(), index.getNativeObject())); } /** @@ -1941,7 +1977,7 @@ public class Context extends IDisposable public SeqExpr MkExtract(SeqExpr s, IntExpr offset, IntExpr length) { checkContextMatch(s, offset, length); - return new SeqExpr(this, Native.mkSeqExtract(nCtx, s.NativeObject, offset.NativeObject, length.NativeObject)); + return new SeqExpr(this, Native.mkSeqExtract(nCtx(), s.getNativeObject(), offset.getNativeObject(), length.getNativeObject())); } /** @@ -1950,7 +1986,7 @@ public class Context extends IDisposable public IntExpr MkIndexOf(SeqExpr s, SeqExpr substr, ArithExpr offset) { checkContextMatch(s, substr, offset); - return new IntExpr(this, Native.mkSeqIndex(nCtx, s.NativeObject, substr.NativeObject, offset.NativeObject)); + return new IntExpr(this, Native.mkSeqIndex(nCtx(), s.getNativeObject(), substr.getNativeObject(), offset.getNativeObject())); } /** @@ -1959,7 +1995,7 @@ public class Context extends IDisposable public SeqExpr MkReplace(SeqExpr s, SeqExpr src, SeqExpr dst) { checkContextMatch(s, src, dst); - return new SeqExpr(this, Native.mkSeqReplace(nCtx, s.NativeObject, src.NativeObject, dst.NativeObject)); + return new SeqExpr(this, Native.mkSeqReplace(nCtx(), s.getNativeObject(), src.getNativeObject(), dst.getNativeObject())); } /** @@ -1968,7 +2004,7 @@ public class Context extends IDisposable public ReExpr MkToRe(SeqExpr s) { checkContextMatch(s); - return new ReExpr(this, Native.mkSeqToRe(nCtx, s.NativeObject)); + return new ReExpr(this, Native.mkSeqToRe(nCtx(), s.getNativeObject())); } @@ -1978,7 +2014,7 @@ public class Context extends IDisposable public BoolExpr MkInRe(SeqExpr s, ReExpr re) { checkContextMatch(s, re); - return new BoolExpr(this, Native.mkSeqInRe(nCtx, s.NativeObject, re.NativeObject)); + return new BoolExpr(this, Native.mkSeqInRe(nCtx(), s.getNativeObject(), re.getNativeObject())); } /** @@ -1987,7 +2023,7 @@ public class Context extends IDisposable public ReExpr MkStar(ReExpr re) { checkContextMatch(re); - return new ReExpr(this, Native.mkReStar(nCtx, re.NativeObject)); + return new ReExpr(this, Native.mkReStar(nCtx(), re.getNativeObject())); } /** @@ -1996,7 +2032,7 @@ public class Context extends IDisposable public ReExpr MPlus(ReExpr re) { checkContextMatch(re); - return new ReExpr(this, Native.mkRePlus(nCtx, re.NativeObject)); + return new ReExpr(this, Native.mkRePlus(nCtx(), re.getNativeObject())); } /** @@ -2005,25 +2041,25 @@ public class Context extends IDisposable public ReExpr MOption(ReExpr re) { checkContextMatch(re); - return new ReExpr(this, Native.mkReOption(nCtx, re.NativeObject)); + return new ReExpr(this, Native.mkReOption(nCtx(), re.getNativeObject())); } /** * Create the concatenation of regular languages. */ - public ReExpr MkConcat(ReExpr[] t) + public ReExpr MkConcat(ReExpr... t) { checkContextMatch(t); - return new ReExpr(this, Native.mkReConcat(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + return new ReExpr(this, Native.mkReConcat(nCtx(), (int)t.length, AST.arrayToNative(t))); } /** * Create the union of regular languages. */ - public ReExpr MkUnion(ReExpr[] t) + public ReExpr MkUnion(ReExpr... t) { checkContextMatch(t); - return new ReExpr(this, Native.mkReUnion(nCtx, (uint)t.Length, AST.ArrayToNative(t))); + return new ReExpr(this, Native.mkReUnion(nCtx(), (int)t.length, AST.arrayToNative(t))); } @@ -4021,6 +4057,7 @@ public class Context extends IDisposable m_boolSort = null; m_intSort = null; m_realSort = null; + m_stringSort = null; synchronized (creation_lock) { if (m_refCount.get() == 0 && m_ctx != 0) { diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 9a9b17500..54b9c3932 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -88,8 +88,6 @@ struct (z3obj_create res) ; res - let ignore2 a b c = ignore a; ignore b - let ignore3 a b c = ignore a; ignore2 b c end @@ -837,20 +835,11 @@ end = struct let o = Z3native.mk_app (context_gno ctx) (AST.ptr_of_ast fa) (List.length args) (expr_lton args) in expr_of_ptr ctx o - let apply_un ctx f t = - let r = expr_of_ptr ctx (f (context_gno ctx) (gno t)) in - ignore t; - r + let apply1 ctx f t = expr_of_ptr ctx (f (context_gno ctx) (gno t)) in - let apply_bin ctx f t1 t2 = - let r = expr_of_ptr ctx (f (context_gno ctx) (gno t1) (gno t2)) in - ignore2 t1 t2; - r + let apply2 ctx f t1 t2 = expr_of_ptr ctx (f (context_gno ctx) (gno t1) (gno t2)) in - let apply_ter ctx f t1 t2 t3 = - let r = expr_of_ptr ctx (f (context_gno ctx) (gno t1) (gno t2) (gno t3)) in - ignore3 t1 t2 t3; - r + let apply3 ctx f t1 t2 t3 = expr_of_ptr ctx (f (context_gno ctx) (gno t1) (gno t2) (gno t3)) in let simplify ( x : expr ) ( p : Params.params option ) = match p with @@ -874,17 +863,13 @@ end = struct if ((AST.is_app (ast_of_expr x)) && (List.length args <> (get_num_args x))) then raise (Z3native.Exception "Number of arguments does not match") else - let r = expr_of_ptr (Expr.gc x) (Z3native.update_term (gnc x) (gno x) (List.length args) (expr_lton args)) in - ignore2 x args; - r - + expr_of_ptr (Expr.gc x) (Z3native.update_term (gnc x) (gno x) (List.length args) (expr_lton args)) + let substitute ( x : expr ) from to_ = if (List.length from) <> (List.length to_) then raise (Z3native.Exception "Argument sizes do not match") else - let r = expr_of_ptr (Expr.gc x) (Z3native.substitute (gnc x) (gno x) (List.length from) (expr_lton from) (expr_lton to_)) in - ignore3 from to_ x; - r + expr_of_ptr (Expr.gc x) (Z3native.substitute (gnc x) (gno x) (List.length from) (expr_lton from) (expr_lton to_)) let substitute_one ( x : expr ) from to_ = substitute ( x : expr ) [ from ] [ to_ ] @@ -896,9 +881,7 @@ end = struct if (Expr.gc x) == to_ctx then x else - let r = expr_of_ptr to_ctx (Z3native.translate (gnc x) (gno x) (context_gno to_ctx)) in - ignore2 x to_ctx; - r + expr_of_ptr to_ctx (Z3native.translate (gnc x) (gno x) (context_gno to_ctx)) let to_string ( x : expr ) = Z3native.ast_to_string (gnc x) (gno x) @@ -959,39 +942,33 @@ struct let mk_val ( ctx : context ) ( value : bool ) = if value then mk_true ctx else mk_false ctx - let mk_not ( ctx : context ) ( a : expr ) = apply_un ctx Z3native.mk_not a + let mk_not ( ctx : context ) ( a : expr ) = apply1 ctx Z3native.mk_not a let mk_ite ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( t3 : expr ) = - apply_ter ctx Z3native.mk_ite t1 t2 t3 + apply3 ctx Z3native.mk_ite t1 t2 t3 let mk_iff ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - apply_bin ctx Z3native.mk_iff t1 t2 + apply2 ctx Z3native.mk_iff t1 t2 let mk_implies ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - apply_bin ctx Z3native.mk_implies t1 t2 + apply2 ctx Z3native.mk_implies t1 t2 let mk_xor ( ctx : context ) ( t1 : expr ) ( t2 : expr ) = - apply_bin ctx Z3native.mk_xor t1 t2 + apply2 ctx Z3native.mk_xor t1 t2 let mk_and ( ctx : context ) ( args : expr list ) = let f x = (Expr.gno (x)) in - let r = expr_of_ptr ctx (Z3native.mk_and (context_gno ctx) (List.length args) (Array.of_list (List.map f args))) in - ignore args; - r + expr_of_ptr ctx (Z3native.mk_and (context_gno ctx) (List.length args) (Array.of_list (List.map f args))) let mk_or ( ctx : context ) ( args : expr list ) = let f x = (Expr.gno (x)) in - let r = expr_of_ptr ctx (Z3native.mk_or (context_gno ctx) (List.length args) (Array.of_list(List.map f args))) in - ignore args; - r + expr_of_ptr ctx (Z3native.mk_or (context_gno ctx) (List.length args) (Array.of_list(List.map f args))) let mk_eq ( ctx : context ) ( x : expr ) ( y : expr ) = - apply_bin ctx Z3native.mk_eq x y + apply2 ctx Z3native.mk_eq x y let mk_distinct ( ctx : context ) ( args : expr list ) = - let r = expr_of_ptr ctx (Z3native.mk_distinct (context_gno ctx) (List.length args) (expr_lton args)) in - ignore args; - r + expr_of_ptr ctx (Z3native.mk_distinct (context_gno ctx) (List.length args) (expr_lton args)) let get_bool_value ( x : expr ) = lbool_of_int (Z3native.get_bool_value (gnc x) (gno x)) @@ -1097,12 +1074,10 @@ struct mk_list f n let get_body ( x : quantifier ) = - apply_un (gc x) Z3native.get_quantifier_body x + apply1 (gc x) Z3native.get_quantifier_body x let mk_bound ( ctx : context ) ( index : int ) ( ty : Sort.sort ) = - let r = expr_of_ptr ctx (Z3native.mk_bound (context_gno ctx) index (Sort.gno ty)) in - ignore ty; - r + expr_of_ptr ctx (Z3native.mk_bound (context_gno ctx) index (Sort.gno ty)) let mk_pattern ( ctx : context ) ( terms : expr list ) = if (List.length terms) == 0 then @@ -1227,27 +1202,23 @@ struct mk_const ctx (Symbol.mk_string ctx name) domain range let mk_select ( ctx : context ) ( a : expr ) ( i : expr ) = - apply_bin ctx Z3native.mk_select a i + apply2 ctx Z3native.mk_select a i let mk_store ( ctx : context ) ( a : expr ) ( i : expr ) ( v : expr ) = - apply_ter ctx Z3native.mk_store a i v + apply3 ctx Z3native.mk_store a i v let mk_const_array ( ctx : context ) ( domain : Sort.sort ) ( v : expr ) = - let r = expr_of_ptr ctx (Z3native.mk_const_array (context_gno ctx) (Sort.gno domain) (Expr.gno v)) in - ignore2 domain v; - r + expr_of_ptr ctx (Z3native.mk_const_array (context_gno ctx) (Sort.gno domain) (Expr.gno v)) let mk_map ( ctx : context ) ( f : func_decl ) ( args : expr list ) = let m x = (Expr.gno x) in - let r = expr_of_ptr ctx (Z3native.mk_map (context_gno ctx) (FuncDecl.gno f) (List.length args) (Array.of_list (List.map m args))) in - ignore2 f args; - r + expr_of_ptr ctx (Z3native.mk_map (context_gno ctx) (FuncDecl.gno f) (List.length args) (Array.of_list (List.map m args))) let mk_term_array ( ctx : context ) ( arg : expr ) = - apply_un ctx Z3native.mk_array_default arg + apply1 ctx Z3native.mk_array_default arg let mk_array_ext ( ctx : context) ( arg1 : expr ) ( arg2 : expr ) = - apply_bin ctx Z3native.mk_array_ext arg1 arg2 + apply2 ctx Z3native.mk_array_ext arg1 arg2 end @@ -1270,14 +1241,13 @@ struct expr_of_ptr ctx (Z3native.mk_full_set (context_gno ctx) (Sort.gno domain)) let mk_set_add ( ctx : context ) ( set : expr ) ( element : expr ) = - apply_bin ctx Z3native.mk_set_add set element + apply2 ctx Z3native.mk_set_add set element let mk_del ( ctx : context ) ( set : expr ) ( element : expr ) = - apply_bin Z3native.mk_set_del set element + apply2 Z3native.mk_set_del set element let mk_union ( ctx : context ) ( args : expr list ) = let r = expr_of_ptr ctx (Z3native.mk_set_union (context_gno ctx) (List.length args) (expr_lton args)) in - ignore r; r let mk_intersection ( ctx : context ) ( args : expr list ) = From fbee36d035eecf1c7a25e38e601a621913254a8a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Jan 2016 20:42:07 -0800 Subject: [PATCH 63/87] remove debug asserts Signed-off-by: Nikolaj Bjorner --- src/muz/rel/dl_mk_simple_joins.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index d3c92b08c..b9febe53e 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -302,8 +302,6 @@ namespace datalog { } void remove_rule_from_pair(app_pair key, rule * r, unsigned original_len) { - SASSERT(m_costs.contains(key)); - SASSERT(m_costs.find(key)); pair_info * ptr = 0; if (m_costs.find(key, ptr) && ptr && ptr->remove_rule(r, original_len)) { From 2c1d2aad44b340da2aab15639a9f0acc6b50f7c9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Jan 2016 22:06:32 -0800 Subject: [PATCH 64/87] seq, API Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.cpp | 33 ++++++++----------------------- src/smt/theory_seq.cpp | 16 ++++++++++----- src/smt/theory_seq.h | 1 + 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 1231369c7..3ee8675d8 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -1001,7 +1001,7 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_ } if (l < s2.length()) { rs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l))); - } + } change = true; } @@ -1023,27 +1023,17 @@ bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_ } else if (!change) { // skip + SASSERT(lhs.empty()); } else { // could solve if either side is fixed size. SASSERT(szl > 0 && szr > 0); - if (head1 > 0) { - for (unsigned i = 0; i < szl; ++i) { - ls[i] = ls[i + head1]; - } - } - ls.shrink(szl); - if (head2 > 0) { - for (unsigned i = 0; i < szr; ++i) { - rs[i] = rs[i + head2]; - } - } - rs.shrink(szr); - lhs.push_back(m_util.str.mk_concat(ls.size(), ls.c_ptr())); - rhs.push_back(m_util.str.mk_concat(rs.size(), rs.c_ptr())); + lhs.push_back(m_util.str.mk_concat(szl, ls.c_ptr() + head1)); + rhs.push_back(m_util.str.mk_concat(szr, rs.c_ptr() + head2)); ls.reset(); rs.reset(); } + SASSERT(lhs.empty() || ls.empty()); return true; } @@ -1054,16 +1044,9 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve m_util.str.get_concat(r, m_rhs); if (reduce_eq(m_lhs, m_rhs, lhs, rhs)) { SASSERT(lhs.size() == rhs.size()); - if (!m_lhs.empty()) { - SASSERT(!m_rhs.empty()); - lhs.push_back(m_util.str.mk_concat(m_lhs.size(), m_lhs.c_ptr())); - rhs.push_back(m_util.str.mk_concat(m_rhs.size(), m_rhs.c_ptr())); - } - for (unsigned i = 0; i < lhs.size(); ++i) { - SASSERT(is_well_sorted(m(), lhs[i].get())); - SASSERT(is_well_sorted(m(), rhs[i].get())); - SASSERT(m().get_sort(lhs[i].get()) == m().get_sort(rhs[i].get())); - TRACE("seq", tout << mk_pp(lhs[i].get(), m()) << " = " << mk_pp(rhs[i].get(), m()) << "\n";); + if (lhs.empty()) { + lhs.push_back(l); + rhs.push_back(r); } return true; } diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 7aa434661..e3ede010c 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -166,6 +166,8 @@ theory_seq::theory_seq(ast_manager& m): m_autil(m), m_trail_stack(*this), m_atoms_qhead(0), + m_ls(m), m_rs(m), + m_lhs(m), m_rhs(m), m_new_solution(false), m_new_propagation(false) { m_prefix = "seq.prefix.suffix"; @@ -874,17 +876,21 @@ void theory_seq::solve_ne(unsigned idx) { } } for (unsigned i = 0; i < n.m_lhs.size(); ++i) { - expr_ref_vector lhs(m), rhs(m); + expr_ref_vector& ls = m_ls; + expr_ref_vector& rs = m_rs; + expr_ref_vector& lhs = m_lhs; + expr_ref_vector& rhs = m_rhs; + ls.reset(); rs.reset(); lhs.reset(); rhs.reset(); dependency* deps = 0; expr* l = n.m_lhs[i]; expr* r = n.m_rhs[i]; - expr_ref lh = canonize(l, deps); - expr_ref rh = canonize(r, deps); - if (!rw.reduce_eq(lh, rh, lhs, rhs)) { + canonize(l, ls, deps); + canonize(r, rs, deps); + if (!rw.reduce_eq(ls, rs, lhs, rhs)) { mark_solved(idx); return; } - else if (unchanged(l, lhs, r, rhs) ) { + else if (lhs.empty() || (lhs.size() == 1 && lhs[0].get() == l)) { // continue } else { diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 511c6917c..cd8d67cd1 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -318,6 +318,7 @@ namespace smt { symbol m_tail, m_nth, m_seq_first, m_seq_last, m_indexof_left, m_indexof_right, m_aut_step; symbol m_extract_prefix, m_at_left, m_at_right; ptr_vector m_todo; + expr_ref_vector m_ls, m_rs, m_lhs, m_rhs; // maintain automata with regular expressions. scoped_ptr_vector m_automata; From 2f9fda45c3e90fcfa0127448951cda2e4550b244 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Jan 2016 22:14:45 -0800 Subject: [PATCH 65/87] fix tabs Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 103 +++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 9129cb854..1a9ef204b 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -931,9 +931,9 @@ def _to_expr_ref(a, ctx): if sk == Z3_ROUNDING_MODE_SORT: return FPRMRef(a, ctx) if sk == Z3_SEQ_SORT: - return SeqRef(a, ctx) + return SeqRef(a, ctx) if sk == Z3_RE_SORT: - return ReRef(a, ctx) + return ReRef(a, ctx) return ExprRef(a, ctx) def _coerce_expr_merge(s, a): @@ -3573,24 +3573,24 @@ def Concat(*args): ctx = args[0].ctx if is_seq(args[0]): - if __debug__: - _z3_assert(all([is_seq(a) for a in args]), "All arguments must be sequence expressions.") - v = (Ast * sz)() + if __debug__: + _z3_assert(all([is_seq(a) for a in args]), "All arguments must be sequence expressions.") + v = (Ast * sz)() for i in range(sz): v[i] = args[i].as_ast() - return SeqRef(Z3_mk_seq_concat(ctx.ref(), sz, v), ctx) - + return SeqRef(Z3_mk_seq_concat(ctx.ref(), sz, v), ctx) + if is_re(args[0]): - if __debug__: - _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.") - v = (Ast * sz)() - for i in range(sz): - v[i] = args[i].as_ast() - return ReRef(Z3_mk_re_concat(ctx.ref(), sz, v), ctx) - + if __debug__: + _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.") + v = (Ast * sz)() + for i in range(sz): + v[i] = args[i].as_ast() + return ReRef(Z3_mk_re_concat(ctx.ref(), sz, v), ctx) + if __debug__: _z3_assert(all([is_bv(a) for a in args]), "All arguments must be Z3 bit-vector expressions.") - r = args[0] + r = args[0] for i in range(sz - 1): r = BitVecRef(Z3_mk_concat(ctx.ref(), r.as_ast(), args[i+1].as_ast()), ctx) return r @@ -3607,14 +3607,14 @@ def Extract(high, low, a): "c" """ if isinstance(high, str): - high = StringVal(high) + high = StringVal(high) if is_seq(high): - s = high - offset = _py2expr(low, high.ctx) - length = _py2expr(a, high.ctx) - - if __debug__: - _z3_assert(is_int(offset) and is_int(length), "Second and third arguments must be integers") + s = high + offset = _py2expr(low, high.ctx) + length = _py2expr(a, high.ctx) + + if __debug__: + _z3_assert(is_int(offset) and is_int(length), "Second and third arguments must be integers") return SeqRef(Z3_mk_seq_extract(s.ctx_ref(), s.as_ast(), offset.as_ast(), length.as_ast()), s.ctx) if __debug__: _z3_assert(low <= high, "First argument must be greater than or equal to second argument") @@ -8951,15 +8951,15 @@ class SeqSortRef(SortRef): """Sequence sort.""" def is_string(self): - """Determine if sort is a string - >>> s = StringSort() - >>> s.is_string() - True - >>> s = SeqSort(IntSort()) - >>> s.is_string() - False - """ - return Z3_is_string_sort(self.ctx_ref(), self.ast) + """Determine if sort is a string + >>> s = StringSort() + >>> s.is_string() + True + >>> s = SeqSort(IntSort()) + >>> s.is_string() + False + """ + return Z3_is_string_sort(self.ctx_ref(), self.ast) def StringSort(ctx=None): """Create a string sort @@ -8983,19 +8983,19 @@ class SeqRef(ExprRef): """Sequence expression.""" def sort(self): - return SeqSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx) + return SeqSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx) def __add__(self, other): - return Concat(self, other) + return Concat(self, other) def __getitem__(self, i): - return SeqRef(Z3_mk_seq_at(self.ctx_ref(), self.as_ast(), i.as_ast()), self.ctx) - + return SeqRef(Z3_mk_seq_at(self.ctx_ref(), self.as_ast(), i.as_ast()), self.ctx) + def is_string(self): - return Z3_is_string_sort(self.ctx_ref(), Z3_get_sort(self.ctx_ref(), self.as_ast())) + return Z3_is_string_sort(self.ctx_ref(), Z3_get_sort(self.ctx_ref(), self.as_ast())) def is_string_value(self): - return Z3_is_string(self.ctx_ref(), self.as_ast()) + return Z3_is_string(self.ctx_ref(), self.as_ast()) def as_string(self): """Return a string representation of sequence expression.""" @@ -9004,17 +9004,17 @@ class SeqRef(ExprRef): def _coerce_seq(s, ctx=None): if isinstance(s, str): - ctx = _get_ctx(ctx) - s = StringVal(s, ctx) + ctx = _get_ctx(ctx) + s = StringVal(s, ctx) return s def _get_ctx2(a, b, ctx=None): if is_expr(a): - return a.ctx + return a.ctx if is_expr(b): - return b.ctx + return b.ctx if ctx is None: - ctx = main_ctx() + ctx = main_ctx() return ctx def is_seq(a): @@ -9136,7 +9136,7 @@ def Replace(s, src, dst): """ ctx = _get_ctx2(dst, s) if ctx is None and is_expr(src): - ctx = src.ctx + ctx = src.ctx src = _coerce_seq(src, ctx) dst = _coerce_seq(dst, ctx) s = _coerce_seq(s, ctx) @@ -9154,12 +9154,12 @@ def IndexOf(s, substr, offset): """ ctx = None if is_expr(offset): - ctx = offset.ctx + ctx = offset.ctx ctx = _get_ctx2(s, substr, ctx) s = _coerce_seq(s, ctx) substr = _coerce_seq(substr, ctx) if isinstance(offset, int): - offset = IntVal(offset, ctx) + offset = IntVal(offset, ctx) return SeqRef(Z3_mk_seq_index(s.ctx_ref(), s.as_ast(), substr.as_ast(), offset.as_ast()), s.ctx) def Length(s): @@ -9191,10 +9191,10 @@ class ReSortRef(SortRef): def ReSort(s): if is_ast(s): - return ReSortRef(Z3_mk_re_sort(s.ctx.ref(), s.as_ast()), ctx) + return ReSortRef(Z3_mk_re_sort(s.ctx.ref(), s.as_ast()), ctx) if s is None or isinstance(s, Context): - ctx = _get_ctx(s) - return ReSortRef(Z3_mk_re_sort(ctx.ref(), Z3_mk_string_sort(ctx.ref())), ctx) + ctx = _get_ctx(s) + return ReSortRef(Z3_mk_re_sort(ctx.ref(), Z3_mk_string_sort(ctx.ref())), ctx) raise Z3Exception("Regular expression sort constructor expects either a string or a context or no argument") @@ -9202,7 +9202,7 @@ class ReRef(ExprRef): """Regular expressions.""" def __add__(self, other): - return Union(self, other) + return Union(self, other) def is_re(s): @@ -9232,13 +9232,12 @@ def Union(*args): sz = len(args) if __debug__: _z3_assert(sz >= 2, "At least two arguments expected.") - _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.") + _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.") ctx = args[0].ctx v = (Ast * sz)() for i in range(sz): - v[i] = args[i].as_ast() + v[i] = args[i].as_ast() return ReRef(Z3_mk_re_union(ctx.ref(), sz, v), ctx) - def Plus(re): """Create the regular expression accepting one or more repetitions of argument. From 3f040dbd23b7a3dc622c31c6ca51aef30f073a29 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Jan 2016 22:26:54 -0800 Subject: [PATCH 66/87] remove std::cout usage Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/expr_safe_replace.cpp | 1 - src/muz/rel/dl_mk_simple_joins.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp index 8ce40e49a..25a8fd657 100644 --- a/src/ast/rewriter/expr_safe_replace.cpp +++ b/src/ast/rewriter/expr_safe_replace.cpp @@ -76,7 +76,6 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) { } } else { - (std::cout << "q\n").flush(); SASSERT(is_quantifier(a)); quantifier* q = to_quantifier(a); expr_safe_replace replace(m); diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp index b6fe39617..b9febe53e 100644 --- a/src/muz/rel/dl_mk_simple_joins.cpp +++ b/src/muz/rel/dl_mk_simple_joins.cpp @@ -273,7 +273,6 @@ namespace datalog { */ void register_pair(app * t1, app * t2, rule * r, const var_idx_set & non_local_vars) { SASSERT(t1!=t2); - std::cout << "insert: " << mk_pp(t1, m) << " - " << mk_pp(t2, m) << "\n"; cost_map::entry * e = m_costs.insert_if_not_there2(get_key(t1, t2), 0); pair_info * & ptr_inf = e->get_data().m_value; if (ptr_inf==0) { From c008c2c274fb56903a308d5173389a1b6946e912 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Jan 2016 22:36:50 -0800 Subject: [PATCH 67/87] fix indentation error Signed-off-by: Nikolaj Bjorner --- src/api/python/z3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 1a9ef204b..695ee9632 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -3576,7 +3576,7 @@ def Concat(*args): if __debug__: _z3_assert(all([is_seq(a) for a in args]), "All arguments must be sequence expressions.") v = (Ast * sz)() - for i in range(sz): + for i in range(sz): v[i] = args[i].as_ast() return SeqRef(Z3_mk_seq_concat(ctx.ref(), sz, v), ctx) From a2fb4fc589d54ff776ec9b20a0849b9926fbb345 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 4 Jan 2016 22:49:28 -0800 Subject: [PATCH 68/87] remove tabs, fix build Signed-off-by: Nikolaj Bjorner --- src/api/python/z3printer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py index 24d0359c9..1561e6667 100644 --- a/src/api/python/z3printer.py +++ b/src/api/python/z3printer.py @@ -571,7 +571,7 @@ class Formatter: return to_format(a.as_decimal(self.precision)) def pp_string(self, a): - return to_format(a.as_string()) + return to_format(a.as_string()) def pp_bv(self, a): return to_format(a.as_string()) @@ -878,8 +878,8 @@ class Formatter: return self.pp_fp_value(a) elif z3.is_fp(a): return self.pp_fp(a, d, xs) - elif z3.is_string_value(a): - return self.pp_string(a) + elif z3.is_string_value(a): + return self.pp_string(a) elif z3.is_const(a): return self.pp_const(a) else: From a06f754683c04ecf8cf502b8c3c0df1384a317a3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 5 Jan 2016 03:31:21 -0800 Subject: [PATCH 69/87] tabs --- src/api/python/z3printer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py index 24d0359c9..1561e6667 100644 --- a/src/api/python/z3printer.py +++ b/src/api/python/z3printer.py @@ -571,7 +571,7 @@ class Formatter: return to_format(a.as_decimal(self.precision)) def pp_string(self, a): - return to_format(a.as_string()) + return to_format(a.as_string()) def pp_bv(self, a): return to_format(a.as_string()) @@ -878,8 +878,8 @@ class Formatter: return self.pp_fp_value(a) elif z3.is_fp(a): return self.pp_fp(a, d, xs) - elif z3.is_string_value(a): - return self.pp_string(a) + elif z3.is_string_value(a): + return self.pp_string(a) elif z3.is_const(a): return self.pp_const(a) else: From bd8a5982ad70d44d4cb6ed7cb5de8516a3973d3a Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 5 Jan 2016 11:37:34 +0000 Subject: [PATCH 70/87] Added new items to .NET project file --- src/api/dotnet/Microsoft.Z3.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/api/dotnet/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj index a753e0193..cde8b78c9 100644 --- a/src/api/dotnet/Microsoft.Z3.csproj +++ b/src/api/dotnet/Microsoft.Z3.csproj @@ -374,7 +374,11 @@ + + + + From 097552768f6b878ebded164dc5fc0451a6d0d884 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 5 Jan 2016 11:51:28 +0000 Subject: [PATCH 71/87] Merged Python API changes. --- src/api/python/z3.py | 420 +++++++++++++++++++++--------------- src/api/python/z3printer.py | 26 ++- 2 files changed, 265 insertions(+), 181 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 695ee9632..4fc362e20 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -999,6 +999,8 @@ def is_expr(a): >>> x = Int('x') >>> is_expr(ForAll(x, x >= 0)) True + >>> is_expr(FPVal(1.0)) + True """ return isinstance(a, ExprRef) @@ -7912,6 +7914,30 @@ def _dflt_rm(ctx=None): def _dflt_fps(ctx=None): return get_default_fp_sort(ctx) +def _coerce_fp_expr_list(alist, ctx): + first_fp_sort = None + for a in alist: + if is_fp(a): + if first_fp_sort == None: + first_fp_sort = a.sort() + elif first_fp_sort == a.sort(): + pass # OK, same as before + else: + # we saw at least 2 different float sorts; something will + # throw a sort mismatch later, for now assume None. + first_fp_sort = None + break + + r = [] + for i in range(len(alist)): + a = alist[i] + if (isinstance(a, str) and a.contains('2**(') and a.endswith(')')) or _is_int(a) or isinstance(a, float) or isinstance(a, bool): + r.append(FPVal(a, None, first_fp_sort, ctx)) + else: + r.append(a) + return _coerce_expr_list(r, ctx) + + ### FP Sorts class FPSortRef(SortRef): @@ -8076,8 +8102,8 @@ class FPRef(ExprRef): >>> (x + y).sort() FPSort(8, 24) """ - a, b = z3._coerce_exprs(self, other) - return fpAdd(_dflt_rm(), self, other) + [a, b] = _coerce_fp_expr_list([self, other], self.ctx) + return fpAdd(_dflt_rm(), a, b, self.ctx) def __radd__(self, other): """Create the Z3 expression `other + self`. @@ -8086,8 +8112,8 @@ class FPRef(ExprRef): >>> 10 + x 1.25*(2**3) + x """ - a, b = _coerce_exprs(self, other) - return fpAdd(_dflt_rm(), other, self) + [a, b] = _coerce_fp_expr_list([other, self], self.ctx) + return fpAdd(_dflt_rm(), a, b, self.ctx) def __sub__(self, other): """Create the Z3 expression `self - other`. @@ -8099,8 +8125,8 @@ class FPRef(ExprRef): >>> (x - y).sort() FPSort(8, 24) """ - a, b = z3._coerce_exprs(self, other) - return fpSub(_dflt_rm(), self, other) + [a, b] = _coerce_fp_expr_list([self, other], self.ctx) + return fpSub(_dflt_rm(), a, b, self.ctx) def __rsub__(self, other): """Create the Z3 expression `other - self`. @@ -8109,9 +8135,9 @@ class FPRef(ExprRef): >>> 10 - x 1.25*(2**3) - x """ - a, b = _coerce_exprs(self, other) - return fpSub(_dflt_rm(), other, self) - + [a, b] = _coerce_fp_expr_list([other, self], self.ctx) + return fpSub(_dflt_rm(), a, b, self.ctx) + def __mul__(self, other): """Create the Z3 expression `self * other`. @@ -8124,8 +8150,8 @@ class FPRef(ExprRef): >>> 10 * y 1.25*(2**3) * y """ - a, b = z3._coerce_exprs(self, other) - return fpMul(_dflt_rm(), self, other) + [a, b] = _coerce_fp_expr_list([self, other], self.ctx) + return fpMul(_dflt_rm(), a, b, self.ctx) def __rmul__(self, other): """Create the Z3 expression `other * self`. @@ -8137,8 +8163,8 @@ class FPRef(ExprRef): >>> x * 10 x * 1.25*(2**3) """ - a, b = _coerce_exprs(self, other) - return fpMul(_dflt_rm(), other, self) + [a, b] = _coerce_fp_expr_list([other, self], self.ctx) + return fpMul(_dflt_rm(), a, b, self.ctx) def __pos__(self): """Create the Z3 expression `+self`.""" @@ -8147,14 +8173,43 @@ class FPRef(ExprRef): def __neg__(self): """Create the Z3 expression `-self`.""" return FPRef(fpNeg(self)) + + def __div__(self, other): + """Create the Z3 expression `self / other`. + + >>> x = FP('x', FPSort(8, 24)) + >>> y = FP('y', FPSort(8, 24)) + >>> x / y + x / y + >>> (x / y).sort() + FPSort(8, 24) + >>> 10 / y + 1.25*(2**3) / y + """ + [a, b] = _coerce_fp_expr_list([self, other], self.ctx) + return fpDiv(_dflt_rm(), a, b, self.ctx) - def __truediv__(self, other): - """Create the Z3 expression division `self / other`.""" - return self.__div__(other) + def __rdiv__(self, other): + """Create the Z3 expression `other / self`. + + >>> x = FP('x', FPSort(8, 24)) + >>> y = FP('y', FPSort(8, 24)) + >>> x / y + x / y + >>> x / 10 + x / 1.25*(2**3) + """ + [a, b] = _coerce_fp_expr_list([other, self], self.ctx) + return fpDiv(_dflt_rm(), a, b, self.ctx) - def __rtruediv__(self, other): - """Create the Z3 expression division `other / self`.""" - return self.__rdiv__(other) + if not sys.version < '3': + def __truediv__(self, other): + """Create the Z3 expression division `self / other`.""" + return self.__div__(other) + + def __rtruediv__(self, other): + """Create the Z3 expression division `other / self`.""" + return self.__rdiv__(other) def __mod__(self, other): """Create the Z3 expression mod `self % other`.""" @@ -8384,31 +8439,60 @@ def _to_float_str(val, exp=0): def fpNaN(s): + """Create a Z3 floating-point NaN term. + + >>> s = FPSort(8, 24) + >>> set_fpa_pretty(True) + >>> fpNaN(s) + NaN + >>> pb = get_fpa_pretty() + >>> set_fpa_pretty(False) + >>> fpNaN(s) + fpNaN(FPSort(8, 24)) + >>> set_fpa_pretty(pb) + """ _z3_assert(isinstance(s, FPSortRef), "sort mismatch") return FPNumRef(Z3_mk_fpa_nan(s.ctx_ref(), s.ast), s.ctx) def fpPlusInfinity(s): + """Create a Z3 floating-point +oo term. + + >>> s = FPSort(8, 24) + >>> pb = get_fpa_pretty() + >>> set_fpa_pretty(True) + >>> fpPlusInfinity(s) + +oo + >>> set_fpa_pretty(False) + >>> fpPlusInfinity(s) + fpPlusInfinity(FPSort(8, 24)) + >>> set_fpa_pretty(pb) + """ _z3_assert(isinstance(s, FPSortRef), "sort mismatch") return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, False), s.ctx) def fpMinusInfinity(s): + """Create a Z3 floating-point -oo term.""" _z3_assert(isinstance(s, FPSortRef), "sort mismatch") return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, True), s.ctx) def fpInfinity(s, negative): + """Create a Z3 floating-point +oo or -oo term.""" _z3_assert(isinstance(s, FPSortRef), "sort mismatch") _z3_assert(isinstance(negative, bool), "expected Boolean flag") return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, negative), s.ctx) def fpPlusZero(s): + """Create a Z3 floating-point +0.0 term.""" _z3_assert(isinstance(s, FPSortRef), "sort mismatch") return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, False), s.ctx) def fpMinusZero(s): + """Create a Z3 floating-point -0.0 term.""" _z3_assert(isinstance(s, FPSortRef), "sort mismatch") return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, True), s.ctx) def fpZero(s, negative): + """Create a Z3 floating-point +0.0 or -0.0 term.""" _z3_assert(isinstance(s, FPSortRef), "sort mismatch") _z3_assert(isinstance(negative, bool), "expected Boolean flag") return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, negative), s.ctx) @@ -8456,8 +8540,8 @@ def FP(name, fpsort, ctx=None): >>> x2 = FP('x', word) >>> eq(x, x2) True - """ - if isinstance(fpsort, FPSortRef): + """ + if isinstance(fpsort, FPSortRef) and ctx is None: ctx = fpsort.ctx else: ctx = _get_ctx(ctx) @@ -8481,7 +8565,7 @@ def FPs(names, fpsort, ctx=None): names = names.split(" ") return [FP(name, fpsort, ctx) for name in names] -def fpAbs(a): +def fpAbs(a, ctx=None): """Create a Z3 floating-point absolute value expression. >>> s = FPSort(8, 24) @@ -8499,18 +8583,11 @@ def fpAbs(a): >>> fpAbs(x).sort() FPSort(8, 24) """ - ctx = None - if not is_expr(a): - ctx =_get_ctx(ctx) - s = get_default_fp_sort(ctx) - a = FPVal(a, s) - else: - ctx = a.ctx - if __debug__: - _z3_assert(is_fp(a), "First argument must be Z3 floating-point expression") - return FPRef(Z3_mk_fpa_abs(a.ctx_ref(), a.as_ast()), a.ctx) + ctx = _get_ctx(ctx) + [a] = _coerce_fp_expr_list([a], ctx) + return FPRef(Z3_mk_fpa_abs(ctx.ref(), a.as_ast()), ctx) -def fpNeg(a): +def fpNeg(a, ctx=None): """Create a Z3 floating-point addition expression. >>> s = FPSort(8, 24) @@ -8521,18 +8598,63 @@ def fpNeg(a): >>> fpNeg(x).sort() FPSort(8, 24) """ - ctx = None - if not is_expr(a): - ctx =_get_ctx(ctx) - s = get_default_fp_sort(ctx) - a = FPVal(a, s) - else: - ctx = a.ctx - if __debug__: - _z3_assert(is_fp(a), "First argument must be Z3 floating-point expression") - return FPRef(Z3_mk_fpa_neg(a.ctx_ref(), a.as_ast()), a.ctx) + ctx = _get_ctx(ctx) + [a] = _coerce_fp_expr_list([a], ctx) + return FPRef(Z3_mk_fpa_neg(ctx.ref(), a.as_ast()), ctx) -def fpAdd(rm, a, b): +def _mk_fp_unary(f, rm, a, ctx): + ctx = _get_ctx(ctx) + [a] = _coerce_fp_expr_list([a], ctx) + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(a), "Second argument must be a Z3 floating-point expression") + return FPRef(f(ctx.ref(), rm.as_ast(), a.as_ast()), ctx) + +def _mk_fp_unary_norm(f, a, ctx): + ctx = _get_ctx(ctx) + [a] = _coerce_fp_expr_list([a], ctx) + if __debug__: + _z3_assert(is_fp(a), "First argument must be a Z3 floating-point expression") + return FPRef(f(ctx.ref(), a.as_ast()), ctx) + +def _mk_fp_unary_pred(f, a, ctx): + ctx = _get_ctx(ctx) + [a] = _coerce_fp_expr_list([a], ctx) + if __debug__: + _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression") + return BoolRef(f(ctx.ref(), a.as_ast()), ctx) + +def _mk_fp_bin(f, rm, a, b, ctx): + ctx = _get_ctx(ctx) + [a, b] = _coerce_fp_expr_list([a, b], ctx) + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression") + return FPRef(f(ctx.ref(), rm.as_ast(), a.as_ast(), b.as_ast()), ctx) + +def _mk_fp_bin_norm(f, a, b, ctx): + ctx = _get_ctx(ctx) + [a, b] = _coerce_fp_expr_list([a, b], ctx) + if __debug__: + _z3_assert(is_fp(a) or is_fp(b), "First or second argument must be a Z3 floating-point expression") + return FPRef(f(ctx.ref(), a.as_ast(), b.as_ast()), ctx) + +def _mk_fp_bin_pred(f, a, b, ctx): + ctx = _get_ctx(ctx) + [a, b] = _coerce_fp_expr_list([a, b], ctx) + if __debug__: + _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression") + return BoolRef(f(ctx.ref(), a.as_ast(), b.as_ast()), ctx) + +def _mk_fp_tern(f, rm, a, b, c, ctx): + ctx = _get_ctx(ctx) + [a, b, c] = _coerce_fp_expr_list([a, b, c], ctx) + if __debug__: + _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") + _z3_assert(is_fp(a) or is_fp(b) or is_fp(c), "At least one of the arguments must be a Z3 floating-point expression") + return FPRef(f(ctx.ref(), rm.as_ast(), a.as_ast(), b.as_ast(), c.as_ast()), ctx) + +def fpAdd(rm, a, b, ctx=None): """Create a Z3 floating-point addition expression. >>> s = FPSort(8, 24) @@ -8541,16 +8663,14 @@ def fpAdd(rm, a, b): >>> y = FP('y', s) >>> fpAdd(rm, x, y) fpAdd(RNE(), x, y) + >>> fpAdd(RTZ(), x, y) # default rounding mode is RTZ + x + y >>> fpAdd(rm, x, y).sort() FPSort(8, 24) """ - if __debug__: - _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") - _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression") - a, b = _coerce_exprs(a, b) - return FPRef(Z3_mk_fpa_add(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx) - -def fpSub(rm, a, b): + return _mk_fp_bin(Z3_mk_fpa_add, rm, a, b, ctx) + +def fpSub(rm, a, b, ctx=None): """Create a Z3 floating-point subtraction expression. >>> s = FPSort(8, 24) @@ -8562,13 +8682,9 @@ def fpSub(rm, a, b): >>> fpSub(rm, x, y).sort() FPSort(8, 24) """ - if __debug__: - _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") - _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression") - a, b = _coerce_exprs(a, b) - return FPRef(Z3_mk_fpa_sub(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx) + return _mk_fp_bin(Z3_mk_fpa_sub, rm, a, b, ctx) -def fpMul(rm, a, b): +def fpMul(rm, a, b, ctx=None): """Create a Z3 floating-point multiplication expression. >>> s = FPSort(8, 24) @@ -8580,13 +8696,9 @@ def fpMul(rm, a, b): >>> fpMul(rm, x, y).sort() FPSort(8, 24) """ - if __debug__: - _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") - _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression") - a, b = _coerce_exprs(a, b) - return FPRef(Z3_mk_fpa_mul(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx) - -def fpDiv(rm, a, b): + return _mk_fp_bin(Z3_mk_fpa_mul, rm, a, b, ctx) + +def fpDiv(rm, a, b, ctx=None): """Create a Z3 floating-point divison expression. >>> s = FPSort(8, 24) @@ -8598,13 +8710,9 @@ def fpDiv(rm, a, b): >>> fpDiv(rm, x, y).sort() FPSort(8, 24) """ - if __debug__: - _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") - _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression") - a, b = _coerce_exprs(a, b) - return FPRef(Z3_mk_fpa_div(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx) + return _mk_fp_bin(Z3_mk_fpa_div, rm, a, b, ctx) -def fpRem(a, b): +def fpRem(a, b, ctx=None): """Create a Z3 floating-point remainder expression. >>> s = FPSort(8, 24) @@ -8615,12 +8723,9 @@ def fpRem(a, b): >>> fpRem(x, y).sort() FPSort(8, 24) """ - if __debug__: - _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression") - a, b = _coerce_exprs(a, b) - return FPRef(Z3_mk_fpa_rem(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + return _mk_fp_bin_norm(Z3_mk_fpa_rem, a, b, ctx) -def fpMin(a, b): +def fpMin(a, b, ctx=None): """Create a Z3 floating-point minimium expression. >>> s = FPSort(8, 24) @@ -8632,12 +8737,9 @@ def fpMin(a, b): >>> fpMin(x, y).sort() FPSort(8, 24) """ - if __debug__: - _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression") - a, b = _coerce_exprs(a, b) - return FPRef(Z3_mk_fpa_min(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + return _mk_fp_bin_norm(Z3_mk_fpa_min, a, b, ctx) -def fpMax(a, b): +def fpMax(a, b, ctx=None): """Create a Z3 floating-point maximum expression. >>> s = FPSort(8, 24) @@ -8649,104 +8751,75 @@ def fpMax(a, b): >>> fpMax(x, y).sort() FPSort(8, 24) """ - if __debug__: - _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression") - a, b = _coerce_exprs(a, b) - return FPRef(Z3_mk_fpa_max(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + return _mk_fp_bin_norm(Z3_mk_fpa_max, a, b, ctx) -def fpFMA(rm, a, b, c): +def fpFMA(rm, a, b, c, ctx=None): """Create a Z3 floating-point fused multiply-add expression. """ - if __debug__: - _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") - _z3_assert(is_fp(a) or is_fp(b) or is_fp(c), "Second, third, or fourth argument must be a Z3 floating-point expression") - a, b, c = _coerce_expr_list([a, b, c]) - return FPRef(Z3_mk_fpa_fma(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast(), c.as_ast()), rm.ctx) + return _mk_fp_tern(Z3_mk_fpa_fma, rm, a, b, c, ctx) -def fpSqrt(rm, a): +def fpSqrt(rm, a, ctx=None): """Create a Z3 floating-point square root expression. """ - ctx = None - if not is_expr(a): - ctx =_get_ctx(ctx) - s = get_default_fp_sort(ctx) - a = FPVal(a, s) - else: - ctx = a.ctx - if __debug__: - _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") - _z3_assert(is_fp(a), "Second argument must be a Z3 floating-point expressions") - return FPRef(Z3_mk_fpa_sqrt(rm.ctx_ref(), rm.as_ast(), a.as_ast()), rm.ctx) + return _mk_fp_unary(Z3_mk_fpa_sqrt, rm, a, ctx) -def fpRoundToIntegral(rm, a): +def fpRoundToIntegral(rm, a, ctx=None): """Create a Z3 floating-point roundToIntegral expression. """ - ctx = None - if not is_expr(a): - ctx =_get_ctx(ctx) - s = get_default_fp_sort(ctx) - a = FPVal(a, s) - else: - ctx = a.ctx - if __debug__: - _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") - _z3_assert(is_fp(a), "Second argument must be a Z3 floating-point expressions") - return FPRef(Z3_mk_fpa_round_to_integral(rm.ctx_ref(), rm.as_ast(), a.as_ast()), rm.ctx) + return _mk_fp_unary(Z3_mk_fpa_round_to_integral, rm, a, ctx) -def fpIsNaN(a): +def fpIsNaN(a, ctx=None): """Create a Z3 floating-point isNaN expression. - """ - if __debug__: - _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") - return FPRef(Z3_mk_fpa_is_nan(a.ctx_ref(), a.as_ast()), a.ctx) -def fpIsInfinite(a): + >>> s = FPSort(8, 24) + >>> x = FP('x', s) + >>> y = FP('y', s) + >>> fpIsNaN(x) + fpIsNaN(x) + """ + return _mk_fp_unary_norm(Z3_mk_fpa_is_nan, a, ctx) + +def fpIsInf(a, ctx=None): """Create a Z3 floating-point isInfinite expression. - """ - if __debug__: - _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") - return FPRef(Z3_mk_fpa_is_infinite(a.ctx_ref(), a.as_ast()), a.ctx) -def fpIsZero(a): + >>> s = FPSort(8, 24) + >>> x = FP('x', s) + >>> fpIsInf(x) + fpIsInf(x) + """ + return _mk_fp_unary_norm(Z3_mk_fpa_is_infinite, a, ctx) + +def fpIsZero(a, ctx=None): """Create a Z3 floating-point isZero expression. """ - if __debug__: - _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") - return FPRef(Z3_mk_fpa_is_zero(a.ctx_ref(), a.as_ast()), a.ctx) + return _mk_fp_unary_norm(Z3_mk_fpa_is_zero, a, ctx) -def fpIsNormal(a): +def fpIsNormal(a, ctx=None): """Create a Z3 floating-point isNormal expression. """ - if __debug__: - _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") - return FPRef(Z3_mk_fpa_is_normal(a.ctx_ref(), a.as_ast()), a.ctx) + return _mk_fp_unary_norm(Z3_mk_fpa_is_normal, a, ctx) -def fpIsSubnormal(a): +def fpIsSubnormal(a, ctx=None): """Create a Z3 floating-point isSubnormal expression. """ - if __debug__: - _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") - return FPRef(Z3_mk_fpa_is_subnormal(a.ctx_ref(), a.as_ast()), a.ctx) + return _mk_fp_unary_norm(Z3_mk_fpa_is_subnormal, a, ctx) -def fpIsNegative(a): +def fpIsNegative(a, ctx=None): """Create a Z3 floating-point isNegative expression. """ - if __debug__: - _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") - return FPRef(Z3_mk_fpa_is_negative(a.ctx_ref(), a.as_ast()), a.ctx) + return _mk_fp_unary_norm(Z3_mk_fpa_is_negative, a, ctx) -def fpIsPositive(a): +def fpIsPositive(a, ctx=None): """Create a Z3 floating-point isPositive expression. """ - if __debug__: - _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions") + return _mk_fp_unary_norm(Z3_mk_fpa_is_positive, a, ctx) return FPRef(Z3_mk_fpa_is_positive(a.ctx_ref(), a.as_ast()), a.ctx) def _check_fp_args(a, b): if __debug__: _z3_assert(is_fp(a) or is_fp(b), "At least one of the arguments must be a Z3 floating-point expression") -def fpLT(a, b): +def fpLT(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. >>> x, y = FPs('x y', FPSort(8, 24)) @@ -8755,11 +8828,9 @@ def fpLT(a, b): >>> (x <= y).sexpr() '(fp.leq x y)' """ - _check_fp_args(a, b) - a, b = _coerce_exprs(a, b) - return BoolRef(Z3_mk_fpa_lt(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + return _mk_fp_bin_pred(Z3_mk_fpa_lt, a, b, ctx) -def fpLEQ(a, b): +def fpLEQ(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. >>> x, y = FPs('x y', FPSort(8, 24)) @@ -8768,11 +8839,9 @@ def fpLEQ(a, b): >>> (x <= y).sexpr() '(fp.leq x y)' """ - _check_fp_args(a, b) - a, b = _coerce_exprs(a, b) - return BoolRef(Z3_mk_fpa_leq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + return _mk_fp_bin_pred(Z3_mk_fpa_leq, a, b, ctx) -def fpGT(a, b): +def fpGT(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. >>> x, y = FPs('x y', FPSort(8, 24)) @@ -8781,12 +8850,9 @@ def fpGT(a, b): >>> (x > y).sexpr() '(fp.gt x y)' """ - _check_fp_args(a, b) - a, b = _coerce_exprs(a, b) - return BoolRef(Z3_mk_fpa_gt(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + return _mk_fp_bin_pred(Z3_mk_fpa_gt, a, b, ctx) - -def fpGEQ(a, b): +def fpGEQ(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. >>> x, y = FPs('x y', FPSort(8, 24)) @@ -8797,11 +8863,9 @@ def fpGEQ(a, b): >>> (x >= y).sexpr() '(fp.geq x y)' """ - _check_fp_args(a, b) - a, b = _coerce_exprs(a, b) - return BoolRef(Z3_mk_fpa_geq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + return _mk_fp_bin_pred(Z3_mk_fpa_geq, a, b, ctx) -def fpEQ(a, b): +def fpEQ(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. >>> x, y = FPs('x y', FPSort(8, 24)) @@ -8810,11 +8874,9 @@ def fpEQ(a, b): >>> fpEQ(x, y).sexpr() '(fp.eq x y)' """ - _check_fp_args(a, b) - a, b = _coerce_exprs(a, b) - return BoolRef(Z3_mk_fpa_eq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) + return _mk_fp_bin_pred(Z3_mk_fpa_eq, a, b, ctx) -def fpNEQ(a, b): +def fpNEQ(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. >>> x, y = FPs('x y', FPSort(8, 24)) @@ -8823,18 +8885,26 @@ def fpNEQ(a, b): >>> (x != y).sexpr() '(not (fp.eq x y))' """ - _check_fp_args(a, b) - a, b = _coerce_exprs(a, b) - return Not(BoolRef(Z3_mk_fpa_eq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx), a.ctx) - - + return Not(fpEQ(a, b, ctx)) def fpFP(sgn, exp, sig): - """Create the Z3 floating-point value `fpFP(sgn, sig, exp)` from the three bit-vectorssgn, sig, and exp.""" + """Create the Z3 floating-point value `fpFP(sgn, sig, exp)` from the three bit-vectors sgn, sig, and exp. + + >>> s = FPSort(11, 53) + >>> x = fpFP(BitVecVal(1, 1), BitVecVal(0, 11), BitVecVal(0, 52)) + >>> print(x) + fpFP(1, 0, 0) + >>> slvr = Solver() + >>> slvr.add(fpEQ(x, fpMinusZero(s))) + >>> slvr.check() + sat + >>> slvr.model() + [x = 1] + """ _z3_assert(is_bv(sgn) and is_bv(exp) and is_bv(sig), "sort mismatch") _z3_assert(sgn.sort().size() == 1, "sort mismatch") - return FPRef(Z3_mk_fpa_fp(sgn.ctx_ref(), sgn.ast, exp.ast, sig.ast), sgn.ctx) - + _z3_assert(sgn.ctx == exp.ctx == sig.ctx, "sort mismatch") + return FPRef(Z3_mk_fpa_fp(sgn.ctx.ref(), sgn.ast, exp.ast, sig.ast), sgn.ctx) def fpToFP(a1, a2=None, a3=None): """Create a Z3 floating-point conversion expression from other terms.""" @@ -8849,7 +8919,7 @@ def fpToFP(a1, a2=None, a3=None): else: raise Z3Exception("Unsupported combination of arguments for conversion to floating-point term.") -def fpToFPUnsigned(rm, x, s): +def fpToFPUnsigned(rm, x, s, ctx=None): """Create a Z3 floating-point conversion expression, from unsigned bit-vector to floating-point expression.""" if __debug__: _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") @@ -8857,7 +8927,7 @@ def fpToFPUnsigned(rm, x, s): _z3_assert(is_fp_sort(s), "Third argument must be Z3 floating-point sort") return FPRef(Z3_mk_fpa_to_fp_unsigned(rm.ctx_ref(), rm.ast, x.ast, s.ast), rm.ctx) -def fpToSBV(rm, x, s): +def fpToSBV(rm, x, s, ctx=None): """Create a Z3 floating-point conversion expression, from floating-point expression to signed bit-vector. >>> x = FP('x', FPSort(8, 24)) diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py index 1561e6667..c8d69900a 100644 --- a/src/api/python/z3printer.py +++ b/src/api/python/z3printer.py @@ -68,8 +68,8 @@ _z3_op_to_fpa_normal_str = { Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN : 'RoundNearestTiesToEven()', Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY : 'RoundNearestTiesToAway()', Z3_OP_FPA_RM_TOWARD_POSITIVE : 'RoundTowardPositive()', Z3_OP_FPA_RM_TOWARD_NEGATIVE : 'RoundTowardNegative()', Z3_OP_FPA_RM_TOWARD_ZERO : 'RoundTowardZero()', - Z3_OP_FPA_PLUS_INF : '+oo', Z3_OP_FPA_MINUS_INF : '-oo', - Z3_OP_FPA_NAN : 'NaN', Z3_OP_FPA_PLUS_ZERO : 'PZero', Z3_OP_FPA_MINUS_ZERO : 'NZero', + Z3_OP_FPA_PLUS_INF : 'fpPlusInfinity', Z3_OP_FPA_MINUS_INF : 'fpMinusInfinity', + Z3_OP_FPA_NAN : 'fpNaN', Z3_OP_FPA_PLUS_ZERO : 'fpPZero', Z3_OP_FPA_MINUS_ZERO : 'fpNZero', Z3_OP_FPA_ADD : 'fpAdd', Z3_OP_FPA_SUB : 'fpSub', Z3_OP_FPA_NEG : 'fpNeg', Z3_OP_FPA_MUL : 'fpMul', Z3_OP_FPA_DIV : 'fpDiv', Z3_OP_FPA_REM : 'fpRem', Z3_OP_FPA_ABS : 'fpAbs', Z3_OP_FPA_MIN : 'fpMin', Z3_OP_FPA_MAX : 'fpMax', @@ -588,14 +588,24 @@ class Formatter: def pp_fp_value(self, a): z3._z3_assert(isinstance(a, z3.FPNumRef), 'type mismatch') - if not self.fpa_pretty: + if not self.fpa_pretty: + r = [] if (a.isNaN()): - return to_format('NaN') + r.append(to_format(_z3_op_to_fpa_normal_str[Z3_OP_FPA_NAN])) + r.append(to_format('(')) + r.append(to_format(a.sort())) + r.append(to_format(')')) + return compose(r) elif (a.isInf()): if (a.isNegative()): - return to_format('-oo') + r.append(to_format(_z3_op_to_fpa_normal_str[Z3_OP_FPA_MINUS_INF])) else: - return to_format('+oo') + r.append(to_format(_z3_op_to_fpa_normal_str[Z3_OP_FPA_PLUS_INF])) + r.append(to_format('(')) + r.append(to_format(a.sort())) + r.append(to_format(')')) + return compose(r) + elif (a.isZero()): if (a.isNegative()): return to_format('-zero') @@ -1195,6 +1205,10 @@ def set_fpa_pretty(flag=True): set_fpa_pretty(True) +def get_fpa_pretty(): + global Formatter + return _Formatter.fpa_pretty + def in_html_mode(): return isinstance(_Formatter, HTMLFormatter) From bc123dc79b865dcacdb6993e684a34c3befaea11 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 5 Jan 2016 14:10:32 +0000 Subject: [PATCH 72/87] fix build with c++98 compilers --- src/math/automata/automaton.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h index 2a4c964f9..e7d7c8bfb 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -476,7 +476,7 @@ public: get_moves(state, m_delta_inv, mvs, epsilon_closure); } - template + template std::ostream& display(std::ostream& out, D& displayer = D()) const { out << "init: " << init() << "\n"; out << "final: "; From 3e000d752542dd0aa4b795ca5a62b5d679e2c6ec Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 5 Jan 2016 14:40:31 +0000 Subject: [PATCH 73/87] build fix for libz3.vcxproj --- scripts/mk_util.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 89634c952..6a070fe93 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -3305,7 +3305,18 @@ def mk_z3consts_ml(api_files): def mk_gui_str(id): return '4D2F40D8-E5F9-473B-B548-%012d' % id -def mk_vs_proj_property_groups(f, name, type): +def get_platform_toolset_str(): + default = 'v110'; + vstr = check_output(['msbuild', '/ver']) + lines = vstr.split('\n') + lline = lines[-1] + tokens = lline.split('.') + if len(tokens) < 2: + return default + else: + return 'v' + tokens[0] + tokens[1] + +def mk_vs_proj_property_groups(f, name, target_ext, type): f.write(' \n') f.write(' \n') f.write(' Debug\n') @@ -3320,6 +3331,7 @@ def mk_vs_proj_property_groups(f, name, type): f.write(' {%s}\n' % mk_gui_str(0)) f.write(' %s\n' % name) f.write(' Win32Proj\n') + f.write(' %s\n' % get_platform_toolset_str()) f.write(' \n') f.write(' \n') f.write(' \n') @@ -3335,10 +3347,10 @@ def mk_vs_proj_property_groups(f, name, type): f.write(' \n') f.write(' $(SolutionDir)\$(ProjectName)\$(Configuration)\\n') f.write(' %s\n' % name) - f.write(' .dll\n') + f.write(' .%s\n' % target_ext) f.write(' $(SolutionDir)\$(ProjectName)\$(Configuration)\\n') f.write(' %s\n' % name) - f.write(' .dll\n') + f.write(' .%s\n' % target_ext) f.write(' \n') f.write(' \n') f.write(' $(ProjectName)\$(Configuration)\\n') @@ -3414,7 +3426,7 @@ def mk_vs_proj(name, components): f = open(proj_name, 'w') f.write('\n') f.write('\n') - mk_vs_proj_property_groups(f, name, 'Application') + mk_vs_proj_property_groups(f, name, 'exe', 'Application') f.write(' \n') mk_vs_proj_cl_compile(f, name, components, debug=True) mk_vs_proj_link_exe(f, name, debug=True) @@ -3455,7 +3467,7 @@ def mk_vs_proj_dll(name, components): f = open(proj_name, 'w') f.write('\n') f.write('\n') - mk_vs_proj_property_groups(f, name, 'DynamicLibrary') + mk_vs_proj_property_groups(f, name, 'dll', 'DynamicLibrary') f.write(' \n') mk_vs_proj_cl_compile(f, name, components, debug=True) mk_vs_proj_link_dll(f, name, debug=True) From 13cbd19411b4337d3491381204e3a890ae7acb91 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 5 Jan 2016 14:48:42 +0000 Subject: [PATCH 74/87] FPA Python API cleanup. --- src/api/python/z3.py | 1048 +++++++++++++++++++++--------------------- 1 file changed, 528 insertions(+), 520 deletions(-) diff --git a/src/api/python/z3.py b/src/api/python/z3.py index 4fc362e20..77af10463 100644 --- a/src/api/python/z3.py +++ b/src/api/python/z3.py @@ -1,7 +1,7 @@ ############################################ # Copyright (c) 2012 Microsoft Corporation -# +# # Z3 Python interface # # Author: Leonardo de Moura (leonardo) @@ -123,7 +123,7 @@ def _Z3python_error_handler_core(c, e): # Do nothing error handler, just avoid exit(0) # The wrappers in z3core.py will raise a Z3Exception if an error is detected return - + _Z3Python_error_handler = _error_handler_fptr(_Z3python_error_handler_core) def _to_param_value(val): @@ -137,12 +137,12 @@ def _to_param_value(val): class Context: """A Context manages all other Z3 objects, global configuration options, etc. - + Z3Py uses a default global context. For most applications this is sufficient. An application may use multiple Z3 contexts. Objects created in one context cannot be used in another one. However, several objects may be "translated" from one context to another. It is not safe to access Z3 objects from multiple threads. - The only exception is the method `interrupt()` that can be used to interrupt() a long + The only exception is the method `interrupt()` that can be used to interrupt() a long computation. The initialization method receives global configuration options for the new context. """ @@ -176,19 +176,19 @@ class Context: return self.ctx def interrupt(self): - """Interrupt a solver performing a satisfiability test, a tactic processing a goal, or simplify functions. + """Interrupt a solver performing a satisfiability test, a tactic processing a goal, or simplify functions. This method can be invoked from a thread different from the one executing the interruptable procedure. """ Z3_interrupt(self.ref()) - + # Global Z3 context _main_ctx = None def main_ctx(): - """Return a reference to the global Z3 context. - + """Return a reference to the global Z3 context. + >>> x = Real('x') >>> x.ctx == main_ctx() True @@ -204,7 +204,7 @@ def main_ctx(): global _main_ctx if _main_ctx == None: _main_ctx = Context() - return _main_ctx + return _main_ctx def _get_ctx(ctx): if ctx == None: @@ -293,7 +293,7 @@ class AstRef(Z3PPObject): def sexpr(self): """Return an string representing the AST node in s-expression notation. - + >>> x = Int('x') >>> ((x + 1)*x).sexpr() '(* (+ x 1) x)' @@ -311,10 +311,10 @@ class AstRef(Z3PPObject): def ctx_ref(self): """Return a reference to the C context where this AST node is stored.""" return self.ctx.ref() - + def eq(self, other): """Return `True` if `self` and `other` are structurally identical. - + >>> x = Int('x') >>> n1 = x + 1 >>> n2 = 1 + x @@ -328,10 +328,10 @@ class AstRef(Z3PPObject): if __debug__: _z3_assert(is_ast(other), "Z3 AST expected") return Z3_is_eq_ast(self.ctx_ref(), self.as_ast(), other.as_ast()) - + def translate(self, target): - """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`. - + """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`. + >>> c1 = Context() >>> c2 = Context() >>> x = Int('x', c1) @@ -347,7 +347,7 @@ class AstRef(Z3PPObject): def hash(self): """Return a hashcode for the `self`. - + >>> n1 = simplify(Int('x') + 1) >>> n2 = simplify(2 + Int('x') - 1) >>> n1.hash() == n2.hash() @@ -357,7 +357,7 @@ class AstRef(Z3PPObject): def is_ast(a): """Return `True` if `a` is an AST node. - + >>> is_ast(10) False >>> is_ast(IntVal(10)) @@ -377,7 +377,7 @@ def is_ast(a): def eq(a, b): """Return `True` if `a` and `b` are structurally identical AST nodes. - + >>> x = Int('x') >>> y = Int('y') >>> eq(x, y) @@ -463,7 +463,7 @@ class SortRef(AstRef): def kind(self): """Return the Z3 internal kind of a sort. This method can be used to test if `self` is one of the Z3 builtin sorts. - + >>> b = BoolSort() >>> b.kind() == Z3_BOOL_SORT True @@ -478,15 +478,15 @@ class SortRef(AstRef): return _sort_kind(self.ctx, self.ast) def subsort(self, other): - """Return `True` if `self` is a subsort of `other`. - + """Return `True` if `self` is a subsort of `other`. + >>> IntSort().subsort(RealSort()) True """ return False def cast(self, val): - """Try to cast `val` as an element of sort `self`. + """Try to cast `val` as an element of sort `self`. This method is used in Z3Py to convert Python objects such as integers, floats, longs and strings into Z3 expressions. @@ -494,7 +494,7 @@ class SortRef(AstRef): >>> x = Int('x') >>> RealSort().cast(x) ToReal(x) - """ + """ if __debug__: _z3_assert(is_expr(val), "Z3 expression expected") _z3_assert(self.eq(val.sort()), "Sort mismatch") @@ -502,7 +502,7 @@ class SortRef(AstRef): def name(self): """Return the name (string) of sort `self`. - + >>> BoolSort().name() 'Bool' >>> ArraySort(IntSort(), IntSort()).name() @@ -512,7 +512,7 @@ class SortRef(AstRef): def __eq__(self, other): """Return `True` if `self` and `other` are the same Z3 sort. - + >>> p = Bool('p') >>> p.sort() == BoolSort() True @@ -525,7 +525,7 @@ class SortRef(AstRef): def __ne__(self, other): """Return `True` if `self` and `other` are not the same Z3 sort. - + >>> p = Bool('p') >>> p.sort() != BoolSort() False @@ -540,7 +540,7 @@ class SortRef(AstRef): def is_sort(s): """Return `True` if `s` is a Z3 sort. - + >>> is_sort(IntSort()) True >>> is_sort(Int('x')) @@ -601,9 +601,9 @@ def DeclareSort(name, ctx=None): class FuncDeclRef(AstRef): """Function declaration. Every constant and function have an associated declaration. - + The declaration assigns a name, a sort (i.e., type), and for function - the sort (i.e., type) of each of its arguments. Note that, in Z3, + the sort (i.e., type) of each of its arguments. Note that, in Z3, a constant is a function with 0 arguments. """ def as_ast(self): @@ -617,7 +617,7 @@ class FuncDeclRef(AstRef): def name(self): """Return the name of the function declaration `self`. - + >>> f = Function('f', IntSort(), IntSort()) >>> f.name() 'f' @@ -628,7 +628,7 @@ class FuncDeclRef(AstRef): def arity(self): """Return the number of arguments of a function declaration. If `self` is a constant, then `self.arity()` is 0. - + >>> f = Function('f', IntSort(), RealSort(), BoolSort()) >>> f.arity() 2 @@ -637,7 +637,7 @@ class FuncDeclRef(AstRef): def domain(self, i): """Return the sort of the argument `i` of a function declaration. This method assumes that `0 <= i < self.arity()`. - + >>> f = Function('f', IntSort(), RealSort(), BoolSort()) >>> f.domain(0) Int @@ -650,7 +650,7 @@ class FuncDeclRef(AstRef): def range(self): """Return the sort of the range of a function declaration. For constants, this is the sort of the constant. - + >>> f = Function('f', IntSort(), RealSort(), BoolSort()) >>> f.range() Bool @@ -659,7 +659,7 @@ class FuncDeclRef(AstRef): def kind(self): """Return the internal kind of a function declaration. It can be used to identify Z3 built-in functions such as addition, multiplication, etc. - + >>> x = Int('x') >>> d = (x + 1).decl() >>> d.kind() == Z3_OP_ADD @@ -670,7 +670,7 @@ class FuncDeclRef(AstRef): return Z3_get_decl_kind(self.ctx_ref(), self.ast) def __call__(self, *args): - """Create a Z3 application expression using the function `self`, and the given arguments. + """Create a Z3 application expression using the function `self`, and the given arguments. The arguments must be Z3 expressions. This method assumes that the sorts of the elements in `args` match the sorts of the @@ -703,7 +703,7 @@ class FuncDeclRef(AstRef): def is_func_decl(a): """Return `True` if `a` is a Z3 function declaration. - + >>> f = Function('f', IntSort(), IntSort()) >>> is_func_decl(f) True @@ -714,8 +714,8 @@ def is_func_decl(a): return isinstance(a, FuncDeclRef) def Function(name, *sig): - """Create a new Z3 uninterpreted function with the given sorts. - + """Create a new Z3 uninterpreted function with the given sorts. + >>> f = Function('f', IntSort(), IntSort()) >>> f(f(0)) f(f(0)) @@ -748,10 +748,10 @@ class ExprRef(AstRef): """Constraints, formulas and terms are expressions in Z3. Expressions are ASTs. Every expression has a sort. - There are three main kinds of expressions: + There are three main kinds of expressions: function applications, quantifiers and bounded variables. A constant is a function application with 0 arguments. - For quantifier free problems, all expressions are + For quantifier free problems, all expressions are function applications. """ def as_ast(self): @@ -762,7 +762,7 @@ class ExprRef(AstRef): def sort(self): """Return the sort of expression `self`. - + >>> x = Int('x') >>> (x + 1).sort() Int @@ -774,7 +774,7 @@ class ExprRef(AstRef): def sort_kind(self): """Shorthand for `self.sort().kind()`. - + >>> a = Array('a', IntSort(), IntSort()) >>> a.sort_kind() == Z3_ARRAY_SORT True @@ -786,7 +786,7 @@ class ExprRef(AstRef): def __eq__(self, other): """Return a Z3 expression that represents the constraint `self == other`. - If `other` is `None`, then this method simply returns `False`. + If `other` is `None`, then this method simply returns `False`. >>> a = Int('a') >>> b = Int('b') @@ -806,8 +806,8 @@ class ExprRef(AstRef): def __ne__(self, other): """Return a Z3 expression that represents the constraint `self != other`. - - If `other` is `None`, then this method simply returns `True`. + + If `other` is `None`, then this method simply returns `True`. >>> a = Int('a') >>> b = Int('b') @@ -824,7 +824,7 @@ class ExprRef(AstRef): def decl(self): """Return the Z3 function declaration associated with a Z3 application. - + >>> f = Function('f', IntSort(), IntSort()) >>> a = Int('a') >>> t = f(a) @@ -836,7 +836,7 @@ class ExprRef(AstRef): if __debug__: _z3_assert(is_app(self), "Z3 application expected") return FuncDeclRef(Z3_get_app_decl(self.ctx_ref(), self.as_ast()), self.ctx) - + def num_args(self): """Return the number of arguments of a Z3 application. @@ -854,7 +854,7 @@ class ExprRef(AstRef): return int(Z3_get_app_num_args(self.ctx_ref(), self.as_ast())) def arg(self, idx): - """Return argument `idx` of the application `self`. + """Return argument `idx` of the application `self`. This method assumes that `self` is a function application with at least `idx+1` arguments. @@ -893,7 +893,7 @@ def _to_expr_ref(a, ctx): if isinstance(a, Pattern): return PatternRef(a, ctx) ctx_ref = ctx.ref() - k = Z3_get_ast_kind(ctx_ref, a) + k = Z3_get_ast_kind(ctx_ref, a) if k == Z3_QUANTIFIER_AST: return QuantifierRef(a, ctx) sk = Z3_get_sort_kind(ctx_ref, Z3_get_sort(ctx_ref, a)) @@ -918,7 +918,7 @@ def _to_expr_ref(a, ctx): return ArrayRef(a, ctx) if sk == Z3_DATATYPE_SORT: return DatatypeRef(a, ctx) - if sk == Z3_FLOATING_POINT_SORT: + if sk == Z3_FLOATING_POINT_SORT: if k == Z3_APP_AST and _is_numeral(ctx, a): return FPNumRef(a, ctx) else: @@ -964,7 +964,7 @@ def _coerce_exprs(a, b, ctx=None): a = s.cast(a) b = s.cast(b) return (a, b) - + def _reduce(f, l, a): r = a for e in l: @@ -984,7 +984,7 @@ def _coerce_expr_list(alist, ctx=None): def is_expr(a): """Return `True` if `a` is a Z3 expression. - + >>> a = Int('a') >>> is_expr(a) True @@ -1005,9 +1005,9 @@ def is_expr(a): return isinstance(a, ExprRef) def is_app(a): - """Return `True` if `a` is a Z3 function application. - - Note that, constants are function applications with 0 arguments. + """Return `True` if `a` is a Z3 function application. + + Note that, constants are function applications with 0 arguments. >>> a = Int('a') >>> is_app(a) @@ -1030,8 +1030,8 @@ def is_app(a): return k == Z3_NUMERAL_AST or k == Z3_APP_AST def is_const(a): - """Return `True` if `a` is Z3 constant/variable expression. - + """Return `True` if `a` is Z3 constant/variable expression. + >>> a = Int('a') >>> is_const(a) True @@ -1048,8 +1048,8 @@ def is_const(a): return is_app(a) and a.num_args() == 0 def is_var(a): - """Return `True` if `a` is variable. - + """Return `True` if `a` is variable. + Z3 uses de-Bruijn indices for representing bound variables in quantifiers. @@ -1073,7 +1073,7 @@ def is_var(a): def get_var_index(a): """Return the de-Bruijn index of the Z3 bounded variable `a`. - + >>> x = Int('x') >>> y = Int('y') >>> is_var(x) @@ -1104,8 +1104,8 @@ def get_var_index(a): return int(Z3_get_index_value(a.ctx.ref(), a.as_ast())) def is_app_of(a, k): - """Return `True` if `a` is an application of the given kind `k`. - + """Return `True` if `a` is an application of the given kind `k`. + >>> x = Int('x') >>> n = x + 1 >>> is_app_of(n, Z3_OP_ADD) @@ -1116,8 +1116,8 @@ def is_app_of(a, k): return is_app(a) and a.decl().kind() == k def If(a, b, c, ctx=None): - """Create a Z3 if-then-else expression. - + """Create a Z3 if-then-else expression. + >>> x = Int('x') >>> y = Int('y') >>> max = If(x > y, x, y) @@ -1138,8 +1138,8 @@ def If(a, b, c, ctx=None): return _to_expr_ref(Z3_mk_ite(ctx.ref(), a.as_ast(), b.as_ast(), c.as_ast()), ctx) def Distinct(*args): - """Create a Z3 distinct expression. - + """Create a Z3 distinct expression. + >>> x = Int('x') >>> y = Int('y') >>> Distinct(x, y) @@ -1180,11 +1180,11 @@ def Const(name, sort): return _to_expr_ref(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), sort.ast), ctx) def Consts(names, sort): - """Create a several constants of the given sort. - - `names` is a string containing the names of all constants to be created. + """Create a several constants of the given sort. + + `names` is a string containing the names of all constants to be created. Blank spaces separate the names of different constants. - + >>> x, y, z = Consts('x y z', IntSort()) >>> x + y + z x + y + z @@ -1195,7 +1195,7 @@ def Consts(names, sort): def Var(idx, s): """Create a Z3 free variable. Free variables are used to create quantified formulas. - + >>> Var(0, IntSort()) Var(0) >>> eq(Var(0, IntSort()), Var(0, BoolSort())) @@ -1209,7 +1209,7 @@ def RealVar(idx, ctx=None): """ Create a real free variable. Free variables are used to create quantified formulas. They are also used to create polynomials. - + >>> RealVar(0) Var(0) """ @@ -1219,7 +1219,7 @@ def RealVarVector(n, ctx=None): """ Create a list of Real free variables. The variables have ids: 0, 1, ..., n-1 - + >>> x0, x1, x2, x3 = RealVarVector(4) >>> x2 Var(2) @@ -1236,7 +1236,7 @@ class BoolSortRef(SortRef): """Boolean sort.""" def cast(self, val): """Try to cast `val` as a Boolean. - + >>> x = BoolSort().cast(True) >>> x True @@ -1288,7 +1288,7 @@ def is_bool(a): def is_true(a): """Return `True` if `a` is the Z3 true expression. - + >>> p = Bool('p') >>> is_true(p) False @@ -1318,7 +1318,7 @@ def is_false(a): def is_and(a): """Return `True` if `a` is a Z3 and expression. - + >>> p, q = Bools('p q') >>> is_and(And(p, q)) True @@ -1340,7 +1340,7 @@ def is_or(a): def is_not(a): """Return `True` if `a` is a Z3 not expression. - + >>> p = Bool('p') >>> is_not(p) False @@ -1351,7 +1351,7 @@ def is_not(a): def is_eq(a): """Return `True` if `a` is a Z3 equality expression. - + >>> x, y = Ints('x y') >>> is_eq(x == y) True @@ -1360,7 +1360,7 @@ def is_eq(a): def is_distinct(a): """Return `True` if `a` is a Z3 distinct expression. - + >>> x, y, z = Ints('x y z') >>> is_distinct(x == y) False @@ -1371,7 +1371,7 @@ def is_distinct(a): def BoolSort(ctx=None): """Return the Boolean Z3 sort. If `ctx=None`, then the global context is used. - + >>> BoolSort() Bool >>> p = Const('p', BoolSort()) @@ -1388,7 +1388,7 @@ def BoolSort(ctx=None): def BoolVal(val, ctx=None): """Return the Boolean value `True` or `False`. If `ctx=None`, then the global context is used. - + >>> BoolVal(True) True >>> is_true(BoolVal(True)) @@ -1406,7 +1406,7 @@ def BoolVal(val, ctx=None): def Bool(name, ctx=None): """Return a Boolean constant named `name`. If `ctx=None`, then the global context is used. - + >>> p = Bool('p') >>> q = Bool('q') >>> And(p, q) @@ -1416,9 +1416,9 @@ def Bool(name, ctx=None): return BoolRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), BoolSort(ctx).ast), ctx) def Bools(names, ctx=None): - """Return a tuple of Boolean constants. - - `names` is a single string containing all names separated by blank spaces. + """Return a tuple of Boolean constants. + + `names` is a single string containing all names separated by blank spaces. If `ctx=None`, then the global context is used. >>> p, q, r = Bools('p q r') @@ -1435,7 +1435,7 @@ def BoolVector(prefix, sz, ctx=None): The constants are named using the given prefix. If `ctx=None`, then the global context is used. - + >>> P = BoolVector('p', 3) >>> P [p__0, p__1, p__2] @@ -1446,8 +1446,8 @@ def BoolVector(prefix, sz, ctx=None): def FreshBool(prefix='b', ctx=None): """Return a fresh Boolean constant in the given context using the given prefix. - - If `ctx=None`, then the global context is used. + + If `ctx=None`, then the global context is used. >>> b1 = FreshBool() >>> b2 = FreshBool() @@ -1458,8 +1458,8 @@ def FreshBool(prefix='b', ctx=None): return BoolRef(Z3_mk_fresh_const(ctx.ref(), prefix, BoolSort(ctx).ast), ctx) def Implies(a, b, ctx=None): - """Create a Z3 implies expression. - + """Create a Z3 implies expression. + >>> p, q = Bools('p q') >>> Implies(p, q) Implies(p, q) @@ -1488,8 +1488,8 @@ def Xor(a, b, ctx=None): return BoolRef(Z3_mk_xor(ctx.ref(), a.as_ast(), b.as_ast()), ctx) def Not(a, ctx=None): - """Create a Z3 not expression or probe. - + """Create a Z3 not expression or probe. + >>> p = Bool('p') >>> Not(Not(p)) Not(Not(p)) @@ -1513,8 +1513,8 @@ def _has_probe(args): return False def And(*args): - """Create a Z3 and-expression or and-probe. - + """Create a Z3 and-expression or and-probe. + >>> p, q, r = Bools('p q r') >>> And(p, q, r) And(p, q, r) @@ -1543,8 +1543,8 @@ def And(*args): return BoolRef(Z3_mk_and(ctx.ref(), sz, _args), ctx) def Or(*args): - """Create a Z3 or-expression or or-probe. - + """Create a Z3 or-expression or or-probe. + >>> p, q, r = Bools('p q r') >>> Or(p, q, r) Or(p, q, r) @@ -1579,8 +1579,8 @@ def Or(*args): ######################################### class PatternRef(ExprRef): - """Patterns are hints for quantifier instantiation. - + """Patterns are hints for quantifier instantiation. + See http://rise4fun.com/Z3Py/tutorial/advanced for more details. """ def as_ast(self): @@ -1593,7 +1593,7 @@ def is_pattern(a): """Return `True` if `a` is a Z3 pattern (hint for quantifier instantiation. See http://rise4fun.com/Z3Py/tutorial/advanced for more details. - + >>> f = Function('f', IntSort(), IntSort()) >>> x = Int('x') >>> q = ForAll(x, f(x) == 0, patterns = [ f(x) ]) @@ -1612,7 +1612,7 @@ def MultiPattern(*args): """Create a Z3 multi-pattern using the given expressions `*args` See http://rise4fun.com/Z3Py/tutorial/advanced for more details. - + >>> f = Function('f', IntSort(), IntSort()) >>> g = Function('g', IntSort(), IntSort()) >>> x = Int('x') @@ -1660,7 +1660,7 @@ class QuantifierRef(BoolRef): def is_forall(self): """Return `True` if `self` is a universal quantifier. - + >>> f = Function('f', IntSort(), IntSort()) >>> x = Int('x') >>> q = ForAll(x, f(x) == 0) @@ -1736,22 +1736,22 @@ class QuantifierRef(BoolRef): f(Var(0)) == 0 """ return _to_expr_ref(Z3_get_quantifier_body(self.ctx_ref(), self.ast), self.ctx) - + def num_vars(self): - """Return the number of variables bounded by this quantifier. - + """Return the number of variables bounded by this quantifier. + >>> f = Function('f', IntSort(), IntSort(), IntSort()) >>> x = Int('x') >>> y = Int('y') >>> q = ForAll([x, y], f(x, y) >= x) - >>> q.num_vars() + >>> q.num_vars() 2 """ return int(Z3_get_quantifier_num_bound(self.ctx_ref(), self.ast)) def var_name(self, idx): - """Return a string representing a name used when displaying the quantifier. - + """Return a string representing a name used when displaying the quantifier. + >>> f = Function('f', IntSort(), IntSort(), IntSort()) >>> x = Int('x') >>> y = Int('y') @@ -1794,7 +1794,7 @@ class QuantifierRef(BoolRef): def is_quantifier(a): """Return `True` if `a` is a Z3 quantifier. - + >>> f = Function('f', IntSort(), IntSort()) >>> x = Int('x') >>> q = ForAll(x, f(x) == 0) @@ -1827,15 +1827,15 @@ def _mk_quantifier(is_forall, vs, body, weight=1, qid="", skid="", patterns=[], _no_pats, num_no_pats = _to_ast_array(no_patterns) qid = to_symbol(qid, ctx) skid = to_symbol(skid, ctx) - return QuantifierRef(Z3_mk_quantifier_const_ex(ctx.ref(), is_forall, weight, qid, skid, - num_vars, _vs, - num_pats, _pats, - num_no_pats, _no_pats, + return QuantifierRef(Z3_mk_quantifier_const_ex(ctx.ref(), is_forall, weight, qid, skid, + num_vars, _vs, + num_pats, _pats, + num_no_pats, _no_pats, body.as_ast()), ctx) def ForAll(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]): """Create a Z3 forall formula. - + The parameters `weight`, `qif`, `skid`, `patterns` and `no_patterns` are optional annotations. See http://rise4fun.com/Z3Py/tutorial/advanced for more details. @@ -1854,7 +1854,7 @@ def ForAll(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]): def Exists(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]): """Create a Z3 exists formula. - + The parameters `weight`, `qif`, `skid`, `patterns` and `no_patterns` are optional annotations. See http://rise4fun.com/Z3Py/tutorial/advanced for more details. @@ -1884,7 +1884,7 @@ class ArithSortRef(SortRef): def is_real(self): """Return `True` if `self` is of the sort Real. - + >>> x = Real('x') >>> x.is_real() True @@ -1898,7 +1898,7 @@ class ArithSortRef(SortRef): def is_int(self): """Return `True` if `self` is of the sort Integer. - + >>> x = Int('x') >>> x.is_int() True @@ -1916,7 +1916,7 @@ class ArithSortRef(SortRef): def cast(self, val): """Try to cast `val` as an Integer or Real. - + >>> IntSort().cast(10) 10 >>> is_int(IntSort().cast(10)) @@ -1952,7 +1952,7 @@ class ArithSortRef(SortRef): def is_arith_sort(s): """Return `True` if s is an arithmetical sort (type). - + >>> is_arith_sort(IntSort()) True >>> is_arith_sort(RealSort()) @@ -1964,13 +1964,13 @@ def is_arith_sort(s): True """ return isinstance(s, ArithSortRef) - + class ArithRef(ExprRef): """Integer and Real expressions.""" def sort(self): """Return the sort (type) of the arithmetical expression `self`. - + >>> Int('x').sort() Int >>> (Real('x') + 1).sort() @@ -1980,7 +1980,7 @@ class ArithRef(ExprRef): def is_int(self): """Return `True` if `self` is an integer expression. - + >>> x = Int('x') >>> x.is_int() True @@ -1994,7 +1994,7 @@ class ArithRef(ExprRef): def is_real(self): """Return `True` if `self` is an real expression. - + >>> x = Real('x') >>> x.is_real() True @@ -2005,7 +2005,7 @@ class ArithRef(ExprRef): def __add__(self, other): """Create the Z3 expression `self + other`. - + >>> x = Int('x') >>> y = Int('y') >>> x + y @@ -2018,7 +2018,7 @@ class ArithRef(ExprRef): def __radd__(self, other): """Create the Z3 expression `other + self`. - + >>> x = Int('x') >>> 10 + x 10 + x @@ -2028,7 +2028,7 @@ class ArithRef(ExprRef): def __mul__(self, other): """Create the Z3 expression `self * other`. - + >>> x = Real('x') >>> y = Real('y') >>> x * y @@ -2041,7 +2041,7 @@ class ArithRef(ExprRef): def __rmul__(self, other): """Create the Z3 expression `other * self`. - + >>> x = Real('x') >>> 10 * x 10*x @@ -2064,7 +2064,7 @@ class ArithRef(ExprRef): def __rsub__(self, other): """Create the Z3 expression `other - self`. - + >>> x = Int('x') >>> 10 - x 10 - x @@ -2074,7 +2074,7 @@ class ArithRef(ExprRef): def __pow__(self, other): """Create the Z3 expression `self**other` (** is the power operator). - + >>> x = Real('x') >>> x**3 x**3 @@ -2088,7 +2088,7 @@ class ArithRef(ExprRef): def __rpow__(self, other): """Create the Z3 expression `other**self` (** is the power operator). - + >>> x = Real('x') >>> 2**x 2**x @@ -2102,7 +2102,7 @@ class ArithRef(ExprRef): def __div__(self, other): """Create the Z3 expression `other/self`. - + >>> x = Int('x') >>> y = Int('y') >>> x/y @@ -2129,7 +2129,7 @@ class ArithRef(ExprRef): def __rdiv__(self, other): """Create the Z3 expression `other/self`. - + >>> x = Int('x') >>> 10/x 10/x @@ -2150,7 +2150,7 @@ class ArithRef(ExprRef): def __mod__(self, other): """Create the Z3 expression `other%self`. - + >>> x = Int('x') >>> y = Int('y') >>> x % y @@ -2165,7 +2165,7 @@ class ArithRef(ExprRef): def __rmod__(self, other): """Create the Z3 expression `other%self`. - + >>> x = Int('x') >>> 10 % x 10%x @@ -2185,10 +2185,10 @@ class ArithRef(ExprRef): x """ return ArithRef(Z3_mk_unary_minus(self.ctx_ref(), self.as_ast()), self.ctx) - + def __pos__(self): """Return `self`. - + >>> x = Int('x') >>> +x x @@ -2197,7 +2197,7 @@ class ArithRef(ExprRef): def __le__(self, other): """Create the Z3 expression `other <= self`. - + >>> x, y = Ints('x y') >>> x <= y x <= y @@ -2210,7 +2210,7 @@ class ArithRef(ExprRef): def __lt__(self, other): """Create the Z3 expression `other < self`. - + >>> x, y = Ints('x y') >>> x < y x < y @@ -2223,7 +2223,7 @@ class ArithRef(ExprRef): def __gt__(self, other): """Create the Z3 expression `other > self`. - + >>> x, y = Ints('x y') >>> x > y x > y @@ -2233,10 +2233,10 @@ class ArithRef(ExprRef): """ a, b = _coerce_exprs(self, other) return BoolRef(Z3_mk_gt(self.ctx_ref(), a.as_ast(), b.as_ast()), self.ctx) - + def __ge__(self, other): """Create the Z3 expression `other >= self`. - + >>> x, y = Ints('x y') >>> x >= y x >= y @@ -2249,7 +2249,7 @@ class ArithRef(ExprRef): def is_arith(a): """Return `True` if `a` is an arithmetical expression. - + >>> x = Int('x') >>> is_arith(x) True @@ -2269,7 +2269,7 @@ def is_arith(a): def is_int(a): """Return `True` if `a` is an integer expression. - + >>> x = Int('x') >>> is_int(x + 1) True @@ -2287,7 +2287,7 @@ def is_int(a): def is_real(a): """Return `True` if `a` is a real expression. - + >>> x = Int('x') >>> is_real(x + 1) False @@ -2311,7 +2311,7 @@ def _is_algebraic(ctx, a): def is_int_value(a): """Return `True` if `a` is an integer value of sort Int. - + >>> is_int_value(IntVal(1)) True >>> is_int_value(1) @@ -2334,7 +2334,7 @@ def is_int_value(a): def is_rational_value(a): """Return `True` if `a` is rational value of sort Real. - + >>> is_rational_value(RealVal(1)) True >>> is_rational_value(RealVal("3/5")) @@ -2355,7 +2355,7 @@ def is_rational_value(a): def is_algebraic_value(a): """Return `True` if `a` is an algerbraic value of sort Real. - + >>> is_algebraic_value(RealVal("3/5")) False >>> n = simplify(Sqrt(2)) @@ -2368,7 +2368,7 @@ def is_algebraic_value(a): def is_add(a): """Return `True` if `a` is an expression of the form b + c. - + >>> x, y = Ints('x y') >>> is_add(x + y) True @@ -2379,7 +2379,7 @@ def is_add(a): def is_mul(a): """Return `True` if `a` is an expression of the form b * c. - + >>> x, y = Ints('x y') >>> is_mul(x * y) True @@ -2390,7 +2390,7 @@ def is_mul(a): def is_sub(a): """Return `True` if `a` is an expression of the form b - c. - + >>> x, y = Ints('x y') >>> is_sub(x - y) True @@ -2401,7 +2401,7 @@ def is_sub(a): def is_div(a): """Return `True` if `a` is an expression of the form b / c. - + >>> x, y = Reals('x y') >>> is_div(x / y) True @@ -2417,7 +2417,7 @@ def is_div(a): def is_idiv(a): """Return `True` if `a` is an expression of the form b div c. - + >>> x, y = Ints('x y') >>> is_idiv(x / y) True @@ -2439,7 +2439,7 @@ def is_mod(a): def is_le(a): """Return `True` if `a` is an expression of the form b <= c. - + >>> x, y = Ints('x y') >>> is_le(x <= y) True @@ -2450,7 +2450,7 @@ def is_le(a): def is_lt(a): """Return `True` if `a` is an expression of the form b < c. - + >>> x, y = Ints('x y') >>> is_lt(x < y) True @@ -2461,7 +2461,7 @@ def is_lt(a): def is_ge(a): """Return `True` if `a` is an expression of the form b >= c. - + >>> x, y = Ints('x y') >>> is_ge(x >= y) True @@ -2472,7 +2472,7 @@ def is_ge(a): def is_gt(a): """Return `True` if `a` is an expression of the form b > c. - + >>> x, y = Ints('x y') >>> is_gt(x > y) True @@ -2483,7 +2483,7 @@ def is_gt(a): def is_is_int(a): """Return `True` if `a` is an expression of the form IsInt(b). - + >>> x = Real('x') >>> is_is_int(IsInt(x)) True @@ -2494,7 +2494,7 @@ def is_is_int(a): def is_to_real(a): """Return `True` if `a` is an expression of the form ToReal(b). - + >>> x = Int('x') >>> n = ToReal(x) >>> n @@ -2508,7 +2508,7 @@ def is_to_real(a): def is_to_int(a): """Return `True` if `a` is an expression of the form ToInt(b). - + >>> x = Real('x') >>> n = ToInt(x) >>> n @@ -2524,8 +2524,8 @@ class IntNumRef(ArithRef): """Integer values.""" def as_long(self): - """Return a Z3 integer numeral as a Python long (bignum) numeral. - + """Return a Z3 integer numeral as a Python long (bignum) numeral. + >>> v = IntVal(1) >>> v + 1 1 + 1 @@ -2548,7 +2548,7 @@ class RatNumRef(ArithRef): """Rational values.""" def numerator(self): - """ Return the numerator of a Z3 rational numeral. + """ Return the numerator of a Z3 rational numeral. >>> is_rational_value(RealVal("3/5")) True @@ -2563,8 +2563,8 @@ class RatNumRef(ArithRef): return IntNumRef(Z3_get_numerator(self.ctx_ref(), self.as_ast()), self.ctx) def denominator(self): - """ Return the denominator of a Z3 rational numeral. - + """ Return the denominator of a Z3 rational numeral. + >>> is_rational_value(Q(3,5)) True >>> n = Q(3,5) @@ -2575,7 +2575,7 @@ class RatNumRef(ArithRef): def numerator_as_long(self): """ Return the numerator as a Python long. - + >>> v = RealVal(10000000000) >>> v 10000000000 @@ -2585,7 +2585,7 @@ class RatNumRef(ArithRef): True """ return self.numerator().as_long() - + def denominator_as_long(self): """ Return the denominator as a Python long. @@ -2599,7 +2599,7 @@ class RatNumRef(ArithRef): def as_decimal(self, prec): """ Return a Z3 rational value as a string in decimal notation using at most `prec` decimal places. - + >>> v = RealVal("1/5") >>> v.as_decimal(3) '0.2' @@ -2620,7 +2620,7 @@ class RatNumRef(ArithRef): def as_fraction(self): """Return a Z3 rational as a Python Fraction object. - + >>> v = RealVal("1/5") >>> v.as_fraction() Fraction(1, 5) @@ -2631,9 +2631,9 @@ class AlgebraicNumRef(ArithRef): """Algebraic irrational values.""" def approx(self, precision=10): - """Return a Z3 rational number that approximates the algebraic number `self`. - The result `r` is such that |r - self| <= 1/10^precision - + """Return a Z3 rational number that approximates the algebraic number `self`. + The result `r` is such that |r - self| <= 1/10^precision + >>> x = simplify(Sqrt(2)) >>> x.approx(20) 6838717160008073720548335/4835703278458516698824704 @@ -2664,7 +2664,7 @@ def _py2expr(a, ctx=None): def IntSort(ctx=None): """Return the integer sort in the given context. If `ctx=None`, then the global context is used. - + >>> IntSort() Int >>> x = Const('x', IntSort()) @@ -2680,7 +2680,7 @@ def IntSort(ctx=None): def RealSort(ctx=None): """Return the real sort in the given context. If `ctx=None`, then the global context is used. - + >>> RealSort() Real >>> x = Const('x', RealSort()) @@ -2711,7 +2711,7 @@ def _to_int_str(val): def IntVal(val, ctx=None): """Return a Z3 integer value. If `ctx=None`, then the global context is used. - + >>> IntVal(1) 1 >>> IntVal("100") @@ -2721,11 +2721,11 @@ def IntVal(val, ctx=None): return IntNumRef(Z3_mk_numeral(ctx.ref(), _to_int_str(val), IntSort(ctx).ast), ctx) def RealVal(val, ctx=None): - """Return a Z3 real value. - + """Return a Z3 real value. + `val` may be a Python int, long, float or string representing a number in decimal or rational notation. If `ctx=None`, then the global context is used. - + >>> RealVal(1) 1 >>> RealVal(1).sort() @@ -2742,7 +2742,7 @@ def RatVal(a, b, ctx=None): """Return a Z3 rational a/b. If `ctx=None`, then the global context is used. - + >>> RatVal(3,5) 3/5 >>> RatVal(3,5).sort() @@ -2755,7 +2755,7 @@ def RatVal(a, b, ctx=None): def Q(a, b, ctx=None): """Return a Z3 rational a/b. - + If `ctx=None`, then the global context is used. >>> Q(3,5) @@ -2778,8 +2778,8 @@ def Int(name, ctx=None): return ArithRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), IntSort(ctx).ast), ctx) def Ints(names, ctx=None): - """Return a tuple of Integer constants. - + """Return a tuple of Integer constants. + >>> x, y, z = Ints('x y z') >>> Sum(x, y, z) x + y + z @@ -2791,7 +2791,7 @@ def Ints(names, ctx=None): def IntVector(prefix, sz, ctx=None): """Return a list of integer constants of size `sz`. - + >>> X = IntVector('x', 3) >>> X [x__0, x__1, x__2] @@ -2826,8 +2826,8 @@ def Real(name, ctx=None): return ArithRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), RealSort(ctx).ast), ctx) def Reals(names, ctx=None): - """Return a tuple of real constants. - + """Return a tuple of real constants. + >>> x, y, z = Reals('x y z') >>> Sum(x, y, z) x + y + z @@ -2841,7 +2841,7 @@ def Reals(names, ctx=None): def RealVector(prefix, sz, ctx=None): """Return a list of real constants of size `sz`. - + >>> X = RealVector('x', 3) >>> X [x__0, x__1, x__2] @@ -2866,8 +2866,8 @@ def FreshReal(prefix='b', ctx=None): return ArithRef(Z3_mk_fresh_const(ctx.ref(), prefix, RealSort(ctx).ast), ctx) def ToReal(a): - """ Return the Z3 expression ToReal(a). - + """ Return the Z3 expression ToReal(a). + >>> x = Int('x') >>> x.sort() Int @@ -2883,8 +2883,8 @@ def ToReal(a): return ArithRef(Z3_mk_int2real(ctx.ref(), a.as_ast()), ctx) def ToInt(a): - """ Return the Z3 expression ToInt(a). - + """ Return the Z3 expression ToInt(a). + >>> x = Real('x') >>> x.sort() Real @@ -2900,8 +2900,8 @@ def ToInt(a): return ArithRef(Z3_mk_real2int(ctx.ref(), a.as_ast()), ctx) def IsInt(a): - """ Return the Z3 predicate IsInt(a). - + """ Return the Z3 predicate IsInt(a). + >>> x = Real('x') >>> IsInt(x + "1/2") IsInt(x + 1/2) @@ -2914,10 +2914,10 @@ def IsInt(a): _z3_assert(a.is_real(), "Z3 real expression expected.") ctx = a.ctx return BoolRef(Z3_mk_is_int(ctx.ref(), a.as_ast()), ctx) - + def Sqrt(a, ctx=None): - """ Return a Z3 expression which represents the square root of a. - + """ Return a Z3 expression which represents the square root of a. + >>> x = Real('x') >>> Sqrt(x) x**(1/2) @@ -2928,8 +2928,8 @@ def Sqrt(a, ctx=None): return a ** "1/2" def Cbrt(a, ctx=None): - """ Return a Z3 expression which represents the cubic root of a. - + """ Return a Z3 expression which represents the cubic root of a. + >>> x = Real('x') >>> Cbrt(x) x**(1/3) @@ -2950,7 +2950,7 @@ class BitVecSortRef(SortRef): def size(self): """Return the size (number of bits) of the bit-vector sort `self`. - + >>> b = BitVecSort(32) >>> b.size() 32 @@ -3003,7 +3003,7 @@ class BitVecRef(ExprRef): def size(self): """Return the number of bits of the bit-vector expression `self`. - + >>> x = BitVec('x', 32) >>> (x + 1).size() 32 @@ -3011,10 +3011,10 @@ class BitVecRef(ExprRef): 64 """ return self.sort().size() - + def __add__(self, other): """Create the Z3 expression `self + other`. - + >>> x = BitVec('x', 32) >>> y = BitVec('y', 32) >>> x + y @@ -3027,7 +3027,7 @@ class BitVecRef(ExprRef): def __radd__(self, other): """Create the Z3 expression `other + self`. - + >>> x = BitVec('x', 32) >>> 10 + x 10 + x @@ -3037,7 +3037,7 @@ class BitVecRef(ExprRef): def __mul__(self, other): """Create the Z3 expression `self * other`. - + >>> x = BitVec('x', 32) >>> y = BitVec('y', 32) >>> x * y @@ -3050,7 +3050,7 @@ class BitVecRef(ExprRef): def __rmul__(self, other): """Create the Z3 expression `other * self`. - + >>> x = BitVec('x', 32) >>> 10 * x 10*x @@ -3060,7 +3060,7 @@ class BitVecRef(ExprRef): def __sub__(self, other): """Create the Z3 expression `self - other`. - + >>> x = BitVec('x', 32) >>> y = BitVec('y', 32) >>> x - y @@ -3073,7 +3073,7 @@ class BitVecRef(ExprRef): def __rsub__(self, other): """Create the Z3 expression `other - self`. - + >>> x = BitVec('x', 32) >>> 10 - x 10 - x @@ -3083,7 +3083,7 @@ class BitVecRef(ExprRef): def __or__(self, other): """Create the Z3 expression bitwise-or `self | other`. - + >>> x = BitVec('x', 32) >>> y = BitVec('y', 32) >>> x | y @@ -3096,7 +3096,7 @@ class BitVecRef(ExprRef): def __ror__(self, other): """Create the Z3 expression bitwise-or `other | self`. - + >>> x = BitVec('x', 32) >>> 10 | x 10 | x @@ -3106,7 +3106,7 @@ class BitVecRef(ExprRef): def __and__(self, other): """Create the Z3 expression bitwise-and `self & other`. - + >>> x = BitVec('x', 32) >>> y = BitVec('y', 32) >>> x & y @@ -3119,7 +3119,7 @@ class BitVecRef(ExprRef): def __rand__(self, other): """Create the Z3 expression bitwise-or `other & self`. - + >>> x = BitVec('x', 32) >>> 10 & x 10 & x @@ -3129,7 +3129,7 @@ class BitVecRef(ExprRef): def __xor__(self, other): """Create the Z3 expression bitwise-xor `self ^ other`. - + >>> x = BitVec('x', 32) >>> y = BitVec('y', 32) >>> x ^ y @@ -3142,7 +3142,7 @@ class BitVecRef(ExprRef): def __rxor__(self, other): """Create the Z3 expression bitwise-xor `other ^ self`. - + >>> x = BitVec('x', 32) >>> 10 ^ x 10 ^ x @@ -3265,7 +3265,7 @@ class BitVecRef(ExprRef): def __le__(self, other): """Create the Z3 expression (signed) `other <= self`. - + Use the function ULE() for unsigned less than or equal to. >>> x, y = BitVecs('x y', 32) @@ -3281,7 +3281,7 @@ class BitVecRef(ExprRef): def __lt__(self, other): """Create the Z3 expression (signed) `other < self`. - + Use the function ULT() for unsigned less than. >>> x, y = BitVecs('x y', 32) @@ -3297,7 +3297,7 @@ class BitVecRef(ExprRef): def __gt__(self, other): """Create the Z3 expression (signed) `other > self`. - + Use the function UGT() for unsigned greater than. >>> x, y = BitVecs('x y', 32) @@ -3310,10 +3310,10 @@ class BitVecRef(ExprRef): """ a, b = _coerce_exprs(self, other) return BoolRef(Z3_mk_bvsgt(self.ctx_ref(), a.as_ast(), b.as_ast()), self.ctx) - + def __ge__(self, other): """Create the Z3 expression (signed) `other >= self`. - + Use the function UGE() for unsigned greater than or equal to. >>> x, y = BitVecs('x y', 32) @@ -3403,8 +3403,8 @@ class BitVecNumRef(BitVecRef): """Bit-vector values.""" def as_long(self): - """Return a Z3 bit-vector numeral as a Python long (bignum) numeral. - + """Return a Z3 bit-vector numeral as a Python long (bignum) numeral. + >>> v = BitVecVal(0xbadc0de, 32) >>> v 195936478 @@ -3415,7 +3415,7 @@ class BitVecNumRef(BitVecRef): def as_signed_long(self): """Return a Z3 bit-vector numeral as a Python long (bignum) numeral. The most significant bit is assumed to be the sign. - + >>> BitVecVal(4, 3).as_signed_long() -4 >>> BitVecVal(7, 3).as_signed_long() @@ -3440,7 +3440,7 @@ class BitVecNumRef(BitVecRef): def is_bv(a): """Return `True` if `a` is a Z3 bit-vector expression. - + >>> b = BitVec('b', 32) >>> is_bv(b) True @@ -3466,8 +3466,8 @@ def is_bv_value(a): return is_bv(a) and _is_numeral(a.ctx, a.as_ast()) def BV2Int(a): - """Return the Z3 expression BV2Int(a). - + """Return the Z3 expression BV2Int(a). + >>> b = BitVec('b', 3) >>> BV2Int(b).sort() Int @@ -3499,7 +3499,7 @@ def BitVecSort(sz, ctx=None): def BitVecVal(val, bv, ctx=None): """Return a bit-vector value with the given number of bits. If `ctx=None`, then the global context is used. - + >>> v = BitVecVal(10, 32) >>> v 10 @@ -3537,8 +3537,8 @@ def BitVec(name, bv, ctx=None): return BitVecRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), bv.ast), ctx) def BitVecs(names, bv, ctx=None): - """Return a tuple of bit-vector constants of size bv. - + """Return a tuple of bit-vector constants of size bv. + >>> x, y, z = BitVecs('x y z', 16) >>> x.size() 16 @@ -3557,8 +3557,8 @@ def BitVecs(names, bv, ctx=None): return [BitVec(name, bv, ctx) for name in names] def Concat(*args): - """Create a Z3 bit-vector concatenation expression. - + """Create a Z3 bit-vector concatenation expression. + >>> v = BitVecVal(1, 4) >>> Concat(v, v+1, v) Concat(Concat(1, 1 + 1), 1) @@ -3573,7 +3573,7 @@ def Concat(*args): _z3_assert(sz >= 2, "At least two arguments expected.") ctx = args[0].ctx - + if is_seq(args[0]): if __debug__: _z3_assert(all([is_seq(a) for a in args]), "All arguments must be sequence expressions.") @@ -3581,7 +3581,7 @@ def Concat(*args): for i in range(sz): v[i] = args[i].as_ast() return SeqRef(Z3_mk_seq_concat(ctx.ref(), sz, v), ctx) - + if is_re(args[0]): if __debug__: _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.") @@ -3589,7 +3589,7 @@ def Concat(*args): for i in range(sz): v[i] = args[i].as_ast() return ReRef(Z3_mk_re_concat(ctx.ref(), sz, v), ctx) - + if __debug__: _z3_assert(all([is_bv(a) for a in args]), "All arguments must be Z3 bit-vector expressions.") r = args[0] @@ -3614,7 +3614,7 @@ def Extract(high, low, a): s = high offset = _py2expr(low, high.ctx) length = _py2expr(a, high.ctx) - + if __debug__: _z3_assert(is_int(offset) and is_int(length), "Second and third arguments must be integers") return SeqRef(Z3_mk_seq_extract(s.ctx_ref(), s.as_ast(), offset.as_ast(), length.as_ast()), s.ctx) @@ -3630,9 +3630,9 @@ def _check_bv_args(a, b): def ULE(a, b): """Create the Z3 expression (unsigned) `other <= self`. - + Use the operator <= for signed less than or equal to. - + >>> x, y = BitVecs('x y', 32) >>> ULE(x, y) ULE(x, y) @@ -3647,9 +3647,9 @@ def ULE(a, b): def ULT(a, b): """Create the Z3 expression (unsigned) `other < self`. - + Use the operator < for signed less than. - + >>> x, y = BitVecs('x y', 32) >>> ULT(x, y) ULT(x, y) @@ -3664,9 +3664,9 @@ def ULT(a, b): def UGE(a, b): """Create the Z3 expression (unsigned) `other >= self`. - + Use the operator >= for signed greater than or equal to. - + >>> x, y = BitVecs('x y', 32) >>> UGE(x, y) UGE(x, y) @@ -3681,9 +3681,9 @@ def UGE(a, b): def UGT(a, b): """Create the Z3 expression (unsigned) `other > self`. - + Use the operator > for signed greater than. - + >>> x, y = BitVecs('x y', 32) >>> UGT(x, y) UGT(x, y) @@ -3698,9 +3698,9 @@ def UGT(a, b): def UDiv(a, b): """Create the Z3 expression (unsigned) division `self / other`. - + Use the operator / for signed division. - + >>> x = BitVec('x', 32) >>> y = BitVec('y', 32) >>> UDiv(x, y) @@ -3718,9 +3718,9 @@ def UDiv(a, b): def URem(a, b): """Create the Z3 expression (unsigned) remainder `self % other`. - + Use the operator % for signed modulus, and SRem() for signed remainder. - + >>> x = BitVec('x', 32) >>> y = BitVec('y', 32) >>> URem(x, y) @@ -3738,9 +3738,9 @@ def URem(a, b): def SRem(a, b): """Create the Z3 expression signed remainder. - + Use the operator % for signed modulus, and URem() for unsigned remainder. - + >>> x = BitVec('x', 32) >>> y = BitVec('y', 32) >>> SRem(x, y) @@ -3919,16 +3919,16 @@ class ArraySortRef(SortRef): def domain(self): """Return the domain of the array sort `self`. - + >>> A = ArraySort(IntSort(), BoolSort()) >>> A.domain() Int """ return _to_sort_ref(Z3_get_array_sort_domain(self.ctx_ref(), self.ast), self.ctx) - + def range(self): """Return the range of the array sort `self`. - + >>> A = ArraySort(IntSort(), BoolSort()) >>> A.range() Bool @@ -3946,7 +3946,7 @@ class ArrayRef(ExprRef): Array(Int, Bool) """ return ArraySortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx) - + def domain(self): """Shorthand for `self.sort().domain()`. @@ -3955,7 +3955,7 @@ class ArrayRef(ExprRef): Int """ return self.sort().domain() - + def range(self): """Shorthand for `self.sort().range()`. @@ -3984,7 +3984,7 @@ class ArrayRef(ExprRef): def is_array(a): """Return `True` if `a` is a Z3 array expression. - + >>> a = Array('a', IntSort(), IntSort()) >>> is_array(a) True @@ -4020,7 +4020,7 @@ def is_K(a): return is_app_of(a, Z3_OP_CONST_ARRAY) def is_map(a): - """Return `True` if `a` is a Z3 map array expression. + """Return `True` if `a` is a Z3 map array expression. >>> f = Function('f', IntSort(), IntSort()) >>> b = Array('b', IntSort(), IntSort()) @@ -4061,7 +4061,7 @@ def get_map_func(a): def ArraySort(d, r): """Return the Z3 array sort with the given domain and range sorts. - + >>> A = ArraySort(IntSort(), BoolSort()) >>> A Array(Int, Bool) @@ -4114,15 +4114,15 @@ def Update(a, i, v): ctx = a.ctx return _to_expr_ref(Z3_mk_store(ctx.ref(), a.as_ast(), i.as_ast(), v.as_ast()), ctx) -def Default(a): - """ Return a default value for array expression. - >>> b = K(IntSort(), 1) - >>> prove(Default(b) == 1) +def Default(a): + """ Return a default value for array expression. + >>> b = K(IntSort(), 1) + >>> prove(Default(b) == 1) proved - """ - if __debug__: - _z3_assert(is_array(a), "First argument must be a Z3 array expression") - return a.default() + """ + if __debug__: + _z3_assert(is_array(a), "First argument must be a Z3 array expression") + return a.default() def Store(a, i, v): @@ -4156,7 +4156,7 @@ def Select(a, i): return a[i] def Map(f, *args): - """Return a Z3 map array expression. + """Return a Z3 map array expression. >>> f = Function('f', IntSort(), IntSort(), IntSort()) >>> a1 = Array('a1', IntSort(), IntSort()) @@ -4178,8 +4178,8 @@ def Map(f, *args): return ArrayRef(Z3_mk_map(ctx.ref(), f.ast, sz, _args), ctx) def K(dom, v): - """Return a Z3 constant array expression. - + """Return a Z3 constant array expression. + >>> a = K(IntSort(), 10) >>> a K(Int, 10) @@ -4207,7 +4207,7 @@ def Ext(a, b): def is_select(a): """Return `True` if `a` is a Z3 array select application. - + >>> a = Array('a', IntSort(), IntSort()) >>> is_select(a) False @@ -4219,7 +4219,7 @@ def is_select(a): def is_store(a): """Return `True` if `a` is a Z3 array store application. - + >>> a = Array('a', IntSort(), IntSort()) >>> is_store(a) False @@ -4239,7 +4239,7 @@ def _valid_accessor(acc): return isinstance(acc, tuple) and len(acc) == 2 and isinstance(acc[0], str) and (isinstance(acc[1], Datatype) or is_sort(acc[1])) class Datatype: - """Helper class for declaring Z3 datatypes. + """Helper class for declaring Z3 datatypes. >>> List = Datatype('List') >>> List.declare('cons', ('car', IntSort()), ('cdr', List)) @@ -4277,15 +4277,15 @@ class Datatype: self.constructors.append((name, rec_name, args)) def declare(self, name, *args): - """Declare constructor named `name` with the given accessors `args`. - Each accessor is a pair `(name, sort)`, where `name` is a string and `sort` a Z3 sort or a reference to the datatypes being declared. + """Declare constructor named `name` with the given accessors `args`. + Each accessor is a pair `(name, sort)`, where `name` is a string and `sort` a Z3 sort or a reference to the datatypes being declared. - In the followin example `List.declare('cons', ('car', IntSort()), ('cdr', List))` - declares the constructor named `cons` that builds a new List using an integer and a List. - It also declares the accessors `car` and `cdr`. The accessor `car` extracts the integer of a `cons` cell, - and `cdr` the list of a `cons` cell. After all constructors were declared, we use the method create() to create + In the followin example `List.declare('cons', ('car', IntSort()), ('cdr', List))` + declares the constructor named `cons` that builds a new List using an integer and a List. + It also declares the accessors `car` and `cdr`. The accessor `car` extracts the integer of a `cons` cell, + and `cdr` the list of a `cons` cell. After all constructors were declared, we use the method create() to create the actual datatype in Z3. - + >>> List = Datatype('List') >>> List.declare('cons', ('car', IntSort()), ('cdr', List)) >>> List.declare('nil') @@ -4301,7 +4301,7 @@ class Datatype: def create(self): """Create a Z3 datatype based on the constructors declared using the mehtod `declare()`. - + The function `CreateDatatypes()` must be used to define mutually recursive datatypes. >>> List = Datatype('List') @@ -4333,7 +4333,7 @@ class ScopedConstructorList: def CreateDatatypes(*ds): """Create mutually recursive Z3 datatypes using 1 or more Datatype helper objects. - + In the following example we define a Tree-List using two mutually recursive datatypes. >>> TreeList = Datatype('TreeList') @@ -4426,8 +4426,8 @@ def CreateDatatypes(*ds): class DatatypeSortRef(SortRef): """Datatype sorts.""" def num_constructors(self): - """Return the number of constructors in the given Z3 datatype. - + """Return the number of constructors in the given Z3 datatype. + >>> List = Datatype('List') >>> List.declare('cons', ('car', IntSort()), ('cdr', List)) >>> List.declare('nil') @@ -4456,12 +4456,12 @@ class DatatypeSortRef(SortRef): if __debug__: _z3_assert(idx < self.num_constructors(), "Invalid constructor index") return FuncDeclRef(Z3_get_datatype_sort_constructor(self.ctx_ref(), self.ast, idx), self.ctx) - + def recognizer(self, idx): - """In Z3, each constructor has an associated recognizer predicate. + """In Z3, each constructor has an associated recognizer predicate. If the constructor is named `name`, then the recognizer `is_name`. - + >>> List = Datatype('List') >>> List.declare('cons', ('car', IntSort()), ('cdr', List)) >>> List.declare('nil') @@ -4487,7 +4487,7 @@ class DatatypeSortRef(SortRef): def accessor(self, i, j): """In Z3, each constructor has 0 or more accessor. The number of accessors is equal to the arity of the constructor. - + >>> List = Datatype('List') >>> List.declare('cons', ('car', IntSort()), ('cdr', List)) >>> List.declare('nil') @@ -4537,7 +4537,7 @@ def EnumSort(name, values, ctx=None): for i in range(num): _val_names[i] = to_symbol(values[i]) _values = (FuncDecl * num)() - _testers = (FuncDecl * num)() + _testers = (FuncDecl * num)() name = to_symbol(name) S = DatatypeSortRef(Z3_mk_enumeration_sort(ctx.ref(), name, num, _val_names, _values, _testers), ctx) V = [] @@ -4554,7 +4554,7 @@ def EnumSort(name, values, ctx=None): class ParamsRef: """Set of parameters used to configure Solvers, Tactics and Simplifiers in Z3. - + Consider using the function `args2params` to create instances of this object. """ def __init__(self, ctx=None): @@ -4637,12 +4637,12 @@ class ParamDescrsRef: """Return the i-th parameter name in the parameter description `self`. """ return _symbol2py(self.ctx, Z3_param_descrs_get_name(self.ctx.ref(), self.descr, i)) - + def get_kind(self, n): """Return the kind of the parameter named `n`. """ return Z3_param_descrs_get_kind(self.ctx.ref(), self.descr, to_symbol(n, self.ctx)) - + def __getitem__(self, arg): if _is_int(arg): return self.get_name(arg) @@ -4660,7 +4660,7 @@ class ParamDescrsRef: class Goal(Z3PPObject): """Goal is a collection of constraints we want to find a solution or show to be unsatisfiable (infeasible). - + Goals are processed using Tactics. A Tactic transforms a goal into a set of subgoals. A goal has a solution if one of its subgoals has a solution. A goal is unsatisfiable if all subgoals are unsatisfiable. @@ -4698,13 +4698,13 @@ class Goal(Z3PPObject): def inconsistent(self): """Return `True` if `self` contains the `False` constraints. - + >>> x, y = Ints('x y') >>> g = Goal() >>> g.inconsistent() False >>> g.add(x == 0, x == 1) - >>> g + >>> g [x == 0, x == 1] >>> g.inconsistent() False @@ -4716,7 +4716,7 @@ class Goal(Z3PPObject): def prec(self): """Return the precision (under-approximation, over-approximation, or precise) of the goal `self`. - + >>> g = Goal() >>> g.prec() == Z3_GOAL_PRECISE True @@ -4746,7 +4746,7 @@ class Goal(Z3PPObject): def size(self): """Return the number of constraints in the goal `self`. - + >>> g = Goal() >>> g.size() 0 @@ -4772,7 +4772,7 @@ class Goal(Z3PPObject): def get(self, i): """Return a constraint in the goal `self`. - + >>> g = Goal() >>> x, y = Ints('x y') >>> g.add(x == 0, y > x) @@ -4785,7 +4785,7 @@ class Goal(Z3PPObject): def __getitem__(self, arg): """Return a constraint in the goal `self`. - + >>> g = Goal() >>> x, y = Ints('x y') >>> g.add(x == 0, y > x) @@ -4800,7 +4800,7 @@ class Goal(Z3PPObject): def assert_exprs(self, *args): """Assert constraints into the goal. - + >>> x = Int('x') >>> g = Goal() >>> g.assert_exprs(x > 0, x < 2) @@ -4815,7 +4815,7 @@ class Goal(Z3PPObject): def append(self, *args): """Add constraints. - + >>> x = Int('x') >>> g = Goal() >>> g.append(x > 0, x < 2) @@ -4823,10 +4823,10 @@ class Goal(Z3PPObject): [x > 0, x < 2] """ self.assert_exprs(*args) - + def insert(self, *args): """Add constraints. - + >>> x = Int('x') >>> g = Goal() >>> g.insert(x > 0, x < 2) @@ -4837,7 +4837,7 @@ class Goal(Z3PPObject): def add(self, *args): """Add constraints. - + >>> x = Int('x') >>> g = Goal() >>> g.add(x > 0, x < 2) @@ -4855,7 +4855,7 @@ class Goal(Z3PPObject): def translate(self, target): """Copy goal `self` to context `target`. - + >>> x = Int('x') >>> g = Goal() >>> g.add(x > 10) @@ -4878,9 +4878,9 @@ class Goal(Z3PPObject): def simplify(self, *arguments, **keywords): """Return a new simplified goal. - + This method is essentially invoking the simplify tactic. - + >>> g = Goal() >>> x = Int('x') >>> g.add(x + 1 >= 2) @@ -4898,7 +4898,7 @@ class Goal(Z3PPObject): def as_expr(self): """Return goal `self` as a single Z3 expression. - + >>> x = Int('x') >>> g = Goal() >>> g.as_expr() @@ -4940,7 +4940,7 @@ class AstVector(Z3PPObject): def __del__(self): if self.vector != None: Z3_ast_vector_dec_ref(self.ctx.ref(), self.vector) - + def __len__(self): """Return the size of the vector `self`. @@ -4971,7 +4971,7 @@ class AstVector(Z3PPObject): def __setitem__(self, i, v): """Update AST at position `i`. - + >>> A = AstVector() >>> A.push(Int('x') + 1) >>> A.push(Int('y')) @@ -4984,7 +4984,7 @@ class AstVector(Z3PPObject): if i >= self.__len__(): raise IndexError Z3_ast_vector_set(self.ctx.ref(), self.vector, i, v.as_ast()) - + def push(self, v): """Add `v` in the end of the vector. @@ -5032,7 +5032,7 @@ class AstVector(Z3PPObject): if elem.eq(item): return True return False - + def translate(self, other_ctx): """Copy vector `self` to context `other_ctx`. @@ -5077,7 +5077,7 @@ class AstMap: Z3_ast_map_dec_ref(self.ctx.ref(), self.map) def __len__(self): - """Return the size of the map. + """Return the size of the map. >>> M = AstMap() >>> len(M) @@ -5101,7 +5101,7 @@ class AstMap: False """ return Z3_ast_map_contains(self.ctx.ref(), self.map, key.as_ast()) - + def __getitem__(self, key): """Retrieve the value associated with key `key`. @@ -5192,7 +5192,7 @@ class FuncEntry: def num_args(self): """Return the number of arguments in the given entry. - + >>> f = Function('f', IntSort(), IntSort(), IntSort()) >>> s = Solver() >>> s.add(f(0, 1) == 10, f(1, 2) == 20, f(1, 0) == 10) @@ -5210,7 +5210,7 @@ class FuncEntry: def arg_value(self, idx): """Return the value of argument `idx`. - + >>> f = Function('f', IntSort(), IntSort(), IntSort()) >>> s = Solver() >>> s.add(f(0, 1) == 10, f(1, 2) == 20, f(1, 0) == 10) @@ -5241,7 +5241,7 @@ class FuncEntry: def value(self): """Return the value of the function at point `self`. - + >>> f = Function('f', IntSort(), IntSort(), IntSort()) >>> s = Solver() >>> s.add(f(0, 1) == 10, f(1, 2) == 20, f(1, 0) == 10) @@ -5260,7 +5260,7 @@ class FuncEntry: 10 """ return _to_expr_ref(Z3_func_entry_get_value(self.ctx.ref(), self.entry), self.ctx) - + def as_list(self): """Return entry `self` as a Python list. >>> f = Function('f', IntSort(), IntSort(), IntSort()) @@ -5282,7 +5282,7 @@ class FuncEntry: def __repr__(self): return repr(self.as_list()) - + class FuncInterp(Z3PPObject): """Stores the interpretation of a function in a Z3 model.""" @@ -5348,7 +5348,7 @@ class FuncInterp(Z3PPObject): 1 """ return int(Z3_func_interp_get_arity(self.ctx.ref(), self.f)) - + def entry(self, idx): """Return an entry at position `idx < self.num_entries()` in the function interpretation `self`. @@ -5372,7 +5372,7 @@ class FuncInterp(Z3PPObject): if idx >= self.num_entries(): raise IndexError return FuncEntry(Z3_func_interp_get_entry(self.ctx.ref(), self.f, idx), self.ctx) - + def as_list(self): """Return the function interpretation as a Python list. >>> f = Function('f', IntSort(), IntSort()) @@ -5443,7 +5443,7 @@ class ModelRef(Z3PPObject): def evaluate(self, t, model_completion=False): """Alias for `eval`. - + >>> x = Int('x') >>> s = Solver() >>> s.add(x > 0, x < 2) @@ -5515,7 +5515,7 @@ class ModelRef(Z3PPObject): def num_sorts(self): """Return the number of unintepreted sorts that contain an interpretation in the model `self`. - + >>> A = DeclareSort('A') >>> a, b = Consts('a b', A) >>> s = Solver() @@ -5530,7 +5530,7 @@ class ModelRef(Z3PPObject): def get_sort(self, idx): """Return the unintepreted sort at position `idx` < self.num_sorts(). - + >>> A = DeclareSort('A') >>> B = DeclareSort('B') >>> a1, a2 = Consts('a1 a2', A) @@ -5550,7 +5550,7 @@ class ModelRef(Z3PPObject): if idx >= self.num_sorts(): raise IndexError return _to_sort_ref(Z3_model_get_sort(self.ctx.ref(), self.model, idx), self.ctx) - + def sorts(self): """Return all uninterpreted sorts that have an interpretation in the model `self`. @@ -5590,7 +5590,7 @@ class ModelRef(Z3PPObject): def __getitem__(self, idx): """If `idx` is an integer, then the declaration at position `idx` in the model `self` is returned. If `idx` is a declaration, then the actual interpreation is returned. - + The elements can be retrieved using position or the actual declaration. >>> f = Function('f', IntSort(), IntSort()) @@ -5696,9 +5696,9 @@ class Statistics: return Z3_stats_to_string(self.ctx.ref(), self.stats) def __len__(self): - """Return the number of statistical counters. + """Return the number of statistical counters. - >>> x = Int('x') + >>> x = Int('x') >>> s = Then('simplify', 'nlsat').solver() >>> s.add(x > 0) >>> s.check() @@ -5712,7 +5712,7 @@ class Statistics: def __getitem__(self, idx): """Return the value of statistical counter at position `idx`. The result is a pair (key, value). - >>> x = Int('x') + >>> x = Int('x') >>> s = Then('simplify', 'nlsat').solver() >>> s.add(x > 0) >>> s.check() @@ -5732,11 +5732,11 @@ class Statistics: else: val = Z3_stats_get_double_value(self.ctx.ref(), self.stats, idx) return (Z3_stats_get_key(self.ctx.ref(), self.stats, idx), val) - + def keys(self): """Return the list of statistical counters. - - >>> x = Int('x') + + >>> x = Int('x') >>> s = Then('simplify', 'nlsat').solver() >>> s.add(x > 0) >>> s.check() @@ -5748,7 +5748,7 @@ class Statistics: def get_key_value(self, key): """Return the value of a particular statistical counter. - >>> x = Int('x') + >>> x = Int('x') >>> s = Then('simplify', 'nlsat').solver() >>> s.add(x > 0) >>> s.check() @@ -5764,19 +5764,19 @@ class Statistics: else: return Z3_stats_get_double_value(self.ctx.ref(), self.stats, idx) raise Z3Exception("unknown key") - + def __getattr__(self, name): """Access the value of statistical using attributes. - + Remark: to access a counter containing blank spaces (e.g., 'nlsat propagations'), we should use '_' (e.g., 'nlsat_propagations'). - >>> x = Int('x') + >>> x = Int('x') >>> s = Then('simplify', 'nlsat').solver() >>> s.add(x > 0) >>> s.check() sat - >>> st = s.statistics() + >>> st = s.statistics() >>> st.nlsat_propagations 2 >>> st.nlsat_stages @@ -5787,7 +5787,7 @@ class Statistics: return self.get_key_value(key) except Z3Exception: raise AttributeError - + ######################################### # # Solver @@ -5795,7 +5795,7 @@ class Statistics: ######################################### class CheckSatResult: """Represents the result of a satisfiability check: sat, unsat, unknown. - + >>> s = Solver() >>> s.check() sat @@ -5831,7 +5831,7 @@ class CheckSatResult: sat = CheckSatResult(Z3_L_TRUE) unsat = CheckSatResult(Z3_L_FALSE) -unknown = CheckSatResult(Z3_L_UNDEF) +unknown = CheckSatResult(Z3_L_UNDEF) class Solver(Z3PPObject): """Solver API provides methods for implementing the main SMT 2.0 commands: push, pop, check, get-model, etc.""" @@ -5852,7 +5852,7 @@ class Solver(Z3PPObject): def set(self, *args, **keys): """Set a configuration option. The method `help()` return a string containing all available options. - + >>> s = Solver() >>> # The option MBQI can be set using three different approaches. >>> s.set(mbqi=True) @@ -5886,7 +5886,7 @@ class Solver(Z3PPObject): def pop(self, num=1): """Backtrack \c num backtracking points. - + >>> x = Int('x') >>> s = Solver() >>> s.add(x > 0) @@ -5908,7 +5908,7 @@ class Solver(Z3PPObject): def reset(self): """Remove all asserted constraints and backtracking points created using `push()`. - + >>> x = Int('x') >>> s = Solver() >>> s.add(x > 0) @@ -5919,10 +5919,10 @@ class Solver(Z3PPObject): [] """ Z3_solver_reset(self.ctx.ref(), self.solver) - + def assert_exprs(self, *args): """Assert constraints into the solver. - + >>> x = Int('x') >>> s = Solver() >>> s.assert_exprs(x > 0, x < 2) @@ -5941,7 +5941,7 @@ class Solver(Z3PPObject): def add(self, *args): """Assert constraints into the solver. - + >>> x = Int('x') >>> s = Solver() >>> s.add(x > 0, x < 2) @@ -5952,7 +5952,7 @@ class Solver(Z3PPObject): def append(self, *args): """Assert constraints into the solver. - + >>> x = Int('x') >>> s = Solver() >>> s.append(x > 0, x < 2) @@ -5963,7 +5963,7 @@ class Solver(Z3PPObject): def insert(self, *args): """Assert constraints into the solver. - + >>> x = Int('x') >>> s = Solver() >>> s.insert(x > 0, x < 2) @@ -5974,9 +5974,9 @@ class Solver(Z3PPObject): def assert_and_track(self, a, p): """Assert constraint `a` and track it in the unsat core using the Boolean constant `p`. - + If `p` is a string, it will be automatically converted into a Boolean constant. - + >>> x = Int('x') >>> p3 = Bool('p3') >>> s = Solver() @@ -6004,7 +6004,7 @@ class Solver(Z3PPObject): def check(self, *assumptions): """Check whether the assertions in the given solver plus the optional assumptions are consistent or not. - + >>> x = Int('x') >>> s = Solver() >>> s.check() @@ -6031,9 +6031,9 @@ class Solver(Z3PPObject): return CheckSatResult(r) def model(self): - """Return a model for the last `check()`. - - This function raises an exception if + """Return a model for the last `check()`. + + This function raises an exception if a model is not available (e.g., last `check()` returned unsat). >>> s = Solver() @@ -6051,11 +6051,11 @@ class Solver(Z3PPObject): def unsat_core(self): """Return a subset (as an AST vector) of the assumptions provided to the last check(). - + These are the assumptions Z3 used in the unsatisfiability proof. - Assumptions are available in Z3. They are used to extract unsatisfiable cores. - They may be also used to "retract" assumptions. Note that, assumptions are not really - "soft constraints", but they can be used to implement them. + Assumptions are available in Z3. They are used to extract unsatisfiable cores. + They may be also used to "retract" assumptions. Note that, assumptions are not really + "soft constraints", but they can be used to implement them. >>> p1, p2, p3 = Bools('p1 p2 p3') >>> x, y = Ints('x y') @@ -6087,7 +6087,7 @@ class Solver(Z3PPObject): def assertions(self): """Return an AST vector containing all added constraints. - + >>> s = Solver() >>> s.assertions() [] @@ -6101,7 +6101,7 @@ class Solver(Z3PPObject): def statistics(self): """Return statistics for the last `check()`. - + >>> s = SimpleSolver() >>> x = Int('x') >>> s.add(x > 0) @@ -6119,7 +6119,7 @@ class Solver(Z3PPObject): def reason_unknown(self): """Return a string describing why the last `check()` returned `unknown`. - + >>> x = Int('x') >>> s = SimpleSolver() >>> s.add(2**x == 4) @@ -6129,7 +6129,7 @@ class Solver(Z3PPObject): '(incomplete (theory arithmetic))' """ return Z3_solver_get_reason_unknown(self.ctx.ref(), self.solver) - + def help(self): """Display a string describing all available options.""" print(Z3_solver_get_help(self.ctx.ref(), self.solver)) @@ -6143,8 +6143,8 @@ class Solver(Z3PPObject): return obj_to_string(self) def translate(self, target): - """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`. - + """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`. + >>> c1 = Context() >>> c2 = Context() >>> s1 = Solver(ctx=c1) @@ -6154,10 +6154,10 @@ class Solver(Z3PPObject): _z3_assert(isinstance(target, Context), "argument must be a Z3 context") solver = Z3_solver_translate(self.ctx.ref(), self.solver, target.ref()) return Solver(solver, target) - + def sexpr(self): """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format. - + >>> x = Int('x') >>> s = Solver() >>> s.add(x > 0) @@ -6183,7 +6183,7 @@ class Solver(Z3PPObject): return Z3_benchmark_to_smtlib_string(self.ctx.ref(), "benchmark generated from python API", "", "unknown", "", sz1, v, e) def SolverFor(logic, ctx=None): - """Create a solver customized for the given logic. + """Create a solver customized for the given logic. The parameter `logic` is a string. It should be contains the name of a SMT-LIB logic. @@ -6204,7 +6204,7 @@ def SolverFor(logic, ctx=None): def SimpleSolver(ctx=None): """Return a simple general purpose solver with limited amount of preprocessing. - + >>> s = SimpleSolver() >>> x = Int('x') >>> s.add(x > 0) @@ -6222,7 +6222,7 @@ def SimpleSolver(ctx=None): class Fixedpoint(Z3PPObject): """Fixedpoint API provides methods for solving with recursive predicates""" - + def __init__(self, fixedpoint=None, ctx=None): assert fixedpoint == None or ctx != None self.ctx = _get_ctx(ctx) @@ -6239,7 +6239,7 @@ class Fixedpoint(Z3PPObject): Z3_fixedpoint_dec_ref(self.ctx.ref(), self.fixedpoint) def set(self, *args, **keys): - """Set a configuration option. The method `help()` return a string containing all available options. + """Set a configuration option. The method `help()` return a string containing all available options. """ p = args2params(args, keys, self.ctx) Z3_fixedpoint_set_params(self.ctx.ref(), self.fixedpoint, p.params) @@ -6247,11 +6247,11 @@ class Fixedpoint(Z3PPObject): def help(self): """Display a string describing all available options.""" print(Z3_fixedpoint_get_help(self.ctx.ref(), self.fixedpoint)) - + def param_descrs(self): """Return the parameter description set.""" return ParamDescrsRef(Z3_fixedpoint_get_param_descrs(self.ctx.ref(), self.fixedpoint), self.ctx) - + def assert_exprs(self, *args): """Assert constraints as background axioms for the fixedpoint solver.""" args = _get_args(args) @@ -6295,16 +6295,16 @@ class Fixedpoint(Z3PPObject): name = to_symbol(name, self.ctx) if body == None: head = self.abstract(head) - Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, head.as_ast(), name) + Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, head.as_ast(), name) else: body = _get_args(body) f = self.abstract(Implies(And(body, self.ctx),head)) Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name) - + def rule(self, head, body = None, name = None): """Assert rules defining recursive predicates to the fixedpoint solver. Alias for add_rule.""" self.add_rule(head, body, name) - + def fact(self, head, name = None): """Assert facts defining recursive predicates to the fixedpoint solver. Alias for add_rule.""" self.add_rule(head, None, name) @@ -6315,7 +6315,7 @@ class Fixedpoint(Z3PPObject): """ query = _get_args(query) sz = len(query) - if sz >= 1 and isinstance(query[0], FuncDeclRef): + if sz >= 1 and isinstance(query[0], FuncDeclRef): _decls = (FuncDecl * sz)() i = 0 for q in query: @@ -6348,7 +6348,7 @@ class Fixedpoint(Z3PPObject): f = self.abstract(Implies(And(body, self.ctx),head)) Z3_fixedpoint_update_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name) - def get_answer(self): + def get_answer(self): """Retrieve answer from last query call.""" r = Z3_fixedpoint_get_answer(self.ctx.ref(), self.fixedpoint) return _to_expr_ref(r, self.ctx) @@ -6361,7 +6361,7 @@ class Fixedpoint(Z3PPObject): """Retrieve properties known about predicate for the level'th unfolding. -1 is treated as the limit (infinity)""" r = Z3_fixedpoint_get_cover_delta(self.ctx.ref(), self.fixedpoint, level, predicate.ast) return _to_expr_ref(r, self.ctx) - + def add_cover(self, level, predicate, property): """Add property to predicate for the level'th unfolding. -1 is treated as infinity (infinity)""" Z3_fixedpoint_add_cover(self.ctx.ref(), self.fixedpoint, level, predicate.ast, property.ast) @@ -6385,7 +6385,7 @@ class Fixedpoint(Z3PPObject): def parse_string(self, s): """Parse rules and queries from a string""" return AstVector(Z3_fixedpoint_from_string(self.ctx.ref(), self.fixedpoint, s), self.ctx) - + def parse_file(self, f): """Parse rules and queries from a file""" return AstVector(Z3_fixedpoint_from_file(self.ctx.ref(), self.fixedpoint, f), self.ctx) @@ -6403,7 +6403,7 @@ class Fixedpoint(Z3PPObject): return self.sexpr() def sexpr(self): - """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format. + """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format. """ return Z3_fixedpoint_to_string(self.ctx.ref(), self.fixedpoint, 0, (Ast * 0)()) @@ -6414,7 +6414,7 @@ class Fixedpoint(Z3PPObject): """ args, len = _to_ast_array(queries) return Z3_fixedpoint_to_string(self.ctx.ref(), self.fixedpoint, len, args) - + def statistics(self): """Return statistics for the last `query()`. """ @@ -6433,7 +6433,7 @@ class Fixedpoint(Z3PPObject): vars = _get_args(vars) for v in vars: self.vars += [v] - + def abstract(self, fml, is_forall=True): if self.vars == []: return fml @@ -6480,18 +6480,18 @@ def is_finite_domain_sort(s): class FiniteDomainRef(ExprRef): """Finite-domain expressions.""" - + def sort(self): """Return the sort of the finite-domain expression `self`.""" return FiniteDomainSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx) def as_string(self): """Return a Z3 floating point expression as a Python string.""" - return Z3_ast_to_string(self.ctx_ref(), self.as_ast()) + return Z3_ast_to_string(self.ctx_ref(), self.as_ast()) def is_finite_domain(a): """Return `True` if `a` is a Z3 finite-domain expression. - + >>> s = FiniteDomainSort('S', 100) >>> b = Const('b', s) >>> is_finite_domain(b) @@ -6501,13 +6501,13 @@ def is_finite_domain(a): """ return isinstance(a, FiniteDomainRef) - + class FiniteDomainNumRef(FiniteDomainRef): """Integer values.""" def as_long(self): - """Return a Z3 finite-domain numeral as a Python long (bignum) numeral. - + """Return a Z3 finite-domain numeral as a Python long (bignum) numeral. + >>> s = FiniteDomainSort('S', 100) >>> v = FiniteDomainVal(3, s) >>> v @@ -6527,10 +6527,10 @@ class FiniteDomainNumRef(FiniteDomainRef): """ return Z3_get_numeral_string(self.ctx_ref(), self.as_ast()) - + def FiniteDomainVal(val, sort, ctx=None): """Return a Z3 finite-domain value. If `ctx=None`, then the global context is used. - + >>> s = FiniteDomainSort('S', 256) >>> FiniteDomainVal(255, s) 255 @@ -6541,7 +6541,7 @@ def FiniteDomainVal(val, sort, ctx=None): _z3_assert(is_finite_domain_sort(sort), "Expected finite-domain sort" ) ctx = sort.ctx return FiniteDomainNumRef(Z3_mk_numeral(ctx.ref(), _to_int_str(val), sort.ast), ctx) - + def is_finite_domain_value(a): """Return `True` if `a` is a Z3 finite-domain value. @@ -6573,7 +6573,7 @@ class OptimizeObjective: def lower(self): opt = self._opt return _to_expr_ref(Z3_optimize_get_lower(opt.ctx.ref(), opt.optimize, self._value), opt.ctx) - + def upper(self): opt = self._opt return _to_expr_ref(Z3_optimize_get_upper(opt.ctx.ref(), opt.optimize, self._value), opt.ctx) @@ -6586,7 +6586,7 @@ class OptimizeObjective: class Optimize(Z3PPObject): """Optimize API provides methods for solving using objective functions and weighted soft constraints""" - + def __init__(self, ctx=None): self.ctx = _get_ctx(ctx) self.optimize = Z3_mk_optimize(self.ctx.ref()) @@ -6597,7 +6597,7 @@ class Optimize(Z3PPObject): Z3_optimize_dec_ref(self.ctx.ref(), self.optimize) def set(self, *args, **keys): - """Set a configuration option. The method `help()` return a string containing all available options. + """Set a configuration option. The method `help()` return a string containing all available options. """ p = args2params(args, keys, self.ctx) Z3_optimize_set_params(self.ctx.ref(), self.optimize, p.params) @@ -6605,11 +6605,11 @@ class Optimize(Z3PPObject): def help(self): """Display a string describing all available options.""" print(Z3_optimize_get_help(self.ctx.ref(), self.optimize)) - + def param_descrs(self): """Return the parameter description set.""" return ParamDescrsRef(Z3_optimize_get_param_descrs(self.ctx.ref(), self.optimize), self.ctx) - + def assert_exprs(self, *args): """Assert constraints as background axioms for the optimize solver.""" args = _get_args(args) @@ -6681,23 +6681,23 @@ class Optimize(Z3PPObject): if not isinstance(obj, OptimizeObjective): raise Z3Exception("Expecting objective handle returned by maximize/minimize") return obj.upper() - + def __repr__(self): """Return a formatted string with all added rules and constraints.""" return self.sexpr() def sexpr(self): - """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format. + """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format. """ return Z3_optimize_to_string(self.ctx.ref(), self.optimize) - + def statistics(self): """Return statistics for the last `query()`. """ return Statistics(Z3_optimize_get_statistics(self.ctx.ref(), self.optimize), self.ctx) - + ######################################### # @@ -6706,7 +6706,7 @@ class Optimize(Z3PPObject): ######################################### class ApplyResult(Z3PPObject): """An ApplyResult object contains the subgoals produced by a tactic when applied to a goal. It also contains model and proof converters.""" - + def __init__(self, result, ctx): self.result = result self.ctx = ctx @@ -6717,7 +6717,7 @@ class ApplyResult(Z3PPObject): def __len__(self): """Return the number of subgoals in `self`. - + >>> a, b = Ints('a b') >>> g = Goal() >>> g.add(Or(a == 0, a == 1), Or(b == 0, b == 1), a > b) @@ -6742,7 +6742,7 @@ class ApplyResult(Z3PPObject): >>> g.add(Or(a == 0, a == 1), Or(b == 0, b == 1), a > b) >>> t = Tactic('split-clause') >>> r = t(g) - >>> r[0] + >>> r[0] [a == 0, Or(b == 0, b == 1), a > b] >>> r[1] [a == 1, Or(b == 0, b == 1), a > b] @@ -6766,7 +6766,7 @@ class ApplyResult(Z3PPObject): >>> g.add(Or(a == 0, a == 1), Or(b == 0, b == 1), a > b) >>> t = Then(Tactic('split-clause'), Tactic('solve-eqs')) >>> r = t(g) - >>> r[0] + >>> r[0] [Or(b == 0, b == 1), Not(0 <= b)] >>> r[1] [Or(b == 0, b == 1), Not(1 <= b)] @@ -6791,7 +6791,7 @@ class ApplyResult(Z3PPObject): def as_expr(self): """Return a Z3 expression consisting of all subgoals. - + >>> x = Int('x') >>> g = Goal() >>> g.add(x > 1) @@ -6814,7 +6814,7 @@ class ApplyResult(Z3PPObject): return self[0].as_expr() else: return Or([ self[i].as_expr() for i in range(len(self)) ]) - + ######################################### # # Tactics @@ -6848,7 +6848,7 @@ class Tactic: The solver supports the methods `push()` and `pop()`, but it will always solve each `check()` from scratch. - + >>> t = Then('simplify', 'nlsat') >>> s = t.solver() >>> x = Real('x') @@ -6862,7 +6862,7 @@ class Tactic: def apply(self, goal, *arguments, **keywords): """Apply tactic `self` to the given goal or Z3 Boolean expression using the given options. - + >>> x, y = Ints('x y') >>> t = Tactic('solve-eqs') >>> t.apply(And(x == 0, y >= x + 1)) @@ -6879,7 +6879,7 @@ class Tactic: def __call__(self, goal, *arguments, **keywords): """Apply tactic `self` to the given goal or Z3 Boolean expression using the given options. - + >>> x, y = Ints('x y') >>> t = Tactic('solve-eqs') >>> t(And(x == 0, y >= x + 1)) @@ -6925,7 +6925,7 @@ def _or_else(t1, t2, ctx=None): def AndThen(*ts, **ks): """Return a tactic that applies the tactics in `*ts` in sequence. - + >>> x, y = Ints('x y') >>> t = AndThen(Tactic('simplify'), Tactic('solve-eqs')) >>> t(And(x == 0, y > x + 1)) @@ -6944,7 +6944,7 @@ def AndThen(*ts, **ks): def Then(*ts, **ks): """Return a tactic that applies the tactics in `*ts` in sequence. Shorthand for AndThen(*ts, **ks). - + >>> x, y = Ints('x y') >>> t = Then(Tactic('simplify'), Tactic('solve-eqs')) >>> t(And(x == 0, y > x + 1)) @@ -6953,7 +6953,7 @@ def Then(*ts, **ks): Not(y <= 1) """ return AndThen(*ts, **ks) - + def OrElse(*ts, **ks): """Return a tactic that applies the tactics in `*ts` until one of them succeeds (it doesn't fail). @@ -6994,7 +6994,7 @@ def ParOr(*ts, **ks): def ParThen(t1, t2, ctx=None): """Return a tactic that applies t1 and then t2 to every subgoal produced by t1. The subgoals are processed in parallel. - + >>> x, y = Ints('x y') >>> t = ParThen(Tactic('split-clause'), Tactic('propagate-values')) >>> t(And(Or(x == 1, x == 2), y == x + 1)) @@ -7012,7 +7012,7 @@ def ParAndThen(t1, t2, ctx=None): def With(t, *args, **keys): """Return a tactic that applies tactic `t` using the given configuration options. - + >>> x, y = Ints('x y') >>> t = With(Tactic('simplify'), som=True) >>> t((x + 1)*(y + 2) == 0) @@ -7044,7 +7044,7 @@ def Repeat(t, max=4294967295, ctx=None): def TryFor(t, ms, ctx=None): """Return a tactic that applies `t` to a given goal for `ms` milliseconds. - + If `t` does not terminate in `ms` milliseconds, then it fails. """ t = _to_tactic(t, ctx) @@ -7052,7 +7052,7 @@ def TryFor(t, ms, ctx=None): def tactics(ctx=None): """Return a list of all available tactics in Z3. - + >>> l = tactics() >>> l.count('simplify') == 1 True @@ -7196,7 +7196,7 @@ class Probe: def __call__(self, goal): """Evaluate the probe `self` in the given goal. - + >>> p = Probe('size') >>> x = Int('x') >>> g = Goal() @@ -7218,13 +7218,13 @@ class Probe: 1.0 """ if __debug__: - _z3_assert(isinstance(goal, Goal) or isinstance(goal, BoolRef), "Z3 Goal or Boolean expression expected") + _z3_assert(isinstance(goal, Goal) or isinstance(goal, BoolRef), "Z3 Goal or Boolean expression expected") goal = _to_goal(goal) return Z3_probe_apply(self.ctx.ref(), self.probe, goal.goal) def is_probe(p): """Return `True` if `p` is a Z3 probe. - + >>> is_probe(Int('x')) False >>> is_probe(Probe('memory')) @@ -7240,7 +7240,7 @@ def _to_probe(p, ctx=None): def probes(ctx=None): """Return a list of all available probes in Z3. - + >>> l = probes() >>> l.count('memory') == 1 True @@ -7250,7 +7250,7 @@ def probes(ctx=None): def probe_description(name, ctx=None): """Return a short description for the probe named `name`. - + >>> d = probe_description('memory') """ ctx = _get_ctx(ctx) @@ -7310,7 +7310,7 @@ def FailIf(p, ctx=None): def When(p, t, ctx=None): """Return a tactic that applies tactic `t` only if probe `p` evaluates to true. Otherwise, it returns the input goal unmodified. - + >>> t = When(Probe('size') > 2, Tactic('simplify')) >>> x, y = Ints('x y') >>> g = Goal() @@ -7328,7 +7328,7 @@ def When(p, t, ctx=None): def Cond(p, t1, t2, ctx=None): """Return a tactic that applies tactic `t1` to a goal if probe `p` evaluates to true, and `t2` otherwise. - + >>> t = Cond(Probe('is-qfnra'), Tactic('qfnra'), Tactic('smt')) """ p = _to_probe(p, ctx) @@ -7346,7 +7346,7 @@ def simplify(a, *arguments, **keywords): """Simplify the expression `a` using the given options. This function has many options. Use `help_simplify` to obtain the complete list. - + >>> x = Int('x') >>> y = Int('y') >>> simplify(x + 1 + y + x + 1) @@ -7376,7 +7376,7 @@ def simplify_param_descrs(): def substitute(t, *m): """Apply substitution m on t, m is a list of pairs of the form (from, to). Every occurrence in t of from is replaced with to. - + >>> x = Int('x') >>> y = Int('y') >>> substitute(x + 1, (x, y + 1)) @@ -7402,7 +7402,7 @@ def substitute(t, *m): def substitute_vars(t, *m): """Substitute the free variables in t with the expression in m. - + >>> v0 = Var(0, IntSort()) >>> v1 = Var(1, IntSort()) >>> x = Int('x') @@ -7421,8 +7421,8 @@ def substitute_vars(t, *m): return _to_expr_ref(Z3_substitute_vars(t.ctx.ref(), t.as_ast(), num, _to), t.ctx) def Sum(*args): - """Create the sum of the Z3 expressions. - + """Create the sum of the Z3 expressions. + >>> a, b, c = Ints('a b c') >>> Sum(a, b, c) a + b + c @@ -7446,8 +7446,8 @@ def Sum(*args): return ArithRef(Z3_mk_add(ctx.ref(), sz, _args), ctx) def Product(*args): - """Create the product of the Z3 expressions. - + """Create the product of the Z3 expressions. + >>> a, b, c = Ints('a b c') >>> Product(a, b, c) a*b*c @@ -7510,11 +7510,11 @@ def PbLe(args, k): def solve(*args, **keywords): """Solve the constraints `*args`. - + This is a simple function for creating demonstrations. It creates a solver, configure it using the options in `keywords`, adds the constraints in `args`, and invokes check. - + >>> a = Int('a') >>> solve(a > 0, a < 2) [a = 1] @@ -7538,7 +7538,7 @@ def solve(*args, **keywords): def solve_using(s, *args, **keywords): """Solve the constraints `*args` using solver `s`. - + This is a simple function for creating demonstrations. It is similar to `solve`, but it uses the given solver `s`. It configures solver `s` using the options in `keywords`, adds the constraints @@ -7691,7 +7691,7 @@ def _dict2darray(decls, ctx): def parse_smt2_string(s, sorts={}, decls={}, ctx=None): """Parse a string in SMT 2.0 format using the given sorts and decls. - + The arguments sorts and decls are Python dictionaries used to initialize the symbol table used for the SMT 2.0 parser. @@ -7711,18 +7711,18 @@ def parse_smt2_string(s, sorts={}, decls={}, ctx=None): def parse_smt2_file(f, sorts={}, decls={}, ctx=None): """Parse a file in SMT 2.0 format using the given sorts and decls. - + This function is similar to parse_smt2_string(). """ ctx = _get_ctx(ctx) ssz, snames, ssorts = _dict2sarray(sorts, ctx) dsz, dnames, ddecls = _dict2darray(decls, ctx) return _to_expr_ref(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx) - + def Interpolant(a,ctx=None): """Create an interpolation operator. - - The argument is an interpolation pattern (see tree_interpolant). + + The argument is an interpolation pattern (see tree_interpolant). >>> x = Int('x') >>> print(Interpolant(x>0)) @@ -7754,7 +7754,7 @@ def tree_interpolant(pat,p=None,ctx=None): and moreover pat sigma implies false. In the simplest case an interpolant for the pattern "(and (interp A) B)" maps A - to an interpolant for A /\ B. + to an interpolant for A /\ B. The return value is a vector of formulas representing sigma. This vector contains sigma(phi) for each marked subformula of pat, in @@ -7836,8 +7836,8 @@ def sequence_interpolant(v,p=None,ctx=None): 1) w[i] & v[i+1] implies w[i+1] (or false if i+1 = N) 2) All uninterpreted symbols in w[i] occur in both v[0]..v[i] and v[i+1]..v[n] - - Requires len(v) >= 1. + + Requires len(v) >= 1. If a & b is satisfiable, raises an object of class ModelRef that represents a model of a & b. @@ -7866,7 +7866,7 @@ def sequence_interpolant(v,p=None,ctx=None): # ######################################### - + # Global default rounding mode _dflt_rounding_mode = Z3_OP_FPA_RM_TOWARD_ZERO _dflt_fpsort_ebits = 11 @@ -7927,7 +7927,7 @@ def _coerce_fp_expr_list(alist, ctx): # throw a sort mismatch later, for now assume None. first_fp_sort = None break - + r = [] for i in range(len(alist)): a = alist[i] @@ -7939,7 +7939,7 @@ def _coerce_fp_expr_list(alist, ctx): ### FP Sorts - + class FPSortRef(SortRef): """Floating-point sort.""" @@ -8041,10 +8041,10 @@ def is_fprm_sort(s): return isinstance(s, FPRMSortRef) ### FP Expressions - + class FPRef(ExprRef): """Floating-point expressions.""" - + def sort(self): """Return the sort of the floating-point expression `self`. @@ -8077,24 +8077,24 @@ class FPRef(ExprRef): return Z3_ast_to_string(self.ctx_ref(), self.as_ast()) def __le__(self, other): - return fpLEQ(self, other) + return fpLEQ(self, other, self.ctx) def __lt__(self, other): - return fpLT(self, other) + return fpLT(self, other, self.ctx) def __ge__(self, other): - return fpGEQ(self, other) - + return fpGEQ(self, other, self.ctx) + def __gt__(self, other): - return fpGT(self, other) + return fpGT(self, other, self.ctx) def __ne__(self, other): - return fpNEQ(self, other) + return fpNEQ(self, other, self.ctx) def __add__(self, other): """Create the Z3 expression `self + other`. - + >>> x = FP('x', FPSort(8, 24)) >>> y = FP('y', FPSort(8, 24)) >>> x + y @@ -8107,7 +8107,7 @@ class FPRef(ExprRef): def __radd__(self, other): """Create the Z3 expression `other + self`. - + >>> x = FP('x', FPSort(8, 24)) >>> 10 + x 1.25*(2**3) + x @@ -8117,7 +8117,7 @@ class FPRef(ExprRef): def __sub__(self, other): """Create the Z3 expression `self - other`. - + >>> x = FP('x', FPSort(8, 24)) >>> y = FP('y', FPSort(8, 24)) >>> x - y @@ -8130,17 +8130,17 @@ class FPRef(ExprRef): def __rsub__(self, other): """Create the Z3 expression `other - self`. - + >>> x = FP('x', FPSort(8, 24)) >>> 10 - x 1.25*(2**3) - x """ [a, b] = _coerce_fp_expr_list([other, self], self.ctx) return fpSub(_dflt_rm(), a, b, self.ctx) - + def __mul__(self, other): """Create the Z3 expression `self * other`. - + >>> x = FP('x', FPSort(8, 24)) >>> y = FP('y', FPSort(8, 24)) >>> x * y @@ -8155,7 +8155,7 @@ class FPRef(ExprRef): def __rmul__(self, other): """Create the Z3 expression `other * self`. - + >>> x = FP('x', FPSort(8, 24)) >>> y = FP('y', FPSort(8, 24)) >>> x * y @@ -8169,14 +8169,14 @@ class FPRef(ExprRef): def __pos__(self): """Create the Z3 expression `+self`.""" return self - + def __neg__(self): """Create the Z3 expression `-self`.""" return FPRef(fpNeg(self)) - + def __div__(self, other): """Create the Z3 expression `self / other`. - + >>> x = FP('x', FPSort(8, 24)) >>> y = FP('y', FPSort(8, 24)) >>> x / y @@ -8191,7 +8191,7 @@ class FPRef(ExprRef): def __rdiv__(self, other): """Create the Z3 expression `other / self`. - + >>> x = FP('x', FPSort(8, 24)) >>> y = FP('y', FPSort(8, 24)) >>> x / y @@ -8206,10 +8206,10 @@ class FPRef(ExprRef): def __truediv__(self, other): """Create the Z3 expression division `self / other`.""" return self.__div__(other) - + def __rtruediv__(self, other): """Create the Z3 expression division `other / self`.""" - return self.__rdiv__(other) + return self.__rdiv__(other) def __mod__(self, other): """Create the Z3 expression mod `self % other`.""" @@ -8226,7 +8226,7 @@ class FPRMRef(ExprRef): """Return a Z3 floating point expression as a Python string.""" return Z3_ast_to_string(self.ctx_ref(), self.as_ast()) - + def RoundNearestTiesToEven(ctx=None): ctx = _get_ctx(ctx) return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_even(ctx.ref()), ctx) @@ -8282,7 +8282,7 @@ def is_fprm(a): def is_fprm_value(a): """Return `True` if `a` is a Z3 floating-point rounding mode numeral value.""" return is_fprm(a) and _is_numeral(a.ctx, a.ast) - + ### FP Numerals class FPNumRef(FPRef): @@ -8345,7 +8345,7 @@ class FPNumRef(FPRef): def exponent_as_long(self): ptr = (ctypes.c_longlong * 1)() if not Z3_fpa_get_numeral_exponent_int64(self.ctx.ref(), self.as_ast(), ptr): - raise Z3Exception("error retrieving the exponent of a numeral.") + raise Z3Exception("error retrieving the exponent of a numeral.") return ptr[0] """ @@ -8359,16 +8359,9 @@ class FPNumRef(FPRef): s = Z3_fpa_get_numeral_string(self.ctx.ref(), self.as_ast()) return ("FPVal(%s, %s)" % (s, FPSortRef(self.sort()).as_string())) - -def _to_fpnum(num, ctx=None): - if isinstance(num, FPNum): - return num - else: - return FPNum(num, ctx) - def is_fp(a): """Return `True` if `a` is a Z3 floating-point expression. - + >>> b = FP('b', FPSort(8, 24)) >>> is_fp(b) True @@ -8499,7 +8492,7 @@ def fpZero(s, negative): def FPVal(sig, exp=None, fps=None, ctx=None): """Return a floating-point value of value `val` and sort `fps`. If `ctx=None`, then the global context is used. - + >>> v = FPVal(20.0, FPSort(8, 24)) >>> v 1.25*(2**4) @@ -8520,12 +8513,12 @@ def FPVal(sig, exp=None, fps=None, ctx=None): fps = _dflt_fps(ctx) _z3_assert(is_fp_sort(fps), "sort mismatch") if exp == None: - exp = 0 + exp = 0 val = _to_float_str(sig) return FPNumRef(Z3_mk_numeral(ctx.ref(), val, fps.ast), ctx) def FP(name, fpsort, ctx=None): - """Return a floating-point constant named `name`. + """Return a floating-point constant named `name`. `fpsort` is the floating-point sort. If `ctx=None`, then the global context is used. @@ -8549,7 +8542,7 @@ def FP(name, fpsort, ctx=None): def FPs(names, fpsort, ctx=None): """Return an array of floating-point constants. - + >>> x, y, z = FPs('x y z', FPSort(8, 24)) >>> x.sort() FPSort(8, 24) @@ -8600,7 +8593,7 @@ def fpNeg(a, ctx=None): """ ctx = _get_ctx(ctx) [a] = _coerce_fp_expr_list([a], ctx) - return FPRef(Z3_mk_fpa_neg(ctx.ref(), a.as_ast()), ctx) + return FPRef(Z3_mk_fpa_neg(ctx.ref(), a.as_ast()), ctx) def _mk_fp_unary(f, rm, a, ctx): ctx = _get_ctx(ctx) @@ -8669,7 +8662,7 @@ def fpAdd(rm, a, b, ctx=None): FPSort(8, 24) """ return _mk_fp_bin(Z3_mk_fpa_add, rm, a, b, ctx) - + def fpSub(rm, a, b, ctx=None): """Create a Z3 floating-point subtraction expression. @@ -8697,7 +8690,7 @@ def fpMul(rm, a, b, ctx=None): FPSort(8, 24) """ return _mk_fp_bin(Z3_mk_fpa_mul, rm, a, b, ctx) - + def fpDiv(rm, a, b, ctx=None): """Create a Z3 floating-point divison expression. @@ -8813,7 +8806,7 @@ def fpIsPositive(a, ctx=None): """Create a Z3 floating-point isPositive expression. """ return _mk_fp_unary_norm(Z3_mk_fpa_is_positive, a, ctx) - return FPRef(Z3_mk_fpa_is_positive(a.ctx_ref(), a.as_ast()), a.ctx) + return FPRef(Z3_mk_fpa_is_positive(a.ctx_ref(), a.as_ast()), a.ctx) def _check_fp_args(a, b): if __debug__: @@ -8821,7 +8814,7 @@ def _check_fp_args(a, b): def fpLT(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. - + >>> x, y = FPs('x y', FPSort(8, 24)) >>> fpLT(x, y) x < y @@ -8832,7 +8825,7 @@ def fpLT(a, b, ctx=None): def fpLEQ(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. - + >>> x, y = FPs('x y', FPSort(8, 24)) >>> fpLEQ(x, y) x <= y @@ -8843,7 +8836,7 @@ def fpLEQ(a, b, ctx=None): def fpGT(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. - + >>> x, y = FPs('x y', FPSort(8, 24)) >>> fpGT(x, y) x > y @@ -8854,7 +8847,7 @@ def fpGT(a, b, ctx=None): def fpGEQ(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. - + >>> x, y = FPs('x y', FPSort(8, 24)) >>> x + y x + y @@ -8867,7 +8860,7 @@ def fpGEQ(a, b, ctx=None): def fpEQ(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. - + >>> x, y = FPs('x y', FPSort(8, 24)) >>> fpEQ(x, y) fpEQ(x, y) @@ -8878,7 +8871,7 @@ def fpEQ(a, b, ctx=None): def fpNEQ(a, b, ctx=None): """Create the Z3 floating-point expression `other <= self`. - + >>> x, y = FPs('x y', FPSort(8, 24)) >>> fpNEQ(x, y) Not(fpEQ(x, y)) @@ -8887,35 +8880,45 @@ def fpNEQ(a, b, ctx=None): """ return Not(fpEQ(a, b, ctx)) -def fpFP(sgn, exp, sig): +def fpFP(sgn, exp, sig, ctx=None): """Create the Z3 floating-point value `fpFP(sgn, sig, exp)` from the three bit-vectors sgn, sig, and exp. - >>> s = FPSort(11, 53) - >>> x = fpFP(BitVecVal(1, 1), BitVecVal(0, 11), BitVecVal(0, 52)) + >>> s = FPSort(8, 24) + >>> x = fpFP(BitVecVal(1, 1), BitVecVal(2**7-1, 8), BitVecVal(2**22, 23)) >>> print(x) - fpFP(1, 0, 0) + fpFP(1, 127, 4194304) + >>> xv = FPVal(-1.5, s) + >>> print(xv) + -1.5 >>> slvr = Solver() - >>> slvr.add(fpEQ(x, fpMinusZero(s))) + >>> slvr.add(fpEQ(x, xv)) >>> slvr.check() sat - >>> slvr.model() - [x = 1] + >>> xv = FPVal(+1.5, s) + >>> print(xv) + 1.5 + >>> slvr = Solver() + >>> slvr.add(fpEQ(x, xv)) + >>> slvr.check() + unsat """ _z3_assert(is_bv(sgn) and is_bv(exp) and is_bv(sig), "sort mismatch") _z3_assert(sgn.sort().size() == 1, "sort mismatch") - _z3_assert(sgn.ctx == exp.ctx == sig.ctx, "sort mismatch") - return FPRef(Z3_mk_fpa_fp(sgn.ctx.ref(), sgn.ast, exp.ast, sig.ast), sgn.ctx) + ctx = _get_ctx(ctx) + _z3_assert(ctx == sgn.ctx == exp.ctx == sig.ctx, "context mismatch") + return FPRef(Z3_mk_fpa_fp(ctx.ref(), sgn.ast, exp.ast, sig.ast), ctx) -def fpToFP(a1, a2=None, a3=None): +def fpToFP(a1, a2=None, a3=None, ctx=None): """Create a Z3 floating-point conversion expression from other terms.""" + ctx = _get_ctx(ctx) if is_bv(a1) and is_fp_sort(a2): - return FPRef(Z3_mk_fpa_to_fp_bv(a1.ctx_ref(), a1.ast, a2.ast), a1.ctx) + return FPRef(Z3_mk_fpa_to_fp_bv(ctx.ref(), a1.ast, a2.ast), ctx) elif is_fprm(a1) and is_fp(a2) and is_fp_sort(a3): - return FPRef(Z3_mk_fpa_to_fp_float(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx) + return FPRef(Z3_mk_fpa_to_fp_float(ctx.ref(), a1.ast, a2.ast, a3.ast), ctx) elif is_fprm(a1) and is_real(a2) and is_fp_sort(a3): - return FPRef(Z3_mk_fpa_to_fp_real(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx) + return FPRef(Z3_mk_fpa_to_fp_real(ctx.ref(), a1.ast, a2.ast, a3.ast), ctx) elif is_fprm(a1) and is_bv(a2) and is_fp_sort(a3): - return FPRef(Z3_mk_fpa_to_fp_signed(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx) + return FPRef(Z3_mk_fpa_to_fp_signed(ctx.ref(), a1.ast, a2.ast, a3.ast), ctx) else: raise Z3Exception("Unsupported combination of arguments for conversion to floating-point term.") @@ -8925,7 +8928,8 @@ def fpToFPUnsigned(rm, x, s, ctx=None): _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") _z3_assert(is_bv(x), "Second argument must be a Z3 bit-vector expression") _z3_assert(is_fp_sort(s), "Third argument must be Z3 floating-point sort") - return FPRef(Z3_mk_fpa_to_fp_unsigned(rm.ctx_ref(), rm.ast, x.ast, s.ast), rm.ctx) + ctx = _get_ctx(ctx) + return FPRef(Z3_mk_fpa_to_fp_unsigned(ctx.ref(), rm.ast, x.ast, s.ast), ctx) def fpToSBV(rm, x, s, ctx=None): """Create a Z3 floating-point conversion expression, from floating-point expression to signed bit-vector. @@ -8945,9 +8949,10 @@ def fpToSBV(rm, x, s, ctx=None): _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") _z3_assert(is_fp(x), "Second argument must be a Z3 floating-point expression") _z3_assert(is_bv_sort(s), "Third argument must be Z3 bit-vector sort") - return BitVecRef(Z3_mk_fpa_to_sbv(rm.ctx_ref(), rm.ast, x.ast, s.size()), rm.ctx) + ctx = _get_ctx(ctx) + return BitVecRef(Z3_mk_fpa_to_sbv(ctx.ref(), rm.ast, x.ast, s.size()), ctx) -def fpToUBV(rm, x, s): +def fpToUBV(rm, x, s, ctx=None): """Create a Z3 floating-point conversion expression, from floating-point expression to unsigned bit-vector. >>> x = FP('x', FPSort(8, 24)) @@ -8965,9 +8970,10 @@ def fpToUBV(rm, x, s): _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression") _z3_assert(is_fp(x), "Second argument must be a Z3 floating-point expression") _z3_assert(is_bv_sort(s), "Third argument must be Z3 bit-vector sort") - return BitVecRef(Z3_mk_fpa_to_ubv(rm.ctx_ref(), rm.ast, x.ast, s.size()), rm.ctx) + ctx = _get_ctx(ctx) + return BitVecRef(Z3_mk_fpa_to_ubv(ctx.ref(), rm.ast, x.ast, s.size()), ctx) -def fpToReal(x): +def fpToReal(x, ctx=None): """Create a Z3 floating-point conversion expression, from floating-point expression to real. >>> x = FP('x', FPSort(8, 24)) @@ -8983,15 +8989,16 @@ def fpToReal(x): """ if __debug__: _z3_assert(is_fp(x), "First argument must be a Z3 floating-point expression") - return ArithRef(Z3_mk_fpa_to_real(x.ctx_ref(), x.ast), x.ctx) + ctx = _get_ctx(ctx) + return ArithRef(Z3_mk_fpa_to_real(ctx.ref(), x.ast), ctx) -def fpToIEEEBV(x): +def fpToIEEEBV(x, ctx=None): """\brief Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format. - - The size of the resulting bit-vector is automatically determined. - - Note that IEEE 754-2008 allows multiple different representations of NaN. This conversion - knows only one NaN and it will always produce the same bit-vector represenatation of + + The size of the resulting bit-vector is automatically determined. + + Note that IEEE 754-2008 allows multiple different representations of NaN. This conversion + knows only one NaN and it will always produce the same bit-vector represenatation of that NaN. >>> x = FP('x', FPSort(8, 24)) @@ -9007,7 +9014,8 @@ def fpToIEEEBV(x): """ if __debug__: _z3_assert(is_fp(x), "First argument must be a Z3 floating-point expression") - return BitVecRef(Z3_mk_fpa_to_ieee_bv(x.ctx_ref(), x.ast), x.ctx) + ctx = _get_ctx(ctx) + return BitVecRef(Z3_mk_fpa_to_ieee_bv(ctx.ref(), x.ast), ctx) @@ -9030,7 +9038,7 @@ class SeqSortRef(SortRef): False """ return Z3_is_string_sort(self.ctx_ref(), self.ast) - + def StringSort(ctx=None): """Create a string sort >>> s = StringSort() @@ -9060,7 +9068,7 @@ class SeqRef(ExprRef): def __getitem__(self, i): return SeqRef(Z3_mk_seq_at(self.ctx_ref(), self.as_ast(), i.as_ast()), self.ctx) - + def is_string(self): return Z3_is_string_sort(self.ctx_ref(), Z3_get_sort(self.ctx_ref(), self.as_ast())) @@ -9069,7 +9077,7 @@ class SeqRef(ExprRef): def as_string(self): """Return a string representation of sequence expression.""" - return Z3_ast_to_string(self.ctx_ref(), self.as_ast()) + return Z3_ast_to_string(self.ctx_ref(), self.as_ast()) def _coerce_seq(s, ctx=None): @@ -9176,7 +9184,7 @@ def SuffixOf(a, b): """ ctx = _get_ctx2(a, b) a = _coerce_seq(a, ctx) - b = _coerce_seq(b, ctx) + b = _coerce_seq(b, ctx) return BoolRef(Z3_mk_seq_suffix(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) def Contains(a, b): @@ -9194,7 +9202,7 @@ def Contains(a, b): """ ctx = _get_ctx2(a, b) a = _coerce_seq(a, ctx) - b = _coerce_seq(b, ctx) + b = _coerce_seq(b, ctx) return BoolRef(Z3_mk_seq_contains(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx) @@ -9229,7 +9237,7 @@ def IndexOf(s, substr, offset): s = _coerce_seq(s, ctx) substr = _coerce_seq(substr, ctx) if isinstance(offset, int): - offset = IntVal(offset, ctx) + offset = IntVal(offset, ctx) return SeqRef(Z3_mk_seq_index(s.ctx_ref(), s.as_ast(), substr.as_ast(), offset.as_ast()), s.ctx) def Length(s): @@ -9297,13 +9305,13 @@ def Union(*args): >>> re = Union(Re("a"), Re("b"), Re("c")) >>> print (simplify(InRe("d", re))) False - """ + """ args = _get_args(args) sz = len(args) if __debug__: _z3_assert(sz >= 2, "At least two arguments expected.") _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.") - ctx = args[0].ctx + ctx = args[0].ctx v = (Ast * sz)() for i in range(sz): v[i] = args[i].as_ast() @@ -9318,7 +9326,7 @@ def Plus(re): False >>> print(simplify(InRe("", re))) False - """ + """ return ReRef(Z3_mk_re_plus(re.ctx_ref(), re.as_ast()), re.ctx) def Option(re): @@ -9342,5 +9350,5 @@ def Star(re): False >>> print(simplify(InRe("", re))) True - """ + """ return ReRef(Z3_mk_re_star(re.ctx_ref(), re.as_ast()), re.ctx) From 465d28e160700580c31078f0c5548c3622d5b1ec Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 5 Jan 2016 14:57:41 +0000 Subject: [PATCH 75/87] seq_decl: fix build with stricter compilers get rid of 32 rellocations as a nice side-effect --- src/ast/seq_decl_plugin.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp index 44901b506..9c8a085e8 100644 --- a/src/ast/seq_decl_plugin.cpp +++ b/src/ast/seq_decl_plugin.cpp @@ -80,8 +80,9 @@ zstring zstring::replace(zstring const& src, zstring const& dst) const { return result; } -static char* esc_table[32] = { "\\0", "^A", "^B", "^C", "^D", "^E", "^F", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "^N", - "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V","^W","^X","^Y","^Z","\\e","^\\","^]","^^","^_"}; +static const char esc_table[32][3] = + { "\\0", "^A", "^B", "^C", "^D", "^E", "^F", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "^N", + "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V","^W","^X","^Y","^Z","\\e","^\\","^]","^^","^_"}; std::string zstring::encode() const { SASSERT(m_encoding == ascii); From af758dea4ae0b7c438de749977ade9d3f19407de Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Jan 2016 08:23:44 -0800 Subject: [PATCH 76/87] tuning for seq Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith.h | 2 ++ src/smt/theory_arith_aux.h | 3 ++ src/smt/theory_arith_core.h | 14 +++++++++ src/smt/theory_seq.cpp | 57 ++++++++++++++++++++++++++++--------- src/smt/theory_seq.h | 4 +-- 5 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 2f5590e25..7b56f19e5 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -429,6 +429,7 @@ namespace smt { arith_util m_util; arith_eq_solver m_arith_eq_solver; bool m_found_unsupported_op; + bool m_found_underspecified_op; arith_eq_adapter m_arith_eq_adapter; vector m_rows; svector m_dead_rows; @@ -510,6 +511,7 @@ namespace smt { virtual theory_var mk_var(enode * n); void found_unsupported_op(app * n); + void found_underspecified_op(app * n); bool has_var(expr * v) const { return get_context().e_internalized(v) && get_context().get_enode(v)->get_th_var(get_id()) != null_theory_var; } theory_var expr2var(expr * v) const { SASSERT(get_context().e_internalized(v)); return get_context().get_enode(v)->get_th_var(get_id()); } diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 2473b32ab..4291590c6 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -2153,6 +2153,9 @@ namespace smt { */ template bool theory_arith::is_shared(theory_var v) const { + if (!m_found_underspecified_op) { + return false; + } enode * n = get_enode(v); enode * r = n->get_root(); enode_vector::const_iterator it = r->begin_parents(); diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index d6fe16089..4561e1ced 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -37,6 +37,15 @@ namespace smt { } } + template + void theory_arith::found_underspecified_op(app * n) { + if (!m_found_underspecified_op) { + TRACE("arith", tout << "found non underspecificed expression:\n" << mk_pp(n, get_manager()) << "\n";); + get_context().push_trail(value_trail(m_found_underspecified_op)); + m_found_underspecified_op = true; + } + } + template bool theory_arith::process_atoms() const { if (!adaptive()) @@ -308,6 +317,7 @@ namespace smt { template theory_var theory_arith::internalize_div(app * n) { + found_underspecified_op(n); theory_var s = mk_binary_op(n); context & ctx = get_context(); if (!ctx.relevancy()) @@ -317,6 +327,7 @@ namespace smt { template theory_var theory_arith::internalize_idiv(app * n) { + found_underspecified_op(n); theory_var s = mk_binary_op(n); context & ctx = get_context(); app * mod = m_util.mk_mod(n->get_arg(0), n->get_arg(1)); @@ -329,6 +340,7 @@ namespace smt { template theory_var theory_arith::internalize_mod(app * n) { TRACE("arith_mod", tout << "internalizing...\n" << mk_pp(n, get_manager()) << "\n";); + found_underspecified_op(n); theory_var s = mk_binary_op(n); context & ctx = get_context(); if (!ctx.relevancy()) @@ -338,6 +350,7 @@ namespace smt { template theory_var theory_arith::internalize_rem(app * n) { + found_underspecified_op(n); theory_var s = mk_binary_op(n); context & ctx = get_context(); if (!ctx.relevancy()) { @@ -1514,6 +1527,7 @@ namespace smt { m_util(m), m_arith_eq_solver(m), m_found_unsupported_op(false), + m_found_underspecified_op(false), m_arith_eq_adapter(*this, params, m_util), m_asserted_qhead(0), m_to_patch(1024), diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index e3ede010c..0592f88d9 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -159,7 +159,6 @@ theory_seq::theory_seq(ast_manager& m): m_exclude(m), m_axioms(m), m_axioms_head(0), - m_branch_variable_head(0), m_mg(0), m_rewrite(m), m_util(m), @@ -234,8 +233,9 @@ bool theory_seq::branch_variable() { context& ctx = get_context(); unsigned sz = m_eqs.size(); expr_ref_vector ls(m), rs(m); + int start = ctx.get_random_value(); for (unsigned i = 0; i < sz; ++i) { - unsigned k = (i + m_branch_variable_head) % sz; + unsigned k = (i + start) % sz; eq e = m_eqs[k]; TRACE("seq", tout << e.m_lhs << " = " << e.m_rhs << "\n";); ls.reset(); rs.reset(); @@ -243,21 +243,17 @@ bool theory_seq::branch_variable() { m_util.str.get_concat(e.m_rhs, rs); #if 1 - if (!ls.empty() && find_branch_candidate(e.m_dep, ls[0].get(), rs)) { - m_branch_variable_head = k; + if (find_branch_candidate(e.m_dep, ls, rs)) { return true; } - if (!rs.empty() && find_branch_candidate(e.m_dep, rs[0].get(), ls)) { - m_branch_variable_head = k; + if (find_branch_candidate(e.m_dep, rs, ls)) { return true; } #else - if (ls.size() > 1 && find_branch_candidate(e.m_dep, ls.back(), rs)) { - m_branch_variable_head = k; + if (find_branch_candidate(e.m_dep, ls.back(), rs)) { return true; } - if (rs.size() > 1 && find_branch_candidate(e.m_dep, rs.back(), ls)) { - m_branch_variable_head = k; + if (find_branch_candidate(e.m_dep, rs.back(), ls)) { return true; } #endif @@ -273,10 +269,12 @@ bool theory_seq::branch_variable() { return ctx.inconsistent(); } -bool theory_seq::find_branch_candidate(dependency* dep, expr* l, expr_ref_vector const& rs) { +bool theory_seq::find_branch_candidate(dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs) { - TRACE("seq", tout << mk_pp(l, m) << " " - << (is_var(l)?"var":"not var") << "\n";); + if (ls.empty()) { + return false; + } + expr* l = ls[0]; if (!is_var(l)) { return false; @@ -286,7 +284,8 @@ bool theory_seq::find_branch_candidate(dependency* dep, expr* l, expr_ref_vector expr_ref_vector cases(m); expr_ref v0(m), v(m); v0 = m_util.str.mk_empty(m.get_sort(l)); - if (l_false != assume_equality(l, v0)) { + if (can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size(), rs.c_ptr()) && l_false != assume_equality(l, v0)) { + TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";); return true; } for (unsigned j = 0; j < rs.size(); ++j) { @@ -295,8 +294,12 @@ bool theory_seq::find_branch_candidate(dependency* dep, expr* l, expr_ref_vector } SASSERT(!m_util.str.is_string(rs[j])); all_units &= m_util.str.is_unit(rs[j]); + if (!can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size() - j - 1, rs.c_ptr() + j + 1)) { + continue; + } v0 = m_util.str.mk_concat(j + 1, rs.c_ptr()); if (l_false != assume_equality(l, v0)) { + TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";); return true; } } @@ -308,11 +311,37 @@ bool theory_seq::find_branch_candidate(dependency* dep, expr* l, expr_ref_vector lits.push_back(~mk_eq(l, v0, false)); } set_conflict(dep, lits); + TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";); return true; } return false; } +bool theory_seq::can_be_equal(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs) const { + unsigned i = 0; + for (; i < szl && i < szr; ++i) { + if (m.are_distinct(ls[i], rs[i])) { + return false; + } + if (!m.are_equal(ls[i], rs[i])) { + break; + } + } + if (i == szr) { + std::swap(ls, rs); + std::swap(szl, szr); + } + if (i == szl && i < szr) { + for (; i < szr; ++i) { + if (m_util.str.is_unit(rs[i])) { + return false; + } + } + } + return true; +} + + lbool theory_seq::assume_equality(expr* l, expr* r) { context& ctx = get_context(); if (m_exclude.contains(l, r)) { diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index cd8d67cd1..12975b94d 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -304,7 +304,6 @@ namespace smt { expr_ref_vector m_axioms; // list of axioms to add. obj_hashtable m_axiom_set; unsigned m_axioms_head; // index of first axiom to add. - unsigned m_branch_variable_head; // index of first equation to examine. bool m_incomplete; // is the solver (clearly) incomplete for the fragment. obj_hashtable m_length; // is length applied scoped_ptr_vector m_replay; // set of actions to replay @@ -387,7 +386,8 @@ namespace smt { void propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs = false); void set_conflict(dependency* dep, literal_vector const& lits = literal_vector()); - bool find_branch_candidate(dependency* dep, expr* l, expr_ref_vector const& rs); + bool find_branch_candidate(dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs); + bool can_be_equal(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs) const; lbool assume_equality(expr* l, expr* r); // variable solving utilities From 752a973e53bd21da97b34fb715c7bda7a097a483 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Jan 2016 08:32:48 -0800 Subject: [PATCH 77/87] missing files? Signed-off-by: Nikolaj Bjorner --- src/api/java/ReExpr.java | 33 +++++++++++++++++++++++++++++++++ src/api/java/ReSort.java | 29 +++++++++++++++++++++++++++++ src/api/java/SeqExpr.java | 33 +++++++++++++++++++++++++++++++++ src/api/java/SeqSort.java | 29 +++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 src/api/java/ReExpr.java create mode 100644 src/api/java/ReSort.java create mode 100644 src/api/java/SeqExpr.java create mode 100644 src/api/java/SeqSort.java diff --git a/src/api/java/ReExpr.java b/src/api/java/ReExpr.java new file mode 100644 index 000000000..60dc2bf96 --- /dev/null +++ b/src/api/java/ReExpr.java @@ -0,0 +1,33 @@ +/** +Copyright (c) 2012-2016 Microsoft Corporation + +Module Name: + + ReExpr.java + +Abstract: + +Author: + + @author Christoph Wintersteiger (cwinter) 2012-03-15 + +Notes: + +**/ + +package com.microsoft.z3; + +/** + * Re expressions + **/ +public class ReExpr extends Expr +{ + /** + * Constructor for ReExpr + * @throws Z3Exception on error + **/ + ReExpr(Context ctx, long obj) + { + super(ctx, obj); + } +} diff --git a/src/api/java/ReSort.java b/src/api/java/ReSort.java new file mode 100644 index 000000000..74e7c5c5f --- /dev/null +++ b/src/api/java/ReSort.java @@ -0,0 +1,29 @@ +/** +Copyright (c) 2012-2014 Microsoft Corporation + +Module Name: + + ReSort.java + +Abstract: + +Author: + + @author Christoph Wintersteiger (cwinter) 2012-03-15 + +Notes: + +**/ + +package com.microsoft.z3; + +/** + * A Regular expression sort + **/ +public class ReSort extends Sort +{ + ReSort(Context ctx, long obj) + { + super(ctx, obj); + } +} diff --git a/src/api/java/SeqExpr.java b/src/api/java/SeqExpr.java new file mode 100644 index 000000000..47976dd5e --- /dev/null +++ b/src/api/java/SeqExpr.java @@ -0,0 +1,33 @@ +/** +Copyright (c) 2012-2016 Microsoft Corporation + +Module Name: + + SeqExpr.java + +Abstract: + +Author: + + @author Christoph Wintersteiger (cwinter) 2012-03-15 + +Notes: + +**/ + +package com.microsoft.z3; + +/** + * Seq expressions + **/ +public class SeqExpr extends Expr +{ + /** + * Constructor for SeqExpr + * @throws Z3Exception on error + **/ + SeqExpr(Context ctx, long obj) + { + super(ctx, obj); + } +} diff --git a/src/api/java/SeqSort.java b/src/api/java/SeqSort.java new file mode 100644 index 000000000..5c7a549c9 --- /dev/null +++ b/src/api/java/SeqSort.java @@ -0,0 +1,29 @@ +/** +Copyright (c) 2012-2014 Microsoft Corporation + +Module Name: + + SeqSort.java + +Abstract: + +Author: + + @author Christoph Wintersteiger (cwinter) 2012-03-15 + +Notes: + +**/ + +package com.microsoft.z3; + +/** + * A Sequence sort + **/ +public class SeqSort extends Sort +{ + SeqSort(Context ctx, long obj) + { + super(ctx, obj); + } +} From 65de39f403bdd36893c98319c31c56bb3348b41a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Jan 2016 08:45:10 -0800 Subject: [PATCH 78/87] disabling mk_const_case_multiplier until debugged Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index 942f97e93..25bc72add 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -171,12 +171,14 @@ void bit_blaster_tpl::mk_multiplier(unsigned sz, expr * const * a_bits, exp return; } +#if 1 if (mk_const_multiplier(sz, a_bits, b_bits, out_bits)) { return; } if (mk_const_multiplier(sz, b_bits, a_bits, out_bits)) { return; } +#endif if (!m_use_wtm) { #if 0 @@ -1217,6 +1219,7 @@ void bit_blaster_tpl::mk_const_case_multiplier(bool is_a, unsigned i, unsig n_a *= n_b; num2bits(n_a, sz, out_bits); } + SASSERT(out_bits.size() == sz); } template @@ -1227,7 +1230,8 @@ bool bit_blaster_tpl::mk_const_multiplier(unsigned sz, expr * const * a_bit } SASSERT(out_bits.empty()); - if (mk_const_case_multiplier(sz, a_bits, b_bits, out_bits)) { + if (false && mk_const_case_multiplier(sz, a_bits, b_bits, out_bits)) { + SASSERT(sz == out_bits.size()); return true; } if (!m_use_bcm) { @@ -1239,7 +1243,7 @@ bool bit_blaster_tpl::mk_const_multiplier(unsigned sz, expr * const * a_bit out_bits.resize(sz, m().mk_false()); #if 1 - bool last=false, now; + bool last = false, now; for (unsigned i = 0; i < sz; i++) { now = m().is_true(a_bits[i]); SASSERT(now || m().is_false(a_bits[i])); @@ -1311,5 +1315,6 @@ bool bit_blaster_tpl::mk_const_multiplier(unsigned sz, expr * const * a_bit TRACE("bit_blaster_tpl_booth", for (unsigned i=0; i Date: Tue, 5 Jan 2016 09:19:21 -0800 Subject: [PATCH 79/87] fix crash caused by recycling variable names. Stackoverflow segfault-in-bv-rewritermk-mul-eq Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_rewriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index c571a5c56..2f1fe3c90 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2064,12 +2064,12 @@ br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) { } } if (m_util.is_numeral(lhs, c_val, sz) && is_add_mul_const(rhs)) { - unsigned sz = to_app(rhs)->get_num_args(); + unsigned num_args = to_app(rhs)->get_num_args(); unsigned i = 0; expr* c2, *x2; numeral c2_val, c2_inv_val; bool found = false; - for (; !found && i < sz; ++i) { + for (; !found && i < num_args; ++i) { expr* arg = to_app(rhs)->get_arg(i); if (m_util.is_bv_mul(arg, c2, x2) && m_util.is_numeral(c2, c2_val, sz) && m_util.mult_inverse(c2_val, sz, c2_inv_val)) { From de3cb7e5dc65c7f2770a4690b60602afb7de1b7c Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Tue, 5 Jan 2016 18:05:21 +0000 Subject: [PATCH 80/87] More FPA exponent/siginficand order consistency --- examples/c/test_capi.c | 414 +++++++++++++++--------------- src/api/api_fpa.cpp | 2 +- src/ast/fpa/fpa2bv_converter.cpp | 8 +- src/ast/fpa_decl_plugin.cpp | 22 +- src/ast/fpa_decl_plugin.h | 4 +- src/ast/rewriter/fpa_rewriter.cpp | 14 + 6 files changed, 246 insertions(+), 218 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 07fc05b21..0c6e2fae4 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -19,7 +19,7 @@ Copyright (c) 2015 Microsoft Corporation #define LOG_MSG(msg) ((void)0) #endif -/** +/** \defgroup capi_ex C API examples */ /*@{*/ @@ -31,7 +31,7 @@ Copyright (c) 2015 Microsoft Corporation /** \brief exit gracefully in case of error. */ -void exitf(const char* message) +void exitf(const char* message) { fprintf(stderr,"BUG: %s.\n", message); exit(1); @@ -40,7 +40,7 @@ void exitf(const char* message) /** \brief exit if unreachable code was reached. */ -void unreachable() +void unreachable() { exitf("unreachable code was reached"); } @@ -48,7 +48,7 @@ void unreachable() /** \brief Simpler error handler. */ -void error_handler(Z3_context c, Z3_error_code e) +void error_handler(Z3_context c, Z3_error_code e) { printf("Error code: %d\n", e); exitf("incorrect use of Z3"); @@ -56,34 +56,34 @@ void error_handler(Z3_context c, Z3_error_code e) static jmp_buf g_catch_buffer; /** - \brief Low tech exceptions. - + \brief Low tech exceptions. + In high-level programming languages, an error handler can throw an exception. */ -void throw_z3_error(Z3_context c, Z3_error_code e) +void throw_z3_error(Z3_context c, Z3_error_code e) { longjmp(g_catch_buffer, e); } /** - \brief Create a logical context. + \brief Create a logical context. Enable model construction. Other configuration parameters can be passed in the cfg variable. Also enable tracing to stderr and register custom error handler. */ -Z3_context mk_context_custom(Z3_config cfg, Z3_error_handler err) +Z3_context mk_context_custom(Z3_config cfg, Z3_error_handler err) { Z3_context ctx; - + Z3_set_param_value(cfg, "model", "true"); ctx = Z3_mk_context(cfg); Z3_set_error_handler(ctx, err); - + return ctx; } -Z3_solver mk_solver(Z3_context ctx) +Z3_solver mk_solver(Z3_context ctx) { Z3_solver s = Z3_mk_solver(ctx); Z3_solver_inc_ref(ctx, s); @@ -102,7 +102,7 @@ void del_solver(Z3_context ctx, Z3_solver s) Also enable tracing to stderr and register standard error handler. */ -Z3_context mk_context() +Z3_context mk_context() { Z3_config cfg; Z3_context ctx; @@ -132,7 +132,7 @@ Z3_context mk_proof_context() { /** \brief Create a variable using the given name and type. */ -Z3_ast mk_var(Z3_context ctx, const char * name, Z3_sort ty) +Z3_ast mk_var(Z3_context ctx, const char * name, Z3_sort ty) { Z3_symbol s = Z3_mk_string_symbol(ctx, name); return Z3_mk_const(ctx, s, ty); @@ -141,7 +141,7 @@ Z3_ast mk_var(Z3_context ctx, const char * name, Z3_sort ty) /** \brief Create a boolean variable using the given name. */ -Z3_ast mk_bool_var(Z3_context ctx, const char * name) +Z3_ast mk_bool_var(Z3_context ctx, const char * name) { Z3_sort ty = Z3_mk_bool_sort(ctx); return mk_var(ctx, name, ty); @@ -150,16 +150,16 @@ Z3_ast mk_bool_var(Z3_context ctx, const char * name) /** \brief Create an integer variable using the given name. */ -Z3_ast mk_int_var(Z3_context ctx, const char * name) +Z3_ast mk_int_var(Z3_context ctx, const char * name) { Z3_sort ty = Z3_mk_int_sort(ctx); return mk_var(ctx, name, ty); } /** - \brief Create a Z3 integer node using a C int. + \brief Create a Z3 integer node using a C int. */ -Z3_ast mk_int(Z3_context ctx, int v) +Z3_ast mk_int(Z3_context ctx, int v) { Z3_sort ty = Z3_mk_int_sort(ctx); return Z3_mk_int(ctx, v, ty); @@ -168,7 +168,7 @@ Z3_ast mk_int(Z3_context ctx, int v) /** \brief Create a real variable using the given name. */ -Z3_ast mk_real_var(Z3_context ctx, const char * name) +Z3_ast mk_real_var(Z3_context ctx, const char * name) { Z3_sort ty = Z3_mk_real_sort(ctx); return mk_var(ctx, name, ty); @@ -177,7 +177,7 @@ Z3_ast mk_real_var(Z3_context ctx, const char * name) /** \brief Create the unary function application: (f x). */ -Z3_ast mk_unary_app(Z3_context ctx, Z3_func_decl f, Z3_ast x) +Z3_ast mk_unary_app(Z3_context ctx, Z3_func_decl f, Z3_ast x) { Z3_ast args[1] = {x}; return Z3_mk_app(ctx, f, 1, args); @@ -186,7 +186,7 @@ Z3_ast mk_unary_app(Z3_context ctx, Z3_func_decl f, Z3_ast x) /** \brief Create the binary function application: (f x y). */ -Z3_ast mk_binary_app(Z3_context ctx, Z3_func_decl f, Z3_ast x, Z3_ast y) +Z3_ast mk_binary_app(Z3_context ctx, Z3_func_decl f, Z3_ast x, Z3_ast y) { Z3_ast args[2] = {x, y}; return Z3_mk_app(ctx, f, 2, args); @@ -205,7 +205,7 @@ void check(Z3_context ctx, Z3_solver s, Z3_lbool expected_result) printf("unsat\n"); break; case Z3_L_UNDEF: - printf("unknown\n"); + printf("unknown\n"); m = Z3_solver_get_model(ctx, s); if (m) Z3_model_inc_ref(ctx, m); printf("potential model:\n%s\n", Z3_model_to_string(ctx, m)); @@ -226,7 +226,7 @@ void check(Z3_context ctx, Z3_solver s, Z3_lbool expected_result) \brief Prove that the constraints already asserted into the logical context implies the given formula. The result of the proof is displayed. - + Z3 is a satisfiability checker. So, one can prove \c f by showing that (not f) is unsatisfiable. @@ -242,7 +242,7 @@ void prove(Z3_context ctx, Z3_solver s, Z3_ast f, Z3_bool is_valid) not_f = Z3_mk_not(ctx, f); Z3_solver_assert(ctx, s, not_f); - + switch (Z3_solver_check(ctx, s)) { case Z3_L_FALSE: /* proved */ @@ -286,7 +286,7 @@ void prove(Z3_context ctx, Z3_solver s, Z3_ast f, Z3_bool is_valid) /** \brief Assert the axiom: function f is injective in the i-th argument. - + The following axiom is asserted into the logical context: \code forall (x_0, ..., x_n) finv(f(x_0, ..., x_i, ..., x_{n-1})) = x_i @@ -294,7 +294,7 @@ void prove(Z3_context ctx, Z3_solver s, Z3_ast f, Z3_bool is_valid) Where, \c finv is a fresh function declaration. */ -void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i) +void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i) { unsigned sz, j; Z3_sort finv_domain, finv_range; @@ -310,7 +310,7 @@ void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i) if (i >= sz) { exitf("failed to create inj axiom"); } - + /* declare the i-th inverse of f: finv */ finv_domain = Z3_get_range(ctx, f); finv_range = Z3_get_domain(ctx, f, i); @@ -320,7 +320,7 @@ void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i) types = (Z3_sort *) malloc(sizeof(Z3_sort) * sz); names = (Z3_symbol *) malloc(sizeof(Z3_symbol) * sz); xs = (Z3_ast *) malloc(sizeof(Z3_ast) * sz); - + /* fill types, names and xs */ for (j = 0; j < sz; j++) { types[j] = Z3_get_domain(ctx, f, j); }; for (j = 0; j < sz; j++) { names[j] = Z3_mk_int_symbol(ctx, j); }; @@ -328,7 +328,7 @@ void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i) x_i = xs[i]; - /* create f(x_0, ..., x_i, ..., x_{n-1}) */ + /* create f(x_0, ..., x_i, ..., x_{n-1}) */ fxs = Z3_mk_app(ctx, f, sz, xs); /* create f_inv(f(x_0, ..., x_i, ..., x_{n-1})) */ @@ -343,12 +343,12 @@ void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i) printf("\n"); /* create & assert quantifier */ - q = Z3_mk_forall(ctx, + q = Z3_mk_forall(ctx, 0, /* using default weight */ 1, /* number of patterns */ &p, /* address of the "array" of patterns */ sz, /* number of quantified variables */ - types, + types, names, eq); printf("assert axiom:\n%s\n", Z3_ast_to_string(ctx, q)); @@ -361,11 +361,11 @@ void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i) } /** - \brief Assert the axiom: function f is commutative. - + \brief Assert the axiom: function f is commutative. + This example uses the SMT-LIB parser to simplify the axiom construction. */ -void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f) +void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f) { Z3_sort t; Z3_symbol f_name, t_name; @@ -377,16 +377,16 @@ void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f) Z3_get_domain(ctx, f, 0) != t || Z3_get_domain(ctx, f, 1) != t) { exitf("function must be binary, and argument types must be equal to return type"); - } - + } + /* Inside the parser, function f will be referenced using the symbol 'f'. */ f_name = Z3_mk_string_symbol(ctx, "f"); - + /* Inside the parser, type t will be referenced using the symbol 'T'. */ t_name = Z3_mk_string_symbol(ctx, "T"); - - Z3_parse_smtlib_string(ctx, + + Z3_parse_smtlib_string(ctx, "(benchmark comm :formula (forall (x T) (y T) (= (f x y) (f y x))))", 1, &t_name, &t, 1, &f_name, &f); @@ -396,15 +396,15 @@ void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f) } /** - \brief Z3 does not support explicitly tuple updates. They can be easily implemented - as macros. The argument \c t must have tuple type. + \brief Z3 does not support explicitly tuple updates. They can be easily implemented + as macros. The argument \c t must have tuple type. A tuple update is a new tuple where field \c i has value \c new_val, and all other fields have the value of the respective field of \c t. update(t, i, new_val) is equivalent to - mk_tuple(proj_0(t), ..., new_val, ..., proj_n(t)) + mk_tuple(proj_0(t), ..., new_val, ..., proj_n(t)) */ -Z3_ast mk_tuple_update(Z3_context c, Z3_ast t, unsigned i, Z3_ast new_val) +Z3_ast mk_tuple_update(Z3_context c, Z3_ast t, unsigned i, Z3_ast new_val) { Z3_sort ty; Z3_func_decl mk_tuple_decl; @@ -419,11 +419,11 @@ Z3_ast mk_tuple_update(Z3_context c, Z3_ast t, unsigned i, Z3_ast new_val) } num_fields = Z3_get_tuple_sort_num_fields(c, ty); - + if (i >= num_fields) { exitf("invalid tuple update, index is too big"); } - + new_fields = (Z3_ast*) malloc(sizeof(Z3_ast) * num_fields); for (j = 0; j < num_fields; j++) { if (i == j) { @@ -445,7 +445,7 @@ Z3_ast mk_tuple_update(Z3_context c, Z3_ast t, unsigned i, Z3_ast new_val) /** \brief Display a symbol in the given output stream. */ -void display_symbol(Z3_context c, FILE * out, Z3_symbol s) +void display_symbol(Z3_context c, FILE * out, Z3_symbol s) { switch (Z3_get_symbol_kind(c, s)) { case Z3_INT_SYMBOL: @@ -462,7 +462,7 @@ void display_symbol(Z3_context c, FILE * out, Z3_symbol s) /** \brief Display the given type. */ -void display_sort(Z3_context c, FILE * out, Z3_sort ty) +void display_sort(Z3_context c, FILE * out, Z3_sort ty) { switch (Z3_get_sort_kind(c, ty)) { case Z3_UNINTERPRETED_SORT: @@ -480,7 +480,7 @@ void display_sort(Z3_context c, FILE * out, Z3_sort ty) case Z3_BV_SORT: fprintf(out, "bv%d", Z3_get_bv_sort_size(c, ty)); break; - case Z3_ARRAY_SORT: + case Z3_ARRAY_SORT: fprintf(out, "["); display_sort(c, out, Z3_get_array_sort_domain(c, ty)); fprintf(out, "->"); @@ -488,7 +488,7 @@ void display_sort(Z3_context c, FILE * out, Z3_sort ty) fprintf(out, "]"); break; case Z3_DATATYPE_SORT: - if (Z3_get_datatype_sort_num_constructors(c, ty) != 1) + if (Z3_get_datatype_sort_num_constructors(c, ty) != 1) { fprintf(out, "%s", Z3_sort_to_string(c,ty)); break; @@ -516,11 +516,11 @@ void display_sort(Z3_context c, FILE * out, Z3_sort ty) } /** - \brief Custom ast pretty printer. + \brief Custom ast pretty printer. This function demonstrates how to use the API to navigate terms. */ -void display_ast(Z3_context c, FILE * out, Z3_ast v) +void display_ast(Z3_context c, FILE * out, Z3_ast v) { switch (Z3_get_ast_kind(c, v)) { case Z3_NUMERAL_AST: { @@ -551,7 +551,7 @@ void display_ast(Z3_context c, FILE * out, Z3_ast v) } case Z3_QUANTIFIER_AST: { fprintf(out, "quantifier"); - ; + ; } default: fprintf(out, "#unknown"); @@ -561,7 +561,7 @@ void display_ast(Z3_context c, FILE * out, Z3_ast v) /** \brief Custom function interpretations pretty printer. */ -void display_function_interpretations(Z3_context c, FILE * out, Z3_model m) +void display_function_interpretations(Z3_context c, FILE * out, Z3_model m) { unsigned num_functions, i; @@ -574,14 +574,14 @@ void display_function_interpretations(Z3_context c, FILE * out, Z3_model m) Z3_ast func_else; unsigned num_entries = 0, j; Z3_func_interp_opt finterp; - + fdecl = Z3_model_get_func_decl(c, m, i); finterp = Z3_model_get_func_interp(c, m, fdecl); Z3_func_interp_inc_ref(c, finterp); name = Z3_get_decl_name(c, fdecl); display_symbol(c, out, name); fprintf(out, " = {"); - if (finterp) + if (finterp) num_entries = Z3_func_interp_get_num_entries(c, finterp); for (j = 0; j < num_entries; j++) { unsigned num_args, k; @@ -617,7 +617,7 @@ void display_function_interpretations(Z3_context c, FILE * out, Z3_model m) /** \brief Custom model pretty printer. */ -void display_model(Z3_context c, FILE * out, Z3_model m) +void display_model(Z3_context c, FILE * out, Z3_model m) { unsigned num_constants; unsigned i; @@ -677,7 +677,7 @@ void check2(Z3_context ctx, Z3_solver s, Z3_lbool expected_result) /** \brief Display Z3 version in the standard output. */ -void display_version() +void display_version() { unsigned major, minor, build, revision; Z3_get_version(&major, &minor, &build, &revision); @@ -692,12 +692,12 @@ void display_version() /** \brief "Hello world" example: create a Z3 logical context, and delete it. */ -void simple_example() +void simple_example() { Z3_context ctx; LOG_MSG("simple_example"); printf("\nsimple_example\n"); - + ctx = mk_context(); /* delete logical context */ @@ -708,7 +708,7 @@ void simple_example() Demonstration of how Z3 can be used to prove validity of De Morgan's Duality Law: {e not(x and y) <-> (not x) or ( not y) } */ -void demorgan() +void demorgan() { Z3_config cfg; Z3_context ctx; @@ -720,7 +720,7 @@ void demorgan() printf("\nDeMorgan\n"); LOG_MSG("DeMorgan"); - + cfg = Z3_mk_config(); ctx = Z3_mk_context(cfg); Z3_del_config(cfg); @@ -729,7 +729,7 @@ void demorgan() symbol_y = Z3_mk_int_symbol(ctx, 1); x = Z3_mk_const(ctx, symbol_x, bool_sort); y = Z3_mk_const(ctx, symbol_y, bool_sort); - + /* De Morgan - with a negation around */ /* !(!(x && y) <-> (!x || !y)) */ not_x = Z3_mk_not(ctx, x); @@ -743,8 +743,8 @@ void demorgan() rs = Z3_mk_or(ctx, 2, args); conjecture = Z3_mk_iff(ctx, ls, rs); negated_conjecture = Z3_mk_not(ctx, conjecture); - - s = mk_solver(ctx); + + s = mk_solver(ctx); Z3_solver_assert(ctx, s, negated_conjecture); switch (Z3_solver_check(ctx, s)) { case Z3_L_FALSE: @@ -767,7 +767,7 @@ void demorgan() /** \brief Find a model for x xor y. */ -void find_model_example1() +void find_model_example1() { Z3_context ctx; Z3_ast x, y, x_xor_y; @@ -782,7 +782,7 @@ void find_model_example1() x = mk_bool_var(ctx, "x"); y = mk_bool_var(ctx, "y"); x_xor_y = Z3_mk_xor(ctx, x, y); - + Z3_solver_assert(ctx, s, x_xor_y); printf("model for: x xor y\n"); @@ -796,7 +796,7 @@ void find_model_example1() \brief Find a model for x < y + 1, x > 2. Then, assert not(x = y), and find another model. */ -void find_model_example2() +void find_model_example2() { Z3_context ctx; Z3_ast x, y, one, two, y_plus_one; @@ -807,7 +807,7 @@ void find_model_example2() printf("\nfind_model_example2\n"); LOG_MSG("find_model_example2"); - + ctx = mk_context(); s = mk_solver(ctx); x = mk_int_var(ctx, "x"); @@ -821,7 +821,7 @@ void find_model_example2() c1 = Z3_mk_lt(ctx, x, y_plus_one); c2 = Z3_mk_gt(ctx, x, two); - + Z3_solver_assert(ctx, s, c1); Z3_solver_assert(ctx, s, c2); @@ -847,7 +847,7 @@ void find_model_example2() This function demonstrates how to create uninterpreted types and functions. */ -void prove_example1() +void prove_example1() { Z3_context ctx; Z3_solver s; @@ -860,14 +860,14 @@ void prove_example1() printf("\nprove_example1\n"); LOG_MSG("prove_example1"); - + ctx = mk_context(); s = mk_solver(ctx); /* create uninterpreted type. */ U_name = Z3_mk_string_symbol(ctx, "U"); U = Z3_mk_uninterpreted_sort(ctx, U_name); - + /* declare function g */ g_name = Z3_mk_string_symbol(ctx, "g"); g_domain[0] = U; @@ -881,7 +881,7 @@ void prove_example1() /* create g(x), g(y) */ gx = mk_unary_app(ctx, g, x); gy = mk_unary_app(ctx, g, y); - + /* assert x = y */ eq = Z3_mk_eq(ctx, x, y); Z3_solver_assert(ctx, s, eq); @@ -893,7 +893,7 @@ void prove_example1() /* create g(g(x)) */ ggx = mk_unary_app(ctx, g, gx); - + /* disprove g(g(x)) = g(y) */ f = Z3_mk_eq(ctx, ggx, gy); printf("disprove: x = y implies g(g(x)) = g(y)\n"); @@ -909,7 +909,7 @@ void prove_example1() This example demonstrates how to combine uninterpreted functions and arithmetic. */ -void prove_example2() +void prove_example2() { Z3_context ctx; Z3_solver s; @@ -923,7 +923,7 @@ void prove_example2() printf("\nprove_example2\n"); LOG_MSG("prove_example2"); - + ctx = mk_context(); s = mk_solver(ctx); @@ -932,7 +932,7 @@ void prove_example2() g_name = Z3_mk_string_symbol(ctx, "g"); g_domain[0] = int_sort; g = Z3_mk_func_decl(ctx, g_name, 1, g_domain, int_sort); - + /* create x, y, and z */ x = mk_int_var(ctx, "x"); y = mk_int_var(ctx, "y"); @@ -942,7 +942,7 @@ void prove_example2() gx = mk_unary_app(ctx, g, x); gy = mk_unary_app(ctx, g, y); gz = mk_unary_app(ctx, g, z); - + /* create zero */ zero = mk_int(ctx, 0); @@ -987,7 +987,7 @@ void prove_example2() This example also demonstrates how big numbers can be created in Z3. */ -void push_pop_example1() +void push_pop_example1() { Z3_context ctx; Z3_solver s; @@ -1005,7 +1005,7 @@ void push_pop_example1() /* create a big number */ int_sort = Z3_mk_int_sort(ctx); big_number = Z3_mk_numeral(ctx, "1000000000000000000000000000000000000000000000000000000", int_sort); - + /* create number 3 */ three = Z3_mk_numeral(ctx, "3", int_sort); @@ -1044,7 +1044,7 @@ void push_pop_example1() check2(ctx, s, Z3_L_TRUE); /* new constraints can be asserted... */ - + /* create y */ y_sym = Z3_mk_string_symbol(ctx, "y"); y = Z3_mk_const(ctx, y_sym, int_sort); @@ -1056,18 +1056,18 @@ void push_pop_example1() /* the context is still consistent. */ check2(ctx, s, Z3_L_TRUE); - + del_solver(ctx, s); Z3_del_context(ctx); } /** - \brief Prove that f(x, y) = f(w, v) implies y = v when + \brief Prove that f(x, y) = f(w, v) implies y = v when \c f is injective in the second argument. \sa assert_inj_axiom. */ -void quantifier_example1() +void quantifier_example1() { Z3_config cfg; Z3_context ctx; @@ -1102,10 +1102,10 @@ void quantifier_example1() f_domain[0] = int_sort; f_domain[1] = int_sort; f = Z3_mk_func_decl(ctx, f_name, 2, f_domain, int_sort); - + /* assert that f is injective in the second argument. */ assert_inj_axiom(ctx, s, f, 1); - + /* create x, y, v, w, fxy, fwv */ x = mk_int_var(ctx, "x"); y = mk_int_var(ctx, "y"); @@ -1113,7 +1113,7 @@ void quantifier_example1() w = mk_int_var(ctx, "w"); fxy = mk_binary_app(ctx, f, x, y); fwv = mk_binary_app(ctx, f, w, v); - + /* assert f(x, y) = f(w, v) */ p1 = Z3_mk_eq(ctx, fxy, fwv); Z3_solver_assert(ctx, s, p1); @@ -1135,15 +1135,15 @@ void quantifier_example1() del_solver(ctx, s); Z3_del_context(ctx); /* reset global parameters set by this function */ - Z3_global_param_reset_all(); + Z3_global_param_reset_all(); } /** \brief Prove store(a1, i1, v1) = store(a2, i2, v2) implies (i1 = i3 or i2 = i3 or select(a1, i3) = select(a2, i3)). - + This example demonstrates how to use the array theory. */ -void array_example1() +void array_example1() { Z3_context ctx = mk_context(); Z3_solver s = mk_solver(ctx); @@ -1168,10 +1168,10 @@ void array_example1() i3 = mk_var(ctx, "i3", int_sort); v1 = mk_var(ctx, "v1", int_sort); v2 = mk_var(ctx, "v2", int_sort); - + st1 = Z3_mk_store(ctx, a1, i1, v1); st2 = Z3_mk_store(ctx, a2, i2, v2); - + sel1 = Z3_mk_select(ctx, a1, i3); sel2 = Z3_mk_select(ctx, a2, i3); @@ -1201,7 +1201,7 @@ void array_example1() This example also shows how to use the \c distinct construct. */ -void array_example2() +void array_example2() { Z3_context ctx; Z3_solver s; @@ -1217,16 +1217,16 @@ void array_example2() printf("n = %d\n", n); ctx = mk_context(); s = mk_solver(ctx); - + bool_sort = Z3_mk_bool_sort(ctx); array_sort = Z3_mk_array_sort(ctx, bool_sort, bool_sort); - + /* create arrays */ for (i = 0; i < n; i++) { Z3_symbol s = Z3_mk_int_symbol(ctx, i); a[i] = Z3_mk_const(ctx, s, array_sort); } - + /* assert distinct(a[0], ..., a[n]) */ d = Z3_mk_distinct(ctx, n, a); printf("%s\n", Z3_ast_to_string(ctx, d)); @@ -1234,7 +1234,7 @@ void array_example2() /* context is satisfiable if n < 5 */ check2(ctx, s, n < 5 ? Z3_L_TRUE : Z3_L_FALSE); - + del_solver(ctx, s); Z3_del_context(ctx); } @@ -1243,7 +1243,7 @@ void array_example2() /** \brief Simple array type construction/deconstruction example. */ -void array_example3() +void array_example3() { Z3_context ctx = mk_context(); Z3_solver s = mk_solver(ctx); @@ -1254,13 +1254,13 @@ void array_example3() bool_sort = Z3_mk_bool_sort(ctx); - int_sort = Z3_mk_int_sort(ctx); + int_sort = Z3_mk_int_sort(ctx); array_sort = Z3_mk_array_sort(ctx, int_sort, bool_sort); if (Z3_get_sort_kind(ctx, array_sort) != Z3_ARRAY_SORT) { exitf("type must be an array type"); } - + domain = Z3_get_array_sort_domain(ctx, array_sort); range = Z3_get_array_sort_range(ctx, array_sort); @@ -1282,21 +1282,21 @@ void array_example3() /** \brief Simple tuple type example. It creates a tuple that is a pair of real numbers. */ -void tuple_example1() +void tuple_example1() { Z3_context ctx = mk_context(); Z3_solver s = mk_solver(ctx); Z3_sort real_sort, pair_sort; Z3_symbol mk_tuple_name; Z3_func_decl mk_tuple_decl; - Z3_symbol proj_names[2]; - Z3_sort proj_sorts[2]; + Z3_symbol proj_names[2]; + Z3_sort proj_sorts[2]; Z3_func_decl proj_decls[2]; Z3_func_decl get_x_decl, get_y_decl; printf("\ntuple_example1\n"); LOG_MSG("tuple_example1"); - + real_sort = Z3_mk_real_sort(ctx); @@ -1310,7 +1310,7 @@ void tuple_example1() pair_sort = Z3_mk_tuple_sort(ctx, mk_tuple_name, 2, proj_names, proj_sorts, &mk_tuple_decl, proj_decls); get_x_decl = proj_decls[0]; /* function that extracts the first element of a tuple. */ get_y_decl = proj_decls[1]; /* function that extracts the second element of a tuple. */ - + printf("tuple_sort: "); display_sort(ctx, stdout, pair_sort); printf("\n"); @@ -1319,11 +1319,11 @@ void tuple_example1() /* prove that get_x(mk_pair(x,y)) == 1 implies x = 1*/ Z3_ast app1, app2, x, y, one; Z3_ast eq1, eq2, eq3, thm; - + x = mk_real_var(ctx, "x"); y = mk_real_var(ctx, "y"); app1 = mk_binary_app(ctx, mk_tuple_decl, x, y); - app2 = mk_unary_app(ctx, get_x_decl, app1); + app2 = mk_unary_app(ctx, get_x_decl, app1); one = Z3_mk_numeral(ctx, "1", real_sort); eq1 = Z3_mk_eq(ctx, app2, one); eq2 = Z3_mk_eq(ctx, x, one); @@ -1343,7 +1343,7 @@ void tuple_example1() Z3_ast p1, p2, x1, x2, y1, y2; Z3_ast antecedents[2]; Z3_ast antecedent, consequent, thm; - + p1 = mk_var(ctx, "p1", pair_sort); p2 = mk_var(ctx, "p2", pair_sort); x1 = mk_unary_app(ctx, get_x_decl, p1); @@ -1397,7 +1397,7 @@ void tuple_example1() /** \brief Simple bit-vector example. This example disproves that x - 10 <= 0 IFF x <= 10 for (32-bit) machine integers */ -void bitvector_example1() +void bitvector_example1() { Z3_context ctx = mk_context(); Z3_solver s = mk_solver(ctx); @@ -1406,10 +1406,10 @@ void bitvector_example1() printf("\nbitvector_example1\n"); LOG_MSG("bitvector_example1"); - - + + bv_sort = Z3_mk_bv_sort(ctx, 32); - + x = mk_var(ctx, "x", bv_sort); zero = Z3_mk_numeral(ctx, "0", bv_sort); ten = Z3_mk_numeral(ctx, "10", bv_sort); @@ -1420,7 +1420,7 @@ void bitvector_example1() thm = Z3_mk_iff(ctx, c1, c2); printf("disprove: x - 10 <= 0 IFF x <= 10 for (32-bit) machine integers\n"); prove(ctx, s, thm, Z3_FALSE); - + del_solver(ctx, s); Z3_del_context(ctx); } @@ -1432,7 +1432,7 @@ void bitvector_example2() { Z3_context ctx = mk_context(); Z3_solver s = mk_solver(ctx); - + /* construct x ^ y - 103 == x * y */ Z3_sort bv_sort = Z3_mk_bv_sort(ctx, 32); Z3_ast x = mk_var(ctx, "x", bv_sort); @@ -1446,13 +1446,13 @@ void bitvector_example2() printf("\nbitvector_example2\n"); LOG_MSG("bitvector_example2"); printf("find values of x and y, such that x ^ y - 103 == x * y\n"); - + /* add the constraint x ^ y - 103 == x * y<\tt> to the logical context */ Z3_solver_assert(ctx, s, ctr); - + /* find a model (i.e., values for x an y that satisfy the constraint */ check(ctx, s, Z3_L_TRUE); - + del_solver(ctx, s); Z3_del_context(ctx); } @@ -1460,7 +1460,7 @@ void bitvector_example2() /** \brief Demonstrate how to use #Z3_eval. */ -void eval_example1() +void eval_example1() { Z3_context ctx = mk_context(); Z3_solver s = mk_solver(ctx); @@ -1470,11 +1470,11 @@ void eval_example1() printf("\neval_example1\n"); LOG_MSG("eval_example1"); - + x = mk_int_var(ctx, "x"); y = mk_int_var(ctx, "y"); two = mk_int(ctx, 2); - + /* assert x < y */ c1 = Z3_mk_lt(ctx, x, y); Z3_solver_assert(ctx, s, c1); @@ -1514,7 +1514,7 @@ void eval_example1() /** \brief Several logical context can be used simultaneously. */ -void two_contexts_example1() +void two_contexts_example1() { Z3_context ctx1, ctx2; Z3_ast x1, x2; @@ -1525,22 +1525,22 @@ void two_contexts_example1() /* using the same (default) configuration to initialized both logical contexts. */ ctx1 = mk_context(); ctx2 = mk_context(); - + x1 = Z3_mk_const(ctx1, Z3_mk_int_symbol(ctx1,0), Z3_mk_bool_sort(ctx1)); x2 = Z3_mk_const(ctx2, Z3_mk_int_symbol(ctx2,0), Z3_mk_bool_sort(ctx2)); Z3_del_context(ctx1); - + /* ctx2 can still be used. */ printf("%s\n", Z3_ast_to_string(ctx2, x2)); - + Z3_del_context(ctx2); } /** \brief Demonstrates how error codes can be read insted of registering an error handler. */ -void error_code_example1() +void error_code_example1() { Z3_config cfg; Z3_context ctx; @@ -1563,7 +1563,7 @@ void error_code_example1() x = mk_bool_var(ctx, "x"); x_decl = Z3_get_app_decl(ctx, Z3_to_app(ctx, x)); Z3_solver_assert(ctx, s, x); - + if (Z3_solver_check(ctx, s) != Z3_L_TRUE) { exitf("unexpected result"); } @@ -1596,19 +1596,19 @@ void error_code_example2() { printf("\nerror_code_example2\n"); LOG_MSG("error_code_example2"); - + /* low tech try&catch */ r = setjmp(g_catch_buffer); if (r == 0) { Z3_ast x, y, app; - + cfg = Z3_mk_config(); ctx = mk_context_custom(cfg, throw_z3_error); Z3_del_config(cfg); - + x = mk_int_var(ctx, "x"); y = mk_bool_var(ctx, "y"); - printf("before Z3_mk_iff\n"); + printf("before Z3_mk_iff\n"); /* the next call will produce an error */ app = Z3_mk_iff(ctx, x, y); unreachable(); @@ -1625,7 +1625,7 @@ void error_code_example2() { /** \brief Demonstrates how to use the SMTLIB parser. */ -void parser_example1() +void parser_example1() { Z3_context ctx = mk_context(); Z3_solver s = mk_solver(ctx); @@ -1633,9 +1633,9 @@ void parser_example1() printf("\nparser_example1\n"); LOG_MSG("parser_example1"); - - - Z3_parse_smtlib_string(ctx, + + + Z3_parse_smtlib_string(ctx, "(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))", 0, 0, 0, 0, 0, 0); @@ -1645,7 +1645,7 @@ void parser_example1() printf("formula %d: %s\n", i, Z3_ast_to_string(ctx, f)); Z3_solver_assert(ctx, s, f); } - + check(ctx, s, Z3_L_TRUE); del_solver(ctx, s); @@ -1655,7 +1655,7 @@ void parser_example1() /** \brief Demonstrates how to initialize the parser symbol table. */ -void parser_example2() +void parser_example2() { Z3_context ctx = mk_context(); Z3_solver s = mk_solver(ctx); @@ -1671,16 +1671,16 @@ void parser_example2() /* Z3_enable_arithmetic doesn't need to be invoked in this example because it will be implicitly invoked by mk_int_var. */ - + x = mk_int_var(ctx, "x"); decls[0] = Z3_get_app_decl(ctx, Z3_to_app(ctx, x)); y = mk_int_var(ctx, "y"); decls[1] = Z3_get_app_decl(ctx, Z3_to_app(ctx, y)); - + names[0] = Z3_mk_string_symbol(ctx, "a"); names[1] = Z3_mk_string_symbol(ctx, "b"); - - Z3_parse_smtlib_string(ctx, + + Z3_parse_smtlib_string(ctx, "(benchmark tst :formula (> a b))", 0, 0, 0, /* 'x' and 'y' declarations are inserted as 'a' and 'b' into the parser symbol table. */ @@ -1697,7 +1697,7 @@ void parser_example2() /** \brief Demonstrates how to initialize the parser symbol table. */ -void parser_example3() +void parser_example3() { Z3_config cfg; Z3_context ctx; @@ -1724,10 +1724,10 @@ void parser_example3() g_domain[0] = int_sort; g_domain[1] = int_sort; g = Z3_mk_func_decl(ctx, g_name, 2, g_domain, int_sort); - + assert_comm_axiom(ctx, s, g); - Z3_parse_smtlib_string(ctx, + Z3_parse_smtlib_string(ctx, "(benchmark tst :formula (forall (x Int) (y Int) (implies (= x y) (= (g x 0) (g 0 y)))))", 0, 0, 0, 1, &g_name, &g); @@ -1742,17 +1742,17 @@ void parser_example3() /** \brief Display the declarations, assumptions and formulas in a SMT-LIB string. */ -void parser_example4() +void parser_example4() { Z3_context ctx; unsigned i, num_decls, num_assumptions, num_formulas; printf("\nparser_example4\n"); LOG_MSG("parser_example4"); - + ctx = mk_context(); - - Z3_parse_smtlib_string(ctx, + + Z3_parse_smtlib_string(ctx, "(benchmark tst :extrafuns ((x Int) (y Int)) :assumption (= x 20) :formula (> x y) :formula (> x 0))", 0, 0, 0, 0, 0, 0); @@ -1792,8 +1792,8 @@ void parser_example5() { ctx = mk_context_custom(cfg, throw_z3_error); s = mk_solver(ctx); Z3_del_config(cfg); - - Z3_parse_smtlib_string(ctx, + + Z3_parse_smtlib_string(ctx, /* the following string has a parsing error: missing parenthesis */ "(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))", 0, 0, 0, @@ -1822,7 +1822,7 @@ void numeral_example() { Z3_sort real_ty; printf("\nnumeral_example\n"); LOG_MSG("numeral_example"); - + ctx = mk_context(); s = mk_solver(ctx); @@ -1841,25 +1841,25 @@ void numeral_example() { del_solver(ctx, s); Z3_del_context(ctx); } - + /** \brief Test ite-term (if-then-else terms). */ -void ite_example() +void ite_example() { Z3_context ctx; Z3_ast f, one, zero, ite; - + printf("\nite_example\n"); LOG_MSG("ite_example"); ctx = mk_context(); - + f = Z3_mk_false(ctx); one = mk_int(ctx, 1); zero = mk_int(ctx, 0); ite = Z3_mk_ite(ctx, f, one, zero); - + printf("term: %s\n", Z3_ast_to_string(ctx, ite)); /* delete logical context */ @@ -1879,7 +1879,7 @@ void enum_example() { Z3_func_decl enum_testers[3]; Z3_ast apple, orange, banana, fruity; Z3_ast ors[3]; - + printf("\nenum_example\n"); LOG_MSG("enum_example"); @@ -1888,7 +1888,7 @@ void enum_example() { enum_names[2] = Z3_mk_string_symbol(ctx,"orange"); fruit = Z3_mk_enumeration_sort(ctx, name, 3, enum_names, enum_consts, enum_testers); - + printf("%s\n", Z3_func_decl_to_string(ctx, enum_consts[0])); printf("%s\n", Z3_func_decl_to_string(ctx, enum_consts[1])); printf("%s\n", Z3_func_decl_to_string(ctx, enum_consts[2])); @@ -1935,7 +1935,7 @@ void list_example() { Z3_func_decl nil_decl, is_nil_decl, cons_decl, is_cons_decl, head_decl, tail_decl; Z3_ast nil, l1, l2, x, y, u, v, fml, fml1; Z3_ast ors[2]; - + printf("\nlist_example\n"); LOG_MSG("list_example"); @@ -1944,7 +1944,7 @@ void list_example() { int_list = Z3_mk_list_sort(ctx, Z3_mk_string_symbol(ctx, "int_list"), int_ty, &nil_decl, &is_nil_decl, &cons_decl, &is_cons_decl, &head_decl, &tail_decl); - + nil = Z3_mk_app(ctx, nil_decl, 0, 0); l1 = mk_binary_app(ctx, cons_decl, mk_int(ctx, 1), nil); l2 = mk_binary_app(ctx, cons_decl, mk_int(ctx, 2), nil); @@ -1957,14 +1957,14 @@ void list_example() { /* cons(x,nil) = cons(y, nil) => x = y */ x = mk_var(ctx, "x", int_ty); - y = mk_var(ctx, "y", int_ty); + y = mk_var(ctx, "y", int_ty); l1 = mk_binary_app(ctx, cons_decl, x, nil); l2 = mk_binary_app(ctx, cons_decl, y, nil); prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, x, y)), Z3_TRUE); /* cons(x,u) = cons(x, v) => u = v */ u = mk_var(ctx, "u", int_list); - v = mk_var(ctx, "v", int_list); + v = mk_var(ctx, "v", int_list); l1 = mk_binary_app(ctx, cons_decl, x, u); l2 = mk_binary_app(ctx, cons_decl, y, v); prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, u, v)), Z3_TRUE); @@ -1975,7 +1975,7 @@ void list_example() { ors[1] = Z3_mk_app(ctx, is_cons_decl, 1, &u); prove(ctx, s, Z3_mk_or(ctx, 2, ors), Z3_TRUE); - /* occurs check u != cons(x,u) */ + /* occurs check u != cons(x,u) */ prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), Z3_TRUE); /* destructors: is_cons(u) => u = cons(head(u),tail(u)) */ @@ -1993,7 +1993,7 @@ void list_example() { /** \brief Create a binary tree datatype. -*/ +*/ void tree_example() { Z3_context ctx = mk_context(); Z3_solver s = mk_solver(ctx); @@ -2015,7 +2015,7 @@ void tree_example() { cons_con = Z3_mk_constructor(ctx, Z3_mk_string_symbol(ctx, "cons"), Z3_mk_string_symbol(ctx, "is_cons"), 2, head_tail, sorts, sort_refs); constructors[0] = nil_con; constructors[1] = cons_con; - + cell = Z3_mk_datatype(ctx, Z3_mk_string_symbol(ctx, "cell"), 2, constructors); Z3_query_constructor(ctx, nil_con, 0, &nil_decl, &is_nil_decl, 0); @@ -2036,9 +2036,9 @@ void tree_example() { /* cons(x,u) = cons(x, v) => u = v */ u = mk_var(ctx, "u", cell); - v = mk_var(ctx, "v", cell); + v = mk_var(ctx, "v", cell); x = mk_var(ctx, "x", cell); - y = mk_var(ctx, "y", cell); + y = mk_var(ctx, "y", cell); l1 = mk_binary_app(ctx, cons_decl, x, u); l2 = mk_binary_app(ctx, cons_decl, y, v); prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, u, v)), Z3_TRUE); @@ -2049,7 +2049,7 @@ void tree_example() { ors[1] = Z3_mk_app(ctx, is_cons_decl, 1, &u); prove(ctx, s, Z3_mk_or(ctx, 2, ors), Z3_TRUE); - /* occurs check u != cons(x,u) */ + /* occurs check u != cons(x,u) */ prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), Z3_TRUE); /* destructors: is_cons(u) => u = cons(car(u),cdr(u)) */ @@ -2072,7 +2072,7 @@ void tree_example() { forest ::= nil | cons(tree, forest) tree ::= nil | cons(forest, forest) -*/ +*/ void forest_example() { Z3_context ctx = mk_context(); @@ -2110,7 +2110,7 @@ void forest_example() { cons2_con = Z3_mk_constructor(ctx, Z3_mk_string_symbol(ctx, "cons2"), Z3_mk_string_symbol(ctx, "is_cons2"),2, head_tail, sorts, sort_refs); constructors2[0] = nil2_con; constructors2[1] = cons2_con; - + clist1 = Z3_mk_constructor_list(ctx, 2, constructors1); clist2 = Z3_mk_constructor_list(ctx, 2, constructors2); @@ -2130,7 +2130,7 @@ void forest_example() { Z3_query_constructor(ctx, cons2_con, 2, &cons2_decl, &is_cons2_decl, cons_accessors); car2_decl = cons_accessors[0]; cdr2_decl = cons_accessors[1]; - + Z3_del_constructor_list(ctx, clist1); Z3_del_constructor_list(ctx, clist2); Z3_del_constructor(ctx,nil1_con); @@ -2156,7 +2156,7 @@ void forest_example() { /* cons(x,u) = cons(x, v) => u = v */ u = mk_var(ctx, "u", forest); - v = mk_var(ctx, "v", forest); + v = mk_var(ctx, "v", forest); x = mk_var(ctx, "x", tree); y = mk_var(ctx, "y", tree); l1 = mk_binary_app(ctx, cons1_decl, x, u); @@ -2169,7 +2169,7 @@ void forest_example() { ors[1] = Z3_mk_app(ctx, is_cons1_decl, 1, &u); prove(ctx, s, Z3_mk_or(ctx, 2, ors), Z3_TRUE); - /* occurs check u != cons(x,u) */ + /* occurs check u != cons(x,u) */ prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), Z3_TRUE); /* delete logical context */ @@ -2181,14 +2181,14 @@ void forest_example() { /** \brief Create a binary tree datatype of the form - BinTree ::= nil + BinTree ::= nil | node(value : Int, left : BinTree, right : BinTree) -*/ +*/ void binary_tree_example() { Z3_context ctx = mk_context(); Z3_solver s = mk_solver(ctx); Z3_sort cell; - Z3_func_decl + Z3_func_decl nil_decl, /* nil : BinTree (constructor) */ is_nil_decl, /* is_nil : BinTree -> Bool (tester, return true if the given BinTree is a nil) */ node_decl, /* node : Int, BinTree, BinTree -> BinTree (constructor) */ @@ -2208,15 +2208,15 @@ void binary_tree_example() { /* nil_con and node_con are auxiliary datastructures used to create the new recursive datatype BinTree */ nil_con = Z3_mk_constructor(ctx, Z3_mk_string_symbol(ctx, "nil"), Z3_mk_string_symbol(ctx, "is-nil"), 0, 0, 0, 0); - node_con = Z3_mk_constructor(ctx, Z3_mk_string_symbol(ctx, "node"), Z3_mk_string_symbol(ctx, "is-cons"), + node_con = Z3_mk_constructor(ctx, Z3_mk_string_symbol(ctx, "node"), Z3_mk_string_symbol(ctx, "is-cons"), 3, node_accessor_names, node_accessor_sorts, node_accessor_sort_refs); constructors[0] = nil_con; constructors[1] = node_con; - + /* create the new recursive datatype */ cell = Z3_mk_datatype(ctx, Z3_mk_string_symbol(ctx, "BinTree"), 2, constructors); - /* retrieve the new declarations: constructors (nil_decl, node_decl), testers (is_nil_decl, is_cons_del), and + /* retrieve the new declarations: constructors (nil_decl, node_decl), testers (is_nil_decl, is_cons_del), and accessors (value_decl, left_decl, right_decl */ Z3_query_constructor(ctx, nil_con, 0, &nil_decl, &is_nil_decl, 0); Z3_query_constructor(ctx, node_con, 3, &node_decl, &is_node_decl, node_accessors); @@ -2267,7 +2267,7 @@ void binary_tree_example() { \brief Prove a theorem and extract, and print the proof. This example illustrates the use of #Z3_check_assumptions. -*/ +*/ void unsat_core_and_proof_example() { Z3_context ctx = mk_proof_context(); Z3_solver s = mk_solver(ctx); @@ -2290,7 +2290,7 @@ void unsat_core_and_proof_example() { Z3_ast g1[2] = { f1, p1 }; Z3_ast g2[2] = { f2, p2 }; Z3_ast g3[2] = { f3, p3 }; - Z3_ast g4[2] = { f4, p4 }; + Z3_ast g4[2] = { f4, p4 }; Z3_lbool result; Z3_ast proof; Z3_model m = 0; @@ -2299,7 +2299,7 @@ void unsat_core_and_proof_example() { printf("\nunsat_core_and_proof_example\n"); LOG_MSG("unsat_core_and_proof_example"); - + Z3_solver_assert(ctx, s, Z3_mk_or(ctx, 2, g1)); Z3_solver_assert(ctx, s, Z3_mk_or(ctx, 2, g2)); Z3_solver_assert(ctx, s, Z3_mk_or(ctx, 2, g3)); @@ -2381,7 +2381,7 @@ void del_ext_context(Z3_ext_context ctx) { /** \brief Create a retractable constraint. - + \return An id that can be used to retract/reassert the constraint. */ unsigned assert_retractable_cnstr(Z3_ext_context ctx, Z3_ast c) { @@ -2488,7 +2488,7 @@ void incremental_example1() { z = mk_int_var(ctx, "z"); two = mk_int(ctx, 2); one = mk_int(ctx, 1); - + /* assert x < y */ c1 = assert_retractable_cnstr(ext_ctx, Z3_mk_lt(ctx, x, y)); /* assert x = z */ @@ -2497,8 +2497,8 @@ void incremental_example1() { c3 = assert_retractable_cnstr(ext_ctx, Z3_mk_gt(ctx, x, two)); /* assert y < 1 */ c4 = assert_retractable_cnstr(ext_ctx, Z3_mk_lt(ctx, y, one)); - - result = ext_check(ext_ctx); + + result = ext_check(ext_ctx); if (result != Z3_L_FALSE) exitf("bug in Z3"); printf("unsat\n"); @@ -2550,7 +2550,7 @@ void reference_counter_example() { // Create a Z3 context where the user is reponsible for managing // Z3_ast reference counters. ctx = Z3_mk_context_rc(cfg); - Z3_del_config(cfg); + Z3_del_config(cfg); s = mk_solver(ctx); Z3_solver_inc_ref(ctx, s); @@ -2564,16 +2564,16 @@ void reference_counter_example() { y = Z3_mk_const(ctx, sy, ty); Z3_inc_ref(ctx, y); // ty is not needed anymore. - Z3_dec_ref(ctx, Z3_sort_to_ast(ctx, ty)); + Z3_dec_ref(ctx, Z3_sort_to_ast(ctx, ty)); x_xor_y = Z3_mk_xor(ctx, x, y); Z3_inc_ref(ctx, x_xor_y); // x and y are not needed anymore. - Z3_dec_ref(ctx, x); + Z3_dec_ref(ctx, x); Z3_dec_ref(ctx, y); Z3_solver_assert(ctx, s, x_xor_y); // x_or_y is not needed anymore. - Z3_dec_ref(ctx, x_xor_y); - + Z3_dec_ref(ctx, x_xor_y); + printf("model for: x xor y\n"); check(ctx, s, Z3_L_TRUE); @@ -2619,12 +2619,12 @@ void substitute_example() { int_ty = Z3_mk_int_sort(ctx); a = mk_int_var(ctx,"a"); b = mk_int_var(ctx,"b"); - { + { Z3_sort f_domain[2] = { int_ty, int_ty }; f = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "f"), 2, f_domain, int_ty); } g = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "g"), 1, &int_ty, int_ty); - { + { Z3_ast args[2] = { a, b }; fab = Z3_mk_app(ctx, f, 2, args); } @@ -2665,12 +2665,12 @@ void substitute_vars_example() { int_ty = Z3_mk_int_sort(ctx); x0 = Z3_mk_bound(ctx, 0, int_ty); x1 = Z3_mk_bound(ctx, 1, int_ty); - { + { Z3_sort f_domain[2] = { int_ty, int_ty }; f = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "f"), 2, f_domain, int_ty); } g = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "g"), 1, &int_ty, int_ty); - { + { Z3_ast args[2] = { x0, x1 }; f01 = Z3_mk_app(ctx, f, 2, args); } @@ -2706,7 +2706,7 @@ void fpa_example() { printf("\nFPA-example\n"); LOG_MSG("FPA-example"); - + cfg = Z3_mk_config(); ctx = Z3_mk_context(cfg); s = mk_solver(ctx); @@ -2715,7 +2715,7 @@ void fpa_example() { double_sort = Z3_mk_fpa_sort(ctx, 11, 53); rm_sort = Z3_mk_fpa_rounding_mode_sort(ctx); - // Show that there are x, y s.t. (x + y) = 42.0 (with rounding mode). + // Show that there are x, y s.t. (x + y) = 42.0 (with rounding mode). s_rm = Z3_mk_string_symbol(ctx, "rm"); rm = Z3_mk_const(ctx, s_rm, rm_sort); s_x = Z3_mk_string_symbol(ctx, "x"); @@ -2742,33 +2742,33 @@ void fpa_example() { args3[0] = c3; args3[1] = Z3_mk_and(ctx, 3, and_args); c4 = Z3_mk_and(ctx, 2, (Z3_ast*)&args3); - + printf("c4: %s\n", Z3_ast_to_string(ctx, c4)); - Z3_solver_push(ctx, s); + Z3_solver_push(ctx, s); Z3_solver_assert(ctx, s, c4); check(ctx, s, Z3_L_TRUE); Z3_solver_pop(ctx, s, 1); // Show that the following are equal: - // (fp #b0 #b10000000001 #xc000000000000) + // (fp #b0 #b10000000001 #xc000000000000) // ((_ to_fp 11 53) #x401c000000000000)) // ((_ to_fp 11 53) RTZ 1.75 2))) // ((_ to_fp 11 53) RTZ 7.0))) - + Z3_solver_push(ctx, s); - c1 = Z3_mk_fpa_fp(ctx, + c1 = Z3_mk_fpa_fp(ctx, Z3_mk_numeral(ctx, "0", Z3_mk_bv_sort(ctx, 1)), - Z3_mk_numeral(ctx, "3377699720527872", Z3_mk_bv_sort(ctx, 52)), - Z3_mk_numeral(ctx, "1025", Z3_mk_bv_sort(ctx, 11))); + Z3_mk_numeral(ctx, "1025", Z3_mk_bv_sort(ctx, 11)), + Z3_mk_numeral(ctx, "3377699720527872", Z3_mk_bv_sort(ctx, 52))); c2 = Z3_mk_fpa_to_fp_bv(ctx, Z3_mk_numeral(ctx, "4619567317775286272", Z3_mk_bv_sort(ctx, 64)), Z3_mk_fpa_sort(ctx, 11, 53)); - c3 = Z3_mk_fpa_to_fp_int_real(ctx, + c3 = Z3_mk_fpa_to_fp_int_real(ctx, Z3_mk_fpa_rtz(ctx), - Z3_mk_numeral(ctx, "2", Z3_mk_int_sort(ctx)), - Z3_mk_numeral(ctx, "1.75", Z3_mk_real_sort(ctx)), + Z3_mk_numeral(ctx, "2", Z3_mk_int_sort(ctx)), /* exponent */ + Z3_mk_numeral(ctx, "1.75", Z3_mk_real_sort(ctx)), /* significand */ Z3_mk_fpa_sort(ctx, 11, 53)); - c4 = Z3_mk_fpa_to_fp_real(ctx, + c4 = Z3_mk_fpa_to_fp_real(ctx, Z3_mk_fpa_rtz(ctx), Z3_mk_numeral(ctx, "7.0", Z3_mk_real_sort(ctx)), Z3_mk_fpa_sort(ctx, 11, 53)); diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index c910b3f99..90b818b4b 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -1077,8 +1077,8 @@ extern "C" { api::context * ctx = mk_c(c); fpa_util & fu = ctx->fpautil(); if (!fu.is_rm(to_expr(rm)) || - !ctx->autil().is_real(to_expr(sig)) || !ctx->autil().is_int(to_expr(exp)) || + !ctx->autil().is_real(to_expr(sig)) || !fu.is_float(to_sort(s))) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp index 2cce08697..863d1d8db 100644 --- a/src/ast/fpa/fpa2bv_converter.cpp +++ b/src/ast/fpa/fpa2bv_converter.cpp @@ -2490,12 +2490,12 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM)); expr * bv_rm = to_app(args[0])->get_arg(0); - rational q; - if (!m_arith_util.is_numeral(args[1], q)) + rational e; + if (!m_arith_util.is_numeral(args[1], e)) UNREACHABLE(); - rational e; - if (!m_arith_util.is_numeral(args[2], e)) + rational q; + if (!m_arith_util.is_numeral(args[2], q)) UNREACHABLE(); SASSERT(e.is_int64()); diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 7833ae7d1..317112cae 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -490,11 +490,24 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); } else if (arity == 3 && - is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) && - is_sort_of(domain[1], m_arith_fid, REAL_SORT) && - is_sort_of(domain[2], m_arith_fid, INT_SORT)) + is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) && + is_sort_of(domain[1], m_arith_fid, REAL_SORT) && + is_sort_of(domain[2], m_arith_fid, INT_SORT)) { - // Rounding + 1 Real + 1 Int -> 1 FP + // Rounding + 1 Real + 1 Int -> 1 FP + if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) + m_manager->raise_exception("expecting two integer parameters to to_fp"); + + sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int()); + symbol name("to_fp"); + return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters)); + } + else if (arity == 3 && + is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) && + is_sort_of(domain[1], m_arith_fid, INT_SORT) && + is_sort_of(domain[2], m_arith_fid, REAL_SORT)) + { + // Rounding + 1 Int + 1 Real -> 1 FP if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int())) m_manager->raise_exception("expecting two integer parameters to to_fp"); @@ -545,6 +558,7 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para "(Real), " "(RoundingMode (_ BitVec (eb+sb))), " "(RoundingMode (_ FloatingPoint eb' sb')), " + "(RoundingMode Int Real), " "(RoundingMode Real Int), " "(RoundingMode Int), and " "(RoundingMode Real)." diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h index 90e50d8c3..a667bc6f8 100644 --- a/src/ast/fpa_decl_plugin.h +++ b/src/ast/fpa_decl_plugin.h @@ -286,9 +286,9 @@ public: expr * args[] = { rm, t }; return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 2, args); } - app * mk_to_fp(sort * s, expr * rm, expr * sig, expr * exp) { + app * mk_to_fp(sort * s, expr * rm, expr * exp, expr * sig) { SASSERT(is_float(s) && s->get_num_parameters() == 2); - expr * args[] = { rm, sig, exp }; + expr * args[] = { rm, exp, sig}; return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 3, args); } app * mk_to_fp_unsigned(sort * s, expr * rm, expr * t) { diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp index cd096d6a5..bc3f8c25e 100644 --- a/src/ast/rewriter/fpa_rewriter.cpp +++ b/src/ast/rewriter/fpa_rewriter.cpp @@ -271,6 +271,20 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const result = m_util.mk_value(v); return BR_DONE; } + else if (m_util.is_rm_numeral(args[0], rmv) && + m_util.au().is_int(args[1]) && + m_util.au().is_real(args[2])) { + // rm + int + real -> float + if (!m_util.is_rm_numeral(args[0], rmv) || + !m_util.au().is_numeral(args[1], r1) || + !m_util.au().is_numeral(args[2], r2)) + return BR_FAILED; + + TRACE("fp_rewriter", tout << "r1: " << r1 << ", r2: " << r2 << "\n";); + m_fm.set(v, ebits, sbits, rmv, r1.to_mpq().numerator(), r2.to_mpq()); + result = m_util.mk_value(v); + return BR_DONE; + } else if (bu.is_numeral(args[0], r1, bvs1) && bu.is_numeral(args[1], r2, bvs2) && bu.is_numeral(args[2], r3, bvs3)) { From 9dfcaaa01dbfd3892400bc6831539d589fcd99c1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Jan 2016 10:07:44 -0800 Subject: [PATCH 81/87] reset out_bits when blasting multiplication of bit-vectors Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index 25bc72add..c0e8476fe 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -163,23 +163,25 @@ void bit_blaster_tpl::mk_multiplier(unsigned sz, expr * const * a_bits, exp std::swap(a_bits, b_bits); if (is_minus_one(sz, b_bits)) { mk_neg(sz, a_bits, out_bits); + SASSERT(sz == out_bits.size()); return; } if (is_numeral(sz, a_bits, n_a)) { n_a *= n_b; num2bits(n_a, sz, out_bits); + SASSERT(sz == out_bits.size()); return; } -#if 1 if (mk_const_multiplier(sz, a_bits, b_bits, out_bits)) { + SASSERT(sz == out_bits.size()); return; } if (mk_const_multiplier(sz, b_bits, a_bits, out_bits)) { + SASSERT(sz == out_bits.size()); return; } -#endif - + out_bits.reset(); if (!m_use_wtm) { #if 0 static unsigned counter = 0; @@ -1230,10 +1232,11 @@ bool bit_blaster_tpl::mk_const_multiplier(unsigned sz, expr * const * a_bit } SASSERT(out_bits.empty()); - if (false && mk_const_case_multiplier(sz, a_bits, b_bits, out_bits)) { + if (mk_const_case_multiplier(sz, a_bits, b_bits, out_bits)) { SASSERT(sz == out_bits.size()); return true; } + out_bits.reset(); if (!m_use_bcm) { return false; } From fafdbfaf0ec0e1bbf59d47526f7e8cffd833b4b4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 5 Jan 2016 10:16:02 -0800 Subject: [PATCH 82/87] reset out_bits when blasting multiplication of bit-vectors Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h index c0e8476fe..102082cd5 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -159,6 +159,7 @@ template void bit_blaster_tpl::mk_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) { SASSERT(sz > 0); numeral n_a, n_b; + out_bits.reset(); if (is_numeral(sz, a_bits, n_b)) std::swap(a_bits, b_bits); if (is_minus_one(sz, b_bits)) { From aec5a38b146471396772b505a9c113adf3c0c14e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jan 2016 11:44:55 -0800 Subject: [PATCH 83/87] fix memory leak in SAT solver exposed by regression tests Signed-off-by: Nikolaj Bjorner --- src/sat/sat_asymm_branch.cpp | 6 +++- src/sat/sat_clause.cpp | 1 + src/sat/sat_solver.cpp | 1 + src/smt/mam.cpp | 2 +- src/smt/smt_context.cpp | 6 ++-- src/smt/smt_enode.h | 1 + src/smt/smt_quantifier.cpp | 10 ++++-- src/smt/theory_arith_aux.h | 2 ++ src/smt/theory_seq.cpp | 65 ++++++++++++++++++++++++------------ src/smt/theory_seq.h | 18 +++++++++- 10 files changed, 82 insertions(+), 30 deletions(-) diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp index 193bf59f2..8a761ea3a 100644 --- a/src/sat/sat_asymm_branch.cpp +++ b/src/sat/sat_asymm_branch.cpp @@ -78,8 +78,12 @@ namespace sat { clause_vector::iterator end = s.m_clauses.end(); try { for (; it != end; ++it) { - if (s.inconsistent()) + if (s.inconsistent()) { + for (; it != end; ++it, ++it2) { + *it2 = *it; + } break; + } SASSERT(s.m_qhead == s.m_trail.size()); if (m_counter < limit || s.inconsistent()) { *it2 = *it; diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 6314d6fad..fe4822406 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -169,6 +169,7 @@ namespace sat { #endif void * mem = m_allocator.allocate(size); clause * cls = new (mem) clause(m_id_gen.mk(), num_lits, lits, learned); + TRACE("sat", tout << "alloc: " << cls->id() << " " << cls << " " << *cls << " " << (learned?"l":"a") << "\n";); SASSERT(!learned || cls->is_learned()); return cls; } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index f636c726b..373838c15 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -461,6 +461,7 @@ namespace sat { } void solver::dettach_clause(clause & c) { + TRACE("sat", tout << c.id() << "\n";); if (c.size() == 3) dettach_ter_clause(c); else diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index d22ca88db..764176ea0 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -3936,7 +3936,7 @@ namespace smt { } virtual bool is_shared(enode * n) const { - return m_shared_enodes.contains(n); + return !m_shared_enodes.empty() && m_shared_enodes.contains(n); } // This method is invoked when n becomes relevant. diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 45dd7e3dc..405fa79d8 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4025,8 +4025,9 @@ namespace smt { return false; } case 1: { - if (m_qmanager->is_shared(n)) + if (m_qmanager->is_shared(n)) { return true; + } // the variabe is shared if the equivalence class of n // contains a parent application. @@ -4071,7 +4072,8 @@ namespace smt { // the theories of (array int int) and (array (array int int) int). // Remark: The inconsistency is not going to be detected if they are // not marked as shared. - return get_theory(th_id)->is_shared(l->get_th_var()); + bool result = get_theory(th_id)->is_shared(l->get_th_var()); + return result; } default: return true; diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 7c3224882..adc035304 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -192,6 +192,7 @@ namespace smt { return m_owner->hash(); } + enode * get_root() const { return m_root; } diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 69bf0b72f..e06480bc5 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -396,12 +396,14 @@ namespace smt { scoped_ptr m_model_checker; unsigned m_new_enode_qhead; unsigned m_lazy_matching_idx; + bool m_active; public: default_qm_plugin(): m_qm(0), m_context(0), m_new_enode_qhead(0), - m_lazy_matching_idx(0) { + m_lazy_matching_idx(0), + m_active(false) { } virtual ~default_qm_plugin() { @@ -427,7 +429,7 @@ namespace smt { virtual bool model_based() const { return m_fparams->m_mbqi; } - virtual bool mbqi_enabled(quantifier *q) const { + virtual bool mbqi_enabled(quantifier *q) const { if(!m_fparams->m_mbqi_id) return true; const symbol &s = q->get_qid(); size_t len = strlen(m_fparams->m_mbqi_id); @@ -443,6 +445,7 @@ namespace smt { */ virtual void add(quantifier * q) { if (m_fparams->m_mbqi && mbqi_enabled(q)) { + m_active = true; m_model_finder->register_quantifier(q); } } @@ -475,6 +478,7 @@ namespace smt { } virtual void assign_eh(quantifier * q) { + m_active = true; if (m_fparams->m_ematching) { bool has_unary_pattern = false; unsigned num_patterns = q->get_num_patterns(); @@ -537,7 +541,7 @@ namespace smt { } virtual bool is_shared(enode * n) const { - return (m_mam->is_shared(n) || m_lazy_mam->is_shared(n)); + return m_active && (m_mam->is_shared(n) || m_lazy_mam->is_shared(n)); } virtual void adjust_model(proto_model * m) { diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 4291590c6..bff421d12 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -618,8 +618,10 @@ namespace smt { template void theory_arith::remove_fixed_vars_from_base() { int num = get_num_vars(); + //std::cout << "num vars " << num << "\n"; for (theory_var v = 0; v < num; v++) { if (is_base(v) && is_fixed(v)) { + //std::cout << "fixed base " << v << " \n"; // << mk_pp(get_enode(v)->get_owner(), get_manager()) << "\n"; row const & r = m_rows[get_var_row(v)]; typename vector::const_iterator it = r.begin_entries(); typename vector::const_iterator end = r.end_entries(); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 0592f88d9..f1f1ac8a5 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -234,6 +234,7 @@ bool theory_seq::branch_variable() { unsigned sz = m_eqs.size(); expr_ref_vector ls(m), rs(m); int start = ctx.get_random_value(); + unsigned s = 0; for (unsigned i = 0; i < sz; ++i) { unsigned k = (i + start) % sz; eq e = m_eqs[k]; @@ -242,21 +243,19 @@ bool theory_seq::branch_variable() { m_util.str.get_concat(e.m_lhs, ls); m_util.str.get_concat(e.m_rhs, rs); -#if 1 - if (find_branch_candidate(e.m_dep, ls, rs)) { + s = find_branch_start(e.m_lhs, e.m_rhs); + bool found = find_branch_candidate(s, e.m_dep, ls, rs); + insert_branch_start(e.m_lhs, e.m_rhs, s); + if (found) { return true; } - if (find_branch_candidate(e.m_dep, rs, ls)) { + s = find_branch_start(e.m_lhs, e.m_rhs); + found = find_branch_candidate(s, e.m_dep, rs, ls); + insert_branch_start(e.m_rhs, e.m_lhs, s); + if (found) { return true; } -#else - if (find_branch_candidate(e.m_dep, ls.back(), rs)) { - return true; - } - if (find_branch_candidate(e.m_dep, rs.back(), ls)) { - return true; - } -#endif + #if 0 if (!has_length(e.m_lhs)) { enforce_length(ensure_enode(e.m_lhs)); @@ -269,7 +268,20 @@ bool theory_seq::branch_variable() { return ctx.inconsistent(); } -bool theory_seq::find_branch_candidate(dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs) { +void theory_seq::insert_branch_start(expr* l, expr* r, unsigned s) { + m_branch_start.insert(l, r, s); + m_trail_stack.push(pop_branch(m, l, r)); +} + +unsigned theory_seq::find_branch_start(expr* l, expr* r) { + unsigned s = 0; + if (m_branch_start.find(l, r, s)) { + return s; + } + return 0; +} + +bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs) { if (ls.empty()) { return false; @@ -280,29 +292,34 @@ bool theory_seq::find_branch_candidate(dependency* dep, expr_ref_vector const& l return false; } - bool all_units = true; - expr_ref_vector cases(m); - expr_ref v0(m), v(m); + expr_ref v0(m); v0 = m_util.str.mk_empty(m.get_sort(l)); if (can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size(), rs.c_ptr()) && l_false != assume_equality(l, v0)) { TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";); return true; } - for (unsigned j = 0; j < rs.size(); ++j) { +// start = 0; + for (; start < rs.size(); ++start) { + unsigned j = start; if (occurs(l, rs[j])) { return false; } SASSERT(!m_util.str.is_string(rs[j])); - all_units &= m_util.str.is_unit(rs[j]); if (!can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size() - j - 1, rs.c_ptr() + j + 1)) { continue; } v0 = m_util.str.mk_concat(j + 1, rs.c_ptr()); if (l_false != assume_equality(l, v0)) { TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";); + ++start; return true; } } + + bool all_units = true; + for (unsigned j = 0; all_units && j < rs.size(); ++j) { + all_units &= m_util.str.is_unit(rs[j]); + } if (all_units) { literal_vector lits; lits.push_back(~mk_eq_empty(l)); @@ -1634,11 +1651,15 @@ void theory_seq::add_length_axiom(expr* n) { m_util.str.is_string(x)) { expr_ref len(n, m); m_rewrite(len); - if (n != len) { - TRACE("seq", tout << "Add length coherence for " << mk_pp(n, m) << "\n";); - add_axiom(mk_eq(n, len, false)); - m_trail_stack.push(push_replay(alloc(replay_axiom, m, n))); - } + SASSERT(n != len); + add_axiom(mk_eq(len, n, false)); + + //std::cout << len << "\n"; + //len = m_autil.mk_add(len, m_autil.mk_mul(m_autil.mk_int(-1), n)); + //TRACE("seq", tout << "Add length coherence for " << mk_pp(n, m) << "\n";); + //add_axiom(mk_literal(m_autil.mk_le(len, m_autil.mk_int(0)))); + //add_axiom(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(0)))); + m_trail_stack.push(push_replay(alloc(replay_axiom, m, n))); } else { add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0)))); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 12975b94d..4fedd4692 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -258,6 +258,7 @@ namespace smt { replay_length_coherence(ast_manager& m, expr* e) : m_e(e, m) {} virtual void operator()(theory_seq& th) { th.check_length_coherence(m_e); + m_e.reset(); } }; @@ -267,6 +268,7 @@ namespace smt { replay_axiom(ast_manager& m, expr* e) : m_e(e, m) {} virtual void operator()(theory_seq& th) { th.enque_axiom(m_e); + m_e.reset(); } }; @@ -279,6 +281,17 @@ namespace smt { } }; + class pop_branch : public trail { + expr_ref m_l, m_r; + public: + pop_branch(ast_manager& m, expr* l, expr* r): m_l(l, m), m_r(r, m) {} + virtual void undo(theory_seq& th) { + th.m_branch_start.erase(m_l, m_r); + m_l.reset(); + m_r.reset(); + } + }; + void erase_index(unsigned idx, unsigned i); struct stats { @@ -386,7 +399,10 @@ namespace smt { void propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs = false); void set_conflict(dependency* dep, literal_vector const& lits = literal_vector()); - bool find_branch_candidate(dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs); + obj_pair_map m_branch_start; + void insert_branch_start(expr* l, expr* r, unsigned s); + unsigned find_branch_start(expr* l, expr* r); + bool find_branch_candidate(unsigned& start, dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs); bool can_be_equal(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs) const; lbool assume_equality(expr* l, expr* r); From 00f3a1fe81e40b612097e9337e115052b019ef64 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jan 2016 11:47:45 -0800 Subject: [PATCH 84/87] fix memory leak in SAT solver exposed by regression tests Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 1 - src/smt/theory_arith_aux.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 373838c15..f636c726b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -461,7 +461,6 @@ namespace sat { } void solver::dettach_clause(clause & c) { - TRACE("sat", tout << c.id() << "\n";); if (c.size() == 3) dettach_ter_clause(c); else diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index bff421d12..4291590c6 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -618,10 +618,8 @@ namespace smt { template void theory_arith::remove_fixed_vars_from_base() { int num = get_num_vars(); - //std::cout << "num vars " << num << "\n"; for (theory_var v = 0; v < num; v++) { if (is_base(v) && is_fixed(v)) { - //std::cout << "fixed base " << v << " \n"; // << mk_pp(get_enode(v)->get_owner(), get_manager()) << "\n"; row const & r = m_rows[get_var_row(v)]; typename vector::const_iterator it = r.begin_entries(); typename vector::const_iterator end = r.end_entries(); From 643999860dc86e8c3072a93c3c179c5d96f5dc81 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 6 Jan 2016 17:32:54 -0800 Subject: [PATCH 85/87] fix memory leak in SAT solver exposed by regression tests Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index f1f1ac8a5..eb149250b 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -787,7 +787,7 @@ bool theory_seq::propagate_max_length(expr* l, expr* r, dependency* deps) { } rational hi; if (is_tail(l, s, idx) && has_length(s) && m_util.str.is_empty(r) && !upper_bound(s, hi)) { - std::cout << "max length " << mk_pp(s, m) << " " << idx << "\n"; + //std::cout << "max length " << mk_pp(s, m) << " " << idx << "\n"; propagate_lit(deps, 0, 0, mk_literal(m_autil.mk_le(m_util.str.mk_length(s), m_autil.mk_int(idx+1)))); return true; } @@ -1654,7 +1654,8 @@ void theory_seq::add_length_axiom(expr* n) { SASSERT(n != len); add_axiom(mk_eq(len, n, false)); - //std::cout << len << "\n"; +// std::cout << len << " = "; +// std::cout << mk_pp(n, m) << "\n"; //len = m_autil.mk_add(len, m_autil.mk_mul(m_autil.mk_int(-1), n)); //TRACE("seq", tout << "Add length coherence for " << mk_pp(n, m) << "\n";); //add_axiom(mk_literal(m_autil.mk_le(len, m_autil.mk_int(0)))); @@ -1914,38 +1915,36 @@ void theory_seq::propagate_step(literal lit, expr* step) { void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) { context& ctx = get_context(); rational r; + SASSERT(ctx.get_assignment(lit) == l_true); VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); unsigned _idx = r.get_unsigned(); dependency* dep = 0; - expr_ref s1 = canonize(s, dep); - ptr_vector es; expr* e1; expr_ref nth = mk_nth(s, idx); - expr_ref head(m), tail(m), conc(m); - expr_ref_vector elems(m); - get_concat(s1, es); + expr_ref head(m), tail(m), conc(m), len1(m), len2(m); + expr_ref_vector elems(m), es(m); + canonize(s, es, dep); unsigned i = 0; - for (; i <= _idx && i < es.size() && m_util.str.is_unit(es[i]); ++i) {}; - if (i == _idx && i < es.size() && m_util.str.is_unit(es[i], e1)) { + + for (; i <= _idx && i < es.size() && m_util.str.is_unit(es[i].get()); ++i) {}; + if (i == _idx && i < es.size() && m_util.str.is_unit(es[i].get(), e1)) { dep = m_dm.mk_join(dep, m_dm.mk_leaf(assumption(lit))); propagate_eq(dep, ensure_enode(nth), ensure_enode(e1)); return; } - // TBD could tune this aggregate quadratic overhead + // TBD: what about 'dep'? expr* s2 = s; for (unsigned j = 0; j <= _idx; ++j) { mk_decompose(s2, head, tail); elems.push_back(head); + len1 = m_util.str.mk_length(s2); + len2 = m_autil.mk_add(m_autil.mk_int(1), m_util.str.mk_length(tail)); + propagate_eq(lit, len1, len2, false); s2 = tail; } elems.push_back(s2); conc = m_util.str.mk_concat(elems.size(), elems.c_ptr()); propagate_eq(lit, s, conc, true); - - // TBD: examine other places for enforcing constraints on tail - conc = m_autil.mk_add(m_autil.mk_int(_idx+1), m_util.str.mk_length(s2)); - add_axiom(~lit, mk_eq(m_util.str.mk_length(s), conc, false)); - //add_axiom(~lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), m_autil.mk_int(_idx + 1)))); } literal theory_seq::mk_literal(expr* _e) { From 0c2334417c82d631d6b8bc877b314579b1463f76 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 7 Jan 2016 06:53:00 -0800 Subject: [PATCH 86/87] fix build warnigs with && vs ||, tuning seq Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bv_rewriter.cpp | 4 +- src/smt/smt_context.cpp | 3 +- src/smt/smt_enode.h | 2 + src/smt/theory_seq.cpp | 392 +++++++++++++++++++++---------- src/smt/theory_seq.h | 113 ++++++--- 5 files changed, 362 insertions(+), 152 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 2f1fe3c90..6a652c2f7 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -2010,8 +2010,8 @@ bool bv_rewriter::is_add_mul_const(expr* e) const { bool bv_rewriter::is_concat_target(expr* lhs, expr* rhs) const { return - m_util.is_concat(lhs) && (is_concat_split_target(rhs) || has_numeral(to_app(lhs))) || - m_util.is_concat(rhs) && (is_concat_split_target(lhs) || has_numeral(to_app(rhs))); + (m_util.is_concat(lhs) && (is_concat_split_target(rhs) || has_numeral(to_app(lhs)))) || + (m_util.is_concat(rhs) && (is_concat_split_target(lhs) || has_numeral(to_app(rhs)))); } bool bv_rewriter::has_numeral(app* a) const { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 405fa79d8..04b7ce234 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4072,8 +4072,7 @@ namespace smt { // the theories of (array int int) and (array (array int int) int). // Remark: The inconsistency is not going to be detected if they are // not marked as shared. - bool result = get_theory(th_id)->is_shared(l->get_th_var()); - return result; + return get_theory(th_id)->is_shared(l->get_th_var()); } default: return true; diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index adc035304..69a882c99 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -113,6 +113,7 @@ namespace smt { friend class context; friend class euf_manager; friend class conflict_resolution; + theory_var_list * get_th_var_list() { return m_th_var_list.get_th_var() == null_theory_var ? 0 : &m_th_var_list; @@ -170,6 +171,7 @@ namespace smt { m_interpreted = true; } + void del_eh(ast_manager & m, bool update_children_parent = true); app * get_owner() const { diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index eb149250b..f5353e8d0 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -23,7 +23,6 @@ Revision History: #include "smt_context.h" #include "smt_model_generator.h" #include "theory_seq.h" -#include "seq_rewriter.h" #include "ast_trail.h" #include "theory_arith.h" @@ -155,12 +154,14 @@ theory_seq::theory_seq(ast_manager& m): theory(m.mk_family_id("seq")), m(m), m_rep(m, m_dm), + m_eq_id(0), m_factory(0), m_exclude(m), m_axioms(m), m_axioms_head(0), m_mg(0), - m_rewrite(m), + m_rewrite(m), + m_seq_rewrite(m), m_util(m), m_autil(m), m_trail_stack(*this), @@ -232,50 +233,47 @@ final_check_status theory_seq::final_check_eh() { bool theory_seq::branch_variable() { context& ctx = get_context(); unsigned sz = m_eqs.size(); - expr_ref_vector ls(m), rs(m); int start = ctx.get_random_value(); unsigned s = 0; for (unsigned i = 0; i < sz; ++i) { unsigned k = (i + start) % sz; - eq e = m_eqs[k]; - TRACE("seq", tout << e.m_lhs << " = " << e.m_rhs << "\n";); - ls.reset(); rs.reset(); - m_util.str.get_concat(e.m_lhs, ls); - m_util.str.get_concat(e.m_rhs, rs); + eq const& e = m_eqs[k]; + unsigned id = e.id(); + TRACE("seq", tout << e.ls() << " = " << e.rs() << "\n";); - s = find_branch_start(e.m_lhs, e.m_rhs); - bool found = find_branch_candidate(s, e.m_dep, ls, rs); - insert_branch_start(e.m_lhs, e.m_rhs, s); + s = find_branch_start(2*id); + bool found = find_branch_candidate(s, e.dep(), e.ls(), e.rs()); + insert_branch_start(2*id, s); if (found) { return true; } - s = find_branch_start(e.m_lhs, e.m_rhs); - found = find_branch_candidate(s, e.m_dep, rs, ls); - insert_branch_start(e.m_rhs, e.m_lhs, s); + s = find_branch_start(2*id + 1); + found = find_branch_candidate(s, e.dep(), e.rs(), e.ls()); + insert_branch_start(2*id + 1, s); if (found) { return true; } #if 0 - if (!has_length(e.m_lhs)) { - enforce_length(ensure_enode(e.m_lhs)); + if (!has_length(e.ls())) { + enforce_length(ensure_enode(e.ls())); } - if (!has_length(e.m_rhs)) { - enforce_length(ensure_enode(e.m_rhs)); + if (!has_length(e.rs())) { + enforce_length(ensure_enode(e.rs())); } #endif } return ctx.inconsistent(); } -void theory_seq::insert_branch_start(expr* l, expr* r, unsigned s) { - m_branch_start.insert(l, r, s); - m_trail_stack.push(pop_branch(m, l, r)); +void theory_seq::insert_branch_start(unsigned k, unsigned s) { + m_branch_start.insert(k, s); + m_trail_stack.push(pop_branch(k)); } -unsigned theory_seq::find_branch_start(expr* l, expr* r) { +unsigned theory_seq::find_branch_start(unsigned k) { unsigned s = 0; - if (m_branch_start.find(l, r, s)) { + if (m_branch_start.find(k, s)) { return s; } return 0; @@ -301,14 +299,15 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re // start = 0; for (; start < rs.size(); ++start) { unsigned j = start; - if (occurs(l, rs[j])) { + SASSERT(!m_util.str.is_concat(rs[j])); + SASSERT(!m_util.str.is_string(rs[j])); + if (l == rs[j]) { return false; } - SASSERT(!m_util.str.is_string(rs[j])); if (!can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size() - j - 1, rs.c_ptr() + j + 1)) { continue; } - v0 = m_util.str.mk_concat(j + 1, rs.c_ptr()); + v0 = mk_concat(j + 1, rs.c_ptr()); if (l_false != assume_equality(l, v0)) { TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";); ++start; @@ -324,7 +323,7 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re literal_vector lits; lits.push_back(~mk_eq_empty(l)); for (unsigned i = 0; i < rs.size(); ++i) { - v0 = m_util.str.mk_concat(i + 1, rs.c_ptr()); + v0 = mk_concat(i + 1, rs.c_ptr()); lits.push_back(~mk_eq(l, v0, false)); } set_conflict(dep, lits); @@ -412,7 +411,7 @@ bool theory_seq::propagate_length_coherence(expr* e) { } expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); elems.push_back(seq); - tail = m_util.str.mk_concat(elems.size(), elems.c_ptr()); + tail = mk_concat(elems.size(), elems.c_ptr()); // len(e) >= low => e = tail; literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true)))); add_axiom(~low, mk_eq(e, tail, false)); @@ -441,7 +440,7 @@ bool theory_seq::check_length_coherence(expr* e) { l_false == assume_equality(e, emp)) { // e = emp \/ e = unit(head.elem(e))*tail(e) mk_decompose(e, head, tail); - expr_ref conc(m_util.str.mk_concat(head, tail), m); + expr_ref conc = mk_concat(head, tail); propagate_is_conc(e, conc); assume_equality(tail, emp); } @@ -549,7 +548,7 @@ void theory_seq::mk_decompose(expr* e, expr_ref& head, expr_ref& tail) { bool theory_seq::is_solved() { if (!m_eqs.empty()) { - IF_VERBOSE(10, verbose_stream() << "(seq.giveup " << m_eqs[0].m_lhs << " = " << m_eqs[0].m_rhs << " is unsolved)\n";); + IF_VERBOSE(10, verbose_stream() << "(seq.giveup " << m_eqs[0].ls() << " = " << m_eqs[0].rs() << " is unsolved)\n";); return false; } for (unsigned i = 0; i < m_automata.size(); ++i) { @@ -632,54 +631,76 @@ void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) { void theory_seq::enforce_length_coherence(enode* n1, enode* n2) { expr* o1 = n1->get_owner(); expr* o2 = n2->get_owner(); + if (m_util.str.is_concat(o1) && m_util.str.is_concat(o2)) { + //std::cout << "concats:\n" << mk_pp(o1,m) << "\n" << mk_pp(o2,m) << "\n"; + return; + } if (has_length(o1) && !has_length(o2)) { + //std::cout << "enforce length: " << mk_pp(o1,m) << " -> " << mk_pp(o2,m) << "\n"; enforce_length(n2); } else if (has_length(o2) && !has_length(o1)) { + //std::cout << "enforce length: " << mk_pp(o2,m) << " -> " << mk_pp(o1,m) << "\n"; enforce_length(n1); } } -bool theory_seq::simplify_eq(expr* l, expr* r, dependency* deps) { +bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependency* deps) { context& ctx = get_context(); - seq_rewriter rw(m); expr_ref_vector lhs(m), rhs(m); - if (!rw.reduce_eq(l, r, lhs, rhs)) { - // equality is inconsistent. - TRACE("seq", tout << mk_pp(l, m) << " != " << mk_pp(r, m) << "\n";); + if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs)) { + // equality is inconsistent.x2 + TRACE("seq", tout << ls << " != " << rs << "\n";); set_conflict(deps); return true; } - if (unchanged(l, lhs, r, rhs)) { + if (lhs.empty()) { return false; } SASSERT(lhs.size() == rhs.size()); - for (unsigned i = 0; i < lhs.size(); ++i) { + SASSERT(ls.empty() && rs.empty()); + for (unsigned i = 0; !ctx.inconsistent() && i < lhs.size(); ++i) { expr_ref li(lhs[i].get(), m); expr_ref ri(rhs[i].get(), m); - if (m_util.is_seq(li) || m_util.is_re(li)) { - m_eqs.push_back(eq(li, ri, deps)); + if (solve_unit_eq(li, ri, deps)) { + // skip + } + else if (m_util.is_seq(li) || m_util.is_re(li)) { + m_eqs.push_back(mk_eqdep(li, ri, deps)); } else { propagate_eq(deps, ensure_enode(li), ensure_enode(ri)); } } TRACE("seq", - tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " => \n"; + tout << ls << " = " << rs << " => \n"; for (unsigned i = 0; i < lhs.size(); ++i) { tout << mk_pp(lhs[i].get(), m) << "\n = \n" << mk_pp(rhs[i].get(), m) << "; \n"; } tout << "\n";); + + return true; } +bool theory_seq::solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* deps) { + if (l.size() == 1 && is_var(l[0]) && !occurs(l[0], r) && add_solution(l[0], mk_concat(r), deps)) { + return true; + } + if (r.size() == 1 && is_var(r[0]) && !occurs(r[0], l) && add_solution(r[0], mk_concat(l), deps)) { + return true; + } + + return false; +} + bool theory_seq::solve_unit_eq(expr* l, expr* r, dependency* deps) { + SASSERT(l != r); if (l == r) { return true; } - //propagate_max_length(l, r, deps); if (is_var(l) && !occurs(l, r) && add_solution(l, r, deps)) { return true; @@ -691,8 +712,16 @@ bool theory_seq::solve_unit_eq(expr* l, expr* r, dependency* deps) { return false; } + +bool theory_seq::occurs(expr* a, expr_ref_vector const& b) { + for (unsigned i = 0; i < b.size(); ++i) { + if (a == b[i]) return true; + } + return false; +} + bool theory_seq::occurs(expr* a, expr* b) { - // true if a occurs under an interpreted function or under left/right selector. + // true if a occurs under an interpreted function or under left/right selector. SASSERT(is_var(a)); SASSERT(m_todo.empty()); expr* e1, *e2; @@ -709,9 +738,10 @@ bool theory_seq::occurs(expr* a, expr* b) { m_todo.push_back(e2); } } - return false; + return false; } + bool theory_seq::is_var(expr* a) { return m_util.is_seq(a) && @@ -744,7 +774,7 @@ bool theory_seq::solve_eqs(unsigned i) { bool change = false; for (; !ctx.inconsistent() && i < m_eqs.size(); ++i) { eq e = m_eqs[i]; - if (solve_eq(e.m_lhs, e.m_rhs, e.m_dep)) { + if (solve_eq(e.ls(), e.rs(), e.dep())) { if (i + 1 != m_eqs.size()) { eq e1 = m_eqs[m_eqs.size()-1]; m_eqs.set(i, e1); @@ -758,22 +788,32 @@ bool theory_seq::solve_eqs(unsigned i) { return change || ctx.inconsistent(); } -bool theory_seq::solve_eq(expr* _l, expr* _r, dependency* deps) { +bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* deps) { context& ctx = get_context(); - expr_ref l = canonize(_l, deps); - expr_ref r = canonize(_r, deps); - TRACE("seq", tout << l << " = " << r << "\n";); - if (!ctx.inconsistent() && simplify_eq(l, r, deps)) { + expr_ref_vector& ls = m_ls; + expr_ref_vector& rs = m_rs; + rs.reset(); ls.reset(); + dependency* dep2 = 0; + bool change = canonize(l, ls, dep2); + change = canonize(r, rs, dep2) || change; + TRACE("seq", tout << ls << " = " << rs << "\n";); + deps = m_dm.mk_join(dep2, deps); + if (!ctx.inconsistent() && simplify_eq(ls, rs, deps)) { return true; } - if (!ctx.inconsistent() && solve_unit_eq(l, r, deps)) { + TRACE("seq", tout << ls << " = " << rs << "\n";); + SASSERT(rs.empty() == ls.empty()); + if (ls.empty()) { + return true; + } + if (!ctx.inconsistent() && solve_unit_eq(ls, rs, deps)) { return true; } - if (!ctx.inconsistent() && solve_binary_eq(l, r, deps)) { + if (!ctx.inconsistent() && solve_binary_eq(ls, rs, deps)) { return true; } - if (!ctx.inconsistent() && (_l != l || _r != r)) { - m_eqs.push_back(eq(l, r, deps)); + if (!ctx.inconsistent() && change) { + m_eqs.push_back(eq(m_eq_id++, ls, rs, deps)); return true; } return false; @@ -794,38 +834,33 @@ bool theory_seq::propagate_max_length(expr* l, expr* r, dependency* deps) { return false; } -bool theory_seq::is_binary_eq(expr* l, expr* r, expr*& x, ptr_vector& xs, ptr_vector& ys, expr*& y) { - xs.reset(); - ys.reset(); - get_concat(l, xs); - if (xs.size() > 1 && is_var(xs[0])) { - get_concat(r, ys); - if (ys.size() > 1 && is_var(ys.back())) { - x = xs[0]; - y = ys.back(); - for (unsigned i = 1; i < xs.size(); ++i) { - if (!m_util.str.is_unit(xs[i])) return false; - xs[i-1] = xs[i]; - } - xs.pop_back(); - for (unsigned i = 0; i < ys.size()-1; ++i) { - if (!m_util.str.is_unit(ys[i])) return false; - } - ys.pop_back(); - return true; +bool theory_seq::is_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr*& x, ptr_vector& xs, ptr_vector& ys, expr*& y) { + if (ls.size() > 1 && is_var(ls[0]) && + rs.size() > 1 && is_var(rs.back())) { + xs.reset(); + ys.reset(); + x = ls[0]; + y = rs.back(); + for (unsigned i = 1; i < ls.size(); ++i) { + if (!m_util.str.is_unit(ls[i])) return false; } + for (unsigned i = 0; i < rs.size()-1; ++i) { + if (!m_util.str.is_unit(rs[i])) return false; + } + xs.append(ls.size()-1, ls.c_ptr() + 1); + ys.append(rs.size()-1, rs.c_ptr()); + return true; } return false; } -bool theory_seq::solve_binary_eq(expr* l, expr* r, dependency* dep) { +bool theory_seq::solve_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep) { context& ctx = get_context(); ptr_vector xs, ys; expr* x, *y; - bool is_binary = is_binary_eq(l, r, x, xs, ys, y); + bool is_binary = is_binary_eq(ls, rs, x, xs, ys, y); if (!is_binary) { - std::swap(l, r); - is_binary = is_binary_eq(l, r, x, xs, ys, y); + is_binary = is_binary_eq(rs, ls, x, xs, ys, y); } if (!is_binary) { return false; @@ -902,7 +937,6 @@ bool theory_seq::solve_nqs(unsigned i) { void theory_seq::solve_ne(unsigned idx) { context& ctx = get_context(); - seq_rewriter rw(m); ne const& n = m_nqs[idx]; TRACE("seq", display_disequation(tout, n);); @@ -932,7 +966,7 @@ void theory_seq::solve_ne(unsigned idx) { expr* r = n.m_rhs[i]; canonize(l, ls, deps); canonize(r, rs, deps); - if (!rw.reduce_eq(ls, rs, lhs, rhs)) { + if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs)) { mark_solved(idx); return; } @@ -1015,7 +1049,7 @@ void theory_seq::solve_ne(unsigned idx) { case l_true: { expr_ref head(m), tail(m); mk_decompose(r, head, tail); - expr_ref conc(m_util.str.mk_concat(head, tail), m); + expr_ref conc = mk_concat(head, tail); propagate_is_conc(r, conc); m_new_propagation = true; break; @@ -1031,6 +1065,120 @@ void theory_seq::solve_ne(unsigned idx) { } +#if 0 +bool theory_seq::solve_ne2(unsigned idx) { + context& ctx = get_context(); + ne2 const& n = m_nqs[idx]; + TRACE("seq", display_disequation(tout, n);); + + unsigned num_undef_lits = 0; + for (unsigned i = 0; i < n.lits().size(); ++i) { + switch (ctx.get_assignment(n.lits(i))) { + case l_false: + return true; + case l_true: + break; + case l_undef: + ++num_undef_lits; + break; + } + } + unsigned_vector unchanged; + dependency* new_deps = 0; + vector new_ls, new_rs; + literal_vector new_lits = n.lits(); + bool updated = false; + for (unsigned i = 0; i < n.ls().size(); ++i) { + expr_ref_vector& ls = m_ls; + expr_ref_vector& rs = m_rs; + expr_ref_vector& lhs = m_lhs; + expr_ref_vector& rhs = m_rhs; + ls.reset(); rs.reset(); lhs.reset(); rhs.reset(); + dependency* deps = 0; + expr_ref_vector const& l = n.ls(i); + expr_ref_vector const& r = n.rs(i); + change = canonize(l, ls, deps) || change; + change = canonize(r, rs, deps) || change; + if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs)) { + return true; + } + else if (!change && lhs.empty()) { + unchanged.push_back(i); + } + else if (change && lhs.empty()) { + + } + else { + updated = true; + TRACE("seq", + for (unsigned j = 0; j < lhs.size(); ++j) { + tout << mk_pp(lhs[j].get(), m) << " "; + } + tout << "\n"; + tout << l << " != " << r << "\n";); + + for (unsigned j = 0; j < lhs.size(); ++j) { + expr_ref nl(lhs[j].get(), m); + expr_ref nr(rhs[j].get(), m); + if (m_util.is_seq(nl) || m_util.is_re(nl)) { + new_ls.push_back(nl); + new_rs.push_back(nr); + } + else { + literal lit(mk_eq(nl, nr, false)); + ctx.mark_as_relevant(lit); + new_lits.push_back(lit); + switch (ctx.get_assignment(lit)) { + case l_false: + return true; + case l_true: + break; + case l_undef: + ++num_undef_lits; + m_new_propagation = true; + break; + } + } + } + new_deps = deps; + } + } + if (num_undef_lits == 1 && new_ls.empty()) { + literal_vector lits; + literal undef_lit = null_literal; + for (unsigned i = 0; i < new_lits.size(); ++i) { + literal lit = new_lits[i]; + switch (ctx.get_assignment(lit)) { + case l_true: + lits.push_back(lit); + break; + case l_false: + UNREACHABLE(); + break; + case l_undef: + SASSERT(undef_lit == null_literal); + undef_lit = lit; + break; + } + } + TRACE("seq", tout << "propagate: " << undef_lit << "\n";); + SASSERT(undef_lit != null_literal); + propagate_lit(new_deps, lits.size(), lits.c_ptr(), ~undef_lit); + return true; + } + else if (num_undef_lits == 0 && new_ls.empty()) { + set_conflict(new_deps, new_lits); + SASSERT(m_new_propagation); + return true; + } + else if (change) { + + } + return change; +} + +#endif + void theory_seq::mark_solved(unsigned idx) { m_trail_stack.push(solved_ne(*this, idx)); } @@ -1152,8 +1300,8 @@ void theory_seq::display(std::ostream & out) const { void theory_seq::display_equations(std::ostream& out) const { for (unsigned i = 0; i < m_eqs.size(); ++i) { eq const& e = m_eqs[i]; - out << e.m_lhs << " = " << e.m_rhs << " <- "; - display_deps(out, e.m_dep); + out << e.ls() << " = " << e.rs() << " <- "; + display_deps(out, e.dep()); } } @@ -1381,13 +1529,14 @@ expr_ref theory_seq::canonize(expr* e, dependency*& eqs) { return result; } -void theory_seq::canonize(expr* e0, expr_ref_vector& es, dependency*& eqs) { +bool theory_seq::canonize(expr* e0, expr_ref_vector& es, dependency*& eqs) { dependency* dep = 0; expr* e = m_rep.find(e0, dep); + bool change = e != e0; expr* e1, *e2; if (m_util.str.is_concat(e, e1, e2)) { - canonize(e1, es, eqs); - canonize(e2, es, eqs); + change = canonize(e1, es, eqs) || change; + change = canonize(e2, es, eqs) || change; } else if (m_util.str.is_empty(e)) { // skip @@ -1395,15 +1544,34 @@ void theory_seq::canonize(expr* e0, expr_ref_vector& es, dependency*& eqs) { else { expr_ref e3 = expand(e, eqs); if (m_util.str.is_concat(e3) || m_util.str.is_empty(e3)) { - canonize(e3, es, eqs); + change = canonize(e3, es, eqs) || change; } else { + change = e3 != e || change; es.push_back(e3); } } eqs = m_dm.mk_join(eqs, dep); + return change; } +bool theory_seq::canonize(expr_ref_vector const& es, expr_ref_vector& result, dependency*& eqs) { + dependency* dep = 0; + bool change = false; + for (unsigned i = 0; i < es.size(); ++i) { + expr_ref r = expand(es[i], eqs); + change |= r != es[i]; + if (m_util.str.is_concat(r)) { + canonize(r, result, eqs); + } + else if (!m_util.str.is_empty(r)) { + result.push_back(r); + } + } + return change; +} + + expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { expr_ref result(m); dependency* deps = 0; @@ -1416,7 +1584,7 @@ expr_ref theory_seq::expand(expr* e0, dependency*& eqs) { expr* e = m_rep.find(e0, deps); expr* e1, *e2; if (m_util.str.is_concat(e, e1, e2)) { - result = m_util.str.mk_concat(expand(e1, deps), expand(e2, deps)); + result = mk_concat(expand(e1, deps), expand(e2, deps)); } else if (m_util.str.is_empty(e) || m_util.str.is_string(e)) { result = e; @@ -1515,10 +1683,10 @@ void theory_seq::deque_axiom(expr* n) { void theory_seq::tightest_prefix(expr* s, expr* x, literal lit1, literal lit2) { expr_ref s1 = mk_skolem(m_seq_first, s); expr_ref c = mk_last(s); - expr_ref s1c(m_util.str.mk_concat(s1, m_util.str.mk_unit(c)), m); + expr_ref s1c = mk_concat(s1, m_util.str.mk_unit(c)); literal s_eq_emp = mk_eq_empty(s); add_axiom(lit1, lit2, s_eq_emp, mk_eq(s, s1c, false)); - add_axiom(lit1, lit2, s_eq_emp, ~mk_literal(m_util.str.mk_prefix(s, m_util.str.mk_concat(x, s1)))); + add_axiom(lit1, lit2, s_eq_emp, ~mk_literal(m_util.str.mk_prefix(s, mk_concat(x, s1)))); } /* @@ -1564,7 +1732,7 @@ void theory_seq::add_indexof_axiom(expr* i) { if (m_autil.is_numeral(offset, r) && r.is_zero()) { expr_ref x = mk_skolem(m_contains_left, t, s); expr_ref y = mk_skolem(m_contains_right, t, s); - xsy = m_util.str.mk_concat(x,s,y); + xsy = mk_concat(x,s,y); literal cnt = mk_literal(m_util.str.mk_contains(t, s)); literal eq_empty = mk_eq_empty(s); add_axiom(cnt, mk_eq(i, minus_one, false)); @@ -1585,7 +1753,7 @@ void theory_seq::add_indexof_axiom(expr* i) { // 0 <= offset & offset < len(t) & indexof(y,s,0) >= 0 = -1 => // -1 = indexof(y,s,0) + offset = indexof(t, s, offset) - add_axiom(~offset_ge_0, offset_ge_len, mk_eq(t, m_util.str.mk_concat(x, y), false)); + add_axiom(~offset_ge_0, offset_ge_len, mk_eq(t, mk_concat(x, y), false)); add_axiom(~offset_ge_0, offset_ge_len, mk_eq(m_util.str.mk_length(x), offset, false)); add_axiom(~offset_ge_0, offset_ge_len, ~mk_eq(indexof0, minus_one, false), mk_eq(i, minus_one, false)); @@ -1608,8 +1776,8 @@ void theory_seq::add_replace_axiom(expr* r) { VERIFY(m_util.str.is_replace(r, a, s, t)); expr_ref x = mk_skolem(m_contains_left, a, s); expr_ref y = mk_skolem(m_contains_right, a, s); - expr_ref xty(m_util.str.mk_concat(x, t, y), m); - expr_ref xsy(m_util.str.mk_concat(x, s, y), m); + expr_ref xty = mk_concat(x, t, y); + expr_ref xsy = mk_concat(x, s, y); literal cnt = mk_literal(m_util.str.mk_contains(a ,s)); add_axiom(cnt, mk_eq(r, a, false)); add_axiom(~cnt, mk_eq(a, xsy, false)); @@ -1626,7 +1794,7 @@ void theory_seq::add_elim_string_axiom(expr* n) { expr_ref result(m_util.str.mk_unit(m_util.str.mk_char(s, s.length()-1)), m); for (unsigned i = s.length()-1; i > 0; ) { --i; - result = m_util.str.mk_concat(m_util.str.mk_unit(m_util.str.mk_char(s, i)), result); + result = mk_concat(m_util.str.mk_unit(m_util.str.mk_char(s, i)), result); } add_axiom(mk_eq(n, result, false)); m_rep.update(n, result, 0); @@ -1654,12 +1822,6 @@ void theory_seq::add_length_axiom(expr* n) { SASSERT(n != len); add_axiom(mk_eq(len, n, false)); -// std::cout << len << " = "; -// std::cout << mk_pp(n, m) << "\n"; - //len = m_autil.mk_add(len, m_autil.mk_mul(m_autil.mk_int(-1), n)); - //TRACE("seq", tout << "Add length coherence for " << mk_pp(n, m) << "\n";); - //add_axiom(mk_literal(m_autil.mk_le(len, m_autil.mk_int(0)))); - //add_axiom(mk_literal(m_autil.mk_ge(len, m_autil.mk_int(0)))); m_trail_stack.push(push_replay(alloc(replay_axiom, m, n))); } else { @@ -1847,7 +2009,7 @@ void theory_seq::add_extract_axiom(expr* e) { expr_ref lx(m_util.str.mk_length(x), m); expr_ref le(m_util.str.mk_length(e), m); expr_ref ls_minus_i(mk_sub(ls, i), m); - expr_ref xe(m_util.str.mk_concat(x, e), m); + expr_ref xe = mk_concat(x, e); expr_ref zero(m_autil.mk_int(0), m); literal i_ge_0 = mk_literal(m_autil.mk_ge(i, zero)); @@ -1873,7 +2035,7 @@ void theory_seq::add_at_axiom(expr* e) { expr_ref x(m), y(m), lx(m), le(m), xey(m), zero(m), one(m), len_e(m), len_x(m); x = mk_skolem(m_at_left, s); y = mk_skolem(m_at_right, s); - xey = m_util.str.mk_concat(x, e, y); + xey = mk_concat(x, e, y); zero = m_autil.mk_int(0); one = m_autil.mk_int(1); len_e = m_util.str.mk_length(e); @@ -1918,21 +2080,9 @@ void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) { SASSERT(ctx.get_assignment(lit) == l_true); VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned()); unsigned _idx = r.get_unsigned(); - dependency* dep = 0; - expr* e1; - expr_ref nth = mk_nth(s, idx); expr_ref head(m), tail(m), conc(m), len1(m), len2(m); - expr_ref_vector elems(m), es(m); - canonize(s, es, dep); - unsigned i = 0; + expr_ref_vector elems(m); - for (; i <= _idx && i < es.size() && m_util.str.is_unit(es[i].get()); ++i) {}; - if (i == _idx && i < es.size() && m_util.str.is_unit(es[i].get(), e1)) { - dep = m_dm.mk_join(dep, m_dm.mk_leaf(assumption(lit))); - propagate_eq(dep, ensure_enode(nth), ensure_enode(e1)); - return; - } - // TBD: what about 'dep'? expr* s2 = s; for (unsigned j = 0; j <= _idx; ++j) { mk_decompose(s2, head, tail); @@ -1943,7 +2093,7 @@ void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) { s2 = tail; } elems.push_back(s2); - conc = m_util.str.mk_concat(elems.size(), elems.c_ptr()); + conc = mk_concat(elems); propagate_eq(lit, s, conc, true); } @@ -2036,7 +2186,7 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { if (m_util.str.is_prefix(e, e1, e2)) { if (is_true) { f = mk_skolem(m_prefix, e1, e2); - f = m_util.str.mk_concat(e1, f); + f = mk_concat(e1, f); propagate_eq(lit, f, e2, true); } else { @@ -2050,7 +2200,7 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { else if (m_util.str.is_suffix(e, e1, e2)) { if (is_true) { f = mk_skolem(m_suffix, e1, e2); - f = m_util.str.mk_concat(f, e1); + f = mk_concat(f, e1); propagate_eq(lit, f, e2, true); } else { @@ -2060,7 +2210,7 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { // lit => e1 = first ++ (unit last) expr_ref f1 = mk_skolem(m_seq_first, e1); expr_ref f2 = mk_last(e1); - f = m_util.str.mk_concat(f1, m_util.str.mk_unit(f2)); + f = mk_concat(f1, m_util.str.mk_unit(f2)); propagate_eq(lit, e1, f, true); if (add_suffix2suffix(e)) { @@ -2072,7 +2222,7 @@ void theory_seq::assign_eh(bool_var v, bool is_true) { if (is_true) { expr_ref f1 = mk_skolem(m_contains_left, e1, e2); expr_ref f2 = mk_skolem(m_contains_right, e1, e2); - f = m_util.str.mk_concat(f1, e2, f2); + f = mk_concat(f1, e2, f2); propagate_eq(lit, f, e1, true); } else if (!canonizes(false, e)) { @@ -2130,7 +2280,7 @@ void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) { expr_ref o1(n1->get_owner(), m); expr_ref o2(n2->get_owner(), m); TRACE("seq", tout << o1 << " = " << o2 << "\n";); - m_eqs.push_back(eq(o1, o2, deps)); + m_eqs.push_back(mk_eqdep(o1, o2, deps)); solve_eqs(m_eqs.size()-1); enforce_length_coherence(n1, n2); } @@ -2554,7 +2704,7 @@ bool theory_seq::add_suffix2suffix(expr* e) { expr_ref last2 = mk_last(e2); expr_ref first1 = mk_skolem(m_seq_first, e1); expr_ref last1 = mk_last(e1); - expr_ref conc(m_util.str.mk_concat(first2, m_util.str.mk_unit(last2)), m); + expr_ref conc = mk_concat(first2, m_util.str.mk_unit(last2)); propagate_eq(~mk_eq(e2, emp, false), e2, conc); literal last_eq = mk_eq(last1, last2, false); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index 4fedd4692..1e19bcddb 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -106,14 +106,72 @@ namespace smt { }; // Asserted or derived equality with dependencies - struct eq { - expr_ref m_lhs; - expr_ref m_rhs; - dependency* m_dep; - eq(expr_ref& l, expr_ref& r, dependency* d): - m_lhs(l), m_rhs(r), m_dep(d) {} - eq(eq const& other): m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_dep(other.m_dep) {} - eq& operator=(eq const& other) { m_lhs = other.m_lhs; m_rhs = other.m_rhs; m_dep = other.m_dep; return *this; } + class eq { + unsigned m_id; + expr_ref_vector m_lhs; + expr_ref_vector m_rhs; + dependency* m_dep; + public: + + eq(unsigned id, expr_ref_vector& l, expr_ref_vector& r, dependency* d): + m_id(id), m_lhs(l), m_rhs(r), m_dep(d) {} + eq(eq const& other): m_id(other.m_id), m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_dep(other.m_dep) {} + eq& operator=(eq const& other) { + if (this != &other) { + m_lhs.reset(); + m_rhs.reset(); + m_lhs.append(other.m_lhs); + m_rhs.append(other.m_rhs); + m_dep = other.m_dep; + m_id = other.m_id; + } + return *this; + } + expr_ref_vector const& ls() const { return m_lhs; } + expr_ref_vector const& rs() const { return m_rhs; } + dependency* dep() const { return m_dep; } + unsigned id() const { return m_id; } + }; + + eq mk_eqdep(expr* l, expr* r, dependency* dep) { + expr_ref_vector ls(m), rs(m); + m_util.str.get_concat(l, ls); + m_util.str.get_concat(r, rs); + return eq(m_eq_id++, ls, rs, dep); + } + + + class ne2 { + vector m_lhs; + vector m_rhs; + literal_vector m_lits; + dependency* m_dep; + public: + ne2(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep): + m_dep(dep) { + m_lhs.push_back(l); + m_rhs.push_back(r); + } + + ne2(ne2 const& other): + m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_lits(other.m_lits), m_dep(other.m_dep) {} + + ne2& operator=(ne2 const& other) { + if (this != &other) { + m_lhs.reset(); m_lhs.append(other.m_lhs); + m_rhs.reset(); m_rhs.append(other.m_rhs); + m_lits.reset(); m_lits.append(other.m_lits); + m_dep = other.m_dep; + } + return *this; + } + vector const& ls() const { return m_lhs; } + vector const& rs() const { return m_rhs; } + expr_ref_vector const& ls(unsigned i) const { return m_lhs[i]; } + expr_ref_vector const& rs(unsigned i) const { return m_rhs[i]; } + literal_vector const& lits() const { return m_lits; } + literal lits(unsigned i) const { return m_lits[i]; } + dependency* dep() const { return m_dep; } }; @@ -282,13 +340,11 @@ namespace smt { }; class pop_branch : public trail { - expr_ref m_l, m_r; + unsigned k; public: - pop_branch(ast_manager& m, expr* l, expr* r): m_l(l, m), m_r(r, m) {} + pop_branch(unsigned k): k(k) {} virtual void undo(theory_seq& th) { - th.m_branch_start.erase(m_l, m_r); - m_l.reset(); - m_r.reset(); + th.m_branch_start.erase(k); } }; @@ -311,6 +367,7 @@ namespace smt { solution_map m_rep; // unification representative. scoped_vector m_eqs; // set of current equations. scoped_vector m_nqs; // set of current disequalities. + unsigned m_eq_id; seq_factory* m_factory; // value factory exclusion_table m_exclude; // set of asserted disequalities. @@ -322,6 +379,7 @@ namespace smt { scoped_ptr_vector m_replay; // set of actions to replay model_generator* m_mg; th_rewriter m_rewrite; + seq_rewriter m_seq_rewrite; seq_util m_util; arith_util m_autil; th_trail_stack m_trail_stack; @@ -375,21 +433,20 @@ namespace smt { bool propagate_length_coherence(expr* e); bool solve_eqs(unsigned start); - bool solve_eq(expr* l, expr* r, dependency* dep); - bool simplify_eq(expr* l, expr* r, dependency* dep); + bool solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep); + bool simplify_eq(expr_ref_vector& l, expr_ref_vector& r, dependency* dep); bool solve_unit_eq(expr* l, expr* r, dependency* dep); - bool is_binary_eq(expr* l, expr* r, expr*& x, ptr_vector& xunits, ptr_vector& yunits, expr*& y); - bool solve_binary_eq(expr* l, expr* r, dependency* dep); + bool solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep); + bool is_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, expr*& x, ptr_vector& xunits, ptr_vector& yunits, expr*& y); + bool solve_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep); bool propagate_max_length(expr* l, expr* r, dependency* dep); + expr_ref mk_concat(unsigned n, expr*const* es) { return expr_ref(m_util.str.mk_concat(n, es), m); } + expr_ref mk_concat(expr_ref_vector const& es) { return mk_concat(es.size(), es.c_ptr()); } + expr_ref mk_concat(expr* e1, expr* e2) { return expr_ref(m_util.str.mk_concat(e1, e2), m); } + expr_ref mk_concat(expr* e1, expr* e2, expr* e3) { return expr_ref(m_util.str.mk_concat(e1, e2, e3), m); } bool solve_nqs(unsigned i); void solve_ne(unsigned i); - bool unchanged(expr* e, expr_ref_vector& es) const { return es.size() == 1 && es[0] == e; } - bool unchanged(expr* e, expr_ref_vector& es, expr* f, expr_ref_vector& fs) const { - return - (unchanged(e, es) && unchanged(f, fs)) || - (unchanged(e, fs) && unchanged(e, fs)); - } // asserting consequences void linearize(dependency* dep, enode_pair_vector& eqs, literal_vector& lits) const; @@ -399,15 +456,16 @@ namespace smt { void propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs = false); void set_conflict(dependency* dep, literal_vector const& lits = literal_vector()); - obj_pair_map m_branch_start; - void insert_branch_start(expr* l, expr* r, unsigned s); - unsigned find_branch_start(expr* l, expr* r); + u_map m_branch_start; + void insert_branch_start(unsigned k, unsigned s); + unsigned find_branch_start(unsigned k); bool find_branch_candidate(unsigned& start, dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs); bool can_be_equal(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs) const; lbool assume_equality(expr* l, expr* r); // variable solving utilities bool occurs(expr* a, expr* b); + bool occurs(expr* a, expr_ref_vector const& b); bool is_var(expr* b); bool add_solution(expr* l, expr* r, dependency* dep); bool is_nth(expr* a) const; @@ -415,7 +473,8 @@ namespace smt { expr_ref mk_nth(expr* s, expr* idx); expr_ref mk_last(expr* e); expr_ref canonize(expr* e, dependency*& eqs); - void canonize(expr* e, expr_ref_vector& es, dependency*& eqs); + bool canonize(expr* e, expr_ref_vector& es, dependency*& eqs); + bool canonize(expr_ref_vector const& es, expr_ref_vector& result, dependency*& eqs); expr_ref expand(expr* e, dependency*& eqs); void add_dependency(dependency*& dep, enode* a, enode* b); From e53b580cb463ac36b369823ead3b81d7308b02bf Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 7 Jan 2016 15:58:10 +0000 Subject: [PATCH 87/87] added compiler macro to disable invocation of the debugger upon failure. --- src/util/debug.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util/debug.h b/src/util/debug.h index 439a19b27..6e295dcaa 100644 --- a/src/util/debug.h +++ b/src/util/debug.h @@ -44,12 +44,16 @@ bool assertions_enabled(); #define DEBUG_CODE(CODE) ((void) 0) #endif +#ifdef NO_Z3_DEBUGGER +#define INVOKE_DEBUGGER() exit(ERR_INTERNAL_FATAL) +#else #ifdef _WINDOWS #define INVOKE_DEBUGGER() __debugbreak() #else void invoke_gdb(); #define INVOKE_DEBUGGER() invoke_gdb() #endif +#endif void notify_assertion_violation(const char * file_name, int line, const char * condition); void enable_debug(const char * tag);