From 49678065bd133721445bb7ef7be6ac03d826dd36 Mon Sep 17 00:00:00 2001 From: Ivan Gotovchits Date: Wed, 13 Dec 2017 14:37:19 -0500 Subject: [PATCH 01/37] fixes compilation flags for OCaml plugins The `-linkall` option is needed for a plugin to be standalone, otherwise it will miss those dependencies that are not used. --- 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 b155fd7c2..03256125c 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1990,7 +1990,7 @@ class MLComponent(Component): out.write('%s.cmxa: %s %s %s %s.cma\n' % (z3mls, cmxs, stubso, z3dllso, z3mls)) out.write('\t%s -o %s -I %s %s %s %s\n' % (OCAMLMKLIB, z3mls, self.sub_dir, stubso, cmxs, LIBZ3)) out.write('%s.cmxs: %s.cmxa\n' % (z3mls, z3mls)) - out.write('\t%s -shared -o %s.cmxs -I %s %s.cmxa\n' % (OCAMLOPTF, z3mls, self.sub_dir, z3mls)) + out.write('\t%s -linkall -shared -o %s.cmxs -I %s %s.cmxa\n' % (OCAMLOPTF, z3mls, self.sub_dir, z3mls)) out.write('\n') out.write('ml: %s.cma %s.cmxa %s.cmxs\n' % (z3mls, z3mls, z3mls)) From 5a479fca76d6e249490c7a9b42d9431318ddb6c9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 13 Dec 2017 13:48:24 -0800 Subject: [PATCH 02/37] generalize model finder code to be independent of conjunction elimination Signed-off-by: Nikolaj Bjorner --- src/smt/smt_model_finder.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 11202d58a..28a65f898 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -2272,10 +2272,9 @@ namespace smt { process_literal(atom, pol == NEG); } - void process_or(app * n, polarity p) { - unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) - visit_formula(n->get_arg(i), p); + void process_and_or(app * n, polarity p) { + for (expr* arg : *n) + visit_formula(arg, p); } void process_ite(app * n, polarity p) { @@ -2306,13 +2305,13 @@ namespace smt { if (is_app(curr)) { if (to_app(curr)->get_family_id() == m_manager.get_basic_family_id() && m_manager.is_bool(curr)) { switch (static_cast(to_app(curr)->get_decl_kind())) { - case OP_AND: case OP_IMPLIES: case OP_XOR: UNREACHABLE(); // simplifier eliminated ANDs, IMPLIEs, and XORs break; case OP_OR: - process_or(to_app(curr), pol); + case OP_AND: + process_and_or(to_app(curr), pol); break; case OP_NOT: visit_formula(to_app(curr)->get_arg(0), neg(pol)); From 58c6cb87c3bc26824fd2386e2eeb74bb3a826537 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Dec 2017 11:48:22 -0800 Subject: [PATCH 03/37] small improvements to QF_NIA tactic Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_nl.h | 1 + src/tactic/smtlogics/qfnia_tactic.cpp | 35 +++++++++++++++++++++------ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 230b6de77..87b811e8f 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -711,6 +711,7 @@ namespace smt { if (ctx.is_relevant(get_enode(*it)) && !check_monomial_assignment(*it, computed_epsilon)) { TRACE("non_linear_failed", tout << "check_monomial_assignment failed for:\n" << mk_ismt2_pp(var2expr(*it), get_manager()) << "\n"; display_var(tout, *it);); + return false; } } diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 3fb733ca4..f0a4ceb57 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -26,8 +26,10 @@ Notes: #include "tactic/bv/max_bv_sharing_tactic.h" #include "sat/tactic/sat_tactic.h" #include "tactic/arith/nla2bv_tactic.h" +#include "tactic/arith/elim01_tactic.h" #include "tactic/core/ctx_simplify_tactic.h" #include "tactic/core/cofactor_term_ite_tactic.h" +#include "nlsat/tactic/qfnra_nlsat_tactic.h" static tactic * mk_qfnia_bv_solver(ast_manager & m, params_ref const & p_ref) { params_ref p = p_ref; @@ -61,8 +63,6 @@ static tactic * mk_qfnia_premable(ast_manager & m, params_ref const & p_ref) { ctx_simp_p.set_uint("max_depth", 30); ctx_simp_p.set_uint("max_steps", 5000000); - params_ref simp_p = p_ref; - simp_p.set_bool("hoist_mul", true); params_ref elim_p = p_ref; elim_p.set_uint("max_memory",20); @@ -73,21 +73,42 @@ static tactic * mk_qfnia_premable(ast_manager & m, params_ref const & p_ref) { using_params(mk_ctx_simplify_tactic(m), ctx_simp_p), using_params(mk_simplify_tactic(m), pull_ite_p), mk_elim_uncnstr_tactic(m), - skip_if_failed(using_params(mk_cofactor_term_ite_tactic(m), elim_p)), - using_params(mk_simplify_tactic(m), simp_p)); + mk_elim01_tactic(m), + skip_if_failed(using_params(mk_cofactor_term_ite_tactic(m), elim_p))); } static tactic * mk_qfnia_sat_solver(ast_manager & m, params_ref const & p) { params_ref nia2sat_p = p; - nia2sat_p.set_uint("nla2bv_max_bv_size", 64); + nia2sat_p.set_uint("nla2bv_max_bv_size", 64); + params_ref simp_p = p; + simp_p.set_bool("hoist_mul", true); // hoist multipliers to create smaller circuits. - return and_then(mk_nla2bv_tactic(m, nia2sat_p), + return and_then(using_params(mk_simplify_tactic(m), simp_p), + mk_nla2bv_tactic(m, nia2sat_p), mk_qfnia_bv_solver(m, p), mk_fail_if_undecided_tactic()); } +static tactic * mk_qfnia_nlsat_solver(ast_manager & m, params_ref const & p) { + params_ref nia2sat_p = p; + nia2sat_p.set_uint("nla2bv_max_bv_size", 64); + params_ref simp_p = p; + simp_p.set_bool("som", true); // expand into sums of monomials + simp_p.set_bool("factor", false); + + + return and_then(using_params(mk_simplify_tactic(m), simp_p), + try_for(mk_qfnra_nlsat_tactic(m, simp_p), 10000), + mk_fail_if_undecided_tactic()); +} + tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { + params_ref simp_p = p; + simp_p.set_bool("som", true); // expand into sums of monomials + return and_then(mk_qfnia_premable(m, p), or_else(mk_qfnia_sat_solver(m, p), - mk_smt_tactic())); + mk_qfnia_nlsat_solver(m, p), + and_then(using_params(mk_simplify_tactic(m), simp_p), + mk_smt_tactic()))); } From e5fa35e969283027e6ca4b75a5dc5ee493c2e5e9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Dec 2017 17:07:17 -0800 Subject: [PATCH 04/37] add integer branch and bound to nlsat Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_interval_set.cpp | 4 +- src/nlsat/nlsat_interval_set.h | 2 +- src/nlsat/nlsat_solver.cpp | 70 ++++++++++++++++++++++++--- src/tactic/smtlogics/qfnia_tactic.cpp | 2 +- 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index 2028095f4..090f94eeb 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -672,14 +672,14 @@ namespace nlsat { return new_set; } - void interval_set_manager::peek_in_complement(interval_set const * s, anum & w, bool randomize) { + void interval_set_manager::peek_in_complement(interval_set const * s, bool is_int, anum & w, bool randomize) { SASSERT(!is_full(s)); if (s == 0) { if (randomize) { int num = m_rand() % 2 == 0 ? 1 : -1; #define MAX_RANDOM_DEN_K 4 int den_k = (m_rand() % MAX_RANDOM_DEN_K); - int den = 1 << den_k; + int den = is_int ? 1 : (1 << den_k); scoped_mpq _w(m_am.qm()); m_am.qm().set(_w, num, den); m_am.set(w, _w); diff --git a/src/nlsat/nlsat_interval_set.h b/src/nlsat/nlsat_interval_set.h index 24b2ab37f..363d48de9 100644 --- a/src/nlsat/nlsat_interval_set.h +++ b/src/nlsat/nlsat_interval_set.h @@ -108,7 +108,7 @@ namespace nlsat { \pre !is_full(s) */ - void peek_in_complement(interval_set const * s, anum & w, bool randomize); + void peek_in_complement(interval_set const * s, bool is_int, anum & w, bool randomize); }; typedef obj_ref interval_set_ref; diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index c5e9babae..0ccaa2f2c 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -903,15 +903,18 @@ namespace nlsat { */ lbool value(literal l) { lbool val = assigned_value(l); - if (val != l_undef) + if (val != l_undef) { return val; + } bool_var b = l.var(); atom * a = m_atoms[b]; - if (a == 0) + if (a == 0) { return l_undef; + } var max = a->max_var(); - if (!m_assignment.is_assigned(max)) + if (!m_assignment.is_assigned(max)) { return l_undef; + } val = to_lbool(m_evaluator.eval(a, l.sign())); TRACE("value_bug", tout << "value of: "; display(tout, l); tout << " := " << val << "\n"; tout << "xk: " << m_xk << ", a->max_var(): " << a->max_var() << "\n"; @@ -1168,7 +1171,7 @@ namespace nlsat { void select_witness() { scoped_anum w(m_am); SASSERT(!m_ism.is_full(m_infeasible[m_xk])); - m_ism.peek_in_complement(m_infeasible[m_xk], w, m_randomize); + m_ism.peek_in_complement(m_infeasible[m_xk], m_is_int[m_xk], w, m_randomize); TRACE("nlsat", tout << "infeasible intervals: "; m_ism.display(tout, m_infeasible[m_xk]); tout << "\n"; tout << "assigning "; m_display_var(tout, m_xk); tout << "(x" << m_xk << ") -> " << w << "\n";); @@ -1232,6 +1235,61 @@ namespace nlsat { } } + lbool search_check() { + lbool r = l_undef; + while (true) { + r = search(); + if (r != l_true) break; + random_gen r(++m_random_seed); + unsigned start = r(num_vars()); + for (var y = 0; y < num_vars(); y++) { + var x = (y + start) % num_vars(); + if (m_is_int[x] && m_assignment.is_assigned(x) && !m_am.is_int(m_assignment.value(x))) { + scoped_anum v(m_am), vlo(m_am), vhi(m_am); + rational lo, hi; + bool is_even = false; + v = m_assignment.value(x); + init_search(); + m_am.int_lt(v, vlo); + m_am.int_gt(v, vhi); + if (!m_am.is_int(vlo)) break; + if (!m_am.is_int(vhi)) break; + m_am.to_rational(vlo, lo); + m_am.to_rational(vhi, hi); + + // derive tight bounds. + while (true) { + lo++; + if (!m_am.gt(v, lo.to_mpq())) { lo--; break; } + } + while (true) { + hi--; + if (!m_am.lt(v, hi.to_mpq())) { hi++; break; } + } + + polynomial_ref p(m_pm); + rational one(1); + m_lemma.reset(); + p = m_pm.mk_linear(1, &one, &x, -lo); + poly* p1 = p.get(); + m_lemma.push_back(~mk_ineq_literal(atom::GT, 1, &p1, &is_even)); + p = m_pm.mk_linear(1, &one, &x, -hi); + poly* p2 = p.get(); + m_lemma.push_back(~mk_ineq_literal(atom::LT, 1, &p2, &is_even)); + + // perform branch and bound + clause * cls = mk_clause(m_lemma.size(), m_lemma.c_ptr(), false, 0); + if (cls) { + TRACE("nlsat", display(tout << "conflict " << lo << " " << hi, *cls); tout << "\n";); + } + r = l_undef; + break; + } + } + } + return r; + } + lbool check() { TRACE("nlsat_smt2", display_smt2(tout);); TRACE("nlsat_fd", tout << "is_full_dimensional: " << is_full_dimensional() << "\n";); @@ -1250,7 +1308,7 @@ namespace nlsat { reordered = true; } sort_watched_clauses(); - lbool r = search(); + lbool r = search_check(); CTRACE("nlsat_model", r == l_true, tout << "model before restore order\n"; display_assignment(tout);); if (reordered) restore_order(); @@ -1929,7 +1987,7 @@ namespace nlsat { for (var x = 0; x < num; x++) { p.push_back(x); } - random_gen r(m_random_seed); + random_gen r(++m_random_seed); shuffle(p.size(), p.c_ptr(), r); reorder(p.size(), p.c_ptr()); } diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index f0a4ceb57..b4f25243a 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -107,7 +107,7 @@ tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { simp_p.set_bool("som", true); // expand into sums of monomials return and_then(mk_qfnia_premable(m, p), - or_else(mk_qfnia_sat_solver(m, p), + or_else(// mk_qfnia_sat_solver(m, p), mk_qfnia_nlsat_solver(m, p), and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic()))); From 1dac5bd45973c5954f29db23fbb77c429ddf7395 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Dec 2017 17:07:52 -0800 Subject: [PATCH 05/37] remove comment out Signed-off-by: Nikolaj Bjorner --- src/tactic/smtlogics/qfnia_tactic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index b4f25243a..f0a4ceb57 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -107,7 +107,7 @@ tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { simp_p.set_bool("som", true); // expand into sums of monomials return and_then(mk_qfnia_premable(m, p), - or_else(// mk_qfnia_sat_solver(m, p), + or_else(mk_qfnia_sat_solver(m, p), mk_qfnia_nlsat_solver(m, p), and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic()))); From ab39f06df7833f1f3a47efbac2e7e8db3741c5d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Dec 2017 17:22:49 -0800 Subject: [PATCH 06/37] fix crashes in nlsat Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 9 ++++++--- src/tactic/smtlogics/qfnia_tactic.cpp | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 0ccaa2f2c..0e3bf8c95 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -734,8 +734,10 @@ namespace nlsat { void undo_set_updt(interval_set * old_set) { SASSERT(m_xk != null_var); var x = m_xk; - m_ism.dec_ref(m_infeasible[x]); - m_infeasible[x] = old_set; + if (x < m_infeasible.size() && m_infeasible[x]) { + m_ism.dec_ref(m_infeasible[x]); + m_infeasible[x] = old_set; + } } void undo_new_stage() { @@ -757,7 +759,8 @@ namespace nlsat { void undo_updt_eq(atom * a) { SASSERT(m_xk != null_var); - m_var2eq[m_xk] = a; + if (m_var2eq.size() > m_xk) + m_var2eq[m_xk] = a; } template diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index f0a4ceb57..3b890b632 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -107,8 +107,8 @@ tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { simp_p.set_bool("som", true); // expand into sums of monomials return and_then(mk_qfnia_premable(m, p), - or_else(mk_qfnia_sat_solver(m, p), - mk_qfnia_nlsat_solver(m, p), + or_else(mk_qfnia_nlsat_solver(m, p), + mk_qfnia_sat_solver(m, p), and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic()))); } From 1c3d385c253b94b1932adf769a0059d1fad58b65 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 14 Dec 2017 17:24:13 -0800 Subject: [PATCH 07/37] fix crashes in nlsat Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 0e3bf8c95..da4f9646d 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -734,7 +734,7 @@ namespace nlsat { void undo_set_updt(interval_set * old_set) { SASSERT(m_xk != null_var); var x = m_xk; - if (x < m_infeasible.size() && m_infeasible[x]) { + if (x < m_infeasible.size()) { m_ism.dec_ref(m_infeasible[x]); m_infeasible[x] = old_set; } From 397cdfc608229a745879aa34ac191b56a79b3c6b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Dec 2017 06:38:56 -0800 Subject: [PATCH 08/37] avoid crash on nl Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 6 ++---- src/tactic/portfolio/default_tactic.cpp | 2 +- src/tactic/smtlogics/quant_tactics.cpp | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index da4f9646d..8f61fffac 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -732,7 +732,7 @@ namespace nlsat { } void undo_set_updt(interval_set * old_set) { - SASSERT(m_xk != null_var); + if (m_xk == null_var) return; var x = m_xk; if (x < m_infeasible.size()) { m_ism.dec_ref(m_infeasible[x]); @@ -741,8 +741,7 @@ namespace nlsat { } void undo_new_stage() { - SASSERT(m_xk != null_var); - if (m_xk == 0) { + if (m_xk == 0 || m_xk == null_var) { m_xk = null_var; } else { @@ -758,7 +757,6 @@ namespace nlsat { } void undo_updt_eq(atom * a) { - SASSERT(m_xk != null_var); if (m_var2eq.size() > m_xk) m_var2eq[m_xk] = a; } diff --git a/src/tactic/portfolio/default_tactic.cpp b/src/tactic/portfolio/default_tactic.cpp index 420cb961a..09052869b 100644 --- a/src/tactic/portfolio/default_tactic.cpp +++ b/src/tactic/portfolio/default_tactic.cpp @@ -41,8 +41,8 @@ tactic * mk_default_tactic(ast_manager & m, params_ref const & p) { cond(mk_is_qflra_probe(), mk_qflra_tactic(m), cond(mk_is_qfnra_probe(), mk_qfnra_tactic(m), cond(mk_is_qfnia_probe(), mk_qfnia_tactic(m), - cond(mk_is_nra_probe(), mk_nra_tactic(m), cond(mk_is_lira_probe(), mk_lira_tactic(m, p), + cond(mk_is_nra_probe(), mk_nra_tactic(m), cond(mk_is_qffp_probe(), mk_qffp_tactic(m, p), //cond(mk_is_qfufnra_probe(), mk_qfufnra_tactic(m, p), mk_smt_tactic()))))))))))), diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp index 400089a0c..8438d1a32 100644 --- a/src/tactic/smtlogics/quant_tactics.cpp +++ b/src/tactic/smtlogics/quant_tactics.cpp @@ -24,7 +24,6 @@ Revision History: #include "qe/qe_tactic.h" #include "qe/qe_lite.h" #include "qe/qsat.h" -#include "qe/nlqsat.h" #include "tactic/core/ctx_simplify_tactic.h" #include "smt/tactic/smt_tactic.h" #include "tactic/core/elim_term_ite_tactic.h" From 21f685fa5a4a6f20e27bb0eb86828c0e553138dc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Dec 2017 06:54:02 -0800 Subject: [PATCH 09/37] fix nlsat regression Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 87 +++++++++++++-------------- src/tactic/smtlogics/qfnia_tactic.cpp | 2 +- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 8f61fffac..c088c406b 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -732,19 +732,19 @@ namespace nlsat { } void undo_set_updt(interval_set * old_set) { - if (m_xk == null_var) return; + if (m_xk == null_var) return; var x = m_xk; - if (x < m_infeasible.size()) { - m_ism.dec_ref(m_infeasible[x]); - m_infeasible[x] = old_set; - } + if (x < m_infeasible.size()) { + m_ism.dec_ref(m_infeasible[x]); + m_infeasible[x] = old_set; + } } void undo_new_stage() { - if (m_xk == 0 || m_xk == null_var) { + if (m_xk == 0) { m_xk = null_var; } - else { + else if (m_xk != null_var) { m_xk--; m_assignment.reset(m_xk); } @@ -757,7 +757,7 @@ namespace nlsat { } void undo_updt_eq(atom * a) { - if (m_var2eq.size() > m_xk) + if (m_var2eq.size() > m_xk) m_var2eq[m_xk] = a; } @@ -1241,50 +1241,47 @@ namespace nlsat { while (true) { r = search(); if (r != l_true) break; - random_gen r(++m_random_seed); - unsigned start = r(num_vars()); - for (var y = 0; y < num_vars(); y++) { - var x = (y + start) % num_vars(); - if (m_is_int[x] && m_assignment.is_assigned(x) && !m_am.is_int(m_assignment.value(x))) { - scoped_anum v(m_am), vlo(m_am), vhi(m_am); - rational lo, hi; - bool is_even = false; - v = m_assignment.value(x); - init_search(); - m_am.int_lt(v, vlo); - m_am.int_gt(v, vhi); - if (!m_am.is_int(vlo)) break; - if (!m_am.is_int(vhi)) break; - m_am.to_rational(vlo, lo); - m_am.to_rational(vhi, hi); + vector lows; + vector vars; + for (var x = 0; x < num_vars(); x++) { + if (m_is_int[x] && m_assignment.is_assigned(x) && !m_am.is_int(m_assignment.value(x))) { + scoped_anum v(m_am), vlo(m_am); + v = m_assignment.value(x); + rational lo; + m_am.int_lt(v, vlo); + if (!m_am.is_int(vlo)) continue; // derive tight bounds. while (true) { lo++; if (!m_am.gt(v, lo.to_mpq())) { lo--; break; } } - while (true) { - hi--; - if (!m_am.lt(v, hi.to_mpq())) { hi++; break; } - } - - polynomial_ref p(m_pm); - rational one(1); - m_lemma.reset(); - p = m_pm.mk_linear(1, &one, &x, -lo); - poly* p1 = p.get(); - m_lemma.push_back(~mk_ineq_literal(atom::GT, 1, &p1, &is_even)); - p = m_pm.mk_linear(1, &one, &x, -hi); - poly* p2 = p.get(); - m_lemma.push_back(~mk_ineq_literal(atom::LT, 1, &p2, &is_even)); + lows.push_back(lo); + vars.push_back(x); + } + } + if (lows.empty()) break; - // perform branch and bound - clause * cls = mk_clause(m_lemma.size(), m_lemma.c_ptr(), false, 0); - if (cls) { - TRACE("nlsat", display(tout << "conflict " << lo << " " << hi, *cls); tout << "\n";); - } - r = l_undef; - break; + init_search(); + for (unsigned i = 0; i < lows.size(); ++i) { + rational lo = lows[i]; + rational hi = lo + rational::one(); + var x = vars[i]; + bool is_even = false; + polynomial_ref p(m_pm); + rational one(1); + m_lemma.reset(); + p = m_pm.mk_linear(1, &one, &x, -lo); + poly* p1 = p.get(); + m_lemma.push_back(~mk_ineq_literal(atom::GT, 1, &p1, &is_even)); + p = m_pm.mk_linear(1, &one, &x, -hi); + poly* p2 = p.get(); + m_lemma.push_back(~mk_ineq_literal(atom::LT, 1, &p2, &is_even)); + + // perform branch and bound + clause * cls = mk_clause(m_lemma.size(), m_lemma.c_ptr(), false, 0); + if (cls) { + TRACE("nlsat", display(tout << "conflict " << lo << " " << hi, *cls); tout << "\n";); } } } diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 3b890b632..5374ba1c1 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -98,7 +98,7 @@ static tactic * mk_qfnia_nlsat_solver(ast_manager & m, params_ref const & p) { return and_then(using_params(mk_simplify_tactic(m), simp_p), - try_for(mk_qfnra_nlsat_tactic(m, simp_p), 10000), + try_for(mk_qfnra_nlsat_tactic(m, simp_p), 3000), mk_fail_if_undecided_tactic()); } From c3add4eeda15dd44d8afe7423b0037dec34e9c8d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 15 Dec 2017 06:56:36 -0800 Subject: [PATCH 10/37] add back missing initialization of lo Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index c088c406b..e1dadf12b 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -1251,6 +1251,7 @@ namespace nlsat { rational lo; m_am.int_lt(v, vlo); if (!m_am.is_int(vlo)) continue; + m_am.to_rational(vlo, lo); // derive tight bounds. while (true) { lo++; From b0aaa4c6d7a739eb5e8e56a73e0486df46483222 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 18 Dec 2017 14:18:30 +0000 Subject: [PATCH 11/37] Updated release notes --- RELEASE_NOTES | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index e85e3d8d6..4f10cad26 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -2,6 +2,7 @@ RELEASE NOTES Version 4.6.0 ============= + - New requirements: - C++11 capable compiler to build Z3. - C++ API now requires C++11 or newer. @@ -14,6 +15,10 @@ Version 4.6.0 issuing the command (get-objectives). Pareto front objectives are accessed by issuing multiple (check-sat) calls until it returns unsat. +- Removed features: + - Removed support for SMT-LIB 1.x + + Version 4.5.0 ============= @@ -49,10 +54,9 @@ Version 4.5.0 over compound formulas, introduce a fresh predicate whose arguments are the relevant free variables in the formula and add a rule that uses the fresh predicate in the head and formula in the body. - - minimization of unsat cores is avaialble as an option for the SAT and SMT cores. + - Minimization of unsat cores is available as an option for the SAT and SMT cores. By setting smt.core.minimize=true resp. sat.core.minimize=true - cores produced by these modules are minimized. - + cores produced by these modules are minimized. - A multitude of bugs has been fixed. From 63951b815dec78bf4b49e9e39a1fef8b5e739939 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 18 Dec 2017 18:58:21 +0000 Subject: [PATCH 12/37] Bumped version number. --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 871852c04..0be2de537 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 6) -set(Z3_VERSION_PATCH 0) +set(Z3_VERSION_PATCH 1) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 60b3b7756..8f75e97ed 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 6, 0, 0) + set_version(4, 6, 1, 0) add_lib('util', []) add_lib('lp', ['util'], 'util/lp') add_lib('polynomial', ['util'], 'math/polynomial') From c3c06d756c9fe7a1e9ed06600cb500014977bf99 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Mon, 18 Dec 2017 20:11:18 +0000 Subject: [PATCH 13/37] Documentation fixes. --- doc/mk_api_doc.py | 7 +++++-- src/api/ml/z3.mli | 4 +--- src/api/z3_api.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index a944f2c65..a1a9e64bd 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -226,12 +226,14 @@ try: website_dox_substitutions = {} bullet_point_prefix='\n - ' if Z3PY_ENABLED: + print("Python documentation enabled") website_dox_substitutions['PYTHON_API'] = ( '{prefix}Python API ' '(also available in pydoc format)' ).format( prefix=bullet_point_prefix) else: + print("Python documentation disabled") website_dox_substitutions['PYTHON_API'] = '' if DOTNET_ENABLED: website_dox_substitutions['DOTNET_API'] = ( @@ -250,7 +252,7 @@ try: website_dox_substitutions['JAVA_API'] = '' if ML_ENABLED: website_dox_substitutions['OCAML_API'] = ( - 'ML/OCaml API' + '{prefix}ML/OCaml API' ).format( prefix=bullet_point_prefix) else: @@ -316,7 +318,7 @@ try: if ML_ENABLED: ml_output_dir = os.path.join(OUTPUT_DIRECTORY, 'html', 'ml') mk_dir(ml_output_dir) - if subprocess.call(['ocamldoc', '-html', '-d', ml_output_dir, '-sort', '-hide', 'Z3', '-I', '%s/api/ml' % BUILD_DIR, doc_path('../src/api/ml/z3enums.mli'), doc_path('../src/api/ml/z3.mli')]) != 0: + if subprocess.call(['ocamldoc', '-html', '-d', ml_output_dir, '-sort', '-hide', 'Z3', '-I', '%s/api/ml' % BUILD_DIR, '%s/api/ml/z3enums.mli' % BUILD_DIR, '%s/api/ml/z3.mli' % BUILD_DIR]) != 0: print("ERROR: ocamldoc failed.") exit(1) print("Generated ML/OCaml documentation.") @@ -326,3 +328,4 @@ except Exception: exctype, value = sys.exc_info()[:2] print("ERROR: failed to generate documentation: %s" % value) exit(1) + diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 9f4cd9cd9..80923a0c7 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -3443,12 +3443,10 @@ sig (** Parse the given string using the SMT-LIB2 parser. - {!parse_smtlib_string} @return A conjunction of assertions in the scope (up to push/pop) at the end of the string. *) val parse_smtlib2_string : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr - (** Parse the given file using the SMT-LIB2 parser. - {!parse_smtlib2_string} *) + (** Parse the given file using the SMT-LIB2 parser. *) val parse_smtlib2_file : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr end diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 064476b9b..007bc3ab6 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1331,7 +1331,7 @@ typedef enum { - Z3_IOB: Index out of bounds. - Z3_INVALID_ARG: Invalid argument was provided. - Z3_PARSER_ERROR: An error occurred when parsing a string or file. - - Z3_NO_PARSER: Parser output is not available, that is, user didn't invoke #Z3_parse_smtlib_string or #Z3_parse_smtlib_file. + - Z3_NO_PARSER: Parser output is not available, that is, user didn't invoke #Z3_parse_smtlib2_string or #Z3_parse_smtlib2_file. - Z3_INVALID_PATTERN: Invalid pattern was used to build a quantifier. - Z3_MEMOUT_FAIL: A memory allocation failure was encountered. - Z3_FILE_ACCESS_ERRROR: A file could not be accessed. From 399b27fda3874a3897e8af8d531758e54b71f818 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2017 12:20:44 -0800 Subject: [PATCH 14/37] add Python facility for int2bv, fix #1398 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 237f35433..3bf48b611 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -3568,6 +3568,14 @@ def BV2Int(a, is_signed=False): ## investigate problem with bv2int return ArithRef(Z3_mk_bv2int(ctx.ref(), a.as_ast(), is_signed), ctx) +def Int2BV(a, num_bits): + """Return the z3 expression Int2BV(a, num_bits). + It is a bit-vector of width num_bits and represents the + modulo of a by 2^num_bits + """ + ctx = a.ctx + return BitVecRef(Z3_mk_int2bv(ctx.ref(), num_bits, a.as_ast()), ctx) + def BitVecSort(sz, ctx=None): """Return a Z3 bit-vector sort of the given size. If `ctx=None`, then the global context is used. From d695767f61f752ca8aecfe53792dd0fd1b90ec1e Mon Sep 17 00:00:00 2001 From: bannsec Date: Mon, 18 Dec 2017 21:48:54 +0000 Subject: [PATCH 15/37] Allowing slices and negative index in assertions --- src/api/python/z3/z3.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 3bf48b611..4cc401156 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -5140,9 +5140,18 @@ class AstVector(Z3PPObject): >>> A[1] y """ - if i >= self.__len__(): - raise IndexError - return _to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, i), self.ctx) + + if isinstance(i, int): + if i < 0: + i += self.__len__() + + if i >= self.__len__(): + raise IndexError + return _to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, i), self.ctx) + + elif isinstance(i, slice): + return [_to_ast_ref(Z3_ast_vector_get(self.ctx.ref(), self.vector, ii), self.ctx) for ii in range(*i.indices(self.__len__()))] + def __setitem__(self, i, v): """Update AST at position `i`. From 13ee8da65968d3f111666032f27813eee51e9e66 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2017 15:57:16 -0800 Subject: [PATCH 16/37] add virtual destructor to see if this helps ASan error Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_types.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index 8704f4444..488e16ae9 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -151,6 +151,7 @@ namespace nlsat { class solver_exception : public default_exception { public: solver_exception(char const * msg):default_exception(msg) {} + virtual ~solver_exception() {} }; class assignment; From 517b0812021129377590f2fc2afcbd263461a3ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2017 21:13:03 -0800 Subject: [PATCH 17/37] remove custom exception, perhaps this handles exception issue Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_types.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index 488e16ae9..db3b6ffa5 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -148,11 +148,7 @@ namespace nlsat { typedef algebraic_numbers::anum anum; typedef algebraic_numbers::manager anum_manager; - class solver_exception : public default_exception { - public: - solver_exception(char const * msg):default_exception(msg) {} - virtual ~solver_exception() {} - }; + typedef default_exception solver_exception; class assignment; From 36204fafa09f601052044052e1477b7ad3264005 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Dec 2017 20:27:08 -0800 Subject: [PATCH 18/37] alternate strategies for QF_NIA Signed-off-by: Nikolaj Bjorner --- src/tactic/smtlogics/qflia_tactic.cpp | 1 - src/tactic/smtlogics/qfnia_tactic.cpp | 14 +++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/tactic/smtlogics/qflia_tactic.cpp b/src/tactic/smtlogics/qflia_tactic.cpp index de542f3c4..23ae179e2 100644 --- a/src/tactic/smtlogics/qflia_tactic.cpp +++ b/src/tactic/smtlogics/qflia_tactic.cpp @@ -24,7 +24,6 @@ Notes: #include "tactic/core/solve_eqs_tactic.h" #include "tactic/core/elim_uncnstr_tactic.h" #include "smt/tactic/smt_tactic.h" -// include"mip_tactic.h" #include "tactic/arith/add_bounds_tactic.h" #include "tactic/arith/pb2bv_tactic.h" #include "tactic/arith/lia2pb_tactic.h" diff --git a/src/tactic/smtlogics/qfnia_tactic.cpp b/src/tactic/smtlogics/qfnia_tactic.cpp index 5374ba1c1..d967660ce 100644 --- a/src/tactic/smtlogics/qfnia_tactic.cpp +++ b/src/tactic/smtlogics/qfnia_tactic.cpp @@ -102,13 +102,17 @@ static tactic * mk_qfnia_nlsat_solver(ast_manager & m, params_ref const & p) { mk_fail_if_undecided_tactic()); } -tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { +static tactic * mk_qfnia_smt_solver(ast_manager& m, params_ref const& p) { params_ref simp_p = p; simp_p.set_bool("som", true); // expand into sums of monomials + return and_then(using_params(mk_simplify_tactic(m), simp_p), mk_smt_tactic()); +} + +tactic * mk_qfnia_tactic(ast_manager & m, params_ref const & p) { return and_then(mk_qfnia_premable(m, p), - or_else(mk_qfnia_nlsat_solver(m, p), - mk_qfnia_sat_solver(m, p), - and_then(using_params(mk_simplify_tactic(m), simp_p), - mk_smt_tactic()))); + or_else(mk_qfnia_sat_solver(m, p), + try_for(mk_qfnia_smt_solver(m, p), 2000), + mk_qfnia_nlsat_solver(m, p), + mk_qfnia_smt_solver(m, p))); } From 5bc4c9809e232d63f46018b200cb930bca993ce5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Dec 2017 12:50:11 -0800 Subject: [PATCH 19/37] initialize additional assumptions after setup_context is called the first time Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 59 +++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 3b69d4846..a87042e2b 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3202,10 +3202,8 @@ namespace smt { }); validate_unsat_core(); // theory validation of unsat core - ptr_vector::iterator th_it = m_theory_set.begin(); - ptr_vector::iterator th_end = m_theory_set.end(); - for (; th_it != th_end; ++th_it) { - lbool theory_result = (*th_it)->validate_unsat_core(m_unsat_core); + for (theory* th : m_theory_set) { + lbool theory_result = th->validate_unsat_core(m_unsat_core); if (theory_result == l_undef) { return l_undef; } @@ -3296,10 +3294,8 @@ namespace smt { #ifndef _EXTERNAL_RELEASE if (m_fparams.m_display_installed_theories) { std::cout << "(theories"; - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) { - std::cout << " " << (*it)->get_name(); + for (theory* th : m_theory_set) { + std::cout << " " << th->get_name(); } std::cout << ")" << std::endl; } @@ -3316,17 +3312,13 @@ namespace smt { m_fparams.m_relevancy_lemma = false; // setup all the theories - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) - (*it)->setup(); + for (theory* th : m_theory_set) + th->setup(); } void context::add_theory_assumptions(expr_ref_vector & theory_assumptions) { - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end; ++it) { - (*it)->add_theory_assumptions(theory_assumptions); + for (theory* th : m_theory_set) { + th->add_theory_assumptions(theory_assumptions); } } @@ -3342,18 +3334,7 @@ namespace smt { if (!check_preamble(reset_cancel)) return l_undef; - expr_ref_vector all_assumptions(m_manager, ext_num_assumptions, ext_assumptions); - if (!already_did_theory_assumptions) { - add_theory_assumptions(all_assumptions); - } - - unsigned num_assumptions = all_assumptions.size(); - expr * const * assumptions = all_assumptions.c_ptr(); - - if (!validate_assumptions(num_assumptions, assumptions)) - return l_undef; TRACE("check_bug", tout << "inconsistent: " << inconsistent() << ", m_unsat_core.empty(): " << m_unsat_core.empty() << "\n";); - TRACE("unsat_core_bug", for (unsigned i = 0; i < num_assumptions; i++) { tout << mk_pp(assumptions[i], m_manager) << "\n";}); pop_to_base_lvl(); TRACE("before_search", display(tout);); SASSERT(at_base_level()); @@ -3363,6 +3344,18 @@ namespace smt { } else { setup_context(false); + expr_ref_vector all_assumptions(m_manager, ext_num_assumptions, ext_assumptions); + if (!already_did_theory_assumptions) { + add_theory_assumptions(all_assumptions); + } + + unsigned num_assumptions = all_assumptions.size(); + expr * const * assumptions = all_assumptions.c_ptr(); + + if (!validate_assumptions(num_assumptions, assumptions)) + return l_undef; + TRACE("unsat_core_bug", tout << all_assumptions << "\n";); + internalize_assertions(); TRACE("after_internalize_assertions", display(tout);); if (m_asserted_formulas.inconsistent()) { @@ -3551,10 +3544,9 @@ namespace smt { pop_scope(m_scope_lvl - curr_lvl); SASSERT(at_search_level()); } - ptr_vector::iterator it = m_theory_set.begin(); - ptr_vector::iterator end = m_theory_set.end(); - for (; it != end && !inconsistent(); ++it) - (*it)->restart_eh(); + for (theory* th : m_theory_set) { + if (!inconsistent()) th->restart_eh(); + } TRACE("mbqi_bug_detail", tout << "before instantiating quantifiers...\n";); if (!inconsistent()) { m_qmanager->restart_eh(); @@ -4070,10 +4062,7 @@ namespace smt { bool include = false; if (at_lbls) { // include if there is a label with the '@' sign. - buffer::const_iterator it = lbls.begin(); - buffer::const_iterator end = lbls.end(); - for (; it != end; ++it) { - symbol const & s = *it; + for (symbol const& s : lbls) { if (s.contains('@')) { include = true; break; From d86e8f02d7808fed783a5eedc4d8f5255008c6f4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 27 Dec 2017 10:09:10 -0800 Subject: [PATCH 20/37] fix get-objectives error #1419 message (get-objectives) Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 3d296d92b..0daf98320 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1235,6 +1235,9 @@ namespace opt { } void context::display_assignment(std::ostream& out) { + if (m_scoped_state.m_objectives.size() != m_objectives.size()) { + throw default_exception("check-sat has not been called with latest objectives"); + } out << "(objectives\n"; for (unsigned i = 0; i < m_scoped_state.m_objectives.size(); ++i) { objective const& obj = m_scoped_state.m_objectives[i]; From 79a9dfd8fdd1ff3072fc571286217f788147084c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Dec 2017 20:35:33 -0800 Subject: [PATCH 21/37] adding pre-processing to nlsat for equations Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.h | 4 +- src/math/polynomial/polynomial.cpp | 93 +++- src/math/polynomial/polynomial.h | 35 +- src/nlsat/nlsat_clause.h | 2 + src/nlsat/nlsat_solver.cpp | 631 +++++++++++++++++------- src/nlsat/nlsat_solver.h | 2 +- src/nlsat/nlsat_types.h | 2 + src/nlsat/tactic/nlsat_tactic.cpp | 8 +- src/nlsat/tactic/qfnra_nlsat_tactic.cpp | 4 + src/qe/nlqsat.cpp | 2 +- src/tactic/core/solve_eqs_tactic.cpp | 135 +++-- 11 files changed, 696 insertions(+), 222 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 4b24ea5e6..4850b52a8 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -370,7 +370,7 @@ public: app * mk_lt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LT, arg1, arg2); } app * mk_gt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_GT, arg1, arg2); } - app * mk_add(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_ADD, num_args, args); } + app * mk_add(unsigned num_args, expr * const * args) const { return num_args == 1 && is_app(args[0]) ? to_app(args[0]) : m_manager.mk_app(m_afid, OP_ADD, num_args, args); } app * mk_add(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2); } app * mk_add(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2, arg3); } @@ -378,7 +378,7 @@ public: app * mk_sub(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_SUB, num_args, args); } app * mk_mul(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2); } app * mk_mul(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2, arg3); } - app * mk_mul(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_MUL, num_args, args); } + app * mk_mul(unsigned num_args, expr * const * args) const { return num_args == 1 && is_app(args[0]) ? to_app(args[0]) : m_manager.mk_app(m_afid, OP_MUL, num_args, args); } app * mk_uminus(expr * arg) const { return m_manager.mk_app(m_afid, OP_UMINUS, arg); } app * mk_div(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_DIV, arg1, arg2); } app * mk_idiv(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_IDIV, arg1, arg2); } diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index d6d392148..51d8489e3 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -150,7 +150,6 @@ namespace polynomial { return r; } - /** \brief Monomials (power products) */ @@ -192,7 +191,7 @@ namespace polynomial { }; static unsigned get_obj_size(unsigned sz) { return sizeof(monomial) + sz * sizeof(power); } - + monomial(unsigned id, unsigned sz, power const * pws, unsigned h): m_ref_count(0), m_id(id), @@ -257,9 +256,7 @@ namespace polynomial { if (m_size < SMALL_MONOMIAL) { // use linear search for small monomials // search backwards since we usually ask for the degree of "big" variables - unsigned i = last; - while (i > 0) { - --i; + for (unsigned i = last; i-- > 0; ) { if (get_var(i) == x) return i; } @@ -798,9 +795,8 @@ namespace polynomial { dec_ref(m_unit); CTRACE("polynomial", !m_monomials.empty(), tout << "monomials leaked\n"; - monomial_table::iterator it = m_monomials.begin(); monomial_table::iterator end = m_monomials.end(); - for (; it != end; ++it) { - (*it)->display(tout); tout << "\n"; + for (auto * m : m_monomials) { + m->display(tout); tout << "\n"; }); SASSERT(m_monomials.empty()); if (m_own_allocator) @@ -1510,6 +1506,8 @@ namespace polynomial { unsigned id() const { return m_id; } unsigned size() const { return m_size; } monomial * m(unsigned idx) const { SASSERT(idx < size()); return m_ms[idx]; } + monomial *const* begin() const { return m_ms; } + monomial *const* end() const { return m_ms + size(); } numeral const & a(unsigned idx) const { SASSERT(idx < size()); return m_as[idx]; } numeral & a(unsigned idx) { SASSERT(idx < size()); return m_as[idx]; } numeral const * as() const { return m_as; } @@ -1773,11 +1771,9 @@ namespace polynomial { } bool manager::is_linear(polynomial const * p) { - unsigned sz = p->size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_linear(p->m(0))) + for (monomial* m : *p) + if (!is_linear(m)) return false; - } return true; } @@ -2396,6 +2392,7 @@ namespace polynomial { return mm().is_valid(x); } + void add_del_eh(del_eh * eh) { eh->m_next = m_del_eh; m_del_eh = eh; @@ -6101,6 +6098,33 @@ namespace polynomial { }); } + lbool sign(monomial* m, numeral const& c, svector const& sign_of_vars) { + unsigned sz = size(m); + lbool sign1 = m_manager.is_pos(c) ? l_true : l_false; + for (unsigned i = 0; i < sz; ++i) { + var v = get_var(m, i); + unsigned d = degree(m, i); + lbool sign2 = sign_of_vars.get(v, l_undef); + if (sign2 == l_undef) + return l_undef; + else if (1 == (d % 2) && sign2 == l_false) { + sign1 = sign1 == l_true ? l_false : l_true; + } + } + return sign1; + } + + lbool sign(polynomial const * p, svector const& sign_of_vars) { + unsigned sz = size(p); + if (sz == 0) return l_undef; + lbool sign1 = sign(p->m(0), p->a(0), sign_of_vars); + for (unsigned i = 1; sign1 != l_undef && i < sz; ++i) { + if (sign(p->m(i), p->a(i), sign_of_vars) != sign1) + return l_undef; + } + return sign1; + } + bool is_pos(polynomial const * p) { bool found_unit = false; unsigned sz = p->size(); @@ -6372,6 +6396,31 @@ namespace polynomial { R.add(new_a, mk_monomial(new_m)); } return R.mk(); + } + + void substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) { + unsigned md = degree(r, x); + if (md == 0) { + result = const_cast(r); + return; + } + result = 0; + polynomial_ref p1(pm()), q1(pm()); + polynomial_ref_buffer ps(pm()); + unsigned sz = r->size(); + for (unsigned i = 0; i < sz; i++) { + monomial * m0 = r->m(i); + unsigned dm = m0->degree_of(x); + SASSERT(md >= dm); + monomial_ref m1(div_x(m0, x), pm()); + pw(p, dm, p1); + pw(q, md - dm, q1); + p1 = mul(r->a(i), m1, p1 * q1); + if (result) + result = add(result, p1); + else + result = p1; + } } @@ -6918,6 +6967,18 @@ namespace polynomial { return m_imp->m().set_zp(p); } + bool manager::is_var(polynomial const* p, var& v) { + return p->size() == 1 && is_var(p->m(0), v) && m_imp->m().is_one(p->a(0)); + } + + bool manager::is_var(monomial const* m, var& v) { + return m->size() == 1 && m->degree(0) == 1 && (v = m->get_var(0), true); + } + + bool manager::is_var_num(polynomial const* p, var& v, scoped_numeral& n) { + return p->size() == 2 && m_imp->m().is_one(p->a(0)) && is_var(p->m(0), v) && is_unit(p->m(1)) && (n = p->a(1), true); + } + small_object_allocator & manager::allocator() const { return m_imp->mm().allocator(); } @@ -7271,6 +7332,10 @@ namespace polynomial { void manager::psc_chain(polynomial const * p, polynomial const * q, var x, polynomial_ref_vector & S) { m_imp->psc_chain(p, q, x, S); } + + lbool manager::sign(polynomial const * p, svector const& sign_of_vars) { + return m_imp->sign(p, sign_of_vars); + } bool manager::is_pos(polynomial const * p) { return m_imp->is_pos(p); @@ -7307,6 +7372,10 @@ namespace polynomial { polynomial * manager::substitute(polynomial const * p, unsigned xs_sz, var const * xs, numeral const * vs) { return m_imp->substitute(p, xs_sz, xs, vs); } + + void manager::substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result) { + m_imp->substitute(r, x, p, q, result); + } void manager::factor(polynomial const * p, factors & r, factor_params const & params) { m_imp->factor(p, r, params); diff --git a/src/math/polynomial/polynomial.h b/src/math/polynomial/polynomial.h index 43b3c1138..b09af94bc 100644 --- a/src/math/polynomial/polynomial.h +++ b/src/math/polynomial/polynomial.h @@ -29,6 +29,7 @@ Notes: #include "util/params.h" #include "util/mpbqi.h" #include "util/rlimit.h" +#include "util/lbool.h" class small_object_allocator; @@ -98,7 +99,7 @@ namespace polynomial { }; struct display_var_proc { - virtual void operator()(std::ostream & out, var x) const { out << "x" << x; } + virtual std::ostream& operator()(std::ostream & out, var x) const { return out << "x" << x; } }; class polynomial; @@ -306,12 +307,27 @@ namespace polynomial { \brief Return true if m is linear (i.e., it is of the form 1 or x). */ static bool is_linear(monomial const * m); - + /** \brief Return true if all monomials in p are linear. */ static bool is_linear(polynomial const * p); + /** + \brief Return true if the monomial is a variable. + */ + static bool is_var(monomial const* p, var& v); + + /** + \brief Return true if the polynomial is a variable. + */ + bool is_var(polynomial const* p, var& v); + + /** + \brief Return true if the polynomial is of the form x + k + */ + bool is_var_num(polynomial const* p, var& v, scoped_numeral& n); + /** \brief Return the degree of variable x in p. */ @@ -860,7 +876,13 @@ namespace polynomial { \brief Return true if p is a square, and store its square root in r. */ bool sqrt(polynomial const * p, polynomial_ref & r); - + + + /** + \brief obtain the sign of the polynomial given sign of variables. + */ + lbool sign(polynomial const* p, svector const& sign_of_vars); + /** \brief Return true if p is always positive for any assignment of its variables. @@ -936,6 +958,13 @@ namespace polynomial { return substitute(p, 1, &x, &v); } + /** + \brief Apply substiution [x -> p/q] in r. + That is, given r \in Z[x, y_1, .., y_m] return + polynomial q^k * r(p/q, y_1, .., y_m), where k is the maximal degree of x in r. + */ + void substitute(polynomial const* r, var x, polynomial const* p, polynomial const* q, polynomial_ref& result); + /** \brief Factorize the given polynomial p and store its factors in r. */ diff --git a/src/nlsat/nlsat_clause.h b/src/nlsat/nlsat_clause.h index 898c32449..93dfb0e80 100644 --- a/src/nlsat/nlsat_clause.h +++ b/src/nlsat/nlsat_clause.h @@ -44,6 +44,8 @@ namespace nlsat { bool is_learned() const { return m_learned; } literal * begin() { return m_lits; } literal * end() { return m_lits + m_size; } + literal const * begin() const { return m_lits; } + literal const * end() const { return m_lits + m_size; } literal const * c_ptr() const { return m_lits; } void inc_activity() { m_activity++; } void set_activity(unsigned v) { m_activity = v; } diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index e1dadf12b..4cba6d123 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -18,19 +18,20 @@ Author: Revision History: --*/ +#include "util/z3_exception.h" +#include "util/chashtable.h" +#include "util/id_gen.h" +#include "util/map.h" +#include "util/dependency.h" +#include "util/permutation.h" +#include "math/polynomial/algebraic_numbers.h" +#include "math/polynomial/polynomial_cache.h" #include "nlsat/nlsat_solver.h" #include "nlsat/nlsat_clause.h" #include "nlsat/nlsat_assignment.h" #include "nlsat/nlsat_justification.h" #include "nlsat/nlsat_evaluator.h" #include "nlsat/nlsat_explain.h" -#include "math/polynomial/algebraic_numbers.h" -#include "util/z3_exception.h" -#include "util/chashtable.h" -#include "util/id_gen.h" -#include "util/dependency.h" -#include "math/polynomial/polynomial_cache.h" -#include "util/permutation.h" #include "nlsat/nlsat_params.hpp" #define NLSAT_EXTRA_VERBOSE @@ -68,6 +69,7 @@ namespace nlsat { reslimit& m_rlimit; small_object_allocator m_allocator; + bool m_incremental; unsynch_mpq_manager m_qm; pmanager m_pm; cache m_cache; @@ -78,6 +80,8 @@ namespace nlsat { interval_set_manager & m_ism; ineq_atom_table m_ineq_atoms; root_atom_table m_root_atoms; + svector m_patch_var; + polynomial_ref_vector m_patch_num, m_patch_denom; id_gen m_cid_gen; clause_vector m_clauses; // set of clauses @@ -108,11 +112,12 @@ namespace nlsat { m_perm(perm), m_proc(0) { } - virtual void operator()(std::ostream & out, var x) const { + std::ostream& operator()(std::ostream & out, var x) const { if (m_proc == 0) m_default_display_var(out, x); else (*m_proc)(out, m_perm[x]); + return out; } }; perm_display_var_proc m_display_var; @@ -158,9 +163,10 @@ namespace nlsat { unsigned m_stages; unsigned m_irrational_assignments; // number of irrational witnesses - imp(solver& s, reslimit& rlim, params_ref const & p): + imp(solver& s, reslimit& rlim, params_ref const & p, bool incremental): m_rlimit(rlim), m_allocator("nlsat"), + m_incremental(incremental), m_pm(rlim, m_qm, &m_allocator), m_cache(m_pm), m_am(rlim, m_qm, p, &m_allocator), @@ -168,6 +174,8 @@ namespace nlsat { m_assignment(m_am), m_evaluator(s, m_assignment, m_pm, m_allocator), m_ism(m_evaluator.ism()), + m_patch_num(m_pm), + m_patch_denom(m_pm), m_num_bool_vars(0), m_display_var(m_perm), m_explain(s, m_assignment, m_cache, m_atoms, m_var2eq, m_evaluator), @@ -330,9 +338,7 @@ namespace nlsat { */ bool_var max_bvar(clause const & cls) const { bool_var b = null_bool_var; - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { - literal l = cls[i]; + for (literal l : cls) { if (b == null_bool_var || l.var() > b) b = l.var(); } @@ -367,9 +373,7 @@ namespace nlsat { if (x == null_var) return 0; unsigned max = 0; - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - literal l = c[i]; + for (literal l : c) { atom const * a = m_atoms[l.var()]; if (a == 0) continue; @@ -496,13 +500,12 @@ namespace nlsat { // Delete atoms with ref_count == 0 void del_unref_atoms() { - unsigned sz = m_atoms.size(); - for (unsigned i = 0; i < sz; i++) { - del(m_atoms[i]); + for (auto* a : m_atoms) { + del(a); } } - bool_var mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { + ineq_atom* mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even, bool& is_new) { SASSERT(sz >= 1); SASSERT(k == atom::LT || k == atom::GT || k == atom::EQ); int sign = 1; @@ -522,23 +525,36 @@ namespace nlsat { void * mem = m_allocator.allocate(ineq_atom::get_obj_size(sz)); if (sign < 0) k = atom::flip(k); - ineq_atom * new_atom = new (mem) ineq_atom(k, sz, uniq_ps.c_ptr(), is_even, max); + ineq_atom * tmp_atom = new (mem) ineq_atom(k, sz, uniq_ps.c_ptr(), is_even, max); TRACE("nlsat_table_bug", ineq_atom::hash_proc h; - tout << "mk_ineq_atom hash: " << h(new_atom) << "\n"; display(tout, *new_atom, m_display_var); tout << "\n";); - ineq_atom * old_atom = m_ineq_atoms.insert_if_not_there(new_atom); - CTRACE("nlsat_table_bug", old_atom->max_var() != max, display(tout, *old_atom, m_display_var); tout << "\n";); - SASSERT(old_atom->max_var() == max); - if (old_atom != new_atom) { - deallocate(new_atom); - return old_atom->bvar(); + tout << "mk_ineq_atom hash: " << h(tmp_atom) << "\n"; display(tout, *tmp_atom, m_display_var); tout << "\n";); + ineq_atom * atom = m_ineq_atoms.insert_if_not_there(tmp_atom); + CTRACE("nlsat_table_bug", atom->max_var() != max, display(tout, *atom, m_display_var); tout << "\n";); + SASSERT(atom->max_var() == max); + is_new = (atom == tmp_atom); + if (is_new) { + for (unsigned i = 0; i < sz; i++) { + m_pm.inc_ref(atom->p(i)); + } } - bool_var b = mk_bool_var_core(); - m_atoms[b] = new_atom; - new_atom->m_bool_var = b; - for (unsigned i = 0; i < sz; i++) { - m_pm.inc_ref(new_atom->p(i)); + else { + deallocate(tmp_atom); + } + return atom; + } + + bool_var mk_ineq_atom(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { + bool is_new = false; + ineq_atom* atom = mk_ineq_atom(k, sz, ps, is_even, is_new); + if (!is_new) { + return atom->bvar(); + } + else { + bool_var b = mk_bool_var_core(); + m_atoms[b] = atom; + atom->m_bool_var = b; + return b; } - return b; } literal mk_ineq_literal(atom::kind k, unsigned sz, poly * const * ps, bool const * is_even) { @@ -619,10 +635,14 @@ namespace nlsat { deallocate(cls); } + void del_clause(clause * cls, clause_vector& clauses) { + clauses.erase(cls); + del_clause(cls); + } + void del_clauses(ptr_vector & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) - del_clause(cs[i]); + for (clause* cp : cs) + del_clause(cp); } void del_clauses() { @@ -927,10 +947,9 @@ namespace nlsat { \brief Return true if the given clause is already satisfied in the current partial interpretation. */ bool is_satisfied(clause const & cls) const { - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { - if (const_cast(this)->value(cls[i]) == l_true) { - TRACE("value_bug:", tout << cls[i] << " := true\n";); + for (literal l : cls) { + if (const_cast(this)->value(l) == l_true) { + TRACE("value_bug:", tout << l << " := true\n";); return true; } } @@ -1023,7 +1042,7 @@ namespace nlsat { SASSERT(x != null_var); if (m_var2eq[x] != 0 && degree(m_var2eq[x]) <= degree(a)) return; // we only update m_var2eq if the new equality has smaller degree - TRACE("simplify_core", tout << "Saving equality for "; m_display_var(tout, x); tout << " (x" << x << ") "; + TRACE("simplify_core", tout << "Saving equality for "; m_display_var(tout, x) << " (x" << x << ") "; tout << "scope-lvl: " << scope_lvl() << "\n"; display(tout, literal(b, false)); tout << "\n";); save_updt_eq_trail(m_var2eq[x]); m_var2eq[x] = a; @@ -1045,10 +1064,9 @@ namespace nlsat { interval_set_ref first_undef_set(m_ism); // infeasible region of the first undefined literal interval_set * xk_set = m_infeasible[m_xk]; // current set of infeasible interval for current variable SASSERT(!m_ism.is_full(xk_set)); - unsigned sz = cls.size(); - for (unsigned i = 0; i < sz; i++) { + for (unsigned idx = 0; idx < cls.size(); ++idx) { + literal l = cls[idx]; checkpoint(); - literal l = cls[i]; if (value(l) == l_false) continue; SASSERT(value(l) == l_undef); @@ -1085,7 +1103,7 @@ namespace nlsat { } num_undef++; if (first_undef == UINT_MAX) { - first_undef = i; + first_undef = idx; first_undef_set = curr_set; } } @@ -1131,9 +1149,7 @@ namespace nlsat { Return 0, if the set was satisfied, or the violating clause otherwise */ clause * process_clauses(clause_vector const & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause * c = cs[i]; + for (clause* c : cs) { if (!process_clause(*c, false)) return c; } @@ -1175,7 +1191,7 @@ namespace nlsat { m_ism.peek_in_complement(m_infeasible[m_xk], m_is_int[m_xk], w, m_randomize); TRACE("nlsat", tout << "infeasible intervals: "; m_ism.display(tout, m_infeasible[m_xk]); tout << "\n"; - tout << "assigning "; m_display_var(tout, m_xk); tout << "(x" << m_xk << ") -> " << w << "\n";); + tout << "assigning "; m_display_var(tout, m_xk) << "(x" << m_xk << ") -> " << w << "\n";); TRACE("nlsat_root", tout << "value as root object: "; m_am.display_root(tout, w); tout << "\n";); if (!m_am.is_rational(w)) m_irrational_assignments++; @@ -1205,6 +1221,7 @@ namespace nlsat { TRACE("nlsat_bug", tout << "xk: x" << m_xk << " bk: b" << m_bk << "\n";); if (m_bk == null_bool_var && m_xk >= num_vars()) { TRACE("nlsat", tout << "found model\n"; display_assignment(tout);); + fix_patch(); return l_true; // all variables were assigned, and all clauses were satisfied. } TRACE("nlsat", tout << "processing variable "; @@ -1295,6 +1312,13 @@ namespace nlsat { init_search(); m_explain.set_full_dimensional(is_full_dimensional()); bool reordered = false; + +#if 0 + // disabled + if (!m_incremental) + simplify(); +#endif + if (!can_reorder()) { } @@ -1497,9 +1521,9 @@ namespace nlsat { TRACE("nlsat_mathematica", display_mathematica_lemma(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr());); TRACE("nlsat_proof_sk", tout << "theory lemma\n"; display_abst(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()); tout << "\n";); TRACE("nlsat_resolve", - tout << "m_xk: " << m_xk << ", "; m_display_var(tout, m_xk); tout << "\n"; + tout << "m_xk: " << m_xk << ", "; m_display_var(tout, m_xk) << "\n"; tout << "new valid clause:\n"; - display(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()); tout << "\n";); + display(tout, m_lazy_clause.size(), m_lazy_clause.c_ptr()) << "\n";); DEBUG_CODE({ unsigned sz = m_lazy_clause.size(); @@ -1633,15 +1657,10 @@ namespace nlsat { TRACE("nlsat_proof", tout << "STARTING RESOLUTION\n";); TRACE("nlsat_proof_sk", tout << "STARTING RESOLUTION\n";); m_conflicts++; - TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause); tout << "\n"; + TRACE("nlsat", tout << "resolve, conflicting clause:\n"; display(tout, *conflict_clause) << "\n"; tout << "xk: "; if (m_xk != null_var) m_display_var(tout, m_xk); else tout << ""; tout << "\n"; tout << "scope_lvl: " << scope_lvl() << "\n"; tout << "current assignment\n"; display_assignment(tout);); - - // static unsigned counter = 0; - // counter++; - // if (counter > 6) - // exit(0); m_num_marks = 0; m_lemma.reset(); @@ -1750,7 +1769,7 @@ namespace nlsat { SASSERT(m_xk == new_max_var); new_cls = mk_clause(sz, m_lemma.c_ptr(), true, m_lemma_assumptions.get()); TRACE("nlsat", tout << "new_level: " << scope_lvl() << "\nnew_stage: " << new_max_var << " "; - if (new_max_var != null_var) m_display_var(tout, new_max_var); tout << "\n";); + if (new_max_var != null_var) m_display_var(tout, new_max_var) << "\n";); } else { SASSERT(scope_lvl() >= 1); @@ -1931,11 +1950,12 @@ namespace nlsat { collect(*(cs[i])); } - void display(std::ostream & out, display_var_proc const & proc) { + std::ostream& display(std::ostream & out, display_var_proc const & proc) { unsigned sz = m_num_occs.size(); for (unsigned i = 0; i < sz; i++) { proc(out, i); out << " -> " << m_max_degree[i] << " : " << m_num_occs[i] << "\n"; } + return out; } }; @@ -2169,12 +2189,10 @@ namespace nlsat { } void reattach_arith_clauses(clause_vector const & cs) { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - clause & c = *cs[i]; - var x = max_var(c); + for (clause* cp : cs) { + var x = max_var(*cp); if (x != null_var) - m_watches[x].push_back(&c); + m_watches[x].push_back(cp); } } @@ -2251,18 +2269,16 @@ namespace nlsat { } bool is_full_dimensional(clause const & c) const { - unsigned sz = c.size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_full_dimensional(c[i])) + for (literal l : c) { + if (!is_full_dimensional(l)) return false; } return true; } bool is_full_dimensional(clause_vector const & cs) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - if (!is_full_dimensional(*(cs[i]))) + for (clause* c : cs) { + if (!is_full_dimensional(*c)) return false; } return true; @@ -2272,13 +2288,271 @@ namespace nlsat { return is_full_dimensional(m_clauses); } + + // ----------------------- + // + // Simplification + // + // ----------------------- + + // solve simple equalities + // TBD WU-Reit decomposition? + + /** + \brief isolate variables in unit equalities. + Assume a clause is c == v*p + q + and the context implies p > 0 + + replace v by -q/p + remove clause c, + The for other occurrences of v, + replace v*r + v*v*r' > 0 by + by p*p*v*r + p*p*v*v*r' > 0 + by p*q*r + q*q*r' > 0 + + The method ignores lemmas and assumes constraints don't use roots. + */ + + void simplify() { + polynomial_ref p(m_pm), q(m_pm); + var v; + init_var_signs(); + SASSERT(m_learned.empty()); + bool change = true; + while (change) { + change = false; + for (clause* c : m_clauses) { + if (solve_var(*c, v, p, q)) { + q = -q; + m_patch_var.push_back(v); + m_patch_num.push_back(q); + m_patch_denom.push_back(p); + del_clause(c, m_clauses); + substitute_var(v, p, q); + change = true; + break; + } + } + } + } + + void fix_patch() { + for (unsigned i = m_patch_var.size(); i-- > 0; ) { + var v = m_patch_var[i]; + poly* q = m_patch_num.get(i); + poly* p = m_patch_denom.get(i); + scoped_anum pv(m_am), qv(m_am), val(m_am); + m_pm.eval(p, m_assignment, pv); + m_pm.eval(q, m_assignment, qv); + val = qv / pv; + TRACE("nlsat", + m_display_var(tout << "patch ", v) << "\n"; + if (m_assignment.is_assigned(v)) m_am.display(tout << "previous value: ", m_assignment.value(v)); tout << "\n"; + m_am.display(tout << "updated value: ", val); tout << "\n"; + ); + m_assignment.set_core(v, val); + } + } + + void substitute_var(var x, poly* p, poly* q) { + polynomial_ref pr(m_pm); + polynomial_ref_vector ps(m_pm); + u_map b2l; + svector even; + unsigned num_atoms = m_atoms.size(); + for (unsigned j = 0; j < num_atoms; ++j) { + atom* a = m_atoms[j]; + if (a && a->is_ineq_atom()) { + ineq_atom const& a1 = *to_ineq_atom(a); + unsigned sz = a1.size(); + ps.reset(); + even.reset(); + bool change = false; + for (unsigned i = 0; i < sz; ++i) { + poly * po = a1.p(i); + m_pm.substitute(po, x, q, p, pr); + ps.push_back(pr); + even.push_back(a1.is_even(i)); + change |= pr != po; + if (m_pm.is_zero(pr)) { + ps.reset(); + even.reset(); + change = true; + break; + } + } + if (!change) continue; + literal l = mk_ineq_literal(a1.get_kind(), ps.size(), ps.c_ptr(), even.c_ptr()); + if (a1.m_bool_var != l.var()) { + b2l.insert(a1.m_bool_var, l); + inc_ref(l); + } + } + } + update_clauses(b2l); + for (auto const& kv : b2l) { + dec_ref(kv.m_value); + } + } + + + void update_clauses(u_map const& b2l) { + literal_vector lits; + clause_vector to_delete; + unsigned n = m_clauses.size(); + for (unsigned i = 0; i < n; ++i) { + clause* c = m_clauses[i]; + lits.reset(); + bool changed = false; + bool is_tautology = false; + for (literal l : *c) { + literal lit = null_literal; + if (b2l.find(l.var(), lit)) { + lit = l.sign() ? ~lit : lit; + if (lit == true_literal) { + is_tautology = true; + } + else if (lit != false_literal) { + lits.push_back(lit); + } + changed = true; + } + else { + lits.push_back(l); + } + } + if (changed) { + to_delete.push_back(c); + if (!is_tautology) { + mk_clause(lits.size(), lits.c_ptr(), c->is_learned(), static_cast<_assumption_set>(c->assumptions())); + } + } + } + for (clause* c : to_delete) { + del_clause(c, m_clauses); + } + } + + bool is_unit_ineq(clause const& c) const { + return + c.size() == 1 && + m_atoms[c[0].var()] && + m_atoms[c[0].var()]->is_ineq_atom(); + } + + bool is_unit_eq(clause const& c) const { + return + is_unit_ineq(c) && + !c[0].sign() && + m_atoms[c[0].var()]->is_eq(); + } + + /** + \brief determine whether the clause is a comparison v > k or v < k', where k >= 0 or k' <= 0. + */ + lbool is_cmp0(clause const& c, var& v) { + if (!is_unit_ineq(c)) return l_undef; + literal lit = c[0]; + ineq_atom const& a = *to_ineq_atom(m_atoms[lit.var()]); + bool sign = lit.sign(); + poly * p0; + if (!is_single_poly(a, p0)) return l_undef; + if (m_pm.is_var(p0, v)) { + if (!sign && a.get_kind() == atom::GT) { + return l_true; + } + if (!sign && a.get_kind() == atom::LT) { + return l_false; + } + return l_undef; + } + polynomial::scoped_numeral n(m_pm.m()); + if (m_pm.is_var_num(p0, v, n)) { + // x - k > 0 + if (!sign && a.get_kind() == atom::GT && m_pm.m().is_nonneg(n)) { + return l_true; + } + // x + k < 0 + if (!sign && a.get_kind() == atom::LT && m_pm.m().is_nonpos(n)) { + return l_false; + } + // !(x + k > 0) + if (sign && a.get_kind() == atom::GT && m_pm.m().is_pos(n)) { + return l_false; + } + // !(x - k < 0) + if (sign && a.get_kind() == atom::LT && m_pm.m().is_neg(n)) { + return l_true; + } + } + return l_undef; + } + + bool is_single_poly(ineq_atom const& a, poly*& p) { + unsigned sz = a.size(); + return sz == 1 && a.is_odd(0) && (p = a.p(0), true); + } + + svector m_var_signs; + + void init_var_signs() { + m_var_signs.reset(); + for (clause* cp : m_clauses) { + clause& c = *cp; + var x = 0; + lbool cmp = is_cmp0(c, x); + switch (cmp) { + case l_true: + m_var_signs.setx(x, l_true, l_undef); + break; + case l_false: + m_var_signs.setx(x, l_false, l_undef); + break; + default: + break; + } + } + } + + /** + \brief returns true then c is an equality that is equivalent to v*p + q, + and p > 0, v does not occur in p, q. + */ + bool solve_var(clause& c, var& v, polynomial_ref& p, polynomial_ref& q) { + poly* p0; + if (!is_unit_eq(c)) return false; + ineq_atom & a = *to_ineq_atom(m_atoms[c[0].var()]); + if (!is_single_poly(a, p0)) return false; + var mx = max_var(p0); + if (mx >= m_is_int.size()) return false; + for (var x = 0; x <= mx; ++x) { + if (m_is_int[x]) continue; + if (1 == m_pm.degree(p0, x)) { + p = m_pm.coeff(p0, x, 1, q); + switch (m_pm.sign(p, m_var_signs)) { + case l_true: + v = x; + return true; + case l_false: + v = x; + p = -p; + q = -q; + return true; + default: + break; + } + } + } + return false; + } + // ----------------------- // // Pretty printing // // ----------------------- - void display_num_assignment(std::ostream & out, display_var_proc const & proc) const { + std::ostream& display_num_assignment(std::ostream & out, display_var_proc const & proc) const { for (var x = 0; x < num_vars(); x++) { if (m_assignment.is_assigned(x)) { proc(out, x); @@ -2287,9 +2561,10 @@ namespace nlsat { out << "\n"; } } + return out; } - void display_bool_assignment(std::ostream & out) const { + std::ostream& display_bool_assignment(std::ostream & out) const { unsigned sz = m_atoms.size(); for (bool_var b = 0; b < sz; b++) { if (m_atoms[b] == 0 && m_bvalues[b] != l_undef) { @@ -2300,6 +2575,7 @@ namespace nlsat { for (bool_var b = 0; b < sz; b++) { out << "b" << b << " -> " << m_bvalues[b] << " " << m_atoms[b] << "\n"; }); + return out; } bool display_mathematica_assignment(std::ostream & out) const { @@ -2317,16 +2593,17 @@ namespace nlsat { return !first; } - void display_num_assignment(std::ostream & out) const { - display_num_assignment(out, m_display_var); + std::ostream& display_num_assignment(std::ostream & out) const { + return display_num_assignment(out, m_display_var); } - void display_assignment(std::ostream& out) const { + std::ostream& display_assignment(std::ostream& out) const { display_bool_assignment(out); display_num_assignment(out); + return out; } - void display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const { + std::ostream& display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const { unsigned sz = a.size(); for (unsigned i = 0; i < sz; i++) { if (use_star && i > 0) @@ -2346,9 +2623,10 @@ namespace nlsat { case atom::EQ: out << " = 0"; break; default: UNREACHABLE(); break; } + return out; } - - void display_mathematica(std::ostream & out, ineq_atom const & a) const { + + std::ostream& display_mathematica(std::ostream & out, ineq_atom const & a) const { unsigned sz = a.size(); for (unsigned i = 0; i < sz; i++) { if (i > 0) @@ -2370,9 +2648,10 @@ namespace nlsat { case atom::EQ: out << " == 0"; break; default: UNREACHABLE(); break; } + return out; } - void display_smt2(std::ostream & out, ineq_atom const & a, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, ineq_atom const & a, display_var_proc const & proc) const { switch (a.get_kind()) { case atom::LT: out << "(< "; break; case atom::GT: out << "(> "; break; @@ -2398,9 +2677,10 @@ namespace nlsat { if (sz > 1) out << ")"; out << " 0)"; + return out; } - void display(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { proc(out, a.x()); switch (a.get_kind()) { case atom::ROOT_LT: out << " < "; break; @@ -2413,21 +2693,22 @@ namespace nlsat { out << "root[" << a.i() << "]("; m_pm.display(out, a.p(), proc); out << ")"; + return out; } struct mathematica_var_proc : public display_var_proc { var m_x; public: mathematica_var_proc(var x):m_x(x) {} - virtual void operator()(std::ostream & out, var x) const { + virtual std::ostream& operator()(std::ostream & out, var x) const { if (m_x == x) - out << "#1"; + return out << "#1"; else - out << "x" << x; + return out << "x" << x; } }; - void display_mathematica(std::ostream & out, root_atom const & a) const { + std::ostream& display_mathematica(std::ostream & out, root_atom const & a) const { out << "x" << a.x(); switch (a.get_kind()) { case atom::ROOT_LT: out << " < "; break; @@ -2440,65 +2721,74 @@ namespace nlsat { out << "Root["; m_pm.display(out, a.p(), mathematica_var_proc(a.x()), true); out << " &, " << a.i() << "]"; + return out; } - void display_smt2(std::ostream & out, root_atom const & a) const { + std::ostream& display_smt2(std::ostream & out, root_atom const & a) const { NOT_IMPLEMENTED_YET(); + return out; } - void display(std::ostream & out, atom const & a, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, atom const & a, display_var_proc const & proc) const { if (a.is_ineq_atom()) - display(out, static_cast(a), proc); + return display(out, static_cast(a), proc); else - display(out, static_cast(a), proc); + return display(out, static_cast(a), proc); } - void display_mathematica(std::ostream & out, atom const & a) const { - if (a.is_ineq_atom()) - display_mathematica(out, static_cast(a)); - else - display_mathematica(out, static_cast(a)); + std::ostream& display(std::ostream & out, atom const & a) const { + return display(out, a, m_display_var); } - void display_smt2(std::ostream & out, atom const & a, display_var_proc const & proc) const { + std::ostream& display_mathematica(std::ostream & out, atom const & a) const { if (a.is_ineq_atom()) - display_smt2(out, static_cast(a), proc); + return display_mathematica(out, static_cast(a)); else - display_smt2(out, static_cast(a), proc); + return display_mathematica(out, static_cast(a)); } - void display_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, atom const & a, display_var_proc const & proc) const { + if (a.is_ineq_atom()) + return display_smt2(out, static_cast(a), proc); + else + return display_smt2(out, static_cast(a), proc); + } + + std::ostream& display_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { if (b == 0) out << "true"; else if (m_atoms[b] == 0) out << "b" << b; else display(out, *(m_atoms[b]), proc); + return out; } - void display_atom(std::ostream & out, bool_var b) const { - display_atom(out, b, m_display_var); + std::ostream& display_atom(std::ostream & out, bool_var b) const { + return display_atom(out, b, m_display_var); } - void display_mathematica_atom(std::ostream & out, bool_var b) const { + std::ostream& display_mathematica_atom(std::ostream & out, bool_var b) const { if (b == 0) out << "(0 < 1)"; else if (m_atoms[b] == 0) out << "b" << b; else display_mathematica(out, *(m_atoms[b])); + return out; } - void display_smt2_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { + std::ostream& display_smt2_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { if (b == 0) out << "true"; else if (m_atoms[b] == 0) out << "b" << b; else display_smt2(out, *(m_atoms[b]), proc); + return out; } - void display(std::ostream & out, literal l, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, literal l, display_var_proc const & proc) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2511,13 +2801,14 @@ namespace nlsat { else { display_atom(out, l.var(), proc); } + return out; } - void display(std::ostream & out, literal l) const { - display(out, l, m_display_var); + std::ostream& display(std::ostream & out, literal l) const { + return display(out, l, m_display_var); } - void display_mathematica(std::ostream & out, literal l) const { + std::ostream& display_mathematica(std::ostream & out, literal l) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2530,9 +2821,10 @@ namespace nlsat { else { display_mathematica_atom(out, l.var()); } + return out; } - void display_smt2(std::ostream & out, literal l, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, literal l, display_var_proc const & proc) const { if (l.sign()) { bool_var b = l.var(); out << "(not "; @@ -2542,41 +2834,43 @@ namespace nlsat { else { display_smt2_atom(out, l.var(), proc); } + return out; } - void display_assumptions(std::ostream & out, _assumption_set s) const { - + std::ostream& display_assumptions(std::ostream & out, _assumption_set s) const { + return out; } - void display(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { for (unsigned i = 0; i < num; i++) { if (i > 0) out << " or "; display(out, ls[i], proc); } + return out; } - void display(std::ostream & out, unsigned num, literal const * ls) { - display(out, num, ls, m_display_var); + std::ostream& display(std::ostream & out, unsigned num, literal const * ls) { + return display(out, num, ls, m_display_var); + } + + std::ostream& display(std::ostream & out, scoped_literal_vector const & cs) { + return display(out, cs.size(), cs.c_ptr(), m_display_var); } - void display(std::ostream & out, scoped_literal_vector const & cs) { - display(out, cs.size(), cs.c_ptr(), m_display_var); - } - - void display(std::ostream & out, clause const & c, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, clause const & c, display_var_proc const & proc) const { if (c.assumptions() != 0) { display_assumptions(out, static_cast<_assumption_set>(c.assumptions())); out << " |- "; } - display(out, c.size(), c.c_ptr(), proc); + return display(out, c.size(), c.c_ptr(), proc); } - void display(std::ostream & out, clause const & c) const { - display(out, c, m_display_var); + std::ostream& display(std::ostream & out, clause const & c) const { + return display(out, c, m_display_var); } - void display_smt2(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { + std::ostream& display_smt2(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { if (num == 0) { out << "false"; } @@ -2591,13 +2885,14 @@ namespace nlsat { } out << ")"; } + return out; } - void display_smt2(std::ostream & out, clause const & c, display_var_proc const & proc = display_var_proc()) const { - display_smt2(out, c.size(), c.c_ptr(), proc); + std::ostream& display_smt2(std::ostream & out, clause const & c, display_var_proc const & proc = display_var_proc()) const { + return display_smt2(out, c.size(), c.c_ptr(), proc); } - void display_abst(std::ostream & out, literal l) const { + std::ostream& display_abst(std::ostream & out, literal l) const { if (l.sign()) { bool_var b = l.var(); out << "!"; @@ -2609,25 +2904,27 @@ namespace nlsat { else { out << "b" << l.var(); } + return out; } - void display_abst(std::ostream & out, unsigned num, literal const * ls) const { + std::ostream& display_abst(std::ostream & out, unsigned num, literal const * ls) const { for (unsigned i = 0; i < num; i++) { if (i > 0) out << " or "; display_abst(out, ls[i]); } + return out; } - void display_abst(std::ostream & out, scoped_literal_vector const & cs) const { - display_abst(out, cs.size(), cs.c_ptr()); + std::ostream& display_abst(std::ostream & out, scoped_literal_vector const & cs) const { + return display_abst(out, cs.size(), cs.c_ptr()); } - void display_abst(std::ostream & out, clause const & c) const { - display_abst(out, c.size(), c.c_ptr()); + std::ostream& display_abst(std::ostream & out, clause const & c) const { + return display_abst(out, c.size(), c.c_ptr()); } - void display_mathematica(std::ostream & out, clause const & c) const { + std::ostream& display_mathematica(std::ostream & out, clause const & c) const { out << "("; unsigned sz = c.size(); for (unsigned i = 0; i < sz; i++) { @@ -2636,12 +2933,13 @@ namespace nlsat { display_mathematica(out, c[i]); } out << ")"; + return out; } // Debugging support: // Display generated lemma in Mathematica format. // Mathematica must reduce lemma to True (modulo resource constraints). - void display_mathematica_lemma(std::ostream & out, unsigned num, literal const * ls, bool include_assignment = false) const { + std::ostream& display_mathematica_lemma(std::ostream & out, unsigned num, literal const * ls, bool include_assignment = false) const { out << "Resolve[ForAll[{"; // var definition for (unsigned i = 0; i < num_vars(); i++) { @@ -2662,71 +2960,69 @@ namespace nlsat { display_mathematica(out, ls[i]); } out << "], Reals]\n"; // end of exists + return out; } - void display(std::ostream & out, clause_vector const & cs, display_var_proc const & proc) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - display(out, *(cs[i]), proc); - out << "\n"; + std::ostream& display(std::ostream & out, clause_vector const & cs, display_var_proc const & proc) const { + for (clause* c : cs) { + display(out, *c, proc) << "\n"; } + return out; } - void display(std::ostream & out, clause_vector const & cs) const { - display(out, cs, m_display_var); + std::ostream& display(std::ostream & out, clause_vector const & cs) const { + return display(out, cs, m_display_var); } - void display_mathematica(std::ostream & out, clause_vector const & cs) const { + std::ostream& display_mathematica(std::ostream & out, clause_vector const & cs) const { unsigned sz = cs.size(); for (unsigned i = 0; i < sz; i++) { if (i > 0) out << ",\n"; - out << " "; - display_mathematica(out, *(cs[i])); + display_mathematica(out << " ", *(cs[i])); } + return out; } - void display_abst(std::ostream & out, clause_vector const & cs) const { - unsigned sz = cs.size(); - for (unsigned i = 0; i < sz; i++) { - display_abst(out, *(cs[i])); - out << "\n"; + std::ostream& display_abst(std::ostream & out, clause_vector const & cs) const { + for (clause* c : cs) { + display_abst(out, *c) << "\n"; } + return out; } - void display(std::ostream & out, display_var_proc const & proc) const { + std::ostream& display(std::ostream & out, display_var_proc const & proc) const { display(out, m_clauses, proc); if (!m_learned.empty()) { - out << "Lemmas:\n"; - display(out, m_learned, proc); + display(out << "Lemmas:\n", m_learned, proc); } + return out; } - void display_mathematica(std::ostream & out) const { - out << "{\n"; - display_mathematica(out, m_clauses); - out << "}\n"; + std::ostream& display_mathematica(std::ostream & out) const { + return display_mathematica(out << "{\n", m_clauses) << "}\n"; } - void display_abst(std::ostream & out) const { + std::ostream& display_abst(std::ostream & out) const { display_abst(out, m_clauses); if (!m_learned.empty()) { - out << "Lemmas:\n"; - display_abst(out, m_learned); + display_abst(out << "Lemmas:\n", m_learned); } + return out; } - void display(std::ostream & out) const { + std::ostream& display(std::ostream & out) const { display(out, m_display_var); - display_assignment(out); + return display_assignment(out); } - void display_vars(std::ostream & out) const { + std::ostream& display_vars(std::ostream & out) const { for (unsigned i = 0; i < num_vars(); i++) { out << i << " -> "; m_display_var(out, i); out << "\n"; } + return out; } - void display_smt2_arith_decls(std::ostream & out) const { + std::ostream& display_smt2_arith_decls(std::ostream & out) const { unsigned sz = m_is_int.size(); for (unsigned i = 0; i < sz; i++) { if (m_is_int[i]) @@ -2734,31 +3030,32 @@ namespace nlsat { else out << "(declare-fun x" << i << " () Real)\n"; } + return out; } - void display_smt2_bool_decls(std::ostream & out) const { + std::ostream& display_smt2_bool_decls(std::ostream & out) const { unsigned sz = m_atoms.size(); for (unsigned i = 0; i < sz; i++) { if (m_atoms[i] == 0) out << "(declare-fun b" << i << " () Bool)\n"; } + return out; } - void display_smt2(std::ostream & out) const { + std::ostream& display_smt2(std::ostream & out) const { display_smt2_bool_decls(out); display_smt2_arith_decls(out); out << "(assert (and true\n"; - unsigned sz = m_clauses.size(); - for (unsigned i = 0; i < sz; i++) { - display_smt2(out, *(m_clauses[i])); - out << "\n"; + for (clause* c : m_clauses) { + display_smt2(out, *c) << "\n"; } out << "))\n(check-sat)" << std::endl; + return out; } }; - solver::solver(reslimit& rlim, params_ref const & p) { - m_imp = alloc(imp, *this, rlim, p); + solver::solver(reslimit& rlim, params_ref const & p, bool incremental) { + m_imp = alloc(imp, *this, rlim, p, incremental); } solver::~solver() { diff --git a/src/nlsat/nlsat_solver.h b/src/nlsat/nlsat_solver.h index ac503c603..c632a0334 100644 --- a/src/nlsat/nlsat_solver.h +++ b/src/nlsat/nlsat_solver.h @@ -35,7 +35,7 @@ namespace nlsat { struct imp; imp * m_imp; public: - solver(reslimit& rlim, params_ref const & p); + solver(reslimit& rlim, params_ref const & p, bool incremental); ~solver(); /** diff --git a/src/nlsat/nlsat_types.h b/src/nlsat/nlsat_types.h index db3b6ffa5..647a5e3ee 100644 --- a/src/nlsat/nlsat_types.h +++ b/src/nlsat/nlsat_types.h @@ -47,6 +47,8 @@ namespace nlsat { typedef polynomial::var_vector var_vector; typedef polynomial::manager pmanager; typedef polynomial::polynomial poly; + typedef polynomial::monomial monomial; + typedef polynomial::numeral numeral; const var null_var = polynomial::null_var; const var true_bool_var = 0; diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 510f503e7..9de7215e3 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -32,11 +32,11 @@ class nlsat_tactic : public tactic { ast_manager & m; expr_ref_vector m_var2expr; expr_display_var_proc(ast_manager & _m):m(_m), m_var2expr(_m) {} - virtual void operator()(std::ostream & out, nlsat::var x) const { + virtual std::ostream& operator()(std::ostream & out, nlsat::var x) const { if (x < m_var2expr.size()) - out << mk_ismt2_pp(m_var2expr.get(x), m); + return out << mk_ismt2_pp(m_var2expr.get(x), m); else - out << "x!" << x; + return out << "x!" << x; } }; @@ -51,7 +51,7 @@ class nlsat_tactic : public tactic { m(_m), m_params(p), m_display_var(_m), - m_solver(m.limit(), p) { + m_solver(m.limit(), p, false) { } void updt_params(params_ref const & p) { diff --git a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp index 22f64af47..47b9e0505 100644 --- a/src/nlsat/tactic/qfnra_nlsat_tactic.cpp +++ b/src/nlsat/tactic/qfnra_nlsat_tactic.cpp @@ -48,11 +48,15 @@ tactic * mk_qfnra_nlsat_tactic(ast_manager & m, params_ref const & p) { purify_p), mk_propagate_values_tactic(m, p), mk_solve_eqs_tactic(m, p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), mk_elim_uncnstr_tactic(m, p), mk_elim_term_ite_tactic(m, p)), and_then(/* mk_degree_shift_tactic(m, p), */ // may affect full dimensionality detection factor, mk_solve_eqs_tactic(m, p), + using_params(mk_purify_arith_tactic(m, p), + purify_p), using_params(mk_simplify_tactic(m, p), main_p), mk_tseitin_cnf_core_tactic(m, p), diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index ab5095328..e28f6ae4f 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -782,7 +782,7 @@ namespace qe { m(m), m_mode(mode), m_params(p), - m_solver(m.limit(), p), + m_solver(m.limit(), p, true), m_nftactic(0), m_rmodel(m_solver.am()), m_rmodel0(m_solver.am()), diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 65d474182..5df523ff7 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -44,6 +44,7 @@ class solve_eqs_tactic : public tactic { expr_sparse_mark m_candidate_set; ptr_vector m_candidates; ptr_vector m_vars; + expr_sparse_mark m_nonzero; ptr_vector m_ordered_vars; bool m_produce_proofs; bool m_produce_unsat_cores; @@ -55,8 +56,7 @@ class solve_eqs_tactic : public tactic { m_r_owner(r == 0 || owner), m_a_util(m), m_num_steps(0), - m_num_eliminated_vars(0) - { + m_num_eliminated_vars(0) { updt_params(p); if (m_r == 0) m_r = mk_default_expr_replacer(m); @@ -78,7 +78,7 @@ class solve_eqs_tactic : public tactic { void checkpoint() { if (m().canceled()) throw tactic_exception(m().limit().get_cancel_msg()); - cooperate("solve-eqs"); + cooperate("solve-eqs"); } // Check if the number of occurrences of t is below the specified threshold :solve-eqs-max-occs @@ -106,7 +106,8 @@ class solve_eqs_tactic : public tactic { } } bool trivial_solve(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) { - if (trivial_solve1(lhs, rhs, var, def, pr)) return true; + if (trivial_solve1(lhs, rhs, var, def, pr)) + return true; if (trivial_solve1(rhs, lhs, var, def, pr)) { if (m_produce_proofs) { pr = m().mk_commutativity(m().mk_eq(lhs, rhs)); @@ -187,6 +188,77 @@ class solve_eqs_tactic : public tactic { } return false; } + + void add_pos(expr* f) { + expr* lhs = nullptr, *rhs = nullptr; + rational val; + if (m_a_util.is_le(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_neg()) { + m_nonzero.mark(lhs); + } + else if (m_a_util.is_ge(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_pos()) { + m_nonzero.mark(lhs); + } + else if (m().is_not(f, f)) { + if (m_a_util.is_le(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && !val.is_neg()) { + m_nonzero.mark(lhs); + } + else if (m_a_util.is_ge(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && !val.is_pos()) { + m_nonzero.mark(lhs); + } + else if (m().is_eq(f, lhs, rhs) && m_a_util.is_numeral(rhs, val) && val.is_zero()) { + m_nonzero.mark(lhs); + } + } + } + + bool is_nonzero(expr* e) { + return m_nonzero.is_marked(e); + } + + bool isolate_var(app* arg, app_ref& var, expr_ref& div, unsigned i, app* lhs, expr* rhs) { + if (!m_a_util.is_mul(arg)) return false; + unsigned n = arg->get_num_args(); + for (unsigned j = 0; j < n; ++j) { + expr* e = arg->get_arg(j); + bool ok = is_uninterp_const(e) && check_occs(e) && !occurs(e, rhs) && !occurs_except(e, lhs, i); + if (!ok) continue; + var = to_app(e); + for (unsigned k = 0; ok && k < n; ++k) { + expr* arg_k = arg->get_arg(k); + ok = k == j || (!occurs(var, arg_k) && is_nonzero(arg_k)); + } + if (!ok) continue; + ptr_vector args; + for (unsigned k = 0; k < n; ++k) { + if (k != j) args.push_back(arg->get_arg(k)); + } + div = m_a_util.mk_mul(args.size(), args.c_ptr()); + return true; + } + return false; + } + + bool solve_nl(app * lhs, expr * rhs, expr* eq, app_ref& var, expr_ref & def, proof_ref & pr) { + SASSERT(m_a_util.is_add(lhs)); + if (m_a_util.is_int(lhs)) return false; + unsigned num = lhs->get_num_args(); + expr_ref div(m()); + for (unsigned i = 0; i < num; i++) { + expr * arg = lhs->get_arg(i); + if (is_app(arg) && isolate_var(to_app(arg), var, div, i, lhs, rhs)) { + ptr_vector args; + for (unsigned k = 0; k < num; ++k) { + if (k != i) args.push_back(lhs->get_arg(k)); + } + def = m_a_util.mk_sub(rhs, m_a_util.mk_add(args.size(), args.c_ptr())); + def = m_a_util.mk_div(def, div); + if (m_produce_proofs) + pr = m().mk_rewrite(eq, m().mk_eq(var, def)); + return true; + } + } + return false; + } bool solve_arith_core(app * lhs, expr * rhs, expr * eq, app_ref & var, expr_ref & def, proof_ref & pr) { SASSERT(m_a_util.is_add(lhs)); @@ -204,7 +276,8 @@ class solve_eqs_tactic : public tactic { break; } else if (m_a_util.is_mul(arg, a, v) && - is_uninterp_const(v) && !m_candidate_vars.is_marked(v) && + is_uninterp_const(v) && + !m_candidate_vars.is_marked(v) && m_a_util.is_numeral(a, a_val) && !a_val.is_zero() && (!is_int || a_val.is_minus_one()) && @@ -252,16 +325,20 @@ class solve_eqs_tactic : public tactic { return (m_a_util.is_add(lhs) && solve_arith_core(to_app(lhs), rhs, eq, var, def, pr)) || (m_a_util.is_add(rhs) && solve_arith_core(to_app(rhs), lhs, eq, var, def, pr)); +#if 0 + // better done inside of nlsat + (m_a_util.is_add(lhs) && solve_nl(to_app(lhs), rhs, eq, var, def, pr)) || + (m_a_util.is_add(rhs) && solve_nl(to_app(rhs), lhs, eq, var, def, pr)); +#endif } bool solve(expr * f, app_ref & var, expr_ref & def, proof_ref & pr) { - if (m().is_eq(f)) { - if (trivial_solve(to_app(f)->get_arg(0), to_app(f)->get_arg(1), var, def, pr)) + expr* arg1 = 0, *arg2 = 0; + if (m().is_eq(f, arg1, arg2)) { + if (trivial_solve(arg1, arg2, var, def, pr)) return true; if (m_theory_solver) { - expr * lhs = to_app(f)->get_arg(0); - expr * rhs = to_app(f)->get_arg(1); - if (solve_arith(lhs, rhs, f, var, def, pr)) + if (solve_arith(arg1, arg2, f, var, def, pr)) return true; } return false; @@ -321,11 +398,14 @@ class solve_eqs_tactic : public tactic { m_candidate_set.reset(); m_candidates.reset(); m_vars.reset(); - + m_nonzero.reset(); app_ref var(m()); expr_ref def(m()); proof_ref pr(m()); unsigned size = g.size(); + for (unsigned idx = 0; idx < size; idx++) { + add_pos(g.form(idx)); + } for (unsigned idx = 0; idx < size; idx++) { checkpoint(); expr * f = g.form(idx); @@ -347,10 +427,8 @@ class solve_eqs_tactic : public tactic { TRACE("solve_eqs", tout << "candidate vars:\n"; - ptr_vector::iterator it = m_vars.begin(); - ptr_vector::iterator end = m_vars.end(); - for (; it != end; ++it) { - tout << mk_ismt2_pp(*it, m()) << " "; + for (app* v : m_vars) { + tout << mk_ismt2_pp(v, m()) << " "; } tout << "\n";); } @@ -374,12 +452,9 @@ class solve_eqs_tactic : public tactic { typedef std::pair frame; svector todo; - ptr_vector::const_iterator it = m_vars.begin(); - ptr_vector::const_iterator end = m_vars.end(); - unsigned num; - for (; it != end; ++it) { + unsigned num = 0; + for (app* v : m_vars) { checkpoint(); - app * v = *it; if (!m_candidate_vars.is_marked(v)) continue; todo.push_back(frame(v, 0)); @@ -483,20 +558,19 @@ class solve_eqs_tactic : public tactic { } // cleanup - it = m_vars.begin(); - for (unsigned idx = 0; it != end; ++it, ++idx) { - if (!m_candidate_vars.is_marked(*it)) { + unsigned idx = 0; + for (expr* v : m_vars) { + if (!m_candidate_vars.is_marked(v)) { m_candidate_set.mark(m_candidates[idx], false); } + ++idx; } TRACE("solve_eqs", tout << "ordered vars:\n"; - ptr_vector::iterator it = m_ordered_vars.begin(); - ptr_vector::iterator end = m_ordered_vars.end(); - for (; it != end; ++it) { - SASSERT(m_candidate_vars.is_marked(*it)); - tout << mk_ismt2_pp(*it, m()) << " "; + for (app* v : m_ordered_vars) { + SASSERT(m_candidate_vars.is_marked(v)); + tout << mk_ismt2_pp(v, m()) << " "; } tout << "\n";); m_candidate_vars.reset(); @@ -609,10 +683,7 @@ class solve_eqs_tactic : public tactic { if (m_produce_models) { if (mc.get() == 0) mc = alloc(gmc, m()); - ptr_vector::iterator it = m_ordered_vars.begin(); - ptr_vector::iterator end = m_ordered_vars.end(); - for (; it != end; ++it) { - app * v = *it; + for (app* v : m_ordered_vars) { expr * def = 0; proof * pr; expr_dependency * dep; From b78c538e021763ef6608801bfa84d593964a63f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 30 Dec 2017 22:58:41 -0800 Subject: [PATCH 22/37] fix build of test Signed-off-by: Nikolaj Bjorner --- src/test/nlsat.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/nlsat.cpp b/src/test/nlsat.cpp index ecf73843f..19add1fab 100644 --- a/src/test/nlsat.cpp +++ b/src/test/nlsat.cpp @@ -272,7 +272,7 @@ static void tst4() { static void tst5() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -330,7 +330,7 @@ static nlsat::literal mk_eq(nlsat::solver& s, nlsat::poly* p) { static void tst6() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -390,7 +390,7 @@ static void tst6() { static void tst7() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); nlsat::pmanager & pm = s.pm(); nlsat::var x0, x1, x2, a, b, c, d; a = s.mk_var(false); @@ -443,7 +443,7 @@ static void tst7() { static void tst8() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -492,7 +492,7 @@ static void tst8() { static void tst9() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); @@ -624,7 +624,7 @@ static bool satisfies_root(nlsat::solver& s, nlsat::atom::kind k, nlsat::poly* p static void tst10() { params_ref ps; reslimit rlim; - nlsat::solver s(rlim, ps); + nlsat::solver s(rlim, ps, false); anum_manager & am = s.am(); nlsat::pmanager & pm = s.pm(); nlsat::assignment as(am); From 8dadd30db5e1f09739bcb877e9dc5fb3240b1cf9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 17:11:43 -0800 Subject: [PATCH 23/37] add __copy__, __deepcopy__ as alias to translate on same context #1427. Add generalized Gaussian elimination as an option to first-pass NL solver Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 24 +++++++++++++++++++ .../bit_blaster/bit_blaster_tpl_def.h | 1 - src/nlsat/nlsat_params.pyg | 1 + src/nlsat/nlsat_solver.cpp | 7 +++--- src/tactic/smtlogics/qfnra_tactic.cpp | 6 +++-- 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 4cc401156..20c521df6 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -365,6 +365,12 @@ class AstRef(Z3PPObject): _z3_assert(isinstance(target, Context), "argument must be a Z3 context") return _to_ast_ref(Z3_translate(self.ctx.ref(), self.as_ast(), target.ref()), target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def hash(self): """Return a hashcode for the `self`. @@ -5048,6 +5054,12 @@ class Goal(Z3PPObject): _z3_assert(isinstance(target, Context), "target must be a context") return Goal(goal=Z3_goal_translate(self.ctx.ref(), self.goal, target.ref()), ctx=target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def simplify(self, *arguments, **keywords): """Return a new simplified goal. @@ -5230,6 +5242,12 @@ class AstVector(Z3PPObject): """ return AstVector(Z3_ast_vector_translate(self.ctx.ref(), self.vector, other_ctx.ref()), other_ctx) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def __repr__(self): return obj_to_string(self) @@ -6430,6 +6448,12 @@ class Solver(Z3PPObject): solver = Z3_solver_translate(self.ctx.ref(), self.solver, target.ref()) return Solver(solver, target) + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def sexpr(self): """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format. 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 a80994f6c..cf7e7c951 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h +++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h @@ -1193,7 +1193,6 @@ bool bit_blaster_tpl::mk_const_case_multiplier(unsigned sz, expr * const * return false; } SASSERT(out_bits.empty()); - ptr_buffer na_bits; na_bits.append(sz, a_bits); ptr_buffer nb_bits; diff --git a/src/nlsat/nlsat_params.pyg b/src/nlsat/nlsat_params.pyg index 6b1577113..0f2e03069 100644 --- a/src/nlsat/nlsat_params.pyg +++ b/src/nlsat/nlsat_params.pyg @@ -10,6 +10,7 @@ def_module_params('nlsat', ('randomize', BOOL, True, "randomize selection of a witness in nlsat."), ('max_conflicts', UINT, UINT_MAX, "maximum number of conflicts."), ('shuffle_vars', BOOL, False, "use a random variable order."), + ('inline_vars', BOOL, False, "inline variables that can be isolated from equations"), ('seed', UINT, 0, "random seed."), ('factor', BOOL, True, "factor polynomials produced during conflict resolution.") )) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 4cba6d123..448aa624d 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -154,6 +154,7 @@ namespace nlsat { bool m_randomize; bool m_random_order; unsigned m_random_seed; + bool m_inline_vars; unsigned m_max_conflicts; // statistics @@ -210,6 +211,7 @@ namespace nlsat { m_max_conflicts = p.max_conflicts(); m_random_order = p.shuffle_vars(); m_random_seed = p.seed(); + m_inline_vars = p.inline_vars(); m_ism.set_seed(m_random_seed); m_explain.set_simplify_cores(m_simplify_cores); m_explain.set_minimize_cores(min_cores); @@ -1313,11 +1315,8 @@ namespace nlsat { m_explain.set_full_dimensional(is_full_dimensional()); bool reordered = false; -#if 0 - // disabled - if (!m_incremental) + if (!m_incremental && m_inline_vars) simplify(); -#endif if (!can_reorder()) { diff --git a/src/tactic/smtlogics/qfnra_tactic.cpp b/src/tactic/smtlogics/qfnra_tactic.cpp index 63c09c19c..cc01950a2 100644 --- a/src/tactic/smtlogics/qfnra_tactic.cpp +++ b/src/tactic/smtlogics/qfnra_tactic.cpp @@ -33,7 +33,9 @@ static tactic * mk_qfnra_sat_solver(ast_manager& m, params_ref const& p, unsigne } tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) { - params_ref p1 = p; + params_ref p0 = p; + p0.set_bool("inline_vars", true); + params_ref p1 = p; p1.set_uint("seed", 11); p1.set_bool("factor", false); params_ref p2 = p; @@ -42,7 +44,7 @@ tactic * mk_qfnra_tactic(ast_manager & m, params_ref const& p) { return and_then(mk_simplify_tactic(m, p), mk_propagate_values_tactic(m, p), - or_else(try_for(mk_qfnra_nlsat_tactic(m, p), 5000), + or_else(try_for(mk_qfnra_nlsat_tactic(m, p0), 5000), try_for(mk_qfnra_nlsat_tactic(m, p1), 10000), mk_qfnra_sat_solver(m, p, 4), and_then(try_for(mk_smt_tactic(), 5000), mk_fail_if_undecided_tactic()), From f0a30ded7db8aa1e93cf91840ae2469e51c5deb5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 19:25:09 -0800 Subject: [PATCH 24/37] add shorthand for translating models #1407 Signed-off-by: Nikolaj Bjorner --- src/api/api_model.cpp | 12 ++++++++++++ src/api/c++/z3++.h | 2 ++ src/api/python/z3/z3.py | 31 +++++++++++++++++++++++++------ src/api/z3_api.h | 7 +++++++ src/smt/theory_seq.cpp | 3 ++- 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index bda33f186..d9936ff66 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -212,6 +212,18 @@ extern "C" { RETURN_Z3(of_ast_vector(v)); Z3_CATCH_RETURN(0); } + + Z3_model Z3_API Z3_model_translate(Z3_context c, Z3_model m, Z3_context target) { + Z3_TRY; + LOG_Z3_model_translate(c, m, target); + RESET_ERROR_CODE(); + Z3_model_ref* dst = alloc(Z3_model_ref, *mk_c(target)); + ast_translation tr(mk_c(c)->m(), mk_c(target)->m()); + dst->m_model = to_model_ref(m)->translate(tr); + mk_c(target)->save_object(dst); + RETURN_Z3(of_model(dst)); + Z3_CATCH_RETURN(0); + } Z3_bool Z3_API Z3_is_as_array(Z3_context c, Z3_ast a) { Z3_TRY; diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 8ff2be239..b1e667e9f 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1809,9 +1809,11 @@ namespace z3 { Z3_model_inc_ref(ctx(), m); } public: + struct translate {}; model(context & c):object(c) { init(Z3_mk_model(c)); } model(context & c, Z3_model m):object(c) { init(m); } model(model const & s):object(s) { init(s.m_model); } + model(model& src, context& dst, translate) : object(dst) { init(Z3_model_translate(src.ctx(), src, dst)); } ~model() { Z3_model_dec_ref(ctx(), m_model); } operator Z3_model() const { return m_model; } model & operator=(model const & s) { diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 20c521df6..465e9aab8 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -5585,6 +5585,17 @@ class FuncInterp(Z3PPObject): raise IndexError return FuncEntry(Z3_func_interp_get_entry(self.ctx.ref(), self.f, idx), self.ctx) + def translate(self, other_ctx): + """Copy model 'self' to context 'other_ctx'. + """ + return ModelRef(Z3_model_translate(self.ctx.ref(), self.model, other_ctx.ref()), other_ctx) + + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def as_list(self): """Return the function interpretation as a Python list. >>> f = Function('f', IntSort(), IntSort()) @@ -5614,9 +5625,6 @@ class ModelRef(Z3PPObject): self.ctx = ctx Z3_model_inc_ref(self.ctx.ref(), self.model) - def __deepcopy__(self, memo={}): - return ModelRef(self.m, self.ctx) - def __del__(self): if self.ctx.ref() is not None: Z3_model_dec_ref(self.ctx.ref(), self.model) @@ -5870,6 +5878,20 @@ class ModelRef(Z3PPObject): r.append(FuncDeclRef(Z3_model_get_func_decl(self.ctx.ref(), self.model, i), self.ctx)) return r + def translate(self, target): + """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`. + """ + if __debug__: + _z3_assert(isinstance(target, Context), "argument must be a Z3 context") + model = Z3_model_translate(self.ctx.ref(), self.model, target.ref()) + return Model(model, target) + + def __copy__(self): + return self.translate(self.ctx) + + def __deepcopy__(self): + return self.translate(self.ctx) + def is_as_array(n): """Return true if n is a Z3 expression of the form (_ as-array f).""" return isinstance(n, ExprRef) and Z3_is_as_array(n.ctx.ref(), n.as_ast()) @@ -6072,9 +6094,6 @@ class Solver(Z3PPObject): self.solver = solver Z3_solver_inc_ref(self.ctx.ref(), self.solver) - def __deepcopy__(self, memo={}): - return Solver(self.solver, self.ctx) - def __del__(self): if self.solver is not None and self.ctx.ref() is not None: Z3_solver_dec_ref(self.ctx.ref(), self.solver) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 007bc3ab6..0ba49a5e5 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4896,6 +4896,13 @@ extern "C" { */ Z3_ast_vector Z3_API Z3_model_get_sort_universe(Z3_context c, Z3_model m, Z3_sort s); + /** + \brief translate model from context c to context \c dst. + + def_API('Z3_model_translate', MODEL, (_in(CONTEXT), _in(MODEL), _in(CONTEXT))) + */ + Z3_model Z3_API Z3_model_translate(Z3_context c, Z3_model m, Z3_context dst); + /** \brief The \ccode{(_ as-array f)} AST node is a construct for assigning interpretations for arrays in Z3. It is the array such that forall indices \c i we have that \ccode{(select (_ as-array f) i)} is equal to \ccode{(f i)}. diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 597348589..27ed95155 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3218,9 +3218,10 @@ void theory_seq::add_indexof_axiom(expr* i) { literal t_eq_empty = mk_eq_empty(t); // |t| = 0 => |s| = 0 or indexof(t,s,offset) = -1 - // ~contains(t,s) => indexof(t,s,offset) = -1 + // ~contains(t,s) <=> indexof(t,s,offset) = -1 add_axiom(cnt, i_eq_m1); + add_axiom(~cnt, ~i_eq_m1); add_axiom(~t_eq_empty, s_eq_empty, i_eq_m1); if (!offset || (m_autil.is_numeral(offset, r) && r.is_zero())) { From c1c1b7378cffe3ac0781d4765fd1602c40531d33 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 19:44:16 -0800 Subject: [PATCH 25/37] removing axiom exposing unsoundness, replace by weaker axiom Signed-off-by: Nikolaj Bjorner --- src/smt/theory_seq.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 27ed95155..f91685d43 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -3221,7 +3221,7 @@ void theory_seq::add_indexof_axiom(expr* i) { // ~contains(t,s) <=> indexof(t,s,offset) = -1 add_axiom(cnt, i_eq_m1); - add_axiom(~cnt, ~i_eq_m1); +// add_axiom(~cnt, ~i_eq_m1); add_axiom(~t_eq_empty, s_eq_empty, i_eq_m1); if (!offset || (m_autil.is_numeral(offset, r) && r.is_zero())) { @@ -3234,6 +3234,7 @@ void theory_seq::add_indexof_axiom(expr* i) { add_axiom(~s_eq_empty, i_eq_0); add_axiom(~cnt, s_eq_empty, mk_seq_eq(t, xsy)); add_axiom(~cnt, s_eq_empty, mk_eq(i, lenx, false)); + add_axiom(~cnt, mk_literal(m_autil.mk_ge(i, zero))); tightest_prefix(s, x); } else { From e8a9e1a58b3dac9155e93bd2b61ee89ba1275771 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 1 Jan 2018 20:04:55 -0800 Subject: [PATCH 26/37] set default rewriter behavior in incremental mode to distribute multiplication over addition #1373 Signed-off-by: Nikolaj Bjorner --- src/smt/asserted_formulas.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 56600266a..6ddce341d 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -131,6 +131,7 @@ void asserted_formulas::set_eliminate_and(bool flag) { p.set_bool("gcd_rounding", true); p.set_bool("expand_select_store", true); p.set_bool("bv_sort_ac", true); + p.set_bool("som", true); m_rewriter.updt_params(p); flush_cache(); } From 73b3da37d898c261892807197f72df48711383ab Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 22:47:52 +0700 Subject: [PATCH 27/37] Typo fixes. --- README-CMake.md | 4 +- RELEASE_NOTES | 2 +- cmake/Z3Config.cmake.in | 2 +- contrib/suppressions/sanitizers/README.md | 2 +- examples/c/test_capi.c | 4 +- examples/dotnet/Program.cs | 2 +- examples/java/JavaExample.java | 2 +- examples/maxsat/README | 2 +- src/api/dotnet/Context.cs | 12 +++--- src/api/dotnet/Expr.cs | 14 +++---- src/api/dotnet/Model.cs | 2 +- src/api/java/Context.java | 6 +-- src/api/java/Expr.java | 10 ++--- src/api/java/Model.java | 2 +- src/api/ml/z3.mli | 26 ++++++------ src/api/python/z3/z3.py | 10 ++--- src/api/z3_api.h | 50 +++++++++++------------ src/ast/ast.h | 14 +++---- src/ast/proofs/proof_checker.cpp | 2 +- src/interp/iz3proof_itp.cpp | 8 ++-- src/interp/iz3translate_direct.cpp | 2 +- src/math/simplex/simplex_def.h | 2 +- src/muz/rel/dl_compiler.h | 2 +- src/muz/rel/dl_relation_manager.h | 2 +- src/nlsat/nlsat_solver.cpp | 8 ++-- src/qe/qe_lite.cpp | 2 +- src/smt/mam.cpp | 4 +- src/smt/smt_internalizer.cpp | 12 +++--- src/smt/smt_model_finder.cpp | 22 +++++----- src/smt/smt_quantifier.h | 2 +- src/smt/theory_arith.h | 2 +- src/tactic/arith/purify_arith_tactic.h | 2 +- src/tactic/ufbv/ufbv_rewriter.h | 2 +- 33 files changed, 120 insertions(+), 120 deletions(-) diff --git a/README-CMake.md b/README-CMake.md index 0d323e08f..1b1f72729 100644 --- a/README-CMake.md +++ b/README-CMake.md @@ -5,7 +5,7 @@ of the project written in the ``CMakeLists.txt`` files and emits a build system for that project of your choice using one of CMake's "generators". This allows CMake to support many different platforms and build tools. You can run ``cmake --help`` to see the list of supported "generators" -on your platform. Example generators include "UNIX Makfiles" and "Visual Studio +on your platform. Example generators include "UNIX Makefiles" and "Visual Studio 12 2013". ## Getting started @@ -44,7 +44,7 @@ cmake -G "Unix Makefiles" ../ make -j4 # Replace 4 with an appropriate number ``` -Note that on some platforms "Unix Makesfiles" is the default generator so on those +Note that on some platforms "Unix Makefiles" is the default generator so on those platforms you don't need to pass ``-G "Unix Makefiles"`` command line option to ``cmake``. diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 4f10cad26..5ce4d2682 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -712,7 +712,7 @@ The following bugs are fixed in this release: bvshl when using a shift amount that evaluates to the length of the bit-vector. Thanks to Trevor Hansen and Robert Brummayer. -- Incorrect NNF conversion in linear quantifier elimniation routines. +- Incorrect NNF conversion in linear quantifier elimination routines. Thanks to Josh Berdine. - Missing constant folding of extraction for large bit-vectors. diff --git a/cmake/Z3Config.cmake.in b/cmake/Z3Config.cmake.in index e7f604591..dbd63b103 100644 --- a/cmake/Z3Config.cmake.in +++ b/cmake/Z3Config.cmake.in @@ -2,7 +2,7 @@ # @AUTO_GEN_MSG@ # # This file is intended to be consumed by clients who wish to use Z3 from CMake. -# It can be use by doing `find_package(Z3 config)` from within a +# It can be used by doing `find_package(Z3 config)` from within a # `CMakeLists.txt` file. If CMake doesn't find this package automatically you # can give it a hint by passing `-DZ3_DIR=` to the CMake invocation where # `` is the path to the directory containing this file. diff --git a/contrib/suppressions/sanitizers/README.md b/contrib/suppressions/sanitizers/README.md index f76f920b2..1d7cd0ac8 100644 --- a/contrib/suppressions/sanitizers/README.md +++ b/contrib/suppressions/sanitizers/README.md @@ -1,4 +1,4 @@ -# Sanitizer supression files +# Sanitizer suppression files This directory contains files used to suppress ASan/LSan/UBSan warnings/errors. diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index d71771f98..b947928a7 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -1546,7 +1546,7 @@ void two_contexts_example1() } /** - \brief Demonstrates how error codes can be read insted of registering an error handler. + \brief Demonstrates how error codes can be read instead of registering an error handler. */ void error_code_example1() { @@ -2533,7 +2533,7 @@ void reference_counter_example() { cfg = Z3_mk_config(); Z3_set_param_value(cfg, "model", "true"); - // Create a Z3 context where the user is reponsible for managing + // Create a Z3 context where the user is responsible for managing // Z3_ast reference counters. ctx = Z3_mk_context_rc(cfg); Z3_del_config(cfg); diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 71364013b..aec3bdcc5 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -622,7 +622,7 @@ namespace test_mapi Console.WriteLine("{0}", q1); } - // Quantifier with de-Brujin indices. + // Quantifier with de-Bruijn indices. { Expr x = ctx.MkBound(1, ctx.IntSort); Expr y = ctx.MkBound(0, ctx.IntSort); diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 40fb25a92..7b8902768 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -660,7 +660,7 @@ class JavaExample System.out.println(q1); } - // Quantifier with de-Brujin indices. + // Quantifier with de-Bruijn indices. { Expr x = ctx.mkBound(1, ctx.getIntSort()); Expr y = ctx.mkBound(0, ctx.getIntSort()); diff --git a/examples/maxsat/README b/examples/maxsat/README index e5e4ba610..6c24da66b 100644 --- a/examples/maxsat/README +++ b/examples/maxsat/README @@ -9,4 +9,4 @@ On OSX and Linux, you must install z3 first using sudo make install OR update LD_LIBRARY_PATH (Linux) or DYLD_LIBRARY_PATH (OSX) with the build directory. You need that to be able to find the Z3 shared library. -This directory contains a test file (ex.smt) that can be use as input for the maxsat test application. +This directory contains a test file (ex.smt) that can be used as input for the maxsat test application. diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs index ac23d1dbc..cbd6a1bac 100644 --- a/src/api/dotnet/Context.cs +++ b/src/api/dotnet/Context.cs @@ -2262,7 +2262,7 @@ namespace Microsoft.Z3 /// Maps f on the argument arrays. /// /// - /// Eeach element of args must be of an array sort [domain_i -> range_i]. + /// Each element of args must be of an array sort [domain_i -> range_i]. /// The function declaration f must have type range_1 .. range_n -> range. /// v must have sort range. The sort of the result is [domain_i -> range]. /// @@ -2862,7 +2862,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2878,7 +2878,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2894,7 +2894,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -2910,7 +2910,7 @@ namespace Microsoft.Z3 } /// - /// Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. + /// Create a Term of a given sort. This function can be used to create numerals that fit in a machine integer. /// It is slightly faster than MakeNumeral since it is not necessary to parse a string. /// /// Value of the numeral @@ -3211,7 +3211,7 @@ namespace Microsoft.Z3 /// Create an existential Quantifier. /// /// - /// Creates an existential quantifier using de-Brujin indexed variables. + /// Creates an existential quantifier using de-Bruijn indexed variables. /// (). /// public Quantifier MkExists(Sort[] sorts, Symbol[] names, Expr body, uint weight = 1, Pattern[] patterns = null, Expr[] noPatterns = null, Symbol quantifierID = null, Symbol skolemID = null) diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 4fd306052..0726f9d53 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -959,7 +959,7 @@ namespace Microsoft.Z3 /// Tn: (R t_n s_n) /// [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) /// Remark: if t_i == s_i, then the antecedent Ti is suppressed. - /// That is, reflexivity proofs are supressed to save space. + /// That is, reflexivity proofs are suppressed to save space. /// public bool IsProofMonotonicity { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_MONOTONICITY; } } @@ -1002,7 +1002,7 @@ namespace Microsoft.Z3 public bool IsProofAndElimination { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_AND_ELIM; } } /// - /// Indicates whether the term is a proof by eliminiation of not-or + /// Indicates whether the term is a proof by elimination of not-or /// /// /// Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). @@ -1112,7 +1112,7 @@ namespace Microsoft.Z3 public bool IsProofQuantInst { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_QUANT_INST; } } /// - /// Indicates whether the term is a hypthesis marker. + /// Indicates whether the term is a hypothesis marker. /// /// Mark a hypothesis in a natural deduction style proof. public bool IsProofHypothesis { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_PR_HYPOTHESIS; } } @@ -1433,7 +1433,7 @@ namespace Microsoft.Z3 /// /// Filter (restrict) a relation with respect to a predicate. /// The first argument is a relation. - /// The second argument is a predicate with free de-Brujin indices + /// The second argument is a predicate with free de-Bruijn indices /// corresponding to the columns of the relation. /// So the first column in the relation has index 0. /// @@ -1649,7 +1649,7 @@ namespace Microsoft.Z3 public bool IsFPMul { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_MUL; } } /// - /// Indicates whether the term is a floating-point divison term + /// Indicates whether the term is a floating-point division term /// public bool IsFPDiv { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_DIV; } } @@ -1709,7 +1709,7 @@ namespace Microsoft.Z3 public bool IsFPLe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_LE; } } /// - /// Indicates whether the term is a floating-point greater-than or erqual term + /// Indicates whether the term is a floating-point greater-than or equal term /// public bool IsFPGe { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_FPA_GE; } } @@ -1789,7 +1789,7 @@ namespace Microsoft.Z3 #region Bound Variables /// - /// The de-Burijn index of a bound variable. + /// The de-Bruijn index of a bound variable. /// /// /// Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain diff --git a/src/api/dotnet/Model.cs b/src/api/dotnet/Model.cs index 12992fa8a..d11a57052 100644 --- a/src/api/dotnet/Model.cs +++ b/src/api/dotnet/Model.cs @@ -253,7 +253,7 @@ namespace Microsoft.Z3 /// The uninterpreted sorts that the model has an interpretation for. /// /// - /// Z3 also provides an intepretation for uninterpreted sorts used in a formula. + /// Z3 also provides an interpretation for uninterpreted sorts used in a formula. /// The interpretation for a sort is a finite set of distinct values. We say this finite set is /// the "universe" of the sort. /// diff --git a/src/api/java/Context.java b/src/api/java/Context.java index 3458f4d97..7e73fc15e 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -2234,7 +2234,7 @@ public class Context implements AutoCloseable { } /** - * Create a Term of a given sort. This function can be use to create + * Create a Term of a given sort. This function can be used to create * numerals that fit in a machine integer. It is slightly faster than * {@code MakeNumeral} since it is not necessary to parse a string. * @@ -2250,7 +2250,7 @@ public class Context implements AutoCloseable { } /** - * Create a Term of a given sort. This function can be use to create + * Create a Term of a given sort. This function can be used to create * numerals that fit in a machine integer. It is slightly faster than * {@code MakeNumeral} since it is not necessary to parse a string. * @@ -2438,7 +2438,7 @@ public class Context implements AutoCloseable { } /** - * Creates an existential quantifier using de-Brujin indexed variables. + * Creates an existential quantifier using de-Bruijn indexed variables. * @see #mkForall(Sort[],Symbol[],Expr,int,Pattern[],Expr[],Symbol,Symbol) **/ public Quantifier mkExists(Sort[] sorts, Symbol[] names, Expr body, diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java index d3793a24b..7b20b7993 100644 --- a/src/api/java/Expr.java +++ b/src/api/java/Expr.java @@ -1421,7 +1421,7 @@ public class Expr extends AST * Remarks: T1: * (R t_1 s_1) ... Tn: (R t_n s_n) [monotonicity T1 ... Tn]: (R (f t_1 ... * t_n) (f s_1 ... s_n)) Remark: if t_i == s_i, then the antecedent Ti is - * suppressed. That is, reflexivity proofs are supressed to save space. + * suppressed. That is, reflexivity proofs are suppressed to save space. * * @throws Z3Exception on error * @return a boolean @@ -1473,7 +1473,7 @@ public class Expr extends AST } /** - * Indicates whether the term is a proof by eliminiation of not-or + * Indicates whether the term is a proof by elimination of not-or * Remarks: * Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). * T1: (not (or l_1 ... l_n)) [not-or-elim T1]: (not l_i) * @throws Z3Exception on error * @return a boolean @@ -1605,7 +1605,7 @@ public class Expr extends AST } /** - * Indicates whether the term is a hypthesis marker. + * Indicates whether the term is a hypothesis marker. * Remarks: Mark a * hypothesis in a natural deduction style proof. * @throws Z3Exception on error @@ -1987,7 +1987,7 @@ public class Expr extends AST * Indicates whether the term is a relation filter * Remarks: Filter * (restrict) a relation with respect to a predicate. The first argument is - * a relation. The second argument is a predicate with free de-Brujin + * a relation. The second argument is a predicate with free de-Bruijn * indices corresponding to the columns of the relation. So the first column * in the relation has index 0. * @throws Z3Exception on error @@ -2094,7 +2094,7 @@ public class Expr extends AST } /** - * The de-Burijn index of a bound variable. + * The de-Bruijn index of a bound variable. * Remarks: Bound variables are * indexed by de-Bruijn indices. It is perhaps easiest to explain the * meaning of de-Bruijn indices by indicating the compilation process from diff --git a/src/api/java/Model.java b/src/api/java/Model.java index 9c7013aca..d809b6790 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -239,7 +239,7 @@ public class Model extends Z3Object { /** * The uninterpreted sorts that the model has an interpretation for. - * Remarks: Z3 also provides an intepretation for uninterpreted sorts used + * Remarks: Z3 also provides an interpretation for uninterpreted sorts used * in a formula. The interpretation for a sort is a finite set of distinct * values. We say this finite set is the "universe" of the sort. * diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 80923a0c7..20a1e9c10 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -536,7 +536,7 @@ sig @return A Term with the given value and sort *) val mk_numeral_string : context -> string -> Sort.sort -> expr - (** Create a numeral of a given sort. This function can be use to create numerals that fit in a machine integer. + (** Create a numeral of a given sort. This function can be used to create numerals that fit in a machine integer. It is slightly faster than [MakeNumeral] since it is not necessary to parse a string. @return A Term with the given value and sort *) val mk_numeral_int : context -> int -> Sort.sort -> expr @@ -667,7 +667,7 @@ sig end - (** The de-Burijn index of a bound variable. + (** The de-Bruijn index of a bound variable. Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain the meaning of de-Bruijn indices by indicating the compilation process from @@ -830,7 +830,7 @@ sig (** Maps f on the argument arrays. - Eeach element of [args] must be of an array sort [[domain_i -> range_i]]. + Each element of [args] must be of an array sort [[domain_i -> range_i]]. The function declaration [f] must have type [ range_1 .. range_n -> range]. [v] must have sort range. The sort of the result is [[domain_i -> range]]. {!Z3Array.mk_sort} @@ -962,7 +962,7 @@ sig Filter (restrict) a relation with respect to a predicate. The first argument is a relation. - The second argument is a predicate with free de-Brujin indices + The second argument is a predicate with free de-Bruijn indices corresponding to the columns of the relation. So the first column in the relation has index 0. *) val is_filter : Expr.expr -> bool @@ -2085,7 +2085,7 @@ sig (** Indicates whether an expression is a floating-point lt expression *) val is_lt : Expr.expr -> bool - (** Indicates whether an expression is a floating-point geqexpression *) + (** Indicates whether an expression is a floating-point geq expression *) val is_geq : Expr.expr -> bool (** Indicates whether an expression is a floating-point gt expression *) @@ -2233,7 +2233,7 @@ sig (** Conversion of a 2's complement unsigned bit-vector term into a term of FloatingPoint sort. *) val mk_to_fp_unsigned : context -> Expr.expr -> Expr.expr -> Sort.sort -> Expr.expr - (** C1onversion of a floating-point term into an unsigned bit-vector. *) + (** Conversion of a floating-point term into an unsigned bit-vector. *) val mk_to_ubv : context -> Expr.expr -> Expr.expr -> int -> Expr.expr (** Conversion of a floating-point term into a signed bit-vector. *) @@ -2385,7 +2385,7 @@ sig Tn: (R t_n s_n) [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) Remark: if t_i == s_i, then the antecedent Ti is suppressed. - That is, reflexivity proofs are supressed to save space. *) + That is, reflexivity proofs are suppressed to save space. *) val is_monotonicity : Expr.expr -> bool (** Indicates whether the term is a quant-intro proof @@ -2417,7 +2417,7 @@ sig [and-elim T1]: l_i *) val is_and_elimination : Expr.expr -> bool - (** Indicates whether the term is a proof by eliminiation of not-or + (** Indicates whether the term is a proof by elimination of not-or Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). T1: (not (or l_1 ... l_n)) @@ -2500,7 +2500,7 @@ sig A proof of (or (not (forall (x) (P x))) (P a)) *) val is_quant_inst : Expr.expr -> bool - (** Indicates whether the term is a hypthesis marker. + (** Indicates whether the term is a hypothesis marker. Mark a hypothesis in a natural deduction style proof. *) val is_hypothesis : Expr.expr -> bool @@ -2882,7 +2882,7 @@ sig (** The uninterpreted sorts that the model has an interpretation for. - Z3 also provides an intepretation for uninterpreted sorts used in a formula. + Z3 also provides an interpretation for uninterpreted sorts used in a formula. The interpretation for a sort is a finite set of distinct values. We say this finite set is the "universe" of the sort. {!get_num_sorts} @@ -3056,7 +3056,7 @@ sig (** Create a tactic that fails if the probe evaluates to false. *) val fail_if : context -> Probe.probe -> tactic - (** Create a tactic that fails if the goal is not triviall satisfiable (i.e., empty) + (** Create a tactic that fails if the goal is not trivially satisfiable (i.e., empty) or trivially unsatisfiable (i.e., contains `false'). *) val fail_if_not_decided : context -> tactic @@ -3105,7 +3105,7 @@ sig (** True if the entry is float-valued. *) val is_float : statistics_entry -> bool - (** The string representation of the the entry's value. *) + (** The string representation of the entry's value. *) val to_string_value : statistics_entry -> string (** The string representation of the entry (key and value) *) @@ -3370,7 +3370,7 @@ sig (** Assert a constraints into the optimize solver. *) val add : optimize -> Expr.expr list -> unit - (** Asssert a soft constraint. + (** Assert a soft constraint. Supply integer weight and string that identifies a group of soft constraints. *) val add_soft : optimize -> Expr.expr -> string -> Symbol.symbol -> handle diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 465e9aab8..4896a475d 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -182,7 +182,7 @@ class Context: """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. + interruptible procedure. """ Z3_interrupt(self.ref()) @@ -602,7 +602,7 @@ def _sort(ctx, a): return _to_sort_ref(Z3_get_sort(ctx.ref(), a), ctx) def DeclareSort(name, ctx=None): - """Create a new uninterpred sort named `name`. + """Create a new uninterpreted sort named `name`. If `ctx=None`, then the new sort is declared in the global Z3Py context. @@ -724,7 +724,7 @@ class FuncDeclRef(AstRef): The arguments must be Z3 expressions. This method assumes that the sorts of the elements in `args` match the sorts of the - domain. Limited coersion is supported. For example, if + domain. Limited coercion is supported. For example, if args[0] is a Python integer, and the function expects a Z3 integer, then the argument is automatically converted into a Z3 integer. @@ -9243,7 +9243,7 @@ def fpMul(rm, a, b, ctx=None): 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. + """Create a Z3 floating-point division expression. >>> s = FPSort(8, 24) >>> rm = RNE() @@ -9270,7 +9270,7 @@ def fpRem(a, b, ctx=None): return _mk_fp_bin_norm(Z3_mk_fpa_rem, a, b, ctx) def fpMin(a, b, ctx=None): - """Create a Z3 floating-point minimium expression. + """Create a Z3 floating-point minimum expression. >>> s = FPSort(8, 24) >>> rm = RNE() diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 0ba49a5e5..5e5b84450 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -270,7 +270,7 @@ typedef enum - Z3_OP_ARRAY_MAP Array map operator. It satisfies map[f](a1,..,a_n)[i] = f(a1[i],...,a_n[i]) for every i. - - Z3_OP_SET_UNION Set union between two Booelan arrays (two arrays whose range type is Boolean). The function is binary. + - Z3_OP_SET_UNION Set union between two Boolean arrays (two arrays whose range type is Boolean). The function is binary. - Z3_OP_SET_INTERSECT Set intersection between two Boolean arrays. The function is binary. @@ -406,7 +406,7 @@ typedef enum - Z3_OP_BSMUL_NO_UDFL: check that bit-wise signed multiplication does not underflow. Signed multiplication underflows if the operands have opposite signs and the result of multiplication - does not fit within the avaialble bits. Z3_mk_bvmul_no_underflow. + does not fit within the available bits. Z3_mk_bvmul_no_underflow. - Z3_OP_BSDIV_I: Binary signed division. It has the same semantics as Z3_OP_BSDIV, but created in a context where the second operand can be assumed to be non-zero. @@ -485,7 +485,7 @@ typedef enum [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) } Remark: if t_i == s_i, then the antecedent Ti is suppressed. - That is, reflexivity proofs are supressed to save space. + That is, reflexivity proofs are suppressed to save space. - Z3_OP_PR_QUANT_INTRO: Given a proof for (~ p q), produces a proof for (~ (forall (x) p) (forall (x) q)). @@ -832,7 +832,7 @@ typedef enum - Z3_OP_RA_FILTER: Filter (restrict) a relation with respect to a predicate. The first argument is a relation. - The second argument is a predicate with free de-Brujin indices + The second argument is a predicate with free de-Bruijn indices corresponding to the columns of the relation. So the first column in the relation has index 0. @@ -969,7 +969,7 @@ typedef enum - Z3_OP_FPA_TO_FP: Floating-point conversion (various) - - Z3_OP_FPA_TO_FP_UNSIGNED: Floating-point conversion from unsigend bit-vector + - Z3_OP_FPA_TO_FP_UNSIGNED: Floating-point conversion from unsigned bit-vector - Z3_OP_FPA_TO_UBV: Floating-point conversion to unsigned bit-vector @@ -984,7 +984,7 @@ typedef enum of non-relevant terms in theory_fpa) - Z3_OP_FPA_BV2RM: Conversion of a 3-bit bit-vector term to a - floating-point rouding-mode term + floating-point rounding-mode term The conversion uses the following values: 0 = 000 = Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN, @@ -1922,7 +1922,7 @@ extern "C" { \param c logical context \param name name of the enumeration sort. - \param n number of elemenets in enumeration sort. + \param n number of elements in enumeration sort. \param enum_names names of the enumerated elements. \param enum_consts constants corresponding to the enumerated elements. \param enum_testers predicates testing if terms of the enumeration sort correspond to an enumeration. @@ -3186,7 +3186,7 @@ extern "C" { \param c logical context. \param num numerator of rational. - \param den denomerator of rational. + \param den denominator of rational. \pre den != 0 @@ -3201,7 +3201,7 @@ extern "C" { /** \brief Create a numeral of an int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine integer. + This function can be used to create numerals that fit in a machine integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3213,7 +3213,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine unsinged integer. + This function can be used to create numerals that fit in a machine unsigned integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3225,7 +3225,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine __int64 integer. + This function can be used to create numerals that fit in a machine __int64 integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3237,7 +3237,7 @@ extern "C" { /** \brief Create a numeral of a int, bit-vector, or finite-domain sort. - This function can be use to create numerals that fit in a machine __uint64 integer. + This function can be used to create numerals that fit in a machine __uint64 integer. It is slightly faster than #Z3_mk_numeral since it is not necessary to parse a string. \sa Z3_mk_numeral @@ -3493,8 +3493,8 @@ extern "C" { Z3_ast Z3_API Z3_mk_re_range(Z3_context c, Z3_ast lo, Z3_ast hi); /** - \brief Create a regular expression loop. The supplied regular expression \c r is repated - between \c lo and \c hi times. The \c lo should be below \c hi with one exection: when + \brief Create a regular expression loop. The supplied regular expression \c r is repeated + between \c lo and \c hi times. The \c lo should be below \c hi with one exception: when supplying the value \c hi as 0, the meaning is to repeat the argument \c r at least \c lo number of times, and with an unbounded upper bound. @@ -4248,7 +4248,7 @@ extern "C" { Z3_sort Z3_API Z3_get_decl_sort_parameter(Z3_context c, Z3_func_decl d, unsigned idx); /** - \brief Return the expresson value associated with an expression parameter. + \brief Return the expression value associated with an expression parameter. \pre Z3_get_decl_parameter_kind(c, d, idx) == Z3_PARAMETER_AST @@ -4257,7 +4257,7 @@ extern "C" { Z3_ast Z3_API Z3_get_decl_ast_parameter(Z3_context c, Z3_func_decl d, unsigned idx); /** - \brief Return the expresson value associated with an expression parameter. + \brief Return the expression value associated with an expression parameter. \pre Z3_get_decl_parameter_kind(c, d, idx) == Z3_PARAMETER_FUNC_DECL @@ -4327,7 +4327,7 @@ extern "C" { /** \brief Return a hash code for the given AST. - The hash code is structural. You can use Z3_get_ast_id interchangably with + The hash code is structural. You can use Z3_get_ast_id interchangeably with this function. def_API('Z3_get_ast_hash', UINT, (_in(CONTEXT), _in(AST))) @@ -4556,7 +4556,7 @@ extern "C" { Z3_ast Z3_API Z3_get_pattern(Z3_context c, Z3_pattern p, unsigned idx); /** - \brief Return index of de-Brujin bound variable. + \brief Return index of de-Bruijn bound variable. \pre Z3_get_ast_kind(a) == Z3_VAR_AST @@ -4659,7 +4659,7 @@ extern "C" { Provides an interface to the AST simplifier used by Z3. It returns an AST object which is equal to the argument. - The returned AST is simplified using algebraic simplificaiton rules, + The returned AST is simplified using algebraic simplification rules, such as constant propagation (propagating true/false over logical connectives). def_API('Z3_simplify', AST, (_in(CONTEXT), _in(AST))) @@ -4861,9 +4861,9 @@ extern "C" { Z3_func_decl Z3_API Z3_model_get_func_decl(Z3_context c, Z3_model m, unsigned i); /** - \brief Return the number of uninterpreted sorts that \c m assigs an interpretation to. + \brief Return the number of uninterpreted sorts that \c m assigns an interpretation to. - Z3 also provides an intepretation for uninterpreted sorts used in a formua. + Z3 also provides an interpretation for uninterpreted sorts used in a formula. The interpretation for a sort \c s is a finite set of distinct values. We say this finite set is the "universe" of \c s. @@ -4971,7 +4971,7 @@ extern "C" { unsigned Z3_API Z3_func_interp_get_num_entries(Z3_context c, Z3_func_interp f); /** - \brief Return a "point" of the given function intepretation. It represents the + \brief Return a "point" of the given function interpretation. It represents the value of \c f in a particular point. \pre i < Z3_func_interp_get_num_entries(c, f) @@ -5013,7 +5013,7 @@ extern "C" { \brief add a function entry to a function interpretation. \param c logical context - \param fi a function interpregation to be updated. + \param fi a function interpretation to be updated. \param args list of arguments. They should be constant values (such as integers) and be of the same types as the domain of the function. \param value value of the function when the parameters match args. @@ -5466,7 +5466,7 @@ extern "C" { Z3_bool Z3_API Z3_goal_is_decided_unsat(Z3_context c, Z3_goal g); /** - \brief Copy a goal \c g from the context \c source to a the context \c target. + \brief Copy a goal \c g from the context \c source to the context \c target. def_API('Z3_goal_translate', GOAL, (_in(CONTEXT), _in(GOAL), _in(CONTEXT))) */ @@ -5932,7 +5932,7 @@ extern "C" { Z3_solver Z3_API Z3_mk_solver_from_tactic(Z3_context c, Z3_tactic t); /** - \brief Copy a solver \c s from the context \c source to a the context \c target. + \brief Copy a solver \c s from the context \c source to the context \c target. def_API('Z3_solver_translate', SOLVER, (_in(CONTEXT), _in(SOLVER), _in(CONTEXT))) */ diff --git a/src/ast/ast.h b/src/ast/ast.h index 2d06d03de..24e2b93b6 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -330,7 +330,7 @@ std::ostream& operator<<(std::ostream& out, sort_size const & ss); // ----------------------------------- /** - \brief Extra information that may be attached to intepreted sorts. + \brief Extra information that may be attached to interpreted sorts. */ class sort_info : public decl_info { sort_size m_num_elements; @@ -932,7 +932,7 @@ struct builtin_name { }; /** - \brief Each family of intepreted function declarations and sorts must provide a plugin + \brief Each family of interpreted function declarations and sorts must provide a plugin to build sorts and decls of the family. */ class decl_plugin { @@ -1059,7 +1059,7 @@ protected: ptr_vector m_eq_decls; // cached eqs ptr_vector m_ite_decls; // cached ites - ptr_vector m_oeq_decls; // cached obsevational eqs + ptr_vector m_oeq_decls; // cached observational eqs sort * m_proof_sort; func_decl * m_undef_decl; func_decl * m_true_pr_decl; @@ -1161,7 +1161,7 @@ public: virtual expr * get_some_value(sort * s); }; -typedef app proof; /* a proof is just an applicaton */ +typedef app proof; /* a proof is just an application */ // ----------------------------------- // @@ -1220,7 +1220,7 @@ enum pattern_op_kind { /** \brief Patterns are used to group expressions. These expressions are using during E-matching for - heurisitic quantifier instantiation. + heuristic quantifier instantiation. */ class pattern_decl_plugin : public decl_plugin { public: @@ -1245,13 +1245,13 @@ enum model_value_op_kind { /** \brief Values are used during model construction. All values are assumed to be different. Users should not use them, since they may - introduce unsoundess if the sort of a value is finite. + introduce unsoundness if the sort of a value is finite. Moreover, values should never be internalized in a logical context. However, values can be used during evaluation (i.e., simplification). - \remark Model values can be viewed as the partion ids in Z3 1.x. + \remark Model values can be viewed as the partition ids in Z3 1.x. */ class model_value_decl_plugin : public decl_plugin { public: diff --git a/src/ast/proofs/proof_checker.cpp b/src/ast/proofs/proof_checker.cpp index 6fd876efc..5126198c6 100644 --- a/src/ast/proofs/proof_checker.cpp +++ b/src/ast/proofs/proof_checker.cpp @@ -502,7 +502,7 @@ bool proof_checker::check1_basic(proof* p, expr_ref_vector& side_conditions) { return false; } case PR_HYPOTHESIS: { - // TBD all branches with hyptheses must be closed by a later lemma. + // TBD all branches with hypotheses must be closed by a later lemma. if (match_proof(p) && match_fact(p, fml)) { return true; diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp index fc9d0fac6..32cb9cccb 100755 --- a/src/interp/iz3proof_itp.cpp +++ b/src/interp/iz3proof_itp.cpp @@ -55,7 +55,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /* The summation rule. The term sum(p,c,i) takes a proof p of an inequality i', an integer coefficient c and an inequality i, and - yieds a proof of i' + ci. */ + yields a proof of i' + ci. */ symb sum; /* Proof rotation. The proof term rotate(q,p) takes a @@ -75,7 +75,7 @@ class iz3proof_itp_impl : public iz3proof_itp { symb leq2eq; /* Equality to inequality. eq2leq(p, q) takes a proof p of x=y, and - a proof q ~(x <= y) and and yields a proof of false. */ + a proof q ~(x <= y) and yields a proof of false. */ symb eq2leq; /* Proof term cong(p,q) takes a proof p of x=y and a proof @@ -97,7 +97,7 @@ class iz3proof_itp_impl : public iz3proof_itp { /* This oprerator represents a concatenation of rewrites. The term a=b;c=d represents an A rewrite from a to b, followed by a B - rewrite fron b to c, followed by an A rewrite from c to d. + rewrite from b to c, followed by an A rewrite from c to d. */ symb concat; @@ -1542,7 +1542,7 @@ class iz3proof_itp_impl : public iz3proof_itp { return my_implies(arg(rew,1),arg(rew,2)); } - // make rewrite rew conditon on rewrite cond + // make rewrite rew condition on rewrite cond ast rewrite_conditional(const ast &cond, const ast &rew){ ast cf = rewrite_to_formula(cond); return make(sym(rew),arg(rew,0),my_and(arg(rew,1),cf),arg(rew,2)); diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp index b88e488b4..e71475e45 100755 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -9,7 +9,7 @@ Translate a Z3 proof into the interpolating proof calculus. Translation is direct, without transformations on the target proof - representaiton. + representation. Author: diff --git a/src/math/simplex/simplex_def.h b/src/math/simplex/simplex_def.h index 762e8ceb2..ceec60622 100644 --- a/src/math/simplex/simplex_def.h +++ b/src/math/simplex/simplex_def.h @@ -634,7 +634,7 @@ namespace simplex { // // max { c*x | A*x = 0 and l <= x <= u } // - // start with feasible assigment + // start with feasible assignment // A*x0 = 0 and l <= x0 <= u // // Identify pivot: i, j: such that x_i is base, diff --git a/src/muz/rel/dl_compiler.h b/src/muz/rel/dl_compiler.h index 9aedf141a..6ac33ae91 100644 --- a/src/muz/rel/dl_compiler.h +++ b/src/muz/rel/dl_compiler.h @@ -60,7 +60,7 @@ namespace datalog { ACK_UNBOUND_VAR(var_index) - encodes that the column contains a variable that is unbound (by the corresponding rule body), - var_index is the de-Brujin index (var->get_idx()) + var_index is the de-Bruijn index (var->get_idx()) of the variable associated with the column. ACK_CONSTANT(constant) - encodes that the column contains the constant. diff --git a/src/muz/rel/dl_relation_manager.h b/src/muz/rel/dl_relation_manager.h index c77127eb7..610c523e1 100644 --- a/src/muz/rel/dl_relation_manager.h +++ b/src/muz/rel/dl_relation_manager.h @@ -609,7 +609,7 @@ namespace datalog { std::string to_nice_string(const relation_element & el) const; /** This one may give a nicer representation of \c el than the - \c to_nice_string(const relation_element & el) function, by unsing the information about the sort + \c to_nice_string(const relation_element & el) function, by using the information about the sort of the element. */ std::string to_nice_string(const relation_sort & s, const relation_element & el) const; diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 448aa624d..12b063759 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -89,7 +89,7 @@ namespace nlsat { unsigned m_num_bool_vars; atom_vector m_atoms; // bool_var -> atom - svector m_bvalues; // boolean assigment + svector m_bvalues; // boolean assignment unsigned_vector m_levels; // bool_var -> level svector m_justifications; vector m_bwatches; // bool_var (that are not attached to atoms) -> clauses where it is maximal @@ -1051,7 +1051,7 @@ namespace nlsat { } /** - \brief Process a clause that contains nonlinar arithmetic literals + \brief Process a clause that contains nonlinear arithmetic literals If satisfy_learned is true, then learned clauses are satisfied even if m_lazy > 0 */ @@ -1569,7 +1569,7 @@ namespace nlsat { max = lvl; } else { - // l must be a literal from a previous stage that is false in the current intepretation + // l must be a literal from a previous stage that is false in the current interpretation SASSERT(assigned_value(l) == l_undef); SASSERT(max_var(b) != null_var); SASSERT(m_xk != null_var); @@ -1890,7 +1890,7 @@ namespace nlsat { // ----------------------- // - // Variable reodering + // Variable reordering // // ----------------------- diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 01806bc24..3975945cb 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -974,7 +974,7 @@ namespace ar { // ------------------------------------------------------------ -// fm_tactic adapted to eliminate designated de-Brujin indices. +// fm_tactic adapted to eliminate designated de-Bruijn indices. namespace fm { typedef ptr_vector clauses; diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp index 96334e3ce..c979e476e 100644 --- a/src/smt/mam.cpp +++ b/src/smt/mam.cpp @@ -188,7 +188,7 @@ namespace smt { 1) Variables: (f ... X ...) 2) Ground terms: (f ... t ...) 3) depth 2 joint: (f ... (g ... X ...) ...) - Joint2 stores the declartion g, and the position of variable X, and its idx. + Joint2 stores the declaration g, and the position of variable X, and its idx. \remark Z3 has no support for depth 3 joints (f ... (g ... (h ... X ...) ...) ....) */ @@ -211,7 +211,7 @@ namespace smt { approx_set m_lbl_set; // singleton set containing m_label /* The following field is an array of tagged pointers. - Each positon contains: + Each position contains: 1- null (no joint), NULL_TAG 2- a boxed integer (i.e., register that contains the variable bind) VAR_TAG 3- an enode pointer (ground term) GROUND_TERM_TAG diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index ffaee434f..c38ef4e4a 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -369,7 +369,7 @@ namespace smt { else { TRACE("internalize_bug", tout << "creating enode for #" << n->get_id() << "\n";); mk_enode(to_app(n), - true, /* supress arguments, we not not use CC for this kind of enode */ + true, /* suppress arguments, we not not use CC for this kind of enode */ true, /* bool enode must be merged with true/false, since it is not in the context of a gate */ false /* CC is not enabled */ ); set_enode_flag(v, false); @@ -453,7 +453,7 @@ namespace smt { // must be associated with an enode. if (!e_internalized(n)) { mk_enode(to_app(n), - true, /* supress arguments, we not not use CC for this kind of enode */ + true, /* suppress arguments, we not not use CC for this kind of enode */ true /* bool enode must be merged with true/false, since it is not in the context of a gate */, false /* CC is not enabled */); } @@ -739,7 +739,7 @@ namespace smt { app_ref eq1(mk_eq_atom(n, t), m_manager); app_ref eq2(mk_eq_atom(n, e), m_manager); mk_enode(n, - true /* supress arguments, I don't want to apply CC on ite terms */, + true /* suppress arguments, I don't want to apply CC on ite terms */, false /* it is a term, so it should not be merged with true/false */, false /* CC is not enabled */); internalize(c, true); @@ -797,7 +797,7 @@ namespace smt { } enode * e = mk_enode(n, - false, /* do not supress args */ + false, /* do not suppress args */ false, /* it is a term, so it should not be merged with true/false */ true); apply_sort_cnstr(n, e); @@ -1506,7 +1506,7 @@ namespace smt { relevancy_eh * eh = m_relevancy_propagator->mk_and_relevancy_eh(n); unsigned num = n->get_num_args(); for (unsigned i = 0; i < num; i++) { - // if one child is assigned to false, the the and-parent must be notified + // if one child is assigned to false, the and-parent must be notified literal l = get_literal(n->get_arg(i)); add_rel_watch(~l, eh); } @@ -1518,7 +1518,7 @@ namespace smt { relevancy_eh * eh = m_relevancy_propagator->mk_or_relevancy_eh(n); unsigned num = n->get_num_args(); for (unsigned i = 0; i < num; i++) { - // if one child is assigned to true, the the or-parent must be notified + // if one child is assigned to true, the or-parent must be notified literal l = get_literal(n->get_arg(i)); add_rel_watch(l, eh); } diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 28a65f898..f443d671b 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -537,7 +537,7 @@ namespace smt { } } - // For each instantiation_set, reemove entries that do not evaluate to values. + // For each instantiation_set, remove entries that do not evaluate to values. void cleanup_instantiation_sets() { ptr_vector to_delete; for (node * curr : m_nodes) { @@ -735,7 +735,7 @@ namespace smt { } } // TBD: add support for the else of bitvectors. - // Idea: get the term t with the minimal interpreation and use t - 1. + // Idea: get the term t with the minimal interpretation and use t - 1. } n->set_else((*(elems.begin())).m_key); } @@ -955,7 +955,7 @@ namespace smt { if (elems.empty()) { // The method get_some_value cannot be used if n->get_sort() is an uninterpreted sort or is a sort built using uninterpreted sorts // (e.g., (Array S S) where S is uninterpreted). The problem is that these sorts do not have a fixed interpretation. - // Moreover, a model assigns an arbitrary intepretation to these sorts using "model_values" a model value. + // Moreover, a model assigns an arbitrary interpretation to these sorts using "model_values" a model value. // If these module values "leak" inside the logical context, they may affect satisfiability. // sort * ns = n->get_sort(); @@ -1007,7 +1007,7 @@ namespace smt { This may happen because the evaluator uses model_completion. In the beginning of fix_model() we collected all f with partial interpretations. During the process of computing the - projections we used the evalutator with model_completion, + projections we used the evaluator with model_completion, and it may have fixed the "else" case of some partial interpretations. This is ok, because in the "limit" the "else" of the interpretation is irrelevant after the projections are applied. @@ -1570,7 +1570,7 @@ namespace smt { ast_manager & m = ctx->get_manager(); sort * s = q->get_decl_sort(num_vars - m_var_i - 1); if (m.is_uninterp(s)) { - // For uninterpreted sorst, we add all terms in the context. + // For uninterpreted sorts, we add all terms in the context. // See Section 4.1 in the paper "Complete Quantifier Instantiation" node * S_q_i = slv.get_uvar(q, m_var_i); ptr_vector::const_iterator it = ctx->begin_enodes(); @@ -1741,7 +1741,7 @@ namespace smt { if (has_quantifiers(q->get_expr())) { static bool displayed_flat_msg = false; if (!displayed_flat_msg) { - // [Leo]: This warning message is not usefult. + // [Leo]: This warning message is not useful. // warning_msg("For problems containing quantifiers, the model finding capabilities of Z3 work better when the formula does not contain nested quantifiers. You can use PULL_NESTED_QUANTIFIERS=true to eliminate nested quantifiers."); displayed_flat_msg = true; } @@ -2104,7 +2104,7 @@ namespace smt { } /** - \brief Process unintrepreted applications. + \brief Process uninterpreted applications. */ void process_u_app(app * t) { unsigned num_args = t->get_num_args(); @@ -2130,7 +2130,7 @@ namespace smt { /** \brief A term \c t is said to be a auf_select if - it is of ther form + it is of the form (select a i) Where: @@ -2151,7 +2151,7 @@ namespace smt { } /** - \brief Process intrepreted applications. + \brief Process interpreted applications. */ void process_i_app(app * t) { if (is_auf_select(t)) { @@ -2512,7 +2512,7 @@ namespace smt { SASSERT(f_else != 0); // Remark: I can ignore the conditions of m because // I know the (partial) interpretation of f satisfied the ground part. - // MBQI will force extra instantiations if the the (partial) interpretation of f + // MBQI will force extra instantiations if the (partial) interpretation of f // does not satisfy the quantifier. // In all other cases the "else" of f will satisfy the quantifier. set_else_interp(f, f_else); @@ -2937,7 +2937,7 @@ namespace smt { } /** - \brief Use m_fs to set the interpreation of the function symbols that were used to satisfy the + \brief Use m_fs to set the interpretation of the function symbols that were used to satisfy the quantifiers in m_satisfied. */ void set_interp() { diff --git a/src/smt/smt_quantifier.h b/src/smt/smt_quantifier.h index d89f3f6a4..ad5f58e49 100644 --- a/src/smt/smt_quantifier.h +++ b/src/smt/smt_quantifier.h @@ -152,7 +152,7 @@ namespace smt { virtual bool mbqi_enabled(quantifier *q) const {return true;} /** - \brief Give a change to the plugin to adjust the interpretation of unintepreted functions. + \brief Give a change to the plugin to adjust the interpretation of uninterpreted functions. It can basically change the "else" of each uninterpreted function. */ virtual void adjust_model(proto_model * m) = 0; diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 806b2a05b..6794ca3ac 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -660,7 +660,7 @@ namespace smt { satisfy their respective constraints. However, when they do that the may create inconsistencies in the other modules. I use m_liberal_final_check to avoid infinite - loops where the modules keep changing the assigment and no + loops where the modules keep changing the assignment and no progress is made. If m_liberal_final_check is set to false, these modules will avoid mutating the assignment to satisfy constraints. diff --git a/src/tactic/arith/purify_arith_tactic.h b/src/tactic/arith/purify_arith_tactic.h index bbb62710c..44b4f9b58 100644 --- a/src/tactic/arith/purify_arith_tactic.h +++ b/src/tactic/arith/purify_arith_tactic.h @@ -16,7 +16,7 @@ Abstract: Remarks: - The semantics of division by zero is not specified. Thus, uninterpreted functions are used. An ExRCF procedure may - treat the unintepreted function applications as fresh + treat the uninterpreted function applications as fresh constants. Then, in any model produced by this procedure, the interpretation for division by zero must be checked. diff --git a/src/tactic/ufbv/ufbv_rewriter.h b/src/tactic/ufbv/ufbv_rewriter.h index 1e13f4fa4..af9888751 100644 --- a/src/tactic/ufbv/ufbv_rewriter.h +++ b/src/tactic/ufbv/ufbv_rewriter.h @@ -74,7 +74,7 @@ each offset is a different "variable bank". A pair (expr, offset) is essentially where every variable in expr is assumed to be from the "bank" offset. The class substitution (in substitution.h) manages offsets for us. -The class matcher (in matcher.h) can be use to test whether an expression is an instance of another one. +The class matcher (in matcher.h) can be used to test whether an expression is an instance of another one. Finally, there is the problem when we have N demodulators (where N is big), and a big formula, and we want to traverse the formula only once looking for opportunities for applying these N demodulators. From a3ad0aff8b6750c25e730c3e6493736545fd841c Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 22:50:50 +0700 Subject: [PATCH 28/37] print_stat_f: Remove implicit conversion of float to double. --- src/util/stats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/stats.h b/src/util/stats.h index 0acc18f43..680f9c9df 100644 --- a/src/util/stats.h +++ b/src/util/stats.h @@ -29,7 +29,7 @@ inline void print_stat(std::ostream& out, char const* msg, unsigned num) { } inline void print_stat_f(std::ostream& out, char const* msg, float num) { - if (num > 0.0) { + if (num > 0.0f) { out << msg << num << "\n"; } } From a875d3e491052bccb62ac490cbb554a97be4c129 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jan 2018 07:54:31 -0800 Subject: [PATCH 29/37] fix #1429 Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index ce305bb4e..120b0ddfd 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1994,7 +1994,7 @@ struct if csn <> cs || cdn <> cd then raise (Error "Argument size mismatch") else - Z3native.parse_smtlib2_string ctx file_name + Z3native.parse_smtlib2_file ctx file_name cs sort_names sorts cd decl_names decls end From a5a31fc23cd74463749da2911a71d60edcddcb19 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:11:36 +0700 Subject: [PATCH 30/37] Fix code formatting: Incorrect indentation. --- src/util/container_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/container_util.h b/src/util/container_util.h index e114c87b9..e68ab7199 100644 --- a/src/util/container_util.h +++ b/src/util/container_util.h @@ -29,7 +29,7 @@ Revision History: // ----------------------------------- template - void set_intersection(Set1 & tgt, const Set2 & src) { +void set_intersection(Set1 & tgt, const Set2 & src) { svector to_remove; for (auto const& itm : tgt) if (!src.contains(itm)) From 11db7784425516f77d1a378cea2a3c5bb5589a63 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:12:28 +0700 Subject: [PATCH 31/37] Remove ignored const qualifiers. The `const` qualifier on a scalar value is ignored in return types. --- src/util/lp/numeric_pair.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/lp/numeric_pair.h b/src/util/lp/numeric_pair.h index 4ebe63613..a8a743a71 100644 --- a/src/util/lp/numeric_pair.h +++ b/src/util/lp/numeric_pair.h @@ -38,10 +38,10 @@ template class numeric_traits {}; template <> class numeric_traits { public: static bool precise() { return true; } - static unsigned const zero() { return 0; } - static unsigned const one() { return 1; } + static unsigned zero() { return 0; } + static unsigned one() { return 1; } static bool is_zero(unsigned v) { return v == 0; } - static double const get_double(unsigned const & d) { return d; } + static double get_double(unsigned const & d) { return d; } }; template <> class numeric_traits { @@ -66,7 +66,7 @@ template <> class numeric_traits { static rational const & zero() { return rational::zero(); } static rational const & one() { return rational::one(); } static bool is_zero(const rational & v) { return v.is_zero(); } - static double const get_double(const rational & d) { return d.get_double();} + static double get_double(const rational & d) { return d.get_double();} static rational log(rational const& r) { UNREACHABLE(); return r; } static rational from_string(std::string const & str) { return rational(str.c_str()); } static bool is_pos(const rational & d) {return d.is_pos();} From 5a0f5a778fd6cdc383dd3594034b456b5911fb99 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:14:29 +0700 Subject: [PATCH 32/37] Remove unnecessary copy of coeff in iteration. --- src/smt/theory_lra.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 292d2ab0d..21b66d3a0 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1916,7 +1916,7 @@ namespace smt { lp::var_index vi = m_theory_var2var_index[v]; SASSERT(m_solver->is_term(vi)); lp::lar_term const& term = m_solver->get_term(vi); - for (auto const coeff : term.m_coeffs) { + for (auto const& coeff : term.m_coeffs) { lp::var_index wi = coeff.first; lp::constraint_index ci; rational value; From b06f4135852cce8649fa1da92a9a53a8c7994782 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Tue, 2 Jan 2018 23:20:00 +0700 Subject: [PATCH 33/37] raise_exception: Annotate that this doesn't return. --- src/ast/ast.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index 24e2b93b6..ea97af004 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,6 +53,12 @@ Revision History: #pragma warning(disable : 4355) #endif +#ifdef __GNUC__ +# define Z3_NORETURN __attribute__((noreturn)) +#else +# define Z3_NORETURN +#endif + class ast; class ast_manager; @@ -1515,7 +1521,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - void raise_exception(char const * msg); + void raise_exception(char const * msg) Z3_NORETURN; bool is_format_manager() const { return m_format_manager == 0; } From 7457fa77cb44f9cfdfb4fc552581e10c41ee69b6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jan 2018 08:46:17 -0800 Subject: [PATCH 34/37] add noreturn attribute #1435 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 41 ++++++++++++++--------------------------- src/ast/ast.h | 8 +------- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 3824325b3..0f18170df 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1492,11 +1492,8 @@ void ast_manager::compact_memory() { unsigned capacity = m_ast_table.capacity(); if (capacity > 4*m_ast_table.size()) { ast_table new_ast_table; - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - new_ast_table.insert(*it); - } + for (ast* curr : m_ast_table) + new_ast_table.insert(curr); m_ast_table.swap(new_ast_table); IF_VERBOSE(10, verbose_stream() << "(ast-table :prev-capacity " << capacity << " :capacity " << m_ast_table.capacity() << " :size " << m_ast_table.size() << ")\n";); @@ -1510,10 +1507,7 @@ void ast_manager::compress_ids() { ptr_vector asts; m_expr_id_gen.cleanup(); m_decl_id_gen.cleanup(c_first_decl_id); - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - ast * n = *it; + for (ast * n : m_ast_table) { if (is_decl(n)) n->m_id = m_decl_id_gen.mk(); else @@ -1521,13 +1515,11 @@ void ast_manager::compress_ids() { asts.push_back(n); } m_ast_table.finalize(); - ptr_vector::iterator it2 = asts.begin(); - ptr_vector::iterator end2 = asts.end(); - for (; it2 != end2; ++it2) - m_ast_table.insert(*it2); + for (ast* a : asts) + m_ast_table.insert(a); } -void ast_manager::raise_exception(char const * msg) { +[[noreturn]] void ast_manager::raise_exception(char const * msg) { throw ast_exception(msg); } @@ -1570,20 +1562,15 @@ void ast_manager::copy_families_plugins(ast_manager const & from) { } void ast_manager::set_next_expr_id(unsigned id) { - while (true) { - id = m_expr_id_gen.set_next_id(id); - ast_table::iterator it = m_ast_table.begin(); - ast_table::iterator end = m_ast_table.end(); - for (; it != end; ++it) { - ast * curr = *it; - if (curr->get_id() == id) - break; + try_again: + id = m_expr_id_gen.set_next_id(id); + for (ast * curr : m_ast_table) { + if (curr->get_id() == id) { + // id is in use, move to the next one. + ++id; + goto try_again; } - if (it == end) - return; - // id is in use, move to the next one. - id++; - } + } } unsigned ast_manager::get_node_size(ast const * n) { return ::get_node_size(n); } diff --git a/src/ast/ast.h b/src/ast/ast.h index ea97af004..482ec3a99 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,12 +53,6 @@ Revision History: #pragma warning(disable : 4355) #endif -#ifdef __GNUC__ -# define Z3_NORETURN __attribute__((noreturn)) -#else -# define Z3_NORETURN -#endif - class ast; class ast_manager; @@ -1521,7 +1515,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - void raise_exception(char const * msg) Z3_NORETURN; + [[noreturn]] void raise_exception(char const * msg); bool is_format_manager() const { return m_format_manager == 0; } From 16044c74bfcd64384065fa38b514882a52a013c7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jan 2018 09:29:14 -0800 Subject: [PATCH 35/37] revert use of [[noreturn]]. It's not fully supported on compilers #1435 Signed-off-by: Nikolaj Bjorner --- src/ast/ast.cpp | 2 +- src/ast/ast.h | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 0f18170df..cc4beb1b6 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1519,7 +1519,7 @@ void ast_manager::compress_ids() { m_ast_table.insert(a); } -[[noreturn]] void ast_manager::raise_exception(char const * msg) { +void ast_manager::raise_exception(char const * msg) { throw ast_exception(msg); } diff --git a/src/ast/ast.h b/src/ast/ast.h index 482ec3a99..ea97af004 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,6 +53,12 @@ Revision History: #pragma warning(disable : 4355) #endif +#ifdef __GNUC__ +# define Z3_NORETURN __attribute__((noreturn)) +#else +# define Z3_NORETURN +#endif + class ast; class ast_manager; @@ -1515,7 +1521,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - [[noreturn]] void raise_exception(char const * msg); + void raise_exception(char const * msg) Z3_NORETURN; bool is_format_manager() const { return m_format_manager == 0; } From 11f5fdccdf1f3e7b72a052be73203760d75472b4 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 3 Jan 2018 01:02:07 +0700 Subject: [PATCH 36/37] Use noreturn attribute and __declspec version. --- src/ast/ast.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index ea97af004..7a662a193 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -53,10 +53,10 @@ Revision History: #pragma warning(disable : 4355) #endif -#ifdef __GNUC__ -# define Z3_NORETURN __attribute__((noreturn)) +#ifdef _MSC_VER +# define Z3_NORETURN __declspec(noreturn) #else -# define Z3_NORETURN +# define Z3_NORETURN [[noreturn]] #endif class ast; @@ -1521,7 +1521,7 @@ public: void compress_ids(); // Equivalent to throw ast_exception(msg) - void raise_exception(char const * msg) Z3_NORETURN; + Z3_NORETURN void raise_exception(char const * msg); bool is_format_manager() const { return m_format_manager == 0; } From e9be339d9df0d7d16d31e58aeb1ff81b9215a563 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Wed, 3 Jan 2018 12:42:43 +0000 Subject: [PATCH 37/37] [CMake] Fix #1437. The `clock_gettime()` function in glibc < 2.17 required linking against librt. Until #1437 nobody had tried using the CMake build system with a really old version of glibc (in this case 2.12). The python build system always linked against librt but the CMake build system never tried to link against it leading to link failures. This patch teaches the CMake build system to detect if librt is required when linking against `clock_gettime()` and adds `rt` as a link dependency if necessary. --- CMakeLists.txt | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0be2de537..69a0ca123 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -257,6 +257,46 @@ list(APPEND Z3_COMPONENT_EXTRA_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/src" "${CMAKE_SOURCE_DIR}/src" ) + +################################################################################ +# Linux specific configuration +################################################################################ +if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + # Try to detect if it is necessary to link against librt. + # Note that glibc < 2.17 required librt to be linked to use clock_gettime() + # and friends. + set(CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE + " + #include + int main() { + timespec res; + int result = clock_gettime(CLOCK_REALTIME, &res); + return result == 0; + } + " + ) + check_cxx_source_compiles( + "${CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE}" + CLOCK_GETTIME_NO_REQUIRE_LIBRT + ) + if (NOT CLOCK_GETTIME_NO_REQUIRE_LIBRT) + # Try again with librt + message(STATUS "Failed to link against clock_gettime(), trying with librt") + set(CMAKE_REQUIRED_LIBRARIES_OLD "${CMAKE_REQUIRED_LIBRARIES}") + set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} rt") + check_cxx_source_compiles( + "${CLOCK_GETTIME_REQUIRES_LIBRT_TEST_CODE}" + CLOCK_GETTIME_REQUIRES_LIBRT + ) + set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_OLD}") + if (CLOCK_GETTIME_REQUIRES_LIBRT) + list(APPEND Z3_DEPENDENT_LIBS "rt") + else() + message(FATAL_ERROR "Failed to link against clock_gettime()") + endif() + endif() +endif() + ################################################################################ # GNU multiple precision library support ################################################################################