From 4867073290378ec4a31eb06b4df507c815a12473 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Dec 2023 10:04:49 -0800 Subject: [PATCH 001/224] remove windowsArm64 from nightly Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 45 ------------------------ src/ast/rewriter/arith_rewriter.cpp | 2 +- src/sat/smt/arith_axioms.cpp | 17 +++++++-- src/sat/smt/euf_model.cpp | 2 +- src/sat/smt/intblast_solver.cpp | 53 +++++++++++++++-------------- src/sat/smt/intblast_solver.h | 2 ++ 6 files changed, 47 insertions(+), 74 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 0f5337654..5c1bdff6a 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -233,46 +233,6 @@ stages: symbolServerType: TeamServices detailedLog: true - - job: "WindowsArm64" - displayName: "WindowsArm64" - pool: - vmImage: "windows-latest" - variables: - arch: "amd64_arm64" - bindings: "-DCMAKE_BUILD_TYPE=RelWithDebInfo" - steps: - - script: md build - - script: | - cd build - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" $(arch) - cmake $(bindings) -G "NMake Makefiles" ../ - nmake - cd .. - - task: CopyFiles@2 - inputs: - sourceFolder: build - contents: '*z3*.*' - targetFolder: $(Build.ArtifactStagingDirectory) - - task: PublishPipelineArtifact@1 - inputs: - targetPath: $(Build.ArtifactStagingDirectory) - artifactName: 'WindowsArm64' - - task: CopyFiles@2 - displayName: 'Collect Symbols' - inputs: - sourceFolder: build - contents: '**/*.pdb' - targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' - # Publish symbol archive to match nuget package - # Index your source code and publish symbols to a file share or Azure Artifacts symbol server - - task: PublishSymbols@2 - inputs: - symbolsFolder: '$(Build.ArtifactStagingDirectory)/symbols' - searchPattern: '**/*.pdb' - indexSources: false # Github not supported - publishSymbols: true - symbolServerType: TeamServices - detailedLog: true - stage: Package @@ -576,11 +536,6 @@ stages: inputs: artifactName: 'Windows32' targetPath: tmp - - task: DownloadPipelineArtifact@2 - displayName: "Download windowsArm64" - inputs: - artifactName: 'WindowsArm64' - targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download windows64" inputs: diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index d8a06ada6..13e50da4a 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -1435,7 +1435,7 @@ br_status arith_rewriter::mk_lshr_core(unsigned sz, expr* arg1, expr* arg2, expr } if (is_num_x && is_num_y) { if (y >= sz) - result = m_util.mk_int(N-1); + result = m_util.mk_int(0); else { rational d = div(x, rational::power_of_two(y.get_unsigned())); result = m_util.mk_int(d); diff --git a/src/sat/smt/arith_axioms.cpp b/src/sat/smt/arith_axioms.cpp index ae67783eb..20bc78260 100644 --- a/src/sat/smt/arith_axioms.cpp +++ b/src/sat/smt/arith_axioms.cpp @@ -260,6 +260,9 @@ namespace arith { if (valy >= sz || valy == 0) return true; unsigned k = valy.get_unsigned(); + rational r = mod(valx * rational::power_of_two(k), N); + if (r == valn) + return true; sat::literal eq = eq_internalize(n, a.mk_mod(a.mk_mul(_x, a.mk_int(rational::power_of_two(k))), a.mk_int(N))); if (s().value(eq) == l_true) return true; @@ -272,6 +275,9 @@ namespace arith { if (valy >= sz || valy == 0) return true; unsigned k = valy.get_unsigned(); + rational r = mod(div(valx, rational::power_of_two(k)), N); + if (r == valn) + return true; sat::literal eq = eq_internalize(n, a.mk_idiv(x, a.mk_int(rational::power_of_two(k)))); if (s().value(eq) == l_true) return true; @@ -284,6 +290,12 @@ namespace arith { if (valy >= sz || valy == 0) return true; unsigned k = valy.get_unsigned(); + bool signvalx = x >= N/2; + rational valxdiv2k = div(valx, rational::power_of_two(k)); + if (signvalx) + valxdiv2k = mod(valxdiv2k - rational::power_of_two(sz - k), N); + if (valn == valxdiv2k) + return true; sat::literal signx = mk_literal(a.mk_ge(x, a.mk_int(N/2))); sat::literal eq; expr* xdiv2k; @@ -335,9 +347,10 @@ namespace arith { expr_ref x(a.mk_mod(_x, a.mk_int(N)), m); expr_ref y(a.mk_mod(_y, a.mk_int(N)), m); + add_clause(mk_literal(a.mk_ge(n, a.mk_int(0)))); + add_clause(mk_literal(a.mk_le(n, a.mk_int(N - 1)))); + if (a.is_band(n)) { - add_clause(mk_literal(a.mk_ge(n, a.mk_int(0)))); - add_clause(mk_literal(a.mk_le(n, a.mk_int(N - 1)))); add_clause(mk_literal(a.mk_le(n, x))); add_clause(mk_literal(a.mk_le(n, y))); } diff --git a/src/sat/smt/euf_model.cpp b/src/sat/smt/euf_model.cpp index 073d164be..2035e16b6 100644 --- a/src/sat/smt/euf_model.cpp +++ b/src/sat/smt/euf_model.cpp @@ -282,7 +282,7 @@ namespace euf { } void solver::display_validation_failure(std::ostream& out, model& mdl, enode* n) { - out << "Failed to validate " << n->bool_var() << " " << bpp(n) << " " << mdl(n->get_expr()) << "\n"; + out << "Failed to validate b" << n->bool_var() << " " << bpp(n) << " " << mdl(n->get_expr()) << "\n"; s().display(out); euf::enode_vector nodes; nodes.push_back(n); diff --git a/src/sat/smt/intblast_solver.cpp b/src/sat/smt/intblast_solver.cpp index fed43e217..55ab4846c 100644 --- a/src/sat/smt/intblast_solver.cpp +++ b/src/sat/smt/intblast_solver.cpp @@ -148,7 +148,7 @@ namespace intblast { auto a = expr2literal(e); auto b = mk_literal(r); ctx.mark_relevant(b); -// verbose_stream() << "add-predicate-axiom: " << mk_pp(e, m) << " == " << r << "\n"; + // verbose_stream() << "add-predicate-axiom: " << mk_pp(e, m) << " == " << r << "\n"; add_equiv(a, b); } return true; @@ -305,28 +305,6 @@ namespace intblast { sorted.push_back(arg); } } - - // - // Add ground equalities to ensure the model is valid with respect to the current case splits. - // This may cause more conflicts than necessary. Instead could use intblast on the base level, but using literal - // assignment from complete level. - // E.g., force the solver to completely backtrack, check satisfiability using the assignment obtained under a complete assignment. - // If intblast is SAT, then force the model and literal assignment on the rest of the literals. - // - if (!is_ground(e)) - continue; - euf::enode* n = ctx.get_enode(e); - if (!n) - continue; - if (n == n->get_root()) - continue; - expr* r = n->get_root()->get_expr(); - es.push_back(m.mk_eq(e, r)); - r = es.back(); - if (!visited.is_marked(r) && !is_translated(r)) { - visited.mark(r); - sorted.push_back(r); - } } else if (is_quantifier(e)) { quantifier* q = to_quantifier(e); @@ -646,7 +624,7 @@ namespace intblast { } case OP_BUDIV: case OP_BUDIV_I: { - expr* x = arg(0), * y = umod(e, 1); + expr* x = umod(e, 0), * y = umod(e, 1); r = m.mk_ite(m.mk_eq(y, a.mk_int(0)), a.mk_int(-1), a.mk_idiv(x, y)); break; } @@ -978,13 +956,38 @@ namespace intblast { arith::arith_value av(ctx); rational r; VERIFY(av.get_value(b2i->get_expr(), r)); - verbose_stream() << ctx.bpp(n) << " := " << r << "\n"; value = bv.mk_numeral(r, bv.get_bv_size(n->get_expr())); + verbose_stream() << ctx.bpp(n) << " := " << value << "\n"; } values.set(n->get_root_id(), value); TRACE("model", tout << "add_value " << ctx.bpp(n) << " := " << value << "\n"); } + void solver::finalize_model(model& mdl) { + for (auto n : ctx.get_egraph().nodes()) { + expr* e = n->get_expr(); + if (!bv.is_bv(e)) + continue; + if (!is_translated(e)) + continue; + expr* f = translated(e); + rational r1, r2; + expr_ref val1 = mdl(e); + expr_ref val2 = mdl(f); + if (bv.is_numeral(val1, r1) && a.is_numeral(val2, r2) && r1 != r2) { + rational N = rational::power_of_two(bv.get_bv_size(e)); + r2 = mod(r2, N); + if (r1 == r2) + continue; + verbose_stream() << "value mismatch : " << mk_bounded_pp(e, m) << " := " << val1 << "\n"; + verbose_stream() << mk_bounded_pp(f, m) << " := " << r2 << "\n"; + for (expr* arg : *to_app(e)) { + verbose_stream() << mk_bounded_pp(arg, m) << " := " << mdl(arg) << "\n"; + } + } + } + } + sat::literal_vector const& solver::unsat_core() { return m_core; } diff --git a/src/sat/smt/intblast_solver.h b/src/sat/smt/intblast_solver.h index d59dac935..1739fc09b 100644 --- a/src/sat/smt/intblast_solver.h +++ b/src/sat/smt/intblast_solver.h @@ -108,6 +108,8 @@ namespace intblast { bool add_dep(euf::enode* n, top_sort& dep) override; + void finalize_model(model& mdl) override; + std::ostream& display(std::ostream& out) const override; void collect_statistics(statistics& st) const override; From bb99f442147bf87cc2cd437e6edfdf2ae7e9a068 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Dec 2023 17:42:55 -0800 Subject: [PATCH 002/224] fix bugs in elim-unconstr2 and fix bugs in intblast_solver Signed-off-by: Nikolaj Bjorner --- src/ast/converters/expr_inverter.cpp | 1 + src/ast/simplifiers/elim_unconstrained.cpp | 26 +++++- .../model_reconstruction_trail.cpp | 4 +- src/sat/smt/intblast_solver.cpp | 92 +++++++++---------- 4 files changed, 70 insertions(+), 53 deletions(-) diff --git a/src/ast/converters/expr_inverter.cpp b/src/ast/converters/expr_inverter.cpp index bdc32e97c..a06d125a5 100644 --- a/src/ast/converters/expr_inverter.cpp +++ b/src/ast/converters/expr_inverter.cpp @@ -400,6 +400,7 @@ class bv_expr_inverter : public iexpr_inverter { } bool process_concat(func_decl* f, unsigned num, expr* const* args, expr_ref& r) { +// return false; if (num == 0) return false; if (!uncnstr(num, args)) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 231858897..c7cf2d11c 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -66,7 +66,6 @@ bool elim_unconstrained::is_var_lt(int v1, int v2) const { } void elim_unconstrained::eliminate() { - while (!m_heap.empty()) { expr_ref r(m); int v = m_heap.erase_min(); @@ -86,7 +85,12 @@ void elim_unconstrained::eliminate() { n.m_refcount = 0; continue; } + if (m_heap.contains(root(e))) { + IF_VERBOSE(11, verbose_stream() << "already in heap " << mk_bounded_pp(e, m) << "\n"); + continue; + } app* t = to_app(e); + TRACE("elim_unconstrained", tout << "eliminating " << mk_pp(t, m) << "\n";); unsigned sz = m_args.size(); for (expr* arg : *to_app(t)) m_args.push_back(reconstruct_term(get_node(arg))); @@ -99,12 +103,15 @@ void elim_unconstrained::eliminate() { proof * pr = m.mk_apply_def(s, r, pr1); m_trail.push_back(pr); } + expr_ref rr(m.mk_app(t->get_decl(), t->get_num_args(), m_args.data() + sz), m); n.m_refcount = 0; m_args.shrink(sz); if (!inverted) { IF_VERBOSE(11, verbose_stream() << "not inverted " << mk_bounded_pp(e, m) << "\n"); continue; } + + IF_VERBOSE(11, verbose_stream() << "replace " << mk_pp(t, m) << " / " << rr << " -> " << r << "\n"); TRACE("elim_unconstrained", tout << mk_pp(t, m) << " -> " << r << "\n"); SASSERT(r->get_sort() == t->get_sort()); @@ -119,7 +126,8 @@ void elim_unconstrained::eliminate() { get_node(e).m_term = r; get_node(e).m_proof = pr; get_node(e).m_refcount++; - IF_VERBOSE(11, verbose_stream() << mk_bounded_pp(e, m) << "\n"); + get_node(e).m_dirty = false; + IF_VERBOSE(11, verbose_stream() << "set " << &get_node(e) << " " << root(e) << " " << mk_bounded_pp(e, m) << " := " << mk_bounded_pp(r, m) << "\n"); SASSERT(!m_heap.contains(root(e))); if (is_uninterp_const(r)) m_heap.insert(root(e)); @@ -283,13 +291,22 @@ expr_ref elim_unconstrained::reconstruct_term(node& n0) { expr* t = n0.m_term; if (!n0.m_dirty) return expr_ref(t, m); + if (!is_node(t)) + return expr_ref(t, m); ptr_vector todo; todo.push_back(t); while (!todo.empty()) { t = todo.back(); + if (!is_node(t)) { + UNREACHABLE(); + } node& n = get_node(t); unsigned sz0 = todo.size(); - if (is_app(t)) { + if (is_app(t)) { + if (n.m_term != t) { + todo.pop_back(); + continue; + } for (expr* arg : *to_app(t)) if (get_node(arg).m_dirty || !get_node(arg).m_term) todo.push_back(arg); @@ -300,7 +317,6 @@ expr_ref elim_unconstrained::reconstruct_term(node& n0) { for (expr* arg : *to_app(t)) m_args.push_back(get_node(arg).m_term); n.m_term = m.mk_app(to_app(t)->get_decl(), to_app(t)->get_num_args(), m_args.data() + sz); - m_args.shrink(sz); } else if (is_quantifier(t)) { @@ -410,7 +426,7 @@ void elim_unconstrained::reduce() { generic_model_converter_ref mc = alloc(generic_model_converter, m, "elim-unconstrained"); m_inverter.set_model_converter(mc.get()); m_created_compound = true; - for (unsigned rounds = 0; m_created_compound && rounds < 3; ++rounds) { + for (unsigned rounds = 0; m_created_compound && rounds < 1; ++rounds) { m_created_compound = false; init_nodes(); eliminate(); diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index 95f73fd7a..47ebea525 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -182,11 +182,11 @@ std::ostream& model_reconstruction_trail::display(std::ostream& out) const { out << "hide " << t->m_decl->get_name() << "\n"; else if (t->is_def()) { for (auto const& [f, def, dep] : t->m_defs) - out << f->get_name() << " <- " << mk_pp(def, m) << "\n"; + out << "def: " << f->get_name() << " <- " << mk_pp(def, m) << "\n"; } else { for (auto const& [v, def] : t->m_subst->sub()) - out << mk_pp(v, m) << " <- " << mk_pp(def, m) << "\n"; + out << "sub: " << mk_pp(v, m) << " -> " << mk_pp(def, m) << "\n"; } for (auto const& d : t->m_removed) out << "rm: " << d << "\n"; diff --git a/src/sat/smt/intblast_solver.cpp b/src/sat/smt/intblast_solver.cpp index 55ab4846c..d0ecff794 100644 --- a/src/sat/smt/intblast_solver.cpp +++ b/src/sat/smt/intblast_solver.cpp @@ -104,10 +104,10 @@ namespace intblast { ctx.push(push_back_vector(m_preds)); } - void solver::set_translated(expr* e, expr* r) { + void solver::set_translated(expr* e, expr* r) { SASSERT(r); - SASSERT(!is_translated(e)); - m_translate.setx(e->get_id(), r); + SASSERT(!is_translated(e)); + m_translate.setx(e->get_id(), r); ctx.push(set_vector_idx_trail(m_translate, e->get_id())); } @@ -157,7 +157,7 @@ namespace intblast { bool solver::unit_propagate() { return add_bound_axioms() || add_predicate_axioms(); } - + void solver::ensure_translated(expr* e) { if (m_translate.get(e->get_id(), nullptr)) return; @@ -179,7 +179,7 @@ namespace intblast { } } std::stable_sort(todo.begin(), todo.end(), [&](expr* a, expr* b) { return get_depth(a) < get_depth(b); }); - for (expr* e : todo) + for (expr* e : todo) translate_expr(e); } @@ -335,7 +335,7 @@ namespace intblast { es[i] = translated(es.get(i)); } - sat::check_result solver::check() { + sat::check_result solver::check() { // ensure that bv2int is injective for (auto e : m_bv2int) { euf::enode* n = expr2enode(e); @@ -347,10 +347,12 @@ namespace intblast { continue; if (sib->get_arg(0)->get_root() == r1) continue; - auto a = eq_internalize(n, sib); - auto b = eq_internalize(sib->get_arg(0), n->get_arg(0)); - ctx.mark_relevant(a); - ctx.mark_relevant(b); + if (sib->get_arg(0)->get_sort() != n->get_arg(0)->get_sort()) + continue; + auto a = eq_internalize(n, sib); + auto b = eq_internalize(sib->get_arg(0), n->get_arg(0)); + ctx.mark_relevant(a); + ctx.mark_relevant(b); add_clause(~a, b, nullptr); return sat::check_result::CR_CONTINUE; } @@ -368,13 +370,13 @@ namespace intblast { auto nBv2int = ctx.get_enode(bv2int); auto nxModN = ctx.get_enode(xModN); if (nBv2int->get_root() != nxModN->get_root()) { - auto a = eq_internalize(nBv2int, nxModN); - ctx.mark_relevant(a); + auto a = eq_internalize(nBv2int, nxModN); + ctx.mark_relevant(a); add_unit(a); return sat::check_result::CR_CONTINUE; } } - return sat::check_result::CR_DONE; + return sat::check_result::CR_DONE; } expr* solver::umod(expr* bv_expr, unsigned i) { @@ -482,8 +484,8 @@ namespace intblast { m_args[i] = bv.mk_int2bv(bv.get_bv_size(e->get_arg(i)), m_args.get(i)); if (has_bv_sort) - m_vars.push_back(e); - + m_vars.push_back(e); + if (m_is_plugin) { expr* r = m.mk_app(f, m_args); if (has_bv_sort) { @@ -504,7 +506,7 @@ namespace intblast { f = g; m_pinned.push_back(f); } - set_translated(e, m.mk_app(f, m_args)); + set_translated(e, m.mk_app(f, m_args)); } void solver::translate_bv(app* e) { @@ -536,7 +538,7 @@ namespace intblast { r = a.mk_add(hi, lo); } return r; - }; + }; expr* bv_expr = e; expr* r = nullptr; @@ -634,22 +636,22 @@ namespace intblast { break; } case OP_BSHL: { - if (!a.is_numeral(arg(0)) && !a.is_numeral(arg(1))) - r = a.mk_shl(bv.get_bv_size(e), arg(0),arg(1)); + if (!a.is_numeral(arg(0)) && !a.is_numeral(arg(1))) + r = a.mk_shl(bv.get_bv_size(e), arg(0), arg(1)); else { expr* x = arg(0), * y = umod(e, 1); r = a.mk_int(0); IF_VERBOSE(2, verbose_stream() << "shl " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); for (unsigned i = 0; i < bv.get_bv_size(e); ++i) - r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), a.mk_mul(x, a.mk_int(rational::power_of_two(i))), r); + r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), a.mk_mul(x, a.mk_int(rational::power_of_two(i))), r); } break; } case OP_BNOT: r = bnot(arg(0)); break; - case OP_BLSHR: - if (!a.is_numeral(arg(0)) && !a.is_numeral(arg(1))) + case OP_BLSHR: + if (!a.is_numeral(arg(0)) && !a.is_numeral(arg(1))) r = a.mk_lshr(bv.get_bv_size(e), arg(0), arg(1)); else { expr* x = arg(0), * y = umod(e, 1); @@ -659,11 +661,11 @@ namespace intblast { r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), a.mk_idiv(x, a.mk_int(rational::power_of_two(i))), r); } break; - case OP_BASHR: + case OP_BASHR: if (!a.is_numeral(arg(1))) r = a.mk_ashr(bv.get_bv_size(e), arg(0), arg(1)); else { - + // // ashr(x, y) // if y = k & x >= 0 -> x / 2^k @@ -671,15 +673,15 @@ namespace intblast { // unsigned sz = bv.get_bv_size(e); rational N = bv_size(e); - expr* x = umod(e, 0), *y = umod(e, 1); + expr* x = umod(e, 0), * y = umod(e, 1); expr* signx = a.mk_ge(x, a.mk_int(N / 2)); - r = m.mk_ite(signx, a.mk_int(- 1), a.mk_int(0)); + r = m.mk_ite(signx, a.mk_int(-1), a.mk_int(0)); IF_VERBOSE(1, verbose_stream() << "ashr " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); for (unsigned i = 0; i < sz; ++i) { - expr* d = a.mk_idiv(x, a.mk_int(rational::power_of_two(i))); + expr* d = a.mk_idiv(x, a.mk_int(rational::power_of_two(i))); r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), - m.mk_ite(signx, a.mk_add(d, a.mk_int(- rational::power_of_two(sz-i))), d), - r); + m.mk_ite(signx, a.mk_add(d, a.mk_int(-rational::power_of_two(sz - i))), d), + r); } } break; @@ -744,11 +746,11 @@ namespace intblast { r = m.mk_ite(m.mk_eq(umod(bv_expr, 0), umod(bv_expr, 1)), a.mk_int(1), a.mk_int(0)); break; case OP_BSMOD_I: - case OP_BSMOD: { - expr* x = umod(e, 0), *y = umod(e, 1); - rational N = bv_size(e); - expr* signx = a.mk_ge(x, a.mk_int(N/2)); - expr* signy = a.mk_ge(y, a.mk_int(N/2)); + case OP_BSMOD: { + expr* x = umod(e, 0), * y = umod(e, 1); + rational N = bv_size(e); + expr* signx = a.mk_ge(x, a.mk_int(N / 2)); + expr* signy = a.mk_ge(y, a.mk_int(N / 2)); expr* u = a.mk_mod(x, y); // u = 0 -> 0 // y = 0 -> x @@ -756,14 +758,14 @@ namespace intblast { // x < 0, y >= 0 -> y - u // x >= 0, y < 0 -> y + u // x >= 0, y >= 0 -> u - r = a.mk_uminus(u); + r = a.mk_uminus(u); r = m.mk_ite(m.mk_and(m.mk_not(signx), signy), a.mk_add(u, y), r); r = m.mk_ite(m.mk_and(signx, m.mk_not(signy)), a.mk_sub(y, u), r); r = m.mk_ite(m.mk_and(m.mk_not(signx), m.mk_not(signy)), u, r); r = m.mk_ite(m.mk_eq(u, a.mk_int(0)), a.mk_int(0), r); r = m.mk_ite(m.mk_eq(y, a.mk_int(0)), x, r); break; - } + } case OP_BSDIV_I: case OP_BSDIV: { // d = udiv(abs(x), abs(y)) @@ -799,7 +801,7 @@ namespace intblast { d = m.mk_ite(m.mk_iff(signx, signy), d, a.mk_uminus(d)); r = a.mk_sub(x, a.mk_mul(d, y)); r = m.mk_ite(m.mk_eq(y, a.mk_int(0)), x, r); - break; + break; } case OP_ROTATE_LEFT: { auto n = e->get_parameter(0).get_int(); @@ -812,11 +814,11 @@ namespace intblast { r = rotate_left(sz - n); break; } - case OP_EXT_ROTATE_LEFT: { + case OP_EXT_ROTATE_LEFT: { unsigned sz = bv.get_bv_size(e); expr* y = umod(e, 1); r = a.mk_int(0); - for (unsigned i = 0; i < sz; ++i) + for (unsigned i = 0; i < sz; ++i) r = m.mk_ite(m.mk_eq(a.mk_int(i), y), rotate_left(i), r); break; } @@ -824,7 +826,7 @@ namespace intblast { unsigned sz = bv.get_bv_size(e); expr* y = umod(e, 1); r = a.mk_int(0); - for (unsigned i = 0; i < sz; ++i) + for (unsigned i = 0; i < sz; ++i) r = m.mk_ite(m.mk_eq(a.mk_int(i), y), rotate_left(sz - i), r); break; } @@ -837,7 +839,7 @@ namespace intblast { for (unsigned i = 1; i < n; ++i) r = a.mk_add(a.mk_mul(a.mk_int(N), x), r), N *= N0; break; - } + } case OP_BREDOR: { r = umod(e->get_arg(0), 0); r = m.mk_not(m.mk_eq(r, a.mk_int(0))); @@ -897,7 +899,7 @@ namespace intblast { } bool solver::add_dep(euf::enode* n, top_sort& dep) { - if (!is_app(n->get_expr())) + if (!is_app(n->get_expr())) return false; app* e = to_app(n->get_expr()); if (n->num_args() == 0) { @@ -916,7 +918,7 @@ namespace intblast { void solver::add_value_solver(euf::enode* n, model& mdl, expr_ref_vector& values) { expr* e = n->get_expr(); SASSERT(bv.is_bv(e)); - + if (bv.is_numeral(e)) { values.setx(n->get_root_id(), e); return; @@ -957,7 +959,6 @@ namespace intblast { rational r; VERIFY(av.get_value(b2i->get_expr(), r)); value = bv.mk_numeral(r, bv.get_bv_size(n->get_expr())); - verbose_stream() << ctx.bpp(n) << " := " << value << "\n"; } values.set(n->get_root_id(), value); TRACE("model", tout << "add_value " << ctx.bpp(n) << " := " << value << "\n"); @@ -981,9 +982,8 @@ namespace intblast { continue; verbose_stream() << "value mismatch : " << mk_bounded_pp(e, m) << " := " << val1 << "\n"; verbose_stream() << mk_bounded_pp(f, m) << " := " << r2 << "\n"; - for (expr* arg : *to_app(e)) { + for (expr* arg : *to_app(e)) verbose_stream() << mk_bounded_pp(arg, m) << " := " << mdl(arg) << "\n"; - } } } } From 2f2bf749b9d3fb71f2ae49ffaafde5b6e370f96c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 17 Dec 2023 18:15:51 -0800 Subject: [PATCH 003/224] fixes to intblast encoding and more arithmetic rewriters Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 52 ++++++++++++++++++++++------- src/ast/rewriter/arith_rewriter.h | 1 + src/sat/smt/intblast_solver.cpp | 10 +++--- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 13e50da4a..635d5a3f2 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -1232,19 +1232,20 @@ static rational symmod(rational const& a, rational const& b) { br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & result) { set_curr_sort(arg1->get_sort()); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - result = m_util.mk_numeral(mod(v1, v2), is_int); + numeral x, y; + bool is_num_x = m_util.is_numeral(arg1, x); + bool is_num_y = m_util.is_numeral(arg2, y); + if (is_num_x && is_num_y && !y.is_zero()) { + result = m_util.mk_int(mod(x, y)); return BR_DONE; } - if (m_util.is_numeral(arg2, v2, is_int) && is_int && (v2.is_one() || v2.is_minus_one())) { + if (is_num_y && y.is_int() && (y.is_one() || y.is_minus_one())) { result = m_util.mk_numeral(numeral(0), true); return BR_DONE; } - if (arg1 == arg2 && !m_util.is_numeral(arg2)) { + if (arg1 == arg2 && !is_num_y) { expr_ref zero(m_util.mk_int(0), m); result = m.mk_ite(m.mk_eq(arg2, zero), m_util.mk_mod(zero, zero), zero); return BR_DONE; @@ -1252,29 +1253,35 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul // mod is idempotent on non-zero modulus. expr* t1, *t2; - if (m_util.is_mod(arg1, t1, t2) && t2 == arg2 && m_util.is_numeral(arg2, v2, is_int) && is_int && !v2.is_zero()) { + if (m_util.is_mod(arg1, t1, t2) && t2 == arg2 && is_num_y && y.is_int() && !y.is_zero()) { + result = arg1; + return BR_DONE; + } + + rational lo, hi; + if (is_num_y && get_range(arg1, lo, hi) && 0 <= lo && hi < y) { result = arg1; return BR_DONE; } // propagate mod inside only if there is something to reduce. - if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_pos() && (is_add(arg1) || is_mul(arg1))) { + if (is_num_y && y.is_int() && y.is_pos() && (is_add(arg1) || is_mul(arg1))) { TRACE("mod_bug", tout << "mk_mod:\n" << mk_ismt2_pp(arg1, m) << "\n" << mk_ismt2_pp(arg2, m) << "\n";); expr_ref_buffer args(m); bool change = false; for (expr* arg : *to_app(arg1)) { rational arg_v; - if (m_util.is_numeral(arg, arg_v) && mod(arg_v, v2) != arg_v) { + if (m_util.is_numeral(arg, arg_v) && mod(arg_v, y) != arg_v) { change = true; - args.push_back(m_util.mk_numeral(mod(arg_v, v2), true)); + args.push_back(m_util.mk_numeral(mod(arg_v, y), true)); } else if (m_util.is_mod(arg, t1, t2) && t2 == arg2) { change = true; args.push_back(t1); } - else if (m_util.is_mul(arg, t1, t2) && m_util.is_numeral(t1, arg_v) && symmod(arg_v, v2) != arg_v) { + else if (m_util.is_mul(arg, t1, t2) && m_util.is_numeral(t1, arg_v) && symmod(arg_v, y) != arg_v) { change = true; - args.push_back(m_util.mk_mul(m_util.mk_numeral(symmod(arg_v, v2), true), t2)); + args.push_back(m_util.mk_mul(m_util.mk_numeral(symmod(arg_v, y), true), t2)); } else { args.push_back(arg); @@ -1291,6 +1298,27 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul return BR_FAILED; } +bool arith_rewriter::get_range(expr* e, rational& lo, rational& hi) { + expr* x, *y; + rational r; + if (m_util.is_idiv(e, x, y) && m_util.is_numeral(y, r) && get_range(x, lo, hi) && 0 <= lo && r > 0) { + lo = div(lo, r); + hi = div(hi, r); + return true; + } + if (m_util.is_mod(e, x, y) && m_util.is_numeral(y, r) && r > 0) { + lo = 0; + hi = r - 1; + return true; + } + if (m_util.is_numeral(e, r)) { + lo = hi = r; + return true; + } + return false; +} + + br_status arith_rewriter::mk_rem_core(expr * arg1, expr * arg2, expr_ref & result) { set_curr_sort(arg1->get_sort()); numeral v1, v2; diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index 6066c9eb4..a9a30fe00 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -63,6 +63,7 @@ class arith_rewriter : public poly_rewriter { bool m_eq2ineq; unsigned m_max_degree; + bool get_range(expr* e, rational& lo, rational& hi); void get_coeffs_gcd(expr * t, numeral & g, bool & first, unsigned & num_consts); enum const_treatment { CT_FLOOR, CT_CEIL, CT_FALSE }; bool div_polynomial(expr * t, numeral const & g, const_treatment ct, expr_ref & result); diff --git a/src/sat/smt/intblast_solver.cpp b/src/sat/smt/intblast_solver.cpp index d0ecff794..d1b3a7205 100644 --- a/src/sat/smt/intblast_solver.cpp +++ b/src/sat/smt/intblast_solver.cpp @@ -37,7 +37,6 @@ namespace intblast { euf::theory_var solver::mk_var(euf::enode* n) { auto r = euf::th_euf_solver::mk_var(n); ctx.attach_th_var(n, this, r); - TRACE("bv", tout << "mk-var: v" << r << " " << ctx.bpp(n) << "\n";); return r; } @@ -98,7 +97,7 @@ namespace intblast { ensure_translated(y); m_args.reset(); m_args.push_back(a.mk_sub(translated(x), translated(y))); - set_translated(e, m.mk_eq(umod(x, 0), a.mk_int(0))); + set_translated(e, m.mk_eq(umod(x, 0), a.mk_int(0))); } m_preds.push_back(e); ctx.push(push_back_vector(m_preds)); @@ -148,7 +147,7 @@ namespace intblast { auto a = expr2literal(e); auto b = mk_literal(r); ctx.mark_relevant(b); - // verbose_stream() << "add-predicate-axiom: " << mk_pp(e, m) << " == " << r << "\n"; + TRACE("intblast", tout << "add-predicate-axiom: " << mk_bounded_pp(e, m) << " \n" << r << "\n"); add_equiv(a, b); } return true; @@ -606,9 +605,10 @@ namespace intblast { unsigned lo, hi; expr* old_arg; VERIFY(bv.is_extract(e, lo, hi, old_arg)); - r = arg(0); if (lo > 0) - r = a.mk_idiv(r, a.mk_int(rational::power_of_two(lo))); + r = a.mk_idiv(umod(old_arg, 0), a.mk_int(rational::power_of_two(lo))); + else + r = arg(0); break; } case OP_BV_NUM: { From 085b5e2588f048d6ff2bfec9776e0cf2cb724f3c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 09:25:24 -0800 Subject: [PATCH 004/224] port Jakob's update to union_find from polysat branch Signed-off-by: Nikolaj Bjorner --- src/sat/smt/array_solver.h | 2 +- src/sat/smt/bv_solver.h | 2 +- src/sat/smt/dt_solver.h | 2 +- src/util/union_find.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sat/smt/array_solver.h b/src/sat/smt/array_solver.h index c63eedaca..8dc6e4e84 100644 --- a/src/sat/smt/array_solver.h +++ b/src/sat/smt/array_solver.h @@ -32,7 +32,7 @@ namespace array { typedef sat::literal literal; typedef sat::bool_var bool_var; typedef sat::literal_vector literal_vector; - typedef union_find array_union_find; + typedef union_find array_union_find; struct stats { diff --git a/src/sat/smt/bv_solver.h b/src/sat/smt/bv_solver.h index 91e485a9f..df4e5c9c2 100644 --- a/src/sat/smt/bv_solver.h +++ b/src/sat/smt/bv_solver.h @@ -49,7 +49,7 @@ namespace bv { typedef std::pair value_sort_pair; typedef pair_hash, unsigned_hash> value_sort_pair_hash; typedef map > value2var; - typedef union_find bv_union_find; + typedef union_find bv_union_find; typedef std::pair var_pos; friend class ackerman; diff --git a/src/sat/smt/dt_solver.h b/src/sat/smt/dt_solver.h index b2cbba63b..1bf4d6073 100644 --- a/src/sat/smt/dt_solver.h +++ b/src/sat/smt/dt_solver.h @@ -36,7 +36,7 @@ namespace dt { typedef sat::bool_var bool_var; typedef sat::literal literal; typedef sat::literal_vector literal_vector; - typedef union_find dt_union_find; + typedef union_find dt_union_find; struct var_data { ptr_vector m_recognizers; //!< recognizers of this equivalence class that are being watched. diff --git a/src/util/union_find.h b/src/util/union_find.h index 7e42e1bba..0c08ac446 100644 --- a/src/util/union_find.h +++ b/src/util/union_find.h @@ -35,7 +35,7 @@ private: _trail_stack m_stack; }; -template +template class union_find { Ctx & m_ctx; trail_stack & m_trail_stack; From d008dbe50adc47d776b477158b0beb4238562668 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 09:31:59 -0800 Subject: [PATCH 005/224] port Jakob's update to bv_internalize Signed-off-by: Nikolaj Bjorner --- src/sat/smt/bv_internalize.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/bv_internalize.cpp b/src/sat/smt/bv_internalize.cpp index 99d2a34ae..f1e9e8374 100644 --- a/src/sat/smt/bv_internalize.cpp +++ b/src/sat/smt/bv_internalize.cpp @@ -191,8 +191,8 @@ namespace bv { case OP_BAND: internalize_ac(mk_and); break; case OP_BOR: internalize_ac(mk_or); break; case OP_BXOR: internalize_ac(mk_xor); break; - case OP_BNAND: internalize_bin(mk_nand); break; - case OP_BNOR: internalize_bin(mk_nor); break; + case OP_BNAND: if_unary(mk_not); internalize_bin(mk_nand); break; + case OP_BNOR: if_unary(mk_not); internalize_bin(mk_nor); break; case OP_BXNOR: if_unary(mk_not); internalize_bin(mk_xnor); break; case OP_BCOMP: internalize_bin(mk_comp); break; case OP_SIGN_EXT: internalize_pun(mk_sign_extend); break; From 6d23847482e8ae9f9b68f0bc6e2ff9e371a33ae2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 09:33:40 -0800 Subject: [PATCH 006/224] fix typos Signed-off-by: Nikolaj Bjorner --- src/sat/smt/dt_solver.cpp | 2 +- src/sat/smt/dt_solver.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/dt_solver.cpp b/src/sat/smt/dt_solver.cpp index 52c4ed953..0b3ca2a99 100644 --- a/src/sat/smt/dt_solver.cpp +++ b/src/sat/smt/dt_solver.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Theory plugin for altegraic datatypes + Theory plugin for algebraic datatypes Author: diff --git a/src/sat/smt/dt_solver.h b/src/sat/smt/dt_solver.h index 1bf4d6073..02f1300b8 100644 --- a/src/sat/smt/dt_solver.h +++ b/src/sat/smt/dt_solver.h @@ -7,7 +7,7 @@ Module Name: Abstract: - Theory plugin for altegraic datatypes + Theory plugin for algebraic datatypes Author: From 5d4c18dde27f6e81711bdcabe23e84cf43d8e8bf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 16:56:53 -0800 Subject: [PATCH 007/224] fixes Signed-off-by: Nikolaj Bjorner --- src/sat/smt/intblast_solver.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/sat/smt/intblast_solver.cpp b/src/sat/smt/intblast_solver.cpp index d1b3a7205..f8a7beed0 100644 --- a/src/sat/smt/intblast_solver.cpp +++ b/src/sat/smt/intblast_solver.cpp @@ -573,6 +573,7 @@ namespace intblast { r = a.mk_le(smod(bv_expr, 0), smod(bv_expr, 1)); break; case OP_SGEQ: + bv_expr = e->get_arg(0); r = a.mk_ge(smod(bv_expr, 0), smod(bv_expr, 1)); break; case OP_SLT: @@ -902,6 +903,12 @@ namespace intblast { if (!is_app(n->get_expr())) return false; app* e = to_app(n->get_expr()); + expr *th, * el, * c; + if (m.is_ite(e, c, th, el)) { + dep.add(n, expr2enode(th)->get_root()); + dep.add(n, expr2enode(el)->get_root()); + return true; + } if (n->num_args() == 0) { dep.insert(n, nullptr); return true; @@ -940,6 +947,15 @@ namespace intblast { void solver::add_value_plugin(euf::enode* n, model& mdl, expr_ref_vector& values) { expr_ref value(m); + expr* e = n->get_expr(), *c, *th, *el; + while (m.is_ite(e, c, th, el)) { + auto thn = expr2enode(th); + if (thn->get_root() == n->get_root()) + e = th; + else + e = el; + n = expr2enode(e); + } if (n->interpreted()) value = n->get_expr(); else if (to_app(n->get_expr())->get_family_id() == bv.get_family_id()) { From dff419a7cb5cadc46fc29b99cb4b9d748ad7621f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 13:51:29 -0800 Subject: [PATCH 008/224] pin expressions to fix unsound behavior --- src/solver/simplifier_solver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/solver/simplifier_solver.cpp b/src/solver/simplifier_solver.cpp index 7debe6bc0..ed645dae0 100644 --- a/src/solver/simplifier_solver.cpp +++ b/src/solver/simplifier_solver.cpp @@ -80,8 +80,10 @@ class simplifier_solver : public solver { void flatten_suffix() override { expr_mark seen; unsigned j = qhead(); + expr_ref_vector pinned(s.m); for (unsigned i = qhead(); i < qtail(); ++i) { expr* f = s.m_fmls[i].fml(), *g = nullptr; + pinned.push_back(f); if (seen.is_marked(f)) continue; seen.mark(f, true); From 0daa05aab224dd6e506ca65e2de501f2b703945a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 13:51:45 -0800 Subject: [PATCH 009/224] add ability to log selected bv rewrites --- src/ast/rewriter/bv_rewriter.cpp | 73 ++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index fc672584e..64ecc5f53 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -20,8 +20,9 @@ Notes: #include "ast/rewriter/bv_rewriter.h" #include "ast/rewriter/poly_rewriter_def.h" #include "ast/rewriter/bool_rewriter.h" -#include "ast/ast_smt2_pp.h" #include "ast/ast_lt.h" +#include "ast/ast_pp.h" + void bv_rewriter::updt_local_params(params_ref const & _p) { @@ -54,45 +55,58 @@ void bv_rewriter::get_param_descrs(param_descrs & r) { br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { SASSERT(f->get_family_id() == get_fid()); + br_status st = BR_FAILED; switch(f->get_decl_kind()) { case OP_BIT0: SASSERT(num_args == 0); result = mk_zero(1); return BR_DONE; case OP_BIT1: SASSERT(num_args == 0); result = mk_one(1); return BR_DONE; case OP_ULEQ: SASSERT(num_args == 2); - return mk_ule(args[0], args[1], result); + st = mk_ule(args[0], args[1], result); + break; case OP_UGEQ: SASSERT(num_args == 2); - return mk_uge(args[0], args[1], result); + st = mk_uge(args[0], args[1], result); + break; case OP_ULT: SASSERT(num_args == 2); - return mk_ult(args[0], args[1], result); + st = mk_ult(args[0], args[1], result); + break; case OP_UGT: SASSERT(num_args == 2); - return mk_ult(args[1], args[0], result); + st = mk_ult(args[1], args[0], result); + break; case OP_SLEQ: SASSERT(num_args == 2); - return mk_sle(args[0], args[1], result); + st = mk_sle(args[0], args[1], result); + break; case OP_SGEQ: SASSERT(num_args == 2); - return mk_sge(args[0], args[1], result); + st = mk_sge(args[0], args[1], result); + break; case OP_SLT: SASSERT(num_args == 2); - return mk_slt(args[0], args[1], result); + st = mk_slt(args[0], args[1], result); + break; case OP_SGT: SASSERT(num_args == 2); - return mk_slt(args[1], args[0], result); + st = mk_slt(args[1], args[0], result); + break; case OP_BADD: SASSERT(num_args > 0); - return mk_bv_add(num_args, args, result); + st = mk_bv_add(num_args, args, result); + break; case OP_BMUL: SASSERT(num_args > 0); - return mk_bv_mul(num_args, args, result); + st = mk_bv_mul(num_args, args, result); + break; case OP_BSUB: SASSERT(num_args > 0); - return mk_sub(num_args, args, result); + st = mk_sub(num_args, args, result); + break; case OP_BNEG: SASSERT(num_args == 1); - return mk_uminus(args[0], result); + st = mk_uminus(args[0], result); + break; case OP_BNEG_OVFL: SASSERT(num_args == 1); return mk_bvneg_overflow(args[0], result); @@ -220,6 +234,13 @@ br_status bv_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * cons default: return BR_FAILED; } + + CTRACE("bv", st != BR_FAILED, tout << mk_pp(f, m) << "\n"; + for (unsigned i = 0; i < num_args; ++i) + tout << " " << mk_bounded_pp(args[i], m) << "\n"; + tout << mk_bounded_pp(result, m, 3) << "\n"); + + return st; } br_status bv_rewriter::mk_ule(expr * a, expr * b, expr_ref & result) { @@ -534,6 +555,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref result = m.mk_and(result, m_util.mk_ule(m_util.mk_numeral(r1-r2, sz), a2)); else if (r1 < r2) result = m.mk_or(result, m_util.mk_ule(m_util.mk_numeral(r1-r2, sz), a2)); + verbose_stream() << result << "\n"; return BR_REWRITE2; } @@ -541,7 +563,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref const br_status cst = rw_leq_concats(is_signed, a, b, result); if (cst != BR_FAILED) { TRACE("le_extra", tout << (is_signed ? "bv_sle\n" : "bv_ule\n") - << mk_ismt2_pp(a, m, 2) << "\n" << mk_ismt2_pp(b, m, 2) << "\n--->\n"<< mk_ismt2_pp(result, m, 2) << "\n";); + << mk_pp(a, m, 2) << "\n" << mk_pp(b, m, 2) << "\n--->\n"<< mk_pp(result, m, 2) << "\n";); return cst; } } @@ -550,7 +572,7 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref const br_status cst = rw_leq_overflow(is_signed, a, b, result); if (cst != BR_FAILED) { TRACE("le_extra", tout << (is_signed ? "bv_sle\n" : "bv_ule\n") - << mk_ismt2_pp(a, m, 2) << "\n" << mk_ismt2_pp(b, m, 2) << "\n--->\n"<< mk_ismt2_pp(result, m, 2) << "\n";); + << mk_pp(a, m, 2) << "\n" << mk_pp(b, m, 2) << "\n--->\n"<< mk_pp(result, m, 2) << "\n";); return cst; } } @@ -802,8 +824,8 @@ br_status bv_rewriter::mk_extract(unsigned high, unsigned low, expr * arg, expr_ const unsigned ep_rm = propagate_extract(high, arg, ep_res); if (ep_rm != 0) { result = m_mk_extract(high, low, ep_res); - TRACE("extract_prop", tout << mk_ismt2_pp(arg, m) << "\n[" << high <<"," << low << "]\n" << ep_rm << "---->\n" - << mk_ismt2_pp(result.get(), m) << "\n";); + TRACE("extract_prop", tout << mk_pp(arg, m) << "\n[" << high <<"," << low << "]\n" << ep_rm << "---->\n" + << mk_pp(result.get(), m) << "\n";); return BR_REWRITE2; } } @@ -1132,7 +1154,7 @@ br_status bv_rewriter::mk_bv_udiv_core(expr * arg1, expr * arg2, bool hi_div0, e m_util.mk_bv_udiv0(arg1), m_util.mk_bv_udiv_i(arg1, arg2)); - TRACE("bv_udiv", tout << mk_ismt2_pp(arg1, m) << "\n" << mk_ismt2_pp(arg2, m) << "\n---->\n" << mk_ismt2_pp(result, m) << "\n";); + TRACE("bv_udiv", tout << mk_pp(arg1, m) << "\n" << mk_pp(arg2, m) << "\n---->\n" << mk_pp(result, m) << "\n";); return BR_REWRITE2; } @@ -1792,8 +1814,8 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re std::reverse(exs.begin(), exs.end()); result = m_util.mk_concat(exs.size(), exs.data()); TRACE("mask_bug", - tout << "(assert (distinct (bvor (_ bv" << old_v1 << " " << sz << ")\n" << mk_ismt2_pp(t, m) << ")\n"; - tout << mk_ismt2_pp(result, m) << "))\n";); + tout << "(assert (distinct (bvor (_ bv" << old_v1 << " " << sz << ")\n" << mk_pp(t, m) << ")\n"; + tout << mk_pp(result, m) << "))\n";); return BR_REWRITE2; } @@ -2463,7 +2485,7 @@ br_status bv_rewriter::mk_blast_eq_value(expr * lhs, expr * rhs, expr_ref & resu unsigned sz = get_bv_size(lhs); if (sz == 1) return BR_FAILED; - TRACE("blast_eq_value", tout << "sz: " << sz << "\n" << mk_ismt2_pp(lhs, m) << "\n";); + TRACE("blast_eq_value", tout << "sz: " << sz << "\n" << mk_pp(lhs, m) << "\n";); if (is_numeral(lhs)) std::swap(lhs, rhs); @@ -2573,7 +2595,6 @@ void bv_rewriter::mk_t1_add_t2_eq_c(expr * t1, expr * t2, expr * c, expr_ref & r result = m.mk_eq(t1, m_util.mk_bv_sub(c, t2)); } -#include "ast/ast_pp.h" bool bv_rewriter::isolate_term(expr* lhs, expr* rhs, expr_ref& result) { if (!m_util.is_numeral(lhs) || !is_add(rhs)) { @@ -2730,13 +2751,13 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { st = mk_mul_eq(lhs, rhs, result); if (st != BR_FAILED) { - TRACE("mk_mul_eq", tout << mk_ismt2_pp(lhs, m) << "\n=\n" << mk_ismt2_pp(rhs, m) << "\n----->\n" << mk_ismt2_pp(result,m) << "\n";); + TRACE("mk_mul_eq", tout << mk_pp(lhs, m) << "\n=\n" << mk_pp(rhs, m) << "\n----->\n" << mk_pp(result,m) << "\n";); return st; } st = mk_mul_eq(rhs, lhs, result); if (st != BR_FAILED) { - TRACE("mk_mul_eq", tout << mk_ismt2_pp(lhs, m) << "\n=\n" << mk_ismt2_pp(rhs, m) << "\n----->\n" << mk_ismt2_pp(result,m) << "\n";); + TRACE("mk_mul_eq", tout << mk_pp(lhs, m) << "\n=\n" << mk_pp(rhs, m) << "\n----->\n" << mk_pp(result,m) << "\n";); return st; } @@ -2851,8 +2872,8 @@ bool bv_rewriter::is_eq_bit(expr * t, expr * & x, unsigned & val) { br_status bv_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & result) { - TRACE("bv_ite", tout << "mk_ite_core:\n" << mk_ismt2_pp(c, m) << "?\n" - << mk_ismt2_pp(t, m) << "\n:" << mk_ismt2_pp(e, m) << "\n";); + TRACE("bv_ite", tout << "mk_ite_core:\n" << mk_pp(c, m) << "?\n" + << mk_pp(t, m) << "\n:" << mk_pp(e, m) << "\n";); if (m.are_equal(t, e)) { result = e; return BR_REWRITE1; From 13be3c3fbb75e62cba56f55aa8ba1f0d073525b2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 15:16:04 -0800 Subject: [PATCH 010/224] reset model converter between rounds to elim-unconstrained. --- src/ast/converters/generic_model_converter.h | 2 ++ src/ast/rewriter/bv_rewriter.cpp | 1 - src/ast/simplifiers/elim_unconstrained.cpp | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ast/converters/generic_model_converter.h b/src/ast/converters/generic_model_converter.h index 8a1c62347..0bc6b21b4 100644 --- a/src/ast/converters/generic_model_converter.h +++ b/src/ast/converters/generic_model_converter.h @@ -68,6 +68,8 @@ public: void get_units(obj_map& units) override; vector const& entries() const { return m_entries; } + + void reset() { m_entries.reset(); } }; typedef ref generic_model_converter_ref; diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 64ecc5f53..db87cd008 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -555,7 +555,6 @@ br_status bv_rewriter::mk_leq_core(bool is_signed, expr * a, expr * b, expr_ref result = m.mk_and(result, m_util.mk_ule(m_util.mk_numeral(r1-r2, sz), a2)); else if (r1 < r2) result = m.mk_or(result, m_util.mk_ule(m_util.mk_numeral(r1-r2, sz), a2)); - verbose_stream() << result << "\n"; return BR_REWRITE2; } diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index c7cf2d11c..260f01974 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -426,7 +426,7 @@ void elim_unconstrained::reduce() { generic_model_converter_ref mc = alloc(generic_model_converter, m, "elim-unconstrained"); m_inverter.set_model_converter(mc.get()); m_created_compound = true; - for (unsigned rounds = 0; m_created_compound && rounds < 1; ++rounds) { + for (unsigned rounds = 0; m_created_compound && rounds < 3; ++rounds) { m_created_compound = false; init_nodes(); eliminate(); @@ -434,6 +434,7 @@ void elim_unconstrained::reduce() { vector old_fmls; assert_normalized(old_fmls); update_model_trail(*mc, old_fmls); + mc->reset(); } } From 0dc851132ea75cff932146beaa22427977f31b18 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 19:07:14 -0800 Subject: [PATCH 011/224] Create Windows.yml --- .github/workflows/Windows.yml | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .github/workflows/Windows.yml diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml new file mode 100644 index 000000000..a732854d3 --- /dev/null +++ b/.github/workflows/Windows.yml @@ -0,0 +1,45 @@ +name: Windows +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] +jobs: + build: + runs-on: windows-latest + strategy: + matrix: + x86: + arch: 'x86' + setupCmd1: '' + setupCmd2: '' + setupCmd3: '' + bindings: '$(cmakePy)' + runTests: 'False' + x64: + arch: 'x64' + setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"0.7.0\"))"' + setupCmd2: 'julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))" > tmp.env' + setupCmd3: 'set /P JlCxxDir= Date: Mon, 18 Dec 2023 19:09:01 -0800 Subject: [PATCH 012/224] Update Windows.yml --- .github/workflows/Windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index a732854d3..5ee65b80e 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -1,9 +1,9 @@ name: Windows on: push: - branches: [ main ] + branches: [ master ] pull_request: - branches: [ main ] + branches: [ master ] jobs: build: runs-on: windows-latest From c7c007c2c66e28f584927ceee359e6b8e2832b24 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 19:31:17 -0800 Subject: [PATCH 013/224] Update Windows.yml --- .github/workflows/Windows.yml | 65 ++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 5ee65b80e..c7ad28911 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -4,42 +4,43 @@ on: branches: [ master ] pull_request: branches: [ master ] -jobs: + +jobs: build: - runs-on: windows-latest strategy: matrix: - x86: - arch: 'x86' - setupCmd1: '' - setupCmd2: '' - setupCmd3: '' - bindings: '$(cmakePy)' - runTests: 'False' - x64: - arch: 'x64' - setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"0.7.0\"))"' - setupCmd2: 'julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))" > tmp.env' - setupCmd3: 'set /P JlCxxDir= tmp.env' + cmd3 : 'set /P JlCxxDir= Date: Mon, 18 Dec 2023 19:38:50 -0800 Subject: [PATCH 014/224] Update Windows.yml --- .github/workflows/Windows.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index c7ad28911..77059a652 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -39,7 +39,9 @@ jobs: if: ${{ matrix.cmd3 }} run: cmd3 - name: vscmd - run: call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }} + uses: seanmiddleditch/gha-setup-vsdevenv@v4 + with: + arch: $${ matrix.arch }} - name: configure run: cmake ${{ matrix.bindings }} -G "NMake Makefiles" ../ - name: make From 91ba893d7b4ca6c8fc46a89246d421960c6550f5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 19:43:11 -0800 Subject: [PATCH 015/224] Update Windows.yml --- .github/workflows/Windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 77059a652..0b9210d8c 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -24,7 +24,7 @@ jobs: runs-on: windows-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Create build directory run: md build - name: Build From 62ae9a0b7264ebf252cc38263dcf08a9eb44e930 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 19:46:39 -0800 Subject: [PATCH 016/224] Update Windows.yml --- .github/workflows/Windows.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 0b9210d8c..ef4d919e7 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -31,17 +31,19 @@ jobs: run: cd build - name: cmd1 if: ${{ matrix.cmd1 }} - run: cmd1 + run: ${{ matrix.cmd1 }} - name: cmd2 if: ${{ matrix.cmd2 }} - run: cmd2 + run: ${{ matrix.cmd2 }} - name: cmd3 if: ${{ matrix.cmd3 }} - run: cmd3 + run: ${{ matrix.cmd3 }} - name: vscmd uses: seanmiddleditch/gha-setup-vsdevenv@v4 with: arch: $${ matrix.arch }} + - name: cmake + uses: lukka/get-cmake@latest - name: configure run: cmake ${{ matrix.bindings }} -G "NMake Makefiles" ../ - name: make From 842385a7d7c59800810aee32a01d2d89bee0278c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 19:48:42 -0800 Subject: [PATCH 017/224] Update Windows.yml --- .github/workflows/Windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index ef4d919e7..800095f0f 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -1,9 +1,9 @@ name: Windows on: push: - branches: [ master ] + branches: [ master-test ] pull_request: - branches: [ master ] + branches: [ master-test ] jobs: build: From ea44c110bb5c81d4c190c0c601c5aeafa20f2b91 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 20:08:17 -0800 Subject: [PATCH 018/224] gc expressions in the scope of updates, not old expressions --- src/ast/simplifiers/elim_unconstrained.cpp | 9 +++++++-- src/sat/smt/euf_solver.cpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ast/simplifiers/elim_unconstrained.cpp b/src/ast/simplifiers/elim_unconstrained.cpp index 260f01974..818800d99 100644 --- a/src/ast/simplifiers/elim_unconstrained.cpp +++ b/src/ast/simplifiers/elim_unconstrained.cpp @@ -113,7 +113,7 @@ void elim_unconstrained::eliminate() { IF_VERBOSE(11, verbose_stream() << "replace " << mk_pp(t, m) << " / " << rr << " -> " << r << "\n"); - TRACE("elim_unconstrained", tout << mk_pp(t, m) << " -> " << r << "\n"); + TRACE("elim_unconstrained", tout << mk_pp(t, m) << " / " << rr << " -> " << r << "\n"); SASSERT(r->get_sort() == t->get_sort()); m_stats.m_num_eliminated++; m_trail.push_back(r); @@ -271,12 +271,18 @@ void elim_unconstrained::gc(expr* t) { while (!todo.empty()) { t = todo.back(); todo.pop_back(); + node& n = get_node(t); if (n.m_refcount == 0) continue; + if (n.m_term && !is_node(n.m_term)) + continue; + dec_ref(t); if (n.m_refcount != 0) continue; + if (n.m_term) + t = n.m_term; if (is_app(t)) { for (expr* arg : *to_app(t)) todo.push_back(arg); @@ -436,5 +442,4 @@ void elim_unconstrained::reduce() { update_model_trail(*mc, old_fmls); mc->reset(); } - } diff --git a/src/sat/smt/euf_solver.cpp b/src/sat/smt/euf_solver.cpp index ff11b0749..b108430d8 100644 --- a/src/sat/smt/euf_solver.cpp +++ b/src/sat/smt/euf_solver.cpp @@ -1112,7 +1112,7 @@ namespace euf { if (b != sat::null_bool_var) { r->m_bool_var2expr.setx(b, n->get_expr(), nullptr); SASSERT(r->m.is_bool(n->get_sort())); - IF_VERBOSE(11, verbose_stream() << "set bool_var " << b << " " << r->bpp(n) << " " << mk_bounded_pp(n->get_expr(), m) << "\n"); + IF_VERBOSE(20, verbose_stream() << "set bool_var " << b << " " << r->bpp(n) << " " << mk_bounded_pp(n->get_expr(), m) << "\n"); } } for (auto* s_orig : m_id2solver) { From bb8ed43cdb07e9d88319ea89199693c7ce776bdb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 20:20:21 -0800 Subject: [PATCH 019/224] Update Windows.yml --- .github/workflows/Windows.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 800095f0f..b9b4fab45 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -38,12 +38,10 @@ jobs: - name: cmd3 if: ${{ matrix.cmd3 }} run: ${{ matrix.cmd3 }} - - name: vscmd - uses: seanmiddleditch/gha-setup-vsdevenv@v4 - with: - arch: $${ matrix.arch }} - - name: cmake - uses: lukka/get-cmake@latest + - name: Setup Visual Studio environment + run: | + $vcvarsall = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvarsall.bat" + cmd /c "$vcvarsall" ${{ matrix.arch }} - name: configure run: cmake ${{ matrix.bindings }} -G "NMake Makefiles" ../ - name: make From ea03b558c6549cdfbf70f55915182c1b6e89d7b6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 20:23:45 -0800 Subject: [PATCH 020/224] Update Windows.yml --- .github/workflows/Windows.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index b9b4fab45..a1eb9c89a 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -1,9 +1,6 @@ name: Windows on: - push: - branches: [ master-test ] - pull_request: - branches: [ master-test ] + workflow_dispatch: jobs: build: From 9469f7574a60ec7185afc6665978387e29d60ee2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 20:26:39 -0800 Subject: [PATCH 021/224] Update Windows.yml --- .github/workflows/Windows.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index a1eb9c89a..4c3ef50a6 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -37,8 +37,7 @@ jobs: run: ${{ matrix.cmd3 }} - name: Setup Visual Studio environment run: | - $vcvarsall = "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvarsall.bat" - cmd /c "$vcvarsall" ${{ matrix.arch }} + cmd /c ""C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }} - name: configure run: cmake ${{ matrix.bindings }} -G "NMake Makefiles" ../ - name: make From 394a355b19b6f88b593c54e6d1b01570ba1570d8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Dec 2023 04:29:30 +0000 Subject: [PATCH 022/224] fix string Signed-off-by: Nikolaj Bjorner --- .github/workflows/Windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 4c3ef50a6..d21413496 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -37,7 +37,7 @@ jobs: run: ${{ matrix.cmd3 }} - name: Setup Visual Studio environment run: | - cmd /c ""C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }} + cmd /c "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }} - name: configure run: cmake ${{ matrix.bindings }} -G "NMake Makefiles" ../ - name: make From 00965cbdf2be02a55b62ae35dd7639a037debd82 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Dec 2023 04:31:54 +0000 Subject: [PATCH 023/224] fix string Signed-off-by: Nikolaj Bjorner --- .github/workflows/Windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index d21413496..b607ea2a7 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -39,6 +39,6 @@ jobs: run: | cmd /c "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }} - name: configure - run: cmake ${{ matrix.bindings }} -G "NMake Makefiles" ../ + run: cmake ${{ matrix.bindings }} -G "NMake Makefiles" .. - name: make run: nmake From 1b7550483e2ce2f3153654bd7497fe0df983b935 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Dec 2023 04:33:07 +0000 Subject: [PATCH 024/224] add path n prefix Signed-off-by: Nikolaj Bjorner --- .github/workflows/Windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index b607ea2a7..eaad6b804 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -39,6 +39,6 @@ jobs: run: | cmd /c "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }} - name: configure - run: cmake ${{ matrix.bindings }} -G "NMake Makefiles" .. + run: cmake .. ${{ matrix.bindings }} -G "NMake Makefiles" - name: make run: nmake From 2602fc2eb56b55cdb5d5b38fb997341fc76ccde2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Dec 2023 04:41:02 +0000 Subject: [PATCH 025/224] remove reference to matrix bindings to see if it works Signed-off-by: Nikolaj Bjorner --- .github/workflows/Windows.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index eaad6b804..613cb18c6 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -9,14 +9,14 @@ jobs: arch : [x86,x64,amd64_arm64] include: - arch : x86 - bindings : -DZ3_BUILD_PYTHON_BINDINGS=True + bindings : '-DZ3_BUILD_PYTHON_BINDINGS=True' - arch : x64 cmd1 : 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"0.7.0\"))"' cmd2 : 'julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))" > tmp.env' cmd3 : 'set /P JlCxxDir= Date: Tue, 19 Dec 2023 04:45:02 +0000 Subject: [PATCH 026/224] remove reference to matrix bindings to see if it works Signed-off-by: Nikolaj Bjorner --- .github/workflows/Windows.yml | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 613cb18c6..a0fb58297 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -22,23 +22,11 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Create build directory - run: md build - name: Build - run: cd build - - name: cmd1 - if: ${{ matrix.cmd1 }} - run: ${{ matrix.cmd1 }} - - name: cmd2 - if: ${{ matrix.cmd2 }} - run: ${{ matrix.cmd2 }} - - name: cmd3 - if: ${{ matrix.cmd3 }} - run: ${{ matrix.cmd3 }} - - name: Setup Visual Studio environment - run: | + run: | + md build + cd build cmd /c "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }} - - name: configure - run: cmake -G "NMake Makefiles" ../ - - name: make - run: nmake + cmake -G "NMake Makefiles" ../ + nmake + From 9a18628b17d2704ada69f05774fa4849db70e219 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 18 Dec 2023 18:49:27 -1000 Subject: [PATCH 027/224] remove unnecessary assignments --- src/math/lp/gomory.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 5c38a8c7f..26686b206 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -242,7 +242,6 @@ public: // gomory will be t >= k and the current solution has a property t < k m_k = 1; m_t.clear(); - mpq m_f = fractional_part(get_value(m_inf_col)); TRACE("gomory_cut_detail", tout << "m_f: " << m_f << ", "; tout << "1 - m_f: " << 1 - m_f << ", get_value(m_inf_col).x - m_f = " << get_value(m_inf_col).x - m_f << "\n";); lp_assert(m_f.is_pos() && (get_value(m_inf_col).x - m_f).is_int()); @@ -257,7 +256,6 @@ public: } m_big_number = m_abs_max.expt(2); #endif - mpq one_min_m_f = 1 - m_f; for (const auto & p : m_row) { unsigned j = p.var(); if (j == m_inf_col) { From e5f52e213146c6fc3d3a60bbaee6cdfaef93cb85 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2023 20:53:51 -0800 Subject: [PATCH 028/224] Update Windows.yml --- .github/workflows/Windows.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index a0fb58297..86cd0e9a0 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -22,6 +22,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1.1 - name: Build run: | md build From fcc7b25c191519990b9710db9a86b222e6be8521 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Tue, 19 Dec 2023 14:34:37 +0000 Subject: [PATCH 029/224] remove a few string copies --- src/api/api_ast.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index a28b3f20b..dfe47b8b5 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -377,9 +377,7 @@ extern "C" { RESET_ERROR_CODE(); symbol _s = to_symbol(s); if (_s.is_numerical()) { - std::ostringstream buffer; - buffer << _s.get_num(); - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::to_string(_s.get_num())); } else { return mk_c(c)->mk_external_string(_s.str()); @@ -823,7 +821,7 @@ extern "C" { param_descrs descrs; th_rewriter::get_param_descrs(descrs); descrs.display(buffer); - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); Z3_CATCH_RETURN(""); } @@ -1031,7 +1029,7 @@ extern "C" { default: UNREACHABLE(); } - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); Z3_CATCH_RETURN(nullptr); } @@ -1066,7 +1064,7 @@ extern "C" { pp.add_assumption(to_expr(assumptions[i])); } pp.display_smt2(buffer, to_expr(formula)); - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); Z3_CATCH_RETURN(""); } From 4c9f705cd18054c36f8afd4e13b42ec8b85bf01e Mon Sep 17 00:00:00 2001 From: Jakob Rath Date: Tue, 19 Dec 2023 17:58:32 +0100 Subject: [PATCH 030/224] tptr: add pointer tagging templates (#7067) --- src/util/tptr.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/util/tptr.h b/src/util/tptr.h index 37b6f64fe..99abe34a7 100644 --- a/src/util/tptr.h +++ b/src/util/tptr.h @@ -21,6 +21,7 @@ Revision History: #include #include "util/machine.h" +#include "util/debug.h" #define TAG_SHIFT PTR_ALIGNMENT #define ALIGNMENT_VALUE (1 << PTR_ALIGNMENT) @@ -42,4 +43,22 @@ Revision History: #define UNBOXINT(PTR) static_cast(reinterpret_cast(PTR) >> PTR_ALIGNMENT) +template +U unbox(T* ptr) { + return static_cast(reinterpret_cast(ptr) >> PTR_ALIGNMENT); +} +template +unsigned get_tag(T* ptr) { + return reinterpret_cast(ptr) & TAG_MASK; +} + +template +T* box(U val, std::uintptr_t tag = 0) { + static_assert( sizeof(T*) >= sizeof(U) + PTR_ALIGNMENT ); + SASSERT_EQ(tag & PTR_MASK, 0); + T* ptr = reinterpret_cast((static_cast(val) << PTR_ALIGNMENT) | tag); + SASSERT_EQ(val, unbox(ptr)); // roundtrip of conversion integer -> pointer -> integer is not actually guaranteed by the C++ standard (but seems fine in practice, as indicated by previous usage of BOXINT/UNBOXINT) + SASSERT_EQ(tag, get_tag(ptr)); + return ptr; +} From 97d450868ed06f06874c73210b90c3373075f110 Mon Sep 17 00:00:00 2001 From: Jakob Rath Date: Tue, 19 Dec 2023 17:58:55 +0100 Subject: [PATCH 031/224] Vector updates from polysat branch (#7066) * vector: add erase_if * vector: generalize operator<< * vector: fix missing destructor call --- src/util/vector.h | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/util/vector.h b/src/util/vector.h index ea621b5fb..d684f43eb 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -30,6 +30,7 @@ Revision History: #include #include #include +#include #include "util/memory_manager.h" #include "util/hash.h" #include "util/z3_exception.h" @@ -558,7 +559,7 @@ public: for(; pos != e; ++pos, ++prev) { *prev = std::move(*pos); } - reinterpret_cast(m_data)[SIZE_IDX]--; + pop_back(); } void erase(T const & elem) { @@ -568,6 +569,20 @@ public: } } + /** Erase all elements that satisfy the given predicate. Returns the number of erased elements. */ + template + SZ erase_if(UnaryPredicate should_erase) { + iterator i = begin(); + iterator const e = end(); + for (iterator j = begin(); j != e; ++j) + if (!should_erase(std::as_const(*j))) + *(i++) = std::move(*j); + SZ const count = e - i; + SASSERT_EQ(i - begin(), size() - count); + shrink(size() - count); + return count; + } + void shrink(SZ s) { if (m_data) { SASSERT(s <= reinterpret_cast(m_data)[SIZE_IDX]); @@ -756,7 +771,8 @@ using bool_vector = svector; template inline std::ostream& operator<<(std::ostream& out, svector const& v) { - for (unsigned u : v) out << u << " "; + for (auto const& x : v) + out << x << " "; return out; } From db5a1a7604bfe06299d4273ee4affb2132d24851 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 08:59:11 -0800 Subject: [PATCH 032/224] Bump actions/upload-artifact from 3 to 4 (#7065) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/android-build.yml | 2 +- .github/workflows/coverage.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index 8a6a32c6b..5419720ef 100644 --- a/.github/workflows/android-build.yml +++ b/.github/workflows/android-build.yml @@ -32,7 +32,7 @@ jobs: tar -cvf z3-build-${{ matrix.android-abi }}.tar *.jar *.so - name: Archive production artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: android-build-${{ matrix.android-abi }} path: build/z3-build-${{ matrix.android-abi }}.tar diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 2ed02aab1..30a385b3f 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -91,13 +91,13 @@ jobs: id: date run: echo "::set-output name=date::$(date +'%Y-%m-%d')" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: coverage-${{steps.date.outputs.date}} path: ${{github.workspace}}/coverage.html retention-days: 4 - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: coverage-details-${{steps.date.outputs.date}} path: ${{env.COV_DETAILS_PATH}} From d6365610d54087f2167c8e05423e6a7b3089df2c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 20 Dec 2023 06:49:55 -1000 Subject: [PATCH 033/224] change some TRACE statements --- src/math/lp/int_solver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/math/lp/int_solver.cpp b/src/math/lp/int_solver.cpp index f760755a2..5dde06690 100644 --- a/src/math/lp/int_solver.cpp +++ b/src/math/lp/int_solver.cpp @@ -670,11 +670,11 @@ namespace lp { if (abs(value.x) < small_value || (has_upper(j) && small_value > upper_bound(j).x - value.x) || (has_lower(j) && small_value > value.x - lower_bound(j).x)) { - TRACE("gomory_cut", tout << "small j" << j << "\n"); + TRACE("int_solver", tout << "small j" << j << "\n"); add_column(true, r_small_value, n_small_value, j); continue; } - TRACE("gomory_cut", tout << "any j" << j << "\n"); + TRACE("int_solver", tout << "any j" << j << "\n"); add_column(usage >= prev_usage, r_any_value, n_any_value, j); if (usage > prev_usage) prev_usage = usage; From e28b644a67d44cc39c5ec33456957226c9a9ce1c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 20 Dec 2023 06:53:59 -1000 Subject: [PATCH 034/224] remove an empty line --- src/math/lp/int_solver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/math/lp/int_solver.cpp b/src/math/lp/int_solver.cpp index 5dde06690..cfd94443b 100644 --- a/src/math/lp/int_solver.cpp +++ b/src/math/lp/int_solver.cpp @@ -950,7 +950,6 @@ namespace lp { if (!feas) return lia_move::conflict; - } if (!_check_feasible()) From b2d5c24c1df440b653bd6a31955849545a8bf6ad Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 20 Dec 2023 16:55:09 +0000 Subject: [PATCH 035/224] remove a few string copies --- src/api/api_ast.cpp | 6 ++---- src/api/api_ast_map.cpp | 4 ++-- src/api/api_context.cpp | 6 +++--- src/api/api_fpa.cpp | 4 ++-- src/api/api_goal.cpp | 4 ++-- src/api/api_model.cpp | 4 ++-- src/api/api_numeral.cpp | 10 +++++----- src/api/api_solver.cpp | 16 ++++++++-------- src/ast/ast_pp.h | 4 ++-- src/ast/rewriter/pb_rewriter.cpp | 8 ++------ src/ast/well_sorted.cpp | 3 +-- src/math/lp/numeric_pair.h | 1 - src/model/model_smt2_pp.cpp | 6 ++---- src/sat/sat_cutset.cpp | 2 +- src/sat/sat_solver.cpp | 2 +- src/smt/smt_context_pp.cpp | 4 ++-- src/util/sstream.h | 31 ------------------------------- src/util/zstring.cpp | 4 ++-- 18 files changed, 39 insertions(+), 80 deletions(-) delete mode 100644 src/util/sstream.h diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index dfe47b8b5..424b361f3 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -146,8 +146,7 @@ extern "C" { ast_manager& m = mk_c(c)->m(); recfun::decl::plugin& p = mk_c(c)->recfun().get_plugin(); if (!p.has_def(d)) { - std::string msg = "function " + mk_pp(d, m) + " needs to be declared using rec_func_decl"; - SET_ERROR_CODE(Z3_INVALID_ARG, msg.c_str()); + SET_ERROR_CODE(Z3_INVALID_ARG, "function " + mk_pp(d, m) + " needs to be declared using rec_func_decl"); return; } expr_ref abs_body(m); @@ -168,8 +167,7 @@ extern "C" { return; } if (!pd.get_def()->get_cases().empty()) { - std::string msg = "function " + mk_pp(d, m) + " has already been given a definition"; - SET_ERROR_CODE(Z3_INVALID_ARG, msg.c_str()); + SET_ERROR_CODE(Z3_INVALID_ARG, "function " + mk_pp(d, m) + " has already been given a definition"); return; } diff --git a/src/api/api_ast_map.cpp b/src/api/api_ast_map.cpp index 5976d0e41..523ba1f59 100644 --- a/src/api/api_ast_map.cpp +++ b/src/api/api_ast_map.cpp @@ -160,8 +160,8 @@ extern "C" { for (; it != end; ++it) { buffer << "\n (" << mk_ismt2_pp(it->m_key, mng, 3) << "\n " << mk_ismt2_pp(it->m_value, mng, 3) << ")"; } - buffer << ")"; - return mk_c(c)->mk_external_string(buffer.str()); + buffer << ')'; + return mk_c(c)->mk_external_string(std::move(buffer).str()); Z3_CATCH_RETURN(nullptr); } diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index 66cd715c9..344224dd3 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -338,12 +338,12 @@ namespace api { std::ostringstream buffer; app * a = to_app(n); buffer << mk_pp(a->get_decl(), m()) << " applied to: "; - if (a->get_num_args() > 1) buffer << "\n"; + if (a->get_num_args() > 1) buffer << '\n'; for (unsigned i = 0; i < a->get_num_args(); ++i) { buffer << mk_bounded_pp(a->get_arg(i), m(), 3) << " of sort "; - buffer << mk_pp(a->get_arg(i)->get_sort(), m()) << "\n"; + buffer << mk_pp(a->get_arg(i)->get_sort(), m()) << '\n'; } - auto str = buffer.str(); + auto str = std::move(buffer).str(); warning_msg("%s", str.c_str()); break; } diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp index aeb075e45..3c350ed18 100644 --- a/src/api/api_fpa.cpp +++ b/src/api/api_fpa.cpp @@ -1022,7 +1022,7 @@ extern "C" { if (mpfm.is_inf(val)) mpqm.set(q, 0); std::stringstream ss; mpqm.display_decimal(ss, q, sbits); - return mk_c(c)->mk_external_string(ss.str()); + return mk_c(c)->mk_external_string(std::move(ss).str()); Z3_CATCH_RETURN(""); } @@ -1100,7 +1100,7 @@ extern "C" { } std::stringstream ss; ss << exp; - return mk_c(c)->mk_external_string(ss.str()); + return mk_c(c)->mk_external_string(std::move(ss).str()); Z3_CATCH_RETURN(""); } diff --git a/src/api/api_goal.cpp b/src/api/api_goal.cpp index cfe0974df..cbb67f2a2 100644 --- a/src/api/api_goal.cpp +++ b/src/api/api_goal.cpp @@ -185,7 +185,7 @@ extern "C" { std::ostringstream buffer; to_goal_ref(g)->display(buffer); // Hack for removing the trailing '\n' - std::string result = buffer.str(); + std::string result = std::move(buffer).str(); SASSERT(result.size() > 0); result.resize(result.size()-1); return mk_c(c)->mk_external_string(std::move(result)); @@ -203,7 +203,7 @@ extern "C" { } to_goal_ref(g)->display_dimacs(buffer, include_names); // Hack for removing the trailing '\n' - std::string result = buffer.str(); + std::string result = std::move(buffer).str(); SASSERT(result.size() > 0); result.resize(result.size()-1); return mk_c(c)->mk_external_string(std::move(result)); diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 3512b4b05..e449cb0ea 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -432,14 +432,14 @@ extern "C" { if (mk_c(c)->get_print_mode() == Z3_PRINT_SMTLIB2_COMPLIANT) { model_smt2_pp(buffer, mk_c(c)->m(), *(to_model_ref(m)), 0); // Hack for removing the trailing '\n' - result = buffer.str(); + result = std::move(buffer).str(); if (!result.empty()) result.resize(result.size()-1); } else { model_params p; model_v2_pp(buffer, *(to_model_ref(m)), p.partial()); - result = buffer.str(); + result = std::move(buffer).str(); } return mk_c(c)->mk_external_string(std::move(result)); Z3_CATCH_RETURN(nullptr); diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index ebac4de31..98dceffb7 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -189,7 +189,7 @@ extern "C" { if (ok && r.is_int() && !r.is_neg()) { std::stringstream strm; r.display_bin(strm, r.get_num_bits()); - return mk_c(c)->mk_external_string(strm.str()); + return mk_c(c)->mk_external_string(std::move(strm).str()); } else { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); @@ -237,7 +237,7 @@ extern "C" { else if (mk_c(c)->fpautil().is_numeral(to_expr(a), tmp)) { std::ostringstream buffer; fu.fm().display_smt2(buffer, tmp, false); - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); } else { SET_ERROR_CODE(Z3_INVALID_ARG, nullptr); @@ -288,21 +288,21 @@ extern "C" { if (u.is_numeral(e, r) && !r.is_int()) { std::ostringstream buffer; r.display_decimal(buffer, precision); - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); } if (u.is_irrational_algebraic_numeral(e)) { algebraic_numbers::anum const & n = u.to_irrational_algebraic_numeral(e); algebraic_numbers::manager & am = u.am(); std::ostringstream buffer; am.display_decimal(buffer, n, precision); - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); } else if (mk_c(c)->fpautil().is_rm_numeral(to_expr(a), rm)) return Z3_get_numeral_string(c, a); else if (mk_c(c)->fpautil().is_numeral(to_expr(a), ftmp)) { std::ostringstream buffer; fu.fm().display_decimal(buffer, ftmp, 12); - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); } else if (Z3_get_numeral_rational(c, a, r)) { return mk_c(c)->mk_external_string(r.to_string()); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 953167fe9..ac100ee30 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -170,8 +170,8 @@ extern "C" { if (g_is_threaded || g_thread_id != std::this_thread::get_id()) { g_is_threaded = true; std::ostringstream strm; - strm << smt2log << "-" << std::this_thread::get_id(); - smt2log = symbol(strm.str()); + strm << smt2log << '-' << std::this_thread::get_id(); + smt2log = symbol(std::move(strm).str()); } to_solver(s)->m_pp = alloc(solver2smt2_pp, mk_c(c)->m(), smt2log.str()); } @@ -208,7 +208,7 @@ extern "C" { if (!smt_logics::supported_logic(to_symbol(logic))) { std::ostringstream strm; strm << "logic '" << to_symbol(logic) << "' is not recognized"; - SET_ERROR_CODE(Z3_INVALID_ARG, strm.str()); + SET_ERROR_CODE(Z3_INVALID_ARG, std::move(strm).str()); RETURN_Z3(nullptr); } else { @@ -306,7 +306,7 @@ extern "C" { if (!parse_smt2_commands(*ctx.get(), is)) { ctx = nullptr; - SET_ERROR_CODE(Z3_PARSER_ERROR, errstrm.str()); + SET_ERROR_CODE(Z3_PARSER_ERROR, std::move(errstrm).str()); return; } @@ -333,7 +333,7 @@ extern "C" { std::stringstream err; sat::solver solver(to_solver_ref(s)->get_params(), m.limit()); if (!parse_dimacs(is, err, solver)) { - SET_ERROR_CODE(Z3_PARSER_ERROR, err.str()); + SET_ERROR_CODE(Z3_PARSER_ERROR, std::move(err).str()); return; } sat2goal s2g; @@ -400,7 +400,7 @@ extern "C" { if (!initialized) to_solver(s)->m_solver = nullptr; descrs.display(buffer); - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); Z3_CATCH_RETURN(""); } @@ -799,7 +799,7 @@ extern "C" { init_solver(c, s); std::ostringstream buffer; to_solver_ref(s)->display(buffer); - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); Z3_CATCH_RETURN(""); } @@ -810,7 +810,7 @@ extern "C" { init_solver(c, s); std::ostringstream buffer; to_solver_ref(s)->display_dimacs(buffer, include_names); - return mk_c(c)->mk_external_string(buffer.str()); + return mk_c(c)->mk_external_string(std::move(buffer).str()); Z3_CATCH_RETURN(""); } diff --git a/src/ast/ast_pp.h b/src/ast/ast_pp.h index 7ccb8ec15..1f20ce300 100644 --- a/src/ast/ast_pp.h +++ b/src/ast/ast_pp.h @@ -58,13 +58,13 @@ inline std::ostream& operator<<(std::ostream & out, mk_pp_vec const & pp) { inline std::string operator+(char const* s, mk_pp const& pp) { std::ostringstream strm; strm << s << pp; - return strm.str(); + return std::move(strm).str(); } inline std::string operator+(std::string const& s, mk_pp const& pp) { std::ostringstream strm; strm << s << pp; - return strm.str(); + return std::move(strm).str(); } inline std::string& operator+=(std::string& s, mk_pp const& pp) { diff --git a/src/ast/rewriter/pb_rewriter.cpp b/src/ast/rewriter/pb_rewriter.cpp index 2f06710ff..4f1fe3fd1 100644 --- a/src/ast/rewriter/pb_rewriter.cpp +++ b/src/ast/rewriter/pb_rewriter.cpp @@ -157,9 +157,7 @@ expr_ref pb_rewriter::mk_validate_rewrite(app_ref& e1, app_ref& e2) { continue; } - std::ostringstream strm; - strm << 'x' << i; - name = symbol(strm.str()); + name = symbol('x' + std::to_string(i)); trail.push_back(m.mk_const(name, a.mk_int())); expr* x = trail.back(); m.is_not(e,e); @@ -188,9 +186,7 @@ void pb_rewriter::validate_rewrite(func_decl* f, unsigned sz, expr*const* args, } void pb_rewriter::dump_pb_rewrite(expr* fml) { - std::ostringstream strm; - strm << "pb_rewrite_" << (s_lemma++) << ".smt2"; - std::ofstream out(strm.str()); + std::ofstream out("pb_rewrite_" + std::to_string(s_lemma++) + ".smt2"); ast_smt_pp pp(m()); pp.display_smt2(out, fml); out.close(); diff --git a/src/ast/well_sorted.cpp b/src/ast/well_sorted.cpp index fa8e2768b..84cdf28ad 100644 --- a/src/ast/well_sorted.cpp +++ b/src/ast/well_sorted.cpp @@ -70,8 +70,7 @@ struct well_sorted_proc { strm << "Expected sort: " << mk_pp(expected_sort, m_manager) << '\n'; strm << "Actual sort: " << mk_pp(actual_sort, m_manager) << '\n'; strm << "Function sort: " << mk_pp(decl, m_manager) << '.'; - auto str = strm.str(); - warning_msg("%s", str.c_str()); + warning_msg("%s", std::move(strm).str().c_str()); m_error = true; return; } diff --git a/src/math/lp/numeric_pair.h b/src/math/lp/numeric_pair.h index 251274006..93780f7be 100644 --- a/src/math/lp/numeric_pair.h +++ b/src/math/lp/numeric_pair.h @@ -24,7 +24,6 @@ #include #ifdef lp_for_z3 #include "util/rational.h" -#include "util/sstream.h" #include "util/z3_exception.h" #else // include "util/numerics/mpq.h" diff --git a/src/model/model_smt2_pp.cpp b/src/model/model_smt2_pp.cpp index b5ac3fbad..89ea98075 100644 --- a/src/model/model_smt2_pp.cpp +++ b/src/model/model_smt2_pp.cpp @@ -68,7 +68,7 @@ static void pp_uninterp_sorts(std::ostream & out, ast_printer_context & ctx, mod buffer << " "; } buffer << "\n-----------"; - std::string buffer_str = buffer.str(); + std::string buffer_str = std::move(buffer).str(); unsigned len = static_cast(buffer_str.length()); pp_indent(out, indent); out << ";; "; @@ -206,9 +206,7 @@ static void pp_funs(std::ostream & out, ast_printer_context & ctx, model_core co if (f_i->is_partial()) { body = mk_string(m, "#unspecified"); for (unsigned j = 0; j < f->get_arity(); j++) { - std::stringstream strm; - strm << "x!" << (j+1); - var_names.push_back(symbol(strm.str())); + var_names.push_back(symbol("x!" + std::to_string(j+1))); } } else { diff --git a/src/sat/sat_cutset.cpp b/src/sat/sat_cutset.cpp index aae9bf1ab..2d31bcf14 100644 --- a/src/sat/sat_cutset.cpp +++ b/src/sat/sat_cutset.cpp @@ -273,7 +273,7 @@ namespace sat { std::string cut::table2string(unsigned num_input, uint64_t table) { std::ostringstream strm; display_table(strm, num_input, table); - return strm.str(); + return std::move(strm).str(); } diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index a1b88bed1..2d2962940 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2280,7 +2280,7 @@ namespace sat { << std::setw(4) << m_stats.m_restart << mk_stat(*this) << " " << std::setw(6) << std::setprecision(2) << m_stopwatch.get_current_seconds() << ")\n"; - std::string str(strm.str()); + std::string str = std::move(strm).str(); svector nums; for (size_t i = 0; i < str.size(); ++i) { while (i < str.size() && str[i] != ' ') ++i; diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 3925a4e21..4842f6e23 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -510,7 +510,7 @@ namespace smt { #else strm << "lemma_" << (++m_lemma_id) << ".smt2"; #endif - return strm.str(); + return std::move(strm).str(); } @@ -722,7 +722,7 @@ namespace smt { << std::setw(4) << m_stats.m_num_del_clauses << " " << std::setw(7) << mem_stat() << ")\n"; - std::string str(strm.str()); + std::string str = std::move(strm).str(); svector offsets; for (size_t i = 0; i < str.size(); ++i) { while (i < str.size() && str[i] != ' ') ++i; diff --git a/src/util/sstream.h b/src/util/sstream.h deleted file mode 100644 index fba13c5d5..000000000 --- a/src/util/sstream.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright (c) 2018 Microsoft Corporation - -Module Name: - - nat_set.h - -Abstract: - - Wrapper for sstream. - -Author: - - Leonardo de Moura (leonardo) 2013 - -Revision History: - -*/ -#pragma once -#include -#include - -namespace lean { -/** \brief Wrapper for std::ostringstream */ -class sstream { - std::ostringstream m_strm; -public: - std::string str() const { return m_strm.str(); } - template sstream & operator<<(T const & t) { m_strm << t; return *this; } -}; -} diff --git a/src/util/zstring.cpp b/src/util/zstring.cpp index eaa5bb5ee..8e08820f6 100644 --- a/src/util/zstring.cpp +++ b/src/util/zstring.cpp @@ -152,7 +152,7 @@ std::string zstring::encode() const { unsigned ch = m_buffer[i]; if (ch < 32 || ch >= 128 || ('\\' == ch && i + 1 < m_buffer.size() && 'u' == m_buffer[i+1])) { _flush(); - strm << "\\u{" << std::hex << ch << std::dec << "}"; + strm << "\\u{" << std::hex << ch << std::dec << '}'; } else { if (offset == 99) @@ -161,7 +161,7 @@ std::string zstring::encode() const { } } _flush(); - return strm.str(); + return std::move(strm).str(); } bool zstring::suffixof(zstring const& other) const { From 4898a156d8fcc2a627e82778fae6b55437f829f7 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 20 Dec 2023 16:58:45 +0000 Subject: [PATCH 036/224] shrink ast's app by 8 bytes on 64-bit platforms when number of args > 0 --- src/ast/ast.cpp | 33 ++++++--------------------------- src/ast/ast.h | 17 +++++++---------- 2 files changed, 13 insertions(+), 37 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 6ea293b57..f3be7d2c6 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -319,26 +319,6 @@ func_decl::func_decl(symbol const & name, unsigned arity, sort * const * domain, // // ----------------------------------- -static app_flags mk_const_flags() { - app_flags r; - r.m_depth = 1; - r.m_ground = true; - r.m_has_quantifiers = false; - r.m_has_labels = false; - return r; -} - -static app_flags mk_default_app_flags() { - app_flags r; - r.m_depth = 1; - r.m_ground = true; - r.m_has_quantifiers = false; - r.m_has_labels = false; - return r; -} - -app_flags app::g_constant_flags = mk_const_flags(); - app::app(func_decl * decl, unsigned num_args, expr * const * args): expr(AST_APP), m_decl(decl), @@ -1762,8 +1742,7 @@ ast * ast_manager::register_node_core(ast * n) { inc_ref(t->get_decl()); unsigned num_args = t->get_num_args(); if (num_args > 0) { - app_flags * f = t->flags(); - *f = mk_default_app_flags(); + app_flags * f = &t->m_flags; SASSERT(t->is_ground()); SASSERT(!t->has_quantifiers()); SASSERT(!t->has_labels()); @@ -1776,13 +1755,13 @@ ast * ast_manager::register_node_core(ast * n) { unsigned arg_depth = 0; switch (arg->get_kind()) { case AST_APP: { - app_flags * arg_flags = to_app(arg)->flags(); - arg_depth = arg_flags->m_depth; - if (arg_flags->m_has_quantifiers) + app *app = to_app(arg); + arg_depth = app->get_depth(); + if (app->has_quantifiers()) f->m_has_quantifiers = true; - if (arg_flags->m_has_labels) + if (app->has_labels()) f->m_has_labels = true; - if (!arg_flags->m_ground) + if (!app->is_ground()) f->m_ground = false; break; } diff --git a/src/ast/ast.h b/src/ast/ast.h index b4b3b1b2f..9618c7e12 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -704,6 +704,7 @@ struct app_flags { unsigned m_ground:1; // application does not have free variables or nested quantifiers. unsigned m_has_quantifiers:1; // application has nested quantifiers. unsigned m_has_labels:1; // application has nested labels. + app_flags() : m_depth(1), m_ground(1), m_has_quantifiers(0), m_has_labels(0) {} }; class app : public expr { @@ -711,19 +712,15 @@ class app : public expr { func_decl * m_decl; unsigned m_num_args; + app_flags m_flags; expr * m_args[0]; - static app_flags g_constant_flags; - - // remark: store term depth in the end of the app. the depth is only stored if the num_args > 0 static unsigned get_obj_size(unsigned num_args) { - return num_args == 0 ? sizeof(app) : sizeof(app) + num_args * sizeof(expr *) + sizeof(app_flags); + return sizeof(app) + num_args * sizeof(expr *); } friend class tmp_app; - app_flags * flags() const { return m_num_args == 0 ? &g_constant_flags : reinterpret_cast(const_cast(m_args + m_num_args)); } - app(func_decl * decl, unsigned num_args, expr * const * args); public: func_decl * get_decl() const { return m_decl; } @@ -744,10 +741,10 @@ public: expr * const * end() const { return m_args + m_num_args; } sort * _get_sort() const { return get_decl()->get_range(); } - unsigned get_depth() const { return flags()->m_depth; } - bool is_ground() const { return flags()->m_ground; } - bool has_quantifiers() const { return flags()->m_has_quantifiers; } - bool has_labels() const { return flags()->m_has_labels; } + unsigned get_depth() const { return m_flags.m_depth; } + bool is_ground() const { return m_flags.m_ground; } + bool has_quantifiers() const { return m_flags.m_has_quantifiers; } + bool has_labels() const { return m_flags.m_has_labels; } }; // ----------------------------------- From c9c53b7c6501c7ccd4657353061fbef05aa411b7 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 20 Dec 2023 18:19:20 +0000 Subject: [PATCH 037/224] tmp_enode: don't heap allocate an app. store it inline instead. Saves heap allocations and double indirections --- src/ast/ast.h | 4 ++++ src/smt/smt_enode.cpp | 18 ++++-------------- src/smt/smt_enode.h | 3 +-- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index 9618c7e12..a42d894ae 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -707,6 +707,8 @@ struct app_flags { app_flags() : m_depth(1), m_ground(1), m_has_quantifiers(0), m_has_labels(0) {} }; +namespace smt { class tmp_enode; } + class app : public expr { friend class ast_manager; @@ -720,8 +722,10 @@ class app : public expr { } friend class tmp_app; + friend class smt::tmp_enode; app(func_decl * decl, unsigned num_args, expr * const * args); + app() : expr(AST_APP) {} public: func_decl * get_decl() const { return m_decl; } family_id get_family_id() const { return get_decl()->get_family_id(); } diff --git a/src/smt/smt_enode.cpp b/src/smt/smt_enode.cpp index 86b83af4c..4bcb4a41c 100644 --- a/src/smt/smt_enode.cpp +++ b/src/smt/smt_enode.cpp @@ -327,7 +327,6 @@ namespace smt { } tmp_enode::tmp_enode(): - m_app(0), m_capacity(0), m_enode_data(nullptr) { SASSERT(m_app.get_app()->get_decl() == 0); @@ -340,14 +339,13 @@ namespace smt { void tmp_enode::set_capacity(unsigned new_capacity) { SASSERT(new_capacity > m_capacity); - if (m_enode_data) - dealloc_svect(m_enode_data); + dealloc_svect(m_enode_data); m_capacity = new_capacity; unsigned sz = sizeof(enode) + m_capacity * sizeof(enode*); m_enode_data = alloc_svect(char, sz); memset(m_enode_data, 0, sz); enode * n = get_enode(); - n->m_owner = m_app.get_app(); + n->m_owner = &m_app; n->m_root = n; n->m_next = n; n->m_class_size = 1; @@ -359,19 +357,11 @@ namespace smt { if (num_args > m_capacity) set_capacity(num_args * 2); enode * r = get_enode(); - if (m_app.get_app()->get_decl() != f) { - r->m_func_decl_id = UINT_MAX; - } - m_app.set_decl(f); - m_app.set_num_args(num_args); + m_app.m_decl = f; + m_app.m_num_args = num_args; r->m_commutative = num_args == 2 && f->is_commutative(); memcpy(get_enode()->m_args, args, sizeof(enode*)*num_args); return r; } - void tmp_enode::reset() { - get_enode()->m_func_decl_id = UINT_MAX; - } - }; - diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 92902ea0b..7229dab29 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -456,7 +456,7 @@ namespace smt { void unmark_enodes2(unsigned num_enodes, enode * const * enodes); class tmp_enode { - tmp_app m_app; + app m_app; unsigned m_capacity; char * m_enode_data; enode * get_enode() { return reinterpret_cast(m_enode_data); } @@ -465,7 +465,6 @@ namespace smt { tmp_enode(); ~tmp_enode(); enode * set(func_decl * f, unsigned num_args, enode * const * args); - void reset(); }; inline mk_pp pp(enode* n, ast_manager& m) { return mk_pp(n->get_expr(), m); } From 6246c6517d8743185d8e0b73b7e1a799351ba176 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 20 Dec 2023 18:30:53 +0000 Subject: [PATCH 038/224] fix debug build --- src/smt/smt_enode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/smt/smt_enode.cpp b/src/smt/smt_enode.cpp index 4bcb4a41c..8fbf43d60 100644 --- a/src/smt/smt_enode.cpp +++ b/src/smt/smt_enode.cpp @@ -329,7 +329,6 @@ namespace smt { tmp_enode::tmp_enode(): m_capacity(0), m_enode_data(nullptr) { - SASSERT(m_app.get_app()->get_decl() == 0); set_capacity(5); } From c4fa719751bf867fb9ad61bb60d94eac11e13291 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Wed, 20 Dec 2023 19:10:05 +0000 Subject: [PATCH 039/224] revert last two commits; MSVC doesn't like to statically allocate flexible arrays --- src/ast/ast.h | 4 ---- src/smt/smt_enode.cpp | 9 ++++++--- src/smt/smt_enode.h | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index a42d894ae..9618c7e12 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -707,8 +707,6 @@ struct app_flags { app_flags() : m_depth(1), m_ground(1), m_has_quantifiers(0), m_has_labels(0) {} }; -namespace smt { class tmp_enode; } - class app : public expr { friend class ast_manager; @@ -722,10 +720,8 @@ class app : public expr { } friend class tmp_app; - friend class smt::tmp_enode; app(func_decl * decl, unsigned num_args, expr * const * args); - app() : expr(AST_APP) {} public: func_decl * get_decl() const { return m_decl; } family_id get_family_id() const { return get_decl()->get_family_id(); } diff --git a/src/smt/smt_enode.cpp b/src/smt/smt_enode.cpp index 8fbf43d60..e26ac1aa3 100644 --- a/src/smt/smt_enode.cpp +++ b/src/smt/smt_enode.cpp @@ -327,8 +327,10 @@ namespace smt { } tmp_enode::tmp_enode(): + m_app(0), m_capacity(0), m_enode_data(nullptr) { + SASSERT(m_app.get_app()->get_decl() == 0); set_capacity(5); } @@ -344,7 +346,7 @@ namespace smt { m_enode_data = alloc_svect(char, sz); memset(m_enode_data, 0, sz); enode * n = get_enode(); - n->m_owner = &m_app; + n->m_owner = m_app.get_app(); n->m_root = n; n->m_next = n; n->m_class_size = 1; @@ -356,11 +358,12 @@ namespace smt { if (num_args > m_capacity) set_capacity(num_args * 2); enode * r = get_enode(); - m_app.m_decl = f; - m_app.m_num_args = num_args; + m_app.set_decl(f); + m_app.set_num_args(num_args); r->m_commutative = num_args == 2 && f->is_commutative(); memcpy(get_enode()->m_args, args, sizeof(enode*)*num_args); return r; } }; + diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index 7229dab29..c07576f38 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -456,7 +456,7 @@ namespace smt { void unmark_enodes2(unsigned num_enodes, enode * const * enodes); class tmp_enode { - app m_app; + tmp_app m_app; unsigned m_capacity; char * m_enode_data; enode * get_enode() { return reinterpret_cast(m_enode_data); } From 4317d134bfc82e3326b34d519b8a5eb0359c17e4 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 20 Dec 2023 12:56:20 -1000 Subject: [PATCH 040/224] refactor: move gomory functionaly from int_solver to gomory --- src/math/lp/gomory.cpp | 189 +++++++++++++++++++++++++++++++++---- src/math/lp/gomory.h | 7 +- src/math/lp/int_solver.cpp | 163 +------------------------------- src/math/lp/int_solver.h | 5 +- 4 files changed, 180 insertions(+), 184 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 26686b206..94435e27e 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -401,24 +401,177 @@ public: m_f(fractional_part(get_value(basic_inf_int_j).x)), m_one_minus_f(1 - m_f) {} -}; + }; -lia_move gomory::cut(lar_term & t, mpq & k, explanation* ex, unsigned basic_inf_int_j, const row_strip& row) { - create_cut cc(t, k, ex, basic_inf_int_j, row, lia); - return cc.cut(); -} + lia_move gomory::cut(lar_term & t, mpq & k, explanation* ex, unsigned basic_inf_int_j, const row_strip& row) { + create_cut cc(t, k, ex, basic_inf_int_j, row, lia); + return cc.cut(); + } -lia_move gomory::get_cut(lpvar j) { - unsigned r = lia.row_of_basic_column(j); - const row_strip& row = lra.get_row(r); - SASSERT(lra.row_is_correct(r)); - SASSERT(lia.is_gomory_cut_target(j)); - lia.m_upper = false; - lia.m_cut_vars.push_back(j); - return cut(lia.m_t, lia.m_k, lia.m_ex, j, row); -} - - -gomory::gomory(int_solver& lia): lia(lia), lra(lia.lra) { } - + bool gomory::is_gomory_cut_target(lpvar k) { + SASSERT(lia.is_base(k)); + // All non base variables must be at their bounds and assigned to rationals (that is, infinitesimals are not allowed). + const row_strip& row = lra.get_row(lia.row_of_basic_column(k)); + unsigned j; + for (const auto & p : row) { + j = p.var(); + if ( k != j && (!lia.at_bound(j) || lia.get_value(j).y != 0)) { + TRACE("gomory_cut", tout << "row is not gomory cut target:\n"; + lia.display_column(tout, j); + tout << "infinitesimal: " << !(lia.get_value(j).y ==0) << "\n";); + return false; + } + } + return true; + } + + + lia_move gomory::get_cut(lpvar j) { + unsigned r = lia.row_of_basic_column(j); + const row_strip& row = lra.get_row(r); + SASSERT(lra.row_is_correct(r)); + SASSERT(is_gomory_cut_target(j)); + lia.m_upper = false; + return cut(lia.m_t, lia.m_k, lia.m_ex, j, row); + } + + // return the minimal distance from the variable value to an integer + mpq get_gomory_score(const int_solver& lia, lpvar j) { + const mpq& val = lia.get_value(j).x; + auto l = val - floor(val); + if (l <= mpq(1, 2)) + return l; + return mpq(1) - l; + } + + unsigned_vector gomory::gomory_select_int_infeasible_vars(unsigned num_cuts) { + std::list sorted_vars; + std::unordered_map score; + for (lpvar j : lra.r_basis()) { + if (!lia.column_is_int_inf(j) || !is_gomory_cut_target(j)) + continue; + SASSERT(!lia.is_fixed(j)); + sorted_vars.push_back(j); + score[j] = get_gomory_score(lia, j); + } + // prefer the variables with the values close to integers + sorted_vars.sort([&](lpvar j, lpvar k) { + auto diff = score[j] - score[k]; + if (diff.is_neg()) + return true; + if (diff.is_pos()) + return false; + return lra.usage_in_terms(j) > lra.usage_in_terms(k); + }); + unsigned_vector ret; + unsigned n = static_cast(sorted_vars.size()); + + while (num_cuts-- && n > 0) { + unsigned k = lia.random() % n; + + double k_ratio = k / (double) n; + k_ratio *= k_ratio*k_ratio; // square k_ratio to make it smaller + k = static_cast(std::floor(k_ratio * n)); + // these operations move k to the beginning of the indices range + SASSERT(0 <= k && k < n); + auto it = sorted_vars.begin(); + while(k--) it++; + + ret.push_back(*it); + sorted_vars.erase(it); + n--; + } + return ret; + } + + + lia_move gomory::get_gomory_cuts(unsigned num_cuts) { + struct ex { explanation m_ex; lar_term m_term; mpq m_k; bool m_is_upper; }; + unsigned_vector columns_for_cuts = gomory_select_int_infeasible_vars(num_cuts); + + vector cuts; + + for (unsigned j : columns_for_cuts) { + lia.m_ex->clear(); + lia.m_t.clear(); + lia.m_k.reset(); + auto r = get_cut(j); + if (r != lia_move::cut) + continue; + cuts.push_back({ *lia.m_ex, lia.m_t, lia.m_k, lia.is_upper() }); + if (lia.settings().get_cancel_flag()) + return lia_move::undef; + } + + auto is_small_cut = [&](ex const& cut) { + return all_of(cut.m_term, [&](auto ci) { return ci.coeff().is_small(); }); + }; + + auto add_cut = [&](ex const& cut) { + u_dependency* dep = nullptr; + for (auto c : cut.m_ex) + dep = lra.join_deps(lra.dep_manager().mk_leaf(c.ci()), dep); + lp::lpvar term_index = lra.add_term(cut.m_term.coeffs_as_vector(), UINT_MAX); + term_index = lra.map_term_index_to_column_index(term_index); + lra.update_column_type_and_bound(term_index, + cut.m_is_upper ? lp::lconstraint_kind::LE : lp::lconstraint_kind::GE, + cut.m_k, dep); + }; + + auto _check_feasible = [&](void) { + lra.find_feasible_solution(); + if (!lra.is_feasible() && !lia.settings().get_cancel_flag()) { + lra.get_infeasibility_explanation(*lia.m_ex); + return false; + } + return true; + }; + + bool has_small = false, has_large = false; + + for (auto const& cut : cuts) { + if (!is_small_cut(cut)) { + has_large = true; + continue; + } + has_small = true; + add_cut(cut); + } + + if (has_large) { + lra.push(); + + for (auto const& cut : cuts) + if (!is_small_cut(cut)) + add_cut(cut); + + bool feas = _check_feasible(); + lra.pop(1); + + if (lia.settings().get_cancel_flag()) + return lia_move::undef; + + if (!feas) + return lia_move::conflict; + } + + if (!_check_feasible()) + return lia_move::conflict; + + + lia.m_ex->clear(); + lia.m_t.clear(); + lia.m_k.reset(); + if (!lia.has_inf_int()) + return lia_move::sat; + + if (has_small || has_large) + return lia_move::continue_with_check; + + lra.move_non_basic_columns_to_bounds(); + return lia_move::undef; + } + + + gomory::gomory(int_solver& lia): lia(lia), lra(lia.lra) { } } diff --git a/src/math/lp/gomory.h b/src/math/lp/gomory.h index cdb21a0c3..845f051fa 100644 --- a/src/math/lp/gomory.h +++ b/src/math/lp/gomory.h @@ -28,8 +28,11 @@ namespace lp { class int_solver& lia; class lar_solver& lra; lia_move cut(lar_term & t, mpq & k, explanation* ex, unsigned basic_inf_int_j, const row_strip& row); - public: - gomory(int_solver& lia); + unsigned_vector gomory_select_int_infeasible_vars(unsigned num_cuts); + bool is_gomory_cut_target(lpvar j); lia_move get_cut(lpvar j); + public: + lia_move gomory::get_gomory_cuts(unsigned num_cuts); + gomory(int_solver& lia); }; } diff --git a/src/math/lp/int_solver.cpp b/src/math/lp/int_solver.cpp index cfd94443b..3a2a195dc 100644 --- a/src/math/lp/int_solver.cpp +++ b/src/math/lp/int_solver.cpp @@ -198,8 +198,7 @@ namespace lp { if (r == lia_move::undef) lra.move_non_basic_columns_to_bounds(); if (r == lia_move::undef && should_hnf_cut()) r = hnf_cut(); - std::function gomory_fn = [&](lpvar j) { return gomory(*this).get_cut(j); }; - if (r == lia_move::undef && should_gomory_cut()) r = local_cut(2, gomory_fn); + if (r == lia_move::undef && should_gomory_cut()) r = gomory(*this).get_gomory_cuts(2); if (r == lia_move::undef) r = int_branch(*this)(); if (settings().get_cancel_flag()) r = lia_move::undef; @@ -692,7 +691,6 @@ namespace lp { } void int_solver::simplify(std::function& is_root) { - return; #if 0 @@ -829,162 +827,7 @@ namespace lp { #endif } - // return the minimal distance from the column value to an integer - mpq get_gomory_score(const int_solver& lia, lpvar j) { - const mpq& val = lia.get_value(j).x; - auto l = val - floor(val); - if (l <= mpq(1, 2)) - return l; - return mpq(1) - l; - } - - unsigned_vector int_solver::gomory_select_int_infeasible_vars(unsigned num_cuts) { - SASSERT(m_cut_vars.size() == 0&& num_cuts >= 0); - - std::list sorted_vars; - std::unordered_map score; - for (lpvar j : lra.r_basis()) { - if (!column_is_int_inf(j) || !is_gomory_cut_target(j)) - continue; - SASSERT(!is_fixed(j)); - sorted_vars.push_back(j); - score[j] = get_gomory_score(*this, j); - } - // prefer the columns with the values close to integers - sorted_vars.sort([&](lpvar j, lpvar k) { - auto diff = score[j] - score[k]; - if (diff.is_neg()) - return true; - if (diff.is_pos()) - return false; - return lra.usage_in_terms(j) > lra.usage_in_terms(k); - }); - unsigned_vector ret; - unsigned n = static_cast(sorted_vars.size()); - - while (num_cuts-- && n > 0) { - unsigned k = random() % n; - - double k_ratio = k / (double) n; - k_ratio *= k_ratio*k_ratio; // square k_ratio to make it smaller - k = static_cast(std::floor(k_ratio * n)); - // these operations move k to the beginning of the indices range - SASSERT(0 <= k && k < n); - auto it = sorted_vars.begin(); - while(k--) it++; - - ret.push_back(*it); - sorted_vars.erase(it); - n--; - } - return ret; - } - lia_move int_solver::local_cut(unsigned num_cuts, std::function& cut_fn) { - - struct ex { explanation m_ex; lar_term m_term; mpq m_k; bool m_is_upper; }; - unsigned_vector columns_for_cuts = gomory_select_int_infeasible_vars(num_cuts); - - vector cuts; - - for (unsigned j : columns_for_cuts) { - m_ex->clear(); - m_t.clear(); - m_k.reset(); - auto r = cut_fn(j); - if (r != lia_move::cut) - continue; - cuts.push_back({ *m_ex, m_t, m_k, is_upper() }); - if (settings().get_cancel_flag()) - return lia_move::undef; - } - m_cut_vars.reset(); - - auto is_small_cut = [&](ex const& cut) { - return all_of(cut.m_term, [&](auto ci) { return ci.coeff().is_small(); }); - }; - - auto add_cut = [&](ex const& cut) { - u_dependency* dep = nullptr; - for (auto c : cut.m_ex) - dep = lra.join_deps(lra.dep_manager().mk_leaf(c.ci()), dep); - lp::lpvar term_index = lra.add_term(cut.m_term.coeffs_as_vector(), UINT_MAX); - term_index = lra.map_term_index_to_column_index(term_index); - lra.update_column_type_and_bound(term_index, - cut.m_is_upper ? lp::lconstraint_kind::LE : lp::lconstraint_kind::GE, - cut.m_k, dep); - }; - - auto _check_feasible = [&](void) { - lra.find_feasible_solution(); - if (!lra.is_feasible() && !settings().get_cancel_flag()) { - lra.get_infeasibility_explanation(*m_ex); - return false; - } - return true; - }; - - bool has_small = false, has_large = false; - - for (auto const& cut : cuts) { - if (!is_small_cut(cut)) { - has_large = true; - continue; - } - has_small = true; - add_cut(cut); - } - - if (has_large) { - lra.push(); - - for (auto const& cut : cuts) - if (!is_small_cut(cut)) - add_cut(cut); - - bool feas = _check_feasible(); - lra.pop(1); - - if (settings().get_cancel_flag()) - return lia_move::undef; - - if (!feas) - return lia_move::conflict; - } - - if (!_check_feasible()) - return lia_move::conflict; - - - m_ex->clear(); - m_t.clear(); - m_k.reset(); - if (!has_inf_int()) - return lia_move::sat; - - if (has_small || has_large) - return lia_move::continue_with_check; - - lra.move_non_basic_columns_to_bounds(); - return lia_move::undef; - } - - bool int_solver::is_gomory_cut_target(lpvar k) { - SASSERT(is_base(k)); - // All non base variables must be at their bounds and assigned to rationals (that is, infinitesimals are not allowed). - const row_strip& row = lra.get_row(row_of_basic_column(k)); - unsigned j; - for (const auto & p : row) { - j = p.var(); - if ( k != j && (!at_bound(j) || !is_zero(get_value(j).y))) { - TRACE("gomory_cut", tout << "row is not gomory cut target:\n"; - display_column(tout, j); - tout << "infinitesimal: " << !is_zero(get_value(j).y) << "\n";); - return false; - } - } - return true; - } - - + + } diff --git a/src/math/lp/int_solver.h b/src/math/lp/int_solver.h index feeb96986..8a2a157e3 100644 --- a/src/math/lp/int_solver.h +++ b/src/math/lp/int_solver.h @@ -111,7 +111,6 @@ private: bool has_upper(unsigned j) const; unsigned row_of_basic_column(unsigned j) const; bool cut_indices_are_columns() const; - lia_move local_cut(unsigned num_cuts, std::function& cut_fn); public: std::ostream& display_column(std::ostream & out, unsigned j) const; @@ -129,11 +128,9 @@ private: public: bool is_term(unsigned j) const; unsigned column_count() const; - bool all_columns_are_bounded() const; lia_move hnf_cut(); int select_int_infeasible_var(); - unsigned_vector gomory_select_int_infeasible_vars(unsigned num_cuts); - bool is_gomory_cut_target(lpvar); + }; } From e9fa7db96cc927d92dfc58ac26a79a717e9288f8 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 20 Dec 2023 14:03:27 -1000 Subject: [PATCH 041/224] revert smt_enode Signed-off-by: Lev Nachmanson --- src/smt/smt_enode.cpp | 10 +++++++++- src/smt/smt_enode.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_enode.cpp b/src/smt/smt_enode.cpp index e26ac1aa3..86b83af4c 100644 --- a/src/smt/smt_enode.cpp +++ b/src/smt/smt_enode.cpp @@ -340,7 +340,8 @@ namespace smt { void tmp_enode::set_capacity(unsigned new_capacity) { SASSERT(new_capacity > m_capacity); - dealloc_svect(m_enode_data); + if (m_enode_data) + dealloc_svect(m_enode_data); m_capacity = new_capacity; unsigned sz = sizeof(enode) + m_capacity * sizeof(enode*); m_enode_data = alloc_svect(char, sz); @@ -358,6 +359,9 @@ namespace smt { if (num_args > m_capacity) set_capacity(num_args * 2); enode * r = get_enode(); + if (m_app.get_app()->get_decl() != f) { + r->m_func_decl_id = UINT_MAX; + } m_app.set_decl(f); m_app.set_num_args(num_args); r->m_commutative = num_args == 2 && f->is_commutative(); @@ -365,5 +369,9 @@ namespace smt { return r; } + void tmp_enode::reset() { + get_enode()->m_func_decl_id = UINT_MAX; + } + }; diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index c07576f38..92902ea0b 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -465,6 +465,7 @@ namespace smt { tmp_enode(); ~tmp_enode(); enode * set(func_decl * f, unsigned num_args, enode * const * args); + void reset(); }; inline mk_pp pp(enode* n, ast_manager& m) { return mk_pp(n->get_expr(), m); } From 19f3ad46ce0d41a55c3119c9ed4e70ea79f972d3 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 20 Dec 2023 14:14:01 -1000 Subject: [PATCH 042/224] fix the build --- src/math/lp/gomory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/lp/gomory.h b/src/math/lp/gomory.h index 845f051fa..2586a4d31 100644 --- a/src/math/lp/gomory.h +++ b/src/math/lp/gomory.h @@ -32,7 +32,7 @@ namespace lp { bool is_gomory_cut_target(lpvar j); lia_move get_cut(lpvar j); public: - lia_move gomory::get_gomory_cuts(unsigned num_cuts); + lia_move get_gomory_cuts(unsigned num_cuts); gomory(int_solver& lia); }; } From 68a2c08d5eeb1ef406acd810c62c559339b65f12 Mon Sep 17 00:00:00 2001 From: "Christoph M. Wintersteiger" Date: Thu, 21 Dec 2023 20:54:30 +0000 Subject: [PATCH 043/224] Add Z3_get_estimated_alloc_size to OCaml API (#7068) --- examples/ml/ml_example.ml | 1 + src/api/ml/z3.ml | 3 +++ src/api/ml/z3.mli | 3 +++ 3 files changed, 7 insertions(+) diff --git a/examples/ml/ml_example.ml b/examples/ml/ml_example.ml index e2c7734ff..318c805e8 100644 --- a/examples/ml/ml_example.ml +++ b/examples/ml/ml_example.ml @@ -308,6 +308,7 @@ let fpa_example ( ctx : context ) = ( let solver = (mk_solver ctx None) in (Solver.add solver [ c5 ]) ; + Printf.printf "Memory in use before `check`: %Lu bytes\n" (Statistics.get_estimated_alloc_size()); if (check solver []) != SATISFIABLE then raise (TestFailedException "") else diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 5bd554313..166e474d9 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1832,6 +1832,9 @@ struct let get (x:statistics) (key:string) = try Some(List.find (fun c -> Entry.get_key c = key) (get_entries x)) with | Not_found -> None + + let get_estimated_alloc_size = + Z3native.get_estimated_alloc_size end diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index bb3e70875..5320fc38e 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -3224,6 +3224,9 @@ sig (** The value of a particular statistical counter. *) val get : statistics -> string -> Entry.statistics_entry option + + (** The estimated allocated memory in bytes. *) + val get_estimated_alloc_size : unit -> int64 end (** Solvers *) From b09c23777549529e6f5d89f001e1ff40ce6dc197 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Dec 2023 15:18:17 -0800 Subject: [PATCH 044/224] rudimentary bin cover solver using the user propagator Signed-off-by: Nikolaj Bjorner --- examples/python/bincover.py | 286 ++++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 examples/python/bincover.py diff --git a/examples/python/bincover.py b/examples/python/bincover.py new file mode 100644 index 000000000..f11766d96 --- /dev/null +++ b/examples/python/bincover.py @@ -0,0 +1,286 @@ +from z3 import * +import math + +# Rudimentary bin cover solver using the UserPropagator feature. +# It supports the most basic propagation for bin covering. +# - each bin has a propositional variable set to true if the bin is covered +# - each item has a bit-vector recording the assigned bin +# It searches for a locally optimal solution. + +class Bin: + """ + Each bin carries values: + - min_bound - the lower bound required to be added to bin + - weight - the sum of weight of items currently added to bin + - slack - the difference between the maximal possible assignment and the assignments to other bin2bound. + - var - is propagated to true/false if the bin gets filled/cannot be filled. + """ + def __init__(self, min_bound, index): + assert min_bound > 0 + assert index >= 0 + self.index = index + self.min_bound = min_bound + self.weight = 0 + self.slack = 0 + self.added = [] + self.var = Bool(f"bin-{index}") + + def set_slack(self, slack): + self.slack = slack + + def set_fill(self, fill): + self.weight = fill + + def __repr__(self): + return f"{self.var}:bound-{self.min_bound}" + + +class Item: + def __init__(self, weight, index): + self.weight = weight + self.index = index + self.var = None + + def set_var(self, num_bits): + self.var = BitVec(f"binof-{self.index}", num_bits) + + def __repr__(self): + return f"binof-{self.index}:weight-{self.weight}" + + +class BinCoverSolver(UserPropagateBase): + """Represent a bin-covering problem by associating each bin with a variable + For each item i associate a bit-vector + - bin-of-i that carries the bin identifier where an item is assigned. + + """ + + def __init__(self, s=None, ctx=None): + UserPropagateBase.__init__(self, s, ctx) + self.bins = [] + self.items = [] + self.item2index = {} + self.trail = [] # Undo stack + self.lim = [] + self.solver = s + self.initialized = False + self.add_fixed(lambda x, v : self._fixed(x, v)) + + + # Initialize bit-vector variables for items. + # Register the bit-vector variables with the user propagator to get callbacks + # Ensure the bit-vector variables are assigned to a valid bin. + # Initialize the slack of each bin. + def init(self): + print(self.bins, len(self.bins)) + print(self.items) + assert not self.initialized + self.initialized = True + powerof2, num_bits = self._num_bits() + for item in self.items: + item.set_var(num_bits) + self.item2index[item.var.get_id()] = item.index + self.add(item.var) + if not powerof2: + bound = BitVecVal(len(self.bins), num_bits) + ineq = ULT(item.var, bound) + self.solver.add(ineq) + total_weight = sum(item.weight for item in self.items) + for i in range(len(self.bins)): + self.bins[i].slack = total_weight + + def add_bin(self, min_bound): + assert not self.initialized + index = len(self.bins) + self.bins += [Bin(min_bound, index)] + return index + + def add_item(self, weight): + assert not self.initialized + assert weight > 0 + index = len(self.items) + self.items += [Item(weight, index)] + return index + + def num_items(self): + return len(self.items) + + def num_bins(self): + return len(self.bins) + + def _num_bits(self): + log = math.log2(self.num_bins()) + if log.is_integer(): + return True, int(log) + else: + return False, int(log) + 1 + + def _set_slack(self, bin, slack_value): + bin.slack = slack_value + + def _set_fill(self, bin, fill_value): + bin.weight = fill_value + bin.added.pop() + + def _itemvar2item(self, v): + index = self.item2index[v.get_id()] + if index >= len(self.items): + return None + return self.items[index] + + def _value2bin(self, value): + assert isinstance(value, BitVecNumRef) + bin_index = value.as_long() + if bin_index >= len(self.bins): + return NOne + return self.bins[bin_index] + + def _add_item2bin(self, item, bin): + # print("add", item, "to", bin) + old_weight = bin.weight + bin.weight += item.weight + bin.added += [item] + self.trail += [lambda : self._set_fill(bin, old_weight)] + if old_weight < bin.min_bound and old_weight + item.weight >= bin.min_bound: + self._propagate_filled(bin) + + # This item can never go into bin + def _exclude_item2bin(self, item, bin): + # print("exclude", item, "from", bin) + # Check if bin has already been blocked + if bin.slack < bin.weight: + return + if bin.weight >= bin.min_bound: + return + old_slack = bin.slack + new_slack = old_slack - item.weight + bin.slack = new_slack + self.trail += [lambda : self._set_slack(bin, old_slack)] + # If the new slack does not permit the bin to be filled, propagate + if new_slack < bin.min_bound: + self._propagate_slack(bin) + + + # Callback from Z3 when an item gets fixed. + def _fixed(self, _item, value): + item = self._itemvar2item(_item) + if item is None: + print("no item for ", _item) + return + bin = self._value2bin(value) + if bin is None: + print("no bin for ", value) + return + self._add_item2bin(item, bin) + for idx in range(len(self.bins)): + if idx == bin.index: + continue + other_bin = self.bins[idx] + self._exclude_item2bin(item, other_bin) + + def _propagate_filled(self, bin): + """Propagate that bin_index is filled justified by the set of + items that have been added + """ + justification = [i.var for i in bin.added] + self.propagate(bin.var, justification) + + def _propagate_slack(self, bin): + """Propagate that bin_index cannot be filled""" + justification = [] + for other_bin in self.bins: + if other_bin.index == bin.index: + continue + justification += other_bin.added + justification = [item.var for item in justification] + self.propagate(Not(bin.var), justification) + + def push(self): + self.lim += [len(self.trail)] + + def pop(self, n): + head = self.lim[len(self.lim) - n] + while len(self.trail) > head: + self.trail[-1]() + self.trail.pop(-1) + self.lim = self.lim[0:len(self.lim)-n] + +# Find a first maximally satisfying subset +class MaximalSatisfyingSubset: + def __init__(self, s): + self.s = s + self.model = None + + def tt(self, f): + return is_true(self.model.eval(f)) + + def get_mss(self, ps): + s = self.s + if sat != s.check(): + return [] + self.model = s.model() + mss = { q for q in ps if self.tt(q) } + return self._get_mss(mss, ps) + + def _get_mss(self, mss, ps): + ps = set(ps) - mss + backbones = set([]) + s = self.s + while len(ps) > 0: + p = ps.pop() + if sat == s.check(mss | backbones | { p }): + self.model = s.model() + mss = mss | { p } | { q for q in ps if self.tt(q) } + ps = ps - mss + else: + backbones = backbones | { Not(p) } + return mss + + +class OptimizeBinCoverSolver: + def __init__(self): + self.solver = Solver() + self.bin_solver = BinCoverSolver(self.solver) + self.mss_solver = MaximalSatisfyingSubset(self.solver) + + # Facilities to set up solver + def init(self): + self.bin_solver.init() + + def add_item(self, weight): + return self.bin_solver.add_item(weight) + + def add_bin(self, min_bound): + return self.bin_solver.add_bin(min_bound) + + def item_index2item(self, index): + return self.bin_solver.items[index] + + def bin_index2bin(self, index): + return self.bin_solver.bins[index] + + def optimize(self): + self.init() + mss = self.mss_solver.get_mss([bin.var for bin in self.bin_solver.bins]) + print(self.mss_solver.model) + print("filled bins", mss) + print("bin contents") + for bin in self.bin_solver.bins: + print(bin, bin.added) + + + +def example1(): + s = OptimizeBinCoverSolver() + i1 = s.add_item(2) + i2 = s.add_item(4) + i3 = s.add_item(5) + i4 = s.add_item(2) + b1 = s.add_bin(3) + b2 = s.add_bin(6) + b3 = s.add_bin(1) + s.optimize() + +example1() + + From ae1d9270b55e6e35d132c9f1cb9c43541da60fe3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Dec 2023 15:27:11 -0800 Subject: [PATCH 045/224] improve add bin/item functions Signed-off-by: Nikolaj Bjorner --- examples/python/bincover.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/examples/python/bincover.py b/examples/python/bincover.py index f11766d96..db7400bbd 100644 --- a/examples/python/bincover.py +++ b/examples/python/bincover.py @@ -92,15 +92,17 @@ class BinCoverSolver(UserPropagateBase): def add_bin(self, min_bound): assert not self.initialized index = len(self.bins) - self.bins += [Bin(min_bound, index)] - return index + bin = Bin(min_bound, index) + self.bins += [bin] + return bin def add_item(self, weight): assert not self.initialized assert weight > 0 index = len(self.items) - self.items += [Item(weight, index)] - return index + item = Item(weight, index) + self.items += [item] + return item def num_items(self): return len(self.items) @@ -243,7 +245,13 @@ class OptimizeBinCoverSolver: self.bin_solver = BinCoverSolver(self.solver) self.mss_solver = MaximalSatisfyingSubset(self.solver) + # # Facilities to set up solver + # First add items and bins. + # Keep references to the returned objects. + # Then call init + # Then add any other custom constraints to the "solver" object. + # def init(self): self.bin_solver.init() @@ -253,12 +261,6 @@ class OptimizeBinCoverSolver: def add_bin(self, min_bound): return self.bin_solver.add_bin(min_bound) - def item_index2item(self, index): - return self.bin_solver.items[index] - - def bin_index2bin(self, index): - return self.bin_solver.bins[index] - def optimize(self): self.init() mss = self.mss_solver.get_mss([bin.var for bin in self.bin_solver.bins]) From 766f5f04c0d86cf6fb1ed1ef2da07eab3487a797 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Thu, 21 Dec 2023 23:27:09 +0000 Subject: [PATCH 046/224] reduce memory allocs in params --- src/util/params.cpp | 30 +++++++++++++----------------- src/util/params.h | 4 ++-- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/util/params.cpp b/src/util/params.cpp index d89026152..700a53109 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -99,25 +99,24 @@ struct param_descrs::imp { return CPK_INVALID; } - bool split_name(symbol const& name, symbol & prefix, symbol & suffix) const { + bool split_name(symbol const& name, std::string_view & prefix, symbol & suffix) const { if (name.is_numerical()) return false; char const* str = name.bare_str(); char const* period = strchr(str,'.'); if (!period) return false; - svector prefix_((unsigned)(period-str), str); - prefix_.push_back(0); - prefix = symbol(prefix_.data()); + prefix = std::string_view(str, period - str); suffix = symbol(period + 1); return true; } param_kind get_kind_in_module(symbol & name) const { param_kind k = get_kind(name); - symbol prefix, suffix; + std::string_view prefix; + symbol suffix; if (k == CPK_INVALID && split_name(name, prefix, suffix)) { k = get_kind(suffix); if (k != CPK_INVALID) { - if (symbol(get_module(suffix)) == prefix) { + if (get_module(suffix) == prefix) { name = suffix; } else { @@ -170,8 +169,8 @@ struct param_descrs::imp { if (names.empty()) return; if (markdown) { - out << " Parameter | Type | Description | Default\n"; - out << " ----------|------|-------------|--------\n"; + out << " Parameter | Type | Description | Default\n" + " ----------|------|-------------|--------\n"; } for (symbol const& name : names) { for (unsigned i = 0; i < indent; i++) out << " "; @@ -197,16 +196,14 @@ struct param_descrs::imp { else out << " (" << d.m_kind << ")"; if (markdown) { - out << " | "; - std::string desc; - for (auto ch : std::string(d.m_descr)) { + out << " | "; + for (auto ch : std::string_view(d.m_descr)) { switch (ch) { - case '<': desc += "<"; break; - case '>': desc += ">"; break; - default: desc.push_back(ch); + case '<': out << "<"; break; + case '>': out << ">"; break; + default: out << ch; break; } } - out << " " << desc; } else if (include_descr) out << " " << d.m_descr; @@ -549,8 +546,7 @@ params_ref::~params_ref() { m_params->dec_ref(); } -params_ref::params_ref(params_ref const & p): - m_params(nullptr) { +params_ref::params_ref(params_ref const & p) { set(p); } diff --git a/src/util/params.h b/src/util/params.h index bc45bdbce..200b4aa2c 100644 --- a/src/util/params.h +++ b/src/util/params.h @@ -32,12 +32,12 @@ class param_descrs; class params_ref { static params_ref g_empty_params_ref; - params * m_params; + params * m_params = nullptr; void init(); void copy_core(params const * p); void set(params_ref const& p); public: - params_ref():m_params(nullptr) {} + params_ref() = default; params_ref(params_ref const & p); ~params_ref(); From 4fe423482a1644ea54965768ce332cbb4c20a21c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 21 Dec 2023 15:36:20 -0800 Subject: [PATCH 047/224] bugfix on slack Signed-off-by: Nikolaj Bjorner --- examples/python/bincover.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/python/bincover.py b/examples/python/bincover.py index db7400bbd..d6097af5e 100644 --- a/examples/python/bincover.py +++ b/examples/python/bincover.py @@ -150,7 +150,7 @@ class BinCoverSolver(UserPropagateBase): def _exclude_item2bin(self, item, bin): # print("exclude", item, "from", bin) # Check if bin has already been blocked - if bin.slack < bin.weight: + if bin.slack < bin.min_bound: return if bin.weight >= bin.min_bound: return From ab22e763d72a94937c7b56a3b986444b860c160a Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 22 Dec 2023 15:27:57 +0000 Subject: [PATCH 048/224] some code simplifications in mpn plus remove duplicated assertion --- src/util/mpn.cpp | 37 ++++++++++++------------------------- src/util/mpn.h | 1 - 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/util/mpn.cpp b/src/util/mpn.cpp index bc9017726..e84c15d5e 100644 --- a/src/util/mpn.cpp +++ b/src/util/mpn.cpp @@ -21,24 +21,20 @@ Revision History: #include "util/buffer.h" #include "util/mpn.h" -#define max(a,b) (((a) > (b)) ? (a) : (b)) - typedef uint64_t mpn_double_digit; static_assert(sizeof(mpn_double_digit) == 2 * sizeof(mpn_digit), "size alignment"); -const mpn_digit mpn_manager::zero = 0; - int mpn_manager::compare(mpn_digit const * a, unsigned lnga, mpn_digit const * b, unsigned lngb) const { int res = 0; trace(a, lnga); - unsigned j = max(lnga, lngb); + unsigned j = std::max(lnga, lngb); for (; j-- > 0 && res == 0;) { - mpn_digit const & u_j = (j < lnga) ? a[j] : zero; - mpn_digit const & v_j = (j < lngb) ? b[j] : zero; - if (u_j > v_j) + mpn_digit u_j = (j < lnga) ? a[j] : 0; + mpn_digit v_j = (j < lngb) ? b[j] : 0; + if (u_j > v_j) res = 1; else if (u_j < v_j) res = -1; @@ -56,14 +52,14 @@ bool mpn_manager::add(mpn_digit const * a, unsigned lnga, unsigned * plngc) const { trace(a, lnga, b, lngb, "+"); // Essentially Knuth's Algorithm A - unsigned len = max(lnga, lngb); + unsigned len = std::max(lnga, lngb); SASSERT(lngc_alloc == len+1 && len > 0); mpn_digit k = 0; mpn_digit r; bool c1, c2; for (unsigned j = 0; j < len; j++) { - mpn_digit const & u_j = (j < lnga) ? a[j] : zero; - mpn_digit const & v_j = (j < lngb) ? b[j] : zero; + mpn_digit u_j = (j < lnga) ? a[j] : 0; + mpn_digit v_j = (j < lngb) ? b[j] : 0; r = u_j + v_j; c1 = r < u_j; c[j] = r + k; c2 = c[j] < r; k = c1 | c2; @@ -81,13 +77,13 @@ bool mpn_manager::sub(mpn_digit const * a, unsigned lnga, mpn_digit * c, mpn_digit * pborrow) const { trace(a, lnga, b, lngb, "-"); // Essentially Knuth's Algorithm S - unsigned len = max(lnga, lngb); + unsigned len = std::max(lnga, lngb); mpn_digit & k = *pborrow; k = 0; mpn_digit r; bool c1, c2; for (unsigned j = 0; j < len; j++) { - mpn_digit const & u_j = (j < lnga) ? a[j] : zero; - mpn_digit const & v_j = (j < lngb) ? b[j] : zero; + mpn_digit u_j = (j < lnga) ? a[j] : 0; + mpn_digit v_j = (j < lngb) ? b[j] : 0; r = u_j - v_j; c1 = r > u_j; c[j] = r - k; c2 = c[j] > r; k = c1 | c2; @@ -112,14 +108,14 @@ bool mpn_manager::mul(mpn_digit const * a, unsigned lnga, c[i] = 0; for (unsigned j = 0; j < lngb; j++) { - mpn_digit const & v_j = b[j]; + mpn_digit v_j = b[j]; if (v_j == 0) { // This branch may be omitted according to Knuth. c[j+lnga] = 0; } else { k = 0; for (i = 0; i < lnga; i++) { - mpn_digit const & u_i = a[i]; + mpn_digit u_i = a[i]; mpn_double_digit t; t = ((mpn_double_digit)u_i * (mpn_double_digit)v_j) + (mpn_double_digit) c[i+j] + @@ -156,15 +152,6 @@ bool mpn_manager::div(mpn_digit const * numer, unsigned lnum, return false; } - bool all_zero = true; - for (unsigned i = 0; i < lden && all_zero; i++) - if (denom[i] != zero) all_zero = false; - - if (all_zero) { - UNREACHABLE(); - return res; - } - SASSERT(denom[lden-1] != 0); if (lnum == 1 && lden == 1) { diff --git a/src/util/mpn.h b/src/util/mpn.h index 7cf3eafb6..285edd091 100644 --- a/src/util/mpn.h +++ b/src/util/mpn.h @@ -53,7 +53,6 @@ public: private: using mpn_sbuffer = sbuffer; - static const mpn_digit zero; void display_raw(std::ostream & out, mpn_digit const * a, unsigned lng) const; unsigned div_normalize(mpn_digit const * numer, unsigned lnum, From cab3c45863d5e64a79b22a841d265dd4122cffe5 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 22 Dec 2023 16:11:06 +0000 Subject: [PATCH 049/224] remove unnecessary parameter copies --- src/ast/array_decl_plugin.cpp | 2 +- src/ast/ast.cpp | 10 +--------- src/ast/ast.h | 9 ++++++--- src/ast/ast_lt.cpp | 8 ++++---- src/ast/bv_decl_plugin.cpp | 5 ++--- src/ast/fpa/bv2fpa_converter.cpp | 2 +- src/ast/fpa_decl_plugin.cpp | 3 +-- src/ast/polymorphism_util.cpp | 12 ++++++------ src/muz/spacer/spacer_proof_utils.cpp | 6 +----- 9 files changed, 23 insertions(+), 34 deletions(-) diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index f38894d06..bd9d954c7 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -49,7 +49,7 @@ sort * array_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, paramete m_manager->raise_exception("invalid array sort definition, invalid number of parameters"); return nullptr; } - parameter params[2] = { parameters[0], parameter(m_manager->mk_bool_sort()) }; + parameter params[2] = { parameter(parameters[0]), parameter(m_manager->mk_bool_sort()) }; return mk_sort(ARRAY_SORT, 2, params); } SASSERT(k == ARRAY_SORT); diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index f3be7d2c6..e1e3efe99 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -48,21 +48,13 @@ parameter::~parameter() { } } -parameter& parameter::operator=(parameter const& other) { - if (this == &other) { - return *this; - } - - this->~parameter(); - m_val = other.m_val; - +parameter::parameter(parameter const& other) : m_val(other.m_val) { if (auto p = std::get_if(&m_val)) { m_val = alloc(rational, **p); } if (auto p = std::get_if(&m_val)) { m_val = alloc(zstring, **p); } - return *this; } void parameter::init_eh(ast_manager & m) { diff --git a/src/ast/ast.h b/src/ast/ast.h index 9618c7e12..053390022 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -142,7 +142,7 @@ public: explicit parameter(const char *s): m_val(symbol(s)) {} explicit parameter(const std::string &s): m_val(symbol(s)) {} explicit parameter(unsigned ext_id, bool): m_val(ext_id) {} - parameter(parameter const& other) { *this = other; } + explicit parameter(parameter const& other); parameter(parameter && other) noexcept : m_val(std::move(other.m_val)) { other.m_val = 0; @@ -150,7 +150,10 @@ public: ~parameter(); - parameter& operator=(parameter const& other); + parameter& operator=(parameter && other) { + std::swap(other.m_val, m_val); + return *this; + } kind_t get_kind() const { return static_cast(m_val.index()); } bool is_int() const { return get_kind() == PARAM_INT; } @@ -1099,7 +1102,7 @@ public: // Event handlers for deleting/translating PARAM_EXTERNAL virtual void del(parameter const & p) {} - virtual parameter translate(parameter const & p, decl_plugin & target) { UNREACHABLE(); return p; } + virtual parameter translate(parameter const & p, decl_plugin & target) { UNREACHABLE(); return {}; } virtual bool is_considered_uninterpreted(func_decl * f) { return false; } }; diff --git a/src/ast/ast_lt.cpp b/src/ast/ast_lt.cpp index 3537dc71e..869c7bff8 100644 --- a/src/ast/ast_lt.cpp +++ b/src/ast/ast_lt.cpp @@ -68,8 +68,8 @@ bool lt(ast * n1, ast * n2) { num = to_sort(n1)->get_num_parameters(); SASSERT(num > 0); for (unsigned i = 0; i < num; i++) { - parameter p1 = to_sort(n1)->get_parameter(i); - parameter p2 = to_sort(n2)->get_parameter(i); + const parameter &p1 = to_sort(n1)->get_parameter(i); + const parameter &p2 = to_sort(n2)->get_parameter(i); check_parameter(p1, p2); } UNREACHABLE(); @@ -80,8 +80,8 @@ bool lt(ast * n1, ast * n2) { check_value(to_func_decl(n1)->get_num_parameters(), to_func_decl(n2)->get_num_parameters()); num = to_func_decl(n1)->get_num_parameters(); for (unsigned i = 0; i < num; i++) { - parameter p1 = to_func_decl(n1)->get_parameter(i); - parameter p2 = to_func_decl(n2)->get_parameter(i); + const parameter &p1 = to_func_decl(n1)->get_parameter(i); + const parameter &p2 = to_func_decl(n2)->get_parameter(i); check_parameter(p1, p2); } num = to_func_decl(n1)->get_arity(); diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 30cfe4cdb..6b2106f3f 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -454,9 +454,8 @@ func_decl * bv_decl_plugin::mk_num_decl(unsigned num_parameters, parameter const // This cannot be enforced now, since some Z3 modules try to generate these invalid numerals. // After SMT-COMP, I should find all offending modules. // For now, I will just simplify the numeral here. - rational v = parameters[0].get_rational(); - parameter p0(mod2k(v, bv_size)); - parameter ps[2] = { std::move(p0), parameters[1] }; + const rational &v = parameters[0].get_rational(); + parameter ps[2] = { parameter(mod2k(v, bv_size)), parameter(parameters[1]) }; sort * bv = get_bv_sort(bv_size); return m_manager->mk_const_decl(m_bv_sym, bv, func_decl_info(m_family_id, OP_BV_NUM, num_parameters, ps)); } diff --git a/src/ast/fpa/bv2fpa_converter.cpp b/src/ast/fpa/bv2fpa_converter.cpp index cc2abf01c..a3008851b 100644 --- a/src/ast/fpa/bv2fpa_converter.cpp +++ b/src/ast/fpa/bv2fpa_converter.cpp @@ -319,7 +319,7 @@ func_interp * bv2fpa_converter::convert_func_interp(model_core * mc, func_decl * if (m_fpa_util.is_to_sbv(f) || m_fpa_util.is_to_ubv(f)) { auto k = m_fpa_util.is_to_sbv(f) ? OP_FPA_TO_SBV_I : OP_FPA_TO_UBV_I; - parameter param = f->get_parameter(0); + const parameter ¶m = f->get_parameter(0); func_decl_ref to_bv_i(m.mk_func_decl(fid, k, 1, ¶m, dom.size(), dom.data()), m); expr_ref else_value(m.mk_app(to_bv_i, dom.size(), dom.data()), m); result->set_else(else_value); diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp index 78d300ca7..76e44278d 100644 --- a/src/ast/fpa_decl_plugin.cpp +++ b/src/ast/fpa_decl_plugin.cpp @@ -208,8 +208,7 @@ sort * fpa_decl_plugin::mk_float_sort(unsigned ebits, unsigned sbits) { if (ebits > 63) m_manager->raise_exception("maximum number of exponent bits is 63"); - parameter p1(ebits), p2(sbits); - parameter ps[2] = { p1, p2 }; + parameter ps[2] = { parameter(ebits), parameter(sbits) }; sort_size sz; sz = sort_size::mk_very_big(); // TODO: refine return m_manager->mk_sort(symbol("FloatingPoint"), sort_info(m_family_id, FLOATING_POINT_SORT, sz, 2, ps)); diff --git a/src/ast/polymorphism_util.cpp b/src/ast/polymorphism_util.cpp index 1c961d21f..3431dd034 100644 --- a/src/ast/polymorphism_util.cpp +++ b/src/ast/polymorphism_util.cpp @@ -40,7 +40,7 @@ namespace polymorphism { unsigned n = s->get_num_parameters(); vector ps; for (unsigned i = 0; i < n; ++i) { - auto p = s->get_parameter(i); + auto &p = s->get_parameter(i); if (p.is_ast() && is_sort(p.get_ast())) { sort_ref s = (*this)(to_sort(p.get_ast())); ps.push_back(parameter(s.get())); @@ -167,8 +167,8 @@ namespace polymorphism { if (s1->get_num_parameters() != s2->get_num_parameters()) return false; for (unsigned i = s1->get_num_parameters(); i-- > 0;) { - auto p1 = s1->get_parameter(i); - auto p2 = s2->get_parameter(i); + auto &p1 = s1->get_parameter(i); + auto &p2 = s2->get_parameter(i); if (p1.is_ast() && is_sort(p1.get_ast())) { if (!p2.is_ast()) return false; @@ -204,8 +204,8 @@ namespace polymorphism { if (s1->get_num_parameters() != s2->get_num_parameters()) return false; for (unsigned i = s1->get_num_parameters(); i-- > 0;) { - auto p1 = s1->get_parameter(i); - auto p2 = s2->get_parameter(i); + auto &p1 = s1->get_parameter(i); + auto &p2 = s2->get_parameter(i); if (p1.is_ast() && is_sort(p1.get_ast())) { if (!p2.is_ast()) return false; @@ -282,7 +282,7 @@ namespace polymorphism { } vector params; for (unsigned i = 0; i < s->get_num_parameters(); ++i) { - parameter p = s->get_parameter(i); + const parameter &p = s->get_parameter(i); if (p.is_ast() && is_sort(p.get_ast())) { sort_ref fs = fresh(to_sort(p.get_ast())); params.push_back(parameter(fs.get())); diff --git a/src/muz/spacer/spacer_proof_utils.cpp b/src/muz/spacer/spacer_proof_utils.cpp index 800a63291..9fbd4e01c 100644 --- a/src/muz/spacer/spacer_proof_utils.cpp +++ b/src/muz/spacer/spacer_proof_utils.cpp @@ -209,10 +209,6 @@ namespace spacer { static proof_ref mk_th_lemma(ast_manager &m, ptr_buffer const &parents, unsigned num_params, parameter const *params) { - buffer v; - for (unsigned i = 1; i < num_params; ++i) - v.push_back(params[i]); - SASSERT(params[0].is_symbol()); family_id tid = m.mk_family_id(params[0].get_symbol()); SASSERT(tid != null_family_id); @@ -220,7 +216,7 @@ namespace spacer { proof_ref pf(m); pf = m.mk_th_lemma(tid, m.mk_false(), parents.size(), parents.data(), - v.size(), v.data()); + num_params - 1, params + 1); return pf; } From 606a9a7409df8b31301b9ebd8fedfc357098a6a5 Mon Sep 17 00:00:00 2001 From: Nuno Lopes Date: Fri, 22 Dec 2023 16:19:28 +0000 Subject: [PATCH 050/224] fix test build --- src/test/fuzzing/expr_rand.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/fuzzing/expr_rand.cpp b/src/test/fuzzing/expr_rand.cpp index 65d5f70c9..c0ffcc767 100644 --- a/src/test/fuzzing/expr_rand.cpp +++ b/src/test/fuzzing/expr_rand.cpp @@ -241,8 +241,7 @@ void expr_rand::initialize_bv(unsigned num_vars) { void expr_rand::initialize_array(unsigned num_vars, sort* dom, sort* rng) { family_id afid = m_manager.mk_family_id("array"); - parameter p1(dom), p2(rng); - parameter ps[2] = { p1, p2 }; + parameter ps[2] = { parameter(dom), parameter(rng) }; sort* a = m_manager.mk_sort(afid, ARRAY_SORT, 2, ps); sort* ss[3] = { a, dom, rng }; From e321643bf5d66e4be6dd71c41e20fd17b6a3c277 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Dec 2023 12:00:52 -0800 Subject: [PATCH 051/224] move sls core functionality to be independent of tactic Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 3 +- src/CMakeLists.txt | 1 + src/{tactic => ast}/sls/bvsls_opt_engine.cpp | 2 +- src/{tactic => ast}/sls/bvsls_opt_engine.h | 2 +- src/{tactic => ast}/sls/sls_engine.cpp | 39 ++------------------ src/{tactic => ast}/sls/sls_engine.h | 17 ++++++--- src/{tactic => ast}/sls/sls_evaluator.h | 4 +- src/{tactic => ast}/sls/sls_powers.h | 0 src/{tactic => ast}/sls/sls_tracker.h | 4 +- src/params/CMakeLists.txt | 1 + src/{tactic/sls => params}/sls_params.pyg | 0 src/tactic/sls/CMakeLists.txt | 5 +-- src/tactic/sls/sls_tactic.cpp | 38 +++++++++++++++++-- 13 files changed, 60 insertions(+), 56 deletions(-) rename src/{tactic => ast}/sls/bvsls_opt_engine.cpp (99%) rename src/{tactic => ast}/sls/bvsls_opt_engine.h (98%) rename src/{tactic => ast}/sls/sls_engine.cpp (94%) rename src/{tactic => ast}/sls/sls_engine.h (92%) rename src/{tactic => ast}/sls/sls_evaluator.h (99%) rename src/{tactic => ast}/sls/sls_powers.h (100%) rename src/{tactic => ast}/sls/sls_tracker.h (99%) rename src/{tactic/sls => params}/sls_params.pyg (100%) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 77bb1b680..534e597ef 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -40,6 +40,7 @@ def init_project_def(): add_lib('model', ['macros']) add_lib('converters', ['model'], 'ast/converters') add_lib('simplifiers', ['euf', 'normal_forms', 'bit_blaster', 'converters', 'substitution'], 'ast/simplifiers') + add_lib('ast_sls', ['ast'], 'ast/sls') add_lib('tactic', ['simplifiers']) add_lib('mbp', ['model', 'simplex'], 'qe/mbp') add_lib('qe_lite', ['tactic', 'mbp'], 'qe/lite') @@ -64,7 +65,7 @@ def init_project_def(): add_lib('bv_tactics', ['tactic', 'bit_blaster', 'core_tactics'], 'tactic/bv') add_lib('fuzzing', ['ast'], 'test/fuzzing') add_lib('smt_tactic', ['smt'], 'smt/tactic') - add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls') + add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics', 'ast_sls'], 'tactic/sls') add_lib('qe', ['smt', 'mbp', 'qe_lite', 'nlsat', 'tactic', 'nlsat_tactic'], 'qe') add_lib('sat_solver', ['solver', 'core_tactics', 'aig_tactic', 'bv_tactics', 'arith_tactics', 'sat_tactic'], 'sat/sat_solver') add_lib('fd_solver', ['core_tactics', 'arith_tactics', 'sat_solver', 'smt'], 'tactic/fd_solver') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a12571f35..4c09f31aa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,6 +54,7 @@ add_subdirectory(ast/euf) add_subdirectory(ast/converters) add_subdirectory(ast/substitution) add_subdirectory(ast/simplifiers) +add_subdirectory(ast/sls) add_subdirectory(tactic) add_subdirectory(qe/mbp) add_subdirectory(qe/lite) diff --git a/src/tactic/sls/bvsls_opt_engine.cpp b/src/ast/sls/bvsls_opt_engine.cpp similarity index 99% rename from src/tactic/sls/bvsls_opt_engine.cpp rename to src/ast/sls/bvsls_opt_engine.cpp index 37454ca72..e4c96d735 100644 --- a/src/tactic/sls/bvsls_opt_engine.cpp +++ b/src/ast/sls/bvsls_opt_engine.cpp @@ -17,7 +17,7 @@ Notes: --*/ #include "ast/normal_forms/nnf.h" -#include "tactic/sls/bvsls_opt_engine.h" +#include "ast/sls/bvsls_opt_engine.h" bvsls_opt_engine::bvsls_opt_engine(ast_manager & m, params_ref const & p) : sls_engine(m, p), diff --git a/src/tactic/sls/bvsls_opt_engine.h b/src/ast/sls/bvsls_opt_engine.h similarity index 98% rename from src/tactic/sls/bvsls_opt_engine.h rename to src/ast/sls/bvsls_opt_engine.h index c6b3857af..435fa3af4 100644 --- a/src/tactic/sls/bvsls_opt_engine.h +++ b/src/ast/sls/bvsls_opt_engine.h @@ -18,7 +18,7 @@ Notes: --*/ #pragma once -#include "tactic/sls/sls_engine.h" +#include "ast/sls/sls_engine.h" class bvsls_opt_engine : public sls_engine { sls_tracker & m_hard_tracker; diff --git a/src/tactic/sls/sls_engine.cpp b/src/ast/sls/sls_engine.cpp similarity index 94% rename from src/tactic/sls/sls_engine.cpp rename to src/ast/sls/sls_engine.cpp index 58676edfb..8b4253747 100644 --- a/src/tactic/sls/sls_engine.cpp +++ b/src/ast/sls/sls_engine.cpp @@ -26,8 +26,8 @@ Notes: #include "tactic/tactic.h" #include "util/luby.h" -#include "tactic/sls/sls_params.hpp" -#include "tactic/sls/sls_engine.h" +#include "params/sls_params.hpp" +#include "ast/sls/sls_engine.h" sls_engine::sls_engine(ast_manager & m, params_ref const & p) : @@ -52,7 +52,6 @@ sls_engine::~sls_engine() { void sls_engine::updt_params(params_ref const & _p) { sls_params p(_p); - m_produce_models = _p.get_bool("model", false); m_max_restarts = p.max_restarts(); m_tracker.set_random_seed(p.random_seed()); m_walksat = p.walksat(); @@ -523,38 +522,6 @@ bailout: return res; } -void sls_engine::operator()(goal_ref const & g, model_converter_ref & mc) { - if (g->inconsistent()) { - mc = nullptr; - return; - } - - m_produce_models = g->models_enabled(); - - for (unsigned i = 0; i < g->size(); i++) - assert_expr(g->form(i)); - - lbool res = operator()(); - - if (res == l_true) { - report_tactic_progress("Number of flips:", m_stats.m_moves); - for (unsigned i = 0; i < g->size(); i++) - if (!m_mpz_manager.is_one(m_tracker.get_value(g->form(i)))) - { - verbose_stream() << "Terminated before all assertions were SAT!" << std::endl; - NOT_IMPLEMENTED_YET(); - } - - if (m_produce_models) { - model_ref mdl = m_tracker.get_model(); - mc = model2model_converter(mdl.get()); - TRACE("sls_model", mc->display(tout);); - } - g->reset(); - } - else - mc = nullptr; -} lbool sls_engine::operator()() { m_tracker.initialize(m_assertions); @@ -567,7 +534,7 @@ lbool sls_engine::operator()() { do { checkpoint(); - report_tactic_progress("Searching... restarts left:", m_max_restarts - m_stats.m_restarts); + // report_tactic_progress("Searching... restarts left:", m_max_restarts - m_stats.m_restarts); res = search(); if (res == l_undef) diff --git a/src/tactic/sls/sls_engine.h b/src/ast/sls/sls_engine.h similarity index 92% rename from src/tactic/sls/sls_engine.h rename to src/ast/sls/sls_engine.h index 5f290c626..88ebb98b8 100644 --- a/src/tactic/sls/sls_engine.h +++ b/src/ast/sls/sls_engine.h @@ -21,10 +21,9 @@ Notes: #include "util/stopwatch.h" #include "util/lbool.h" #include "ast/converters/model_converter.h" -#include "tactic/goal.h" -#include "tactic/sls/sls_tracker.h" -#include "tactic/sls/sls_evaluator.h" +#include "ast/sls/sls_tracker.h" +#include "ast/sls/sls_evaluator.h" #include "util/statistics.h" class sls_engine { @@ -62,7 +61,6 @@ protected: unsynch_mpz_manager m_mpz_manager; powers m_powers; mpz m_zero, m_one, m_two; - bool m_produce_models; bv_util m_bv_util; sls_tracker m_tracker; sls_evaluator m_evaluator; @@ -96,7 +94,7 @@ public: void assert_expr(expr * e) { m_assertions.push_back(e); } - // stats const & get_stats(void) { return m_stats; } + stats const & get_stats(void) { return m_stats; } void collect_statistics(statistics & st) const; void reset_statistics() { m_stats.reset(); } @@ -111,7 +109,12 @@ public: lbool search(); lbool operator()(); - void operator()(goal_ref const & g, model_converter_ref & mc); + + mpz & get_value(expr * n) { return m_tracker.get_value(n); } + + model_ref get_model() { return m_tracker.get_model(); } + + unsynch_mpz_manager& get_mpz_manager() { return m_mpz_manager; } protected: void checkpoint(); @@ -135,5 +138,7 @@ protected: //double get_restart_armin(unsigned cnt_restarts); unsigned check_restart(unsigned curr_value); + + }; diff --git a/src/tactic/sls/sls_evaluator.h b/src/ast/sls/sls_evaluator.h similarity index 99% rename from src/tactic/sls/sls_evaluator.h rename to src/ast/sls/sls_evaluator.h index d386ece15..2ee03c928 100644 --- a/src/tactic/sls/sls_evaluator.h +++ b/src/ast/sls/sls_evaluator.h @@ -21,8 +21,8 @@ Notes: #include "model/model_evaluator.h" -#include "tactic/sls/sls_powers.h" -#include "tactic/sls/sls_tracker.h" +#include "ast/sls/sls_powers.h" +#include "ast/sls/sls_tracker.h" class sls_evaluator { ast_manager & m_manager; diff --git a/src/tactic/sls/sls_powers.h b/src/ast/sls/sls_powers.h similarity index 100% rename from src/tactic/sls/sls_powers.h rename to src/ast/sls/sls_powers.h diff --git a/src/tactic/sls/sls_tracker.h b/src/ast/sls/sls_tracker.h similarity index 99% rename from src/tactic/sls/sls_tracker.h rename to src/ast/sls/sls_tracker.h index 951153a5c..67723828f 100644 --- a/src/tactic/sls/sls_tracker.h +++ b/src/ast/sls/sls_tracker.h @@ -25,8 +25,8 @@ Notes: #include "ast/bv_decl_plugin.h" #include "model/model.h" -#include "tactic/sls/sls_params.hpp" -#include "tactic/sls/sls_powers.h" +#include "params/sls_params.hpp" +#include "ast/sls/sls_powers.h" class sls_tracker { ast_manager & m_manager; diff --git a/src/params/CMakeLists.txt b/src/params/CMakeLists.txt index cdc21da97..763702caf 100644 --- a/src/params/CMakeLists.txt +++ b/src/params/CMakeLists.txt @@ -15,6 +15,7 @@ z3_add_component(params poly_rewriter_params.pyg rewriter_params.pyg seq_rewriter_params.pyg + sls_params.pyg solver_params.pyg tactic_params.pyg EXTRA_REGISTER_MODULE_HEADERS diff --git a/src/tactic/sls/sls_params.pyg b/src/params/sls_params.pyg similarity index 100% rename from src/tactic/sls/sls_params.pyg rename to src/params/sls_params.pyg diff --git a/src/tactic/sls/CMakeLists.txt b/src/tactic/sls/CMakeLists.txt index 436b1742f..83599b827 100644 --- a/src/tactic/sls/CMakeLists.txt +++ b/src/tactic/sls/CMakeLists.txt @@ -1,15 +1,12 @@ z3_add_component(sls_tactic SOURCES - bvsls_opt_engine.cpp - sls_engine.cpp sls_tactic.cpp COMPONENT_DEPENDENCIES bv_tactics core_tactics normal_forms tactic - PYG_FILES - sls_params.pyg + ast_sls TACTIC_HEADERS sls_tactic.h ) diff --git a/src/tactic/sls/sls_tactic.cpp b/src/tactic/sls/sls_tactic.cpp index e631c23e9..6daadc83b 100644 --- a/src/tactic/sls/sls_tactic.cpp +++ b/src/tactic/sls/sls_tactic.cpp @@ -27,8 +27,8 @@ Notes: #include "tactic/core/nnf_tactic.h" #include "util/stopwatch.h" #include "tactic/sls/sls_tactic.h" -#include "tactic/sls/sls_params.hpp" -#include "tactic/sls/sls_engine.h" +#include "params/sls_params.hpp" +#include "ast/sls/sls_engine.h" class sls_tactic : public tactic { ast_manager & m; @@ -60,6 +60,38 @@ public: void collect_param_descrs(param_descrs & r) override { sls_params::collect_param_descrs(r); } + + void run(goal_ref const& g, model_converter_ref& mc) { + if (g->inconsistent()) { + mc = nullptr; + return; + } + + for (unsigned i = 0; i < g->size(); i++) + m_engine->assert_expr(g->form(i)); + + lbool res = m_engine->operator()(); + auto const& stats = m_engine->get_stats(); + if (res == l_true) { + report_tactic_progress("Number of flips:", stats.m_moves); + + for (unsigned i = 0; i < g->size(); i++) + if (!m_engine->get_mpz_manager().is_one(m_engine->get_value(g->form(i)))) { + verbose_stream() << "Terminated before all assertions were SAT!" << std::endl; + NOT_IMPLEMENTED_YET(); + } + + if (g->models_enabled()) { + model_ref mdl = m_engine->get_model(); + mc = model2model_converter(mdl.get()); + TRACE("sls_model", mc->display(tout);); + } + g->reset(); + } + else + mc = nullptr; + + } void operator()(goal_ref const & g, goal_ref_buffer & result) override { @@ -69,7 +101,7 @@ public: tactic_report report("sls", *g); model_converter_ref mc; - m_engine->operator()(g, mc); + run(g, mc); g->add(mc.get()); g->inc_depth(); result.push_back(g.get()); From 5f451182f771975796e67093cc1fbbdd6750c18d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Dec 2023 12:02:24 -0800 Subject: [PATCH 052/224] missing cmake list Signed-off-by: Nikolaj Bjorner --- src/ast/sls/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/ast/sls/CMakeLists.txt diff --git a/src/ast/sls/CMakeLists.txt b/src/ast/sls/CMakeLists.txt new file mode 100644 index 000000000..d3147b83a --- /dev/null +++ b/src/ast/sls/CMakeLists.txt @@ -0,0 +1,8 @@ +z3_add_component(ast_sls + SOURCES + bvsls_opt_engine.cpp + sls_engine.cpp + COMPONENT_DEPENDENCIES + ast + converters +) From 7adb402a3fa9fbbf66d7ed18f0431d5061281b66 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Dec 2023 12:06:30 -0800 Subject: [PATCH 053/224] add missing dependencies Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 2 +- src/ast/sls/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 534e597ef..1a8046155 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -40,7 +40,7 @@ def init_project_def(): add_lib('model', ['macros']) add_lib('converters', ['model'], 'ast/converters') add_lib('simplifiers', ['euf', 'normal_forms', 'bit_blaster', 'converters', 'substitution'], 'ast/simplifiers') - add_lib('ast_sls', ['ast'], 'ast/sls') + add_lib('ast_sls', ['ast','normal_forms','converters'], 'ast/sls') add_lib('tactic', ['simplifiers']) add_lib('mbp', ['model', 'simplex'], 'qe/mbp') add_lib('qe_lite', ['tactic', 'mbp'], 'qe/lite') diff --git a/src/ast/sls/CMakeLists.txt b/src/ast/sls/CMakeLists.txt index d3147b83a..17b803cf3 100644 --- a/src/ast/sls/CMakeLists.txt +++ b/src/ast/sls/CMakeLists.txt @@ -5,4 +5,5 @@ z3_add_component(ast_sls COMPONENT_DEPENDENCIES ast converters + normal_forms ) From cd331b8a56bfb76208c0e27e8daef6e2db2a4694 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Dec 2023 13:17:04 -0800 Subject: [PATCH 054/224] remove reference to tactic.h Signed-off-by: Nikolaj Bjorner --- src/ast/sls/bvsls_opt_engine.cpp | 6 ++++-- src/ast/sls/sls_engine.cpp | 13 ++++++------- src/ast/sls/sls_engine.h | 1 - 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ast/sls/bvsls_opt_engine.cpp b/src/ast/sls/bvsls_opt_engine.cpp index e4c96d735..7dc71cd8c 100644 --- a/src/ast/sls/bvsls_opt_engine.cpp +++ b/src/ast/sls/bvsls_opt_engine.cpp @@ -68,7 +68,8 @@ bvsls_opt_engine::optimization_result bvsls_opt_engine::optimize( if (is_sat != l_true) { do { - checkpoint(); + if (!m_manager.inc()) + return res; IF_VERBOSE(1, verbose_stream() << "Satisfying... restarts left:" << (m_max_restarts - m_stats.m_restarts) << std::endl;); is_sat = search(); @@ -136,7 +137,8 @@ expr_ref bvsls_opt_engine::maximize() while (m_mpz_manager.lt(score, max_score) && check_restart(m_stats.m_moves)) { - checkpoint(); + if (!m_manager.inc()) + goto bailout; m_stats.m_moves++; m_mpz_manager.set(old_score, score); new_const = (unsigned)-1; diff --git a/src/ast/sls/sls_engine.cpp b/src/ast/sls/sls_engine.cpp index 8b4253747..8bf70f3dd 100644 --- a/src/ast/sls/sls_engine.cpp +++ b/src/ast/sls/sls_engine.cpp @@ -23,7 +23,6 @@ Notes: #include "ast/ast_pp.h" #include "ast/rewriter/var_subst.h" #include "model/model_pp.h" -#include "tactic/tactic.h" #include "util/luby.h" #include "params/sls_params.hpp" @@ -91,14 +90,12 @@ void sls_engine::collect_statistics(statistics& st) const { st.update("sls moves/sec", m_stats.m_moves / seconds); } -void sls_engine::checkpoint() { - tactic::checkpoint(m_manager); -} bool sls_engine::full_eval(model & mdl) { model::scoped_model_completion _scm(mdl, true); for (expr* a : m_assertions) { - checkpoint(); + if (!m_manager.inc()) + return false; if (!mdl.is_true(a)) { TRACE("sls", tout << "Evaluation: false\n";); return false; @@ -422,7 +419,8 @@ lbool sls_engine::search() { unsigned sz = m_assertions.size(); while (check_restart(m_stats.m_moves)) { - checkpoint(); + if (!m_manager.inc()) + return l_undef; m_stats.m_moves++; // Andreas: Every base restart interval ... @@ -532,7 +530,8 @@ lbool sls_engine::operator()() { lbool res = l_undef; do { - checkpoint(); + if (!m_manager.inc()) + return l_undef; // report_tactic_progress("Searching... restarts left:", m_max_restarts - m_stats.m_restarts); res = search(); diff --git a/src/ast/sls/sls_engine.h b/src/ast/sls/sls_engine.h index 88ebb98b8..32338b8ae 100644 --- a/src/ast/sls/sls_engine.h +++ b/src/ast/sls/sls_engine.h @@ -117,7 +117,6 @@ public: unsynch_mpz_manager& get_mpz_manager() { return m_mpz_manager; } protected: - void checkpoint(); bool what_if(func_decl * fd, const unsigned & fd_inx, const mpz & temp, double & best_score, unsigned & best_const, mpz & best_value); From ad07e0e18d9806c4461beac7670faf4431727af7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Dec 2023 10:27:54 -0800 Subject: [PATCH 055/224] add sub and super-slice functionality directory to euf-bv-plugin --- src/ast/euf/euf_bv_plugin.cpp | 134 ++++++++++++++++++++++++++++++++++ src/ast/euf/euf_bv_plugin.h | 13 ++++ 2 files changed, 147 insertions(+) diff --git a/src/ast/euf/euf_bv_plugin.cpp b/src/ast/euf/euf_bv_plugin.cpp index f640b3ed0..89b5ade16 100644 --- a/src/ast/euf/euf_bv_plugin.cpp +++ b/src/ast/euf/euf_bv_plugin.cpp @@ -352,6 +352,140 @@ namespace euf { push_merge(mk_concat(lo, hi), n); } + void bv_plugin::sub_slices(enode* n, std::function& consumer) { + m_todo.push_back({ n, 0 }); + unsigned lo, hi; + expr* e; + + for (unsigned i = 0; i < m_todo.size(); ++i) { + auto [n, offset] = m_todo[i]; + m_offsets.reserve(n->get_root_id() + 1); + auto& offsets = m_offsets[n->get_root_id()]; + if (offsets.contains(offset)) + continue; + offsets.push_back(offset); + if (!consumer(n, offset)) + continue; + for (auto sib : euf::enode_class(n)) { + if (bv.is_concat(sib->get_expr())) { + unsigned delta = 0; + for (unsigned j = sib->num_args(); j-- > 0; ) { + auto arg = sib->get_arg(j); + m_todo.push_back({ arg, offset + delta }); + delta += width(arg); + } + } + } + for (auto p : euf::enode_parents(n->get_root())) { + if (bv.is_extract(p->get_expr(), lo, hi, e)) { + SASSERT(g.find(e)->get_root() == n->get_root()); + m_todo.push_back({ p, offset + lo }); + } + } + } + clear_offsets(); + } + + void bv_plugin::super_slices(enode* n, std::function& consumer) { + m_todo.push_back({ n, 0 }); + unsigned lo, hi; + expr* e; + + for (unsigned i = 0; i < m_todo.size(); ++i) { + auto [n, offset] = m_todo[i]; + m_offsets.reserve(n->get_root_id() + 1); + auto& offsets = m_offsets[n->get_root_id()]; + if (offsets.contains(offset)) + continue; + offsets.push_back(offset); + if (!consumer(n, offset)) + continue; + for (auto sib : euf::enode_class(n)) { + if (bv.is_extract(sib->get_expr(), lo, hi, e)) { + auto child = g.find(e); + m_todo.push_back({ child, offset + lo }); + } + } + for (auto p : euf::enode_parents(n->get_root())) { + if (bv.is_concat(p->get_expr())) { + unsigned delta = 0; + for (unsigned j = p->num_args(); j-- > 0; ) { + auto arg = p->get_arg(j); + if (arg->get_root() == n->get_root()) + m_todo.push_back({ p, offset + delta }); + delta += width(arg); + } + } + } + } + clear_offsets(); + } + + // + // Explain that a is a subslice of b at offset + // or that b is a subslice of a at offset + // + void bv_plugin::explain_slice(enode* a, unsigned offset, enode* b, std::function& consumer) { + if (width(a) < width(b)) + std::swap(a, b); + SASSERT(width(a) >= width(b)); + svector> just; + m_jtodo.push_back({ a, 0, UINT_MAX }); + unsigned lo, hi; + expr* e; + + for (unsigned i = 0; i < m_jtodo.size(); ++i) { + auto [n, offs, j] = m_jtodo[i]; + m_offsets.reserve(n->get_root_id() + 1); + auto& offsets = m_offsets[n->get_root_id()]; + if (offsets.contains(offs)) + continue; + offsets.push_back(offs); + if (n->get_root() == b->get_root() && offs == offset) { + while (j != UINT_MAX) { + auto [x, y, j2] = just[j]; + consumer(x, y); + j = j2; + } + for (auto const& [n, offset, j] : m_jtodo) { + m_offsets.reserve(n->get_root_id() + 1); + m_offsets[n->get_root_id()].reset(); + } + m_jtodo.reset(); + return; + } + for (auto sib : euf::enode_class(n)) { + if (bv.is_concat(sib->get_expr())) { + unsigned delta = 0; + unsigned j2 = just.size(); + just.push_back({ n, sib, j }); + for (unsigned j = sib->num_args(); j-- > 0; ) { + auto arg = sib->get_arg(j); + m_jtodo.push_back({ arg, offset + delta, j2 }); + delta += width(arg); + } + } + } + for (auto p : euf::enode_parents(n->get_root())) { + if (bv.is_extract(p->get_expr(), lo, hi, e)) { + SASSERT(g.find(e)->get_root() == n->get_root()); + unsigned j2 = just.size(); + just.push_back({ g.find(e), n, j}); + m_jtodo.push_back({ p, offset + lo, j2}); + } + } + } + UNREACHABLE(); + } + + void bv_plugin::clear_offsets() { + for (auto const& [n, offset] : m_todo) { + m_offsets.reserve(n->get_root_id() + 1); + m_offsets[n->get_root_id()].reset(); + } + m_todo.reset(); + } + std::ostream& bv_plugin::display(std::ostream& out) const { out << "bv\n"; for (auto const& i : m_info) diff --git a/src/ast/euf/euf_bv_plugin.h b/src/ast/euf/euf_bv_plugin.h index b8d62051e..199aed4e7 100644 --- a/src/ast/euf/euf_bv_plugin.h +++ b/src/ast/euf/euf_bv_plugin.h @@ -41,6 +41,8 @@ namespace euf { bv_util bv; slice_info_vector m_info; // indexed by enode::get_id() + + enode_vector m_xs, m_ys; bool is_concat(enode* n) const { return bv.is_concat(n->get_expr()); } @@ -74,6 +76,11 @@ namespace euf { void propagate_extract(enode* n); void propagate_values(enode* n); + vector m_offsets; + svector> m_todo; + svector> m_jtodo; + void clear_offsets(); + enode_vector m_undo_split; void push_undo_split(enode* n); @@ -95,6 +102,12 @@ namespace euf { void undo() override; std::ostream& display(std::ostream& out) const override; + + void sub_slices(enode* n, std::function& consumer); + + void super_slices(enode* n, std::function& consumer); + + void explain_slice(enode* a, unsigned offset, enode* b, std::function& consumer); }; } From ebe5ebf0ae63bf520839b4d34d7b19e0af87fe36 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Dec 2023 11:58:29 -0800 Subject: [PATCH 056/224] Add branch and bound solver, for fun --- examples/python/bincover.py | 104 ++++++++++++++++++++++++++++++++++-- 1 file changed, 99 insertions(+), 5 deletions(-) diff --git a/examples/python/bincover.py b/examples/python/bincover.py index d6097af5e..d8a81c25a 100644 --- a/examples/python/bincover.py +++ b/examples/python/bincover.py @@ -46,7 +46,56 @@ class Item: def __repr__(self): return f"binof-{self.index}:weight-{self.weight}" - + +class BranchAndBound: + """Branch and Bound solver. + It keeps track of a current best score and a slack that tracks bins that are set unfilled. + It blocks branches that are worse than the current best score. + In Final check it blocks the current assignment. + """ + def __init__(self, user_propagator): + self.up = user_propagator + + def init(self, soft_literals): + self.value = 0 + self.best = 0 + self.slack = 0 + self.id2weight = {} + self.assigned_to_false = [] + for p, weight in soft_literals: + self.slack += weight + self.id2weight[p.get_id()] = weight + + def fixed(self, p, value): + weight = self.id2weight[p.get_id()] + if is_true(value): + old_value = self.value + self.up.trail += [lambda : self._undo_value(old_value)] + self.value += weight + elif self.best > self.slack - weight: + self.assigned_to_false += [ p ] + self.up.conflict(self.assigned_to_false) + self.assigned_to_false.pop(-1) + else: + old_slack = self.slack + self.up.trail += [lambda : self._undo_slack(old_slack)] + self.slack -= weight + self.assigned_to_false += [p] + + def final(self): + if self.value > self.best: + self.best = self.value + print("Number of bins filled", self.value) + for bin in self.up.bins: + print(bin.var, bin.added) + self.up.conflict(self.assigned_to_false) + + def _undo_value(self, old_value): + self.value = old_value + + def _undo_slack(self, old_slack): + self.slack = old_slack + self.assigned_to_false.pop(-1) class BinCoverSolver(UserPropagateBase): """Represent a bin-covering problem by associating each bin with a variable @@ -65,6 +114,7 @@ class BinCoverSolver(UserPropagateBase): self.solver = s self.initialized = False self.add_fixed(lambda x, v : self._fixed(x, v)) + self.branch_and_bound = None # Initialize bit-vector variables for items. @@ -86,8 +136,19 @@ class BinCoverSolver(UserPropagateBase): ineq = ULT(item.var, bound) self.solver.add(ineq) total_weight = sum(item.weight for item in self.items) - for i in range(len(self.bins)): - self.bins[i].slack = total_weight + for bin in self.bins: + bin.slack = total_weight + + # + # Register optional branch and bound weighted solver. + # If it is registered, it + def init_branch_and_bound(self): + soft = [(bin.var, 1) for bin in self.bins] + self.branch_and_bound = BranchAndBound(self) + self.branch_and_bound.init(soft) + for bin in self.bins: + self.add(bin.var) + self.add_final(lambda : self.branch_and_bound.final()) def add_bin(self, min_bound): assert not self.initialized @@ -165,6 +226,9 @@ class BinCoverSolver(UserPropagateBase): # Callback from Z3 when an item gets fixed. def _fixed(self, _item, value): + if self.branch_and_bound and is_bool(value): + self.branch_and_bound.fixed(_item, value) + return item = self._itemvar2item(_item) if item is None: print("no item for ", _item) @@ -271,7 +335,6 @@ class OptimizeBinCoverSolver: print(bin, bin.added) - def example1(): s = OptimizeBinCoverSolver() i1 = s.add_item(2) @@ -283,6 +346,37 @@ def example1(): b3 = s.add_bin(1) s.optimize() -example1() +#example1() +class BranchAndBoundCoverSolver: + def __init__(self): + self.solver = Solver() + self.bin_solver = BinCoverSolver(self.solver) + + def init(self): + self.bin_solver.init() + self.bin_solver.init_branch_and_bound() + + def add_item(self, weight): + return self.bin_solver.add_item(weight) + + def add_bin(self, min_bound): + return self.bin_solver.add_bin(min_bound) + + def optimize(self): + self.init() + self.solver.check() + +def example2(): + s = BranchAndBoundCoverSolver() + i1 = s.add_item(2) + i2 = s.add_item(4) + i3 = s.add_item(5) + i4 = s.add_item(2) + b1 = s.add_bin(3) + b2 = s.add_bin(6) + b3 = s.add_bin(1) + s.optimize() + +example2() From d7931b93425e5db3dbd0366f1dbdb843313f3fb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 26 Dec 2023 08:41:33 +0000 Subject: [PATCH 057/224] Bump microsoft/setup-msbuild from 1.1 to 1.3 (#7071) Bumps [microsoft/setup-msbuild](https://github.com/microsoft/setup-msbuild) from 1.1 to 1.3. - [Release notes](https://github.com/microsoft/setup-msbuild/releases) - [Changelog](https://github.com/microsoft/setup-msbuild/blob/main/building-release.md) - [Commits](https://github.com/microsoft/setup-msbuild/compare/v1.1...v1.3) --- updated-dependencies: - dependency-name: microsoft/setup-msbuild dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/Windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 86cd0e9a0..a79a088dd 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -23,7 +23,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1.1 + uses: microsoft/setup-msbuild@v1.3 - name: Build run: | md build From af7691224e6fd6dae8ea9b3356e051d445e523f0 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 23 Dec 2023 14:02:14 -1000 Subject: [PATCH 058/224] adding the polarity bound --- src/math/lp/gomory.cpp | 225 +++++++++++++++++++++---------------- src/math/lp/int_branch.cpp | 3 +- src/math/lp/int_solver.cpp | 3 +- src/math/lp/int_solver.h | 2 +- 4 files changed, 134 insertions(+), 99 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 94435e27e..6e6ab2467 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -25,7 +25,7 @@ #define SMALL_CUTS 1 namespace lp { -class create_cut { +struct create_cut { lar_term & m_t; // the term to return in the cut mpq & m_k; // the right side of the cut explanation* m_ex; // the conflict explanation @@ -39,7 +39,8 @@ class create_cut { #if SMALL_CUTS mpq m_abs_max, m_big_number; #endif - struct found_big {}; + int m_polarity; + bool m_found_big; const impq & get_value(unsigned j) const { return lia.get_value(j); } bool is_int(unsigned j) const { return lia.column_is_int(j) || (lia.is_fixed(j) && @@ -70,7 +71,7 @@ class create_cut { new_a = m_fj <= m_one_minus_f ? m_fj / m_one_minus_f : ((1 - m_fj) / m_f); lp_assert(new_a.is_pos()); m_k.addmul(new_a, lower_bound(j).x); - push_explanation(column_lower_bound_constraint(j)); + push_explanation(column_lower_bound_constraint(j)); } else { lp_assert(at_upper(j)); @@ -78,14 +79,14 @@ class create_cut { new_a = - (m_fj <= m_f ? m_fj / m_f : ((1 - m_fj) / m_one_minus_f)); lp_assert(new_a.is_neg()); m_k.addmul(new_a, upper_bound(j).x); - push_explanation(column_upper_bound_constraint(j)); - } + push_explanation(column_upper_bound_constraint(j)); + } m_t.add_monomial(new_a, j); TRACE("gomory_cut_detail", tout << "new_a = " << new_a << ", k = " << m_k << "\n";); #if SMALL_CUTS // if (numerator(new_a).is_big()) throw found_big(); if (numerator(new_a) > m_big_number) - throw found_big(); + m_found_big = true; #endif } @@ -93,25 +94,45 @@ class create_cut { TRACE("gomory_cut_detail_real", tout << "j = " << j << ", a = " << a << ", m_k = " << m_k << "\n";); mpq new_a; if (at_lower(j)) { - if (a.is_pos()) + if (a.is_pos()) { // the delta is a (x - f) is positive it has to grow and fight m_one_minus_f new_a = a / m_one_minus_f; - else + if (m_polarity != 2) { + if (m_polarity == -1) m_polarity = 2; + else m_polarity = 1; + } + } + else { // the delta is negative and it works again m_f new_a = - a / m_f; + if (m_polarity != 2) { + if (m_polarity == 1) m_polarity = 2; + else m_polarity = -1; + } + } m_k.addmul(new_a, lower_bound(j).x); // is it a faster operation than - // k += lower_bound(j).x * new_a; + // k += lower_bound(j).x * new_a; push_explanation(column_lower_bound_constraint(j)); } else { lp_assert(at_upper(j)); - if (a.is_pos()) + if (a.is_pos()) { // the delta is works again m_f - new_a = - a / m_f; - else + new_a = - a / m_f; + if (m_polarity != 2) { + if (m_polarity == 1) m_polarity = 2; + else m_polarity = -1; + } + } + else { // the delta is positive works again m_one_minus_f - new_a = a / m_one_minus_f; - m_k.addmul(new_a, upper_bound(j).x); // k += upper_bound(j).x * new_a; + new_a = a / m_one_minus_f; + if (m_polarity != 2) { + if (m_polarity == -1) m_polarity = 2; + else m_polarity = 1; + } + } + m_k.addmul(new_a, upper_bound(j).x); // k += upper_bound(j).x * new_a; push_explanation(column_upper_bound_constraint(j)); } m_t.add_monomial(new_a, j); @@ -121,7 +142,7 @@ class create_cut { #if SMALL_CUTS // if (numerator(new_a).is_big()) throw found_big(); if (numerator(new_a) > m_big_number) - throw found_big(); + m_found_big = true; #endif } @@ -184,6 +205,7 @@ class create_cut { void dump_lower_bound_expl(std::ostream & out, unsigned j) const { out << "(assert (>= " << var_name(j) << " " << lower_bound(j).x << "))\n"; } + void dump_upper_bound_expl(std::ostream & out, unsigned j) const { out << "(assert (<= " << var_name(j) << " " << upper_bound(j).x << "))\n"; } @@ -238,10 +260,12 @@ public: lia_move cut() { TRACE("gomory_cut", dump(tout);); - - // gomory will be t >= k and the current solution has a property t < k + m_polarity = 0; // 0: means undefined, 1, -1: the polar case, 2: the mixed case + // gomory cut will be m_t >= m_k and the current solution has a property m_t < m_k m_k = 1; m_t.clear(); + m_ex->clear(); + m_found_big = false; TRACE("gomory_cut_detail", tout << "m_f: " << m_f << ", "; tout << "1 - m_f: " << 1 - m_f << ", get_value(m_inf_col).x - m_f = " << get_value(m_inf_col).x - m_f << "\n";); lp_assert(m_f.is_pos() && (get_value(m_inf_col).x - m_f).is_int()); @@ -258,42 +282,59 @@ public: #endif for (const auto & p : m_row) { unsigned j = p.var(); - if (j == m_inf_col) { - lp_assert(p.coeff() == one_of_type()); + if (j == m_inf_col) continue; + // use -p.coeff() to make the format compatible with the format used in: Integrating Simplex with DPLL(T) + + if (lia.is_fixed(j)) { + push_explanation(column_lower_bound_constraint(j)); + push_explanation(column_upper_bound_constraint(j)); continue; } - - // use -p.coeff() to make the format compatible with the format used in: Integrating Simplex with DPLL(T) - try { - if (lia.is_fixed(j)) { - push_explanation(column_lower_bound_constraint(j)); - push_explanation(column_upper_bound_constraint(j)); - continue; + if (is_real(j)) + real_case_in_gomory_cut(- p.coeff(), j); + else if (!p.coeff().is_int()) { + some_int_columns = true; + m_fj = fractional_part(-p.coeff()); + m_one_minus_fj = 1 - m_fj; + int_case_in_gomory_cut(j); + if (p.coeff().is_pos()) { + if (at_lower(j)) { + if (m_polarity == -1) m_polarity = 2; + else m_polarity = 1; + } + else { + if (m_polarity == 1) m_polarity = 2; + else m_polarity = -1; + } } - if (is_real(j)) - real_case_in_gomory_cut(- p.coeff(), j); - else if (!p.coeff().is_int()) { - some_int_columns = true; - m_fj = fractional_part(-p.coeff()); - m_one_minus_fj = 1 - m_fj; - int_case_in_gomory_cut(j); + else { + if (at_lower(j)) { + if (m_polarity == 1) m_polarity = 2; + else m_polarity = -1; + } + else { + if (m_polarity == -1) m_polarity = 2; + else m_polarity = 1; + } } } - catch (found_big) { - m_ex->clear(); - m_t.clear(); - m_k = 1; + + if (m_found_big) { return lia_move::undef; } } + if (m_t.is_empty()) return report_conflict_from_gomory_cut(); + TRACE("gomory_cut", print_linear_combination_of_column_indices_only(m_t.coeffs_as_vector(), tout << "gomory cut: "); tout << " >= " << m_k << std::endl;); if (some_int_columns) simplify_inequality(); - lp_assert(lia.current_solution_is_inf_on_cut()); // checks that indices are columns + TRACE("gomory_cut", print_linear_combination_of_column_indices_only(m_t.coeffs_as_vector(), tout << "gomory cut: "); tout << " >= " << m_k << std::endl;); TRACE("gomory_cut_detail", dump_cut_and_constraints_as_smt_lemma(tout); lia.lra.display(tout)); + SASSERT(lia.current_solution_is_inf_on_cut()); // checks that indices are columns + lia.settings().stats().m_gomory_cuts++; return lia_move::cut; } @@ -403,11 +444,6 @@ public: }; - lia_move gomory::cut(lar_term & t, mpq & k, explanation* ex, unsigned basic_inf_int_j, const row_strip& row) { - create_cut cc(t, k, ex, basic_inf_int_j, row, lia); - return cc.cut(); - } - bool gomory::is_gomory_cut_target(lpvar k) { SASSERT(lia.is_base(k)); // All non base variables must be at their bounds and assigned to rationals (that is, infinitesimals are not allowed). @@ -425,16 +461,6 @@ public: return true; } - - lia_move gomory::get_cut(lpvar j) { - unsigned r = lia.row_of_basic_column(j); - const row_strip& row = lra.get_row(r); - SASSERT(lra.row_is_correct(r)); - SASSERT(is_gomory_cut_target(j)); - lia.m_upper = false; - return cut(lia.m_t, lia.m_k, lia.m_ex, j, row); - } - // return the minimal distance from the variable value to an integer mpq get_gomory_score(const int_solver& lia, lpvar j) { const mpq& val = lia.get_value(j).x; @@ -486,38 +512,28 @@ public: lia_move gomory::get_gomory_cuts(unsigned num_cuts) { - struct ex { explanation m_ex; lar_term m_term; mpq m_k; bool m_is_upper; }; + struct cut_result {explanation ex; lar_term t; mpq k; int polarity; lpvar j;}; + vector big_cuts; + struct polar_pair {int polarity; lpvar j; u_dependency *dep;}; + vector polar_vars; unsigned_vector columns_for_cuts = gomory_select_int_infeasible_vars(num_cuts); - vector cuts; - - for (unsigned j : columns_for_cuts) { - lia.m_ex->clear(); - lia.m_t.clear(); - lia.m_k.reset(); - auto r = get_cut(j); - if (r != lia_move::cut) - continue; - cuts.push_back({ *lia.m_ex, lia.m_t, lia.m_k, lia.is_upper() }); - if (lia.settings().get_cancel_flag()) - return lia_move::undef; - } - - auto is_small_cut = [&](ex const& cut) { - return all_of(cut.m_term, [&](auto ci) { return ci.coeff().is_small(); }); + // define inline helper functions + bool has_small_cut = false; + auto is_small_cut = [&](lar_term const& t) { + return all_of(t, [&](auto ci) { return ci.coeff().is_small(); }); }; - - auto add_cut = [&](ex const& cut) { + auto add_cut = [&](cut_result const& cr) { u_dependency* dep = nullptr; - for (auto c : cut.m_ex) + for (auto c : cr.ex) dep = lra.join_deps(lra.dep_manager().mk_leaf(c.ci()), dep); - lp::lpvar term_index = lra.add_term(cut.m_term.coeffs_as_vector(), UINT_MAX); + lp::lpvar term_index = lra.add_term(cr.t.coeffs_as_vector(), UINT_MAX); term_index = lra.map_term_index_to_column_index(term_index); lra.update_column_type_and_bound(term_index, - cut.m_is_upper ? lp::lconstraint_kind::LE : lp::lconstraint_kind::GE, - cut.m_k, dep); + lp::lconstraint_kind::GE, + lia.m_k, dep); + return dep; }; - auto _check_feasible = [&](void) { lra.find_feasible_solution(); if (!lra.is_feasible() && !lia.settings().get_cancel_flag()) { @@ -527,24 +543,34 @@ public: return true; }; - bool has_small = false, has_large = false; - - for (auto const& cut : cuts) { - if (!is_small_cut(cut)) { - has_large = true; +// start creating cuts + for (unsigned j : columns_for_cuts) { + unsigned row_index = lia.row_of_basic_column(j); + const row_strip& row = lra.get_row(row_index); + create_cut cc(lia.m_t, lia.m_k, lia.m_ex, j, row, lia); + auto r = cc.cut(); + + if (r != lia_move::cut) + continue; + cut_result cr = {*lia.m_ex, lia.m_t, lia.m_k, cc.m_polarity, j}; + + if (!is_small_cut(lia.m_t)) { + big_cuts.push_back(cr); continue; } - has_small = true; - add_cut(cut); + has_small_cut = true; + auto dep = add_cut(cr); + if (abs(cr.polarity) == 1) // need to delay the update of the bounds for j in a polar case, because simplify_inequality relies on the old bounds + polar_vars.push_back({cr.polarity, j, dep}); // todo : polarity for big cuts + + if (lia.settings().get_cancel_flag()) + return lia_move::undef; } - if (has_large) { - lra.push(); - - for (auto const& cut : cuts) - if (!is_small_cut(cut)) - add_cut(cut); - + if (big_cuts.size()) { + lra.push(); + for (auto const& cut : big_cuts) + add_cut(cut); bool feas = _check_feasible(); lra.pop(1); @@ -555,18 +581,25 @@ public: return lia_move::conflict; } + for (auto const& p : polar_vars) { + if (p.polarity == 1) { + lra.update_column_type_and_bound(p.j, lp::lconstraint_kind::LE, floor(lra.get_column_value(p.j).x), p.dep); + } + else if (p.polarity == -1) { + lra.update_column_type_and_bound(p.j, lp::lconstraint_kind::GE, ceil(lra.get_column_value(p.j).x), p.dep); + } + } + if (!_check_feasible()) return lia_move::conflict; - - lia.m_ex->clear(); - lia.m_t.clear(); - lia.m_k.reset(); if (!lia.has_inf_int()) return lia_move::sat; - if (has_small || has_large) + if (has_small_cut || big_cuts.size()) return lia_move::continue_with_check; + + lra.move_non_basic_columns_to_bounds(); return lia_move::undef; diff --git a/src/math/lp/int_branch.cpp b/src/math/lp/int_branch.cpp index 1a998e92a..4ab97d3ed 100644 --- a/src/math/lp/int_branch.cpp +++ b/src/math/lp/int_branch.cpp @@ -31,7 +31,8 @@ lia_move int_branch::operator()() { lia_move int_branch::create_branch_on_column(int j) { TRACE("check_main_int", tout << "branching" << std::endl;); - lp_assert(lia.m_t.is_empty()); + lia.m_t.clear(); + lp_assert(j != -1); lia.m_t.add_monomial(mpq(1), lra.column_to_reported_index(j)); if (lia.is_free(j)) { diff --git a/src/math/lp/int_solver.cpp b/src/math/lp/int_solver.cpp index 3a2a195dc..bf0ae64dd 100644 --- a/src/math/lp/int_solver.cpp +++ b/src/math/lp/int_solver.cpp @@ -198,7 +198,7 @@ namespace lp { if (r == lia_move::undef) lra.move_non_basic_columns_to_bounds(); if (r == lia_move::undef && should_hnf_cut()) r = hnf_cut(); - if (r == lia_move::undef && should_gomory_cut()) r = gomory(*this).get_gomory_cuts(2); + if (r == lia_move::undef && should_gomory_cut()) r = gomory(*this).get_gomory_cuts(1); if (r == lia_move::undef) r = int_branch(*this)(); if (settings().get_cancel_flag()) r = lia_move::undef; @@ -242,6 +242,7 @@ namespace lp { CTRACE("current_solution_is_inf_on_cut", v * sign <= impq(m_k) * sign, tout << "m_upper = " << m_upper << std::endl; tout << "v = " << v << ", k = " << m_k << std::endl; + tout << "term:";lra.print_term(m_t, tout) << "\n"; ); return v * sign > impq(m_k) * sign; } diff --git a/src/math/lp/int_solver.h b/src/math/lp/int_solver.h index 8a2a157e3..d4bffeadc 100644 --- a/src/math/lp/int_solver.h +++ b/src/math/lp/int_solver.h @@ -33,7 +33,7 @@ class lar_solver; class lar_core_solver; class int_solver { - friend class create_cut; + friend struct create_cut; friend class gomory; friend class int_cube; friend class int_branch; From a3529a0046e4c0bcc3e500183d8770c750eafa64 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 23 Dec 2023 19:27:18 -1000 Subject: [PATCH 059/224] create bounds for gomory cuts with big numbers --- src/math/lp/gomory.cpp | 45 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 6e6ab2467..b974c6086 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -39,8 +39,9 @@ struct create_cut { #if SMALL_CUTS mpq m_abs_max, m_big_number; #endif - int m_polarity; - bool m_found_big; + int m_polarity; + bool m_found_big; + u_dependency* m_dep; const impq & get_value(unsigned j) const { return lia.get_value(j); } bool is_int(unsigned j) const { return lia.column_is_int(j) || (lia.is_fixed(j) && @@ -330,6 +331,10 @@ public: if (some_int_columns) simplify_inequality(); + m_dep = nullptr; + for (auto c : *m_ex) + m_dep = lia.lra.join_deps(lia.lra.dep_manager().mk_leaf(c.ci()), m_dep); + TRACE("gomory_cut", print_linear_combination_of_column_indices_only(m_t.coeffs_as_vector(), tout << "gomory cut: "); tout << " >= " << m_k << std::endl;); TRACE("gomory_cut_detail", dump_cut_and_constraints_as_smt_lemma(tout); lia.lra.display(tout)); @@ -512,10 +517,10 @@ public: lia_move gomory::get_gomory_cuts(unsigned num_cuts) { - struct cut_result {explanation ex; lar_term t; mpq k; int polarity; lpvar j;}; + struct cut_result {u_dependency *dep; lar_term t; mpq k; int polarity; lpvar j;}; vector big_cuts; - struct polar_pair {int polarity; lpvar j; u_dependency *dep;}; - vector polar_vars; + struct polar_pair {int polarity; u_dependency *dep;}; + std::unordered_map polar_vars; unsigned_vector columns_for_cuts = gomory_select_int_infeasible_vars(num_cuts); // define inline helper functions @@ -524,15 +529,12 @@ public: return all_of(t, [&](auto ci) { return ci.coeff().is_small(); }); }; auto add_cut = [&](cut_result const& cr) { - u_dependency* dep = nullptr; - for (auto c : cr.ex) - dep = lra.join_deps(lra.dep_manager().mk_leaf(c.ci()), dep); + u_dependency* dep = cr.dep; lp::lpvar term_index = lra.add_term(cr.t.coeffs_as_vector(), UINT_MAX); term_index = lra.map_term_index_to_column_index(term_index); lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::GE, - lia.m_k, dep); - return dep; + lia.m_k, dep); }; auto _check_feasible = [&](void) { lra.find_feasible_solution(); @@ -552,17 +554,16 @@ public: if (r != lia_move::cut) continue; - cut_result cr = {*lia.m_ex, lia.m_t, lia.m_k, cc.m_polarity, j}; - + cut_result cr = {cc.m_dep, lia.m_t, lia.m_k, cc.m_polarity, j}; + if (abs(cr.polarity) == 1) // need to delay the update of the bounds for j in a polar case, because simplify_inequality relies on the old bounds + polar_vars[j] = {cr.polarity, cc.m_dep}; + if (!is_small_cut(lia.m_t)) { big_cuts.push_back(cr); continue; } has_small_cut = true; - auto dep = add_cut(cr); - if (abs(cr.polarity) == 1) // need to delay the update of the bounds for j in a polar case, because simplify_inequality relies on the old bounds - polar_vars.push_back({cr.polarity, j, dep}); // todo : polarity for big cuts - + add_cut(cr); if (lia.settings().get_cancel_flag()) return lia_move::undef; } @@ -581,12 +582,14 @@ public: return lia_move::conflict; } +// this way we create bounds for the variables in polar cases even where the terms had big numbers for (auto const& p : polar_vars) { - if (p.polarity == 1) { - lra.update_column_type_and_bound(p.j, lp::lconstraint_kind::LE, floor(lra.get_column_value(p.j).x), p.dep); + if (p.second.polarity == 1) { + lra.update_column_type_and_bound(p.first, lp::lconstraint_kind::LE, floor(lra.get_column_value(p.first).x), p.second.dep); } - else if (p.polarity == -1) { - lra.update_column_type_and_bound(p.j, lp::lconstraint_kind::GE, ceil(lra.get_column_value(p.j).x), p.dep); + else { + SASSERT(p.second.polarity == -1); + lra.update_column_type_and_bound(p.first, lp::lconstraint_kind::GE, ceil(lra.get_column_value(p.first).x), p.second.dep); } } @@ -598,8 +601,6 @@ public: if (has_small_cut || big_cuts.size()) return lia_move::continue_with_check; - - lra.move_non_basic_columns_to_bounds(); return lia_move::undef; From 5796e8899f6c17051e565c26e67834701e6a2cce Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 24 Dec 2023 07:23:35 -1000 Subject: [PATCH 060/224] use vector instead of unordered_map in gomory Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index b974c6086..130ba631e 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -519,8 +519,8 @@ public: lia_move gomory::get_gomory_cuts(unsigned num_cuts) { struct cut_result {u_dependency *dep; lar_term t; mpq k; int polarity; lpvar j;}; vector big_cuts; - struct polar_pair {int polarity; u_dependency *dep;}; - std::unordered_map polar_vars; + struct polar_info {lpvar j; int polarity; u_dependency *dep;}; + vector polar_vars; unsigned_vector columns_for_cuts = gomory_select_int_infeasible_vars(num_cuts); // define inline helper functions @@ -556,7 +556,7 @@ public: continue; cut_result cr = {cc.m_dep, lia.m_t, lia.m_k, cc.m_polarity, j}; if (abs(cr.polarity) == 1) // need to delay the update of the bounds for j in a polar case, because simplify_inequality relies on the old bounds - polar_vars[j] = {cr.polarity, cc.m_dep}; + polar_vars.push_back( {j, cr.polarity, cc.m_dep} ); if (!is_small_cut(lia.m_t)) { big_cuts.push_back(cr); @@ -584,12 +584,12 @@ public: // this way we create bounds for the variables in polar cases even where the terms had big numbers for (auto const& p : polar_vars) { - if (p.second.polarity == 1) { - lra.update_column_type_and_bound(p.first, lp::lconstraint_kind::LE, floor(lra.get_column_value(p.first).x), p.second.dep); + if (p.polarity == 1) { + lra.update_column_type_and_bound(p.j, lp::lconstraint_kind::LE, floor(lra.get_column_value(p.j).x), p.dep); } else { - SASSERT(p.second.polarity == -1); - lra.update_column_type_and_bound(p.first, lp::lconstraint_kind::GE, ceil(lra.get_column_value(p.first).x), p.second.dep); + SASSERT(p.polarity == -1); + lra.update_column_type_and_bound(p.j, lp::lconstraint_kind::GE, ceil(lra.get_column_value(p.j).x), p.dep); } } From 0728b81e9e272848abcef628c965f9c8ee1f408e Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 27 Dec 2023 08:33:51 -1000 Subject: [PATCH 061/224] add parameter lp_settings.m_gomory_simplify --- src/math/lp/gomory.cpp | 2 +- src/math/lp/int_solver.cpp | 2 +- src/math/lp/lp_settings.cpp | 1 + src/math/lp/lp_settings.h | 2 ++ src/smt/params/smt_params_helper.pyg | 1 + 5 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 130ba631e..f5331ea05 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -328,7 +328,7 @@ public: if (m_t.is_empty()) return report_conflict_from_gomory_cut(); TRACE("gomory_cut", print_linear_combination_of_column_indices_only(m_t.coeffs_as_vector(), tout << "gomory cut: "); tout << " >= " << m_k << std::endl;); - if (some_int_columns) + if (lia.lra.settings().m_gomory_simplify && some_int_columns) simplify_inequality(); m_dep = nullptr; diff --git a/src/math/lp/int_solver.cpp b/src/math/lp/int_solver.cpp index bf0ae64dd..5c480cbb3 100644 --- a/src/math/lp/int_solver.cpp +++ b/src/math/lp/int_solver.cpp @@ -198,7 +198,7 @@ namespace lp { if (r == lia_move::undef) lra.move_non_basic_columns_to_bounds(); if (r == lia_move::undef && should_hnf_cut()) r = hnf_cut(); - if (r == lia_move::undef && should_gomory_cut()) r = gomory(*this).get_gomory_cuts(1); + if (r == lia_move::undef && should_gomory_cut()) r = gomory(*this).get_gomory_cuts(2); if (r == lia_move::undef) r = int_branch(*this)(); if (settings().get_cancel_flag()) r = lia_move::undef; diff --git a/src/math/lp/lp_settings.cpp b/src/math/lp/lp_settings.cpp index b72b837fd..71193914f 100644 --- a/src/math/lp/lp_settings.cpp +++ b/src/math/lp/lp_settings.cpp @@ -32,4 +32,5 @@ void lp::lp_settings::updt_params(params_ref const& _p) { report_frequency = p.arith_rep_freq(); m_simplex_strategy = static_cast(p.arith_simplex_strategy()); m_nlsat_delay = p.arith_nl_delay(); + m_gomory_simplify = p.arith_gomory_simplify(); } diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index a0cb485b5..fef30cb6d 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -187,6 +187,7 @@ private: random_gen m_rand; public: + bool m_gomory_simplify = false; void updt_params(params_ref const& p); bool enable_hnf() const { return m_enable_hnf; } unsigned nlsat_delay() const { return m_nlsat_delay; } @@ -214,6 +215,7 @@ public: bool backup_costs = true; unsigned column_number_threshold_for_using_lu_in_lar_solver = 4000; unsigned m_int_gomory_cut_period = 4; + bool m_gomory_simpliy = false; unsigned m_int_find_cube_period = 4; private: unsigned m_hnf_cut_period = 4; diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 455dd9240..8ae679e43 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -84,6 +84,7 @@ def_module_params(module_name='smt', ('arith.nl.optimize_bounds', BOOL, True, 'enable bounds optimization'), ('arith.nl.cross_nested', BOOL, True, 'enable cross-nested consistency checking'), ('arith.propagate_eqs', BOOL, True, 'propagate (cheap) equalities'), + ('arith.gomory_simplify', BOOL, False, 'simplify gomory term'), ('arith.propagation_mode', UINT, 1, '0 - no propagation, 1 - propagate existing literals, 2 - refine finite bounds'), ('arith.branch_cut_ratio', UINT, 2, 'branch/cut ratio for linear integer arithmetic'), ('arith.int_eq_branch', BOOL, False, 'branching using derived integer equations'), From 53c95e3627325dcae5a01cd3e01ec3f2c301a7e4 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 27 Dec 2023 15:18:48 -1000 Subject: [PATCH 062/224] cleanup --- src/math/lp/gomory.cpp | 6 +++--- src/math/lp/lp_settings.h | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index f5331ea05..89f518eee 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -261,7 +261,7 @@ public: lia_move cut() { TRACE("gomory_cut", dump(tout);); - m_polarity = 0; // 0: means undefined, 1, -1: the polar case, 2: the mixed case + m_polarity = 0; // 0: means undefined, +-1, the polar case, 2: the mixed case // gomory cut will be m_t >= m_k and the current solution has a property m_t < m_k m_k = 1; m_t.clear(); @@ -338,7 +338,7 @@ public: TRACE("gomory_cut", print_linear_combination_of_column_indices_only(m_t.coeffs_as_vector(), tout << "gomory cut: "); tout << " >= " << m_k << std::endl;); TRACE("gomory_cut_detail", dump_cut_and_constraints_as_smt_lemma(tout); lia.lra.display(tout)); - SASSERT(lia.current_solution_is_inf_on_cut()); // checks that indices are columns + SASSERT(lia.current_solution_is_inf_on_cut()); lia.settings().stats().m_gomory_cuts++; return lia_move::cut; @@ -522,9 +522,9 @@ public: struct polar_info {lpvar j; int polarity; u_dependency *dep;}; vector polar_vars; unsigned_vector columns_for_cuts = gomory_select_int_infeasible_vars(num_cuts); + bool has_small_cut = false; // define inline helper functions - bool has_small_cut = false; auto is_small_cut = [&](lar_term const& t) { return all_of(t, [&](auto ci) { return ci.coeff().is_small(); }); }; diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index fef30cb6d..2bed1b1af 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -215,7 +215,6 @@ public: bool backup_costs = true; unsigned column_number_threshold_for_using_lu_in_lar_solver = 4000; unsigned m_int_gomory_cut_period = 4; - bool m_gomory_simpliy = false; unsigned m_int_find_cube_period = 4; private: unsigned m_hnf_cut_period = 4; From ec2b8eb4ca914f7d73457744e9cbf0531c4018f1 Mon Sep 17 00:00:00 2001 From: Jakob Rath Date: Thu, 28 Dec 2023 20:11:53 +0100 Subject: [PATCH 063/224] Merge shared parts from polysat branch (#7063) * sat_literal: make constants constexpr * dlist: rename elem -> list * tbv: use get_bit * additional pdd and rational tests * egraph: callback setters take functions by value This allows to set callbacks without defining a separate variable for the callback lambda. (previous usage does one copy of the function, exactly as before) * cmake: enable compiler error when non-void function does not return value --- cmake/compiler_warnings.cmake | 2 ++ src/ast/euf/euf_egraph.h | 29 ++++++++++----------- src/test/pdd.cpp | 48 +++++++++++++++++++++++++++++++---- src/test/rational.cpp | 23 +++++++++++++++++ src/util/dlist.h | 19 +++++++------- src/util/sat_literal.h | 15 ++++++----- src/util/tbv.cpp | 8 ++---- 7 files changed, 101 insertions(+), 43 deletions(-) diff --git a/cmake/compiler_warnings.cmake b/cmake/compiler_warnings.cmake index 339c2e6f5..d631ee11a 100644 --- a/cmake/compiler_warnings.cmake +++ b/cmake/compiler_warnings.cmake @@ -30,6 +30,8 @@ set(MSVC_WARNINGS "/W3") set(GCC_AND_CLANG_WARNINGS_AS_ERRORS # https://clang.llvm.org/docs/DiagnosticsReference.html#wodr "-Werror=odr" + # https://clang.llvm.org/docs/DiagnosticsReference.html#wreturn-type + "-Werror=return-type" ) set(GCC_WARNINGS_AS_ERRORS "" diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index f2eedc21d..dd6c9b9da 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -192,8 +192,8 @@ namespace euf { enode_vector m_empty_enodes; unsigned m_num_scopes = 0; bool m_inconsistent = false; - enode *m_n1 = nullptr; - enode *m_n2 = nullptr; + enode* m_n1 = nullptr; + enode* m_n2 = nullptr; justification m_justification; unsigned m_new_th_eqs_qhead = 0; svector m_new_th_eqs; @@ -205,11 +205,11 @@ namespace euf { uint64_t m_congruence_timestamp = 0; std::vector> m_on_merge; - std::function m_on_propagate_literal; - std::function m_on_make; - std::function m_used_eq; - std::function m_used_cc; - std::function m_display_justification; + std::function m_on_propagate_literal; + std::function m_on_make; + std::function m_used_eq; + std::function m_used_cc; + std::function m_display_justification; void push_eq(enode* r1, enode* n1, unsigned r2_num_parents) { m_updates.push_back(update_record(r1, n1, r2_num_parents)); @@ -279,7 +279,6 @@ namespace euf { void merge(enode* n1, enode* n2, void* reason) { merge(n1, n2, justification::external(reason)); } void new_diseq(enode* n); - /** \brief propagate set of merges. This call may detect an inconsistency. Then inconsistent() is true. @@ -326,13 +325,13 @@ namespace euf { void set_relevant(enode* n); void set_default_relevant(bool b) { m_default_relevant = b; } - void set_on_merge(std::function& on_merge) { m_on_merge.push_back(on_merge); } - void set_on_propagate(std::function& on_propagate) { m_on_propagate_literal = on_propagate; } - void set_on_make(std::function& on_make) { m_on_make = on_make; } - void set_used_eq(std::function& used_eq) { m_used_eq = used_eq; } - void set_used_cc(std::function& used_cc) { m_used_cc = used_cc; } - void set_display_justification(std::function & d) { m_display_justification = d; } - + void set_on_merge(std::function on_merge) { m_on_merge.push_back(std::move(on_merge)); } + void set_on_propagate(std::function on_propagate) { m_on_propagate_literal = std::move(on_propagate); } + void set_on_make(std::function on_make) { m_on_make = std::move(on_make); } + void set_used_eq(std::function used_eq) { m_used_eq = std::move(used_eq); } + void set_used_cc(std::function used_cc) { m_used_cc = std::move(used_cc); } + void set_display_justification(std::function d) { m_display_justification = std::move(d); } + void begin_explain(); void end_explain(); bool uses_congruence() const { return m_uses_congruence; } diff --git a/src/test/pdd.cpp b/src/test/pdd.cpp index 0c9b0f85c..740ae4f2b 100644 --- a/src/test/pdd.cpp +++ b/src/test/pdd.cpp @@ -153,12 +153,49 @@ public: pdd b = m.mk_var(1); pdd c = m.mk_var(2); pdd d = m.mk_var(3); - pdd p = (a + b)*(c + 3*d) + 2; - std::cout << p << "\n"; - for (auto const& m : p) { - std::cout << m << "\n"; - } + + auto const check = [](unsigned const expected_num_monomials, pdd const& p) { + unsigned count = 0; + std::cout << p << "\n"; + for (auto const& m : p) { + std::cout << " " << m << "\n"; + ++count; + } + VERIFY_EQ(expected_num_monomials, count); + }; + + check(9, (a + b + 2)*(c + 3*d + 5) + 2); + check(5, (a + b)*(c + 3*d) + 2); + check(1, a); + check(2, a + 5); + check(1, m.mk_val(5)); + check(0, m.mk_val(0)); } + + static void linear_iterator() { + std::cout << "test linear iterator\n"; + pdd_manager m(4); + pdd a = m.mk_var(0); + pdd b = m.mk_var(1); + pdd c = m.mk_var(2); + pdd d = m.mk_var(3); + pdd p = (a + b + 2)*(c + 3*d + 5) + 2; + std::cout << p << "\n"; + for (auto const& m : p.linear_monomials()) + std::cout << " " << m << "\n"; + std::cout << a << "\n"; + for (auto const& m : a.linear_monomials()) + std::cout << " " << m << "\n"; + pdd one = m.mk_val(5); + std::cout << one << "\n"; + for (auto const& m : one.linear_monomials()) + std::cout << " " << m << "\n"; + pdd zero = m.mk_val(0); + std::cout << zero << "\n"; + for (auto const& m : zero.linear_monomials()) + std::cout << " " << m << "\n"; + } + static void order() { std::cout << "order\n"; pdd_manager m(4); @@ -693,6 +730,7 @@ void tst_pdd() { dd::test::canonize(); dd::test::reset(); dd::test::iterator(); + dd::test::linear_iterator(); dd::test::order(); dd::test::order_lm(); dd::test::mod4_operations(); diff --git a/src/test/rational.cpp b/src/test/rational.cpp index 711958de5..8fe565c62 100644 --- a/src/test/rational.cpp +++ b/src/test/rational.cpp @@ -466,6 +466,28 @@ static void tst12() { std::cout << i << ": " << r.get_bit(i) << "\n"; } +static void tst13() { + std::cout << "test13\n"; + rational const step = rational(1) / rational(3); + for (rational r; r < 5000; r += step) { + { + unsigned k = r.prev_power_of_two(); + if (r >= 1) { + VERIFY(rational::power_of_two(k) <= r); + VERIFY(r < rational::power_of_two(k + 1)); + } + else { + VERIFY_EQ(k, 0); + } + } + { + unsigned k = r.next_power_of_two(); + VERIFY(r <= rational::power_of_two(k)); + VERIFY(k == 0 || rational::power_of_two(k - 1) < r); + } + } +} + void tst_rational() { TRACE("rational", tout << "starting rational test...\n";); @@ -492,4 +514,5 @@ void tst_rational() { tst10(true); tst10(false); tst12(); + tst13(); } diff --git a/src/util/dlist.h b/src/util/dlist.h index 07aefa97e..4c0e51e58 100644 --- a/src/util/dlist.h +++ b/src/util/dlist.h @@ -188,14 +188,14 @@ class dll_iterator { dll_iterator(T const* elem, bool first): m_elem(elem), m_first(first) { } public: - static dll_iterator mk_begin(T const* elem) { - // Setting first==(bool)elem makes this also work for elem==nullptr; + static dll_iterator mk_begin(T const* list) { + // Setting first==(bool)list makes this also work for list==nullptr; // but we can't implement top-level begin/end for pointers because it clashes with the definition for arrays. - return {elem, (bool)elem}; + return {list, (bool)list}; } - static dll_iterator mk_end(T const* elem) { - return {elem, false}; + static dll_iterator mk_end(T const* list) { + return {list, false}; } using value_type = T; @@ -232,18 +232,17 @@ public: dll_iterator end() const { return dll_iterator::mk_end(m_list); } }; - template < typename T , typename U = std::enable_if_t, T>> // should only match if T actually inherits from dll_base > -dll_iterator begin(T const& elem) { - return dll_iterator::mk_begin(&elem); +dll_iterator begin(T const& list) { + return dll_iterator::mk_begin(&list); } template < typename T , typename U = std::enable_if_t, T>> // should only match if T actually inherits from dll_base > -dll_iterator end(T const& elem) +dll_iterator end(T const& list) { - return dll_iterator::mk_end(&elem); + return dll_iterator::mk_end(&list); } diff --git a/src/util/sat_literal.h b/src/util/sat_literal.h index aeb23bddd..58088e628 100644 --- a/src/util/sat_literal.h +++ b/src/util/sat_literal.h @@ -30,7 +30,7 @@ namespace sat { typedef svector bool_var_vector; - const bool_var null_bool_var = UINT_MAX >> 1; + inline constexpr bool_var null_bool_var = UINT_MAX >> 1; /** \brief The literal b is represented by the value 2*b, and @@ -39,9 +39,7 @@ namespace sat { class literal { unsigned m_val; public: - literal():m_val(null_bool_var << 1) { - SASSERT(var() == null_bool_var && !sign()); - } + constexpr literal(): m_val(null_bool_var << 1) { } explicit literal(bool_var v, bool _sign = false): m_val((v << 1) + static_cast(_sign)) { @@ -49,11 +47,11 @@ namespace sat { SASSERT(sign() == _sign); } - bool_var var() const { + constexpr bool_var var() const { return m_val >> 1; } - bool sign() const { + constexpr bool sign() const { return m_val & 1ul; } @@ -86,7 +84,10 @@ namespace sat { friend bool operator!=(literal const & l1, literal const & l2); }; - const literal null_literal; + inline constexpr literal null_literal; + static_assert(null_literal.var() == null_bool_var); + static_assert(!null_literal.sign()); + using literal_hash = obj_hash; inline literal to_literal(unsigned x) { literal l; l.m_val = x; return l; } diff --git a/src/util/tbv.cpp b/src/util/tbv.cpp index 017ca0eb7..5048267ad 100644 --- a/src/util/tbv.cpp +++ b/src/util/tbv.cpp @@ -142,12 +142,8 @@ void tbv_manager::set(tbv& dst, rational const& r, unsigned hi, unsigned lo) { set(dst, r.get_uint64(), hi, lo); return; } - for (unsigned i = 0; i < hi - lo + 1; ++i) { - if (bitwise_and(r, rational::power_of_two(i)).is_zero()) - set(dst, lo + i, BIT_0); - else - set(dst, lo + i, BIT_1); - } + for (unsigned i = 0; i < hi - lo + 1; ++i) + set(dst, lo + i, r.get_bit(i) ? BIT_1 : BIT_0); } void tbv_manager::set(tbv& dst, tbv const& other, unsigned hi, unsigned lo) { From d66df2616f7523e991e779dc7896a482bb4d3482 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 29 Dec 2023 10:20:06 -0500 Subject: [PATCH 064/224] Fix some typos. (#7075) --- RELEASE_NOTES.md | 2 +- src/ast/euf/euf_ac_plugin.cpp | 6 +++--- src/ast/euf/euf_ac_plugin.h | 2 +- src/ast/euf/euf_arith_plugin.cpp | 2 +- src/ast/euf/euf_arith_plugin.h | 2 +- src/ast/euf/euf_bv_plugin.cpp | 2 +- src/muz/rel/dl_mk_similarity_compressor.cpp | 2 +- src/smt/theory_seq.cpp | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index a10af72a6..ffbe6061c 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -16,7 +16,7 @@ Version 4.12.5 - A new theory solver "int-blast" enabled by using: - sat.smt=true smt.bv.solver=2 - It solves a few bit-vector problems not handled by bit-blasting, especially if the bit-widths are large. - - It is based on encoding bit-vector constraints to non-linear integer arithemtic. + - It is based on encoding bit-vector constraints to non-linear integer arithmetic. Version 4.12.4 diff --git a/src/ast/euf/euf_ac_plugin.cpp b/src/ast/euf/euf_ac_plugin.cpp index 5b4b1df66..ce0817e00 100644 --- a/src/ast/euf/euf_ac_plugin.cpp +++ b/src/ast/euf/euf_ac_plugin.cpp @@ -59,9 +59,9 @@ TODOs: - The shared terms hash table is not incremental. It could be made incremental by updating it on every merge similar to how the egraph handles it. - V2 using multiplicities instead of repeated values in monomials. -- Squash trail updates when equations or monomials are modified within the same epoque. - - by an epoque counter that can be updated by the egraph class whenever there is a push/pop. - - store the epoque as a tick on equations and possibly when updating monomials on equations. +- Squash trail updates when equations or monomials are modified within the same epoch. + - by an epoch counter that can be updated by the egraph class whenever there is a push/pop. + - store the epoch as a tick on equations and possibly when updating monomials on equations. --*/ diff --git a/src/ast/euf/euf_ac_plugin.h b/src/ast/euf/euf_ac_plugin.h index ea444b60c..911f539f9 100644 --- a/src/ast/euf/euf_ac_plugin.h +++ b/src/ast/euf/euf_ac_plugin.h @@ -40,7 +40,7 @@ namespace euf { struct node { enode* n; // associated enode node* root; // path compressed root - node* next; // next in equaivalence class + node* next; // next in equivalence class justification j; // justification for equality node* target = nullptr; // justified next unsigned_vector shared; // shared occurrences diff --git a/src/ast/euf/euf_arith_plugin.cpp b/src/ast/euf/euf_arith_plugin.cpp index 26f8e0bd9..268eff38d 100644 --- a/src/ast/euf/euf_arith_plugin.cpp +++ b/src/ast/euf/euf_arith_plugin.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - plugin structure for arithetic + plugin structure for arithmetic Author: diff --git a/src/ast/euf/euf_arith_plugin.h b/src/ast/euf/euf_arith_plugin.h index 7cca01f1c..cbdb51bef 100644 --- a/src/ast/euf/euf_arith_plugin.h +++ b/src/ast/euf/euf_arith_plugin.h @@ -7,7 +7,7 @@ Module Name: Abstract: - plugin structure for arithetic + plugin structure for arithmetic Author: Nikolaj Bjorner (nbjorner) 2023-11-11 diff --git a/src/ast/euf/euf_bv_plugin.cpp b/src/ast/euf/euf_bv_plugin.cpp index 89b5ade16..6631d9e50 100644 --- a/src/ast/euf/euf_bv_plugin.cpp +++ b/src/ast/euf/euf_bv_plugin.cpp @@ -69,7 +69,7 @@ The formal properties of saturation have to be established. - Saturation does not complete with respect to associativity. Instead the claim is along the lines that the resulting E-graph can be used as a canonizer. If given a set of equations E that are saturated, and terms t1, t2 that are -both simplified with respect to left-associativity of concatentation, and t1, t2 belong to the E-graph, +both simplified with respect to left-associativity of concatenation, and t1, t2 belong to the E-graph, then t1 = t2 iff t1 ~ t2 in the E-graph. TODO: Is saturation for (7) overkill for the purpose of canonization? diff --git a/src/muz/rel/dl_mk_similarity_compressor.cpp b/src/muz/rel/dl_mk_similarity_compressor.cpp index ea1ef42b5..46415a0de 100644 --- a/src/muz/rel/dl_mk_similarity_compressor.cpp +++ b/src/muz/rel/dl_mk_similarity_compressor.cpp @@ -101,7 +101,7 @@ namespace datalog { /** \brief Return 0 if r1 and r2 could be similar. If the rough similarity - equaivelance class of r1 is greater than the one of r2, return 1; otherwise return -1. + equivalence class of r1 is greater than the one of r2, return 1; otherwise return -1. Two rules are in the same rough similarity class if they differ only in constant arguments of positive uninterpreted predicates. diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 02c0c456b..d27d7ba54 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1244,7 +1244,7 @@ bool theory_seq::get_length(expr* e, expr_ref& len, literal_vector& lits) { /** * solve for fold/map (recursive function that depends on a sequence) - * Assumption: the Seq argument of fold/map expands into a concatentation of units + * Assumption: the Seq argument of fold/map expands into a concatenation of units * The assumption is enforced by tracking the length of the seq argument. * This is ensured in relevant_eh. * Under the assumption, evern occurrence of fold/map gets simplified by expanding From fd2b6c62d1e909317d786611bfb2d24d615ae4a2 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 31 Dec 2023 14:22:36 -1000 Subject: [PATCH 065/224] bug fix in gomory polarity Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.cpp | 53 ++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 89f518eee..0f57ced55 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -91,6 +91,12 @@ struct create_cut { #endif } + void set_polarity(int p) { + if (m_polarity == 2) return; + if (m_polarity == 0) m_polarity = p; + else if (m_polarity != p) m_polarity = 2; + } + void real_case_in_gomory_cut(const mpq & a, unsigned j) { TRACE("gomory_cut_detail_real", tout << "j = " << j << ", a = " << a << ", m_k = " << m_k << "\n";); mpq new_a; @@ -98,18 +104,12 @@ struct create_cut { if (a.is_pos()) { // the delta is a (x - f) is positive it has to grow and fight m_one_minus_f new_a = a / m_one_minus_f; - if (m_polarity != 2) { - if (m_polarity == -1) m_polarity = 2; - else m_polarity = 1; - } + set_polarity(1); } else { // the delta is negative and it works again m_f new_a = - a / m_f; - if (m_polarity != 2) { - if (m_polarity == 1) m_polarity = 2; - else m_polarity = -1; - } + set_polarity(-1); } m_k.addmul(new_a, lower_bound(j).x); // is it a faster operation than // k += lower_bound(j).x * new_a; @@ -120,18 +120,12 @@ struct create_cut { if (a.is_pos()) { // the delta is works again m_f new_a = - a / m_f; - if (m_polarity != 2) { - if (m_polarity == 1) m_polarity = 2; - else m_polarity = -1; - } + set_polarity(-1); } else { // the delta is positive works again m_one_minus_f new_a = a / m_one_minus_f; - if (m_polarity != 2) { - if (m_polarity == -1) m_polarity = 2; - else m_polarity = 1; - } + set_polarity(1); } m_k.addmul(new_a, upper_bound(j).x); // k += upper_bound(j).x * new_a; push_explanation(column_upper_bound_constraint(j)); @@ -299,24 +293,16 @@ public: m_one_minus_fj = 1 - m_fj; int_case_in_gomory_cut(j); if (p.coeff().is_pos()) { - if (at_lower(j)) { - if (m_polarity == -1) m_polarity = 2; - else m_polarity = 1; - } - else { - if (m_polarity == 1) m_polarity = 2; - else m_polarity = -1; - } + if (at_lower(j)) + set_polarity(1); + else + set_polarity(-1); } else { - if (at_lower(j)) { - if (m_polarity == 1) m_polarity = 2; - else m_polarity = -1; - } - else { - if (m_polarity == -1) m_polarity = 2; - else m_polarity = 1; - } + if (at_lower(j)) + set_polarity(-1); + else + set_polarity(1); } } @@ -325,8 +311,9 @@ public: } } - if (m_t.is_empty()) + if (m_t.is_empty()) { return report_conflict_from_gomory_cut(); + } TRACE("gomory_cut", print_linear_combination_of_column_indices_only(m_t.coeffs_as_vector(), tout << "gomory cut: "); tout << " >= " << m_k << std::endl;); if (lia.lra.settings().m_gomory_simplify && some_int_columns) simplify_inequality(); From 84997f8b21ec6d4c63d6b3fad21953ff22624b46 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 31 Dec 2023 20:58:26 -1000 Subject: [PATCH 066/224] move a TRACE statement --- src/math/lp/gomory.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 0f57ced55..7916f66f7 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -322,7 +322,6 @@ public: for (auto c : *m_ex) m_dep = lia.lra.join_deps(lia.lra.dep_manager().mk_leaf(c.ci()), m_dep); - TRACE("gomory_cut", print_linear_combination_of_column_indices_only(m_t.coeffs_as_vector(), tout << "gomory cut: "); tout << " >= " << m_k << std::endl;); TRACE("gomory_cut_detail", dump_cut_and_constraints_as_smt_lemma(tout); lia.lra.display(tout)); SASSERT(lia.current_solution_is_inf_on_cut()); From a7bfdcd0ea4d9d4b6b080e3140e6e01836212806 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 2 Jan 2024 11:17:59 -0800 Subject: [PATCH 067/224] readd big cuts Signed-off-by: Nikolaj Bjorner --- src/math/lp/gomory.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 7916f66f7..dbe1194cb 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -561,11 +561,10 @@ public: bool feas = _check_feasible(); lra.pop(1); - if (lia.settings().get_cancel_flag()) - return lia_move::undef; - - if (!feas) - return lia_move::conflict; + if (!feas) + for (auto const& cut : big_cuts) + add_cut(cut); + } // this way we create bounds for the variables in polar cases even where the terms had big numbers From b75367ffc70ae6a950ba51c0f40d822ec42bc4e3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 3 Jan 2024 13:57:09 -0800 Subject: [PATCH 068/224] port improvements to arith rewriter Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 55 +++++++++++++++-------------- src/ast/rewriter/arith_rewriter.h | 2 +- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 635d5a3f2..658ca4110 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -1119,7 +1119,7 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu return BR_REWRITE3; } } - if (divides(arg1, arg2, result)) { + if (get_divides(arg1, arg2, result)) { expr_ref zero(m_util.mk_int(0), m); result = m.mk_ite(m.mk_eq(zero, arg2), m_util.mk_idiv(arg1, zero), result); return BR_REWRITE_FULL; @@ -1137,7 +1137,7 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu // // implement div ab ac = floor( ab / ac) = floor (b / c) = div b c // -bool arith_rewriter::divides(expr* num, expr* den, expr_ref& result) { +bool arith_rewriter::get_divides(expr* num, expr* den, expr_ref& result) { expr_fast_mark1 mark; rational num_r(1), den_r(1); expr* num_e = nullptr, *den_e = nullptr; @@ -1229,23 +1229,25 @@ static rational symmod(rational const& a, rational const& b) { if (2*r > b) r -= b; return r; } - + br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & result) { set_curr_sort(arg1->get_sort()); - numeral x, y; - bool is_num_x = m_util.is_numeral(arg1, x); - bool is_num_y = m_util.is_numeral(arg2, y); - if (is_num_x && is_num_y && !y.is_zero()) { - result = m_util.mk_int(mod(x, y)); + numeral v1, v2; + bool is_int; + bool is_num1 = m_util.is_numeral(arg1, v1, is_int); + bool is_num2 = m_util.is_numeral(arg2, v2, is_int); + + if (is_num1 && is_num2 && !v2.is_zero()) { + result = m_util.mk_numeral(mod(v1, v2), is_int); return BR_DONE; } - if (is_num_y && y.is_int() && (y.is_one() || y.is_minus_one())) { + if (is_num2 && is_int && (v2.is_one() || v2.is_minus_one())) { result = m_util.mk_numeral(numeral(0), true); return BR_DONE; } - if (arg1 == arg2 && !is_num_y) { + if (arg1 == arg2 && !is_num2) { expr_ref zero(m_util.mk_int(0), m); result = m.mk_ite(m.mk_eq(arg2, zero), m_util.mk_mod(zero, zero), zero); return BR_DONE; @@ -1253,46 +1255,45 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul // mod is idempotent on non-zero modulus. expr* t1, *t2; - if (m_util.is_mod(arg1, t1, t2) && t2 == arg2 && is_num_y && y.is_int() && !y.is_zero()) { - result = arg1; - return BR_DONE; - } - - rational lo, hi; - if (is_num_y && get_range(arg1, lo, hi) && 0 <= lo && hi < y) { + if (m_util.is_mod(arg1, t1, t2) && t2 == arg2 && is_num2 && is_int && !v2.is_zero()) { result = arg1; return BR_DONE; } // propagate mod inside only if there is something to reduce. - if (is_num_y && y.is_int() && y.is_pos() && (is_add(arg1) || is_mul(arg1))) { + if (is_num2 && is_int && v2.is_pos() && (is_add(arg1) || is_mul(arg1))) { TRACE("mod_bug", tout << "mk_mod:\n" << mk_ismt2_pp(arg1, m) << "\n" << mk_ismt2_pp(arg2, m) << "\n";); expr_ref_buffer args(m); bool change = false; for (expr* arg : *to_app(arg1)) { rational arg_v; - if (m_util.is_numeral(arg, arg_v) && mod(arg_v, y) != arg_v) { + if (m_util.is_numeral(arg, arg_v) && mod(arg_v, v2) != arg_v) { change = true; - args.push_back(m_util.mk_numeral(mod(arg_v, y), true)); + args.push_back(m_util.mk_numeral(mod(arg_v, v2), true)); } else if (m_util.is_mod(arg, t1, t2) && t2 == arg2) { change = true; args.push_back(t1); } - else if (m_util.is_mul(arg, t1, t2) && m_util.is_numeral(t1, arg_v) && symmod(arg_v, y) != arg_v) { + else if (m_util.is_mul(arg, t1, t2) && m_util.is_numeral(t1, arg_v) && symmod(arg_v, v2) != arg_v) { change = true; - args.push_back(m_util.mk_mul(m_util.mk_numeral(symmod(arg_v, y), true), t2)); + args.push_back(m_util.mk_mul(m_util.mk_numeral(symmod(arg_v, v2), true), t2)); } else { args.push_back(arg); } } - if (!change) { - return BR_FAILED; // did not find any target for applying simplification + if (change) { + result = m_util.mk_mod(m.mk_app(to_app(arg1)->get_decl(), args.size(), args.data()), arg2); + TRACE("mod_bug", tout << "mk_mod result: " << mk_ismt2_pp(result, m) << "\n";); + return BR_REWRITE3; } - result = m_util.mk_mod(m.mk_app(to_app(arg1)->get_decl(), args.size(), args.data()), arg2); - TRACE("mod_bug", tout << "mk_mod result: " << mk_ismt2_pp(result, m) << "\n";); - return BR_REWRITE3; + } + + expr* x, *y; + if (is_num2 && v2.is_pos() && m_util.is_mul(arg1, x, y) && m_util.is_numeral(x, v1, is_int) && divides(v1, v2)) { + result = m_util.mk_mul(x, m_util.mk_mod(y, m_util.mk_int(v2/v1))); + return BR_REWRITE1; } return BR_FAILED; diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index a9a30fe00..01fea0ac7 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -104,7 +104,7 @@ class arith_rewriter : public poly_rewriter { expr_ref neg_monomial(expr * e); expr * mk_sin_value(rational const & k); app * mk_sqrt(rational const & k); - bool divides(expr* d, expr* n, expr_ref& result); + bool get_divides(expr* d, expr* n, expr_ref& result); expr_ref remove_divisor(expr* arg, expr* num, expr* den); void flat_mul(expr* e, ptr_buffer& args); void remove_divisor(expr* d, ptr_buffer& args); From 239d68ed9cb439fe8c8f6501151bbf6543525224 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 3 Jan 2024 18:56:35 -1000 Subject: [PATCH 069/224] return conflict on an empty term in Gomory cuts --- src/math/lp/gomory.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index dbe1194cb..e4736691b 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -538,8 +538,11 @@ public: create_cut cc(lia.m_t, lia.m_k, lia.m_ex, j, row, lia); auto r = cc.cut(); - if (r != lia_move::cut) + if (r != lia_move::cut) { + if (r == lia_move::conflict) + return lia_move::conflict; continue; + } cut_result cr = {cc.m_dep, lia.m_t, lia.m_k, cc.m_polarity, j}; if (abs(cr.polarity) == 1) // need to delay the update of the bounds for j in a polar case, because simplify_inequality relies on the old bounds polar_vars.push_back( {j, cr.polarity, cc.m_dep} ); From 696b70fddbf5017f3c883f9d874ba78ff1e71da7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 4 Jan 2024 10:59:59 -0800 Subject: [PATCH 070/224] fix Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/arith_rewriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 658ca4110..f21a5c4be 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -1291,8 +1291,8 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul } expr* x, *y; - if (is_num2 && v2.is_pos() && m_util.is_mul(arg1, x, y) && m_util.is_numeral(x, v1, is_int) && divides(v1, v2)) { - result = m_util.mk_mul(x, m_util.mk_mod(y, m_util.mk_int(v2/v1))); + if (is_num2 && v2.is_pos() && m_util.is_mul(arg1, x, y) && m_util.is_numeral(x, v1, is_int) && v1 > 0 && divides(v1, v2)) { + result = m_util.mk_mul(m_util.mk_int(v1), m_util.mk_mod(y, m_util.mk_int(v2/v1))); return BR_REWRITE1; } From 2934618c50bc85d94f6f201e62c1581e1a9fce01 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 4 Jan 2024 11:40:57 -1000 Subject: [PATCH 071/224] remove simplify_inequality from gomory.cpp --- src/math/lp/gomory.cpp | 111 +-------------------------- src/math/lp/lp_settings.cpp | 1 - src/math/lp/lp_settings.h | 1 - src/smt/params/smt_params_helper.pyg | 1 - 4 files changed, 2 insertions(+), 112 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index e4736691b..ba0e69558 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -22,7 +22,6 @@ #include "math/lp/lar_solver.h" #include "math/lp/lp_utils.h" -#define SMALL_CUTS 1 namespace lp { struct create_cut { @@ -36,9 +35,7 @@ struct create_cut { mpq m_one_minus_f; mpq m_fj; mpq m_one_minus_fj; -#if SMALL_CUTS mpq m_abs_max, m_big_number; -#endif int m_polarity; bool m_found_big; u_dependency* m_dep; @@ -84,11 +81,8 @@ struct create_cut { } m_t.add_monomial(new_a, j); TRACE("gomory_cut_detail", tout << "new_a = " << new_a << ", k = " << m_k << "\n";); -#if SMALL_CUTS - // if (numerator(new_a).is_big()) throw found_big(); if (numerator(new_a) > m_big_number) m_found_big = true; -#endif } void set_polarity(int p) { @@ -134,11 +128,8 @@ struct create_cut { TRACE("gomory_cut_detail_real", tout << "add " << new_a << "*v" << j << ", k: " << m_k << "\n"; tout << "m_t = "; lia.lra.print_term(m_t, tout) << "\nk: " << m_k << "\n";); -#if SMALL_CUTS - // if (numerator(new_a).is_big()) throw found_big(); if (numerator(new_a) > m_big_number) m_found_big = true; -#endif } lia_move report_conflict_from_gomory_cut() { @@ -265,8 +256,6 @@ public: tout << "1 - m_f: " << 1 - m_f << ", get_value(m_inf_col).x - m_f = " << get_value(m_inf_col).x - m_f << "\n";); lp_assert(m_f.is_pos() && (get_value(m_inf_col).x - m_f).is_int()); - bool some_int_columns = false; -#if SMALL_CUTS m_abs_max = 0; for (const auto & p : m_row) { mpq t = abs(ceil(p.coeff())); @@ -274,7 +263,7 @@ public: m_abs_max = t; } m_big_number = m_abs_max.expt(2); -#endif + for (const auto & p : m_row) { unsigned j = p.var(); if (j == m_inf_col) continue; @@ -288,7 +277,6 @@ public: if (is_real(j)) real_case_in_gomory_cut(- p.coeff(), j); else if (!p.coeff().is_int()) { - some_int_columns = true; m_fj = fractional_part(-p.coeff()); m_one_minus_fj = 1 - m_fj; int_case_in_gomory_cut(j); @@ -315,8 +303,6 @@ public: return report_conflict_from_gomory_cut(); } TRACE("gomory_cut", print_linear_combination_of_column_indices_only(m_t.coeffs_as_vector(), tout << "gomory cut: "); tout << " >= " << m_k << std::endl;); - if (lia.lra.settings().m_gomory_simplify && some_int_columns) - simplify_inequality(); m_dep = nullptr; for (auto c : *m_ex) @@ -330,99 +316,6 @@ public: return lia_move::cut; } - // TODO: use this also for HNF cuts? - mpq m_lcm_den = { mpq(1) }; - - void simplify_inequality() { - - auto divd = [](mpq& r, mpq const& d) { - r /= d; - if (!r.is_int()) - r = ceil(r); - }; - SASSERT(!lia.m_upper); - lp_assert(!m_t.is_empty()); - // k = 1 + sum of m_t at bounds - lar_term t = lia.lra.unfold_nested_subterms(m_t); - auto pol = t.coeffs_as_vector(); - m_t.clear(); - if (pol.size() == 1 && is_int(pol[0].second)) { - TRACE("gomory_cut_detail", tout << "pol.size() is 1" << std::endl;); - auto const& [a, v] = pol[0]; - lp_assert(is_int(v)); - if (a.is_pos()) { // we have av >= k - divd(m_k, a); - m_t.add_monomial(mpq(1), v); - } - else { - // av >= k - // a/-a*v >= k / - a - // -v >= k / - a - // -v >= ceil(k / -a) - divd(m_k, -a); - m_t.add_monomial(-mpq(1), v); - } - } - else { - m_lcm_den = denominator(m_k); - for (auto const& [c, v] : pol) - m_lcm_den = lcm(m_lcm_den, denominator(c)); - lp_assert(m_lcm_den.is_pos()); - bool int_row = all_of(pol, [&](auto const& kv) { return is_int(kv.second); }); - TRACE("gomory_cut_detail", tout << "pol.size() > 1 den: " << m_lcm_den << std::endl;); - - if (!m_lcm_den.is_one()) { - // normalize coefficients of integer parameters to be integers. - for (auto & [c,v]: pol) { - c *= m_lcm_den; - SASSERT(!is_int(v) || c.is_int()); - } - m_k *= m_lcm_den; - } - // ax + by >= k - // b > 0, c1 <= y <= c2 - // ax + b*c2 >= ax + by >= k - // => - // ax >= k - by >= k - b*c1 - // b < 0 - // ax + b*c1 >= ax + by >= k - // - unsigned j = 0, i = 0; - for (auto & [c, v] : pol) { - if (lia.is_fixed(v)) { - push_explanation(column_lower_bound_constraint(v)); - push_explanation(column_upper_bound_constraint(v)); - m_k -= c * lower_bound(v).x; - } - else - pol[j++] = pol[i]; - ++i; - } - pol.shrink(j); - - // gcd reduction is loss-less: - mpq g(1); - for (const auto & [c, v] : pol) - g = gcd(g, c); - if (!int_row) - g = gcd(g, m_k); - - if (g != 1) { - for (auto & [c, v] : pol) - c /= g; - divd(m_k, g); - } - - for (const auto & [c, v]: pol) - m_t.add_monomial(c, v); - VERIFY(m_t.size() > 0); - } - - TRACE("gomory_cut_detail", tout << "k = " << m_k << std::endl;); - lp_assert(m_k.is_int()); - } - - create_cut(lar_term & t, mpq & k, explanation* ex, unsigned basic_inf_int_j, const row_strip& row, int_solver& lia) : m_t(t), m_k(k), @@ -570,7 +463,7 @@ public: } -// this way we create bounds for the variables in polar cases even where the terms had big numbers +// this way we create bounds for the variables in polar cases even where the terms have big numbers for (auto const& p : polar_vars) { if (p.polarity == 1) { lra.update_column_type_and_bound(p.j, lp::lconstraint_kind::LE, floor(lra.get_column_value(p.j).x), p.dep); diff --git a/src/math/lp/lp_settings.cpp b/src/math/lp/lp_settings.cpp index 71193914f..b72b837fd 100644 --- a/src/math/lp/lp_settings.cpp +++ b/src/math/lp/lp_settings.cpp @@ -32,5 +32,4 @@ void lp::lp_settings::updt_params(params_ref const& _p) { report_frequency = p.arith_rep_freq(); m_simplex_strategy = static_cast(p.arith_simplex_strategy()); m_nlsat_delay = p.arith_nl_delay(); - m_gomory_simplify = p.arith_gomory_simplify(); } diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index 2bed1b1af..a0cb485b5 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -187,7 +187,6 @@ private: random_gen m_rand; public: - bool m_gomory_simplify = false; void updt_params(params_ref const& p); bool enable_hnf() const { return m_enable_hnf; } unsigned nlsat_delay() const { return m_nlsat_delay; } diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 8ae679e43..455dd9240 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -84,7 +84,6 @@ def_module_params(module_name='smt', ('arith.nl.optimize_bounds', BOOL, True, 'enable bounds optimization'), ('arith.nl.cross_nested', BOOL, True, 'enable cross-nested consistency checking'), ('arith.propagate_eqs', BOOL, True, 'propagate (cheap) equalities'), - ('arith.gomory_simplify', BOOL, False, 'simplify gomory term'), ('arith.propagation_mode', UINT, 1, '0 - no propagation, 1 - propagate existing literals, 2 - refine finite bounds'), ('arith.branch_cut_ratio', UINT, 2, 'branch/cut ratio for linear integer arithmetic'), ('arith.int_eq_branch', BOOL, False, 'branching using derived integer equations'), From 75005d907725f0c2d4e2f6cf1ebe15ab9d6352c7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 9 Jan 2024 09:18:29 -0800 Subject: [PATCH 072/224] add validation option for debugging regressions Signed-off-by: Nikolaj Bjorner --- src/smt/params/smt_params_helper.pyg | 1 + src/smt/params/theory_arith_params.cpp | 2 ++ src/smt/params/theory_arith_params.h | 1 + src/smt/theory_lra.cpp | 16 ++++++++++------ 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 455dd9240..6ec362449 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -99,6 +99,7 @@ def_module_params(module_name='smt', ('arith.enable_hnf', BOOL, True, 'enable hnf (Hermite Normal Form) cuts'), ('arith.bprop_on_pivoted_rows', BOOL, True, 'propagate bounds on rows changed by the pivot operation'), ('arith.print_ext_var_names', BOOL, False, 'print external variable names'), + ('arith.validate', BOOL, False, 'validate lemmas generated by arithmetic solver'), ('pb.conflict_frequency', UINT, 1000, 'conflict frequency for Pseudo-Boolean theory'), ('pb.learn_complements', BOOL, True, 'learn complement literals for Pseudo-Boolean theory'), ('array.weak', BOOL, False, 'weak array theory'), diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index 9bc830dd1..fef7508f4 100644 --- a/src/smt/params/theory_arith_params.cpp +++ b/src/smt/params/theory_arith_params.cpp @@ -36,6 +36,7 @@ void theory_arith_params::updt_params(params_ref const & _p) { m_arith_bound_prop = static_cast(p.arith_propagation_mode()); m_arith_eager_eq_axioms = p.arith_eager_eq_axioms(); m_arith_auto_config_simplex = p.arith_auto_config_simplex(); + m_arith_validate = p.arith_validate(); m_nl_arith_propagate_linear_monomials = p.arith_nl_propagate_linear_monomials(); m_nl_arith_optimize_bounds = p.arith_nl_optimize_bounds(); m_nl_arith_cross_nested = p.arith_nl_cross_nested(); @@ -95,4 +96,5 @@ void theory_arith_params::display(std::ostream & out) const { DISPLAY_PARAM(m_nl_arith_propagate_linear_monomials); DISPLAY_PARAM(m_nl_arith_optimize_bounds); DISPLAY_PARAM(m_nl_arith_cross_nested); + DISPLAY_PARAM(m_arith_validate); } diff --git a/src/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index f19544157..0a6b9edca 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -82,6 +82,7 @@ struct theory_arith_params { bool m_arith_adaptive_gcd = false; unsigned m_arith_propagation_threshold = UINT_MAX; + bool m_arith_validate = false; arith_pivot_strategy m_arith_pivot_strategy = arith_pivot_strategy::ARITH_PIVOT_SMALLEST; // used in diff-logic diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 8669a514c..b8c95e5c6 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2389,7 +2389,9 @@ public: literal_vector m_core2; - void assign(literal lit, literal_vector const& core, svector const& eqs, vector const& params) { + void assign(literal lit, literal_vector const& core, svector const& eqs, vector const& ps) { + if (params().m_arith_validate) + VERIFY(validate_assign(lit, core, eqs)); if (core.size() < small_lemma_size() && eqs.empty()) { m_core2.reset(); for (auto const& c : core) { @@ -2399,7 +2401,7 @@ public: justification * js = nullptr; if (proofs_enabled()) { js = alloc(theory_lemma_justification, get_id(), ctx(), m_core2.size(), m_core2.data(), - params.size(), params.data()); + ps.size(), ps.data()); } ctx().mk_clause(m_core2.size(), m_core2.data(), js, CLS_TH_LEMMA, nullptr); } @@ -2408,7 +2410,7 @@ public: lit, ctx().mk_justification( ext_theory_propagation_justification( get_id(), ctx(), core.size(), core.data(), - eqs.size(), eqs.data(), lit, params.size(), params.data()))); + eqs.size(), eqs.data(), lit, ps.size(), ps.data()))); } } @@ -3138,7 +3140,8 @@ public: std::function fn = [&]() { return m.mk_eq(x->get_expr(), y->get_expr()); }; scoped_trace_stream _sts(th, fn); - // VERIFY(validate_eq(x, y)); + if (params().m_arith_validate) + VERIFY(validate_eq(x, y)); ctx().assign_eq(x, y, eq_justification(js)); } @@ -3252,8 +3255,9 @@ public: for (auto ev : m_explanation) set_evidence(ev.ci(), m_core, m_eqs); - - // VERIFY(validate_conflict(m_core, m_eqs)); + + if (params().m_arith_validate) + VERIFY(validate_conflict(m_core, m_eqs)); if (is_conflict) { ctx().set_conflict( ctx().mk_justification( From 2ca1187b3ad5308c824d37dab5dfe310eacc1029 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 10 Jan 2024 10:50:56 -1000 Subject: [PATCH 073/224] fix a bug in polarity Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index ba0e69558..cefd9767f 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -276,10 +276,12 @@ public: } if (is_real(j)) real_case_in_gomory_cut(- p.coeff(), j); - else if (!p.coeff().is_int()) { - m_fj = fractional_part(-p.coeff()); - m_one_minus_fj = 1 - m_fj; - int_case_in_gomory_cut(j); + else { + if (!p.coeff().is_int()) { + m_fj = fractional_part(-p.coeff()); + m_one_minus_fj = 1 - m_fj; + int_case_in_gomory_cut(j); + } if (p.coeff().is_pos()) { if (at_lower(j)) set_polarity(1); From 955c80e98bbda9df668eef218705f218d44a3850 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 10 Jan 2024 19:42:58 -0800 Subject: [PATCH 074/224] import updates from poly branch Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.h | 1 + src/ast/euf/euf_bv_plugin.cpp | 162 ++++++++++----- src/ast/euf/euf_bv_plugin.h | 27 ++- src/ast/euf/euf_egraph.cpp | 6 +- src/ast/euf/euf_egraph.h | 31 +-- src/sat/smt/arith_axioms.cpp | 29 +-- src/sat/smt/intblast_solver.cpp | 358 +++++++++++++++++++++----------- src/sat/smt/intblast_solver.h | 11 +- 8 files changed, 408 insertions(+), 217 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 308bc1326..3f094d43f 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -401,6 +401,7 @@ public: // return true if \c n is a term of the form (* -1 r) bool is_zero(expr const* n) const { rational val; return is_numeral(n, val) && val.is_zero(); } + bool is_one(expr const* n) const{ rational val; return is_numeral(n, val) && val.is_one(); } bool is_minus_one(expr* n) const { rational tmp; return is_numeral(n, tmp) && tmp.is_minus_one(); } bool is_times_minus_one(expr* n, expr*& r) const { if (is_mul(n) && to_app(n)->get_num_args() == 2 && is_minus_one(to_app(n)->get_arg(0))) { diff --git a/src/ast/euf/euf_bv_plugin.cpp b/src/ast/euf/euf_bv_plugin.cpp index 6631d9e50..b4abe5e29 100644 --- a/src/ast/euf/euf_bv_plugin.cpp +++ b/src/ast/euf/euf_bv_plugin.cpp @@ -69,18 +69,15 @@ The formal properties of saturation have to be established. - Saturation does not complete with respect to associativity. Instead the claim is along the lines that the resulting E-graph can be used as a canonizer. If given a set of equations E that are saturated, and terms t1, t2 that are -both simplified with respect to left-associativity of concatenation, and t1, t2 belong to the E-graph, +both simplified with respect to left-associativity of concatentation, and t1, t2 belong to the E-graph, then t1 = t2 iff t1 ~ t2 in the E-graph. TODO: Is saturation for (7) overkill for the purpose of canonization? -TODO: revisit re-entrancy during register_node. It can be called when creating internal extract terms. -Instead of allowing re-entrancy we can accumulate nodes that are registered during recursive calls -and have the main call perform recursive slicing. - --*/ +#include "ast/ast_pp.h" #include "ast/euf/euf_bv_plugin.h" #include "ast/euf/euf_egraph.h" @@ -91,19 +88,22 @@ namespace euf { bv(g.get_manager()) {} - enode* bv_plugin::mk_value_concat(enode* a, enode* b) { - auto v1 = get_value(a); - auto v2 = get_value(b); - auto v3 = v1 + v2 * power(rational(2), width(a)); - return mk_value(v3, width(a) + width(b)); + enode* bv_plugin::mk_value_concat(enode* hi, enode* lo) { + auto v1 = get_value(hi); + auto v2 = get_value(lo); + auto v3 = v2 + v1 * rational::power_of_two(width(lo)); + return mk_value(v3, width(lo) + width(hi)); } enode* bv_plugin::mk_value(rational const& v, unsigned sz) { auto e = bv.mk_numeral(v, sz); - return mk(e, 0, nullptr); + auto n = mk(e, 0, nullptr); + if (m_ensure_th_var) + m_ensure_th_var(n); + return n; } - void bv_plugin::merge_eh(enode* x, enode* y) { + void bv_plugin::propagate_merge(enode* x, enode* y) { if (!bv.is_bv(x->get_expr())) return; @@ -128,7 +128,36 @@ namespace euf { propagate_extract(n); } - // enforce concat(v1, v2) = v2*2^|v1| + v1 + void bv_plugin::register_node(enode* n) { + m_queue.push_back(n); + m_trail.push_back(new (get_region()) push_back_vector(m_queue)); + push_plugin_undo(bv.get_family_id()); + } + + void bv_plugin::merge_eh(enode* n1, enode* n2) { + m_queue.push_back(enode_pair(n1, n2)); + m_trail.push_back(new (get_region()) push_back_vector(m_queue)); + push_plugin_undo(bv.get_family_id()); + } + + void bv_plugin::propagate() { + if (m_qhead == m_queue.size()) + return; + m_trail.push_back(new (get_region()) value_trail(m_qhead)); + push_plugin_undo(bv.get_family_id()); + for (; m_qhead < m_queue.size(); ++m_qhead) { + if (std::holds_alternative(m_queue[m_qhead])) { + auto n = *std::get_if(&m_queue[m_qhead]); + propagate_register_node(n); + } + else { + auto [a, b] = *std::get_if(&m_queue[m_qhead]); + propagate_merge(a, b); + } + } + } + + // enforce concat(v1, v2) = v1*2^|v2| + v2 void bv_plugin::propagate_values(enode* x) { if (!is_value(x)) return; @@ -142,9 +171,9 @@ namespace euf { if (is_concat(sib, a, b)) { if (!is_value(a) || !is_value(b)) { auto val = get_value(x); - auto v1 = mod2k(val, width(a)); - auto v2 = machine_div2k(val, width(a)); - push_merge(mk_concat(mk_value(v1, width(a)), mk_value(v2, width(b))), x->get_interpreted()); + auto val_a = machine_div2k(val, width(b)); + auto val_b = mod2k(val, width(b)); + push_merge(mk_concat(mk_value(val_a, width(a)), mk_value(val_b, width(b))), x->get_interpreted()); } } } @@ -176,18 +205,18 @@ namespace euf { if (is_extract(p1, lo_, hi_) && lo_ == lo && hi_ == hi && p1->get_arg(0)->get_root() == arg_r) return; // add the axiom instead of merge(p, mk_extract(arg, lo, hi)), which would require tracking justifications - push_merge(mk_concat(mk_extract(arg, lo, mid), mk_extract(arg, mid + 1, hi)), mk_extract(arg, lo, hi)); + push_merge(mk_concat(mk_extract(arg, mid + 1, hi), mk_extract(arg, lo, mid)), mk_extract(arg, lo, hi)); }; - auto propagate_left = [&](enode* b) { - TRACE("bv", tout << "propagate-left " << g.bpp(b) << "\n"); + auto propagate_above = [&](enode* b) { + TRACE("bv", tout << "propagate-above " << g.bpp(b) << "\n"); for (enode* sib : enode_class(b)) if (is_extract(sib, lo2, hi2) && sib->get_arg(0)->get_root() == arg_r && hi1 + 1 == lo2) ensure_concat(lo1, hi1, hi2); }; - auto propagate_right = [&](enode* a) { - TRACE("bv", tout << "propagate-right " << g.bpp(a) << "\n"); + auto propagate_below = [&](enode* a) { + TRACE("bv", tout << "propagate-below " << g.bpp(a) << "\n"); for (enode* sib : enode_class(a)) if (is_extract(sib, lo2, hi2) && sib->get_arg(0)->get_root() == arg_r && hi2 + 1 == lo1) ensure_concat(lo2, hi2, hi1); @@ -196,46 +225,65 @@ namespace euf { for (enode* p : enode_parents(n)) { if (is_concat(p, a, b)) { if (a->get_root() == n_r) - propagate_left(b); + propagate_below(b); if (b->get_root() == n_r) - propagate_right(a); + propagate_above(a); } } } - void bv_plugin::push_undo_split(enode* n) { - m_undo_split.push_back(n); + class bv_plugin::undo_split : public trail { + bv_plugin& p; + enode* n; + public: + undo_split(bv_plugin& p, enode* n): p(p), n(n) {} + void undo() override { + auto& i = p.info(n); + i.value = nullptr; + i.lo = nullptr; + i.hi = nullptr; + i.cut = null_cut; + } + }; + + void bv_plugin::push_undo_split(enode* n) { + m_trail.push_back(new (get_region()) undo_split(*this, n)); push_plugin_undo(bv.get_family_id()); } void bv_plugin::undo() { - enode* n = m_undo_split.back(); - m_undo_split.pop_back(); - auto& i = info(n); - i.lo = nullptr; - i.hi = nullptr; - i.cut = null_cut; + m_trail.back()->undo(); + m_trail.pop_back(); } + - void bv_plugin::register_node(enode* n) { + void bv_plugin::propagate_register_node(enode* n) { TRACE("bv", tout << "register " << g.bpp(n) << "\n"); - auto& i = info(n); - i.value = n; enode* a, * b; + unsigned lo, hi; if (is_concat(n, a, b)) { - i.lo = a; - i.hi = b; - i.cut = width(a); + auto& i = info(n); + i.value = n; + i.hi = a; + i.lo = b; + i.cut = width(b); push_undo_split(n); } - unsigned lo, hi; - if (is_extract(n, lo, hi) && (lo != 0 || hi + 1 != width(n->get_arg(0)))) { + else if (is_concat(n) && n->num_args() != 2) { + SASSERT(n->num_args() != 0); + auto last = n->get_arg(n->num_args() - 1); + for (unsigned i = n->num_args() - 1; i-- > 0;) + last = mk_concat(n->get_arg(i), last); + push_merge(last, n); + } + else if (is_extract(n, lo, hi) && (lo != 0 || hi + 1 != width(n->get_arg(0)))) { enode* arg = n->get_arg(0); unsigned w = width(arg); if (all_of(enode_parents(arg), [&](enode* p) { unsigned _lo, _hi; return !is_extract(p, _lo, _hi) || _lo != 0 || _hi + 1 != w; })) push_merge(mk_extract(arg, 0, w - 1), arg); ensure_slice(arg, lo, hi); } + TRACE("bv", tout << "done register " << g.bpp(n) << "\n"); } // @@ -250,7 +298,8 @@ namespace euf { SASSERT(ub - lb + 1 == width(r)); if (lb == lo && ub == hi) return; - slice_info& i = info(r); + slice_info const& i = info(r); + if (!i.lo) { if (lo > lb) { split(r, lo - lb); @@ -287,12 +336,20 @@ namespace euf { hi += lo1; n = n->get_arg(0); } + if (n->interpreted()) { + auto v = get_value(n); + if (lo > 0) + v = div(v, rational::power_of_two(lo)); + if (hi + 1 != width(n)) + v = mod(v, rational::power_of_two(hi + 1)); + return mk_value(v, hi - lo + 1); + } return mk(bv.mk_extract(hi, lo, n->get_expr()), 1, &n); } - enode* bv_plugin::mk_concat(enode* lo, enode* hi) { - enode* args[2] = { lo, hi }; - return mk(bv.mk_concat(lo->get_expr(), hi->get_expr()), 2, args); + enode* bv_plugin::mk_concat(enode* hi, enode* lo) { + enode* args[2] = { hi, lo }; + return mk(bv.mk_concat(hi->get_expr(), lo->get_expr()), 2, args); } void bv_plugin::merge(enode_vector& xs, enode_vector& ys, justification dep) { @@ -300,6 +357,7 @@ namespace euf { SASSERT(!ys.empty()); auto x = xs.back(); auto y = ys.back(); + TRACE("bv", tout << "merge " << g.bpp(x) << " " << g.bpp(y) << "\n"); if (unfold_sub(x, xs)) continue; else if (unfold_sub(y, ys)) @@ -342,14 +400,13 @@ namespace euf { SASSERT(0 < cut && cut < w); enode* hi = mk_extract(n, cut, w - 1); enode* lo = mk_extract(n, 0, cut - 1); - auto& i = info(n); - if (!i.value) - i.value = n; + auto& i = info(n); + i.value = n; i.hi = hi; i.lo = lo; i.cut = cut; push_undo_split(n); - push_merge(mk_concat(lo, hi), n); + push_merge(mk_concat(hi, lo), n); } void bv_plugin::sub_slices(enode* n, std::function& consumer) { @@ -442,9 +499,12 @@ namespace euf { continue; offsets.push_back(offs); if (n->get_root() == b->get_root() && offs == offset) { + if (n != b) + consumer(n, b); while (j != UINT_MAX) { auto [x, y, j2] = just[j]; - consumer(x, y); + if (x != y) + consumer(x, y); j = j2; } for (auto const& [n, offset, j] : m_jtodo) { @@ -487,10 +547,10 @@ namespace euf { } std::ostream& bv_plugin::display(std::ostream& out) const { - out << "bv\n"; + out << "bv\n"; for (auto const& i : m_info) - if (i.lo) - out << g.bpp(i.value) << " cut " << i.cut << " lo " << g.bpp(i.lo) << " hi " << g.bpp(i.hi) << "\n"; + if (i.lo) + out << g.bpp(i.value) << " cut " << i.cut << " lo " << g.bpp(i.lo) << " hi " << g.bpp(i.hi) << "\n"; return out; } } diff --git a/src/ast/euf/euf_bv_plugin.h b/src/ast/euf/euf_bv_plugin.h index 199aed4e7..b90318c4d 100644 --- a/src/ast/euf/euf_bv_plugin.h +++ b/src/ast/euf/euf_bv_plugin.h @@ -19,6 +19,7 @@ Author: #pragma once +#include "util/trail.h" #include "ast/bv_decl_plugin.h" #include "ast/euf/euf_plugin.h" @@ -40,26 +41,24 @@ namespace euf { bv_util bv; slice_info_vector m_info; // indexed by enode::get_id() - - - enode_vector m_xs, m_ys; + std::function m_ensure_th_var; + bool is_concat(enode* n) const { return bv.is_concat(n->get_expr()); } - bool is_concat(enode* n, enode*& a, enode*& b) { return is_concat(n) && (a = n->get_arg(0), b = n->get_arg(1), true); } + bool is_concat(enode* n, enode*& a, enode*& b) { return is_concat(n) && n->num_args() == 2 && (a = n->get_arg(0), b = n->get_arg(1), true); } bool is_extract(enode* n, unsigned& lo, unsigned& hi) { expr* body; return bv.is_extract(n->get_expr(), lo, hi, body); } bool is_extract(enode* n) const { return bv.is_extract(n->get_expr()); } unsigned width(enode* n) const { return bv.get_bv_size(n->get_expr()); } enode* mk_extract(enode* n, unsigned lo, unsigned hi); - enode* mk_concat(enode* lo, enode* hi); - enode* mk_value_concat(enode* lo, enode* hi); + enode* mk_concat(enode* hi, enode* lo); + enode* mk_value_concat(enode* hi, enode* lo); enode* mk_value(rational const& v, unsigned sz); unsigned width(enode* n) { return bv.get_bv_size(n->get_expr()); } bool is_value(enode* n) { return n->get_root()->interpreted(); } rational get_value(enode* n) { rational val; VERIFY(bv.is_numeral(n->get_interpreted()->get_expr(), val)); return val; } slice_info& info(enode* n) { unsigned id = n->get_id(); m_info.reserve(id + 1); return m_info[id]; } - slice_info& root_info(enode* n) { unsigned id = n->get_root_id(); m_info.reserve(id + 1); return m_info[id]; } bool has_sub(enode* n) { return !!info(n).lo; } enode* sub_lo(enode* n) { return info(n).lo; } enode* sub_hi(enode* n) { return info(n).hi; } @@ -81,8 +80,16 @@ namespace euf { svector> m_jtodo; void clear_offsets(); - enode_vector m_undo_split; + + ptr_vector m_trail; + + class undo_split; void push_undo_split(enode* n); + + vector> m_queue; + unsigned m_qhead = 0; + void propagate_register_node(enode* n); + void propagate_merge(enode* a, enode* b); public: bv_plugin(egraph& g); @@ -97,9 +104,11 @@ namespace euf { void diseq_eh(enode* eq) override {} - void propagate() override {} + void propagate() override; void undo() override; + + void set_ensure_th_var(std::function& f) { m_ensure_th_var = f; } std::ostream& display(std::ostream& out) const override; diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index c32a81739..12f817212 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -107,6 +107,8 @@ namespace euf { void egraph::update_children(enode* n) { for (enode* child : enode_args(n)) child->get_root()->add_parent(n); + for (enode* child : enode_args(n)) + SASSERT(child->get_root()->m_parents.back() == n); m_updates.push_back(update_record(n, update_record::update_children())); } @@ -158,7 +160,7 @@ namespace euf { } void egraph::add_th_eq(theory_id id, theory_var v1, theory_var v2, enode* c, enode* r) { - TRACE("euf_verbose", tout << "eq: " << v1 << " == " << v2 << "\n";); + TRACE("euf", tout << "eq: " << v1 << " == " << v2 << " - " << bpp(c) << " == " << bpp(r) << "\n";); m_new_th_eqs.push_back(th_eq(id, v1, v2, c, r)); m_updates.push_back(update_record(update_record::new_th_eq())); ++m_stats.m_num_th_eqs; @@ -442,6 +444,8 @@ namespace euf { break; case update_record::tag_t::is_update_children: for (unsigned i = 0; i < p.r1->num_args(); ++i) { + CTRACE("euf", (p.r1->m_args[i]->get_root()->m_parents.back() != p.r1), + display(tout << bpp(p.r1->m_args[i]) << " " << bpp(p.r1->m_args[i]->get_root()) << " ");); SASSERT(p.r1->m_args[i]->get_root()->m_parents.back() == p.r1); p.r1->m_args[i]->get_root()->m_parents.pop_back(); } diff --git a/src/ast/euf/euf_egraph.h b/src/ast/euf/euf_egraph.h index dd6c9b9da..8822b07e7 100644 --- a/src/ast/euf/euf_egraph.h +++ b/src/ast/euf/euf_egraph.h @@ -192,8 +192,8 @@ namespace euf { enode_vector m_empty_enodes; unsigned m_num_scopes = 0; bool m_inconsistent = false; - enode* m_n1 = nullptr; - enode* m_n2 = nullptr; + enode *m_n1 = nullptr; + enode *m_n2 = nullptr; justification m_justification; unsigned m_new_th_eqs_qhead = 0; svector m_new_th_eqs; @@ -205,11 +205,11 @@ namespace euf { uint64_t m_congruence_timestamp = 0; std::vector> m_on_merge; - std::function m_on_propagate_literal; - std::function m_on_make; - std::function m_used_eq; - std::function m_used_cc; - std::function m_display_justification; + std::function m_on_propagate_literal; + std::function m_on_make; + std::function m_used_eq; + std::function m_used_cc; + std::function m_display_justification; void push_eq(enode* r1, enode* n1, unsigned r2_num_parents) { m_updates.push_back(update_record(r1, n1, r2_num_parents)); @@ -218,7 +218,7 @@ namespace euf { // plugin related methods void push_plugin_undo(unsigned th_id) { m_updates.push_back(update_record(th_id, update_record::plugin_undo())); } - void push_merge(enode* a, enode* b, justification j) { m_to_merge.push_back({ a, b, j }); } + void push_merge(enode* a, enode* b, justification j) { SASSERT(a->get_sort() == b->get_sort()); m_to_merge.push_back({ a, b, j }); } void push_merge(enode* a, enode* b, bool comm) { m_to_merge.push_back({ a, b, comm }); } void propagate_plugins(); @@ -279,6 +279,7 @@ namespace euf { void merge(enode* n1, enode* n2, void* reason) { merge(n1, n2, justification::external(reason)); } void new_diseq(enode* n); + /** \brief propagate set of merges. This call may detect an inconsistency. Then inconsistent() is true. @@ -325,13 +326,13 @@ namespace euf { void set_relevant(enode* n); void set_default_relevant(bool b) { m_default_relevant = b; } - void set_on_merge(std::function on_merge) { m_on_merge.push_back(std::move(on_merge)); } - void set_on_propagate(std::function on_propagate) { m_on_propagate_literal = std::move(on_propagate); } - void set_on_make(std::function on_make) { m_on_make = std::move(on_make); } - void set_used_eq(std::function used_eq) { m_used_eq = std::move(used_eq); } - void set_used_cc(std::function used_cc) { m_used_cc = std::move(used_cc); } - void set_display_justification(std::function d) { m_display_justification = std::move(d); } - + void set_on_merge(std::function& on_merge) { m_on_merge.push_back(on_merge); } + void set_on_propagate(std::function& on_propagate) { m_on_propagate_literal = on_propagate; } + void set_on_make(std::function& on_make) { m_on_make = on_make; } + void set_used_eq(std::function& used_eq) { m_used_eq = used_eq; } + void set_used_cc(std::function& used_cc) { m_used_cc = used_cc; } + void set_display_justification(std::function & d) { m_display_justification = d; } + void begin_explain(); void end_explain(); bool uses_congruence() const { return m_uses_congruence; } diff --git a/src/sat/smt/arith_axioms.cpp b/src/sat/smt/arith_axioms.cpp index 20bc78260..b2dd5e969 100644 --- a/src/sat/smt/arith_axioms.cpp +++ b/src/sat/smt/arith_axioms.cpp @@ -260,9 +260,6 @@ namespace arith { if (valy >= sz || valy == 0) return true; unsigned k = valy.get_unsigned(); - rational r = mod(valx * rational::power_of_two(k), N); - if (r == valn) - return true; sat::literal eq = eq_internalize(n, a.mk_mod(a.mk_mul(_x, a.mk_int(rational::power_of_two(k))), a.mk_int(N))); if (s().value(eq) == l_true) return true; @@ -275,9 +272,6 @@ namespace arith { if (valy >= sz || valy == 0) return true; unsigned k = valy.get_unsigned(); - rational r = mod(div(valx, rational::power_of_two(k)), N); - if (r == valn) - return true; sat::literal eq = eq_internalize(n, a.mk_idiv(x, a.mk_int(rational::power_of_two(k)))); if (s().value(eq) == l_true) return true; @@ -290,12 +284,6 @@ namespace arith { if (valy >= sz || valy == 0) return true; unsigned k = valy.get_unsigned(); - bool signvalx = x >= N/2; - rational valxdiv2k = div(valx, rational::power_of_two(k)); - if (signvalx) - valxdiv2k = mod(valxdiv2k - rational::power_of_two(sz - k), N); - if (valn == valxdiv2k) - return true; sat::literal signx = mk_literal(a.mk_ge(x, a.mk_int(N/2))); sat::literal eq; expr* xdiv2k; @@ -334,11 +322,7 @@ namespace arith { return true; } - /* - * 0 <= x&y < 2^sz - * x&y <= x - * x&y <= y - */ + void solver::mk_bv_axiom(app* n) { unsigned sz; expr* _x, * _y; @@ -347,10 +331,15 @@ namespace arith { expr_ref x(a.mk_mod(_x, a.mk_int(N)), m); expr_ref y(a.mk_mod(_y, a.mk_int(N)), m); - add_clause(mk_literal(a.mk_ge(n, a.mk_int(0)))); - add_clause(mk_literal(a.mk_le(n, a.mk_int(N - 1)))); - if (a.is_band(n)) { + + // 0 <= x&y < 2^sz + // x&y <= x + // x&y <= y + // TODO? x = y => x&y = x + + add_clause(mk_literal(a.mk_ge(n, a.mk_int(0)))); + add_clause(mk_literal(a.mk_le(n, a.mk_int(N - 1)))); add_clause(mk_literal(a.mk_le(n, x))); add_clause(mk_literal(a.mk_le(n, y))); } diff --git a/src/sat/smt/intblast_solver.cpp b/src/sat/smt/intblast_solver.cpp index f8a7beed0..2c373f6b9 100644 --- a/src/sat/smt/intblast_solver.cpp +++ b/src/sat/smt/intblast_solver.cpp @@ -37,6 +37,7 @@ namespace intblast { euf::theory_var solver::mk_var(euf::enode* n) { auto r = euf::th_euf_solver::mk_var(n); ctx.attach_th_var(n, this, r); + TRACE("bv", tout << "mk-var: v" << r << " " << ctx.bpp(n) << "\n";); return r; } @@ -97,16 +98,16 @@ namespace intblast { ensure_translated(y); m_args.reset(); m_args.push_back(a.mk_sub(translated(x), translated(y))); - set_translated(e, m.mk_eq(umod(x, 0), a.mk_int(0))); + set_translated(e, m.mk_eq(umod(x, 0), a.mk_int(0))); } m_preds.push_back(e); ctx.push(push_back_vector(m_preds)); } - void solver::set_translated(expr* e, expr* r) { + void solver::set_translated(expr* e, expr* r) { SASSERT(r); - SASSERT(!is_translated(e)); - m_translate.setx(e->get_id(), r); + SASSERT(!is_translated(e)); + m_translate.setx(e->get_id(), r); ctx.push(set_vector_idx_trail(m_translate, e->get_id())); } @@ -147,7 +148,7 @@ namespace intblast { auto a = expr2literal(e); auto b = mk_literal(r); ctx.mark_relevant(b); - TRACE("intblast", tout << "add-predicate-axiom: " << mk_bounded_pp(e, m) << " \n" << r << "\n"); +// verbose_stream() << "add-predicate-axiom: " << mk_pp(e, m) << " == " << r << "\n"; add_equiv(a, b); } return true; @@ -156,7 +157,6 @@ namespace intblast { bool solver::unit_propagate() { return add_bound_axioms() || add_predicate_axioms(); } - void solver::ensure_translated(expr* e) { if (m_translate.get(e->get_id(), nullptr)) return; @@ -178,10 +178,96 @@ namespace intblast { } } std::stable_sort(todo.begin(), todo.end(), [&](expr* a, expr* b) { return get_depth(a) < get_depth(b); }); - for (expr* e : todo) + for (expr* e : todo) translate_expr(e); } + lbool solver::check_axiom(sat::literal_vector const& lits) { + sat::literal_vector core; + for (auto lit : lits) + core.push_back(~lit); + return check_core(core, {}); + } + lbool solver::check_propagation(sat::literal lit, sat::literal_vector const& lits, euf::enode_pair_vector const& eqs) { + sat::literal_vector core; + core.append(lits); + core.push_back(~lit); + return check_core(core, eqs); + } + + lbool solver::check_core(sat::literal_vector const& lits, euf::enode_pair_vector const& eqs) { + m_core.reset(); + m_vars.reset(); + m_is_plugin = false; + m_solver = mk_smt2_solver(m, s.params(), symbol::null); + + for (unsigned i = 0; i < m_translate.size(); ++i) + m_translate[i] = nullptr; + + expr_ref_vector es(m), original_es(m); + for (auto lit : lits) + es.push_back(ctx.literal2expr(lit)); + for (auto [a, b] : eqs) + es.push_back(m.mk_eq(a->get_expr(), b->get_expr())); + + original_es.append(es); + + lbool r; + if (false) { + r = m_solver->check_sat(es); + } + else { + + translate(es); + + for (auto e : m_vars) { + auto v = translated(e); + auto b = rational::power_of_two(bv.get_bv_size(e)); + m_solver->assert_expr(a.mk_le(a.mk_int(0), v)); + m_solver->assert_expr(a.mk_lt(v, a.mk_int(b))); + } + + for (unsigned i = 0; i < es.size(); ++i) { + expr_ref tmp(es.get(i), m); + ctx.get_rewriter()(tmp); + es[i] = tmp; + } + + IF_VERBOSE(2, verbose_stream() << "check\n" << original_es << "\n"); + + IF_VERBOSE(2, + { + m_solver->push(); + m_solver->assert_expr(es); + m_solver->display(verbose_stream()) << "(check-sat)\n"; + m_solver->pop(1); + }); + + + r = m_solver->check_sat(es); + } + + m_solver->collect_statistics(m_stats); + + IF_VERBOSE(2, verbose_stream() << "(sat.intblast :result " << r << ")\n"); + if (r == l_true) { + IF_VERBOSE(0, + model_ref mdl; + m_solver->get_model(mdl); + verbose_stream() << original_es << "\n"; + verbose_stream() << *mdl << "\n"; + verbose_stream() << es << "\n"; + m_solver->display(verbose_stream());); + SASSERT(false); + } + + m_solver = nullptr; + + return r; + } + + + lbool solver::check_solver_state() { sat::literal_vector literals; uint_set selected; @@ -291,6 +377,8 @@ namespace intblast { for (expr* e : es) { if (is_translated(e)) continue; + if (visited.is_marked(e)) + continue; sorted.push_back(e); visited.mark(e); } @@ -304,6 +392,7 @@ namespace intblast { sorted.push_back(arg); } } + } else if (is_quantifier(e)) { quantifier* q = to_quantifier(e); @@ -334,7 +423,7 @@ namespace intblast { es[i] = translated(es.get(i)); } - sat::check_result solver::check() { + sat::check_result solver::check() { // ensure that bv2int is injective for (auto e : m_bv2int) { euf::enode* n = expr2enode(e); @@ -346,12 +435,10 @@ namespace intblast { continue; if (sib->get_arg(0)->get_root() == r1) continue; - if (sib->get_arg(0)->get_sort() != n->get_arg(0)->get_sort()) - continue; - auto a = eq_internalize(n, sib); - auto b = eq_internalize(sib->get_arg(0), n->get_arg(0)); - ctx.mark_relevant(a); - ctx.mark_relevant(b); + auto a = eq_internalize(n, sib); + auto b = eq_internalize(sib->get_arg(0), n->get_arg(0)); + ctx.mark_relevant(a); + ctx.mark_relevant(b); add_clause(~a, b, nullptr); return sat::check_result::CR_CONTINUE; } @@ -369,27 +456,40 @@ namespace intblast { auto nBv2int = ctx.get_enode(bv2int); auto nxModN = ctx.get_enode(xModN); if (nBv2int->get_root() != nxModN->get_root()) { - auto a = eq_internalize(nBv2int, nxModN); - ctx.mark_relevant(a); - add_unit(a); - return sat::check_result::CR_CONTINUE; + auto a = eq_internalize(nBv2int, nxModN); + ctx.mark_relevant(a); + add_unit(a); + return sat::check_result::CR_CONTINUE; } } - return sat::check_result::CR_DONE; + return sat::check_result::CR_DONE; + } + + bool solver::is_bounded(expr* x, rational const& N) { + return any_of(m_vars, [&](expr* v) { + return is_translated(v) && translated(v) == x && bv.get_bv_size(v) <= N; + }); + } + + bool solver::is_non_negative(expr* bv_expr, expr* e) { + auto N = rational::power_of_two(bv.get_bv_size(bv_expr)); + rational r; + if (a.is_numeral(e, r)) + return r >= 0; + if (is_bounded(e, N)) + return true; + expr* x, * y; + if (a.is_mul(e, x, y)) + return is_non_negative(bv_expr, x) && is_non_negative(bv_expr, y); + if (a.is_add(e, x, y)) + return is_non_negative(bv_expr, x) && is_non_negative(bv_expr, y); + return false; } expr* solver::umod(expr* bv_expr, unsigned i) { expr* x = arg(i); - rational r; rational N = bv_size(bv_expr); - if (a.is_numeral(x, r)) { - if (0 <= r && r < N) - return x; - return a.mk_int(mod(r, N)); - } - if (any_of(m_vars, [&](expr* v) { return translated(v) == x && bv.get_bv_size(v) == bv.get_bv_size(bv_expr); })) - return x; - return a.mk_mod(x, a.mk_int(N)); + return amod(bv_expr, x, N); } expr* solver::smod(expr* bv_expr, unsigned i) { @@ -399,7 +499,61 @@ namespace intblast { rational r; if (a.is_numeral(x, r)) return a.mk_int(mod(r + shift, N)); - return a.mk_mod(a.mk_add(x, a.mk_int(shift)), a.mk_int(N)); + return amod(bv_expr, add(x, a.mk_int(shift)), N); + } + + expr_ref solver::mul(expr* x, expr* y) { + expr_ref _x(x, m), _y(y, m); + if (a.is_zero(x)) + return _x; + if (a.is_zero(y)) + return _y; + if (a.is_one(x)) + return _y; + if (a.is_one(y)) + return _x; + rational v1, v2; + if (a.is_numeral(x, v1) && a.is_numeral(y, v2)) + return expr_ref(a.mk_int(v1 * v2), m); + _x = a.mk_mul(x, y); + return _x; + } + + expr_ref solver::add(expr* x, expr* y) { + expr_ref _x(x, m), _y(y, m); + if (a.is_zero(x)) + return _y; + if (a.is_zero(y)) + return _x; + rational v1, v2; + if (a.is_numeral(x, v1) && a.is_numeral(y, v2)) + return expr_ref(a.mk_int(v1 + v2), m); + _x = a.mk_add(x, y); + return _x; + } + + /* + * Perform simplifications that are claimed sound when the bit-vector interpretations of + * mod/div always guard the mod and dividend to be non-zero. + * Potentially shady area is for arithmetic expressions created by int2bv. + * They will be guarded by a modulus which dose not disappear. + */ + expr* solver::amod(expr* bv_expr, expr* x, rational const& N) { + rational v; + expr* r, *c, * t, * e; + if (m.is_ite(x, c, t, e)) + r = m.mk_ite(c, amod(bv_expr, t, N), amod(bv_expr, e, N)); + else if (a.is_idiv(x, t, e) && a.is_numeral(t, v) && 0 <= v && v < N && is_non_negative(bv_expr, e)) + r = x; + else if (a.is_mod(x, t, e) && a.is_numeral(t, v) && 0 <= v && v < N) + r = x; + else if (a.is_numeral(x, v)) + r = a.mk_int(mod(v, N)); + else if (is_bounded(x, N)) + r = x; + else + r = a.mk_mod(x, a.mk_int(N)); + return r; } rational solver::bv_size(expr* bv_expr) { @@ -483,8 +637,7 @@ namespace intblast { m_args[i] = bv.mk_int2bv(bv.get_bv_size(e->get_arg(i)), m_args.get(i)); if (has_bv_sort) - m_vars.push_back(e); - + m_vars.push_back(e); if (m_is_plugin) { expr* r = m.mk_app(f, m_args); if (has_bv_sort) { @@ -505,7 +658,7 @@ namespace intblast { f = g; m_pinned.push_back(f); } - set_translated(e, m.mk_app(f, m_args)); + set_translated(e, m.mk_app(f, m_args)); } void solver::translate_bv(app* e) { @@ -532,15 +685,15 @@ namespace intblast { auto N = bv_size(e); auto A = rational::power_of_two(sz - n); auto B = rational::power_of_two(n); - auto hi = a.mk_mul(r, a.mk_int(A)); - auto lo = a.mk_mod(a.mk_idiv(umod(e, 0), a.mk_int(B)), a.mk_int(A)); - r = a.mk_add(hi, lo); + auto hi = mul(r, a.mk_int(A)); + auto lo = amod(e, a.mk_idiv(umod(e, 0), a.mk_int(B)), A); + r = add(hi, lo); } return r; - }; + }; expr* bv_expr = e; - expr* r = nullptr; + expr_ref r(m); auto const& args = m_args; switch (e->get_decl_kind()) { case OP_BADD: @@ -573,7 +726,6 @@ namespace intblast { r = a.mk_le(smod(bv_expr, 0), smod(bv_expr, 1)); break; case OP_SGEQ: - bv_expr = e->get_arg(0); r = a.mk_ge(smod(bv_expr, 0), smod(bv_expr, 1)); break; case OP_SLT: @@ -589,12 +741,13 @@ namespace intblast { break; case OP_CONCAT: { unsigned sz = 0; + expr_ref new_arg(m); for (unsigned i = args.size(); i-- > 0;) { expr* old_arg = e->get_arg(i); - expr* new_arg = umod(old_arg, i); + new_arg = umod(old_arg, i); if (sz > 0) { - new_arg = a.mk_mul(new_arg, a.mk_int(rational::power_of_two(sz))); - r = a.mk_add(r, new_arg); + new_arg = mul(new_arg, a.mk_int(rational::power_of_two(sz))); + r = add(r, new_arg); } else r = new_arg; @@ -606,10 +759,9 @@ namespace intblast { unsigned lo, hi; expr* old_arg; VERIFY(bv.is_extract(e, lo, hi, old_arg)); + r = arg(0); if (lo > 0) - r = a.mk_idiv(umod(old_arg, 0), a.mk_int(rational::power_of_two(lo))); - else - r = arg(0); + r = a.mk_idiv(r, a.mk_int(rational::power_of_two(lo))); break; } case OP_BV_NUM: { @@ -627,32 +779,32 @@ namespace intblast { } case OP_BUDIV: case OP_BUDIV_I: { - expr* x = umod(e, 0), * y = umod(e, 1); + expr* x = arg(0), * y = umod(e, 1); r = m.mk_ite(m.mk_eq(y, a.mk_int(0)), a.mk_int(-1), a.mk_idiv(x, y)); break; } case OP_BUMUL_NO_OVFL: { bv_expr = e->get_arg(0); - r = a.mk_lt(a.mk_mul(umod(bv_expr, 0), umod(bv_expr, 1)), a.mk_int(bv_size(bv_expr))); + r = a.mk_lt(mul(umod(bv_expr, 0), umod(bv_expr, 1)), a.mk_int(bv_size(bv_expr))); break; } case OP_BSHL: { - if (!a.is_numeral(arg(0)) && !a.is_numeral(arg(1))) - r = a.mk_shl(bv.get_bv_size(e), arg(0), arg(1)); + if (!a.is_numeral(arg(0)) && !a.is_numeral(arg(1))) + r = a.mk_shl(bv.get_bv_size(e), arg(0),arg(1)); else { expr* x = arg(0), * y = umod(e, 1); r = a.mk_int(0); IF_VERBOSE(2, verbose_stream() << "shl " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); for (unsigned i = 0; i < bv.get_bv_size(e); ++i) - r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), a.mk_mul(x, a.mk_int(rational::power_of_two(i))), r); + r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), mul(x, a.mk_int(rational::power_of_two(i))), r); } break; } case OP_BNOT: r = bnot(arg(0)); break; - case OP_BLSHR: - if (!a.is_numeral(arg(0)) && !a.is_numeral(arg(1))) + case OP_BLSHR: + if (!a.is_numeral(arg(0)) && !a.is_numeral(arg(1))) r = a.mk_lshr(bv.get_bv_size(e), arg(0), arg(1)); else { expr* x = arg(0), * y = umod(e, 1); @@ -662,11 +814,11 @@ namespace intblast { r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), a.mk_idiv(x, a.mk_int(rational::power_of_two(i))), r); } break; - case OP_BASHR: + case OP_BASHR: if (!a.is_numeral(arg(1))) r = a.mk_ashr(bv.get_bv_size(e), arg(0), arg(1)); else { - + // // ashr(x, y) // if y = k & x >= 0 -> x / 2^k @@ -674,15 +826,15 @@ namespace intblast { // unsigned sz = bv.get_bv_size(e); rational N = bv_size(e); - expr* x = umod(e, 0), * y = umod(e, 1); + expr* x = umod(e, 0), *y = umod(e, 1); expr* signx = a.mk_ge(x, a.mk_int(N / 2)); - r = m.mk_ite(signx, a.mk_int(-1), a.mk_int(0)); + r = m.mk_ite(signx, a.mk_int(- 1), a.mk_int(0)); IF_VERBOSE(1, verbose_stream() << "ashr " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); for (unsigned i = 0; i < sz; ++i) { - expr* d = a.mk_idiv(x, a.mk_int(rational::power_of_two(i))); + expr* d = a.mk_idiv(x, a.mk_int(rational::power_of_two(i))); r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), - m.mk_ite(signx, a.mk_add(d, a.mk_int(-rational::power_of_two(sz - i))), d), - r); + m.mk_ite(signx, add(d, a.mk_int(- rational::power_of_two(sz-i))), d), + r); } } break; @@ -691,7 +843,7 @@ namespace intblast { IF_VERBOSE(2, verbose_stream() << "bor " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n"); r = arg(0); for (unsigned i = 1; i < args.size(); ++i) - r = a.mk_sub(a.mk_add(r, arg(i)), a.mk_band(bv.get_bv_size(e), r, arg(i))); + r = a.mk_sub(add(r, arg(i)), a.mk_band(bv.get_bv_size(e), r, arg(i))); break; } case OP_BNAND: @@ -709,7 +861,7 @@ namespace intblast { r = arg(0); for (unsigned i = 1; i < args.size(); ++i) { expr* q = arg(i); - r = a.mk_sub(a.mk_add(r, q), a.mk_mul(a.mk_int(2), a.mk_band(sz, r, q))); + r = a.mk_sub(add(r, q), mul(a.mk_int(2), a.mk_band(sz, r, q))); } if (e->get_decl_kind() == OP_BXNOR) r = bnot(r); @@ -747,11 +899,11 @@ namespace intblast { r = m.mk_ite(m.mk_eq(umod(bv_expr, 0), umod(bv_expr, 1)), a.mk_int(1), a.mk_int(0)); break; case OP_BSMOD_I: - case OP_BSMOD: { - expr* x = umod(e, 0), * y = umod(e, 1); - rational N = bv_size(e); - expr* signx = a.mk_ge(x, a.mk_int(N / 2)); - expr* signy = a.mk_ge(y, a.mk_int(N / 2)); + case OP_BSMOD: { + expr* x = umod(e, 0), *y = umod(e, 1); + rational N = bv_size(e); + expr* signx = a.mk_ge(x, a.mk_int(N/2)); + expr* signy = a.mk_ge(y, a.mk_int(N/2)); expr* u = a.mk_mod(x, y); // u = 0 -> 0 // y = 0 -> x @@ -759,14 +911,14 @@ namespace intblast { // x < 0, y >= 0 -> y - u // x >= 0, y < 0 -> y + u // x >= 0, y >= 0 -> u - r = a.mk_uminus(u); - r = m.mk_ite(m.mk_and(m.mk_not(signx), signy), a.mk_add(u, y), r); + r = a.mk_uminus(u); + r = m.mk_ite(m.mk_and(m.mk_not(signx), signy), add(u, y), r); r = m.mk_ite(m.mk_and(signx, m.mk_not(signy)), a.mk_sub(y, u), r); r = m.mk_ite(m.mk_and(m.mk_not(signx), m.mk_not(signy)), u, r); r = m.mk_ite(m.mk_eq(u, a.mk_int(0)), a.mk_int(0), r); r = m.mk_ite(m.mk_eq(y, a.mk_int(0)), x, r); break; - } + } case OP_BSDIV_I: case OP_BSDIV: { // d = udiv(abs(x), abs(y)) @@ -800,9 +952,9 @@ namespace intblast { expr* absy = m.mk_ite(signy, a.mk_sub(a.mk_int(N), y), y); expr* d = a.mk_idiv(absx, absy); d = m.mk_ite(m.mk_iff(signx, signy), d, a.mk_uminus(d)); - r = a.mk_sub(x, a.mk_mul(d, y)); + r = a.mk_sub(x, mul(d, y)); r = m.mk_ite(m.mk_eq(y, a.mk_int(0)), x, r); - break; + break; } case OP_ROTATE_LEFT: { auto n = e->get_parameter(0).get_int(); @@ -815,11 +967,11 @@ namespace intblast { r = rotate_left(sz - n); break; } - case OP_EXT_ROTATE_LEFT: { + case OP_EXT_ROTATE_LEFT: { unsigned sz = bv.get_bv_size(e); expr* y = umod(e, 1); r = a.mk_int(0); - for (unsigned i = 0; i < sz; ++i) + for (unsigned i = 0; i < sz; ++i) r = m.mk_ite(m.mk_eq(a.mk_int(i), y), rotate_left(i), r); break; } @@ -827,7 +979,7 @@ namespace intblast { unsigned sz = bv.get_bv_size(e); expr* y = umod(e, 1); r = a.mk_int(0); - for (unsigned i = 0; i < sz; ++i) + for (unsigned i = 0; i < sz; ++i) r = m.mk_ite(m.mk_eq(a.mk_int(i), y), rotate_left(sz - i), r); break; } @@ -838,9 +990,9 @@ namespace intblast { rational N = bv_size(e->get_arg(0)); rational N0 = N; for (unsigned i = 1; i < n; ++i) - r = a.mk_add(a.mk_mul(a.mk_int(N), x), r), N *= N0; + r = add(mul(a.mk_int(N), x), r), N *= N0; break; - } + } case OP_BREDOR: { r = umod(e->get_arg(0), 0); r = m.mk_not(m.mk_eq(r, a.mk_int(0))); @@ -864,8 +1016,15 @@ namespace intblast { bool has_bv_arg = any_of(*e, [&](expr* arg) { return bv.is_bv(arg); }); if (has_bv_arg) { expr* bv_expr = e->get_arg(0); - m_args[0] = a.mk_sub(arg(0), arg(1)); - set_translated(e, m.mk_eq(umod(bv_expr, 0), a.mk_int(0))); + rational N = rational::power_of_two(bv.get_bv_size(bv_expr)); + if (a.is_numeral(arg(0)) || a.is_numeral(arg(1)) || + is_bounded(arg(0), N) || is_bounded(arg(1), N)) { + set_translated(e, m.mk_eq(umod(bv_expr, 0), umod(bv_expr, 1))); + } + else { + m_args[0] = a.mk_sub(arg(0), arg(1)); + set_translated(e, m.mk_eq(umod(bv_expr, 0), a.mk_int(0))); + } } else set_translated(e, m.mk_eq(arg(0), arg(1))); @@ -874,8 +1033,8 @@ namespace intblast { set_translated(e, m.mk_ite(arg(0), arg(1), arg(2))); else if (m_is_plugin) set_translated(e, e); - else - set_translated(e, m.mk_app(e->get_decl(), m_args)); + else + set_translated(e, m.mk_app(e->get_decl(), m_args)); } rational solver::get_value(expr* e) const { @@ -903,12 +1062,6 @@ namespace intblast { if (!is_app(n->get_expr())) return false; app* e = to_app(n->get_expr()); - expr *th, * el, * c; - if (m.is_ite(e, c, th, el)) { - dep.add(n, expr2enode(th)->get_root()); - dep.add(n, expr2enode(el)->get_root()); - return true; - } if (n->num_args() == 0) { dep.insert(n, nullptr); return true; @@ -925,7 +1078,6 @@ namespace intblast { void solver::add_value_solver(euf::enode* n, model& mdl, expr_ref_vector& values) { expr* e = n->get_expr(); SASSERT(bv.is_bv(e)); - if (bv.is_numeral(e)) { values.setx(n->get_root_id(), e); return; @@ -947,15 +1099,6 @@ namespace intblast { void solver::add_value_plugin(euf::enode* n, model& mdl, expr_ref_vector& values) { expr_ref value(m); - expr* e = n->get_expr(), *c, *th, *el; - while (m.is_ite(e, c, th, el)) { - auto thn = expr2enode(th); - if (thn->get_root() == n->get_root()) - e = th; - else - e = el; - n = expr2enode(e); - } if (n->interpreted()) value = n->get_expr(); else if (to_app(n->get_expr())->get_family_id() == bv.get_family_id()) { @@ -975,35 +1118,12 @@ namespace intblast { rational r; VERIFY(av.get_value(b2i->get_expr(), r)); value = bv.mk_numeral(r, bv.get_bv_size(n->get_expr())); + verbose_stream() << ctx.bpp(n) << " := " << value << "\n"; } values.set(n->get_root_id(), value); TRACE("model", tout << "add_value " << ctx.bpp(n) << " := " << value << "\n"); } - void solver::finalize_model(model& mdl) { - for (auto n : ctx.get_egraph().nodes()) { - expr* e = n->get_expr(); - if (!bv.is_bv(e)) - continue; - if (!is_translated(e)) - continue; - expr* f = translated(e); - rational r1, r2; - expr_ref val1 = mdl(e); - expr_ref val2 = mdl(f); - if (bv.is_numeral(val1, r1) && a.is_numeral(val2, r2) && r1 != r2) { - rational N = rational::power_of_two(bv.get_bv_size(e)); - r2 = mod(r2, N); - if (r1 == r2) - continue; - verbose_stream() << "value mismatch : " << mk_bounded_pp(e, m) << " := " << val1 << "\n"; - verbose_stream() << mk_bounded_pp(f, m) << " := " << r2 << "\n"; - for (expr* arg : *to_app(e)) - verbose_stream() << mk_bounded_pp(arg, m) << " := " << mdl(arg) << "\n"; - } - } - } - sat::literal_vector const& solver::unsat_core() { return m_core; } diff --git a/src/sat/smt/intblast_solver.h b/src/sat/smt/intblast_solver.h index 1739fc09b..0aceb8b2b 100644 --- a/src/sat/smt/intblast_solver.h +++ b/src/sat/smt/intblast_solver.h @@ -73,6 +73,11 @@ namespace intblast { expr* umod(expr* bv_expr, unsigned i); expr* smod(expr* bv_expr, unsigned i); + bool is_bounded(expr* v, rational const& N); + bool is_non_negative(expr* bv_expr, expr* e); + expr_ref mul(expr* x, expr* y); + expr_ref add(expr* x, expr* y); + expr* amod(expr* bv_expr, expr* x, rational const& N); rational bv_size(expr* bv_expr); void translate_expr(expr* e); @@ -100,6 +105,10 @@ namespace intblast { ~solver() override {} + lbool check_axiom(sat::literal_vector const& lits); + lbool check_core(sat::literal_vector const& lits, euf::enode_pair_vector const& eqs); + lbool check_propagation(sat::literal lit, sat::literal_vector const& lits, euf::enode_pair_vector const& eqs); + lbool check_solver_state(); sat::literal_vector const& unsat_core(); @@ -108,8 +117,6 @@ namespace intblast { bool add_dep(euf::enode* n, top_sort& dep) override; - void finalize_model(model& mdl) override; - std::ostream& display(std::ostream& out) const override; void collect_statistics(statistics& st) const override; From aa4e1b34bb2ce3d945a25d1bce05874a43efa44f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Jan 2024 13:15:45 -0800 Subject: [PATCH 075/224] update Julia versions Signed-off-by: Nikolaj Bjorner --- azure-pipelines.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 382c2efc9..26e203d0a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -144,7 +144,7 @@ jobs: buildCmd: 'CC=clang CXX=clang++ cmake -DCMAKE_BUILD_TYPE=Release $(cmakeStdArgs)' runTests: 'True' debugClang: - setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"0.7.0\"))"' + setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"1.10.0\"))"' setupCmd2: 'JlCxxDir=$(julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))")' buildCmd: 'CC=clang CXX=clang++ cmake -DJlCxx_DIR=$JlCxxDir/cmake/JlCxx $(cmakeJulia) $(cmakeStdArgs)' runTests: 'True' @@ -198,7 +198,7 @@ jobs: runTests: 'False' x64: arch: 'x64' - setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"0.7.0\"))"' + setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"1.10.0\"))"' setupCmd2: 'julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))" > tmp.env' setupCmd3: 'set /P JlCxxDir= Date: Thu, 11 Jan 2024 13:30:42 -0800 Subject: [PATCH 076/224] try to remove version spec Signed-off-by: Nikolaj Bjorner --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 26e203d0a..51e8ad08e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -144,7 +144,7 @@ jobs: buildCmd: 'CC=clang CXX=clang++ cmake -DCMAKE_BUILD_TYPE=Release $(cmakeStdArgs)' runTests: 'True' debugClang: - setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"1.10.0\"))"' + setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\"))"' setupCmd2: 'JlCxxDir=$(julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))")' buildCmd: 'CC=clang CXX=clang++ cmake -DJlCxx_DIR=$JlCxxDir/cmake/JlCxx $(cmakeJulia) $(cmakeStdArgs)' runTests: 'True' From 1b3929099b445359aa1982940be3da75a8d060e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Jan 2024 13:36:07 -0800 Subject: [PATCH 077/224] try to remove version spec Signed-off-by: Nikolaj Bjorner --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 51e8ad08e..753c9ae9c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -198,7 +198,7 @@ jobs: runTests: 'False' x64: arch: 'x64' - setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"1.10.0\"))"' + setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\"))"' setupCmd2: 'julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))" > tmp.env' setupCmd3: 'set /P JlCxxDir= Date: Thu, 11 Jan 2024 12:10:37 -1000 Subject: [PATCH 078/224] take the coefficient from cut_result, not lia Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.cpp | 3 +-- src/math/lp/lar_solver.h | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index cefd9767f..167725d31 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -410,12 +410,11 @@ public: return all_of(t, [&](auto ci) { return ci.coeff().is_small(); }); }; auto add_cut = [&](cut_result const& cr) { - u_dependency* dep = cr.dep; lp::lpvar term_index = lra.add_term(cr.t.coeffs_as_vector(), UINT_MAX); term_index = lra.map_term_index_to_column_index(term_index); lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::GE, - lia.m_k, dep); + cr.k, cr.dep); }; auto _check_feasible = [&](void) { lra.find_feasible_solution(); diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index a01a66a38..91d506e1e 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -562,7 +562,9 @@ public: std::ostream& print_implied_bound(const implied_bound& be, std::ostream& out) const; std::ostream& print_values(std::ostream& out) const; std::ostream& display(std::ostream& out) const; - + std::ostream& display_constraint(std::ostream& out, constraint_index ci) const { + return m_constraints.display(out, ci); + } bool init_model() const; mpq from_model_in_impq_to_mpq(const impq& v) const { return v.x + m_delta * v.y; } mpq get_value(column_index const& j) const; From 2b974a0f1dacd465fc4d2345348295f081892c8b Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 11 Jan 2024 13:39:37 -1000 Subject: [PATCH 079/224] do not delay update for the polar case Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.cpp | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 167725d31..bd0283888 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -400,8 +400,6 @@ public: lia_move gomory::get_gomory_cuts(unsigned num_cuts) { struct cut_result {u_dependency *dep; lar_term t; mpq k; int polarity; lpvar j;}; vector big_cuts; - struct polar_info {lpvar j; int polarity; u_dependency *dep;}; - vector polar_vars; unsigned_vector columns_for_cuts = gomory_select_int_infeasible_vars(num_cuts); bool has_small_cut = false; @@ -437,10 +435,14 @@ public: return lia_move::conflict; continue; } + + if (cc.m_polarity == 1) + lra.update_column_type_and_bound(j, lp::lconstraint_kind::LE, floor(lra.get_column_value(j).x), cc.m_dep); + else if (cc.m_polarity == -1) + lra.update_column_type_and_bound(j, lp::lconstraint_kind::GE, ceil(lra.get_column_value(j).x), cc.m_dep); + + cut_result cr = {cc.m_dep, lia.m_t, lia.m_k, cc.m_polarity, j}; - if (abs(cr.polarity) == 1) // need to delay the update of the bounds for j in a polar case, because simplify_inequality relies on the old bounds - polar_vars.push_back( {j, cr.polarity, cc.m_dep} ); - if (!is_small_cut(lia.m_t)) { big_cuts.push_back(cr); continue; @@ -463,17 +465,6 @@ public: add_cut(cut); } - -// this way we create bounds for the variables in polar cases even where the terms have big numbers - for (auto const& p : polar_vars) { - if (p.polarity == 1) { - lra.update_column_type_and_bound(p.j, lp::lconstraint_kind::LE, floor(lra.get_column_value(p.j).x), p.dep); - } - else { - SASSERT(p.polarity == -1); - lra.update_column_type_and_bound(p.j, lp::lconstraint_kind::GE, ceil(lra.get_column_value(p.j).x), p.dep); - } - } if (!_check_feasible()) return lia_move::conflict; From 2d2443658287c54cdad4dd712839ed0d1c2dc467 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 11 Jan 2024 13:42:35 -1000 Subject: [PATCH 080/224] remove a blank line Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index bd0283888..b1ac51d4d 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -441,7 +441,6 @@ public: else if (cc.m_polarity == -1) lra.update_column_type_and_bound(j, lp::lconstraint_kind::GE, ceil(lra.get_column_value(j).x), cc.m_dep); - cut_result cr = {cc.m_dep, lia.m_t, lia.m_k, cc.m_polarity, j}; if (!is_small_cut(lia.m_t)) { big_cuts.push_back(cr); From 999e67df0db670d86275acee572f4f89ccf0c505 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 11 Jan 2024 16:49:10 -1000 Subject: [PATCH 081/224] address Nikolaj's comments in Gomory cut Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.cpp | 62 ++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index b1ac51d4d..d414f88ef 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -23,7 +23,8 @@ #include "math/lp/lp_utils.h" namespace lp { - + +enum class row_polarity { UNDEF, MIN, MAX, MIXED}; struct create_cut { lar_term & m_t; // the term to return in the cut mpq & m_k; // the right side of the cut @@ -36,7 +37,7 @@ struct create_cut { mpq m_fj; mpq m_one_minus_fj; mpq m_abs_max, m_big_number; - int m_polarity; + row_polarity m_polarity; bool m_found_big; u_dependency* m_dep; @@ -85,10 +86,10 @@ struct create_cut { m_found_big = true; } - void set_polarity(int p) { - if (m_polarity == 2) return; - if (m_polarity == 0) m_polarity = p; - else if (m_polarity != p) m_polarity = 2; + void set_polarity(row_polarity p) { + if (m_polarity == row_polarity::MIXED) return; + if (m_polarity == row_polarity::UNDEF) m_polarity = p; + else if (m_polarity != p) m_polarity = row_polarity::MIXED; } void real_case_in_gomory_cut(const mpq & a, unsigned j) { @@ -98,12 +99,12 @@ struct create_cut { if (a.is_pos()) { // the delta is a (x - f) is positive it has to grow and fight m_one_minus_f new_a = a / m_one_minus_f; - set_polarity(1); + set_polarity(row_polarity::MAX); } else { // the delta is negative and it works again m_f new_a = - a / m_f; - set_polarity(-1); + set_polarity(row_polarity::MIN); } m_k.addmul(new_a, lower_bound(j).x); // is it a faster operation than // k += lower_bound(j).x * new_a; @@ -114,12 +115,12 @@ struct create_cut { if (a.is_pos()) { // the delta is works again m_f new_a = - a / m_f; - set_polarity(-1); + set_polarity(row_polarity::MIN); } else { // the delta is positive works again m_one_minus_f new_a = a / m_one_minus_f; - set_polarity(1); + set_polarity(row_polarity::MAX); } m_k.addmul(new_a, upper_bound(j).x); // k += upper_bound(j).x * new_a; push_explanation(column_upper_bound_constraint(j)); @@ -246,7 +247,12 @@ public: lia_move cut() { TRACE("gomory_cut", dump(tout);); - m_polarity = 0; // 0: means undefined, +-1, the polar case, 2: the mixed case + // If m_polarity is MAX, then + // the row constraints the base variable to be at the maximum, + // MIN - at the minimum, + // MIXED : the row does not constraint the base variable to be at an extremum + // UNDEF is the initial state + m_polarity = row_polarity::UNDEF; // gomory cut will be m_t >= m_k and the current solution has a property m_t < m_k m_k = 1; m_t.clear(); @@ -284,15 +290,15 @@ public: } if (p.coeff().is_pos()) { if (at_lower(j)) - set_polarity(1); + set_polarity(row_polarity::MAX); else - set_polarity(-1); + set_polarity(row_polarity::MIN); } else { if (at_lower(j)) - set_polarity(-1); + set_polarity(row_polarity::MIN); else - set_polarity(1); + set_polarity(row_polarity::MAX); } } @@ -398,7 +404,7 @@ public: lia_move gomory::get_gomory_cuts(unsigned num_cuts) { - struct cut_result {u_dependency *dep; lar_term t; mpq k; int polarity; lpvar j;}; + struct cut_result {lar_term t; mpq k; u_dependency *dep;}; vector big_cuts; unsigned_vector columns_for_cuts = gomory_select_int_infeasible_vars(num_cuts); bool has_small_cut = false; @@ -407,12 +413,10 @@ public: auto is_small_cut = [&](lar_term const& t) { return all_of(t, [&](auto ci) { return ci.coeff().is_small(); }); }; - auto add_cut = [&](cut_result const& cr) { - lp::lpvar term_index = lra.add_term(cr.t.coeffs_as_vector(), UINT_MAX); + auto add_cut = [&](const lar_term& t, const mpq& k, u_dependency * dep) { + lp::lpvar term_index = lra.add_term(t.coeffs_as_vector(), UINT_MAX); term_index = lra.map_term_index_to_column_index(term_index); - lra.update_column_type_and_bound(term_index, - lp::lconstraint_kind::GE, - cr.k, cr.dep); + lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::GE, k, dep); }; auto _check_feasible = [&](void) { lra.find_feasible_solution(); @@ -436,18 +440,17 @@ public: continue; } - if (cc.m_polarity == 1) + if (cc.m_polarity == row_polarity::MAX) lra.update_column_type_and_bound(j, lp::lconstraint_kind::LE, floor(lra.get_column_value(j).x), cc.m_dep); - else if (cc.m_polarity == -1) + else if (cc.m_polarity == row_polarity::MIN) lra.update_column_type_and_bound(j, lp::lconstraint_kind::GE, ceil(lra.get_column_value(j).x), cc.m_dep); - - cut_result cr = {cc.m_dep, lia.m_t, lia.m_k, cc.m_polarity, j}; + if (!is_small_cut(lia.m_t)) { - big_cuts.push_back(cr); + big_cuts.push_back({cc.m_t, cc.m_k, cc.m_dep}); continue; } has_small_cut = true; - add_cut(cr); + add_cut(cc.m_t, cc.m_k, cc.m_dep); if (lia.settings().get_cancel_flag()) return lia_move::undef; } @@ -455,14 +458,13 @@ public: if (big_cuts.size()) { lra.push(); for (auto const& cut : big_cuts) - add_cut(cut); + add_cut(cut.t, cut.k, cut.dep); bool feas = _check_feasible(); lra.pop(1); if (!feas) for (auto const& cut : big_cuts) - add_cut(cut); - + add_cut(cut.t, cut.k, cut.dep); } if (!_check_feasible()) From 59b18d4a14eeec6bd887b8135e34677f373e9f02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 12 Jan 2024 09:19:11 -0800 Subject: [PATCH 082/224] create as_bin as_hex wrappers for display Signed-off-by: Nikolaj Bjorner --- src/api/api_numeral.cpp | 2 +- src/ast/bv_decl_plugin.cpp | 8 ++------ src/util/rational.h | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/api/api_numeral.cpp b/src/api/api_numeral.cpp index 98dceffb7..b90a84bb7 100644 --- a/src/api/api_numeral.cpp +++ b/src/api/api_numeral.cpp @@ -188,7 +188,7 @@ extern "C" { bool ok = Z3_get_numeral_rational(c, a, r); if (ok && r.is_int() && !r.is_neg()) { std::stringstream strm; - r.display_bin(strm, r.get_num_bits()); + strm << r.as_bin(r.get_num_bits()); return mk_c(c)->mk_external_string(std::move(strm).str()); } else { diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 6b2106f3f..327e280cf 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -912,13 +912,9 @@ app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const { if (m_plugin->log_constant_meaning_prelude(r)) { if (bv_size % 4 == 0) { - m_manager.trace_stream() << "#x"; - val.display_hex(m_manager.trace_stream(), bv_size); - m_manager.trace_stream() << "\n"; + m_manager.trace_stream() << "#x" << val.as_hex(bv_size) << "\n"; } else { - m_manager.trace_stream() << "#b"; - val.display_bin(m_manager.trace_stream(), bv_size); - m_manager.trace_stream() << "\n"; + m_manager.trace_stream() << "#b" << val.as_bin(bv_size) << "\n"; } } diff --git a/src/util/rational.h b/src/util/rational.h index db60077ac..e9924bca7 100644 --- a/src/util/rational.h +++ b/src/util/rational.h @@ -30,6 +30,10 @@ class rational { static synch_mpq_manager & m() { return *g_mpq_manager; } + void display_hex(std::ostream & out, unsigned num_bits) const { SASSERT(is_int()); m().display_hex(out, m_val.numerator(), num_bits); } + + void display_bin(std::ostream& out, unsigned num_bits) const { SASSERT(is_int()); m().display_bin(out, m_val.numerator(), num_bits); } + public: static void initialize(); static void finalize(); @@ -96,9 +100,33 @@ public: void display_smt2(std::ostream & out) const { return m().display_smt2(out, m_val, false); } - void display_hex(std::ostream & out, unsigned num_bits) const { SASSERT(is_int()); return m().display_hex(out, m_val.numerator(), num_bits); } - void display_bin(std::ostream & out, unsigned num_bits) const { SASSERT(is_int()); return m().display_bin(out, m_val.numerator(), num_bits); } + struct as_hex_wrapper { + rational const& r; + unsigned bw; + }; + + as_hex_wrapper as_hex(unsigned bw) const { return as_hex_wrapper{*this, bw}; } + + friend inline std::ostream& operator<<(std::ostream& out, as_hex_wrapper const& ab) { + ab.r.display_hex(out, ab.bw); + return out; + } + + + + struct as_bin_wrapper { + rational const& r; + unsigned bw; + }; + + as_bin_wrapper as_bin(unsigned bw) const { return as_bin_wrapper{*this, bw}; } + + friend inline std::ostream& operator<<(std::ostream& out, as_bin_wrapper const& ab) { + ab.r.display_bin(out, ab.bw); + return out; + } + bool is_uint64() const { return m().is_uint64(m_val); } From 27171591d1d6c94978f5d7f7122b0b8b2f0bc321 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 12 Jan 2024 09:49:56 -0800 Subject: [PATCH 083/224] Update sat_params.pyg spellcheck from https://github.com/microsoft/z3guide/pull/165 --- src/sat/sat_params.pyg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sat/sat_params.pyg b/src/sat/sat_params.pyg index d40d606d1..370bf1dea 100644 --- a/src/sat/sat_params.pyg +++ b/src/sat/sat_params.pyg @@ -64,7 +64,7 @@ def_module_params('sat', ('ddfw_search', BOOL, False, 'use ddfw local search instead of CDCL'), ('ddfw.init_clause_weight', UINT, 8, 'initial clause weight for DDFW local search'), ('ddfw.use_reward_pct', UINT, 15, 'percentage to pick highest reward variable when it has reward 0'), - ('ddfw.restart_base', UINT, 100000, 'number of flips used a starting point for hessitant restart backoff'), + ('ddfw.restart_base', UINT, 100000, 'number of flips used a starting point for hesitant restart backoff'), ('ddfw.reinit_base', UINT, 10000, 'increment basis for geometric backoff scheme of re-initialization of weights'), ('ddfw.threads', UINT, 0, 'number of ddfw threads to run in parallel with sat solver'), ('prob_search', BOOL, False, 'use probsat local search instead of CDCL'), @@ -105,7 +105,7 @@ def_module_params('sat', ('lookahead.preselect', BOOL, False, 'use pre-selection of subset of variables for branching'), ('lookahead_simplify', BOOL, False, 'use lookahead solver during simplification'), ('lookahead_scores', BOOL, False, 'extract lookahead scores. A utility that can only be used from the DIMACS front-end'), - ('lookahead.double', BOOL, True, 'enable doubld lookahead'), + ('lookahead.double', BOOL, True, 'enable double lookahead'), ('lookahead.use_learned', BOOL, False, 'use learned clauses when selecting lookahead literal'), ('lookahead_simplify.bca', BOOL, True, 'add learned binary clauses as part of lookahead simplification'), ('lookahead.global_autarky', BOOL, False, 'prefer to branch on variables that occur in clauses that are reduced'), From 3381fd2b52615189895a2704a474b9a5ba7637a4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 12 Jan 2024 09:57:41 -0800 Subject: [PATCH 084/224] spell check from https://github.com/microsoft/z3guide/pull/165 Signed-off-by: Nikolaj Bjorner --- src/math/polynomial/algebraic_params.pyg | 2 +- src/opt/opt_params.pyg | 4 ++-- src/smt/params/smt_params_helper.pyg | 3 +-- src/solver/parallel_params.pyg | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/math/polynomial/algebraic_params.pyg b/src/math/polynomial/algebraic_params.pyg index 773548494..0e53a40b8 100644 --- a/src/math/polynomial/algebraic_params.pyg +++ b/src/math/polynomial/algebraic_params.pyg @@ -5,6 +5,6 @@ def_module_params('algebraic', ('min_mag', UINT, 16, 'Z3 represents algebraic numbers using a (square-free) polynomial p and an isolating interval (which contains one and only one root of p). This interval may be refined during the computations. This parameter specifies whether to cache the value of a refined interval or not. It says the minimal size of an interval for caching purposes is 1/2^16'), ('factor', BOOL, True, 'use polynomial factorization to simplify polynomials representing algebraic numbers'), ('factor_max_prime', UINT, 31, 'parameter for the polynomial factorization procedure in the algebraic number module. Z3 polynomial factorization is composed of three steps: factorization in GF(p), lifting and search. This parameter limits the maximum prime number p to be used in the first step'), - ('factor_num_primes', UINT, 1, 'parameter for the polynomial factorization procedure in the algebraic number module. Z3 polynomial factorization is composed of three steps: factorization in GF(p), lifting and search. The search space may be reduced by factoring the polynomial in different GF(p)\'s. This parameter specify the maximum number of finite factorizations to be considered, before lifiting and searching'), + ('factor_num_primes', UINT, 1, 'parameter for the polynomial factorization procedure in the algebraic number module. Z3 polynomial factorization is composed of three steps: factorization in GF(p), lifting and search. The search space may be reduced by factoring the polynomial in different GF(p)\'s. This parameter specify the maximum number of finite factorizations to be considered, before lifting and searching'), ('factor_search_size', UINT, 5000, 'parameter for the polynomial factorization procedure in the algebraic number module. Z3 polynomial factorization is composed of three steps: factorization in GF(p), lifting and search. This parameter can be used to limit the search space'))) diff --git a/src/opt/opt_params.pyg b/src/opt/opt_params.pyg index 893b4bfd6..15f5e5d05 100644 --- a/src/opt/opt_params.pyg +++ b/src/opt/opt_params.pyg @@ -3,7 +3,7 @@ def_module_params('opt', export=True, params=(('optsmt_engine', SYMBOL, 'basic', "select optimization engine: 'basic', 'symba'"), ('maxsat_engine', SYMBOL, 'maxres', "select engine for maxsat: 'core_maxsat', 'wmax', 'maxres', 'pd-maxres', 'maxres-bin', 'rc2'"), - ('priority', SYMBOL, 'lex', "select how to priortize objectives: 'lex' (lexicographic), 'pareto', 'box'"), + ('priority', SYMBOL, 'lex', "select how to prioritize objectives: 'lex' (lexicographic), 'pareto', 'box'"), ('dump_benchmarks', BOOL, False, 'dump benchmarks for profiling'), ('dump_models', BOOL, False, 'display intermediary models to stdout'), ('solution_prefix', SYMBOL, '', "path prefix to dump intermediary, but non-optimal, solutions"), @@ -22,7 +22,7 @@ def_module_params('opt', ('maxlex.enable', BOOL, True, 'enable maxlex heuristic for lexicographic MaxSAT problems'), ('rc2.totalizer', BOOL, True, 'use totalizer for rc2 encoding'), ('maxres.hill_climb', BOOL, True, 'give preference for large weight cores'), - ('maxres.add_upper_bound_block', BOOL, False, 'restict upper bound with constraint'), + ('maxres.add_upper_bound_block', BOOL, False, 'restrict upper bound with constraint'), ('maxres.max_num_cores', UINT, 200, 'maximal number of cores per round'), ('maxres.max_core_size', UINT, 3, 'break batch of generated cores if size reaches this number'), ('maxres.maximize_assignment', BOOL, False, 'find an MSS/MCS to improve current assignment'), diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index 6ec362449..f2e08aaf5 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -99,14 +99,13 @@ def_module_params(module_name='smt', ('arith.enable_hnf', BOOL, True, 'enable hnf (Hermite Normal Form) cuts'), ('arith.bprop_on_pivoted_rows', BOOL, True, 'propagate bounds on rows changed by the pivot operation'), ('arith.print_ext_var_names', BOOL, False, 'print external variable names'), - ('arith.validate', BOOL, False, 'validate lemmas generated by arithmetic solver'), ('pb.conflict_frequency', UINT, 1000, 'conflict frequency for Pseudo-Boolean theory'), ('pb.learn_complements', BOOL, True, 'learn complement literals for Pseudo-Boolean theory'), ('array.weak', BOOL, False, 'weak array theory'), ('array.extensional', BOOL, True, 'extensional array theory'), ('clause_proof', BOOL, False, 'record a clausal proof'), ('dack', UINT, 1, '0 - disable dynamic ackermannization, 1 - expand Leibniz\'s axiom if a congruence is the root of a conflict, 2 - expand Leibniz\'s axiom if a congruence is used during conflict resolution'), - ('dack.eq', BOOL, False, 'enable dynamic ackermannization for transtivity of equalities'), + ('dack.eq', BOOL, False, 'enable dynamic ackermannization for transitivity of equalities'), ('dack.factor', DOUBLE, 0.1, 'number of instance per conflict'), ('dack.gc', UINT, 2000, 'Dynamic ackermannization garbage collection frequency (per conflict)'), ('dack.gc_inv_decay', DOUBLE, 0.8, 'Dynamic ackermannization garbage collection decay'), diff --git a/src/solver/parallel_params.pyg b/src/solver/parallel_params.pyg index 628d4242a..60a77d49a 100644 --- a/src/solver/parallel_params.pyg +++ b/src/solver/parallel_params.pyg @@ -10,7 +10,7 @@ def_module_params('parallel', ('conquer.delay', UINT, 10, 'delay of cubes until applying conquer'), ('conquer.backtrack_frequency', UINT, 10, 'frequency to apply core minimization during conquer'), ('simplify.exp', DOUBLE, 1, 'restart and inprocess max is multiplied by simplify.exp ^ depth'), - ('simplify.max_conflicts', UINT, UINT_MAX, 'maximal number of conflicts during simplifcation phase'), + ('simplify.max_conflicts', UINT, UINT_MAX, 'maximal number of conflicts during simplification phase'), ('simplify.restart.max', UINT, 5000, 'maximal number of restarts during simplification phase'), ('simplify.inprocess.max', UINT, 2, 'maximal number of inprocessing steps during simplification'), )) From ddf2eb57d629eb702fcdf30edd963645ed0d3da1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 12 Jan 2024 10:42:08 -0800 Subject: [PATCH 085/224] deleted parameter Signed-off-by: Nikolaj Bjorner --- src/ast/euf/euf_ac_plugin.cpp | 2 +- src/smt/params/smt_params_helper.pyg | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/euf/euf_ac_plugin.cpp b/src/ast/euf/euf_ac_plugin.cpp index ce0817e00..5e8ec997f 100644 --- a/src/ast/euf/euf_ac_plugin.cpp +++ b/src/ast/euf/euf_ac_plugin.cpp @@ -80,7 +80,7 @@ namespace euf { } ac_plugin::ac_plugin(egraph& g, func_decl* f) : - plugin(g), m_decl(f), m_fid(f->get_family_id()), + plugin(g), m_fid(f->get_family_id()), m_decl(f), m_dep_manager(get_region()), m_hash(*this), m_eq(*this), m_monomial_table(m_hash, m_eq) { diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index f2e08aaf5..c4660d1ea 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -95,6 +95,7 @@ def_module_params(module_name='smt', ('arith.rep_freq', UINT, 0, 'the report frequency, in how many iterations print the cost and other info'), ('arith.min', BOOL, False, 'minimize cost'), ('arith.print_stats', BOOL, False, 'print statistic'), + ('arith.validate', BOOL, False, 'validate lemmas generated by arithmetic solver'), ('arith.simplex_strategy', UINT, 0, 'simplex strategy for the solver'), ('arith.enable_hnf', BOOL, True, 'enable hnf (Hermite Normal Form) cuts'), ('arith.bprop_on_pivoted_rows', BOOL, True, 'propagate bounds on rows changed by the pivot operation'), From 7d7fef061f2ac296835f23e22e8be70bdd9eeef3 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 12 Jan 2024 15:28:16 -1000 Subject: [PATCH 086/224] add explanations and fix polarity Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.cpp | 57 +++++++++++++++++++++++++++++++++------- src/math/lp/int_solver.h | 2 +- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index d414f88ef..a2e65564b 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -99,12 +99,12 @@ struct create_cut { if (a.is_pos()) { // the delta is a (x - f) is positive it has to grow and fight m_one_minus_f new_a = a / m_one_minus_f; - set_polarity(row_polarity::MAX); + set_polarity(row_polarity::MIN); // reverse the polarity since a = -p.coeff() } else { // the delta is negative and it works again m_f new_a = - a / m_f; - set_polarity(row_polarity::MIN); + set_polarity(row_polarity::MAX); } m_k.addmul(new_a, lower_bound(j).x); // is it a faster operation than // k += lower_bound(j).x * new_a; @@ -115,12 +115,12 @@ struct create_cut { if (a.is_pos()) { // the delta is works again m_f new_a = - a / m_f; - set_polarity(row_polarity::MIN); + set_polarity(row_polarity::MAX); } else { // the delta is positive works again m_one_minus_f new_a = a / m_one_minus_f; - set_polarity(row_polarity::MAX); + set_polarity(row_polarity::MIN); } m_k.addmul(new_a, upper_bound(j).x); // k += upper_bound(j).x * new_a; push_explanation(column_upper_bound_constraint(j)); @@ -288,14 +288,21 @@ public: m_one_minus_fj = 1 - m_fj; int_case_in_gomory_cut(j); } + bool lb = at_lower(j); + if (lb) { + push_explanation(column_lower_bound_constraint(j)); + } else { + SASSERT(at_upper(j)); + push_explanation(column_upper_bound_constraint(j)); + } if (p.coeff().is_pos()) { - if (at_lower(j)) + if (lb) set_polarity(row_polarity::MAX); else set_polarity(row_polarity::MIN); } else { - if (at_lower(j)) + if (lb) set_polarity(row_polarity::MIN); else set_polarity(row_polarity::MAX); @@ -402,6 +409,38 @@ public: return ret; } + row_polarity test_row_polarity(const int_solver& lia, const row_strip& row, lpvar basic_j) { + row_polarity ret = row_polarity::UNDEF; + for (const auto& p : row) { + lpvar j = p.var(); + if (j == basic_j) + continue; + if (lia.is_fixed(j)) + continue; + + row_polarity rp; + if (p.coeff().is_pos()) { + if (lia.at_lower(j)) + rp = row_polarity::MAX; + else if (lia.at_upper(j)) + rp = row_polarity::MIN; + else SASSERT(false); + } + else { + if (lia.at_lower(j)) + rp = row_polarity::MIN; + else if (lia.at_upper(j)) + rp = row_polarity::MAX; + else SASSERT(false); + + } + if (ret == row_polarity::UNDEF) + ret = rp; + if (ret != rp) + return row_polarity::MIXED; + } + return ret; + } lia_move gomory::get_gomory_cuts(unsigned num_cuts) { struct cut_result {lar_term t; mpq k; u_dependency *dep;}; @@ -429,22 +468,22 @@ public: // start creating cuts for (unsigned j : columns_for_cuts) { + SASSERT(is_gomory_cut_target(j)); unsigned row_index = lia.row_of_basic_column(j); const row_strip& row = lra.get_row(row_index); create_cut cc(lia.m_t, lia.m_k, lia.m_ex, j, row, lia); auto r = cc.cut(); - if (r != lia_move::cut) { if (r == lia_move::conflict) return lia_move::conflict; continue; } - + SASSERT(test_row_polarity(lia, row, j) == cc.m_polarity); if (cc.m_polarity == row_polarity::MAX) lra.update_column_type_and_bound(j, lp::lconstraint_kind::LE, floor(lra.get_column_value(j).x), cc.m_dep); else if (cc.m_polarity == row_polarity::MIN) lra.update_column_type_and_bound(j, lp::lconstraint_kind::GE, ceil(lra.get_column_value(j).x), cc.m_dep); - + if (!is_small_cut(lia.m_t)) { big_cuts.push_back({cc.m_t, cc.m_k, cc.m_dep}); continue; diff --git a/src/math/lp/int_solver.h b/src/math/lp/int_solver.h index d4bffeadc..5f8e3eeb5 100644 --- a/src/math/lp/int_solver.h +++ b/src/math/lp/int_solver.h @@ -94,7 +94,6 @@ private: // lia_move patch_nbasic_columns(); bool get_freedom_interval_for_column(unsigned j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m); bool is_boxed(unsigned j) const; - bool is_fixed(unsigned j) const; bool is_free(unsigned j) const; bool value_is_int(unsigned j) const; bool is_feasible() const; @@ -113,6 +112,7 @@ private: bool cut_indices_are_columns() const; public: + bool is_fixed(unsigned j) const; std::ostream& display_column(std::ostream & out, unsigned j) const; u_dependency* column_upper_bound_constraint(unsigned j) const; u_dependency* column_lower_bound_constraint(unsigned j) const; From 2eadcf0872b6feab9ff42db552b1df4740d4f34b Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 12 Jan 2024 15:49:21 -1000 Subject: [PATCH 087/224] avoid duplicate explanations Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index a2e65564b..2f8eaf8fc 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -69,16 +69,14 @@ struct create_cut { // here we have the product of new_a*(xj - lb(j)), so new_a*lb(j) is added to m_k new_a = m_fj <= m_one_minus_f ? m_fj / m_one_minus_f : ((1 - m_fj) / m_f); lp_assert(new_a.is_pos()); - m_k.addmul(new_a, lower_bound(j).x); - push_explanation(column_lower_bound_constraint(j)); + m_k.addmul(new_a, lower_bound(j).x); } else { lp_assert(at_upper(j)); // here we have the expression new_a*(xj - ub), so new_a*ub(j) is added to m_k new_a = - (m_fj <= m_f ? m_fj / m_f : ((1 - m_fj) / m_one_minus_f)); lp_assert(new_a.is_neg()); - m_k.addmul(new_a, upper_bound(j).x); - push_explanation(column_upper_bound_constraint(j)); + m_k.addmul(new_a, upper_bound(j).x); } m_t.add_monomial(new_a, j); TRACE("gomory_cut_detail", tout << "new_a = " << new_a << ", k = " << m_k << "\n";); From e2fb4fbd387f06bd670146163df11ee650eb50cd Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 13 Jan 2024 19:01:21 -1000 Subject: [PATCH 088/224] fix dependencies for Gomory polarity Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.cpp | 42 +++++++++++++++++++++++++++++------------- src/math/lp/gomory.h | 2 +- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 2f8eaf8fc..84165cd20 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -69,14 +69,16 @@ struct create_cut { // here we have the product of new_a*(xj - lb(j)), so new_a*lb(j) is added to m_k new_a = m_fj <= m_one_minus_f ? m_fj / m_one_minus_f : ((1 - m_fj) / m_f); lp_assert(new_a.is_pos()); - m_k.addmul(new_a, lower_bound(j).x); + m_k.addmul(new_a, lower_bound(j).x); + push_explanation(column_lower_bound_constraint(j)); } else { lp_assert(at_upper(j)); // here we have the expression new_a*(xj - ub), so new_a*ub(j) is added to m_k new_a = - (m_fj <= m_f ? m_fj / m_f : ((1 - m_fj) / m_one_minus_f)); lp_assert(new_a.is_neg()); - m_k.addmul(new_a, upper_bound(j).x); + m_k.addmul(new_a, upper_bound(j).x); + push_explanation(column_upper_bound_constraint(j)); } m_t.add_monomial(new_a, j); TRACE("gomory_cut_detail", tout << "new_a = " << new_a << ", k = " << m_k << "\n";); @@ -286,21 +288,14 @@ public: m_one_minus_fj = 1 - m_fj; int_case_in_gomory_cut(j); } - bool lb = at_lower(j); - if (lb) { - push_explanation(column_lower_bound_constraint(j)); - } else { - SASSERT(at_upper(j)); - push_explanation(column_upper_bound_constraint(j)); - } if (p.coeff().is_pos()) { - if (lb) + if (at_lower(j)) set_polarity(row_polarity::MAX); else set_polarity(row_polarity::MIN); } else { - if (lb) + if (at_lower(j)) set_polarity(row_polarity::MIN); else set_polarity(row_polarity::MAX); @@ -440,6 +435,27 @@ public: return ret; } + u_dependency* gomory::add_deps(u_dependency* dep, const row_strip& row, lpvar basic_var) { + u_dependency* ret = dep; + for (const auto& p : row) { + lpvar j = p.var(); + if (j == basic_var) + continue; + if (lia.is_fixed(j)) + continue; + if (lia.is_real(j)) continue; + if (!p.coeff().is_int()) continue; + // the explanation for all above have been already added + if (lia.at_lower(j)) + ret = lia.lra.dep_manager().mk_join(lia.column_lower_bound_constraint(j), ret); + else { + SASSERT(lia.at_upper(j)); + ret = lia.lra.dep_manager().mk_join(lia.column_upper_bound_constraint(j), ret); + } + } + return ret; + } + lia_move gomory::get_gomory_cuts(unsigned num_cuts) { struct cut_result {lar_term t; mpq k; u_dependency *dep;}; vector big_cuts; @@ -478,9 +494,9 @@ public: } SASSERT(test_row_polarity(lia, row, j) == cc.m_polarity); if (cc.m_polarity == row_polarity::MAX) - lra.update_column_type_and_bound(j, lp::lconstraint_kind::LE, floor(lra.get_column_value(j).x), cc.m_dep); + lra.update_column_type_and_bound(j, lp::lconstraint_kind::LE, floor(lra.get_column_value(j).x), add_deps(cc.m_dep, row, j)); else if (cc.m_polarity == row_polarity::MIN) - lra.update_column_type_and_bound(j, lp::lconstraint_kind::GE, ceil(lra.get_column_value(j).x), cc.m_dep); + lra.update_column_type_and_bound(j, lp::lconstraint_kind::GE, ceil(lra.get_column_value(j).x), add_deps(cc.m_dep, row, j)); if (!is_small_cut(lia.m_t)) { big_cuts.push_back({cc.m_t, cc.m_k, cc.m_dep}); diff --git a/src/math/lp/gomory.h b/src/math/lp/gomory.h index 2586a4d31..8354bf01f 100644 --- a/src/math/lp/gomory.h +++ b/src/math/lp/gomory.h @@ -30,7 +30,7 @@ namespace lp { lia_move cut(lar_term & t, mpq & k, explanation* ex, unsigned basic_inf_int_j, const row_strip& row); unsigned_vector gomory_select_int_infeasible_vars(unsigned num_cuts); bool is_gomory_cut_target(lpvar j); - lia_move get_cut(lpvar j); + u_dependency* add_deps(u_dependency*, const row_strip&, lpvar); public: lia_move get_gomory_cuts(unsigned num_cuts); gomory(int_solver& lia); From d8df203622a519a7e54a72b22a479e7be9e02318 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 13 Jan 2024 19:11:17 -1000 Subject: [PATCH 089/224] remove an unused declaration Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/math/lp/gomory.h b/src/math/lp/gomory.h index 8354bf01f..0fdf4f8fe 100644 --- a/src/math/lp/gomory.h +++ b/src/math/lp/gomory.h @@ -27,7 +27,6 @@ namespace lp { class gomory { class int_solver& lia; class lar_solver& lra; - lia_move cut(lar_term & t, mpq & k, explanation* ex, unsigned basic_inf_int_j, const row_strip& row); unsigned_vector gomory_select_int_infeasible_vars(unsigned num_cuts); bool is_gomory_cut_target(lpvar j); u_dependency* add_deps(u_dependency*, const row_strip&, lpvar); From 91ca55e5ad159abcc6c90c5576af57076c7b52bc Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 14 Jan 2024 13:37:30 -1000 Subject: [PATCH 090/224] change the definition of Gomory row Signed-off-by: Lev Nachmanson --- src/math/lp/gomory.cpp | 58 +++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 84165cd20..a7c72a76d 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -261,7 +261,26 @@ public: TRACE("gomory_cut_detail", tout << "m_f: " << m_f << ", "; tout << "1 - m_f: " << 1 - m_f << ", get_value(m_inf_col).x - m_f = " << get_value(m_inf_col).x - m_f << "\n";); lp_assert(m_f.is_pos() && (get_value(m_inf_col).x - m_f).is_int()); - + auto set_polarity_for_int = [&](const mpq & a, lpvar j) { + if (a.is_pos()) { + if (at_lower(j)) + set_polarity(row_polarity::MAX); + else if (at_upper(j)) + set_polarity(row_polarity::MIN); + else + set_polarity(row_polarity::MIXED); + } + else { + if (at_lower(j)) + set_polarity(row_polarity::MIN); + else if (at_upper(j)) + set_polarity(row_polarity::MAX); + else + set_polarity(row_polarity::MIXED); + } + }; + + m_abs_max = 0; for (const auto & p : m_row) { mpq t = abs(ceil(p.coeff())); @@ -288,18 +307,9 @@ public: m_one_minus_fj = 1 - m_fj; int_case_in_gomory_cut(j); } - if (p.coeff().is_pos()) { - if (at_lower(j)) - set_polarity(row_polarity::MAX); - else - set_polarity(row_polarity::MIN); - } - else { - if (at_lower(j)) - set_polarity(row_polarity::MIN); - else - set_polarity(row_polarity::MAX); - } + if (m_polarity != row_polarity::MIXED) + set_polarity_for_int(p.coeff(), j); + } if (m_found_big) { @@ -338,12 +348,22 @@ public: bool gomory::is_gomory_cut_target(lpvar k) { SASSERT(lia.is_base(k)); - // All non base variables must be at their bounds and assigned to rationals (that is, infinitesimals are not allowed). const row_strip& row = lra.get_row(lia.row_of_basic_column(k)); + // Consider monomial c*x from the row, where x is non-basic. + // Then, for each such monomial, one of following conditions + // has to hold for the row to be eligible for Gomory cut: + // 1) c is integral and x integral varible with an integral value + // 2) the value of x is at a bound and has no infinitesimals. + + unsigned j; for (const auto & p : row) { j = p.var(); - if ( k != j && (!lia.at_bound(j) || lia.get_value(j).y != 0)) { + if (k == j) continue; + + if (p.coeff().is_int() && lia.column_is_int(j) && lia.get_value(j).is_int()) continue; + + if ( !lia.at_bound(j) || lia.get_value(j).y != 0) { TRACE("gomory_cut", tout << "row is not gomory cut target:\n"; lia.display_column(tout, j); tout << "infinitesimal: " << !(lia.get_value(j).y ==0) << "\n";); @@ -351,6 +371,8 @@ public: } } return true; + + // Condition 1) above can be relaxed even more, allowing any value for x, but it will change the calculation for m_f. } // return the minimal distance from the variable value to an integer @@ -417,14 +439,16 @@ public: rp = row_polarity::MAX; else if (lia.at_upper(j)) rp = row_polarity::MIN; - else SASSERT(false); + else + rp = row_polarity::MIXED; } else { if (lia.at_lower(j)) rp = row_polarity::MIN; else if (lia.at_upper(j)) rp = row_polarity::MAX; - else SASSERT(false); + else + rp = row_polarity::MIXED; } if (ret == row_polarity::UNDEF) From 4ff352fcace8880e3607f643683ca6e9c88c87fd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Jan 2024 08:49:10 -0800 Subject: [PATCH 091/224] fix #7084 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp index 68e3825c9..bb8b067e8 100644 --- a/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp +++ b/src/ast/rewriter/bit_blaster/bit_blaster_rewriter.cpp @@ -615,6 +615,8 @@ MK_PARAMETRIC_UNARY_REDUCE(reduce_sign_extend, mk_sign_extend); if (m_blast_quant) { if (m_bindings.empty()) return false; + if (!butil().is_bv(t)) + return false; unsigned shift = m_shifts.back(); if (t->get_idx() >= m_bindings.size()) { if (shift == 0) From afba43a5a732afa18f361686e5e68135d0a5e02a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Jan 2024 10:18:46 -0800 Subject: [PATCH 092/224] fix #7085 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3printer.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/api/python/z3/z3printer.py b/src/api/python/z3/z3printer.py index 228f212d9..df50aa9b9 100644 --- a/src/api/python/z3/z3printer.py +++ b/src/api/python/z3/z3printer.py @@ -252,11 +252,11 @@ def _is_html_left_assoc(k): def _is_add(k): - return k == Z3_OP_ADD or k == Z3_OP_BADD + return k == Z3_OP_ADD or k == Z3_OP_BADD or k == Z3_OP_FPA_ADD def _is_sub(k): - return k == Z3_OP_SUB or k == Z3_OP_BSUB + return k == Z3_OP_SUB or k == Z3_OP_BSUB or k == Z3_OP_FPA_SUB if sys.version_info.major < 3: @@ -890,9 +890,21 @@ class Formatter: if self.is_infix(k) and n >= 3: rm = a.arg(0) if z3.is_fprm_value(rm) and z3.get_default_rounding_mode(a.ctx).eq(rm): - arg1 = to_format(self.pp_expr(a.arg(1), d + 1, xs)) - arg2 = to_format(self.pp_expr(a.arg(2), d + 1, xs)) + p = self.get_precedence(k) r = [] + x = a.arg(1) + y = a.arg(2) + arg1 = to_format(self.pp_expr(x, d + 1, xs)) + arg2 = to_format(self.pp_expr(y, d + 1, xs)) + if z3.is_app(x): + child_k = x.decl().kind() + if child_k != k and self.is_infix(child_k) and self.get_precedence(child_k) > p: + arg1 = self.add_paren(arg1) + if z3.is_app(y): + child_k = y.decl().kind() + if child_k != k and self.is_infix(child_k) and self.get_precedence(child_k) > p: + arg2 = self.add_paren(arg2) + r.append(arg1) r.append(to_format(" ")) r.append(to_format(op)) From c340233df6bbe98b6225176aed2ba3697236b545 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 16 Jan 2024 10:31:31 -0800 Subject: [PATCH 093/224] fix #7081 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 18d3abc9d..b3b4351ab 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10969,10 +10969,10 @@ def CharVal(ch, ctx=None): raise Z3Exception("character value should be an ordinal") return _to_expr_ref(Z3_mk_char(ctx.ref(), ch), ctx) -def CharFromBv(ch, ctx=None): - if not is_expr(ch): - raise Z3Expression("Bit-vector expression needed") - return _to_expr_ref(Z3_mk_char_from_bv(ch.ctx_ref(), ch.as_ast()), ch.ctx) +def CharFromBv(bv): + if not is_expr(bv): + raise Z3Exception("Bit-vector expression needed") + return _to_expr_ref(Z3_mk_char_from_bv(bv.ctx_ref(), bv.as_ast()), bv.ctx) def CharToBv(ch, ctx=None): ch = _coerce_char(ch, ctx) From 4f75153186f0ceb3a1f8ba3aeee842514e51a3e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Jan 2024 13:53:38 -0800 Subject: [PATCH 094/224] Update z3_api.h Updated doc https://github.com/Z3Prover/z3/discussions/7087 --- src/api/z3_api.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 0468ab91d..fa8ccfe03 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -7184,15 +7184,25 @@ extern "C" { void Z3_API Z3_solver_propagate_register_cb(Z3_context c, Z3_solver_callback cb, Z3_ast e); /** - \brief propagate a consequence based on fixed values. - This is a callback a client may invoke during the fixed_eh callback. - The callback adds a propagation consequence based on the fixed values of the - \c ids. + \brief propagate a consequence based on fixed values and equalities. + A client may invoke it during the \c propagate_fixed, \c propagate_eq, \c propagate_diseq, and \c propagate_final callbacks. + The callback adds a propagation consequence based on the fixed values passed \c ids and equalities \c eqs based on parameters \c lhs, \c rhs. + The solver might discard the propagation in case it is true in the current state. The function returns false in this case; otw. the function returns true. At least one propagation in the final callback has to return true in order to prevent the solver from finishing. + Assume the callback has the signature: \c propagate_consequence_eh(context, solver_cb, num_ids, ids, num_eqs, lhs, rhs, consequence). + \param c - context + \param solver_cb - solver callback + \param num_ids - number of fixed terms used as premise to propagation + \param ids - array of length \c num_ids containing terms that are fixed in the current scope + \param num_eqs - number of equalities used as premise to propagation + \param lhs - left side of equalities + \param rhs - right side of equalities + \param consequence - consequence to propagate. It is typically an atomic formula, but it can be an arbitrary formula. + def_API('Z3_solver_propagate_consequence', BOOL, (_in(CONTEXT), _in(SOLVER_CALLBACK), _in(UINT), _in_array(2, AST), _in(UINT), _in_array(4, AST), _in_array(4, AST), _in(AST))) */ From fef1596c813f0016a22f0febe335da52f61aea98 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Jan 2024 15:11:06 -0800 Subject: [PATCH 095/224] pin expression passed to validate_eq Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index b8c95e5c6..b31867790 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -3499,7 +3499,8 @@ public: flet _svalid(s_validating, true); context nctx(m, ctx().get_fparams(), ctx().get_params()); add_background(nctx); - nctx.assert_expr(m.mk_not(m.mk_eq(x->get_expr(), y->get_expr()))); + expr_ref neq(m.mk_not(m.mk_eq(x->get_expr(), y->get_expr())), m); + nctx.assert_expr(neq); cancel_eh eh(m.limit()); scoped_timer timer(1000, &eh); lbool r = nctx.check(); From c591a7a3e78dfd5f7b9923f2e95cf5922a475236 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 17 Jan 2024 13:53:59 -1000 Subject: [PATCH 096/224] force int bound on int columns, call term_is_int() after subst Signed-off-by: Lev Nachmanson --- src/math/lp/lar_solver.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index a55edfe35..5762cbc9a 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -1641,12 +1641,12 @@ namespace lp { var_index lar_solver::add_term(const vector>& coeffs, unsigned ext_i) { TRACE("lar_solver_terms", print_linear_combination_of_column_indices_only(coeffs, tout) << ", ext_i =" << ext_i << "\n";); SASSERT(!m_var_register.external_is_used(ext_i)); - m_term_register.add_var(ext_i, term_is_int(coeffs)); - lp_assert(all_vars_are_registered(coeffs)); - if (strategy_is_undecided()) - return add_term_undecided(coeffs); + SASSERT(all_vars_are_registered(coeffs)); lar_term* t = new lar_term(coeffs); subst_known_terms(t); + m_term_register.add_var(ext_i, term_is_int(t)); + if (strategy_is_undecided()) + return add_term_undecided(coeffs); push_term(t); SASSERT(m_terms.size() == m_term_register.size()); unsigned adjusted_term_index = m_terms.size() - 1; @@ -1938,10 +1938,11 @@ namespace lp { tout << std::endl; } }); + mpq rs = adjust_bound_for_int(j, kind, right_side); if (column_has_upper_bound(j)) - update_column_type_and_bound_with_ub(j, kind, right_side, dep); + update_column_type_and_bound_with_ub(j, kind, rs, dep); else - update_column_type_and_bound_with_no_ub(j, kind, right_side, dep); + update_column_type_and_bound_with_no_ub(j, kind, rs, dep); if (is_base(j) && column_is_fixed(j)) m_fixed_base_var_set.insert(j); From d084a19630a7c21018cb298258ac165e52f7fa2f Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 17 Jan 2024 14:17:07 -1000 Subject: [PATCH 097/224] take care of strategy undecided, Nikolaj's comments Signed-off-by: Lev Nachmanson --- src/math/lp/lar_solver.cpp | 10 ++-------- src/math/lp/lar_solver.h | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 5762cbc9a..d14a7489e 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -1577,12 +1577,6 @@ namespace lp { } } - - var_index lar_solver::add_term_undecided(const vector>& coeffs) { - push_term(new lar_term(coeffs)); - return tv::mask_term(m_terms.size() - 1); - } - #if Z3DEBUG_CHECK_UNIQUE_TERMS bool lar_solver::term_coeffs_are_ok(const vector>& coeffs) { @@ -1645,9 +1639,9 @@ namespace lp { lar_term* t = new lar_term(coeffs); subst_known_terms(t); m_term_register.add_var(ext_i, term_is_int(t)); - if (strategy_is_undecided()) - return add_term_undecided(coeffs); push_term(t); + if (strategy_is_undecided()) + return tv::mask_term(m_terms.size() - 1); SASSERT(m_terms.size() == m_term_register.size()); unsigned adjusted_term_index = m_terms.size() - 1; var_index ret = tv::mask_term(adjusted_term_index); diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 91d506e1e..b1abb21f7 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -137,7 +137,6 @@ class lar_solver : public column_namer { // terms bool all_vars_are_registered(const vector>& coeffs); - var_index add_term_undecided(const vector>& coeffs); bool term_coeffs_are_ok(const vector>& coeffs); void push_term(lar_term* t); void add_row_from_term_no_constraint(const lar_term* term, unsigned term_ext_index); From 2c55aa5466197ad5ee92c732fa14305a9ba69f3e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Jan 2024 18:03:46 -0800 Subject: [PATCH 098/224] remove unused code Signed-off-by: Nikolaj Bjorner --- src/math/lp/factorization.cpp | 30 +++++++++++++++++---------- src/math/lp/factorization.h | 10 --------- src/math/lp/nla_core.cpp | 39 ----------------------------------- src/math/lp/nla_core.h | 10 +-------- src/math/lp/nla_solver.h | 2 +- src/sat/smt/arith_solver.cpp | 2 +- src/smt/theory_lra.cpp | 2 +- 7 files changed, 23 insertions(+), 72 deletions(-) diff --git a/src/math/lp/factorization.cpp b/src/math/lp/factorization.cpp index 229fca61f..e1dcff626 100644 --- a/src/math/lp/factorization.cpp +++ b/src/math/lp/factorization.cpp @@ -1,3 +1,12 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Author: +Lev Nachmanson (levnach) +Nikolaj Bjorner (nbjorner) + +--*/ + #include "util/vector.h" #include "math/lp/factorization.h" namespace nla { @@ -7,11 +16,10 @@ void const_iterator_mon::init_vars_by_the_mask(unsigned_vector & k_vars, unsigne SASSERT(m_mask.size() + 1 == m_ff->m_vars.size()); k_vars.push_back(m_ff->m_vars.back()); for (unsigned j = 0; j < m_mask.size(); j++) { - if (m_mask[j]) { - k_vars.push_back(m_ff->m_vars[j]); - } else { - j_vars.push_back(m_ff->m_vars[j]); - } + if (m_mask[j]) + k_vars.push_back(m_ff->m_vars[j]); + else + j_vars.push_back(m_ff->m_vars[j]); } } // todo : do we need the sign? @@ -29,9 +37,9 @@ bool const_iterator_mon::get_factors(factor& k, factor& j, rational& sign) const m_full_factorization_returned = true; return false; } - if (k_vars.size() == 1) { - k.set(k_vars[0], factor_type::VAR); - } else { + if (k_vars.size() == 1) + k.set(k_vars[0], factor_type::VAR); + else { unsigned i; if (!m_ff->find_canonical_monic_of_vars(k_vars, i)) { ++m_num_failures; @@ -41,9 +49,9 @@ bool const_iterator_mon::get_factors(factor& k, factor& j, rational& sign) const } m_num_failures = 0; - if (j_vars.size() == 1) { - j.set(j_vars[0], factor_type::VAR); - } else { + if (j_vars.size() == 1) + j.set(j_vars[0], factor_type::VAR); + else { unsigned i; if (!m_ff->find_canonical_monic_of_vars(j_vars, i)) { ++m_num_failures; diff --git a/src/math/lp/factorization.h b/src/math/lp/factorization.h index 04529d033..e1096a75f 100644 --- a/src/math/lp/factorization.h +++ b/src/math/lp/factorization.h @@ -2,20 +2,10 @@ /*++ Copyright (c) 2017 Microsoft Corporation - Module Name: - - - - Abstract: - - - Author: Lev Nachmanson (levnach) Nikolaj Bjorner (nbjorner) - Revision History: - --*/ #pragma once diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index f36fab52e..e2db006fa 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1434,45 +1434,6 @@ void core::patch_monomials_on_to_refine() { void core::patch_monomials() { m_cautious_patching = true; patch_monomials_on_to_refine(); - if (m_to_refine.size() == 0 || !params().arith_nl_expensive_patching()) { - return; - } - NOT_IMPLEMENTED_YET(); - m_cautious_patching = false; - patch_monomials_on_to_refine(); - lra.push(); - save_tableau(); - constrain_nl_in_tableau(); - if (solve_tableau() && integrality_holds()) { - lra.pop(1); - } else { - lra.pop(); - restore_tableau(); - lra.clear_inf_heap(); - } - SASSERT(lra.ax_is_correct()); -} - -void core::constrain_nl_in_tableau() { - NOT_IMPLEMENTED_YET(); -} - -bool core::solve_tableau() { - NOT_IMPLEMENTED_YET(); - return false; -} - -void core::restore_tableau() { - NOT_IMPLEMENTED_YET(); -} - -void core::save_tableau() { - NOT_IMPLEMENTED_YET(); -} - -bool core::integrality_holds() { - NOT_IMPLEMENTED_YET(); - return false; } /** diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 29effd4e4..253306bcd 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -424,18 +424,10 @@ public: vector const& literals() const { return m_literals; } vector const& equalities() const { return m_equalities; } vector const& fixed_equalities() const { return m_fixed_equalities; } - bool check_feasible() const { return m_check_feasible; } + bool should_check_feasible() const { return m_check_feasible; } void add_fixed_equality(lp::lpvar v, rational const& k, lp::explanation const& e) { m_fixed_equalities.push_back({v, k, e}); } void add_equality(lp::lpvar i, lp::lpvar j, lp::explanation const& e) { m_equalities.push_back({i, j, e}); } -private: - void restore_patched_values(); - void constrain_nl_in_tableau(); - bool solve_tableau(); - void restore_tableau(); - void save_tableau(); - bool integrality_holds(); - }; // end of core diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index 1fbafdf6b..1e47362fd 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -53,6 +53,6 @@ namespace nla { vector const& literals() const; vector const& fixed_equalities() const; vector const& equalities() const; - bool check_feasible() const { return m_core->check_feasible(); } + bool should_check_feasible() const { return m_core->should_check_feasible(); } }; } diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 078515184..9b4e40242 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -1506,7 +1506,7 @@ namespace arith { } void solver::add_lemmas() { - if (m_nla->check_feasible()) { + if (m_nla->should_check_feasible()) { auto is_sat = make_feasible(); if (l_false == is_sat) { get_infeasibility_explanation_and_set_conflict(); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index b31867790..4c9e02738 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2151,7 +2151,7 @@ public: } void add_lemmas() { - if (m_nla->check_feasible()) { + if (m_nla->should_check_feasible()) { auto is_sat = make_feasible(); if (l_false == is_sat) { get_infeasibility_explanation_and_set_conflict(); From d2706bab649b966170189d25090284c21cce7186 Mon Sep 17 00:00:00 2001 From: Thomas Haas Date: Thu, 18 Jan 2024 18:29:15 +0100 Subject: [PATCH 099/224] Fixes in Java's User Propagator (#7088) * Fixed decide callback for Java user propagators * Java User Prop: - Added return value to conflict - Added consequence method - Added missing access modifier to decideWrapper * Removed type parameters of expressions in UserPropagatorBase * Renamed propagateConflict to propagateConsequence --- scripts/update_api.py | 4 +++- src/api/java/NativeStatic.txt | 13 ++++++------ src/api/java/UserPropagatorBase.java | 31 +++++++++++++++++++--------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/scripts/update_api.py b/scripts/update_api.py index 7d3d8899f..79f144142 100755 --- a/scripts/update_api.py +++ b/scripts/update_api.py @@ -641,8 +641,8 @@ def mk_java(java_src, java_dir, package_name): public static native void propagateRegisterEq(Object o, long ctx, long solver); public static native void propagateRegisterDecide(Object o, long ctx, long solver); public static native void propagateRegisterFinal(Object o, long ctx, long solver); - public static native void propagateConflict(Object o, long ctx, long solver, long javainfo, int num_fixed, long[] fixed, long num_eqs, long[] eq_lhs, long[] eq_rhs, long conseq); public static native void propagateAdd(Object o, long ctx, long solver, long javainfo, long e); + public static native boolean propagateConsequence(Object o, long ctx, long solver, long javainfo, int num_fixed, long[] fixed, long num_eqs, long[] eq_lhs, long[] eq_rhs, long conseq); public static native boolean propagateNextSplit(Object o, long ctx, long solver, long javainfo, long e, long idx, int phase); public static native void propagateDestroy(Object o, long ctx, long solver, long javainfo); @@ -698,6 +698,8 @@ def mk_java(java_src, java_dir, package_name): protected abstract void createdWrapper(long le); protected abstract void fixedWrapper(long lvar, long lvalue); + + protected abstract void decideWrapper(long lvar, int bit, boolean is_pos); } """) java_native.write('\n') diff --git a/src/api/java/NativeStatic.txt b/src/api/java/NativeStatic.txt index 9507130fd..21d6ba075 100644 --- a/src/api/java/NativeStatic.txt +++ b/src/api/java/NativeStatic.txt @@ -150,7 +150,7 @@ static void final_eh(void* _p, Z3_solver_callback cb) { static void decide_eh(void* _p, Z3_solver_callback cb, Z3_ast _val, unsigned bit, bool is_pos) { JavaInfo *info = static_cast(_p); ScopedCB scoped(info, cb); - info->jenv->CallVoidMethod(info->jobj, info->decide, (jlong)_val); + info->jenv->CallVoidMethod(info->jobj, info->decide, (jlong)_val, bit, is_pos); } DLL_VIS JNIEXPORT jlong JNICALL Java_com_microsoft_z3_Native_propagateInit(JNIEnv *jenv, jclass cls, jobject jobj, jlong ctx, jlong solver) { @@ -166,7 +166,7 @@ DLL_VIS JNIEXPORT jlong JNICALL Java_com_microsoft_z3_Native_propagateInit(JNIEn info->fixed = jenv->GetMethodID(jcls, "fixedWrapper", "(JJ)V"); info->eq = jenv->GetMethodID(jcls, "eqWrapper", "(JJ)V"); info->final = jenv->GetMethodID(jcls, "finWrapper", "()V"); - info->decide = jenv->GetMethodID(jcls, "decideWrapper", "(JII)V"); + info->decide = jenv->GetMethodID(jcls, "decideWrapper", "(JIZ)V"); if (!info->push || !info->pop || !info->fresh || !info->created || !info->fixed || !info->eq || !info->final || !info->decide) { assert(false); @@ -203,15 +203,16 @@ DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_propagateRegisterDec Z3_solver_propagate_decide((Z3_context)ctx, (Z3_solver)solver, decide_eh); } -DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_propagateConflict(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, long num_fixed, jlongArray fixed, long num_eqs, jlongArray eq_lhs, jlongArray eq_rhs, jlong conseq) { +DLL_VIS JNIEXPORT jboolean JNICALL Java_com_microsoft_z3_Native_propagateConsequence(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, long num_fixed, jlongArray fixed, long num_eqs, jlongArray eq_lhs, jlongArray eq_rhs, jlong conseq) { JavaInfo *info = (JavaInfo*)javainfo; GETLONGAELEMS(Z3_ast, fixed, _fixed); GETLONGAELEMS(Z3_ast, eq_lhs, _eq_lhs); GETLONGAELEMS(Z3_ast, eq_rhs, _eq_rhs); - Z3_solver_propagate_consequence((Z3_context)ctx, info->cb, num_fixed, _fixed, num_eqs, _eq_lhs, _eq_rhs, (Z3_ast)conseq); + bool retval = Z3_solver_propagate_consequence((Z3_context)ctx, info->cb, num_fixed, _fixed, num_eqs, _eq_lhs, _eq_rhs, (Z3_ast)conseq); RELEASELONGAELEMS(fixed, _fixed); RELEASELONGAELEMS(eq_lhs, _eq_lhs); RELEASELONGAELEMS(eq_rhs, _eq_rhs); + return (jboolean) retval; } DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_propagateAdd(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, jlong e) { @@ -227,8 +228,8 @@ DLL_VIS JNIEXPORT void JNICALL Java_com_microsoft_z3_Native_propagateAdd(JNIEnv } -DLL_VIS JNIEXPORT bool JNICALL Java_com_microsoft_z3_Native_propagateNextSplit(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, jlong e, long idx, int phase) { +DLL_VIS JNIEXPORT jboolean JNICALL Java_com_microsoft_z3_Native_propagateNextSplit(JNIEnv * jenv, jclass cls, jobject jobj, jlong ctx, jlong solver, jlong javainfo, jlong e, long idx, int phase) { JavaInfo *info = (JavaInfo*)javainfo; Z3_solver_callback cb = info->cb; - return Z3_solver_next_split((Z3_context)ctx, cb, (Z3_ast)e, idx, Z3_lbool(phase)); + return (jboolean) Z3_solver_next_split((Z3_context)ctx, cb, (Z3_ast)e, idx, Z3_lbool(phase)); } diff --git a/src/api/java/UserPropagatorBase.java b/src/api/java/UserPropagatorBase.java index 407d3d0da..46a61400d 100644 --- a/src/api/java/UserPropagatorBase.java +++ b/src/api/java/UserPropagatorBase.java @@ -60,36 +60,47 @@ public abstract class UserPropagatorBase extends Native.UserPropagatorBase { fixed(var, value); } + @Override + protected final void decideWrapper(long lvar, int bit, boolean is_pos) { + Expr var = new Expr(ctx, lvar); + decide(var, bit, is_pos); + } + public abstract void push(); public abstract void pop(int number); public abstract UserPropagatorBase fresh(Context ctx); - public void created(Expr ast) {} + public void created(Expr ast) {} - public void fixed(Expr var, Expr value) {} + public void fixed(Expr var, Expr value) {} - public void eq(Expr x, Expr y) {} + public void eq(Expr x, Expr y) {} + + public void decide(Expr var, int bit, boolean is_pos) {} public void fin() {} - public final void add(Expr expr) { + public final void add(Expr expr) { Native.propagateAdd(this, ctx.nCtx(), solver.getNativeObject(), javainfo, expr.getNativeObject()); } - public final void conflict(Expr[] fixed) { - conflict(fixed, new Expr[0], new Expr[0]); + public final boolean conflict(Expr[] fixed) { + return conflict(fixed, new Expr[0], new Expr[0]); } - public final void conflict(Expr[] fixed, Expr[] lhs, Expr[] rhs) { - AST conseq = ctx.mkBool(false); - Native.propagateConflict( + public final boolean conflict(Expr[] fixed, Expr[] lhs, Expr[] rhs) { + return consequence(fixed, lhs, rhs, ctx.mkBool(false)); + } + + public final boolean consequence(Expr[] fixed, Expr[] lhs, Expr[] rhs, Expr conseq) { + return Native.propagateConsequence( this, ctx.nCtx(), solver.getNativeObject(), javainfo, fixed.length, AST.arrayToNative(fixed), lhs.length, AST.arrayToNative(lhs), AST.arrayToNative(rhs), conseq.getNativeObject()); } - public final boolean nextSplit(Expr e, long idx, Z3_lbool phase) { + public final boolean nextSplit(Expr e, long idx, Z3_lbool phase) { return Native.propagateNextSplit( this, ctx.nCtx(), solver.getNativeObject(), javainfo, e.getNativeObject(), idx, phase.toInt()); From a2993f7457923ecfa1a7bdcaa5057b81f900a01b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Jan 2024 12:57:43 -0800 Subject: [PATCH 100/224] encapsulate mpz a bit more --- src/util/mpq.h | 2 +- src/util/mpz.h | 59 +++++++++++++++++++++++++++----------------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/util/mpq.h b/src/util/mpq.h index fa6e8ec75..286c2758d 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -47,7 +47,7 @@ class mpq_manager : public mpz_manager { void reset_denominator(mpq & a) { del(a.m_den); - a.m_den.m_val = 1; + a.m_den.set(1); } void normalize(mpq & a) { diff --git a/src/util/mpz.h b/src/util/mpz.h index 44e3e9c0b..6d1b3449d 100644 --- a/src/util/mpz.h +++ b/src/util/mpz.h @@ -84,6 +84,7 @@ class mpz { #else typedef mpz_t mpz_type; #endif +protected: int m_val; unsigned m_kind:1; unsigned m_owner:1; @@ -116,6 +117,17 @@ public: unsigned o = m_owner; m_owner = other.m_owner; other.m_owner = o; unsigned k = m_kind; m_kind = other.m_kind; other.m_kind = k; } + + void set(int v) { + m_val = v; + m_kind = mpz_small; + } + + inline bool is_small() const { return m_kind == mpz_small; } + + inline int value() const { SASSERT(is_small()); return m_val; } + + inline int sign() const { SASSERT(!is_small()); return m_val; } }; #ifndef _MP_GMP @@ -242,14 +254,13 @@ class mpz_manager { mpz m_two64; - static int64_t i64(mpz const & a) { return static_cast(a.m_val); } + static int64_t i64(mpz const & a) { return static_cast(a.value()); } void set_big_i64(mpz & c, int64_t v); void set_i64(mpz & c, int64_t v) { if (v >= INT_MIN && v <= INT_MAX) { - c.m_val = static_cast(v); - c.m_kind = mpz_small; + c.set(static_cast(v)); } else { set_big_i64(c, v); @@ -306,25 +317,25 @@ class mpz_manager { void get_sign_cell(mpz const & a, int & sign, mpz_cell * & cell, mpz_cell* reserve) { if (is_small(a)) { - if (a.m_val == INT_MIN) { + if (a.value() == INT_MIN) { sign = -1; cell = m_int_min.m_ptr; } else { cell = reserve; cell->m_size = 1; - if (a.m_val < 0) { + if (a.value() < 0) { sign = -1; - cell->m_digits[0] = -a.m_val; + cell->m_digits[0] = -a.value(); } else { sign = 1; - cell->m_digits[0] = a.m_val; + cell->m_digits[0] = a.value(); } } } else { - sign = a.m_val; + sign = a.sign(); cell = a.m_ptr; } } @@ -398,7 +409,7 @@ public: ~mpz_manager(); - static bool is_small(mpz const & a) { return a.m_kind == mpz_small; } + static bool is_small(mpz const & a) { return a.is_small(); } static mpz mk_z(int val) { return mpz(val); } @@ -461,7 +472,7 @@ public: bool eq(mpz const & a, mpz const & b) { if (is_small(a) && is_small(b)) { - return a.m_val == b.m_val; + return a.value() == b.value(); } else { return big_compare(a, b) == 0; @@ -470,7 +481,7 @@ public: bool lt(mpz const& a, int b) { if (is_small(a)) { - return a.m_val < b; + return a.value() < b; } else { return lt(a, mpz(b)); @@ -479,7 +490,7 @@ public: bool lt(mpz const & a, mpz const & b) { if (is_small(a) && is_small(b)) { - return a.m_val < b.m_val; + return a.value() < b.value(); } else { return big_compare(a, b) < 0; @@ -526,8 +537,7 @@ public: void set(mpz & target, mpz const & source) { if (is_small(source)) { - target.m_val = source.m_val; - target.m_kind = mpz_small; + target.set(source.value()); } else { big_set(target, source); @@ -535,8 +545,7 @@ public: } void set(mpz & a, int val) { - a.m_val = val; - a.m_kind = mpz_small; + a.set(val); } void set(mpz & a, unsigned val) { @@ -554,8 +563,7 @@ public: void set(mpz & a, uint64_t val) { if (val < INT_MAX) { - a.m_val = static_cast(val); - a.m_kind = mpz_small; + a.set(static_cast(val)); } else { set_big_ui64(a, val); @@ -574,10 +582,7 @@ public: void reset(mpz & a); void swap(mpz & a, mpz & b) noexcept { - std::swap(a.m_val, b.m_val); - std::swap(a.m_ptr, b.m_ptr); - auto o = a.m_owner; a.m_owner = b.m_owner; b.m_owner = o; - auto k = a.m_kind; a.m_kind = b.m_kind; b.m_kind = k; + a.swap(b); } bool is_uint64(mpz const & a) const; @@ -624,20 +629,20 @@ public: static bool is_one(mpz const & a) { #ifndef _MP_GMP - return is_small(a) && a.m_val == 1; + return is_small(a) && a.value() == 1; #else if (is_small(a)) - return a.m_val == 1; + return a.value() == 1; return mpz_cmp_si(*a.m_ptr, 1) == 0; #endif } static bool is_minus_one(mpz const & a) { #ifndef _MP_GMP - return is_small(a) && a.m_val == -1; + return is_small(a) && a.value() == -1; #else if (is_small(a)) - return a.m_val == -1; + return a.value() == -1; return mpz_cmp_si(*a.m_ptr, -1) == 0; #endif } @@ -712,7 +717,7 @@ public: bool is_even(mpz const & a) { if (is_small(a)) - return !(a.m_val & 0x1); + return !(a.value() & 0x1); #ifndef _MP_GMP return !(0x1 & digits(a)[0]); #else From 548be4c1f92447fa45e283c2903bb3ea939909bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Jan 2024 12:59:32 -0800 Subject: [PATCH 101/224] add explicit move constructor to deal with unit test regression test-z3 algebraic on Windows/debug - it uses copy constructor instead of move when returning a scoped_anum in functions such as power and root. This leads to freeing memory that gets passed as return value. The copy constructor for scoped_numeral is also suspicious because it doesn't ensure memory ownership. --- src/util/scoped_numeral.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/scoped_numeral.h b/src/util/scoped_numeral.h index b90ba640a..f70f5f185 100644 --- a/src/util/scoped_numeral.h +++ b/src/util/scoped_numeral.h @@ -28,8 +28,8 @@ private: numeral m_num; public: _scoped_numeral(Manager & m):m_manager(m) {} - _scoped_numeral(_scoped_numeral const & n):m_manager(n.m_manager) { m().set(m_num, n.m_num); } - _scoped_numeral(_scoped_numeral &&) = default; + _scoped_numeral(_scoped_numeral const& n) :m_manager(n.m_manager) { m().set(m_num, n.m_num); } + _scoped_numeral(_scoped_numeral && n) noexcept: m_manager(n.m_manager) { m().swap(m_num, n.m_num); } ~_scoped_numeral() { m_manager.del(m_num); } Manager & m() const { return m_manager; } From 17545233e6354d9822efada84a48ca19bdfda69f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Jan 2024 12:59:50 -0800 Subject: [PATCH 102/224] encapsulate anum functionality --- src/math/polynomial/algebraic_numbers.cpp | 20 +++++++++--------- src/math/polynomial/algebraic_numbers.h | 25 +++++++++++++++-------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index 736d08708..9a7a6d527 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -204,13 +204,13 @@ namespace algebraic_numbers { } void del(numeral & a) { - if (a.m_cell == nullptr) + if (a.is_null()) return; if (a.is_basic()) del(a.to_basic()); else del(a.to_algebraic()); - a.m_cell = nullptr; + a.clear(); } void reset(numeral & a) { @@ -218,7 +218,7 @@ namespace algebraic_numbers { } bool is_zero(numeral const & a) { - return a.m_cell == nullptr; + return a.is_null(); } bool is_pos(numeral const & a) { @@ -359,7 +359,7 @@ namespace algebraic_numbers { } void swap(numeral & a, numeral & b) noexcept { - std::swap(a.m_cell, b.m_cell); + a.swap(b); } basic_cell * mk_basic_cell(mpq & n) { @@ -432,13 +432,13 @@ namespace algebraic_numbers { } if (a.is_basic()) { if (is_zero(a)) - a.m_cell = mk_basic_cell(n); + a = mk_basic_cell(n); else qm().set(a.to_basic()->m_value, n); } else { del(a); - a.m_cell = mk_basic_cell(n); + a = mk_basic_cell(n); } } @@ -492,7 +492,7 @@ namespace algebraic_numbers { else { if (a.is_basic()) { del(a); - a.m_cell = TAG(void*, mk_algebraic_cell(sz, p, lower, upper, minimal), ROOT); + a = mk_algebraic_cell(sz, p, lower, upper, minimal); } else { SASSERT(sz > 2); @@ -526,7 +526,7 @@ namespace algebraic_numbers { del(a); void * mem = m_allocator.allocate(sizeof(algebraic_cell)); algebraic_cell * c = new (mem) algebraic_cell(); - a.m_cell = TAG(void *, c, ROOT); + a = c; copy(c, b.to_algebraic()); SASSERT(acell_inv(*c)); } @@ -796,7 +796,7 @@ namespace algebraic_numbers { scoped_mpq r(qm()); to_mpq(qm(), lower(c), r); del(c); - a.m_cell = mk_basic_cell(r); + a = mk_basic_cell(r); return false; } } @@ -817,7 +817,7 @@ namespace algebraic_numbers { scoped_mpq r(qm()); to_mpq(qm(), lower(c), r); del(c); - a.m_cell = mk_basic_cell(r); + a = mk_basic_cell(r); return false; } SASSERT(acell_inv(*c)); diff --git a/src/math/polynomial/algebraic_numbers.h b/src/math/polynomial/algebraic_numbers.h index 63b833b80..e2e95367c 100644 --- a/src/math/polynomial/algebraic_numbers.h +++ b/src/math/polynomial/algebraic_numbers.h @@ -360,19 +360,25 @@ namespace algebraic_numbers { struct basic_cell; struct algebraic_cell; - enum anum_kind { BASIC = 0, ROOT }; + + + class anum { + enum anum_kind { BASIC = 0, ROOT }; + void* m_cell; + public: + anum() :m_cell(nullptr) {} + anum(basic_cell* cell) :m_cell(TAG(void*, cell, BASIC)) { } + anum(algebraic_cell * cell):m_cell(TAG(void*, cell, ROOT)) { } - class anum { - friend struct manager::imp; - friend class manager; - void * m_cell; - anum(basic_cell * cell):m_cell(TAG(void*, cell, BASIC)) {} - anum(algebraic_cell * cell):m_cell(TAG(void*, cell, ROOT)) {} bool is_basic() const { return GET_TAG(m_cell) == BASIC; } basic_cell * to_basic() const { SASSERT(is_basic()); return UNTAG(basic_cell*, m_cell); } algebraic_cell * to_algebraic() const { SASSERT(!is_basic()); return UNTAG(algebraic_cell*, m_cell); } - public: - anum():m_cell(nullptr) {} + + bool is_null() const { return m_cell == nullptr; } + void clear() { m_cell = nullptr; } + void swap(anum & other) { std::swap(m_cell, other.m_cell); } + anum& operator=(basic_cell* cell) { SASSERT(is_null()); m_cell = TAG(void*, cell, BASIC); return *this; } + anum& operator=(algebraic_cell* cell) { SASSERT(is_null()); m_cell = TAG(void*, cell, ROOT); return *this; } }; }; @@ -428,6 +434,7 @@ AN_MK_BINARY(operator/, div) #undef AN_MK_BINARY #undef AN_MK_BINARY_CORE + inline scoped_anum root(scoped_anum const & a, unsigned k) { scoped_anum r(a.m()); a.m().root(a, k, r); From d32dcfc4a4512f61e9c4aa3c97a9dabe5050f7ea Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Jan 2024 13:54:50 -0800 Subject: [PATCH 103/224] free memory the clean way Signed-off-by: Nikolaj Bjorner --- src/math/polynomial/algebraic_numbers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index 9a7a6d527..82f71a23d 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -816,7 +816,7 @@ namespace algebraic_numbers { // actual root was found scoped_mpq r(qm()); to_mpq(qm(), lower(c), r); - del(c); + del(a); a = mk_basic_cell(r); return false; } From 910b3023c22d32469b0a780280132d3bcb148ec0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Jan 2024 14:01:01 -0800 Subject: [PATCH 104/224] free memory the clean way Signed-off-by: Nikolaj Bjorner --- src/math/polynomial/algebraic_numbers.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/math/polynomial/algebraic_numbers.cpp b/src/math/polynomial/algebraic_numbers.cpp index 82f71a23d..06b4465d7 100644 --- a/src/math/polynomial/algebraic_numbers.cpp +++ b/src/math/polynomial/algebraic_numbers.cpp @@ -180,7 +180,7 @@ namespace algebraic_numbers { return m_upmanager; } - void del(basic_cell * c) { + void del_basic(basic_cell * c) { qm().del(c->m_value); m_allocator.deallocate(sizeof(basic_cell), c); } @@ -207,7 +207,7 @@ namespace algebraic_numbers { if (a.is_null()) return; if (a.is_basic()) - del(a.to_basic()); + del_basic(a.to_basic()); else del(a.to_algebraic()); a.clear(); @@ -795,7 +795,7 @@ namespace algebraic_numbers { // root was found scoped_mpq r(qm()); to_mpq(qm(), lower(c), r); - del(c); + del(a); a = mk_basic_cell(r); return false; } From 2dd45f8c1967ecbae85b7e5eb771d29697bf13f1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Jan 2024 16:28:04 -0800 Subject: [PATCH 105/224] add Windows build Signed-off-by: Nikolaj Bjorner --- .github/workflows/Windows.yml | 56 +++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index a79a088dd..08fe45462 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -1,7 +1,9 @@ name: Windows + on: - workflow_dispatch: - + push: + branches: [ master ] + jobs: build: strategy: @@ -9,26 +11,54 @@ jobs: arch : [x86,x64,amd64_arm64] include: - arch : x86 - bindings : '-DZ3_BUILD_PYTHON_BINDINGS=True' + - arch : amd64_arm64 - arch : x64 - cmd1 : 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\", version=\"0.7.0\"))"' + cmd1 : 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\"))"' cmd2 : 'julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))" > tmp.env' cmd3 : 'set /P JlCxxDir= Date: Sat, 20 Jan 2024 16:30:08 -0800 Subject: [PATCH 106/224] add status badge for windows build, remove windows build from Azure pipelines Signed-off-by: Nikolaj Bjorner --- README.md | 6 ++--- azure-pipelines.yml | 57 --------------------------------------------- 2 files changed, 3 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 230b3eeeb..dfbaea599 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ See the [release notes](RELEASE_NOTES.md) for notes on various stable releases o ## Build status -| Azure Pipelines | Code Coverage | Open Bugs | Android Build | WASM Build | -| --------------- | --------------|-----------|---------------|------------| -| [![Build Status](https://dev.azure.com/Z3Public/Z3/_apis/build/status/Z3Prover.z3?branchName=master)](https://dev.azure.com/Z3Public/Z3/_build/latest?definitionId=1&branchName=master) | [![CodeCoverage](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml) | [![Open Issues](https://github.com/Z3Prover/z3/actions/workflows/wip.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/wip.yml) |[![Android Build](https://github.com/Z3Prover/z3/actions/workflows/android-build.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/android-build.yml) | [![WASM Build](https://github.com/Z3Prover/z3/actions/workflows/wasm.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/wasm.yml) | +| Azure Pipelines | Code Coverage | Open Bugs | Android Build | WASM Build | Windows Build | +| --------------- | --------------|-----------|---------------|------------|---------------| +| [![Build Status](https://dev.azure.com/Z3Public/Z3/_apis/build/status/Z3Prover.z3?branchName=master)](https://dev.azure.com/Z3Public/Z3/_build/latest?definitionId=1&branchName=master) | [![CodeCoverage](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/coverage.yml) | [![Open Issues](https://github.com/Z3Prover/z3/actions/workflows/wip.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/wip.yml) |[![Android Build](https://github.com/Z3Prover/z3/actions/workflows/android-build.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/android-build.yml) | [![WASM Build](https://github.com/Z3Prover/z3/actions/workflows/wasm.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/wasm.yml) | [![Windows](https://github.com/Z3Prover/z3/actions/workflows/Windows.yml/badge.svg)](https://github.com/Z3Prover/z3/actions/workflows/Windows.yml) Docker image. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 753c9ae9c..d9d2ab2b2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -183,63 +183,6 @@ jobs: - template: scripts/test-regressions.yml -- job: "WindowsLatest" - displayName: "Windows" - pool: - vmImage: "windows-latest" - strategy: - matrix: - x86: - arch: 'x86' - setupCmd1: '' - setupCmd2: '' - setupCmd3: '' - bindings: '$(cmakePy)' - runTests: 'False' - x64: - arch: 'x64' - setupCmd1: 'julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\"))"' - setupCmd2: 'julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))" > tmp.env' - setupCmd3: 'set /P JlCxxDir= Date: Sat, 20 Jan 2024 16:46:13 -0800 Subject: [PATCH 107/224] prepare for release Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/release.yml b/scripts/release.yml index 76f8a8a57..d0442ff06 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -485,7 +485,7 @@ stages: jobs: - job: GitHubPublish - condition: eq(1,1) + condition: eq(1,0) displayName: "Publish to GitHub" pool: vmImage: "windows-latest" @@ -583,7 +583,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(1,1) + condition: eq(1,0) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From 7486e8724f234b648de9efa92d5508f1d2672866 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 20 Jan 2024 17:44:07 -0800 Subject: [PATCH 108/224] track quantifier instantiation method in proof hint #7080 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/bool_rewriter.cpp | 22 ++++++++++++++++++++++ src/ast/rewriter/bool_rewriter.h | 2 ++ src/sat/smt/q_ematch.cpp | 2 +- src/sat/smt/q_ematch.h | 1 + src/sat/smt/q_mbi.cpp | 2 +- src/sat/smt/q_mbi.h | 1 + src/sat/smt/q_solver.cpp | 9 +++++---- src/sat/smt/q_solver.h | 8 +++++--- 8 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 9afab7a29..13a392d24 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -699,6 +699,22 @@ app* bool_rewriter::mk_eq(expr* lhs, expr* rhs) { return m().mk_eq(lhs, rhs); } +bool bool_rewriter::try_ite_eq(expr* lhs, expr* rhs, expr_ref& r) { + expr* c, *t, *e; + if (!m().is_ite(lhs, c, t, e)) + return false; + if (m().are_equal(t, rhs) && m().are_distinct(e, rhs)) { + r = c; + return true; + } + if (m().are_equal(e, rhs) && m().are_distinct(t, rhs)) { + r = m().mk_not(c); + return true; + } + return false; +} + + br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { if (m().are_equal(lhs, rhs)) { result = m().mk_true(); @@ -713,6 +729,12 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { br_status r = BR_FAILED; + if (try_ite_eq(lhs, rhs, result)) + return BR_REWRITE1; + + if (try_ite_eq(rhs, lhs, result)) + return BR_REWRITE1; + if (m_ite_extra_rules) { if (m().is_ite(lhs) && m().is_value(rhs)) { r = try_ite_value(to_app(lhs), to_app(rhs), result); diff --git a/src/ast/rewriter/bool_rewriter.h b/src/ast/rewriter/bool_rewriter.h index 7c840b647..421811ed4 100644 --- a/src/ast/rewriter/bool_rewriter.h +++ b/src/ast/rewriter/bool_rewriter.h @@ -71,6 +71,8 @@ class bool_rewriter { void mk_and_as_or(unsigned num_args, expr * const * args, expr_ref & result); + bool try_ite_eq(expr* lhs, expr* rhs, expr_ref& r); + expr * mk_or_app(unsigned num_args, expr * const * args); bool simp_nested_not_or(unsigned num_args, expr * const * args, expr_fast_mark1 & neg_lits, expr_fast_mark2 & pos_lits, expr_ref & result); expr * simp_arg(expr * arg, expr_fast_mark1 & neg_lits, expr_fast_mark2 & pos_lits, bool & modified); diff --git a/src/sat/smt/q_ematch.cpp b/src/sat/smt/q_ematch.cpp index aa79bab5b..76d234d8d 100644 --- a/src/sat/smt/q_ematch.cpp +++ b/src/sat/smt/q_ematch.cpp @@ -390,7 +390,7 @@ namespace q { m_qs.log_instantiation(lits, &j); euf::th_proof_hint* ph = nullptr; if (ctx.use_drat()) - ph = q_proof_hint::mk(ctx, j.m_generation, lits, j.m_clause.num_decls(), j.m_binding); + ph = q_proof_hint::mk(ctx, m_ematch, j.m_generation, lits, j.m_clause.num_decls(), j.m_binding); m_qs.add_clause(lits, ph); } diff --git a/src/sat/smt/q_ematch.h b/src/sat/smt/q_ematch.h index cbeb34679..f7de55fb8 100644 --- a/src/sat/smt/q_ematch.h +++ b/src/sat/smt/q_ematch.h @@ -90,6 +90,7 @@ namespace q { unsigned_vector m_clause_queue; euf::enode_pair_vector m_evidence; bool m_enable_propagate = true; + symbol m_ematch = symbol("ematch"); euf::enode* const* copy_nodes(clause& c, euf::enode* const* _binding); binding* tmp_binding(clause& c, app* pat, euf::enode* const* _binding); diff --git a/src/sat/smt/q_mbi.cpp b/src/sat/smt/q_mbi.cpp index 539c4f943..07d4880c9 100644 --- a/src/sat/smt/q_mbi.cpp +++ b/src/sat/smt/q_mbi.cpp @@ -71,7 +71,7 @@ namespace q { for (auto const& [qlit, fml, inst, generation] : m_instantiations) { euf::solver::scoped_generation sg(ctx, generation + 1); sat::literal lit = ~ctx.mk_literal(fml); - auto* ph = ctx.use_drat()? q_proof_hint::mk(ctx, generation, ~qlit, lit, inst.size(), inst.data()) : nullptr; + auto* ph = ctx.use_drat()? q_proof_hint::mk(ctx, m_mbqi, generation, ~qlit, lit, inst.size(), inst.data()) : nullptr; m_qs.add_clause(~qlit, lit, ph); m_qs.log_instantiation(~qlit, lit); } diff --git a/src/sat/smt/q_mbi.h b/src/sat/smt/q_mbi.h index 96e3ba56f..71a15be74 100644 --- a/src/sat/smt/q_mbi.h +++ b/src/sat/smt/q_mbi.h @@ -72,6 +72,7 @@ namespace q { unsigned m_max_choose_candidates = 10; unsigned m_generation_bound = UINT_MAX; unsigned m_generation_max = UINT_MAX; + symbol m_mbqi = symbol("mbqi"); typedef std::tuple instantiation_t; vector m_instantiations; vector m_defs; diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index fff11898c..aec106072 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -364,10 +364,10 @@ namespace q { } } - q_proof_hint* q_proof_hint::mk(euf::solver& s, unsigned generation, sat::literal_vector const& lits, unsigned n, euf::enode* const* bindings) { + q_proof_hint* q_proof_hint::mk(euf::solver& s, symbol const& method, unsigned generation, sat::literal_vector const& lits, unsigned n, euf::enode* const* bindings) { SASSERT(n > 0); auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n, lits.size())); - q_proof_hint* ph = new (mem) q_proof_hint(generation, n, lits.size()); + q_proof_hint* ph = new (mem) q_proof_hint(method, generation, n, lits.size()); for (unsigned i = 0; i < n; ++i) ph->m_bindings[i] = bindings[i]->get_expr(); for (unsigned i = 0; i < lits.size(); ++i) @@ -375,10 +375,10 @@ namespace q { return ph; } - q_proof_hint* q_proof_hint::mk(euf::solver& s, unsigned generation, sat::literal l1, sat::literal l2, unsigned n, expr* const* bindings) { + q_proof_hint* q_proof_hint::mk(euf::solver& s, symbol const& method, unsigned generation, sat::literal l1, sat::literal l2, unsigned n, expr* const* bindings) { SASSERT(n > 0); auto* mem = s.get_region().allocate(q_proof_hint::get_obj_size(n, 2)); - q_proof_hint* ph = new (mem) q_proof_hint(generation, n, 2); + q_proof_hint* ph = new (mem) q_proof_hint(method, generation, n, 2); for (unsigned i = 0; i < n; ++i) ph->m_bindings[i] = bindings[i]; ph->m_literals[0] = l1; @@ -402,6 +402,7 @@ namespace q { args.push_back(s.literal2expr(~m_literals[i])); args.push_back(binding); args.push_back(m.mk_app(symbol("gen"), 1, gens, range)); + args.push_back(m.mk_const(m_method, range)); return m.mk_app(symbol("inst"), args.size(), args.data(), range); } diff --git a/src/sat/smt/q_solver.h b/src/sat/smt/q_solver.h index d0581f852..a7220e68b 100644 --- a/src/sat/smt/q_solver.h +++ b/src/sat/smt/q_solver.h @@ -30,21 +30,23 @@ namespace euf { namespace q { struct q_proof_hint : public euf::th_proof_hint { + symbol m_method; unsigned m_generation; unsigned m_num_bindings; unsigned m_num_literals; sat::literal* m_literals; expr* m_bindings[0]; - q_proof_hint(unsigned g, unsigned b, unsigned l) { + q_proof_hint(symbol const& method, unsigned g, unsigned b, unsigned l) { + m_method = method; m_generation = g; m_num_bindings = b; m_num_literals = l; m_literals = reinterpret_cast(m_bindings + m_num_bindings); } static size_t get_obj_size(unsigned num_bindings, unsigned num_lits) { return sizeof(q_proof_hint) + num_bindings*sizeof(expr*) + num_lits*sizeof(sat::literal); } - static q_proof_hint* mk(euf::solver& s, unsigned generation, sat::literal_vector const& lits, unsigned n, euf::enode* const* bindings); - static q_proof_hint* mk(euf::solver& s, unsigned generation, sat::literal l1, sat::literal l2, unsigned n, expr* const* bindings); + static q_proof_hint* mk(euf::solver& s, symbol const& method, unsigned generation, sat::literal_vector const& lits, unsigned n, euf::enode* const* bindings); + static q_proof_hint* mk(euf::solver& s, symbol const& method, unsigned generation, sat::literal l1, sat::literal l2, unsigned n, expr* const* bindings); expr* get_hint(euf::solver& s) const override; }; From a7b564cafe3b96c8a868388bc4b96b319facea44 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 21 Jan 2024 10:06:38 -0800 Subject: [PATCH 109/224] update release scripts and notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES.md | 2 +- scripts/release.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index ffbe6061c..c795e7a68 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -17,7 +17,7 @@ Version 4.12.5 - sat.smt=true smt.bv.solver=2 - It solves a few bit-vector problems not handled by bit-blasting, especially if the bit-widths are large. - It is based on encoding bit-vector constraints to non-linear integer arithmetic. - +- Optimizations to the arithmetic solver. Description: https://github.com/Z3Prover/doc/tree/master/arithmetic Version 4.12.4 ============== diff --git a/scripts/release.yml b/scripts/release.yml index d0442ff06..76f8a8a57 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -485,7 +485,7 @@ stages: jobs: - job: GitHubPublish - condition: eq(1,0) + condition: eq(1,1) displayName: "Publish to GitHub" pool: vmImage: "windows-latest" @@ -583,7 +583,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(1,0) + condition: eq(1,1) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From 414c33f92d50907bd7b5b1ccba35451b23281620 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:50:06 -0800 Subject: [PATCH 110/224] Bump mymindstorm/setup-emsdk from 13 to 14 (#7095) Bumps [mymindstorm/setup-emsdk](https://github.com/mymindstorm/setup-emsdk) from 13 to 14. - [Release notes](https://github.com/mymindstorm/setup-emsdk/releases) - [Commits](https://github.com/mymindstorm/setup-emsdk/compare/v13...v14) --- updated-dependencies: - dependency-name: mymindstorm/setup-emsdk dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/wasm-release.yml | 2 +- .github/workflows/wasm.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wasm-release.yml b/.github/workflows/wasm-release.yml index f437fcc5f..ed5dacec8 100644 --- a/.github/workflows/wasm-release.yml +++ b/.github/workflows/wasm-release.yml @@ -36,7 +36,7 @@ jobs: cp ../../../LICENSE.txt . - name: Setup emscripten - uses: mymindstorm/setup-emsdk@v13 + uses: mymindstorm/setup-emsdk@v14 with: no-install: true version: ${{env.EM_VERSION}} diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 320f36817..8e157f5a4 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -29,7 +29,7 @@ jobs: node-version: "lts/*" - name: Setup emscripten - uses: mymindstorm/setup-emsdk@v13 + uses: mymindstorm/setup-emsdk@v14 with: no-install: true version: ${{env.EM_VERSION}} From 69f118e77f662920380ec061410efa2511441573 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Jan 2024 11:14:22 -0800 Subject: [PATCH 111/224] use assignment Signed-off-by: Nikolaj Bjorner --- src/smt/fingerprints.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/smt/fingerprints.h b/src/smt/fingerprints.h index b1308e9b0..b1904a4ee 100644 --- a/src/smt/fingerprints.h +++ b/src/smt/fingerprints.h @@ -25,11 +25,11 @@ namespace smt { class fingerprint { protected: - void* m_data{ nullptr }; - unsigned m_data_hash{ 0 }; - expr* m_def{ nullptr }; - unsigned m_num_args{ 0 }; - enode** m_args{ nullptr }; + void* m_data = nullptr; + unsigned m_data_hash = 0; + expr* m_def = nullptr; + unsigned m_num_args = 0; + enode** m_args = nullptr; friend class fingerprint_set; fingerprint() {} From 0ebd8d655bf3bc67832f513e7b5ce4e6d819693b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Jan 2024 15:47:43 -0800 Subject: [PATCH 112/224] prepare for printing more cases of root objects in SMT --- src/nlsat/nlsat_solver.cpp | 39 ++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 40bdd10d6..e7bf58949 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -3081,11 +3081,42 @@ namespace nlsat { return out; } - std::ostream& display_smt2(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { - return display(out, a, proc); - } - std::ostream& display(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { + std::ostream& display_linear_root_smt2(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { + polynomial_ref A(m_pm), B(m_pm); + polynomial::scoped_numeral one(m_qm); + m_pm.m().set(one, 1); + A = m_pm.derivative(a.p(), a.x()); + B = m_pm.substitute(a.p(), a.x(), one); + + // x < root[1](ax + b) == (a > 0 => ax < b) & (a < 0 => ax > b) + + char const* rel1 = "<", *rel2 = ">"; + switch (a.get_kind()) { + case atom::ROOT_LT: rel1 = "<"; rel2 = ">"; break; + case atom::ROOT_GT: rel1 = ">"; rel2 = "<"; break; + case atom::ROOT_LE: rel1 = "<="; rel2 = ">="; break; + case atom::ROOT_GE: rel1 = ">="; rel2 = "<="; break; + case atom::ROOT_EQ: rel1 = rel2 = "="; break; + default: UNREACHABLE(); break; + } + + out << "(and "; + out << "(=> (> "; m_pm.display_smt2(out, A, proc); out << " 0) "; + out << "(" << rel1 << " (* "; proc(out, a.x()); out << " "; m_pm.display_smt2(out, A, proc); out << " "; m_pm.display_smt2(out, B, proc); out << ")) "; + out << "(=> (< "; m_pm.display_smt2(out, A, proc); out << " 0) "; + out << "(" << rel2 << " (* "; proc(out, a.x()); out << " "; m_pm.display_smt2(out, A, proc); out << " "; m_pm.display_smt2(out, B, proc); out << ")) "; + out << ")"; + + return out; + } + + + std::ostream& display_smt2(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { +#if 0 + if (a.i() == 1 && m_pm.degree(a.p(), a.x()) == 1) + return display_linear_root_smt2(out, a, proc); +#endif proc(out, a.x()); switch (a.get_kind()) { case atom::ROOT_LT: out << " < "; break; From 839b7101aef34dce0a33147642f93e0994222e2b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Jan 2024 15:48:03 -0800 Subject: [PATCH 113/224] add ability to multiply term --- src/math/lp/lar_term.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/math/lp/lar_term.h b/src/math/lp/lar_term.h index 5ce1ff2fc..a96d3ad5a 100644 --- a/src/math/lp/lar_term.h +++ b/src/math/lp/lar_term.h @@ -138,6 +138,12 @@ public: } return ret; } + + lar_term& operator*=(mpq const& k) { + for (auto & t : m_coeffs) + t.m_value *= k; + return *this; + } void clear() { m_coeffs.reset(); From 8d4e7fac6bf22c847b225c83a1865466686ad958 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Jan 2024 16:23:19 -0800 Subject: [PATCH 114/224] add diagnostics option to new arithmetic solver --- src/sat/smt/arith_diagnostics.cpp | 19 +++++++++++++++++++ src/sat/smt/arith_internalize.cpp | 2 +- src/sat/smt/arith_solver.cpp | 3 +++ src/sat/smt/arith_solver.h | 1 + 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index 47e3ee551..32e64e2b5 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -15,6 +15,8 @@ Author: --*/ +#include "util/cancel_eh.h" +#include "util/scoped_timer.h" #include "ast/ast_util.h" #include "ast/scoped_proof.h" #include "sat/smt/euf_solver.h" @@ -242,4 +244,21 @@ namespace arith { return m.mk_app(symbol(name), args.size(), args.data(), m.mk_proof_sort()); } + + bool solver::validate_conflict() { + scoped_ptr<::solver> vs = mk_smt2_solver(m, ctx.s().params(), symbol::null); + for (auto lit : m_core) + vs->assert_expr(ctx.literal2expr(lit)); + + for (auto [a, b] : m_eqs) + vs->assert_expr(m.mk_eq(a->get_expr(), b->get_expr())); + + cancel_eh eh(m.limit()); + scoped_timer timer(1000, &eh); + bool result = l_true != vs->check_sat(); + CTRACE("arith", !result, vs->display(tout)); + CTRACE("arith", !result, s().display(tout)); + SASSERT(result); + return result; + } } diff --git a/src/sat/smt/arith_internalize.cpp b/src/sat/smt/arith_internalize.cpp index ed49092fd..00038cf8b 100644 --- a/src/sat/smt/arith_internalize.cpp +++ b/src/sat/smt/arith_internalize.cpp @@ -472,7 +472,7 @@ namespace arith { bool _has_var = has_var(t); mk_enode(t); theory_var v = mk_evar(t); - + if (!_has_var) { svector vars; for (expr* n : *t) { diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 9b4e40242..b2a466779 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -1251,6 +1251,9 @@ namespace arith { for (literal c : m_core) tout << c << ": " << literal2expr(c) << "\n"; for (auto p : m_eqs) tout << ctx.bpp(p.first) << " == " << ctx.bpp(p.second) << "\n";); + if (ctx.get_config().m_arith_validate) + VERIFY(validate_conflict()); + if (is_conflict) { DEBUG_CODE( for (literal c : m_core) VERIFY(s().value(c) == l_true); diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index cbf4206a9..af9df0798 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -483,6 +483,7 @@ namespace arith { arith_proof_hint const* explain_conflict(hint_type ty, sat::literal_vector const& core, euf::enode_pair_vector const& eqs); void explain_assumptions(lp::explanation const& e); + bool validate_conflict(); public: solver(euf::solver& ctx, theory_id id); From 125a82bea54946b85cf4e0ea8bbaf4742320f97d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 22 Jan 2024 16:23:47 -0800 Subject: [PATCH 115/224] improved diagnostics --- src/math/lp/nra_solver.cpp | 4 +- src/math/polynomial/polynomial.cpp | 5 +-- src/nlsat/nlsat_solver.cpp | 63 ++++++++++++++++++------------ 3 files changed, 43 insertions(+), 29 deletions(-) diff --git a/src/math/lp/nra_solver.cpp b/src/math/lp/nra_solver.cpp index ccd95e6be..e035fc34f 100644 --- a/src/math/lp/nra_solver.cpp +++ b/src/math/lp/nra_solver.cpp @@ -158,6 +158,8 @@ struct solver::imp { for (unsigned i : m_term_set) add_term(i); + TRACE("nra", m_nlsat->display(tout)); + lbool r = l_undef; try { r = m_nlsat->check(); @@ -200,7 +202,7 @@ struct solver::imp { for (auto c : core) { unsigned idx = static_cast(static_cast(c) - this); ex.push_back(idx); - TRACE("arith", tout << "ex: " << idx << "\n";); + TRACE("nra", lra.display_constraint(tout << "ex: " << idx << ": ", idx) << "\n";); } nla::new_lemma lemma(m_nla_core, __FUNCTION__); lemma &= ex; diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index dde4a5f80..a3af87f52 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -1285,10 +1285,7 @@ namespace polynomial { } }); monomial_table new_table; - monomial_table::iterator it = m_monomials.begin(); - monomial_table::iterator end = m_monomials.end(); - for (; it != end; ++it) { - monomial * m = *it; + for (monomial * m : m_monomials) { m->rename(sz, xs); SASSERT(!new_table.contains(m)); new_table.insert(m); diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index e7bf58949..2e482218c 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -810,15 +810,20 @@ namespace nlsat { void check_lemma(unsigned n, literal const* cls, bool is_valid, assumption_set a) { TRACE("nlsat", display(tout << "check lemma: ", n, cls) << "\n"; display(tout);); - IF_VERBOSE(0, display(verbose_stream() << "check lemma: ", n, cls) << "\n"); + IF_VERBOSE(0, display(verbose_stream() << "check lemma " << (is_valid?"valid: ":"consequence: "), n, cls) << "\n"); for (clause* c : m_learned) IF_VERBOSE(1, display(verbose_stream() << "lemma: ", *c) << "\n"); - - solver solver2(m_ctx); + scoped_suspend_rlimit _limit(m_rlimit); + ctx c(m_rlimit, m_ctx.m_params, m_ctx.m_incremental); + solver solver2(c); imp& checker = *(solver2.m_imp); checker.m_check_lemmas = false; checker.m_log_lemmas = false; checker.m_inline_vars = false; + auto pconvert = [&](poly* p) { + return convert(m_pm, p, checker.m_pm); + }; + // need to translate Boolean variables and literals scoped_bool_vars tr(checker); for (var x = 0; x < m_is_int.size(); ++x) { @@ -834,10 +839,10 @@ namespace nlsat { else if (a->is_ineq_atom()) { ineq_atom& ia = *to_ineq_atom(a); unsigned sz = ia.size(); - ptr_vector ps; + polynomial_ref_vector ps(checker.m_pm); bool_vector is_even; for (unsigned i = 0; i < sz; ++i) { - ps.push_back(ia.p(i)); + ps.push_back(pconvert(ia.p(i))); is_even.push_back(ia.is_even(i)); } bv = checker.mk_ineq_atom(ia.get_kind(), sz, ps.data(), is_even.data()); @@ -847,7 +852,7 @@ namespace nlsat { if (r.x() >= max_var(r.p())) { // permutation may be reverted after check completes, // but then root atoms are not used in lemmas. - bv = checker.mk_root_atom(r.get_kind(), r.x(), r.i(), r.p()); + bv = checker.mk_root_atom(r.get_kind(), r.x(), r.i(), pconvert(r.p())); } } else { @@ -872,7 +877,6 @@ namespace nlsat { literal nlit(tr[lit.var()], !lit.sign()); checker.mk_clause(1, &nlit, nullptr); } - IF_VERBOSE(0, verbose_stream() << "check\n";); lbool r = checker.check(); if (r == l_true) { for (bool_var b : tr) { @@ -902,15 +906,21 @@ namespace nlsat { TRACE("nlsat", display(tout << "violdated tautology clause: ", *c) << "\n";); } } + throw default_exception("lemma did not check"); UNREACHABLE(); } } void log_lemma(std::ostream& out, clause const& cls) { - display_smt2(out); + log_lemma(out, cls.size(), cls.data(), false); + } + + void log_lemma(std::ostream& out, unsigned n, literal const* cls, bool is_valid) { + if (!is_valid) + display_smt2(out); out << "(assert (not "; - display_smt2(out, cls) << "))\n"; - display(out << "(echo \"#" << m_lemma_count << " ", cls) << "\")\n"; + display_smt2(out, n, cls) << "))\n"; + display(out << "(echo \"#" << m_lemma_count << " ", n, cls) << "\")\n"; out << "(check-sat)\n(reset)\n"; } @@ -935,7 +945,7 @@ namespace nlsat { if (learned && m_log_lemmas) { log_lemma(verbose_stream(), *cls); } - if (learned && m_check_lemmas) { + if (learned && m_check_lemmas && false) { check_lemma(cls->size(), cls->data(), false, cls->assumptions()); } if (learned) @@ -1634,7 +1644,7 @@ namespace nlsat { restore_order(); } CTRACE("nlsat_model", r == l_true, tout << "model\n"; display_assignment(tout);); - CTRACE("nlsat", r == l_false, display(tout);); + CTRACE("nlsat", r == l_false, display(tout << "unsat\n");); SASSERT(r != l_true || check_satisfied(m_clauses)); return r; } @@ -1838,6 +1848,8 @@ namespace nlsat { display(tout, m_lazy_clause.size(), m_lazy_clause.data()) << "\n";); if (m_check_lemmas) { + check_lemma(m_lazy_clause.size(), m_lazy_clause.data(), true, nullptr); + log_lemma(verbose_stream(), m_lazy_clause.size(), m_lazy_clause.data(), true); m_valids.push_back(mk_clause_core(m_lazy_clause.size(), m_lazy_clause.data(), false, nullptr)); } @@ -2076,7 +2088,7 @@ namespace nlsat { TRACE("nlsat", tout << "new lemma:\n"; display(tout, m_lemma.size(), m_lemma.data()); tout << "\n"; tout << "found_decision: " << found_decision << "\n";); - if (false && m_check_lemmas) { + if (m_check_lemmas) { check_lemma(m_lemma.size(), m_lemma.data(), false, m_lemma_assumptions.get()); } @@ -2371,13 +2383,9 @@ namespace nlsat { } bool can_reorder() const { - for (clause* c : m_learned) { - if (has_root_atom(*c)) return false; - } - for (clause* c : m_clauses) { - if (has_root_atom(*c)) return false; - } - return m_patch_var.empty(); + return m_patch_var.empty() + && all_of(m_learned, [&](clause* c) { return !has_root_atom(*c); }) + && all_of(m_clauses, [&](clause* c) { return !has_root_atom(*c); }); } /** @@ -2900,7 +2908,8 @@ namespace nlsat { 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 (is_int(x)) + continue; if (1 == m_pm.degree(p0, x)) { p = m_pm.coeff(p0, x, 1, q); if (!m_pm.is_const(p)) @@ -2944,10 +2953,10 @@ namespace nlsat { unsigned sz = m_atoms.size(); for (bool_var b = 0; b < sz; b++) { if (m_atoms[b] == nullptr && m_bvalues[b] != l_undef) { - out << "b" << b << " -> " << (m_bvalues[b] == l_true ? "true" : "false") << "\n"; + out << "b" << b << " -> " << (m_bvalues[b] == l_true ? "true" : "false") << " @" << m_levels[b] << "\n"; } else if (m_atoms[b] != nullptr && m_bvalues[b] != l_undef) { - display(out << "b" << b << " ", *m_atoms[b]) << " -> " << (m_bvalues[b] == l_true ? "true" : "false") << "\n"; + display(out << "b" << b << " ", *m_atoms[b]) << " -> " << (m_bvalues[b] == l_true ? "true" : "false") << " @" << m_levels[b] << "\n"; } } TRACE("nlsat_bool_assignment", @@ -3330,6 +3339,12 @@ namespace nlsat { return display(out, c, m_display_var); } + + std::ostream& display_smt2(std::ostream & out, unsigned n, literal const* ls) const { + return display_smt2(out, n, ls, display_var_proc()); + } + + std::ostream& display_smt2(std::ostream & out, unsigned num, literal const * ls, display_var_proc const & proc) const { if (num == 0) { out << "false"; @@ -3486,7 +3501,7 @@ namespace nlsat { 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]) + if (is_int(i)) out << "(declare-fun x" << i << " () Int)\n"; else out << "(declare-fun x" << i << " () Real)\n"; From be7856c57ddde2b0aafd2d541a56c60f9d0c08ad Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Jan 2024 14:56:15 -0800 Subject: [PATCH 116/224] fix #7027 TODO: review old nlsat bugs for effect of this fix. --- src/math/polynomial/polynomial.cpp | 2 - src/nlsat/nlsat_evaluator.cpp | 2 +- src/nlsat/nlsat_explain.cpp | 51 +++++++++---- src/nlsat/nlsat_solver.cpp | 115 ++++++++++++++++++++--------- 4 files changed, 117 insertions(+), 53 deletions(-) diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index a3af87f52..96a4a05ca 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -1583,9 +1583,7 @@ namespace polynomial { m_i->display_smt2(out, proc); } else { - out << "(* "; m_i->display_smt2(out, proc); - out << ")"; } } else { diff --git a/src/nlsat/nlsat_evaluator.cpp b/src/nlsat/nlsat_evaluator.cpp index 97e0e3d72..247b41485 100644 --- a/src/nlsat/nlsat_evaluator.cpp +++ b/src/nlsat/nlsat_evaluator.cpp @@ -491,7 +491,7 @@ namespace nlsat { interval_set_ref infeasible_intervals(ineq_atom * a, bool neg, clause const* cls) { sign_table & table = m_sign_table_tmp; table.reset(); - TRACE("nsat_evaluator", m_solver.display(tout, *a) << "\n";); + TRACE("nlsat_evaluator", m_solver.display(tout, *a) << "\n";); unsigned num_ps = a->size(); var x = a->max_var(); for (unsigned i = 0; i < num_ps; i++) { diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index 68a646f92..0b76a14ef 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -38,7 +38,7 @@ namespace nlsat { polynomial_ref_vector m_ps; polynomial_ref_vector m_ps2; polynomial_ref_vector m_psc_tmp; - polynomial_ref_vector m_factors; + polynomial_ref_vector m_factors, m_factors_save; scoped_anum_vector m_roots_tmp; bool m_simplify_cores; bool m_full_dimensional; @@ -142,6 +142,7 @@ namespace nlsat { m_ps2(m_pm), m_psc_tmp(m_pm), m_factors(m_pm), + m_factors_save(m_pm), m_roots_tmp(m_am), m_todo(u), m_core1(s), @@ -259,22 +260,42 @@ namespace nlsat { */ ptr_vector m_zero_fs; bool_vector m_is_even; + struct restore_factors { + polynomial_ref_vector& m_factors, &m_factors_save; + unsigned num_saved = 0; + restore_factors(polynomial_ref_vector&f, polynomial_ref_vector& fs): + m_factors(f), m_factors_save(fs) + { + num_saved = m_factors_save.size(); + m_factors_save.append(m_factors); + } + + ~restore_factors() { + m_factors.reset(); + m_factors.append(m_factors_save.size() - num_saved, m_factors_save.data() + num_saved); + m_factors_save.shrink(num_saved); + } + + }; void add_zero_assumption(polynomial_ref & p) { // If p is of the form p1^n1 * ... * pk^nk, // then only the factors that are zero in the current interpretation needed to be considered. // I don't want to create a nested conjunction in the clause. // Then, I assert p_i1 * ... * p_im != 0 - factor(p, m_factors); - unsigned num_factors = m_factors.size(); - m_zero_fs.reset(); - m_is_even.reset(); - polynomial_ref f(m_pm); - for (unsigned i = 0; i < num_factors; i++) { - f = m_factors.get(i); - if (is_zero(sign(f))) { - m_zero_fs.push_back(m_factors.get(i)); - m_is_even.push_back(false); - } + { + restore_factors _restore(m_factors, m_factors_save); + factor(p, m_factors); + unsigned num_factors = m_factors.size(); + m_zero_fs.reset(); + m_is_even.reset(); + polynomial_ref f(m_pm); + for (unsigned i = 0; i < num_factors; i++) { + f = m_factors.get(i); + if (is_zero(sign(f))) { + m_zero_fs.push_back(m_factors.get(i)); + m_is_even.push_back(false); + } + } } SASSERT(!m_zero_fs.empty()); // one of the factors must be zero in the current interpretation, since p is zero in it. literal l = m_solver.mk_ineq_literal(atom::EQ, m_zero_fs.size(), m_zero_fs.data(), m_is_even.data()); @@ -582,8 +603,9 @@ namespace nlsat { if (is_const(p)) return; if (m_factor) { - TRACE("nlsat_explain", display(tout << "adding factors of\n", p); tout << "\n";); + restore_factors _restore(m_factors, m_factors_save); factor(p, m_factors); + TRACE("nlsat_explain", display(tout << "adding factors of\n", p); tout << "\n" << m_factors << "\n";); polynomial_ref f(m_pm); for (unsigned i = 0; i < m_factors.size(); i++) { f = m_factors.get(i); @@ -859,6 +881,7 @@ namespace nlsat { */ void mk_linear_root(atom::kind k, var y, unsigned i, poly * p, bool mk_neg) { + TRACE("nlsat_explain", display_var(tout, y); m_pm.display(tout << ": ", p, m_solver.display_proc()); tout << "\n"); polynomial_ref p_prime(m_pm); p_prime = p; bool lsign = false; @@ -1379,7 +1402,7 @@ namespace nlsat { var max_x = max_var(m_ps); TRACE("nlsat_explain", tout << "polynomials in the conflict:\n"; display(tout, m_ps); tout << "\n";); elim_vanishing(m_ps); - TRACE("nlsat_explain", tout << "elim vanishing\n"; display(tout, m_ps); tout << "\n";); + TRACE("nlsat_explain", tout << "elim vanishing x" << max_x << "\n"; display(tout, m_ps); tout << "\n";); project(m_ps, max_x); TRACE("nlsat_explain", tout << "after projection\n"; display(tout, m_ps); tout << "\n";); } diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 2e482218c..050398d05 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -114,10 +114,10 @@ namespace nlsat { 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 - bool_vector m_dead; // mark dead boolean variables + bool_vector m_dead; // mark dead boolean variables id_gen m_bid_gen; - bool_vector m_is_int; // m_is_int[x] is true if variable is integer + bool_vector m_is_int; // m_is_int[x] is true if variable is integer vector m_watches; // var -> clauses where variable is maximal interval_set_vector m_infeasible; // var -> to a set of interval where the variable cannot be assigned to. atom_vector m_var2eq; // var -> to asserted equality @@ -810,7 +810,7 @@ namespace nlsat { void check_lemma(unsigned n, literal const* cls, bool is_valid, assumption_set a) { TRACE("nlsat", display(tout << "check lemma: ", n, cls) << "\n"; display(tout);); - IF_VERBOSE(0, display(verbose_stream() << "check lemma " << (is_valid?"valid: ":"consequence: "), n, cls) << "\n"); + IF_VERBOSE(2, display(verbose_stream() << "check lemma " << (is_valid?"valid: ":"consequence: "), n, cls) << "\n"); for (clause* c : m_learned) IF_VERBOSE(1, display(verbose_stream() << "lemma: ", *c) << "\n"); scoped_suspend_rlimit _limit(m_rlimit); ctx c(m_rlimit, m_ctx.m_params, m_ctx.m_incremental); @@ -916,10 +916,13 @@ namespace nlsat { } void log_lemma(std::ostream& out, unsigned n, literal const* cls, bool is_valid) { - if (!is_valid) - display_smt2(out); - out << "(assert (not "; - display_smt2(out, n, cls) << "))\n"; + if (is_valid) { + display_smt2_bool_decls(out); + display_smt2_arith_decls(out); + } + else + display_smt2(out); + display_smt2(out << "(assert (not ", n, cls) << "))\n"; display(out << "(echo \"#" << m_lemma_count << " ", n, cls) << "\")\n"; out << "(check-sat)\n(reset)\n"; } @@ -1144,7 +1147,7 @@ namespace nlsat { \brief Assign literal using the given justification */ void assign(literal l, justification j) { - TRACE("nlsat", + TRACE("nlsat_assign", display(tout << "assigning literal: ", l); display(tout << " <- ", j);); @@ -1264,7 +1267,9 @@ namespace nlsat { m_ism.get_justifications(s, core, clauses); if (include_l) core.push_back(~l); - assign(l, mk_lazy_jst(m_allocator, core.size(), core.data(), clauses.size(), clauses.data())); + auto j = mk_lazy_jst(m_allocator, core.size(), core.data(), clauses.size(), clauses.data()); + TRACE("nlsat_resolve", display(tout, j); display_eval(tout, j)); + assign(l, j); SASSERT(value(l) == l_true); } @@ -1815,7 +1820,7 @@ namespace nlsat { } void resolve_clause(bool_var b, clause const & c) { - TRACE("nlsat_resolve", tout << "resolving clause for b: " << b << "\n"; display(tout, c) << "\n";); + TRACE("nlsat_resolve", tout << "resolving clause "; if (b != null_bool_var) tout << "for b: " << b << "\n"; display(tout, c) << "\n";); resolve_clause(b, c.size(), c.data()); m_lemma_assumptions = m_asm.mk_join(static_cast<_assumption_set>(c.assumptions()), m_lemma_assumptions); } @@ -3012,8 +3017,14 @@ namespace nlsat { } return out; } + + bool m_display_eval = false; + std::ostream& display_eval(std::ostream& out, justification j) { + flet _display(m_display_eval, true); + return display(out, j); + } - std::ostream& display(std::ostream & out, ineq_atom const & a, display_var_proc const & proc, bool use_star = false) const { + std::ostream& display_ineq(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) @@ -3021,7 +3032,7 @@ namespace nlsat { bool is_even = a.is_even(i); if (is_even || sz > 1) out << "("; - m_pm.display(out, a.p(i), proc, use_star); + display_polynomial(out, a.p(i), proc, use_star); if (is_even || sz > 1) out << ")"; if (is_even) @@ -3061,7 +3072,7 @@ namespace nlsat { return out; } - std::ostream& display_smt2(std::ostream & out, ineq_atom const & a, display_var_proc const & proc) const { + std::ostream& display_ineq_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; @@ -3090,15 +3101,29 @@ namespace nlsat { return out; } + + std::ostream& display_binary_smt2(std::ostream& out, poly const* p1, char const* rel, poly const* p2, display_var_proc const& proc) const { + out << "(" << rel << " "; + m_pm.display_smt2(out, p1, proc); + out << " "; + m_pm.display_smt2(out, p2, proc); + out << ")"; + return out; + } + std::ostream& display_linear_root_smt2(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { - polynomial_ref A(m_pm), B(m_pm); - polynomial::scoped_numeral one(m_qm); - m_pm.m().set(one, 1); + polynomial_ref A(m_pm), B(m_pm), Z(m_pm), Ax(m_pm); + polynomial::scoped_numeral zero(m_qm); + m_pm.m().set(zero, 0); A = m_pm.derivative(a.p(), a.x()); - B = m_pm.substitute(a.p(), a.x(), one); + B = m_pm.neg(m_pm.substitute(a.p(), a.x(), zero)); + Z = m_pm.mk_zero(); - // x < root[1](ax + b) == (a > 0 => ax < b) & (a < 0 => ax > b) + Ax = m_pm.mul(m_pm.mk_polynomial(a.x()), A); + + // x < root[1](ax + b) == (a > 0 => ax + b < 0) & (a < 0 => ax + b > 0) + // x < root[1](ax + b) == (a > 0 => ax < -b) & (a < 0 => ax > -b) char const* rel1 = "<", *rel2 = ">"; switch (a.get_kind()) { @@ -3111,21 +3136,22 @@ namespace nlsat { } out << "(and "; - out << "(=> (> "; m_pm.display_smt2(out, A, proc); out << " 0) "; - out << "(" << rel1 << " (* "; proc(out, a.x()); out << " "; m_pm.display_smt2(out, A, proc); out << " "; m_pm.display_smt2(out, B, proc); out << ")) "; - out << "(=> (< "; m_pm.display_smt2(out, A, proc); out << " 0) "; - out << "(" << rel2 << " (* "; proc(out, a.x()); out << " "; m_pm.display_smt2(out, A, proc); out << " "; m_pm.display_smt2(out, B, proc); out << ")) "; + out << "(=> "; display_binary_smt2(out, A, ">", Z, proc); display_binary_smt2(out, Ax, rel1, B, proc); out << ") "; + out << "(=> "; display_binary_smt2(out, A, "<", Z, proc); display_binary_smt2(out, Ax, rel2, B, proc); out << ") "; out << ")"; return out; } - std::ostream& display_smt2(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { -#if 0 + std::ostream& display_root_smt2(std::ostream& out, root_atom const& a, display_var_proc const& proc) const { if (a.i() == 1 && m_pm.degree(a.p(), a.x()) == 1) return display_linear_root_smt2(out, a, proc); -#endif + else + return display_root(out, a, proc); + } + + std::ostream& display_root(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; @@ -3136,7 +3162,7 @@ namespace nlsat { default: UNREACHABLE(); break; } out << "root[" << a.i() << "]("; - m_pm.display(out, a.p(), proc); + display_polynomial(out, a.p(), proc); out << ")"; return out; } @@ -3164,21 +3190,16 @@ namespace nlsat { default: UNREACHABLE(); break; } out << "Root["; - m_pm.display(out, a.p(), mathematica_var_proc(a.x()), true); + display_polynomial(out, a.p(), mathematica_var_proc(a.x()), true); out << " &, " << a.i() << "]"; return out; } - - std::ostream& display_smt2(std::ostream & out, root_atom const & a) const { - NOT_IMPLEMENTED_YET(); - return out; - } std::ostream& display(std::ostream & out, atom const & a, display_var_proc const & proc) const { if (a.is_ineq_atom()) - return display(out, static_cast(a), proc); + return display_ineq(out, static_cast(a), proc); else - return display(out, static_cast(a), proc); + return display_root(out, static_cast(a), proc); } std::ostream& display(std::ostream & out, atom const & a) const { @@ -3194,9 +3215,9 @@ namespace nlsat { 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); + return display_ineq_smt2(out, static_cast(a), proc); else - return display_smt2(out, static_cast(a), proc); + return display_root_smt2(out, static_cast(a), proc); } std::ostream& display_atom(std::ostream & out, bool_var b, display_var_proc const & proc) const { @@ -3340,6 +3361,28 @@ namespace nlsat { } + std::ostream& display_polynomial(std::ostream& out, poly* p, display_var_proc const & proc, bool use_star = false) const { + if (m_display_eval) { + polynomial_ref q(m_pm); + q = p; + for (var x = 0; x < num_vars(); x++) + if (m_assignment.is_assigned(x)) { + auto& a = m_assignment.value(x); + if (!m_am.is_rational(a)) + continue; + mpq r; + m_am.to_rational(a, r); + q = m_pm.substitute(q, 1, &x, &r); + } + m_pm.display(out, q, proc, use_star); + } + else + m_pm.display(out, p, proc, use_star); + return out; + } + + // -- + std::ostream& display_smt2(std::ostream & out, unsigned n, literal const* ls) const { return display_smt2(out, n, ls, display_var_proc()); } From 36453c5949a7c4cffa5ba8df495cf5167ee972c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Jan 2024 14:56:57 -0800 Subject: [PATCH 117/224] use while (true) in do loops with continue Signed-off-by: Nikolaj Bjorner --- src/ast/arith_decl_plugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index f09daaf75..67a605869 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -984,7 +984,8 @@ bool arith_util::is_extended_numeral(expr* term, rational& r) const { return true; } return false; - } while (false); + } + while (true); return false; } From 98c9fa7faf937f67fba51bd6658ec71944ded5d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Jan 2024 15:29:11 -0800 Subject: [PATCH 118/224] prepare for handling integer intervals --- src/nlsat/nlsat_evaluator.cpp | 6 +++--- src/nlsat/nlsat_evaluator.h | 2 +- src/nlsat/nlsat_interval_set.cpp | 5 ++--- src/nlsat/nlsat_solver.cpp | 7 ++++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/nlsat/nlsat_evaluator.cpp b/src/nlsat/nlsat_evaluator.cpp index 247b41485..1d55db9cb 100644 --- a/src/nlsat/nlsat_evaluator.cpp +++ b/src/nlsat/nlsat_evaluator.cpp @@ -488,7 +488,7 @@ namespace nlsat { return sign; } - interval_set_ref infeasible_intervals(ineq_atom * a, bool neg, clause const* cls) { + interval_set_ref infeasible_intervals(ineq_atom * a, bool is_int, bool neg, clause const* cls) { sign_table & table = m_sign_table_tmp; table.reset(); TRACE("nlsat_evaluator", m_solver.display(tout, *a) << "\n";); @@ -685,8 +685,8 @@ namespace nlsat { return m_imp->eval(a, neg); } - interval_set_ref evaluator::infeasible_intervals(atom * a, bool neg, clause const* cls) { - return m_imp->infeasible_intervals(a, neg, cls); + interval_set_ref evaluator::infeasible_intervals(atom * a, bool is_int, bool neg, clause const* cls) { + return m_imp->infeasible_intervals(a, is_int, neg, cls); } void evaluator::push() { diff --git a/src/nlsat/nlsat_evaluator.h b/src/nlsat/nlsat_evaluator.h index d2db3f41a..9f9b346dd 100644 --- a/src/nlsat/nlsat_evaluator.h +++ b/src/nlsat/nlsat_evaluator.h @@ -51,7 +51,7 @@ namespace nlsat { Let x be a->max_var(). Then, the resultant set specifies which values of x falsify the given literal. */ - interval_set_ref infeasible_intervals(atom * a, bool neg, clause const* cls); + interval_set_ref infeasible_intervals(atom * a, bool is_int, bool neg, clause const* cls); void push(); void pop(unsigned num_scopes); diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index 70b2bd02c..bf240119e 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -695,12 +695,11 @@ namespace nlsat { scoped_mpq _w(m_am.qm()); m_am.qm().set(_w, num, den); m_am.set(w, _w); - return; } else { m_am.set(w, 0); - return; } + return; } unsigned n = 0; @@ -741,7 +740,7 @@ namespace nlsat { for (unsigned i = 1; i < num; i++) { if (s->m_intervals[i-1].m_upper_open && s->m_intervals[i].m_lower_open) { SASSERT(m_am.eq(s->m_intervals[i-1].m_upper, s->m_intervals[i].m_lower)); // otherwise we would have found it in the previous step - if (m_am.is_rational(s->m_intervals[i-1].m_upper)) { + if (m_am.is_rational(s->m_intervals[i-1].m_upper)) { m_am.set(w, s->m_intervals[i-1].m_upper); return; } diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 050398d05..ef7afda91 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -486,7 +486,7 @@ namespace nlsat { SASSERT(x == num_vars()); m_is_int. push_back(is_int); m_watches. push_back(clause_vector()); - m_infeasible.push_back(0); + m_infeasible.push_back(nullptr); m_var2eq. push_back(nullptr); m_perm. push_back(x); m_inv_perm. push_back(x); @@ -1006,7 +1006,8 @@ 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]); @@ -1356,7 +1357,7 @@ namespace nlsat { atom * a = m_atoms[b]; SASSERT(a != nullptr); interval_set_ref curr_set(m_ism); - curr_set = m_evaluator.infeasible_intervals(a, l.sign(), &cls); + curr_set = m_evaluator.infeasible_intervals(a, is_int(m_xk), l.sign(), &cls); TRACE("nlsat_inf_set", tout << "infeasible set for literal: "; display(tout, l); tout << "\n"; m_ism.display(tout, curr_set); tout << "\n"; display(tout, cls) << "\n";); if (m_ism.is_empty(curr_set)) { From fad428381a3e8e448e096e57d27b59a464660afe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 23 Jan 2024 15:33:48 -0800 Subject: [PATCH 119/224] prepare for integer intervals --- src/nlsat/nlsat_evaluator.cpp | 7 ++++--- src/nlsat/nlsat_explain.cpp | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/nlsat/nlsat_evaluator.cpp b/src/nlsat/nlsat_evaluator.cpp index 1d55db9cb..f95a80b56 100644 --- a/src/nlsat/nlsat_evaluator.cpp +++ b/src/nlsat/nlsat_evaluator.cpp @@ -593,7 +593,8 @@ namespace nlsat { return result; } - interval_set_ref infeasible_intervals(root_atom * a, bool neg, clause const* cls) { + interval_set_ref infeasible_intervals(root_atom * a, bool is_int, bool neg, clause const* cls) { + (void) is_int; atom::kind k = a->get_kind(); unsigned i = a->i(); SASSERT(i > 0); @@ -664,8 +665,8 @@ namespace nlsat { return result; } - interval_set_ref infeasible_intervals(atom * a, bool neg, clause const* cls) { - return a->is_ineq_atom() ? infeasible_intervals(to_ineq_atom(a), neg, cls) : infeasible_intervals(to_root_atom(a), neg, cls); + interval_set_ref infeasible_intervals(atom * a, bool is_int, bool neg, clause const* cls) { + return a->is_ineq_atom() ? infeasible_intervals(to_ineq_atom(a), is_int, neg, cls) : infeasible_intervals(to_root_atom(a), is_int, neg, cls); } }; diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index 0b76a14ef..ef5745fe4 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -1439,7 +1439,7 @@ namespace nlsat { literal l = core[i]; atom * a = m_atoms[l.var()]; SASSERT(a != 0); - interval_set_ref inf = m_evaluator.infeasible_intervals(a, l.sign(), nullptr); + interval_set_ref inf = m_evaluator.infeasible_intervals(a, m_solver.is_int(a->max_var()), l.sign(), nullptr); r = ism.mk_union(inf, r); if (ism.is_full(r)) { // Done @@ -1458,7 +1458,7 @@ namespace nlsat { literal l = todo[i]; atom * a = m_atoms[l.var()]; SASSERT(a != 0); - interval_set_ref inf = m_evaluator.infeasible_intervals(a, l.sign(), nullptr); + interval_set_ref inf = m_evaluator.infeasible_intervals(a, m_solver.is_int(a->max_var()), l.sign(), nullptr); r = ism.mk_union(inf, r); if (ism.is_full(r)) { // literal l must be in the core From 1b94d43a8bab976e42fc05f41f371a3f806927e2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 Jan 2024 08:52:56 -0800 Subject: [PATCH 120/224] fix build Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_evaluator.cpp | 13 ++++++------- src/nlsat/nlsat_evaluator.h | 2 +- src/nlsat/nlsat_explain.cpp | 4 ++-- src/nlsat/nlsat_solver.cpp | 8 ++++---- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/nlsat/nlsat_evaluator.cpp b/src/nlsat/nlsat_evaluator.cpp index f95a80b56..1f93737dc 100644 --- a/src/nlsat/nlsat_evaluator.cpp +++ b/src/nlsat/nlsat_evaluator.cpp @@ -488,7 +488,7 @@ namespace nlsat { return sign; } - interval_set_ref infeasible_intervals(ineq_atom * a, bool is_int, bool neg, clause const* cls) { + interval_set_ref infeasible_intervals(ineq_atom * a, bool neg, clause const* cls) { sign_table & table = m_sign_table_tmp; table.reset(); TRACE("nlsat_evaluator", m_solver.display(tout, *a) << "\n";); @@ -593,8 +593,7 @@ namespace nlsat { return result; } - interval_set_ref infeasible_intervals(root_atom * a, bool is_int, bool neg, clause const* cls) { - (void) is_int; + interval_set_ref infeasible_intervals(root_atom * a, bool neg, clause const* cls) { atom::kind k = a->get_kind(); unsigned i = a->i(); SASSERT(i > 0); @@ -665,8 +664,8 @@ namespace nlsat { return result; } - interval_set_ref infeasible_intervals(atom * a, bool is_int, bool neg, clause const* cls) { - return a->is_ineq_atom() ? infeasible_intervals(to_ineq_atom(a), is_int, neg, cls) : infeasible_intervals(to_root_atom(a), is_int, neg, cls); + interval_set_ref infeasible_intervals(atom * a, bool neg, clause const* cls) { + return a->is_ineq_atom() ? infeasible_intervals(to_ineq_atom(a), neg, cls) : infeasible_intervals(to_root_atom(a), neg, cls); } }; @@ -686,8 +685,8 @@ namespace nlsat { return m_imp->eval(a, neg); } - interval_set_ref evaluator::infeasible_intervals(atom * a, bool is_int, bool neg, clause const* cls) { - return m_imp->infeasible_intervals(a, is_int, neg, cls); + interval_set_ref evaluator::infeasible_intervals(atom * a, bool neg, clause const* cls) { + return m_imp->infeasible_intervals(a, neg, cls); } void evaluator::push() { diff --git a/src/nlsat/nlsat_evaluator.h b/src/nlsat/nlsat_evaluator.h index 9f9b346dd..d2db3f41a 100644 --- a/src/nlsat/nlsat_evaluator.h +++ b/src/nlsat/nlsat_evaluator.h @@ -51,7 +51,7 @@ namespace nlsat { Let x be a->max_var(). Then, the resultant set specifies which values of x falsify the given literal. */ - interval_set_ref infeasible_intervals(atom * a, bool is_int, bool neg, clause const* cls); + interval_set_ref infeasible_intervals(atom * a, bool neg, clause const* cls); void push(); void pop(unsigned num_scopes); diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index ef5745fe4..0b76a14ef 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -1439,7 +1439,7 @@ namespace nlsat { literal l = core[i]; atom * a = m_atoms[l.var()]; SASSERT(a != 0); - interval_set_ref inf = m_evaluator.infeasible_intervals(a, m_solver.is_int(a->max_var()), l.sign(), nullptr); + interval_set_ref inf = m_evaluator.infeasible_intervals(a, l.sign(), nullptr); r = ism.mk_union(inf, r); if (ism.is_full(r)) { // Done @@ -1458,7 +1458,7 @@ namespace nlsat { literal l = todo[i]; atom * a = m_atoms[l.var()]; SASSERT(a != 0); - interval_set_ref inf = m_evaluator.infeasible_intervals(a, m_solver.is_int(a->max_var()), l.sign(), nullptr); + interval_set_ref inf = m_evaluator.infeasible_intervals(a, l.sign(), nullptr); r = ism.mk_union(inf, r); if (ism.is_full(r)) { // literal l must be in the core diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index ef7afda91..16b28c246 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -827,7 +827,7 @@ namespace nlsat { // need to translate Boolean variables and literals scoped_bool_vars tr(checker); for (var x = 0; x < m_is_int.size(); ++x) { - checker.register_var(x, m_is_int[x]); + checker.register_var(x, is_int(x)); } bool_var bv = 0; tr.push_back(bv); @@ -1357,7 +1357,7 @@ namespace nlsat { atom * a = m_atoms[b]; SASSERT(a != nullptr); interval_set_ref curr_set(m_ism); - curr_set = m_evaluator.infeasible_intervals(a, is_int(m_xk), l.sign(), &cls); + curr_set = m_evaluator.infeasible_intervals(a, l.sign(), &cls); TRACE("nlsat_inf_set", tout << "infeasible set for literal: "; display(tout, l); tout << "\n"; m_ism.display(tout, curr_set); tout << "\n"; display(tout, cls) << "\n";); if (m_ism.is_empty(curr_set)) { @@ -1470,7 +1470,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], m_is_int[m_xk], w, m_randomize); + m_ism.peek_in_complement(m_infeasible[m_xk], 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) << "(x" << m_xk << ") -> " << w << "\n";); @@ -1576,7 +1576,7 @@ namespace nlsat { vector> bounds; 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))) { + if (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; From 133546625c411bb174c66b58341b534713331592 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 Jan 2024 09:24:46 -0800 Subject: [PATCH 121/224] update minor version number Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- scripts/nightly.yaml | 2 +- scripts/release.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 60531ca94..39f89ae74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.16) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_compiler_flags_overrides.cmake") -project(Z3 VERSION 4.12.5.0 LANGUAGES CXX) +project(Z3 VERSION 4.12.6.0 LANGUAGES CXX) ################################################################################ # Project version diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 1a8046155..7cc5a0933 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -8,7 +8,7 @@ from mk_util import * def init_version(): - set_version(4, 12, 5, 0) # express a default build version or pick up ci build version + set_version(4, 12, 6, 0) # express a default build version or pick up ci build version # Z3 Project definition def init_project_def(): diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 5c1bdff6a..55c4c5f0c 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -1,7 +1,7 @@ variables: Major: '4' Minor: '12' - Patch: '5' + Patch: '6' AssemblyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId) NightlyVersion: $(AssemblyVersion)-$(Build.DefinitionName) diff --git a/scripts/release.yml b/scripts/release.yml index 76f8a8a57..c146a85fd 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -6,7 +6,7 @@ trigger: none variables: - ReleaseVersion: '4.12.5' + ReleaseVersion: '4.12.6' stages: From bdb9106f996c838f387c1602f29e9665feccea2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 24 Jan 2024 16:05:18 -0800 Subject: [PATCH 122/224] Api (#7097) * rename ul_pair to column Signed-off-by: Lev Nachmanson * t Signed-off-by: Lev Nachmanson * simple test passed * remove an assert * relax an assertion * remove an obsolete function Signed-off-by: Lev Nachmanson * access a term by the term column * remove the column index from colunm.h * remove an unused method * remove debug code * fix the build of lp_tst Signed-off-by: Lev Nachmanson --------- Signed-off-by: Lev Nachmanson Co-authored-by: Lev Nachmanson --- src/math/lp/bound_analyzer_on_row.h | 1 - src/math/lp/{ul_pair.h => column.h} | 25 +- src/math/lp/emonics.cpp | 2 +- src/math/lp/general_matrix.h | 2 +- src/math/lp/gomory.cpp | 12 +- src/math/lp/hnf_cutter.cpp | 14 +- src/math/lp/hnf_cutter.h | 2 +- src/math/lp/int_branch.cpp | 2 +- src/math/lp/int_cube.cpp | 20 +- src/math/lp/int_solver.cpp | 6 +- src/math/lp/int_solver.h | 2 +- src/math/lp/lar_constraints.h | 12 +- src/math/lp/lar_solver.cpp | 536 +++++++++------------------- src/math/lp/lar_solver.h | 175 ++++----- src/math/lp/lar_term.h | 23 +- src/math/lp/lp_api.h | 6 +- src/math/lp/lp_bound_propagator.h | 21 +- src/math/lp/lp_settings.h | 5 +- src/math/lp/lp_types.h | 60 ---- src/math/lp/lp_utils.h | 9 +- src/math/lp/monic.h | 12 +- src/math/lp/monomial_bounds.cpp | 11 +- src/math/lp/nla_core.cpp | 72 ++-- src/math/lp/nla_core.h | 5 +- src/math/lp/nla_defs.h | 8 +- src/math/lp/nla_divisions.cpp | 17 +- src/math/lp/nla_grobner.cpp | 5 +- src/math/lp/nla_powers.cpp | 4 +- src/math/lp/nla_solver.cpp | 2 +- src/math/lp/nla_solver.h | 2 +- src/math/lp/nla_types.h | 2 +- src/math/lp/nra_solver.cpp | 38 +- src/math/lp/nra_solver.h | 2 +- src/math/lp/static_matrix.h | 4 +- src/math/lp/var_register.h | 11 +- src/sat/smt/arith_diagnostics.cpp | 7 +- src/sat/smt/arith_internalize.cpp | 9 +- src/sat/smt/arith_sls.cpp | 36 +- src/sat/smt/arith_sls.h | 4 +- src/sat/smt/arith_solver.cpp | 85 ++--- src/sat/smt/arith_solver.h | 14 +- src/smt/theory_lra.cpp | 159 ++++----- src/test/lp/gomory_test.h | 2 +- src/test/lp/lp.cpp | 110 +++--- src/test/lp/smt_reader.h | 4 +- 45 files changed, 587 insertions(+), 973 deletions(-) rename src/math/lp/{ul_pair.h => column.h} (75%) diff --git a/src/math/lp/bound_analyzer_on_row.h b/src/math/lp/bound_analyzer_on_row.h index b4d587bec..20e45a218 100644 --- a/src/math/lp/bound_analyzer_on_row.h +++ b/src/math/lp/bound_analyzer_on_row.h @@ -291,7 +291,6 @@ private: int bound_sign = (is_lower_bound ? 1 : -1); int j_sign = (coeff_before_j_is_pos ? 1 : -1) * bound_sign; - SASSERT(!tv::is_term(bound_j)); u_dependency* ret = nullptr; for (auto const& r : lar->get_row(row_index)) { unsigned j = r.var(); diff --git a/src/math/lp/ul_pair.h b/src/math/lp/column.h similarity index 75% rename from src/math/lp/ul_pair.h rename to src/math/lp/column.h index 354070281..4f3e68966 100644 --- a/src/math/lp/ul_pair.h +++ b/src/math/lp/column.h @@ -37,17 +37,19 @@ inline std::ostream& operator<<(std::ostream& out, lconstraint_kind k) { return out << "??"; } -inline bool compare(const std::pair & a, const std::pair & b) { +inline bool compare(const std::pair & a, const std::pair & b) { return a.second < b.second; } - -class ul_pair { +class lar_term; // forward definition +class column { u_dependency* m_lower_bound_witness = nullptr; u_dependency* m_upper_bound_witness = nullptr; bool m_associated_with_row = false; + lpvar m_j; //the column index + lar_term* m_term = nullptr; public: - // TODO - seems more straight-forward to just expose ul_pair as a struct with direct access to attributes. - + lar_term* term() const { return m_term; } + u_dependency*& lower_bound_witness() { return m_lower_bound_witness; } u_dependency* lower_bound_witness() const { return m_lower_bound_witness; } u_dependency*& upper_bound_witness() { return m_upper_bound_witness; } @@ -56,20 +58,21 @@ public: // equality is used by stackedvector operations. // this appears to be a low level reason - bool operator!=(const ul_pair & p) const { + bool operator!=(const column & p) const { return !(*this == p); } - bool operator==(const ul_pair & p) const { + bool operator==(const column & p) const { return m_lower_bound_witness == p.m_lower_bound_witness && m_upper_bound_witness == p.m_upper_bound_witness && m_associated_with_row == p.m_associated_with_row; } - // empty constructor - ul_pair() {} + column() = delete; + column(bool) = delete; - ul_pair(bool associated_with_row) : - m_associated_with_row(associated_with_row) {} + + column(bool associated_with_row, lar_term* term) : + m_associated_with_row(associated_with_row), m_term(term) {} bool associated_with_row() const { return m_associated_with_row; } }; diff --git a/src/math/lp/emonics.cpp b/src/math/lp/emonics.cpp index 5d0e664f2..e6e52e57b 100644 --- a/src/math/lp/emonics.cpp +++ b/src/math/lp/emonics.cpp @@ -536,7 +536,7 @@ bool emonics::invariant() const { do { auto const& m = m_monics[c->m_index]; bool found = false; - for (lp::var_index w : m.rvars()) { + for (lp::lpvar w : m.rvars()) { auto w1 = m_ve.find(w); found |= v1.var() == w1.var(); } diff --git a/src/math/lp/general_matrix.h b/src/math/lp/general_matrix.h index a4f6693a2..fb1030e6b 100644 --- a/src/math/lp/general_matrix.h +++ b/src/math/lp/general_matrix.h @@ -109,7 +109,7 @@ public: auto & row = m_data[adjust_row(i)]; lp_assert(row_is_initialized_correctly(row)); for (lp::lar_term::ival p : c) { - unsigned j = adjust_column(column_fix(p.column().index())); + unsigned j = adjust_column(column_fix(p.j())); row[j] = sign * p.coeff(); } } diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index a7c72a76d..7b4347af5 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -156,7 +156,7 @@ struct create_cut { template void dump_coeff(std::ostream & out, const T& c) const { - dump_coeff_val(out << "(* ", c.coeff()) << " " << var_name(c.column().index()) << ")"; + dump_coeff_val(out << "(* ", c.coeff()) << " " << var_name(c.j()) << ")"; } std::ostream& dump_row_coefficients(std::ostream & out) const { @@ -183,9 +183,8 @@ struct create_cut { for (const auto & p : m_row) dump_declaration(out, p.var()); for (lar_term::ival p : m_t) { - auto t = lia.lra.column2tv(p.column()); - if (t.is_term()) - dump_declaration(out, t.id()); + if (lia.lra.column_has_term(p.j())) + dump_declaration(out, p.j()); } } @@ -491,9 +490,8 @@ public: return all_of(t, [&](auto ci) { return ci.coeff().is_small(); }); }; auto add_cut = [&](const lar_term& t, const mpq& k, u_dependency * dep) { - lp::lpvar term_index = lra.add_term(t.coeffs_as_vector(), UINT_MAX); - term_index = lra.map_term_index_to_column_index(term_index); - lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::GE, k, dep); + lp::lpvar j = lra.add_term(t.coeffs_as_vector(), UINT_MAX); + lra.update_column_type_and_bound(j, lp::lconstraint_kind::GE, k, dep); }; auto _check_feasible = [&](void) { lra.find_feasible_solution(); diff --git a/src/math/lp/hnf_cutter.cpp b/src/math/lp/hnf_cutter.cpp index 75095ca51..b120b7aac 100644 --- a/src/math/lp/hnf_cutter.cpp +++ b/src/math/lp/hnf_cutter.cpp @@ -20,7 +20,7 @@ namespace lp { lra(lia.lra), m_settings(lia.settings()), m_abs_max(zero_of_type()), - m_var_register(false) {} + m_var_register() {} bool hnf_cutter::is_full() const { return @@ -50,7 +50,7 @@ namespace lp { m_constraints_for_explanation.push_back(ci); for (lar_term::ival p : *t) { - m_var_register.add_var(p.column().index(), true); // hnf only deals with integral variables for now + m_var_register.add_var(p.j(), true); // hnf only deals with integral variables for now mpq t = abs(ceil(p.coeff())); if (t > m_abs_max) m_abs_max = t; @@ -227,12 +227,12 @@ branch y_i >= ceil(y0_i) is impossible. svector hnf_cutter::vars() const { return m_var_register.vars(); } - void hnf_cutter::try_add_term_to_A_for_hnf(tv const &i) { + void hnf_cutter::try_add_term_to_A_for_hnf(lpvar j) { mpq rs; - const lar_term& t = lra.get_term(i); + const lar_term& t = lra.get_term(j); u_dependency* dep; bool upper_bound; - if (!is_full() && lra.get_equality_and_right_side_for_term_on_current_x(i, rs, dep, upper_bound)) { + if (!is_full() && lra.get_equality_and_right_side_for_term_on_current_x(j, rs, dep, upper_bound)) { add_term(&t, rs, dep, upper_bound); } } @@ -243,8 +243,8 @@ branch y_i >= ceil(y0_i) is impossible. bool hnf_cutter::init_terms_for_hnf_cut() { clear(); - for (unsigned i = 0; i < lra.terms().size() && !is_full(); i++) - try_add_term_to_A_for_hnf(tv::term(i)); + for (const lar_term* t: lra.terms()) + try_add_term_to_A_for_hnf(t->j()); return hnf_has_var_with_non_integral_value(); } diff --git a/src/math/lp/hnf_cutter.h b/src/math/lp/hnf_cutter.h index 74fb52327..07ddc7b12 100644 --- a/src/math/lp/hnf_cutter.h +++ b/src/math/lp/hnf_cutter.h @@ -50,7 +50,7 @@ public: private: bool init_terms_for_hnf_cut(); bool hnf_has_var_with_non_integral_value() const; - void try_add_term_to_A_for_hnf(tv const& i); + void try_add_term_to_A_for_hnf(lpvar); unsigned terms_count() const { return m_terms.size(); } const mpq & abs_max() const { return m_abs_max; } diff --git a/src/math/lp/int_branch.cpp b/src/math/lp/int_branch.cpp index 4ab97d3ed..10211c4fa 100644 --- a/src/math/lp/int_branch.cpp +++ b/src/math/lp/int_branch.cpp @@ -34,7 +34,7 @@ lia_move int_branch::create_branch_on_column(int j) { lia.m_t.clear(); lp_assert(j != -1); - lia.m_t.add_monomial(mpq(1), lra.column_to_reported_index(j)); + lia.m_t.add_monomial(mpq(1), j); if (lia.is_free(j)) { lia.m_upper = lia.random() % 2; lia.m_k = mpq(0); diff --git a/src/math/lp/int_cube.cpp b/src/math/lp/int_cube.cpp index 9ef9aa341..c8488ca37 100644 --- a/src/math/lp/int_cube.cpp +++ b/src/math/lp/int_cube.cpp @@ -55,21 +55,21 @@ namespace lp { lia.settings().stats().m_cube_success++; return lia_move::sat; } - +// i is the column index having the term bool int_cube::tighten_term_for_cube(unsigned i) { - if (!lra.term_is_used_as_row(i)) + if (!lra.column_associated_with_row(i)) return true; - const lar_term* t = lra.terms()[i]; - impq delta = get_cube_delta_for_term(*t); - TRACE("cube", lra.print_term_as_indices(*t, tout); tout << ", delta = " << delta << "\n";); + const lar_term& t = lra.get_term(i); + impq delta = get_cube_delta_for_term(t); + TRACE("cube", lra.print_term_as_indices(t, tout); tout << ", delta = " << delta << "\n";); if (is_zero(delta)) return true; - return lra.tighten_term_bounds_by_delta(tv::term(i), delta); + return lra.tighten_term_bounds_by_delta(i, delta); } bool int_cube::tighten_terms_for_cube() { - for (unsigned i = 0; i < lra.terms().size(); i++) - if (!tighten_term_for_cube(i)) { + for (const lar_term* t: lra.terms()) + if (!tighten_term_for_cube(t->j())) { TRACE("cube", tout << "cannot tighten";); return false; } @@ -86,7 +86,7 @@ namespace lp { bool seen_minus = false; bool seen_plus = false; for(lar_term::ival p : t) { - if (!lia.column_is_int(p.column())) + if (!lia.column_is_int(p.j())) goto usual_delta; const mpq & c = p.coeff(); if (c == one_of_type()) { @@ -104,7 +104,7 @@ namespace lp { usual_delta: mpq delta = zero_of_type(); for (lar_term::ival p : t) - if (lia.column_is_int(p.column())) + if (lia.column_is_int(p.j())) delta += abs(p.coeff()); delta *= mpq(1, 2); diff --git a/src/math/lp/int_solver.cpp b/src/math/lp/int_solver.cpp index 5c480cbb3..f547ba274 100644 --- a/src/math/lp/int_solver.cpp +++ b/src/math/lp/int_solver.cpp @@ -228,7 +228,7 @@ namespace lp { bool int_solver::cut_indices_are_columns() const { for (lar_term::ival p : m_t) { - if (p.column().index() >= lra.A_r().column_count()) + if (p.j() >= lra.A_r().column_count()) return false; } return true; @@ -271,7 +271,7 @@ namespace lp { return lra.settings(); } - bool int_solver::column_is_int(column_index const& j) const { + bool int_solver::column_is_int(lpvar j) const { return lra.column_is_int(j); } @@ -296,7 +296,7 @@ namespace lp { } bool int_solver::is_term(unsigned j) const { - return lra.column_corresponds_to_term(j); + return lra.column_has_term(j); } unsigned int_solver::column_count() const { diff --git a/src/math/lp/int_solver.h b/src/math/lp/int_solver.h index 5f8e3eeb5..524f8fb28 100644 --- a/src/math/lp/int_solver.h +++ b/src/math/lp/int_solver.h @@ -83,7 +83,7 @@ public: bool is_real(unsigned j) const; const impq & lower_bound(unsigned j) const; const impq & upper_bound(unsigned j) const; - bool column_is_int(column_index const& j) const; + bool column_is_int(lpvar j) const; const impq & get_value(unsigned j) const; bool at_lower(unsigned j) const; bool at_upper(unsigned j) const; diff --git a/src/math/lp/lar_constraints.h b/src/math/lp/lar_constraints.h index f0c937324..b9069625f 100644 --- a/src/math/lp/lar_constraints.h +++ b/src/math/lp/lar_constraints.h @@ -16,7 +16,7 @@ Author: #include "util/region.h" #include "util/stacked_value.h" #include "math/lp/lp_utils.h" -#include "math/lp/ul_pair.h" +#include "math/lp/column.h" #include "math/lp/lar_term.h" #include "math/lp/column_namer.h" namespace lp { @@ -46,7 +46,7 @@ class lar_base_constraint { public: - virtual vector> coeffs() const = 0; + virtual vector> coeffs() const = 0; lar_base_constraint(unsigned j, lconstraint_kind kind, u_dependency* dep, const mpq& right_side) : m_kind(kind), m_right_side(right_side), m_active(false), m_j(j), m_dep(dep) {} virtual ~lar_base_constraint() = default; @@ -69,8 +69,8 @@ public: lar_var_constraint(unsigned j, lconstraint_kind kind, u_dependency* dep, const mpq& right_side) : lar_base_constraint(j, kind, dep, right_side) {} - vector> coeffs() const override { - vector> ret; + vector> coeffs() const override { + vector> ret; ret.push_back(std::make_pair(one_of_type(), column())); return ret; } @@ -84,7 +84,7 @@ public: lar_term_constraint(unsigned j, const lar_term* t, lconstraint_kind kind, u_dependency* dep, const mpq& right_side) : lar_base_constraint(j, kind, dep, right_side), m_term(t) {} - vector> coeffs() const override { return m_term->coeffs_as_vector(); } + vector> coeffs() const override { return m_term->coeffs_as_vector(); } unsigned size() const override { return m_term->size();} }; @@ -168,7 +168,7 @@ public: m_region.pop_scope(k); } - constraint_index add_var_constraint(var_index j, lconstraint_kind k, mpq const& rhs) { + constraint_index add_var_constraint(lpvar j, lconstraint_kind k, mpq const& rhs) { return add(new (m_region) lar_var_constraint(j, k, mk_dep(), rhs)); } diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index d14a7489e..ef61c2209 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -23,8 +23,7 @@ namespace lp { lar_solver::lar_solver() : m_mpq_lar_core_solver(m_settings, *this), - m_var_register(false), - m_term_register(true), + m_var_register(), m_constraints(m_dependencies, *this) {} // start or ends tracking the rows that were changed by solve() @@ -52,9 +51,9 @@ namespace lp { std::ostream& lar_solver::print_implied_bound(const implied_bound& be, std::ostream& out) const { out << "implied bound\n"; unsigned v = be.m_j; - if (tv::is_term(v)) { - out << "it is a term number " << tv::unmask_term(be.m_j) << std::endl; - print_term(*m_terms[tv::unmask_term(v)], out); + if (column_has_term(v)) { + out << "term for column " << v << std::endl; + print_term(*m_columns[v].term(), out); } else { out << get_variable_name(v); @@ -95,7 +94,7 @@ namespace lp { if (strict) kind = static_cast((static_cast(kind) / 2)); - if (!tv::is_term(be.m_j)) { + if (!column_has_term(be.m_j)) { if (coeff_map.size() != 1) return false; auto it = coeff_map.find(be.m_j); @@ -109,13 +108,13 @@ namespace lp { else { lar_term const& t = get_term(be.m_j); auto first_coeff = t.begin(); - unsigned j = (*first_coeff).column(); + unsigned j = (*first_coeff).j(); auto it = coeff_map.find(j); if (it == coeff_map.end()) return false; mpq ratio = it->second / (*first_coeff).coeff(); for (auto p : t) { - it = coeff_map.find(p.column()); + it = coeff_map.find(p.j()); if (it == coeff_map.end()) return false; if (p.coeff() * ratio != it->second) @@ -139,43 +138,6 @@ namespace lp { return false; } - void lar_solver::substitute_basis_var_in_terms_for_row(unsigned i) { - // todo : create a map from term basic vars to the rows where they are used - unsigned basis_j = m_mpq_lar_core_solver.m_r_solver.m_basis[i]; - for (unsigned k = 0; k < m_terms.size(); k++) { - if (term_is_used_as_row(k)) - continue; - if (!m_terms[k]->contains(basis_j)) - continue; - m_terms[k]->subst_in_row(basis_j, m_mpq_lar_core_solver.m_r_solver.m_pivot_row); - } - } - - // Returns the column index without changes, - // but in the case the column was created as - // the slack variable to a term return the term index. - // It is the same index that was returned by add_var(), or - // by add_term() - unsigned lar_solver::column_to_reported_index(unsigned j) const { - if (tv::is_term(j)) - return j; - unsigned ext_var_or_term = m_var_register.local_to_external(j); - if (tv::is_term(ext_var_or_term)) - j = ext_var_or_term; - return j; - } - - unsigned lar_solver::map_term_index_to_column_index(unsigned j) const { - SASSERT(tv::is_term(j)); - return m_var_register.external_to_local(j); - } - - // here i is just the term index - bool lar_solver::term_is_used_as_row(unsigned i) const { - SASSERT(i < m_terms.size()); - return m_var_register.external_is_used(tv::mask_term(i)); - } - lp_status lar_solver::get_status() const { return m_status; } void lar_solver::set_status(lp_status s) { @@ -189,8 +151,6 @@ namespace lp { stats().m_max_cols = A_r().column_count(); if (A_r().row_count() > stats().m_max_rows) stats().m_max_rows = A_r().row_count(); - if (strategy_is_undecided()) - decide_on_strategy_and_adjust_initial_state(); flet f(settings().simplex_strategy(), simplex_strategy_enum::tableau_rows); m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true; auto ret = solve(); @@ -257,7 +217,7 @@ namespace lp { m_crossed_bounds_column = null_lpvar; m_crossed_bounds_deps = nullptr; m_trail.pop_scope(k); - unsigned n = m_columns_to_ul_pairs.size(); + unsigned n = m_columns.size(); m_var_register.shrink(n); lp_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count()); @@ -276,9 +236,7 @@ namespace lp { unsigned m = A_r().row_count(); clean_popped_elements(m, m_touched_rows); clean_inf_heap_of_r_solver_after_pop(); - lp_assert( - m_settings.simplex_strategy() == simplex_strategy_enum::undecided || - m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + SASSERT(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); m_constraints.pop(k); m_simplex_strategy.pop(k); @@ -296,9 +254,6 @@ namespace lp { bool lar_solver::maximize_term_on_tableau(const lar_term& term, impq& term_max) { flet f(m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only, false); - if (settings().simplex_strategy() == simplex_strategy_enum::undecided) - decide_on_strategy_and_adjust_initial_state(); - m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::FEASIBLE); m_mpq_lar_core_solver.solve(); lp_status st = m_mpq_lar_core_solver.m_r_solver.get_status(); @@ -325,7 +280,7 @@ namespace lp { TRACE("lar_solver_improve_bounds", tout << "d[" << j << "] = " << d_j << "\n"; this->m_mpq_lar_core_solver.m_r_solver.print_column_info(j, tout);); - const ul_pair& ul = m_columns_to_ul_pairs[j]; + const column& ul = m_columns[j]; u_dependency * bound_dep; if (d_j.is_pos()) bound_dep = ul.upper_bound_witness(); @@ -411,7 +366,7 @@ namespace lp { auto& d = rslv.m_d; auto& costs = rslv.m_costs; for (lar_term::ival p : term) { - unsigned j = p.column(); + unsigned j = p.j(); costs[j] = zero_of_type(); int i = rslv.m_basis_heading[j]; if (i < 0) @@ -433,7 +388,7 @@ namespace lp { move_non_basic_columns_to_bounds(); rslv.m_costs.resize(A_r().column_count(), zero_of_type()); for (lar_term::ival p : term) { - unsigned j = p.column(); + unsigned j = p.j(); rslv.m_costs[j] = p.coeff(); if (rslv.m_basis_heading[j] < 0) rslv.m_d[j] += p.coeff(); @@ -540,28 +495,28 @@ namespace lp { lp_assert(is_base(j)); unsigned i = row_of_basic_column(j); for (const auto & c : A_r().m_rows[i]) - if (j != c.var() && !is_fixed(c.var())) + if (j != c.var() && !column_is_fixed(c.var())) return m_mpq_lar_core_solver.m_r_solver.remove_from_basis_core(c.var(), j); return false; } - lar_term lar_solver::get_term_to_maximize(unsigned j_or_term) const { - if (tv::is_term(j_or_term)) { - return get_term(j_or_term); + lar_term lar_solver::get_term_to_maximize(unsigned j) const { + if (column_has_term(j)) { + return * m_columns[j].term(); } - if (j_or_term < m_mpq_lar_core_solver.m_r_x.size()) { + if (j < m_mpq_lar_core_solver.m_r_x.size()) { lar_term r; - r.add_monomial(one_of_type(), j_or_term); + r.add_monomial(one_of_type(), j); return r; } return lar_term(); // return an empty term } - lp_status lar_solver::maximize_term(unsigned j_or_term, + lp_status lar_solver::maximize_term(unsigned j, impq& term_max) { TRACE("lar_solver", print_values(tout);); SASSERT(m_mpq_lar_core_solver.m_r_solver.calc_current_x_is_feasible_include_non_basis()); - lar_term term = get_term_to_maximize(j_or_term); + lar_term term = get_term_to_maximize(j); if (term.is_empty()) return lp_status::UNBOUNDED; impq prev_value = term.apply(m_mpq_lar_core_solver.m_r_x); auto backup = m_mpq_lar_core_solver.m_r_x; @@ -607,13 +562,6 @@ namespace lp { return lp_status::FEASIBLE; } - - - const lar_term& lar_solver::get_term(unsigned j) const { - lp_assert(tv::is_term(j)); - return *m_terms[tv::unmask_term(j)]; - } - void lar_solver::pop_core_solver_params() { pop_core_solver_params(1); } @@ -624,17 +572,17 @@ namespace lp { - void lar_solver::set_upper_bound_witness(var_index j, u_dependency* dep) { - m_trail.push(vector_value_trail(m_columns_to_ul_pairs, j)); - m_columns_to_ul_pairs[j].upper_bound_witness() = dep; + void lar_solver::set_upper_bound_witness(lpvar j, u_dependency* dep) { + m_trail.push(vector_value_trail(m_columns, j)); + m_columns[j].upper_bound_witness() = dep; } - void lar_solver::set_lower_bound_witness(var_index j, u_dependency* dep) { - m_trail.push(vector_value_trail(m_columns_to_ul_pairs, j)); - m_columns_to_ul_pairs[j].lower_bound_witness() = dep; + void lar_solver::set_lower_bound_witness(lpvar j, u_dependency* dep) { + m_trail.push(vector_value_trail(m_columns, j)); + m_columns[j].lower_bound_witness() = dep; } - void lar_solver::register_monoid_in_map(std::unordered_map& coeffs, const mpq& a, unsigned j) { + void lar_solver::register_monoid_in_map(std::unordered_map& coeffs, const mpq& a, unsigned j) { auto it = coeffs.find(j); if (it == coeffs.end()) coeffs[j] = a; @@ -643,19 +591,19 @@ namespace lp { } - void lar_solver::substitute_terms_in_linear_expression(const vector>& left_side_with_terms, - vector>& left_side) const { - std::unordered_map coeffs; + void lar_solver::substitute_terms_in_linear_expression(const vector>& left_side_with_terms, + vector>& left_side) const { + std::unordered_map coeffs; for (auto& t : left_side_with_terms) { unsigned j = t.second; - if (!tv::is_term(j)) { + if (!column_has_term(j)) { register_monoid_in_map(coeffs, t.first, j); } else { - const lar_term& term = *m_terms[tv::unmask_term(t.second)]; + const lar_term& term = *m_columns[t.second].term(); for (auto p : term) - register_monoid_in_map(coeffs, t.first * p.coeff(), p.column()); + register_monoid_in_map(coeffs, t.first * p.coeff(), p.j()); } } @@ -675,16 +623,16 @@ namespace lp { unsigned num = A_r().column_count(); unsigned_vector to_remove; for (unsigned j : m_fixed_base_var_set) { - if (j >= num || !is_base(j) || !is_fixed(j)) { + if (j >= num || !is_base(j) || !column_is_fixed(j)) { to_remove.push_back(j); continue; } - lp_assert(is_base(j) && is_fixed(j)); + lp_assert(is_base(j) && column_is_fixed(j)); auto const& r = basic2row(j); for (auto const& c : r) { unsigned j_entering = c.var(); - if (!is_fixed(j_entering)) { + if (!column_is_fixed(j_entering)) { pivot(j_entering, j); to_remove.push_back(j); lp_assert(is_base(j_entering)); @@ -839,15 +787,12 @@ namespace lp { return r; } - bool lar_solver::var_is_registered(var_index vj) const { - if (tv::is_term(vj)) { - return tv::unmask_term(vj) < m_terms.size(); - } - return vj < A_r().column_count(); + bool lar_solver::var_is_registered(lpvar vj) const { + return vj < A_r().column_count(); } - bool lar_solver::all_constrained_variables_are_registered(const vector>& left_side) { + bool lar_solver::all_constrained_variables_are_registered(const vector>& left_side) { for (auto it : left_side) { if (!var_is_registered(it.second)) return false; @@ -858,7 +803,7 @@ namespace lp { bool lar_solver::all_constraints_hold() const { if (m_settings.get_cancel_flag()) return true; - std::unordered_map var_map; + std::unordered_map var_map; get_model_do_not_care_about_diff_vars(var_map); for (auto const& c : m_constraints.active()) { @@ -874,7 +819,7 @@ namespace lp { return true; } - bool lar_solver::constraint_holds(const lar_base_constraint& constr, std::unordered_map& var_map) const { + bool lar_solver::constraint_holds(const lar_base_constraint& constr, std::unordered_map& var_map) const { mpq left_side_val = get_left_side_val(constr, var_map); switch (constr.kind()) { case LE: return left_side_val <= constr.rhs(); @@ -889,7 +834,7 @@ namespace lp { } - void lar_solver::register_in_map(std::unordered_map& coeffs, const lar_base_constraint& cn, const mpq& a) { + void lar_solver::register_in_map(std::unordered_map& coeffs, const lar_base_constraint& cn, const mpq& a) { for (auto& it : cn.coeffs()) { unsigned j = it.second; auto p = coeffs.find(j); @@ -904,7 +849,7 @@ namespace lp { } bool lar_solver::the_left_sides_sum_to_zero(const vector>& evidence) const { - std::unordered_map coeff_map; + std::unordered_map coeff_map; for (auto const & [coeff, con_ind] : evidence) { lp_assert(m_constraints.valid_index(con_ind)); register_in_map(coeff_map, m_constraints[con_ind], coeff); @@ -966,13 +911,13 @@ namespace lp { return ret; } - bool lar_solver::has_lower_bound(var_index var, u_dependency*& ci, mpq& value, bool& is_strict) const { + bool lar_solver::has_lower_bound(lpvar var, u_dependency*& ci, mpq& value, bool& is_strict) const { - if (var >= m_columns_to_ul_pairs.size()) { + if (var >= m_columns.size()) { // TBD: bounds on terms could also be used, caller may have to track these. return false; } - const ul_pair& ul = m_columns_to_ul_pairs[var]; + const column& ul = m_columns[var]; ci = ul.lower_bound_witness(); if (ci != nullptr) { auto& p = m_mpq_lar_core_solver.m_r_lower_bounds()[var]; @@ -985,13 +930,13 @@ namespace lp { } } - bool lar_solver::has_upper_bound(var_index var, u_dependency*& ci, mpq& value, bool& is_strict) const { + bool lar_solver::has_upper_bound(lpvar var, u_dependency*& ci, mpq& value, bool& is_strict) const { - if (var >= m_columns_to_ul_pairs.size()) { + if (var >= m_columns.size()) { // TBD: bounds on terms could also be used, caller may have to track these. return false; } - const ul_pair& ul = m_columns_to_ul_pairs[var]; + const column& ul = m_columns[var]; ci = ul.upper_bound_witness(); if (ci != nullptr) { auto& p = m_mpq_lar_core_solver.m_r_upper_bounds()[var]; @@ -1004,12 +949,12 @@ namespace lp { } } - bool lar_solver::has_value(var_index var, mpq& value) const { - if (tv::is_term(var)) { + bool lar_solver::has_value(lpvar var, mpq& value) const { + if (column_has_term(var)) { lar_term const& t = get_term(var); value = 0; for (lar_term::ival cv : t) { - impq const& r = get_column_value(cv.column()); + impq const& r = get_column_value(cv.j()); if (!numeric_traits::is_zero(r.y)) return false; value += r.x * cv.coeff(); } @@ -1049,7 +994,7 @@ namespace lp { unsigned j = it.second; int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; - const ul_pair& ul = m_columns_to_ul_pairs[j]; + const column& ul = m_columns[j]; u_dependency* bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.lower_bound_witness(); svector deps; @@ -1062,7 +1007,7 @@ namespace lp { } // (x, y) != (x', y') => (x + delta*y) != (x' + delta*y') - void lar_solver::get_model(std::unordered_map& variable_values) const { + void lar_solver::get_model(std::unordered_map& variable_values) const { variable_values.clear(); if (!init_model()) return; @@ -1070,7 +1015,7 @@ namespace lp { unsigned n = m_mpq_lar_core_solver.m_r_x.size(); for (unsigned j = 0; j < n; j++) - variable_values[j] = get_value(column_index(j)); + variable_values[j] = get_value(j); TRACE("lar_solver_model", tout << "delta = " << m_delta << "\nmodel:\n"; for (auto p : variable_values) tout << this->get_variable_name(p.first) << " = " << p.second << "\n";); @@ -1108,7 +1053,7 @@ namespace lp { return true; } - void lar_solver::get_model_do_not_care_about_diff_vars(std::unordered_map& variable_values) const { + void lar_solver::get_model_do_not_care_about_diff_vars(std::unordered_map& variable_values) const { mpq delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(mpq(1)); for (unsigned i = 0; i < m_mpq_lar_core_solver.m_r_x.size(); i++) { const impq& rp = m_mpq_lar_core_solver.m_r_x[i]; @@ -1116,32 +1061,13 @@ namespace lp { } } - mpq lar_solver::get_value(column_index const& j) const { + mpq lar_solver::get_value(lpvar j) const { SASSERT(get_status() == lp_status::OPTIMAL || get_status() == lp_status::FEASIBLE); VERIFY(m_columns_with_changed_bounds.empty()); numeric_pair const& rp = get_column_value(j); return from_model_in_impq_to_mpq(rp); } - mpq lar_solver::get_tv_value(tv const& t) const { - if (t.is_var()) - return get_value(t.column()); -#if 0 - unsigned term_j = 0; - if (m_var_register.term_is_used(t.id(), term_j)) - return get_value(column_index(term_j)); -#endif - mpq r(0); - for (lar_term::ival p : get_term(t)) - r += p.coeff() * get_value(p.column()); - return r; - } - //fetches the cached value of the term or the variable by the given index - const impq& lar_solver::get_tv_ivalue(tv const& t) const { - unsigned j = t.is_var()? (unsigned)t.column(): this->map_term_index_to_column_index(t.index()); - return this->get_column_value(j); - } - void lar_solver::get_rid_of_inf_eps() { bool y_is_zero = true; for (unsigned j = 0; j < number_of_vars(); j++) { @@ -1162,13 +1088,13 @@ namespace lp { } } - void lar_solver::set_variable_name(var_index vi, std::string name) { + void lar_solver::set_variable_name(lpvar vi, std::string name) { m_var_register.set_name(vi, name); } - std::string lar_solver::get_variable_name(var_index j) const { - if (tv::is_term(j)) - return std::string("_t") + T_to_string(tv::unmask_term(j)); + std::string lar_solver::get_variable_name(lpvar j) const { + if (column_has_term(j)) + return std::string("_t") + T_to_string(j); if (j >= m_var_register.size()) return std::string("_s") + T_to_string(j); @@ -1180,7 +1106,7 @@ namespace lp { return std::string("j") + T_to_string(m_var_register.local_to_external(j)); } else { - std::string s = column_corresponds_to_term(j) ? "t" : "j"; + std::string s = column_has_term(j) ? "t" : "j"; return s + T_to_string(j); } } @@ -1225,7 +1151,7 @@ namespace lp { out << " - "; else if (val != numeric_traits::one()) out << T_to_string(val); - out << this->get_variable_name(p.column()); + out << this->get_variable_name(p.j()); } return out; } @@ -1235,10 +1161,10 @@ namespace lp { return out; } - mpq lar_solver::get_left_side_val(const lar_base_constraint& cns, const std::unordered_map& var_map) const { + mpq lar_solver::get_left_side_val(const lar_base_constraint& cns, const std::unordered_map& var_map) const { mpq ret = cns.get_free_coeff_of_left_side(); for (auto& it : cns.coeffs()) { - var_index j = it.second; + lpvar j = it.second; auto vi = var_map.find(j); lp_assert(vi != var_map.end()); ret += it.first * vi->second; @@ -1247,13 +1173,13 @@ namespace lp { } - void lar_solver::fill_var_set_for_random_update(unsigned sz, var_index const* vars, vector& column_list) { + void lar_solver::fill_var_set_for_random_update(unsigned sz, lpvar const* vars, vector& column_list) { TRACE("lar_solver_rand", tout << "sz = " << sz << "\n";); for (unsigned i = 0; i < sz; i++) { - var_index var = vars[i]; - if (tv::is_term(var)) { - if (term_is_used_as_row(tv::unmask_term(var))) { - column_list.push_back(map_term_index_to_column_index(var)); + lpvar var = vars[i]; + if (column_has_term(var)) { + if (m_columns[var].associated_with_row()) { + column_list.push_back(var); } } else { @@ -1262,7 +1188,7 @@ namespace lp { } } - void lar_solver::random_update(unsigned sz, var_index const* vars) { + void lar_solver::random_update(unsigned sz, lpvar const* vars) { vector column_list; fill_var_set_for_random_update(sz, vars, column_list); random_updater ru(*this, column_list); @@ -1280,7 +1206,7 @@ namespace lp { } bool lar_solver::column_represents_row_in_tableau(unsigned j) { - return m_columns_to_ul_pairs[j].associated_with_row(); + return m_columns[j].associated_with_row(); } void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) { @@ -1430,7 +1356,7 @@ namespace lp { bool lar_solver::term_is_int(const lar_term* t) const { for (auto const p : *t) - if (!(column_is_int(p.column()) && p.coeff().is_int())) + if (!(column_is_int(p.j()) && p.coeff().is_int())) return false; return true; } @@ -1442,14 +1368,9 @@ namespace lp { return true; } - bool lar_solver::var_is_int(var_index v) const { - if (tv::is_term(v)) { - lar_term const& t = get_term(v); - return term_is_int(&t); - } - else { - return column_is_int(v); - } + bool lar_solver::var_is_int(lpvar v) const { + SASSERT(!column_has_term(v) || term_is_int(&get_term(v)) == column_is_int(v)); + return column_is_int(v); } bool lar_solver::column_is_int(unsigned j) const { @@ -1466,34 +1387,26 @@ namespace lp { // below is the initialization functionality of lar_solver - bool lar_solver::strategy_is_undecided() const { - return m_settings.simplex_strategy() == simplex_strategy_enum::undecided; - } - - var_index lar_solver::add_named_var(unsigned ext_j, bool is_int, const std::string& name) { - var_index j = add_var(ext_j, is_int); + lpvar lar_solver::add_named_var(unsigned ext_j, bool is_int, const std::string& name) { + lpvar j = add_var(ext_j, is_int); m_var_register.set_name(j, name); return j; } - unsigned lar_solver::external_to_column_index(unsigned ext_j) const { - unsigned j = external_to_local(ext_j); - if (j == null_lpvar) - return j; - - if (tv::is_term(j)) - return map_term_index_to_column_index(j); - - return j; - } - struct lar_solver::undo_add_column : public trail { lar_solver& s; undo_add_column(lar_solver& s) : s(s) {} void undo() override { + auto& col = s.m_columns.back(); + if (col.term() != nullptr) { + if (s.m_need_register_terms) + s.deregister_normalized_term(*col.term()); + delete col.term(); + s.m_terms.pop_back(); + } s.remove_last_column_from_tableau(); - s.m_columns_to_ul_pairs.pop_back(); - unsigned j = s.m_columns_to_ul_pairs.size(); + s.m_columns.pop_back(); + unsigned j = s.m_columns.size(); if (s.m_columns_with_changed_bounds.contains(j)) s.m_columns_with_changed_bounds.remove(j); if (s.m_incorrect_columns.contains(j)) @@ -1501,29 +1414,14 @@ namespace lp { } }; - struct lar_solver::undo_add_term : public trail { - lar_solver& s; - undo_add_term(lar_solver& s):s(s) {} - void undo() override { - auto* t = s.m_terms.back(); - if (s.m_need_register_terms) - s.deregister_normalized_term(*t); - delete t; - s.m_terms.pop_back(); - s.m_term_register.shrink(s.m_terms.size()); - } - }; - - var_index lar_solver::add_var(unsigned ext_j, bool is_int) { + lpvar lar_solver::add_var(unsigned ext_j, bool is_int) { TRACE("add_var", tout << "adding var " << ext_j << (is_int ? " int" : " nonint") << std::endl;); - var_index local_j; - SASSERT(!m_term_register.external_is_used(ext_j)); - lp_assert(!tv::is_term(ext_j)); + lpvar local_j; if (m_var_register.external_is_used(ext_j, local_j)) return local_j; - lp_assert(m_columns_to_ul_pairs.size() == A_r().column_count()); + lp_assert(m_columns.size() == A_r().column_count()); local_j = A_r().column_count(); - m_columns_to_ul_pairs.push_back(ul_pair(false)); // not associated with a row + m_columns.push_back(column(false, nullptr)); // false - not associated with a row, nullptr for term m_trail.push(undo_add_column(*this)); while (m_usage_in_terms.size() <= ext_j) m_usage_in_terms.push_back(0); @@ -1536,17 +1434,17 @@ namespace lp { return m_var_register.has_int_var(); } - void lar_solver::register_new_ext_var_index(unsigned ext_v, bool is_int) { + void lar_solver::register_new_external_var(unsigned ext_v, bool is_int) { lp_assert(!m_var_register.external_is_used(ext_v)); m_var_register.add_var(ext_v, is_int); } bool lar_solver::external_is_used(unsigned v) const { - return m_var_register.external_is_used(v) || m_term_register.external_is_used(v); + return m_var_register.external_is_used(v); } void lar_solver::add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int) { - register_new_ext_var_index(ext_j, is_int); + register_new_external_var(ext_j, is_int); m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); add_new_var_to_core_fields_for_mpq(false); // false for not adding a row } @@ -1578,7 +1476,7 @@ namespace lp { } #if Z3DEBUG_CHECK_UNIQUE_TERMS - bool lar_solver::term_coeffs_are_ok(const vector>& coeffs) { + bool lar_solver::term_coeffs_are_ok(const vector>& coeffs) { for (const auto& p : coeffs) if (column_is_real(p.second)) @@ -1603,50 +1501,40 @@ namespace lp { } #endif - void lar_solver::push_term(lar_term* t) { - m_terms.push_back(t); - m_trail.push(undo_add_term(*this)); - } - + // terms - bool lar_solver::all_vars_are_registered(const vector>& coeffs) { + bool lar_solver::all_vars_are_registered(const vector>& coeffs) { return all_of(coeffs, [&](const auto& p) { return p.second < m_var_register.size(); }); } void lar_solver::subst_known_terms(lar_term* t) { std::set seen_terms; for (auto p : *t) { - auto j = p.column(); - if (this->column_corresponds_to_term(j)) + auto j = p.j(); + if (this->column_has_term(j)) seen_terms.insert(j); } while (!seen_terms.empty()) { unsigned j = *seen_terms.begin(); seen_terms.erase(j); - auto tj = this->m_var_register.local_to_external(j); - auto& ot = this->get_term(tj); + const lar_term& ot = this->get_term(j); for (auto p : ot) - if (this->column_corresponds_to_term(p.column())) - seen_terms.insert(p.column()); + if (this->column_has_term(p.j())) + seen_terms.insert(p.j()); t->subst_by_term(ot, j); } } - // do not register in m_var_register this term if ext_i == UINT_MAX - var_index lar_solver::add_term(const vector>& coeffs, unsigned ext_i) { - TRACE("lar_solver_terms", print_linear_combination_of_column_indices_only(coeffs, tout) << ", ext_i =" << ext_i << "\n";); + // if UINT_MAX == null_lpvar then the term does not correspond and external variable + lpvar lar_solver::add_term(const vector>& coeffs, unsigned ext_i) { + TRACE("lar_solver_terms", print_linear_combination_of_column_indices_only(coeffs, tout) << ", ext_i =" << ext_i << "\n";); SASSERT(!m_var_register.external_is_used(ext_i)); SASSERT(all_vars_are_registered(coeffs)); lar_term* t = new lar_term(coeffs); subst_known_terms(t); - m_term_register.add_var(ext_i, term_is_int(t)); - push_term(t); - if (strategy_is_undecided()) - return tv::mask_term(m_terms.size() - 1); - SASSERT(m_terms.size() == m_term_register.size()); - unsigned adjusted_term_index = m_terms.size() - 1; - var_index ret = tv::mask_term(adjusted_term_index); - if (!coeffs.empty()) - add_row_from_term_no_constraint(m_terms.back(), ret); + SASSERT(t->is_empty() == false); + m_terms.push_back(t); + lpvar ret = A_r().column_count(); + add_row_from_term_no_constraint(t, ext_i); lp_assert(m_var_register.size() == A_r().column_count()); if (m_need_register_terms) @@ -1654,26 +1542,15 @@ namespace lp { return ret; } - /** - * \brief ensure there is a column index corresponding to vi - * If vi is already a column, just return vi - * If vi is for a term, then create a row that uses the term. - */ - var_index lar_solver::ensure_column(var_index vi) { - if (lp::tv::is_term(vi)) - return to_column(vi); - else - return vi; - } - - - void lar_solver::add_row_from_term_no_constraint(const lar_term* term, unsigned term_ext_index) { + void lar_solver::add_row_from_term_no_constraint(lar_term* term, unsigned ext_index) { TRACE("dump_terms", print_term(*term, tout) << std::endl;); - register_new_ext_var_index(term_ext_index, term_is_int(term)); + register_new_external_var(ext_index, term_is_int(term)); // j will be a new variable unsigned j = A_r().column_count(); - ul_pair ul(true); // to mark this column as associated_with_row - m_columns_to_ul_pairs.push_back(ul); + SASSERT(ext_index == null_lpvar || external_to_local(ext_index) == j); + column ul(true, term); // true - to mark this column as associated_with_row + term->j() = j; // point from the term to the column + m_columns.push_back(ul); m_trail.push(undo_add_column(*this)); add_basic_var_to_core_fields(); @@ -1684,7 +1561,7 @@ namespace lp { m_mpq_lar_core_solver.m_r_solver.update_x(j, get_basic_var_value_from_row(A_r().row_count() - 1)); for (lar_term::ival c : *term) { - unsigned j = c.column(); + unsigned j = c.j(); while (m_usage_in_terms.size() <= j) m_usage_in_terms.push_back(0); m_usage_in_terms[j] = m_usage_in_terms[j] + 1; @@ -1700,13 +1577,13 @@ namespace lp { return !column_is_int(j) || right_side.is_int(); } - constraint_index lar_solver::add_var_bound_check_on_equal(var_index j, lconstraint_kind kind, const mpq& right_side, var_index& equal_var) { + constraint_index lar_solver::add_var_bound_check_on_equal(lpvar j, lconstraint_kind kind, const mpq& right_side, lpvar& equal_var) { constraint_index ci = mk_var_bound(j, kind, right_side); activate_check_on_equal(ci, equal_var); return ci; } - constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, const mpq& right_side) { + constraint_index lar_solver::add_var_bound(lpvar j, lconstraint_kind kind, const mpq& right_side) { constraint_index ci = mk_var_bound(j, kind, right_side); activate(ci); return ci; @@ -1756,7 +1633,7 @@ namespace lp { // SASSERT(column_is_fixed(k)); if (j != k && column_is_fixed(k)) { SASSERT(column_is_int(j) == column_is_int(k)); - equal_to_j = column_to_reported_index(k); + equal_to_j = k; TRACE("lar_solver", tout << "found equal column k = " << k << ", external = " << equal_to_j << "\n";); } @@ -1796,10 +1673,10 @@ namespace lp { } - constraint_index lar_solver::mk_var_bound(var_index j, lconstraint_kind kind, const mpq& right_side) { + constraint_index lar_solver::mk_var_bound(lpvar j, lconstraint_kind kind, const mpq& right_side) { TRACE("lar_solver", tout << "j = " << get_variable_name(j) << " " << lconstraint_kind_string(kind) << " " << right_side << std::endl;); constraint_index ci; - if (!tv::is_term(j)) { // j is a var + if (!column_has_term(j)) { mpq rs = adjust_bound_for_int(j, kind, right_side); lp_assert(bound_is_integer_for_integer_column(j, rs)); ci = m_constraints.add_var_constraint(j, kind, rs); @@ -1811,9 +1688,7 @@ namespace lp { return ci; } - bool lar_solver::compare_values(var_index j, lconstraint_kind k, const mpq& rhs) { - if (tv::is_term(j)) - j = to_column(j); + bool lar_solver::compare_values(lpvar j, lconstraint_kind k, const mpq& rhs) { return compare_values(get_column_value(j), k, rhs); } @@ -1897,7 +1772,7 @@ namespace lp { void lar_solver::add_constraint_to_validate(lar_solver& ls, constraint_index ci) { auto const& c = m_constraints[ci]; TRACE("lar_solver_validate", tout << "adding constr with column = "<< c.column() << "\n"; m_constraints.display(tout, c); tout << std::endl;); - vector> coeffs; + vector> coeffs; for (auto p : c.coeffs()) { lpvar jext = p.second; lpvar j = ls.external_to_local(jext); @@ -1910,7 +1785,7 @@ namespace lp { lpvar column_ext = c.column(); unsigned j = ls.external_to_local(column_ext); - var_index tv; + lpvar tv; if (j == UINT_MAX) { tv = ls.add_term(coeffs, column_ext); } @@ -1959,37 +1834,10 @@ namespace lp { } } - constraint_index lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq& right_side) { - lp_assert(tv::is_term(j)); - unsigned adjusted_term_index = tv::unmask_term(j); - // lp_assert(!term_is_int(m_terms[adjusted_term_index]) || right_side.is_int()); - unsigned term_j; - lar_term const* term = m_terms[adjusted_term_index]; - if (m_var_register.external_is_used(j, term_j)) { - mpq rs = adjust_bound_for_int(term_j, kind, right_side); - lp_assert(bound_is_integer_for_integer_column(term_j, rs)); - return m_constraints.add_term_constraint(term_j, term, kind, rs); - } - else { - return add_constraint_from_term_and_create_new_column_row(j, term, kind, right_side); - } - } - - constraint_index lar_solver::add_constraint_from_term_and_create_new_column_row( - unsigned term_j, const lar_term* term, lconstraint_kind kind, const mpq& right_side) { - add_row_from_term_no_constraint(term, term_j); - unsigned j = A_r().column_count() - 1; + constraint_index lar_solver::add_var_bound_on_constraint_for_term(lpvar j, lconstraint_kind kind, const mpq& right_side) { mpq rs = adjust_bound_for_int(j, kind, right_side); - lp_assert(bound_is_integer_for_integer_column(j, rs)); - return m_constraints.add_term_constraint(j, term, kind, rs); - } - - void lar_solver::decide_on_strategy_and_adjust_initial_state() { - lp_assert(strategy_is_undecided()); - - m_settings.simplex_strategy() = simplex_strategy_enum::tableau_rows; - - adjust_initial_state(); + SASSERT(bound_is_integer_for_integer_column(j, rs)); + return m_constraints.add_term_constraint(j, m_columns[j].term(), kind, rs); } struct scoped_backup { @@ -2001,31 +1849,7 @@ namespace lp { m_s.restore_x(); } }; - - - void lar_solver::adjust_initial_state() { - switch (m_settings.simplex_strategy()) { - case simplex_strategy_enum::tableau_rows: - adjust_initial_state_for_tableau_rows(); - break; - case simplex_strategy_enum::tableau_costs: - UNREACHABLE(); // not implemented - case simplex_strategy_enum::undecided: - adjust_initial_state_for_tableau_rows(); - break; - } - } - - - void lar_solver::adjust_initial_state_for_tableau_rows() { - for (unsigned i = 0; i < m_terms.size(); i++) { - if (m_var_register.external_is_used(tv::mask_term(i))) - continue; - add_row_from_term_no_constraint(m_terms[i], tv::mask_term(i)); - } - } - - + void lar_solver::update_column_type_and_bound_with_ub(unsigned j, lp::lconstraint_kind kind, const mpq& right_side, u_dependency* dep) { SASSERT(column_has_upper_bound(j)); if (column_has_lower_bound(j)) { @@ -2046,7 +1870,7 @@ namespace lp { } } - void lar_solver::update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep) { + void lar_solver::update_bound_with_ub_lb(lpvar j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep) { lp_assert(column_has_lower_bound(j) && column_has_upper_bound(j)); lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::boxed || m_mpq_lar_core_solver.m_column_types[j] == column_type::fixed); @@ -2111,7 +1935,7 @@ namespace lp { } } - void lar_solver::update_bound_with_no_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep) { + void lar_solver::update_bound_with_no_ub_lb(lpvar j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep) { lp_assert(column_has_lower_bound(j) && !column_has_upper_bound(j)); lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::lower_bound); @@ -2164,7 +1988,7 @@ namespace lp { } } - void lar_solver::update_bound_with_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep) { + void lar_solver::update_bound_with_ub_no_lb(lpvar j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep) { lp_assert(!column_has_lower_bound(j) && column_has_upper_bound(j)); lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::upper_bound); mpq y_of_bound(0); @@ -2217,7 +2041,7 @@ namespace lp { } } - void lar_solver::update_bound_with_no_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep) { + void lar_solver::update_bound_with_no_ub_no_lb(lpvar j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep) { lp_assert(!column_has_lower_bound(j) && !column_has_upper_bound(j)); mpq y_of_bound(0); @@ -2252,22 +2076,14 @@ namespace lp { UNREACHABLE(); } insert_to_columns_with_changed_bounds(j); - } - - bool lar_solver::column_corresponds_to_term(unsigned j) const { - return tv::is_term(m_var_register.local_to_external(j)); - } + } - var_index lar_solver::to_column(unsigned ext_j) const { + lpvar lar_solver::to_column(unsigned ext_j) const { return m_var_register.external_to_local(ext_j); } - bool lar_solver::tighten_term_bounds_by_delta(tv const& t, const impq& delta) { - SASSERT(t.is_term()); - unsigned tj = t.index(); - unsigned j; - if (!m_var_register.external_is_used(tj, j)) - return true; // the term is not a column so it has no bounds + bool lar_solver::tighten_term_bounds_by_delta(lpvar j, const impq& delta) { + SASSERT(column_has_term(j)); auto& slv = m_mpq_lar_core_solver.m_r_solver; TRACE("cube", tout << "delta = " << delta << std::endl; m_int_solver->display_column(tout, j); ); @@ -2280,15 +2096,15 @@ namespace lp { TRACE("cube", tout << "can tighten";); if (slv.column_has_upper_bound(j)) { if (!is_zero(delta.y) || !is_zero(slv.m_upper_bounds[j].y)) - add_var_bound(tj, lconstraint_kind::LT, slv.m_upper_bounds[j].x - delta.x); + add_var_bound(j, lconstraint_kind::LT, slv.m_upper_bounds[j].x - delta.x); else - add_var_bound(tj, lconstraint_kind::LE, slv.m_upper_bounds[j].x - delta.x); + add_var_bound(j, lconstraint_kind::LE, slv.m_upper_bounds[j].x - delta.x); } if (slv.column_has_lower_bound(j)) { if (!is_zero(delta.y) || !is_zero(slv.m_lower_bounds[j].y)) - add_var_bound(tj, lconstraint_kind::GT, slv.m_lower_bounds[j].x + delta.x); + add_var_bound(j, lconstraint_kind::GT, slv.m_lower_bounds[j].x + delta.x); else - add_var_bound(tj, lconstraint_kind::GE, slv.m_lower_bounds[j].x + delta.x); + add_var_bound(j, lconstraint_kind::GE, slv.m_lower_bounds[j].x + delta.x); } return true; } @@ -2297,7 +2113,7 @@ namespace lp { void lar_solver::round_to_integer_solution() { for (unsigned j = 0; j < column_count(); j++) { if (!column_is_int(j)) continue; - if (column_corresponds_to_term(j)) continue; + if (column_has_term(j)) continue; impq& v = m_mpq_lar_core_solver.m_r_x[j]; if (v.is_int()) continue; @@ -2322,20 +2138,20 @@ namespace lp { void lar_solver::fix_terms_with_rounded_columns() { - for (unsigned i = 0; i < m_terms.size(); i++) { - if (!term_is_used_as_row(i)) + for (const lar_term* t : m_terms) { + lpvar j = t->j(); + if (!m_columns[j].associated_with_row()) continue; bool need_to_fix = false; - const lar_term& t = *m_terms[i]; - for (lar_term::ival p : t) { - if (m_incorrect_columns.contains(p.column())) { + + for (lar_term::ival p : * t) { + if (m_incorrect_columns.contains(p.j())) { need_to_fix = true; break; } } if (need_to_fix) { - lpvar j = m_var_register.external_to_local(tv::mask_term(i)); - impq v = t.apply(m_mpq_lar_core_solver.m_r_x); + impq v = t->apply(m_mpq_lar_core_solver.m_r_x); m_mpq_lar_core_solver.m_r_solver.update_x(j, v); } } @@ -2347,7 +2163,7 @@ namespace lp { bool lar_solver::sum_first_coords(const lar_term& t, mpq& val) const { val = zero_of_type(); for (lar_term::ival c : t) { - const auto& x = m_mpq_lar_core_solver.m_r_x[c.column()]; + const auto& x = m_mpq_lar_core_solver.m_r_x[c.j()]; if (!is_zero(x.y)) return false; val += x.x * c.coeff(); @@ -2355,18 +2171,14 @@ namespace lp { return true; } - bool lar_solver::get_equality_and_right_side_for_term_on_current_x(tv const& t, mpq& rs, u_dependency*& ci, bool& upper_bound) const { - lp_assert(t.is_term()); - unsigned j; - bool is_int; - if (!m_var_register.external_is_used(t.index(), j, is_int)) - return false; // the term does not have a bound because it does not correspond to a column - if (!is_int) // todo - allow for the next version of hnf + bool lar_solver::get_equality_and_right_side_for_term_on_current_x(lpvar j, mpq& rs, u_dependency*& ci, bool& upper_bound) const { + lp_assert(column_has_term(j)); + if (!column_is_int(j)) // todo - allow for the next version of hnf return false; bool rs_is_calculated = false; mpq b; bool is_strict; - const lar_term& term = get_term(t); + const lar_term& term = get_term(j); if (has_upper_bound(j, ci, b, is_strict) && !is_strict) { lp_assert(b.is_int()); if (!sum_first_coords(term, rs)) @@ -2433,9 +2245,8 @@ namespace lp { void lar_solver::register_existing_terms() { if (!m_need_register_terms) { TRACE("nla_solver", tout << "registering " << m_terms.size() << " terms\n";); - for (unsigned k = 0; k < m_terms.size(); k++) { - lpvar j = m_var_register.external_to_local(tv::mask_term(k)); - register_normalized_term(*m_terms[k], j); + for (const lar_term* t : m_terms) { + register_normalized_term(*t, t->j()); } } m_need_register_terms = true; @@ -2455,44 +2266,19 @@ namespace lp { return false; } - lar_term lar_solver::unfold_nested_subterms(lar_term const& term) { - lar_term result; - vector> todo; - for (auto const & [j,c] : term.coeffs()) - todo.push_back({j, c}); - while (!todo.empty()) { - auto [j, c] = todo.back(); - todo.pop_back(); - auto tv = column2tv(j); - if (tv.is_term()) { - for (auto const& [j, c2] : get_term(tv).coeffs()) - todo.push_back({j, c*c2}); - } - else - result.add_monomial(c, j); - } - return result; - } - - std::pair lar_solver::add_equality(lpvar j, lpvar k) { - vector> coeffs; - if (tv::is_term(j)) - j = map_term_index_to_column_index(j); - - if (tv::is_term(k)) - k = map_term_index_to_column_index(k); - + vector> coeffs; + coeffs.push_back(std::make_pair(mpq(1), j)); coeffs.push_back(std::make_pair(mpq(-1), k)); - unsigned term_index = add_term(coeffs, UINT_MAX); // UINT_MAX is the external null var + unsigned ej = add_term(coeffs, UINT_MAX); // UINT_MAX is the external null var if (get_column_value(j) != get_column_value(k)) set_status(lp_status::UNKNOWN); return std::pair( - add_var_bound(term_index, lconstraint_kind::LE, mpq(0)), - add_var_bound(term_index, lconstraint_kind::GE, mpq(0))); + add_var_bound(ej, lconstraint_kind::LE, mpq(0)), + add_var_bound(ej, lconstraint_kind::GE, mpq(0))); } bool lar_solver::inside_bounds(lpvar j, const impq& val) const { @@ -2511,7 +2297,7 @@ namespace lp { SASSERT(m_crossed_bounds_deps == nullptr); set_status(lp_status::INFEASIBLE); m_crossed_bounds_column = j; - const auto& ul = this->m_columns_to_ul_pairs[j]; + const auto& ul = this->m_columns[j]; u_dependency* bdep = lower_bound? ul.lower_bound_witness() : ul.upper_bound_witness(); SASSERT(bdep != nullptr); m_crossed_bounds_deps = m_dependencies.mk_join(bdep, dep); diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index b1abb21f7..4d71d0181 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -59,7 +59,7 @@ class lar_solver : public column_namer { size_t seed = 0; int i = 0; for (const auto p : t) { - hash_combine(seed, (unsigned)p.column()); + hash_combine(seed, (unsigned)p.j()); hash_combine(seed, p.coeff()); if (i++ > 10) break; @@ -86,8 +86,7 @@ class lar_solver : public column_namer { int_solver* m_int_solver = nullptr; bool m_need_register_terms = false; var_register m_var_register; - var_register m_term_register; - svector m_columns_to_ul_pairs; + svector m_columns; constraint_set m_constraints; // the set of column indices j such that bounds have changed for j indexed_uint_set m_columns_with_changed_bounds; @@ -119,16 +118,13 @@ class lar_solver : public column_namer { ////////////////// nested structs ///////////////////////// struct undo_add_column; - struct undo_add_term; ////////////////// methods //////////////////////////////// static bool valid_index(unsigned j) { return static_cast(j) >= 0; } - const lar_term& get_term(unsigned j) const; bool row_has_a_big_num(unsigned i) const; // init region - bool strategy_is_undecided() const; - void register_new_ext_var_index(unsigned ext_v, bool is_int); + void register_new_external_var(unsigned ext_v, bool is_int); bool term_is_int(const lar_term* t) const; bool term_is_int(const vector>& coeffs) const; void add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int); @@ -136,10 +132,9 @@ class lar_solver : public column_namer { mpq adjust_bound_for_int(lpvar j, lconstraint_kind&, const mpq&); // terms - bool all_vars_are_registered(const vector>& coeffs); - bool term_coeffs_are_ok(const vector>& coeffs); - void push_term(lar_term* t); - void add_row_from_term_no_constraint(const lar_term* term, unsigned term_ext_index); + bool all_vars_are_registered(const vector>& coeffs); + bool term_coeffs_are_ok(const vector>& coeffs); + void add_row_from_term_no_constraint(lar_term* term, unsigned term_ext_index); void add_basic_var_to_core_fields(); bool compare_values(impq const& lhs, lconstraint_kind k, const mpq& rhs); @@ -168,27 +163,20 @@ class lar_solver : public column_namer { void update_column_type_and_bound(unsigned j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); private: void require_nbasis_sort() { m_mpq_lar_core_solver.m_r_solver.m_nbasis_sort_counter = 0; } - void update_column_type_and_bound_with_ub(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); - void update_column_type_and_bound_with_no_ub(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); - void update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); - void update_bound_with_no_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); - void update_bound_with_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); - void update_bound_with_no_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); + void update_column_type_and_bound_with_ub(lpvar j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); + void update_column_type_and_bound_with_no_ub(lpvar j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); + void update_bound_with_ub_lb(lpvar j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); + void update_bound_with_no_ub_lb(lpvar j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); + void update_bound_with_ub_no_lb(lpvar j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); + void update_bound_with_no_ub_no_lb(lpvar j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); void register_in_fixed_var_table(unsigned, unsigned&); void remove_non_fixed_from_fixed_var_table(); - constraint_index add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq& right_side); + constraint_index add_var_bound_on_constraint_for_term(lpvar j, lconstraint_kind kind, const mpq& right_side); void set_crossed_bounds_column_and_deps(unsigned j, bool lower_bound, u_dependency* dep); - constraint_index add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, - lconstraint_kind kind, const mpq& right_side); unsigned row_of_basic_column(unsigned) const; - void decide_on_strategy_and_adjust_initial_state(); - void adjust_initial_state(); - void adjust_initial_state_for_tableau_rows(); bool sizes_are_correct() const; bool implied_bound_is_correctly_explained(implied_bound const& be, const vector>& explanation) const; - void substitute_basis_var_in_terms_for_row(unsigned i); - template unsigned calculate_implied_bounds_for_row(unsigned row_index, lp_bound_propagator& bp) { if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation || row_has_a_big_num(row_index)) @@ -214,10 +202,10 @@ class lar_solver : public column_namer { void pop_core_solver_params(); void pop_core_solver_params(unsigned k); - void set_upper_bound_witness(var_index j, u_dependency* ci); - void set_lower_bound_witness(var_index j, u_dependency* ci); - void substitute_terms_in_linear_expression(const vector>& left_side_with_terms, - vector>& left_side) const; + void set_upper_bound_witness(lpvar j, u_dependency* ci); + void set_lower_bound_witness(lpvar j, u_dependency* ci); + void substitute_terms_in_linear_expression(const vector>& left_side_with_terms, + vector>& left_side) const; bool use_tableau_costs() const; bool tableau_with_costs() const; @@ -231,11 +219,11 @@ class lar_solver : public column_namer { void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); void solve_with_core_solver(); numeric_pair get_basic_var_value_from_row(unsigned i); - bool all_constrained_variables_are_registered(const vector>& left_side); + bool all_constrained_variables_are_registered(const vector>& left_side); bool all_constraints_hold() const; - bool constraint_holds(const lar_base_constraint& constr, std::unordered_map& var_map) const; - static void register_in_map(std::unordered_map& coeffs, const lar_base_constraint& cn, const mpq& a); - static void register_monoid_in_map(std::unordered_map& coeffs, const mpq& a, unsigned j); + bool constraint_holds(const lar_base_constraint& constr, std::unordered_map& var_map) const; + static void register_in_map(std::unordered_map& coeffs, const lar_base_constraint& cn, const mpq& a); + static void register_monoid_in_map(std::unordered_map& coeffs, const mpq& a, unsigned j); bool the_left_sides_sum_to_zero(const vector>& evidence) const; bool explanation_is_correct(explanation&) const; bool inf_explanation_is_correct() const; @@ -244,8 +232,8 @@ class lar_solver : public column_namer { explanation& exp, const vector>& inf_row, int inf_sign) const; - mpq get_left_side_val(const lar_base_constraint& cns, const std::unordered_map& var_map) const; - void fill_var_set_for_random_update(unsigned sz, var_index const* vars, vector& column_list); + mpq get_left_side_val(const lar_base_constraint& cns, const std::unordered_map& var_map) const; + void fill_var_set_for_random_update(unsigned sz, lpvar const* vars, vector& column_list); bool column_represents_row_in_tableau(unsigned j); void make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j); void remove_last_row_and_column_from_tableau(unsigned j); @@ -259,7 +247,7 @@ class lar_solver : public column_namer { bool bound_is_integer_for_integer_column(unsigned j, const mpq& right_side) const; inline lar_core_solver& get_core_solver() { return m_mpq_lar_core_solver; } - var_index to_column(unsigned ext_j) const; + lpvar to_column(unsigned ext_j) const; void fix_terms_with_rounded_columns(); bool remove_from_basis(unsigned); lar_term get_term_to_maximize(unsigned ext_j) const; @@ -299,8 +287,6 @@ public: template void remove_non_fixed_from_table(T&); - unsigned external_to_column_index(unsigned) const; - bool inside_bounds(lpvar, const impq&) const; inline void set_column_value(unsigned j, const impq& v) { @@ -311,7 +297,7 @@ public: set_column_value(j, v); } - var_index add_named_var(unsigned ext_j, bool is_integer, const std::string&); + lpvar add_named_var(unsigned ext_j, bool is_integer, const std::string&); lp_status maximize_term(unsigned j_or_term, impq& term_max); @@ -348,7 +334,7 @@ public: mpq const& a = r.coeff(); int a_sign = is_pos(a) ? 1 : -1; int sign = j_sign * a_sign; - const ul_pair& ul = m_columns_to_ul_pairs[j]; + const column& ul = m_columns[j]; auto* witness = sign > 0 ? ul.upper_bound_witness() : ul.lower_bound_witness(); lp_assert(witness); for (auto ci : flatten(witness)) @@ -367,10 +353,10 @@ public: #ifdef Z3DEBUG bool fixed_base_removed_correctly() const; #endif - constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq& right_side); - void activate_check_on_equal(constraint_index, var_index&); + constraint_index mk_var_bound(lpvar j, lconstraint_kind kind, const mpq& right_side); + void activate_check_on_equal(constraint_index, lpvar&); void activate(constraint_index); - void random_update(unsigned sz, var_index const* vars); + void random_update(unsigned sz, lpvar const* vars); void add_column_rows_to_touched_rows(lpvar j); template void propagate_bounds_for_touched_rows(lp_bound_propagator& bp) { @@ -404,34 +390,24 @@ public: } } - bool is_fixed(column_index const& j) const { return column_is_fixed(j); } - inline column_index to_column_index(unsigned v) const { return column_index(external_to_column_index(v)); } bool external_is_used(unsigned) const; void pop(unsigned k); unsigned num_scopes() const { return m_trail.get_num_scopes(); } - bool compare_values(var_index j, lconstraint_kind kind, const mpq& right_side); - var_index add_term(const vector>& coeffs, unsigned ext_i); + bool compare_values(lpvar j, lconstraint_kind kind, const mpq& right_side); + lpvar add_term(const vector>& coeffs, unsigned ext_i); void register_existing_terms(); - var_index ensure_column(var_index vi); - constraint_index add_var_bound(var_index, lconstraint_kind, const mpq&); - constraint_index add_var_bound_check_on_equal(var_index, lconstraint_kind, const mpq&, var_index&); + constraint_index add_var_bound(lpvar, lconstraint_kind, const mpq&); + constraint_index add_var_bound_check_on_equal(lpvar, lconstraint_kind, const mpq&, lpvar&); - var_index add_var(unsigned ext_j, bool is_integer); + lpvar add_var(unsigned ext_j, bool is_integer); void set_cut_strategy(unsigned cut_frequency); inline unsigned column_count() const { return A_r().column_count(); } - inline var_index local_to_external(var_index idx) const { - return tv::is_term(idx) ? m_term_register.local_to_external(idx) : m_var_register.local_to_external(idx); + inline lpvar local_to_external(lpvar idx) const { + return m_var_register.local_to_external(idx); } - bool column_corresponds_to_term(unsigned) const; - const lar_term& column_to_term(unsigned j) const { - SASSERT(column_corresponds_to_term(j)); - return get_term(column2tv(to_column_index(j))); - } - - lar_term unfold_nested_subterms(lar_term const& term); - + inline bool column_associated_with_row(lpvar j) const { return m_columns[j].associated_with_row(); } inline unsigned row_count() const { return A_r().row_count(); } - bool var_is_registered(var_index vj) const; + bool var_is_registered(lpvar vj) const; void clear_inf_heap() { m_mpq_lar_core_solver.m_r_solver.inf_heap().clear(); } @@ -518,33 +494,28 @@ public: u_dependency_manager& dep_manager() { return m_dependencies; } inline u_dependency* get_column_upper_bound_witness(unsigned j) const { - if (tv::is_term(j)) { - j = m_var_register.external_to_local(j); - } - return m_columns_to_ul_pairs[j].upper_bound_witness(); + return m_columns[j].upper_bound_witness(); } - inline const impq& get_upper_bound(column_index j) const { + inline const impq& get_upper_bound(lpvar j) const { return m_mpq_lar_core_solver.m_r_solver.m_upper_bounds[j]; } - inline const impq& get_lower_bound(column_index j) const { + inline const impq& get_lower_bound(lpvar j) const { return m_mpq_lar_core_solver.m_r_solver.m_lower_bounds[j]; } - inline mpq bound_span_x(column_index j) const { + inline mpq bound_span_x(lpvar j) const { return m_mpq_lar_core_solver.m_r_solver.m_upper_bounds[j].x - m_mpq_lar_core_solver.m_r_solver.m_lower_bounds[j].x; } - bool has_lower_bound(var_index var, u_dependency*& ci, mpq& value, bool& is_strict) const; - bool has_upper_bound(var_index var, u_dependency*& ci, mpq& value, bool& is_strict) const; - bool has_value(var_index var, mpq& value) const; + bool has_lower_bound(lpvar var, u_dependency*& ci, mpq& value, bool& is_strict) const; + bool has_upper_bound(lpvar var, u_dependency*& ci, mpq& value, bool& is_strict) const; + bool has_value(lpvar var, mpq& value) const; bool fetch_normalized_term_column(const lar_term& t, std::pair&) const; - unsigned map_term_index_to_column_index(unsigned j) const; bool column_is_fixed(unsigned j) const; bool column_is_free(unsigned j) const; bool column_is_feasible(unsigned j) const { return m_mpq_lar_core_solver.m_r_solver.column_is_feasible(j);} - unsigned column_to_reported_index(unsigned j) const; lp_settings& settings(); lp_settings const& settings() const; statistics& stats(); @@ -552,8 +523,6 @@ public: void updt_params(params_ref const& p); column_type get_column_type(unsigned j) const { return m_mpq_lar_core_solver.m_column_types()[j]; } const vector& get_column_types() const { return m_mpq_lar_core_solver.m_column_types(); } - const impq& get_lower_bound(unsigned j) const { return m_mpq_lar_core_solver.m_r_lower_bounds()[j]; } - const impq& get_upper_bound(unsigned j) const { return m_mpq_lar_core_solver.m_r_upper_bounds()[j]; } std::ostream& print_terms(std::ostream& out) const; std::ostream& print_term(lar_term const& term, std::ostream& out) const; static std::ostream& print_term_as_indices(lar_term const& term, std::ostream& out); @@ -566,14 +535,12 @@ public: } bool init_model() const; mpq from_model_in_impq_to_mpq(const impq& v) const { return v.x + m_delta * v.y; } - mpq get_value(column_index const& j) const; - mpq get_tv_value(tv const& t) const; - const impq& get_tv_ivalue(tv const& t) const; - void get_model(std::unordered_map& variable_values) const; + mpq get_value(lpvar j) const; + void get_model(std::unordered_map& variable_values) const; void get_rid_of_inf_eps(); - void get_model_do_not_care_about_diff_vars(std::unordered_map& variable_values) const; - std::string get_variable_name(var_index vi) const override; - void set_variable_name(var_index vi, std::string); + void get_model_do_not_care_about_diff_vars(std::unordered_map& variable_values) const; + std::string get_variable_name(lpvar vi) const override; + void set_variable_name(lpvar vi, std::string); inline unsigned number_of_vars() const { return m_var_register.size(); } inline bool is_base(unsigned j) const { return m_mpq_lar_core_solver.m_r_heading[j] >= 0; } inline const impq& column_lower_bound(unsigned j) const { @@ -595,7 +562,7 @@ public: std::pair add_equality(lpvar j, lpvar k); u_dependency* get_bound_constraint_witnesses_for_column(unsigned j) { - const ul_pair& ul = m_columns_to_ul_pairs[j]; + const column& ul = m_columns[j]; return m_dependencies.mk_join(ul.lower_bound_witness(), ul.upper_bound_witness()); } template @@ -613,22 +580,15 @@ public: void pop(); inline u_dependency* get_column_lower_bound_witness(unsigned j) const { - if (tv::is_term(j)) { - j = m_var_register.external_to_local(j); - } - return m_columns_to_ul_pairs[j].lower_bound_witness(); + return m_columns[j].lower_bound_witness(); } - - inline tv column2tv(column_index const& c) const { - return tv::raw(column_to_reported_index(c)); - } - + inline bool column_has_term(lpvar j) const { return m_columns[j].term() != nullptr; } inline std::ostream& print_column_info(unsigned j, std::ostream& out) const { m_mpq_lar_core_solver.m_r_solver.print_column_info(j, out); - if (tv::is_term(j)) { + if (column_has_term(j)) { print_term_as_indices(get_term(j), out) << "\n"; - } else if (column_corresponds_to_term(j)) { + } else if (column_has_term(j)) { const lar_term& t = get_term(m_var_register.local_to_external(j)); print_term_as_indices(t, out) << "\n"; } @@ -651,13 +611,12 @@ public: return false; } inline const vector& terms() const { return m_terms; } - inline lar_term const& term(unsigned i) const { return *m_terms[i]; } + inline void set_int_solver(int_solver* int_slv) { m_int_solver = int_slv; } inline int_solver* get_int_solver() { return m_int_solver; } inline const int_solver* get_int_solver() const { return m_int_solver; } - inline const lar_term& get_term(tv const& t) const { - lp_assert(t.is_term()); - return *m_terms[t.id()]; + inline const lar_term& get_term(lpvar j) const { + return *m_columns[j].term(); } lp_status find_feasible_solution(); void move_non_basic_columns_to_bounds(); @@ -675,8 +634,8 @@ public: inline const column_strip& get_column(unsigned i) const { return A_r().m_columns[i]; } bool row_is_correct(unsigned i) const; bool ax_is_correct() const; - bool get_equality_and_right_side_for_term_on_current_x(tv const& t, mpq& rs, u_dependency*& ci, bool& upper_bound) const; - bool var_is_int(var_index v) const; + bool get_equality_and_right_side_for_term_on_current_x(lpvar j, mpq& rs, u_dependency*& ci, bool& upper_bound) const; + bool var_is_int(lpvar v) const; inline const vector& r_heading() const { return m_mpq_lar_core_solver.m_r_heading; } inline const vector& r_basis() const { return m_mpq_lar_core_solver.r_basis(); } inline const vector& r_nbasis() const { return m_mpq_lar_core_solver.r_nbasis(); } @@ -687,7 +646,7 @@ public: lp_status solve(); void fill_explanation_from_crossed_bounds_column(explanation& evidence) const; bool term_is_used_as_row(unsigned term) const; - bool tighten_term_bounds_by_delta(tv const& t, const impq&); + bool tighten_term_bounds_by_delta(lpvar j, const impq&); lar_solver(); void track_touched_rows(bool v); bool touched_rows_are_tracked() const; @@ -698,18 +657,16 @@ public: inline static_matrix& A_r() { return m_mpq_lar_core_solver.m_r_A; } inline const static_matrix& A_r() const { return m_mpq_lar_core_solver.m_r_A; } // columns - bool column_is_int(column_index const& j) const { return column_is_int((unsigned)j); } - const impq& get_column_value(column_index const& j) const { return m_mpq_lar_core_solver.m_r_x[j]; } - inline var_index external_to_local(unsigned j) const { - var_index local_j; - if (m_var_register.external_is_used(j, local_j) || - m_term_register.external_is_used(j, local_j)) { + const impq& get_column_value(lpvar j) const { return m_mpq_lar_core_solver.m_r_x[j]; } + inline lpvar external_to_local(unsigned j) const { + lpvar local_j; + if (m_var_register.external_is_used(j, local_j)) { return local_j; } else { return -1; } } - unsigned usage_in_terms(column_index j) const { + unsigned usage_in_terms(lpvar j) const { if (j >= m_usage_in_terms.size()) return 0; return m_usage_in_terms[j]; diff --git a/src/math/lp/lar_term.h b/src/math/lp/lar_term.h index a96d3ad5a..6547377d3 100644 --- a/src/math/lp/lar_term.h +++ b/src/math/lp/lar_term.h @@ -26,8 +26,12 @@ namespace lp { class lar_term { typedef unsigned lpvar; u_map m_coeffs; + // the column index related to the term + lpvar m_j = -1; public: - lar_term() {} + // the column index related to the term + lpvar j() const { return m_j; } + lpvar& j() { return m_j; } void add_monomial(const mpq& c, unsigned j) { if (c.is_zero()) return; @@ -62,10 +66,11 @@ public: mpq a = it->get_data().m_value; this->m_coeffs.erase(term_column); for (auto p : t) { - this->add_monomial(a * p.coeff(), p.column()); + this->add_monomial(a * p.coeff(), p.j()); } } - + // constructors + lar_term() {} lar_term(const vector>& coeffs) { for (auto const& p : coeffs) { add_monomial(p.first, p.second); @@ -150,11 +155,11 @@ public: } class ival { - unsigned m_var; + lpvar m_var; const mpq & m_coeff; public: - ival(unsigned var, const mpq & val) : m_var(var), m_coeff(val) { } - column_index column() const { return column_index(m_var); } + ival(lpvar var, const mpq & val) : m_var(var), m_coeff(val) { } + lpvar j() const { return m_var; } const mpq & coeff() const { return m_coeff; } }; @@ -173,13 +178,13 @@ public: lpvar min_var = -1; mpq c; for (ival p : *this) { - if (p.column() < min_var) { - min_var = p.column(); + if (p.j() < min_var) { + min_var = p.j(); } } lar_term r; for (ival p : *this) { - if (p.column() == min_var) { + if (p.j() == min_var) { return p.coeff().is_one(); } } diff --git a/src/math/lp/lp_api.h b/src/math/lp/lp_api.h index 021501ecd..325bc980b 100644 --- a/src/math/lp/lp_api.h +++ b/src/math/lp/lp_api.h @@ -31,7 +31,7 @@ namespace lp_api { class bound { Literal m_bv; theory_var m_var; - lp::lpvar m_vi; + lp::lpvar m_column_index; bool m_is_int; rational m_value; bound_kind m_bound_kind; @@ -41,7 +41,7 @@ namespace lp_api { bound(Literal bv, theory_var v, lp::lpvar vi, bool is_int, rational const& val, bound_kind k, lp::constraint_index ct, lp::constraint_index cf) : m_bv(bv), m_var(v), - m_vi(vi), + m_column_index(vi), m_is_int(is_int), m_value(val), m_bound_kind(k) { @@ -53,7 +53,7 @@ namespace lp_api { theory_var get_var() const { return m_var; } - lp::tv tv() const { return lp::tv::raw(m_vi); } + lp::lpvar column_index() const { return m_column_index; } Literal get_lit() const { return m_bv; } diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index c6fa5796d..daeac3b18 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -147,8 +147,6 @@ public: void add_bound(mpq const& v, unsigned j, bool is_low, bool strict, std::function explain_bound) { - j = lp().column_to_reported_index(j); - lconstraint_kind kind = is_low ? GE : LE; if (strict) kind = static_cast(kind / 2); @@ -222,14 +220,11 @@ public: return out; } - bool add_eq_on_columns(const explanation& exp, lpvar j, lpvar k, bool is_fixed) { - lp_assert(j != k && is_int(j) == is_int(k)); - lp_assert(ival(j) == ival(k)); + bool add_eq_on_columns(const explanation& exp, lpvar je, lpvar ke, bool is_fixed) { + lp_assert(je != ke && is_int(je) == is_int(ke)); + lp_assert(ival(je) == ival(ke)); - unsigned je = lp().column_to_reported_index(j); - unsigned ke = lp().column_to_reported_index(k); TRACE("eq", - tout << "reporting eq " << j << ", " << k << "\n"; tout << "reported idx " << je << ", " << ke << "\n"; print_expl(tout, exp); tout << "theory_vars v" << lp().local_to_external(je) << " == v" << lp().local_to_external(ke) << "\n";); @@ -246,12 +241,12 @@ public: // column to theory_var unsigned col_to_imp(unsigned j) const { - return lp().local_to_external(lp().column_to_reported_index(j)); + return lp().local_to_external(j); } // theory_var to column unsigned imp_to_col(unsigned j) const { - return lp().external_to_column_index(j); + return lp().external_to_local(j); } bool is_int(lpvar j) const { @@ -261,7 +256,7 @@ public: void explain_fixed_in_row(unsigned row, explanation& ex) { TRACE("eq", tout << lp().get_row(row) << std::endl); for (const auto& c : lp().get_row(row)) - if (lp().is_fixed(c.var())) + if (lp().column_is_fixed(c.var())) explain_fixed_column(c.var(), ex); } @@ -269,7 +264,7 @@ public: unsigned base = UINT_MAX; TRACE("eq", tout << lp().get_row(row) << std::endl); for (const auto& c : lp().get_row(row)) { - if (lp().is_fixed(c.var())) { + if (lp().column_is_fixed(c.var())) { explain_fixed_column(c.var(), ex); } else if (lp().is_base(c.var())) { @@ -288,7 +283,7 @@ public: #ifdef Z3DEBUG bool all_fixed_in_row(unsigned row) const { for (const auto& c : lp().get_row(row)) - if (!lp().is_fixed(c.var())) + if (!lp().column_is_fixed(c.var())) return false; return true; } diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index a0cb485b5..08fd36505 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -53,9 +53,8 @@ inline std::ostream& operator<<(std::ostream& out, column_type const& t) { } enum class simplex_strategy_enum { - undecided = 3, - tableau_rows = 0, - tableau_costs = 1 + tableau_rows, + tableau_costs }; std::string column_type_to_string(column_type t); diff --git a/src/math/lp/lp_types.h b/src/math/lp/lp_types.h index f770fe956..5883495fa 100644 --- a/src/math/lp/lp_types.h +++ b/src/math/lp/lp_types.h @@ -30,72 +30,12 @@ namespace nla { namespace lp { -typedef unsigned var_index; typedef unsigned constraint_index; typedef unsigned row_index; enum lconstraint_kind { LE = -2, LT = -1 , GE = 2, GT = 1, EQ = 0, NE = 3 }; typedef unsigned lpvar; const lpvar null_lpvar = UINT_MAX; const constraint_index null_ci = UINT_MAX; - - -class column_index { - unsigned m_index; - friend class lar_solver; - friend class lar_term; - friend nla::core; - - operator unsigned() const { return m_index; } - -public: - column_index(unsigned j): m_index(j) {} - unsigned index() const { return m_index; } - bool is_null() const { return m_index == null_lpvar; } -}; - - -// index that comes from term or variable. -class tv { - unsigned m_index; - static const unsigned EF = UINT_MAX >> 1; - tv(unsigned i): m_index(i) {} -public: - static tv term(unsigned i) { SASSERT(0 == (i & left_most_bit)); return tv(mask_term(i)); } - static tv var(unsigned i) { SASSERT(0 == (i & left_most_bit)); return tv(i); } - static tv raw(unsigned i) { return tv(i); } - - // retrieve the identifier associated with tv - unsigned id() const { return unmask_term(m_index); } - column_index column() const { SASSERT(is_var()); return column_index(id()); } - - // retrieve the raw index. - unsigned index() const { return m_index; } - - bool is_term() const { return 0 != (m_index & left_most_bit); } - bool is_var() const { return 0 == (m_index & left_most_bit); } - - // utilities useful where tv isn't already encapsulating id's. - static inline unsigned unmask_term(unsigned j) { return j & EF; } - static inline bool is_term(unsigned j) { return j & left_most_bit; } - static inline unsigned mask_term(unsigned j) { return j | left_most_bit; } - - // used by var_register. could we encapsulate even this? - static const unsigned left_most_bit = ~EF; - - std::string to_string() const { - std::ostringstream strm; - strm << (is_term() ? "t" : "j") << id(); - return strm.str(); - } - - bool is_null() const { return m_index == UINT_MAX; } - -}; - - } -inline std::ostream& operator<<(std::ostream& out, lp::tv const& t) { - return out << (t.is_term() ? "t":"j") << t.id() << "\n"; -} diff --git a/src/math/lp/lp_utils.h b/src/math/lp/lp_utils.h index 3c1383cb3..d6943bf50 100644 --- a/src/math/lp/lp_utils.h +++ b/src/math/lp/lp_utils.h @@ -116,12 +116,9 @@ template std::ostream& print_linear_combination_of_column_indices_only(const vector> & coeffs, std::ostream & out) { return print_linear_combination_customized( coeffs, - [](unsigned j) {std::stringstream ss; - if (tv::is_term(j)) { - ss << "t" << tv::unmask_term(j); - } else { - ss << "j" << j; - } + [](unsigned j) { + std::stringstream ss; + ss << "j" << j; return ss.str();}, out); } diff --git a/src/math/lp/monic.h b/src/math/lp/monic.h index 19137cd31..b51134166 100644 --- a/src/math/lp/monic.h +++ b/src/math/lp/monic.h @@ -21,15 +21,15 @@ namespace nla { class mon_eq { // fields - lp::var_index m_v; - svector m_vs; + lp::lpvar m_v; + svector m_vs; public: // constructors - mon_eq(lp::var_index v, unsigned sz, lp::var_index const* vs): + mon_eq(lp::lpvar v, unsigned sz, lp::lpvar const* vs): m_v(v), m_vs(sz, vs) { std::sort(m_vs.begin(), m_vs.end()); } - mon_eq(lp::var_index v, const svector &vs): + mon_eq(lp::lpvar v, const svector &vs): m_v(v), m_vs(vs) { std::sort(m_vs.begin(), m_vs.end()); } @@ -37,7 +37,7 @@ public: unsigned var() const { return m_v; } unsigned size() const { return m_vs.size(); } - const svector& vars() const { return m_vs; } + const svector& vars() const { return m_vs; } bool empty() const { return m_vs.empty(); } bool is_sorted() const { for (unsigned i = 0; i + 1 < size(); i++) @@ -49,7 +49,7 @@ public: return std::binary_search(m_vs.begin(), m_vs.end(), j); } protected: - svector& vars1() { return m_vs; } + svector& vars1() { return m_vs; } }; // support the congruence diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 9c99fa8c3..f2a1b0287 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -376,7 +376,7 @@ namespace nla { // propagate fixed equality auto exp = get_explanation(dep); - c().add_fixed_equality(c().lra.column_to_reported_index(m.var()), rational(0), exp); + c().add_fixed_equality(m.var(), rational(0), exp); } void monomial_bounds::propagate_fixed(monic const& m, rational const& k) { @@ -386,22 +386,21 @@ namespace nla { // propagate fixed equality auto exp = get_explanation(dep); - c().add_fixed_equality(c().lra.column_to_reported_index(m.var()), k, exp); + c().add_fixed_equality(m.var(), k, exp); } void monomial_bounds::propagate_nonfixed(monic const& m, rational const& k, lpvar w) { vector> coeffs; coeffs.push_back({-k, w}); coeffs.push_back({rational::one(), m.var()}); - lp::lpvar term_index = c().lra.add_term(coeffs, UINT_MAX); + lp::lpvar j = c().lra.add_term(coeffs, UINT_MAX); auto* dep = explain_fixed(m, k); - term_index = c().lra.map_term_index_to_column_index(term_index); TRACE("nla_solver", tout << "propagate nonfixed " << m << " = " << k << " " << w << "\n";); - c().lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::EQ, mpq(0), dep); + c().lra.update_column_type_and_bound(j, lp::lconstraint_kind::EQ, mpq(0), dep); if (k == 1) { lp::explanation exp = get_explanation(dep); - c().add_equality(c().lra.column_to_reported_index(m.var()), c().lra.column_to_reported_index(w), exp); + c().add_equality(m.var(), w, exp); } } diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index e2db006fa..675bf5022 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -68,21 +68,10 @@ bool core::compare_holds(const rational& ls, llc cmp, const rational& rs) const rational core::value(const lp::lar_term& r) const { rational ret(0); for (lp::lar_term::ival t : r) - ret += t.coeff() * val(t.column()); + ret += t.coeff() * val(t.j()); return ret; } -lp::lar_term core::subs_terms_to_columns(const lp::lar_term& t) const { - lp::lar_term r; - for (lp::lar_term::ival p : t) { - lpvar j = p.column(); - if (lp::tv::is_term(j)) - j = lra.map_term_index_to_column_index(j); - r.add_monomial(p.coeff(), j); - } - return r; -} - bool core::ineq_holds(const ineq& n) const { return compare_holds(value(n.term()), n.cmp(), n.rs()); } @@ -139,10 +128,7 @@ bool core::canonize_sign(const factorization& f) const { void core::add_monic(lpvar v, unsigned sz, lpvar const* vs) { m_add_buffer.resize(sz); for (unsigned i = 0; i < sz; i++) { - lpvar j = vs[i]; - if (lp::tv::is_term(j)) - j = lra.map_term_index_to_column_index(j); - m_add_buffer[i] = j; + m_add_buffer[i] = vs[i]; } m_emons.add(v, m_add_buffer); m_monics_with_changed_bounds.insert(v); @@ -326,25 +312,25 @@ bool core::explain_coeff_lower_bound(const lp::lar_term::ival& p, rational& boun const rational& a = p.coeff(); SASSERT(!a.is_zero()); if (a.is_pos()) { - auto* dep = lra.get_column_lower_bound_witness(p.column()); + auto* dep = lra.get_column_lower_bound_witness(p.j()); if (!dep) return false; - bound = a * lra.get_lower_bound(p.column()).x; + bound = a * lra.get_lower_bound(p.j()).x; lra.push_explanation(dep, e); return true; } // a.is_neg() - auto* dep = lra.get_column_upper_bound_witness(p.column()); + auto* dep = lra.get_column_upper_bound_witness(p.j()); if (!dep) return false; - bound = a * lra.get_upper_bound(p.column()).x; + bound = a * lra.get_upper_bound(p.j()).x; lra.push_explanation(dep, e); return true; } bool core::explain_coeff_upper_bound(const lp::lar_term::ival& p, rational& bound, lp::explanation& e) const { const rational& a = p.coeff(); - lpvar j = p.column(); + lpvar j = p.j(); SASSERT(!a.is_zero()); if (a.is_neg()) { auto *dep = lra.get_column_lower_bound_witness(j); @@ -602,7 +588,7 @@ std::ostream & core::print_ineqs(const lemma& l, std::ostream & out) const { print_ineq(in, out); if (i + 1 < l.ineqs().size()) out << " or "; for (lp::lar_term::ival p: in.term()) - vars.insert(p.column()); + vars.insert(p.j()); } out << std::endl; for (lpvar j : vars) { @@ -701,13 +687,13 @@ unsigned core::random() { return lp_settings().random_next(); } void core::collect_equivs() { const lp::lar_solver& s = lra; - for (unsigned i = 0; i < s.terms().size(); i++) { - if (!s.term_is_used_as_row(i)) + for (const auto * t : s.terms()) { + if (!s.column_associated_with_row(t->j())) continue; - lpvar j = s.external_to_local(lp::tv::mask_term(i)); + lpvar j = t->j(); if (var_is_fixed_to_zero(j)) { - TRACE("nla_solver_mons", s.print_term_as_indices(*s.terms()[i], tout << "term = ") << "\n";); - add_equivalence_maybe(s.terms()[i], s.get_column_upper_bound_witness(j), s.get_column_lower_bound_witness(j)); + TRACE("nla_solver_mons", s.print_term_as_indices(*t, tout << "term = ") << "\n";); + add_equivalence_maybe(t, s.get_column_upper_bound_witness(j), s.get_column_lower_bound_witness(j)); } } m_emons.ensure_canonized(); @@ -732,9 +718,9 @@ bool core::is_octagon_term(const lp::lar_term& t, bool & sign, lpvar& i, lpvar & return false; } if (i == null_lpvar) - i = p.column(); + i = p.j(); else - j = p.column(); + j = p.j(); } SASSERT(j != null_lpvar); sign = (seen_minus && seen_plus)? false : true; @@ -871,7 +857,7 @@ std::unordered_set core::collect_vars(const lemma& l) const { for (const auto& i : l.ineqs()) { for (lp::lar_term::ival p : i.term()) { - insert_j(p.column()); + insert_j(p.j()); } } for (auto p : l.expl()) { @@ -1629,17 +1615,9 @@ lbool core::test_check() { } std::ostream& core::print_terms(std::ostream& out) const { - for (unsigned i = 0; i < lra.terms().size(); i++) { - unsigned ext = lp::tv::mask_term(i); - if (!lra.var_is_registered(ext)) { - out << "term is not registered\n"; - continue; - } - - const lp::lar_term & t = *lra.terms()[i]; - out << "term:"; print_term(t, out) << std::endl; - lpvar j = lra.external_to_local(ext); - print_var(j, out); + for (const auto * t: lra.terms()) { + out << "term:"; print_term(*t, out) << std::endl; + print_var(t->j(), out); } return out; } @@ -1673,12 +1651,12 @@ std::unordered_set core::get_vars_of_expr_with_opening_terms(const nex *e } for (unsigned i = 0; i < added.size(); ++i) { lpvar j = added[i]; - if (ls.column_corresponds_to_term(j)) { - const auto& t = lra.get_term(lp::tv::raw(ls.local_to_external(j))); + if (ls.column_has_term(j)) { + const auto& t = lra.get_term(j); for (auto p : t) { - if (ret.find(p.column()) == ret.end()) { - added.push_back(p.column()); - ret.insert(p.column()); + if (ret.find(p.j()) == ret.end()) { + added.push_back(p.j()); + ret.insert(p.j()); } } } @@ -1729,8 +1707,6 @@ void core::set_active_vars_weights(nex_creator& nc) { } bool core::influences_nl_var(lpvar j) const { - if (lp::tv::is_term(j)) - j = lp::tv::unmask_term(j); if (is_nl_var(j)) return true; for (const auto & c : lra.A_r().m_columns[j]) { diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 253306bcd..eb1f8b436 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -135,7 +135,6 @@ public: rational value(const lp::lar_term& r) const; - lp::lar_term subs_terms_to_columns(const lp::lar_term& t) const; bool ineq_holds(const ineq& n) const; bool lemma_holds(const lemma& l) const; bool is_monic_var(lpvar j) const { return m_emons.is_monic_var(j); } @@ -284,10 +283,10 @@ public: } const rational& get_upper_bound(unsigned j) const; const rational& get_lower_bound(unsigned j) const; - bool has_lower_bound(lp::var_index var, u_dependency*& ci, lp::mpq& value, bool& is_strict) const { + bool has_lower_bound(lp::lpvar var, u_dependency*& ci, lp::mpq& value, bool& is_strict) const { return lra.has_lower_bound(var, ci, value, is_strict); } - bool has_upper_bound(lp::var_index var, u_dependency*& ci, lp::mpq& value, bool& is_strict) const { + bool has_upper_bound(lp::lpvar var, u_dependency*& ci, lp::mpq& value, bool& is_strict) const { return lra.has_upper_bound(var, ci, value, is_strict); } diff --git a/src/math/lp/nla_defs.h b/src/math/lp/nla_defs.h index e9807eaeb..b57603614 100644 --- a/src/math/lp/nla_defs.h +++ b/src/math/lp/nla_defs.h @@ -17,7 +17,7 @@ namespace nla { typedef lp::constraint_index lpci; typedef lp::lconstraint_kind llc; typedef lp::explanation expl_set; - typedef lp::var_index lpvar; + typedef unsigned lpvar; struct from_index_dummy{}; class signed_var { @@ -54,12 +54,12 @@ inline std::ostream& operator<<(std::ostream& out, signed_var const& sv) { retur * where m_vs = [v1, v2, .., vn] */ class monic_coeff { - svector m_vs; + svector m_vs; rational m_coeff; public: - monic_coeff(const svector& vs, rational const& coeff): m_vs(vs), m_coeff(coeff) {} + monic_coeff(const svector& vs, rational const& coeff): m_vs(vs), m_coeff(coeff) {} rational const& coeff() const { return m_coeff; } - const svector & vars() const { return m_vs; } + const svector & vars() const { return m_vs; } }; template bool has_zero(const T& product) { for (const rational & t : product) { diff --git a/src/math/lp/nla_divisions.cpp b/src/math/lp/nla_divisions.cpp index 7d52cd0ba..6c3bb178c 100644 --- a/src/math/lp/nla_divisions.cpp +++ b/src/math/lp/nla_divisions.cpp @@ -19,15 +19,9 @@ Description: namespace nla { void divisions::add_idivision(lpvar q, lpvar x, lpvar y) { - auto& lra = m_core.lra; + const auto& lra = m_core.lra; if (x == null_lpvar || y == null_lpvar || q == null_lpvar) return; - if (lp::tv::is_term(x)) - x = lra.map_term_index_to_column_index(x); - if (lp::tv::is_term(y)) - y = lra.map_term_index_to_column_index(y); - if (lp::tv::is_term(q)) - q = lra.map_term_index_to_column_index(q); m_idivisions.push_back({q, x, y}); m_core.trail().push(push_back_vector(m_idivisions)); } @@ -36,13 +30,6 @@ namespace nla { auto& lra = m_core.lra; if (x == null_lpvar || y == null_lpvar || q == null_lpvar) return; - if (lp::tv::is_term(x)) - x = lra.map_term_index_to_column_index(x); - if (lp::tv::is_term(y)) - y = lra.map_term_index_to_column_index(y); - if (lp::tv::is_term(q)) - q = lra.map_term_index_to_column_index(q); - m_rdivisions.push_back({ q, x, y }); m_core.trail().push(push_back_vector(m_rdivisions)); } @@ -50,7 +37,7 @@ namespace nla { void divisions::add_bounded_division(lpvar q, lpvar x, lpvar y) { if (x == null_lpvar || y == null_lpvar || q == null_lpvar) return; - if (lp::tv::is_term(x) || lp::tv::is_term(y) || lp::tv::is_term(q)) + if (m_core.lra.column_has_term(x) || m_core.lra.column_has_term(y) || m_core.lra.column_has_term(q)) return; m_bounded_divisions.push_back({ q, x, y }); m_core.trail().push(push_back_vector(m_bounded_divisions)); diff --git a/src/math/lp/nla_grobner.cpp b/src/math/lp/nla_grobner.cpp index f9974b41c..4beb7eaff 100644 --- a/src/math/lp/nla_grobner.cpp +++ b/src/math/lp/nla_grobner.cpp @@ -406,9 +406,8 @@ namespace nla { coeffs.push_back({lc*coeff, m_mon2var.find(vars)->second}); } - lp::lpvar term_index = c().lra.add_term(coeffs, UINT_MAX); - term_index = c().lra.map_term_index_to_column_index(term_index); - c().lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::EQ, offset, e.dep()); + lp::lpvar j = c().lra.add_term(coeffs, UINT_MAX); + c().lra.update_column_type_and_bound(j, lp::lconstraint_kind::EQ, offset, e.dep()); c().m_check_feasible = true; return true; } diff --git a/src/math/lp/nla_powers.cpp b/src/math/lp/nla_powers.cpp index f389aad93..4e521bb01 100644 --- a/src/math/lp/nla_powers.cpp +++ b/src/math/lp/nla_powers.cpp @@ -80,12 +80,12 @@ namespace nla { lbool powers::check(lpvar r, lpvar x, lpvar y, vector& lemmas) { TRACE("nla", tout << r << " == " << x << "^" << y << "\n"); + core& c = m_core; if (x == null_lpvar || y == null_lpvar || r == null_lpvar) return l_undef; - if (lp::tv::is_term(x) || lp::tv::is_term(y) || lp::tv::is_term(r)) + if (c.lra.column_has_term(x) || c.lra.column_has_term(y) || c.lra.column_has_term(r)) return l_undef; - core& c = m_core; if (c.use_nra_model()) return l_undef; diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index 23d4016bd..f55eec6a6 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -83,7 +83,7 @@ namespace nla { nlsat::anum_manager& solver::am() { return m_core->m_nra.am(); } - nlsat::anum const& solver::am_value(lp::var_index v) const { + nlsat::anum const& solver::am_value(lp::lpvar v) const { SASSERT(use_nra_model()); return m_core->m_nra.value(v); } diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index 1e47362fd..53e62b4f0 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -46,7 +46,7 @@ namespace nla { bool use_nra_model() const; core& get_core(); nlsat::anum_manager& am(); - nlsat::anum const& am_value(lp::var_index v) const; + nlsat::anum const& am_value(lp::lpvar v) const; scoped_anum& tmp1(); scoped_anum& tmp2(); vector const& lemmas() const; diff --git a/src/math/lp/nla_types.h b/src/math/lp/nla_types.h index cb62c5a30..f0f796652 100644 --- a/src/math/lp/nla_types.h +++ b/src/math/lp/nla_types.h @@ -22,7 +22,7 @@ namespace nla { typedef lp::lconstraint_kind llc; typedef lp::constraint_index lpci; typedef lp::explanation expl_set; - typedef lp::var_index lpvar; + typedef lp::lpvar lpvar; const lpvar null_lpvar = UINT_MAX; diff --git a/src/math/lp/nra_solver.cpp b/src/math/lp/nra_solver.cpp index e035fc34f..9c9db4e41 100644 --- a/src/math/lp/nra_solver.cpp +++ b/src/math/lp/nra_solver.cpp @@ -71,12 +71,11 @@ struct solver::imp { } } - for (unsigned i = lra.terms().size(); i-- > 0; ) { - auto const& t = lra.term(i); - for (auto const iv : t) { - auto v = iv.column().index(); + for (const auto *t : lra.terms() ) { + for (auto const iv : *t) { + auto v = iv.j(); var2occurs.reserve(v + 1); - var2occurs[v].terms.push_back(i); + var2occurs[v].terms.push_back(t->j()); } } @@ -99,17 +98,15 @@ struct solver::imp { todo.push_back(w); for (auto ti : var2occurs[v].terms) { - for (auto iv : lra.term(ti)) - todo.push_back(iv.column().index()); - auto vi = lp::tv::mask_term(ti); - todo.push_back(lra.map_term_index_to_column_index(vi)); + for (auto iv : lra.get_term(ti)) + todo.push_back(iv.j()); + todo.push_back(ti); } - if (lra.column_corresponds_to_term(v)) { + if (lra.column_has_term(v)) { m_term_set.insert(v); - lp::tv ti = lp::tv::raw(lra.column_to_reported_index(v)); - for (auto kv : lra.get_term(ti)) - todo.push_back(kv.column().index()); + for (auto kv : lra.get_term(v)) + todo.push_back(kv.j()); } if (m_nla_core.is_monic_var(v)) { @@ -517,16 +514,16 @@ struct solver::imp { - bool is_int(lp::var_index v) { + bool is_int(lp::lpvar v) { return lra.var_is_int(v); } - polynomial::var lp2nl(lp::var_index v) { + polynomial::var lp2nl(lp::lpvar v) { polynomial::var r; if (!m_lp2nl.find(v, r)) { r = m_nlsat->mk_var(is_int(v)); m_lp2nl.insert(v, r); - if (!m_term_set.contains(v) && lra.column_corresponds_to_term(v)) { + if (!m_term_set.contains(v) && lra.column_has_term(v)) { m_term_set.insert(v); } } @@ -534,14 +531,13 @@ struct solver::imp { } // void add_term(unsigned term_column) { - lp::tv ti = lp::tv::raw(lra.column_to_reported_index(term_column)); - const lp::lar_term& t = lra.get_term(ti); + const lp::lar_term& t = lra.get_term(term_column); // code that creates a polynomial equality between the linear coefficients and // variable representing the term. svector vars; rational den(1); for (lp::lar_term::ival kv : t) { - vars.push_back(lp2nl(kv.column().index())); + vars.push_back(lp2nl(kv.j())); den = lcm(den, denominator(kv.coeff())); } vars.push_back(lp2nl(term_column)); @@ -559,7 +555,7 @@ struct solver::imp { m_nlsat->mk_clause(1, &lit, nullptr); } - nlsat::anum const& value(lp::var_index v) { + nlsat::anum const& value(lp::lpvar v) { polynomial::var pv; if (m_lp2nl.find(v, pv)) return m_nlsat->value(pv); @@ -636,7 +632,7 @@ std::ostream& solver::display(std::ostream& out) const { return m_imp->display(out); } -nlsat::anum const& solver::value(lp::var_index v) { +nlsat::anum const& solver::value(lp::lpvar v) { return m_imp->value(v); } diff --git a/src/math/lp/nra_solver.h b/src/math/lp/nra_solver.h index 747b4cee3..90f022ba6 100644 --- a/src/math/lp/nra_solver.h +++ b/src/math/lp/nra_solver.h @@ -55,7 +55,7 @@ namespace nra { /* \brief Access model. */ - nlsat::anum const& value(lp::var_index v); + nlsat::anum const& value(lp::lpvar v); nlsat::anum_manager& am(); diff --git a/src/math/lp/static_matrix.h b/src/math/lp/static_matrix.h index ffbd48021..9d6bb8599 100644 --- a/src/math/lp/static_matrix.h +++ b/src/math/lp/static_matrix.h @@ -346,14 +346,14 @@ public: // we use the form -it + 1 = 0 m_work_vector.set_value(one_of_type(), bj); for (auto p : row) { - m_work_vector.set_value(-p.coeff(), p.column().index()); + m_work_vector.set_value(-p.coeff(), p.j()); // but take care of the basis 1 later } // now iterate with pivoting fill_last_row_with_pivoting_loop_block(bj, basis_heading); for (auto p : row) { - fill_last_row_with_pivoting_loop_block(p.column().index(), basis_heading); + fill_last_row_with_pivoting_loop_block(p.j(), basis_heading); } unsigned last_row = row_count() - 1; diff --git a/src/math/lp/var_register.h b/src/math/lp/var_register.h index 3b326788b..bd7e6efe8 100644 --- a/src/math/lp/var_register.h +++ b/src/math/lp/var_register.h @@ -41,10 +41,7 @@ public: class var_register { vector m_local_to_external; std::unordered_map m_external_to_local; - unsigned m_locals_mask; - unsigned m_locals_mask_inverted; public: - var_register(bool mask_locals): m_locals_mask(mask_locals? tv::left_most_bit: 0), m_locals_mask_inverted(~m_locals_mask) {} void set_name(unsigned j, std::string name) { m_local_to_external[j].set_name(name); @@ -63,7 +60,7 @@ public: } m_local_to_external.push_back(ext_var_info(user_var, is_int)); - unsigned local = ( size() - 1 ) | m_locals_mask; + unsigned local = size() - 1; if (user_var != UINT_MAX) m_external_to_local[user_var] = local; @@ -79,7 +76,7 @@ public: // returns UINT_MAX if unsigned local_to_external(unsigned local_var) const { - unsigned k = local_var & m_locals_mask_inverted; + unsigned k = local_var; if (k >= m_local_to_external.size()) return UINT_MAX; return m_local_to_external[k].external_j(); @@ -119,7 +116,7 @@ public: local_j = UINT_MAX; return false; } - local_j = it->second & m_locals_mask_inverted; + local_j = it->second; is_int = m_local_to_external[local_j].is_integer(); return true; } @@ -129,7 +126,7 @@ public: } bool local_is_int(unsigned j) const { - return m_local_to_external[j & m_locals_mask_inverted].is_integer(); + return m_local_to_external[j].is_integer(); } void shrink(unsigned shrunk_size) { diff --git a/src/sat/smt/arith_diagnostics.cpp b/src/sat/smt/arith_diagnostics.cpp index 32e64e2b5..c408fbf96 100644 --- a/src/sat/smt/arith_diagnostics.cpp +++ b/src/sat/smt/arith_diagnostics.cpp @@ -45,8 +45,7 @@ namespace arith { } unsigned nv = get_num_vars(); for (unsigned v = 0; v < nv; ++v) { - auto t = get_tv(v); - auto vi = lp().external_to_column_index(v); + auto vi = lp().external_to_local(v); out << "v" << v << " "; if (is_bool(v)) { euf::enode* n = var2enode(v); @@ -57,10 +56,10 @@ namespace arith { } } else { - if (t.is_null()) + if (vi == lp::null_lpvar) out << "null"; else - out << (t.is_term() ? "t" : "j") << vi; + out << (lp().column_has_term(vi) ? "t" : "j") << vi; if (m_nla && m_nla->use_nra_model() && is_registered_var(v)) { scoped_anum an(m_nla->am()); m_nla->am().display(out << " = ", nl_value(v, an)); diff --git a/src/sat/smt/arith_internalize.cpp b/src/sat/smt/arith_internalize.cpp index 00038cf8b..a389d13b8 100644 --- a/src/sat/smt/arith_internalize.cpp +++ b/src/sat/smt/arith_internalize.cpp @@ -507,11 +507,11 @@ namespace arith { } else { vi = lp().add_term(m_left_side, v); - SASSERT(lp::tv::is_term(vi)); + SASSERT(lp().column_has_term(vi)); TRACE("arith_verbose", tout << "v" << v << " := " << mk_pp(term, m) << " slack: " << vi << " scopes: " << m_scopes.size() << "\n"; - lp().print_term(lp().get_term(lp::tv::raw(vi)), tout) << "\n";); + lp().print_term(lp().get_term(vi), tout) << "\n";); } } return v; @@ -541,8 +541,6 @@ namespace arith { rational const& r = m_columns[var]; if (!r.is_zero()) { auto vi = register_theory_var_in_lar_solver(var); - if (lp::tv::is_term(vi)) - vi = lp().map_term_index_to_column_index(vi); m_left_side.push_back(std::make_pair(r, vi)); m_columns[var].reset(); } @@ -625,9 +623,6 @@ namespace arith { return lp().external_to_local(v); } - lp::tv solver::get_tv(theory_var v) const { - return lp::tv::raw(get_lpvar(v)); - } /** \brief We must redefine this method, because theory of arithmetic contains diff --git a/src/sat/smt/arith_sls.cpp b/src/sat/smt/arith_sls.cpp index 4fe153289..216829980 100644 --- a/src/sat/smt/arith_sls.cpp +++ b/src/sat/smt/arith_sls.cpp @@ -59,18 +59,10 @@ namespace arith { int64_t val = 0; lp::lar_term const& term = s.lp().get_term(t); for (lp::lar_term::ival const& arg : term) { - auto t2 = s.lp().column2tv(arg.column()); - auto w = s.lp().local_to_external(t2.id()); + auto t2 = arg.j(); + auto w = s.lp().local_to_external(t2); val += to_numeral(arg.coeff()) * m_vars[w].m_best_value; } - if (v == 52) { - verbose_stream() << "update v" << v << " := " << val << "\n"; - for (lp::lar_term::ival const& arg : term) { - auto t2 = s.lp().column2tv(arg.column()); - auto w = s.lp().local_to_external(t2.id()); - verbose_stream() << "v" << w << " := " << m_vars[w].m_best_value << " * " << to_numeral(arg.coeff()) << "\n"; - } - } m_vars[v].m_best_value = val; } @@ -81,12 +73,12 @@ namespace arith { continue; int64_t new_value = m_vars[v].m_best_value; s.ensure_column(v); - lp::column_index vj = s.lp().to_column_index(v); - SASSERT(!vj.is_null()); - if (!s.lp().is_base(vj.index())) { + lp::lpvar vj = s.lp().external_to_local(v); + SASSERT(vj != lp::null_lpvar); + if (!s.lp().is_base(vj)) { rational new_value_(new_value, rational::i64()); lp::impq val(new_value_, rational::zero()); - s.lp().set_value_for_nbasic_column(vj.index(), val); + s.lp().set_value_for_nbasic_column(vj, val); } } @@ -460,18 +452,18 @@ namespace arith { return 0; } - void sls::add_args(sat::bool_var bv, ineq& ineq, lp::tv t, theory_var v, int64_t sign) { - if (t.is_term()) { + void sls::add_args(sat::bool_var bv, ineq& ineq, lp::lpvar t, theory_var v, int64_t sign) { + if (s.lp().column_has_term(t)) { lp::lar_term const& term = s.lp().get_term(t); m_terms.push_back({t,v}); for (lp::lar_term::ival arg : term) { - auto t2 = s.lp().column2tv(arg.column()); - auto w = s.lp().local_to_external(t2.id()); + auto t2 = arg.j(); + auto w = s.lp().local_to_external(t2); add_arg(bv, ineq, sign * to_numeral(arg.coeff()), w); } } else - add_arg(bv, ineq, sign, s.lp().local_to_external(t.id())); + add_arg(bv, ineq, sign, s.lp().local_to_external(t)); } void sls::init_bool_var(sat::bool_var bv) { @@ -480,7 +472,7 @@ namespace arith { api_bound* b = nullptr; s.m_bool_var2bound.find(bv, b); if (b) { - auto t = b->tv(); + auto t = b->column_index(); rational bound = b->get_value(); bool should_minus = false; sls::ineq_kind op; @@ -503,8 +495,8 @@ namespace arith { if (e && m.is_eq(e, l, r) && s.a.is_int_real(l)) { theory_var u = s.get_th_var(l); theory_var v = s.get_th_var(r); - lp::tv tu = s.get_tv(u); - lp::tv tv = s.get_tv(v); + lp::lpvar tu = s.get_column(u); + lp::lpvar tv = s.get_column(v); auto& ineq = new_ineq(sls::ineq_kind::EQ, 0); add_args(bv, ineq, tu, u, 1); add_args(bv, ineq, tv, v, -1); diff --git a/src/sat/smt/arith_sls.h b/src/sat/smt/arith_sls.h index 09a56c84e..55d39b252 100644 --- a/src/sat/smt/arith_sls.h +++ b/src/sat/smt/arith_sls.h @@ -105,7 +105,7 @@ namespace arith { config m_config; scoped_ptr_vector m_bool_vars; vector m_vars; - svector> m_terms; + svector> m_terms; bool m_dscore_mode = false; @@ -140,7 +140,7 @@ namespace arith { void add_vars(); sls::ineq& new_ineq(ineq_kind op, int64_t const& bound); void add_arg(sat::bool_var bv, ineq& ineq, int64_t const& c, var_t v); - void add_args(sat::bool_var bv, ineq& ineq, lp::tv t, euf::theory_var v, int64_t sign); + void add_args(sat::bool_var bv, ineq& ineq, lp::lpvar j, euf::theory_var v, int64_t sign); void init_bool_var(sat::bool_var v); void init_bool_var_assignment(sat::bool_var v); diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index b2a466779..3086d75f4 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -370,7 +370,7 @@ namespace arith { void solver::refine_bound(theory_var v, const lp::implied_bound& be) { lpvar vi = be.m_j; - if (lp::tv::is_term(vi)) + if (lp().column_has_term(vi)) return; expr_ref w(var2expr(v), m); if (a.is_add(w) || a.is_numeral(w) || m.is_ite(w)) @@ -418,7 +418,7 @@ namespace arith { ++m_stats.m_assert_upper; inf_rational value = b.get_value(is_true); if (propagate_eqs() && value.is_rational()) - propagate_eqs(b.tv(), ci, k, b, value.get_rational()); + propagate_eqs(b.column_index(), ci, k, b, value.get_rational()); #if 0 if (propagation_mode() != BP_NONE) lp().add_column_rows_to_touched_rows(b.tv().id()); @@ -426,30 +426,29 @@ namespace arith { } - void solver::propagate_eqs(lp::tv t, lp::constraint_index ci1, lp::lconstraint_kind k, api_bound& b, rational const& value) { + void solver::propagate_eqs(lp::lpvar t, lp::constraint_index ci1, lp::lconstraint_kind k, api_bound& b, rational const& value) { u_dependency* dep; auto& dm = lp().dep_manager(); - if (k == lp::GE && set_lower_bound(t, ci1, value) && has_upper_bound(t.index(), dep, value)) { + if (k == lp::GE && set_lower_bound(t, ci1, value) && has_upper_bound(t, dep, value)) { fixed_var_eh(b.get_var(), dm.mk_join(dm.mk_leaf(ci1), dep), value); } - else if (k == lp::LE && set_upper_bound(t, ci1, value) && has_lower_bound(t.index(), dep, value)) { + else if (k == lp::LE && set_upper_bound(t, ci1, value) && has_lower_bound(t, dep, value)) { fixed_var_eh(b.get_var(), dm.mk_join(dm.mk_leaf(ci1), dep), value); } } - bool solver::set_bound(lp::tv tv, lp::constraint_index ci, rational const& v, bool is_lower) { - if (tv.is_term()) { - lpvar ti = tv.id(); + bool solver::set_bound(lp::lpvar tv, lp::constraint_index ci, rational const& v, bool is_lower) { + if (lp().column_has_term(tv)) { auto& vec = is_lower ? m_lower_terms : m_upper_terms; - if (vec.size() <= ti) { - vec.resize(ti + 1, constraint_bound(UINT_MAX, rational())); + if (vec.size() <= tv) { + vec.resize(tv + 1, constraint_bound(UINT_MAX, rational())); } - constraint_bound& b = vec[ti]; + constraint_bound& b = vec[tv]; if (b.first == UINT_MAX || (is_lower ? b.second < v : b.second > v)) { - TRACE("arith", tout << "tighter bound " << tv.to_string() << "\n";); - m_history.push_back(vec[ti]); - ctx.push(history_trail(vec, ti, m_history)); + TRACE("arith", tout << "tighter bound " << tv << "\n";); + m_history.push_back(vec[tv]); + ctx.push(history_trail(vec, tv, m_history)); b.first = ci; b.second = v; } @@ -461,10 +460,10 @@ namespace arith { rational b; u_dependency* dep = nullptr; if (is_lower) { - return lp().has_lower_bound(tv.id(), dep, b, is_strict) && !is_strict && b == v; + return lp().has_lower_bound(tv, dep, b, is_strict) && !is_strict && b == v; } else { - return lp().has_upper_bound(tv.id(), dep, b, is_strict) && !is_strict && b == v; + return lp().has_upper_bound(tv, dep, b, is_strict) && !is_strict && b == v; } } } @@ -772,7 +771,7 @@ namespace arith { bool solver::has_lower_bound(lpvar vi, u_dependency*& ci, rational const& bound) { return has_bound(vi, ci, bound, true); } bool solver::has_bound(lpvar vi, u_dependency*& dep, rational const& bound, bool is_lower) { - if (lp::tv::is_term(vi)) { + if (lp().column_has_term(vi)) { theory_var v = lp().local_to_external(vi); rational val; TRACE("arith", tout << lp().get_variable_name(vi) << " " << v << "\n";); @@ -782,9 +781,8 @@ namespace arith { } auto& vec = is_lower ? m_lower_terms : m_upper_terms; - lpvar ti = lp::tv::unmask_term(vi); - if (vec.size() > ti) { - auto& [ci, coeff] = vec[ti]; + if (vec.size() > vi) { + auto& [ci, coeff] = vec[vi]; if (ci == UINT_MAX) return false; dep = lp().dep_manager().mk_leaf(ci); @@ -876,11 +874,16 @@ namespace arith { lp::impq solver::get_ivalue(theory_var v) const { SASSERT(is_registered_var(v)); - return m_solver->get_tv_ivalue(get_tv(v)); + return m_solver->get_column_value(get_column(v)); } + lp::lpvar solver::get_column(theory_var v) const { + SASSERT(is_registered_var(v)); + return m_solver->external_to_local(v); + } + rational solver::get_value(theory_var v) const { - return is_registered_var(v) ? m_solver->get_tv_value(get_tv(v)) : rational::zero(); + return is_registered_var(v) ? m_solver->get_value(get_column(v)) : rational::zero(); } void solver::random_update() { @@ -895,18 +898,18 @@ namespace arith { if (is_bool(v)) continue; ensure_column(v); - lp::column_index vj = lp().to_column_index(v); - SASSERT(!vj.is_null()); + lp::lpvar vj = lp().external_to_local(v); + SASSERT(vj != lp::null_lpvar); theory_var other = m_model_eqs.insert_if_not_there(v); if (is_equal(v, other)) continue; - if (!lp().is_fixed(vj)) - vars.push_back(vj.index()); + if (!lp().column_is_fixed(vj)) + vars.push_back(vj); else if (!m_tmp_var_set.contains(other)) { - lp::column_index other_j = lp().to_column_index(other); - if (!lp().is_fixed(other_j)) { + lp::lpvar other_j = lp().external_to_local(other); + if (!lp().column_is_fixed(other_j)) { m_tmp_var_set.insert(other); - vars.push_back(other_j.index()); + vars.push_back(other_j); } } } @@ -1068,14 +1071,14 @@ namespace arith { nlsat::anum const& solver::nl_value(theory_var v, scoped_anum& r) const { SASSERT(m_nla); SASSERT(m_nla->use_nra_model()); - auto t = get_tv(v); - if (!t.is_term()) { - m_nla->am().set(r, m_nla->am_value(t.id())); + auto t = get_column(v); + if (!lp().column_has_term(t)) { + m_nla->am().set(r, m_nla->am_value(t)); } else { m_todo_terms.push_back(std::make_pair(t, rational::one())); - TRACE("nl_value", tout << "v" << v << " " << t.to_string() << "\n";); - TRACE("nl_value", tout << "v" << v << " := w" << t.to_string() << "\n"; + TRACE("nl_value", tout << "v" << v << " " << t << "\n";); + TRACE("nl_value", tout << "v" << v << " := w" << t << "\n"; lp().print_term(lp().get_term(t), tout) << "\n";); m_nla->am().set(r, 0); @@ -1090,14 +1093,14 @@ namespace arith { m_nla->am().set(r1, c1.to_mpq()); m_nla->am().add(r, r1, r); for (lp::lar_term::ival arg : term) { - auto wi = lp().column2tv(arg.column()); + auto wi = arg.j(); c1 = arg.coeff() * wcoeff; - if (wi.is_term()) { + if (lp().column_has_term(wi)) { m_todo_terms.push_back(std::make_pair(wi, c1)); } else { m_nla->am().set(r1, c1.to_mpq()); - m_nla->am().mul(m_nla->am_value(wi.id()), r1, r1); + m_nla->am().mul(m_nla->am_value(wi), r1, r1); m_nla->am().add(r1, r, r); } } @@ -1393,17 +1396,17 @@ namespace arith { TRACE("arith", lp().print_term(term, tout) << "\n";); for (lp::lar_term::ival ti : term) { theory_var w; - auto tv = lp().column2tv(ti.column()); - if (tv.is_term()) { + auto tv = ti.j(); + if (lp().column_has_term(tv)) { lp::lar_term const& term1 = lp().get_term(tv); rational coeff2 = coeff * ti.coeff(); term2coeffs(term1, coeffs, coeff2); continue; } else { - w = lp().local_to_external(tv.id()); + w = lp().local_to_external(tv); SASSERT(w >= 0); - TRACE("arith", tout << (tv.id()) << ": " << w << "\n";); + TRACE("arith", tout << tv << ": " << w << "\n";); } rational c0(0); coeffs.find(w, c0); diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index af9df0798..755611474 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -38,7 +38,7 @@ namespace euf { namespace arith { typedef ptr_vector> lp_bounds; - typedef lp::var_index lpvar; + typedef lp::lpvar lpvar; typedef euf::theory_var theory_var; typedef euf::theory_id theory_id; typedef euf::enode enode; @@ -245,7 +245,7 @@ namespace arith { symbol m_farkas; std_vector m_implied_bounds; lp::lp_bound_propagator m_bp; - mutable vector> m_todo_terms; + mutable vector> m_todo_terms; // lemmas lp::explanation m_explanation; @@ -306,7 +306,7 @@ namespace arith { bool reflect(expr* n) const; lpvar get_lpvar(theory_var v) const; - lp::tv get_tv(theory_var v) const; + lp::lpvar get_column(theory_var v) const; // axioms void mk_div_axiom(expr* p, expr* q); @@ -348,7 +348,7 @@ namespace arith { iterator end, bool& found_compatible); - void propagate_eqs(lp::tv t, lp::constraint_index ci, lp::lconstraint_kind k, api_bound& b, rational const& value); + void propagate_eqs(lp::lpvar t, lp::constraint_index ci, lp::lconstraint_kind k, api_bound& b, rational const& value); void propagate_basic_bounds(unsigned qhead); void propagate_bounds_with_lp_solver(); void propagate_bound(literal lit, api_bound& b); @@ -362,9 +362,9 @@ namespace arith { api_bound* mk_var_bound(sat::literal lit, theory_var v, lp_api::bound_kind bk, rational const& bound); lp::lconstraint_kind bound2constraint_kind(bool is_int, lp_api::bound_kind bk, bool is_true); void fixed_var_eh(theory_var v1, u_dependency* dep, rational const& bound); - bool set_upper_bound(lp::tv t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, false); } - bool set_lower_bound(lp::tv t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, true); } - bool set_bound(lp::tv tv, lp::constraint_index ci, rational const& v, bool is_lower); + bool set_upper_bound(lp::lpvar t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, false); } + bool set_lower_bound(lp::lpvar t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, true); } + bool set_bound(lp::lpvar tv, lp::constraint_index ci, rational const& v, bool is_lower); typedef std::pair constraint_bound; vector m_lower_terms; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 4c9e02738..f0a96ddd1 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -47,7 +47,7 @@ #include "util/scoped_timer.h" #include "util/distribution.h" -typedef lp::var_index lpvar; +typedef lp::lpvar lpvar; namespace smt { @@ -790,10 +790,6 @@ class theory_lra::imp { return v == null_theory_var ? lp::null_lpvar : lp().external_to_local(v); } - lp::tv get_tv(theory_var v) const { - return lp::tv::raw(get_lpvar(v)); - } - theory_var internalize_linearized_def(app* term, scoped_internalize_state& st) { theory_var v = mk_var(term); TRACE("arith_internalize", tout << "v" << v << " " << bpp(term) << "\n";); @@ -812,11 +808,11 @@ class theory_lra::imp { } else { vi = lp().add_term(m_left_side, v); - SASSERT(lp::tv::is_term(vi)); + SASSERT(lp().column_has_term(vi)); TRACE("arith_verbose", tout << "v" << v << " := " << mk_pp(term, m) << " slack: " << vi << " scopes: " << m_scopes.size() << "\n"; - lp().print_term(lp().get_term(lp::tv::raw(vi)), tout) << "\n";); + lp().print_term(lp().get_term(vi), tout) << "\n";); } } @@ -1432,15 +1428,15 @@ public: register_theory_var_in_lar_solver(v); } - mutable vector> m_todo_terms; - + mutable vector> m_todo_terms; + lp::impq get_ivalue(theory_var v) const { SASSERT(is_registered_var(v)); - return lp().get_tv_ivalue(get_tv(v)); + return lp().get_column_value(get_lpvar(v)); } rational get_value(theory_var v) const { - return is_registered_var(v) ? lp().get_tv_value(get_tv(v)) : rational::zero(); + return is_registered_var(v) ? lp().get_value(get_lpvar(v)) : rational::zero(); } bool m_model_is_initialized{ false }; @@ -1467,8 +1463,8 @@ public: continue; } ensure_column(v); - lp::column_index vj = lp().to_column_index(v); - SASSERT(!vj.is_null()); + lp::lpvar vj = lp().external_to_local(v); + SASSERT(vj != lp::null_lpvar); theory_var other = m_model_eqs.insert_if_not_there(v); if (other == v) { continue; @@ -1476,14 +1472,14 @@ public: enode * n2 = get_enode(other); if (n1->get_root() == n2->get_root()) continue; - if (!lp().is_fixed(vj)) { - vars.push_back(vj.index()); + if (!lp().column_is_fixed(vj)) { + vars.push_back(vj); } else if (!m_tmp_var_set.contains(other) ) { - lp::column_index other_j = lp().to_column_index(other); - if (!lp().is_fixed(other_j)) { + lp::lpvar other_j = lp().external_to_local(other); + if (!lp().column_is_fixed(other_j)) { m_tmp_var_set.insert(other); - vars.push_back(other_j.index()); + vars.push_back(other_j); } } } @@ -1794,12 +1790,12 @@ public: expr_ref t(m); expr_ref_vector ts(m); for (lp::lar_term::ival p : term) { - auto ti = lp().column2tv(p.column()); - if (ti.is_term()) { + auto ti = p.j(); + if (lp().column_has_term(ti)) { ts.push_back(multerm(p.coeff(), term2expr(lp().get_term(ti)))); } else { - ts.push_back(multerm(p.coeff(), var2expr(ti.id()))); + ts.push_back(multerm(p.coeff(), var2expr(ti))); } } if (ts.size() == 1) { @@ -1836,13 +1832,13 @@ public: lp().print_term(term, out << "bound: "); out << (upper?" <= ":" >= ") << k << "\n"; for (lp::lar_term::ival p : term) { - auto ti = lp().column2tv(p.column()); + auto ti = p.j(); out << p.coeff() << " * "; - if (ti.is_term()) { + if (lp().column_has_term(ti)) { lp().print_term(lp().get_term(ti), out) << "\n"; } else { - out << "v" << lp().local_to_external(ti.id()) << "\n"; + out << "v" << lp().local_to_external(ti) << "\n"; } } for (auto ev : ex) { @@ -2324,7 +2320,7 @@ public: void refine_bound(theory_var v, const lp::implied_bound& be) { lpvar vi = be.m_j; - if (lp::tv::is_term(vi)) + if (lp().column_has_term(vi)) return; expr_ref w(get_enode(v)->get_expr(), m); if (a.is_add(w) || a.is_numeral(w) || m.is_ite(w)) @@ -2747,27 +2743,27 @@ public: ++m_stats.m_bounds_propagations; } - svector m_todo_vars; + svector m_todo_vars; void add_use_lists(api_bound* b) { theory_var v = b->get_var(); lpvar vi = register_theory_var_in_lar_solver(v); - if (!lp::tv::is_term(vi)) { + if (!lp().column_has_term(vi)) { return; } - m_todo_vars.push_back(lp::tv::raw(vi)); + m_todo_vars.push_back(vi); while (!m_todo_vars.empty()) { auto ti = m_todo_vars.back(); - SASSERT(ti.is_term()); + SASSERT(lp().column_has_term(ti)); m_todo_vars.pop_back(); lp::lar_term const& term = lp().get_term(ti); for (auto p : term) { - lp::tv wi = lp().column2tv(p.column()); - if (wi.is_term()) { + lp::lpvar wi = p.j(); + if (lp().column_has_term(wi)) { m_todo_vars.push_back(wi); } else { - unsigned w = lp().local_to_external(wi.id()); + unsigned w = lp().local_to_external(wi); m_use_list.reserve(w + 1, ptr_vector()); m_use_list[w].push_back(b); } @@ -2778,22 +2774,22 @@ public: void del_use_lists(api_bound* b) { theory_var v = b->get_var(); lpvar vi = get_lpvar(v); - if (!lp::tv::is_term(vi)) { + if (!lp().column_has_term(vi)) { return; } - m_todo_vars.push_back(lp::tv::raw(vi)); + m_todo_vars.push_back(vi); while (!m_todo_vars.empty()) { auto ti = m_todo_vars.back(); - SASSERT(ti.is_term()); + SASSERT(lp().column_has_term(ti)); m_todo_vars.pop_back(); lp::lar_term const& term = lp().get_term(ti); for (auto coeff : term) { - auto wi = lp().column2tv(coeff.column()); - if (wi.is_term()) { + auto wi = coeff.j(); + if (lp().column_has_term(wi)) { m_todo_vars.push_back(wi); } else { - unsigned w = lp().local_to_external(wi.id()); + unsigned w = lp().local_to_external(wi); SASSERT(m_use_list[w].back() == b); m_use_list[w].pop_back(); } @@ -2872,20 +2868,20 @@ public: reset_evidence(); r.reset(); theory_var v = b.get_var(); - auto ti = get_tv(v); - SASSERT(ti.is_term()); + lp::lpvar ti = get_lpvar(v); + SASSERT(lp().column_has_term(ti)); lp::lar_term const& term = lp().get_term(ti); for (auto const mono : term) { - auto wi = lp().column2tv(mono.column()); + auto wi = mono.j(); u_dependency* ci = nullptr; rational value; bool is_strict; - if (wi.is_term()) { + if (lp().column_has_term(wi)) { return false; } if (mono.coeff().is_neg() == is_lub) { // -3*x ... <= lub based on lower bound for x. - if (!lp().has_lower_bound(wi.id(), ci, value, is_strict)) { + if (!lp().has_lower_bound(wi, ci, value, is_strict)) { return false; } if (is_strict) { @@ -2893,7 +2889,7 @@ public: } } else { - if (!lp().has_upper_bound(wi.id(), ci, value, is_strict)) { + if (!lp().has_upper_bound(wi, ci, value, is_strict)) { return false; } if (is_strict) { @@ -2933,7 +2929,7 @@ public: } inf_rational value = b.get_value(is_true); if (propagate_eqs() && value.is_rational()) - propagate_eqs(b.tv(), ci, k, b, value.get_rational()); + propagate_eqs(b.column_index(), ci, k, b, value.get_rational()); return true; #if 0 if (should_propagate()) @@ -2978,13 +2974,13 @@ public: vector m_lower_terms; vector m_upper_terms; - void propagate_eqs(lp::tv t, lp::constraint_index ci1, lp::lconstraint_kind k, api_bound& b, rational const& value) { + void propagate_eqs(lp::lpvar t, lp::constraint_index ci1, lp::lconstraint_kind k, api_bound& b, rational const& value) { u_dependency* ci2 = nullptr; auto pair = [&]() { return lp().dep_manager().mk_join(lp().dep_manager().mk_leaf(ci1), ci2); }; - if (k == lp::GE && set_lower_bound(t, ci1, value) && has_upper_bound(t.index(), ci2, value)) { + if (k == lp::GE && set_lower_bound(t, ci1, value) && has_upper_bound(t, ci2, value)) { fixed_var_eh(b.get_var(), t, pair(), value); } - else if (k == lp::LE && set_upper_bound(t, ci1, value) && has_lower_bound(t.index(), ci2, value)) { + else if (k == lp::LE && set_upper_bound(t, ci1, value) && has_lower_bound(t, ci2, value)) { fixed_var_eh(b.get_var(), t, pair(), value); } } @@ -2998,24 +2994,23 @@ public: bool proofs_enabled() const { return m.proofs_enabled(); } - bool set_upper_bound(lp::tv t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, false); } + bool set_upper_bound(lp::lpvar t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, false); } - bool set_lower_bound(lp::tv t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, true); } + bool set_lower_bound(lp::lpvar t, lp::constraint_index ci, rational const& v) { return set_bound(t, ci, v, true); } vector m_history; - bool set_bound(lp::tv tv, lp::constraint_index ci, rational const& v, bool is_lower) { - if (tv.is_term()) { - lpvar ti = tv.id(); + bool set_bound(lp::lpvar tv, lp::constraint_index ci, rational const& v, bool is_lower) { + if (lp().column_has_term(tv)) { auto& vec = is_lower ? m_lower_terms : m_upper_terms; - if (vec.size() <= ti) { - vec.resize(ti + 1, constraint_bound(UINT_MAX, rational())); + if (vec.size() <= tv) { + vec.resize(tv + 1, constraint_bound(UINT_MAX, rational())); } - constraint_bound& b = vec[ti]; + constraint_bound& b = vec[tv]; if (b.first == UINT_MAX || (is_lower? b.second < v : b.second > v)) { - TRACE("arith", tout << "tighter bound " << tv.to_string() << "\n";); - m_history.push_back(vec[ti]); - ctx().push_trail(history_trail(vec, ti, m_history)); + TRACE("arith", tout << "tighter bound " << tv << "\n";); + m_history.push_back(vec[tv]); + ctx().push_trail(history_trail(vec, tv, m_history)); b.first = ci; b.second = v; } @@ -3027,10 +3022,10 @@ public: rational b; u_dependency* dep = nullptr; if (is_lower) { - return lp().has_lower_bound(tv.id(), dep, b, is_strict) && !is_strict && b == v; + return lp().has_lower_bound(tv, dep, b, is_strict) && !is_strict && b == v; } else { - return lp().has_upper_bound(tv.id(), dep, b, is_strict) && !is_strict && b == v; + return lp().has_upper_bound(tv, dep, b, is_strict) && !is_strict && b == v; } } } @@ -3052,7 +3047,7 @@ public: bool has_lower_bound(lpvar vi, u_dependency*& ci, rational const& bound) { return has_bound(vi, ci, bound, true); } bool has_bound(lpvar vi, u_dependency*& dep, rational const& bound, bool is_lower) { - if (lp::tv::is_term(vi)) { + if (lp().column_has_term(vi)) { theory_var v = lp().local_to_external(vi); rational val; TRACE("arith", tout << lp().get_variable_name(vi) << " " << v << "\n";); @@ -3062,9 +3057,8 @@ public: } auto& vec = is_lower ? m_lower_terms : m_upper_terms; - lpvar ti = lp::tv::unmask_term(vi); - if (vec.size() > ti) { - auto const& [ci, coeff] = vec[ti]; + if (vec.size() > vi) { + auto const& [ci, coeff] = vec[vi]; if (ci == UINT_MAX) return false; dep = lp().dep_manager().mk_leaf(ci); @@ -3145,7 +3139,7 @@ public: ctx().assign_eq(x, y, eq_justification(js)); } - void fixed_var_eh(theory_var v, lp::tv t, u_dependency* dep, rational const& bound) { + void fixed_var_eh(theory_var v, lp::lpvar t, u_dependency* dep, rational const& bound) { theory_var w = null_theory_var; enode* x = get_enode(v); if (m_value2var.find(bound, w)) @@ -3314,14 +3308,14 @@ public: nlsat::anum const& nl_value(theory_var v, scoped_anum& r) const { SASSERT(use_nra_model()); - auto t = get_tv(v); - if (!t.is_term()) - m_nla->am().set(r, m_nla->am_value(t.id())); + auto t = get_lpvar(v); + if (!lp().column_has_term(t)) + m_nla->am().set(r, m_nla->am_value(t)); else { m_todo_terms.push_back({t, rational::one()}); - TRACE("nl_value", tout << "v" << v << " " << t.to_string() << "\n";); - TRACE("nl_value", tout << "v" << v << " := w" << t.to_string() << "\n"; + TRACE("nl_value", tout << "v" << v << " " << t << "\n";); + TRACE("nl_value", tout << "v" << v << " := w" << t << "\n"; lp().print_term(lp().get_term(t), tout) << "\n";); m_nla->am().set(r, 0); @@ -3336,14 +3330,14 @@ public: m_nla->am().set(r1, c1.to_mpq()); m_nla->am().add(r, r1, r); for (lp::lar_term::ival arg : term) { - auto wi = lp().column2tv(arg.column()); + auto wi = arg.j(); c1 = arg.coeff() * wcoeff; - if (wi.is_term()) { + if (lp().column_has_term(wi)) { m_todo_terms.push_back({wi, c1}); } else { m_nla->am().set(r1, c1.to_mpq()); - m_nla->am().mul(m_nla->am_value(wi.id()), r1, r1); + m_nla->am().mul(m_nla->am_value(wi), r1, r1); m_nla->am().add(r1, r, r); } } @@ -3619,17 +3613,17 @@ public: TRACE("arith", lp().print_term(term, tout) << "\n";); for (lp::lar_term::ival ti : term) { theory_var w; - auto tv = lp().column2tv(ti.column()); - if (tv.is_term()) { + auto tv = ti.j(); + if (lp().column_has_term(tv)) { lp::lar_term const& term1 = lp().get_term(tv); rational coeff2 = coeff * ti.coeff(); term2coeffs(term1, coeffs, coeff2); continue; } else { - w = lp().local_to_external(tv.id()); + w = lp().local_to_external(tv); SASSERT(w >= 0); - TRACE("arith", tout << (tv.id()) << ": " << w << "\n";); + TRACE("arith", tout << tv << ": " << w << "\n";); } rational c0(0); coeffs.find(w, c0); @@ -3686,9 +3680,9 @@ public: } app_ref mk_obj(theory_var v) { - auto t = get_tv(v); + auto t = get_lpvar(v); bool is_int = a.is_int(get_enode(v)->get_expr()); - if (t.is_term()) { + if (lp().column_has_term(t)) { return mk_term(lp().get_term(t), is_int); } else { @@ -3744,11 +3738,10 @@ public: } unsigned nv = th.get_num_vars(); for (unsigned v = 0; v < nv; ++v) { - auto t = get_tv(v); - auto vi = lp().external_to_column_index(v); + auto vi = get_lpvar(v); if (!ctx().is_relevant(get_enode(v))) out << "irr: "; out << "v" << v << " "; - if (t.is_null()) out << "null"; else out << (t.is_term() ? "t":"j") << vi; + if (vi == lp::null_lpvar) out << "null"; else out << (lp().column_has_term(vi) ? "t":"j") << vi; if (use_nra_model() && is_registered_var(v)) m_nla->am().display(out << " = ", nl_value(v, m_nla->tmp1())); else if (can_get_value(v)) out << " = " << get_value(v); if (is_int(v)) out << ", int"; diff --git a/src/test/lp/gomory_test.h b/src/test/lp/gomory_test.h index c64c01036..9ac675d1a 100644 --- a/src/test/lp/gomory_test.h +++ b/src/test/lp/gomory_test.h @@ -189,7 +189,7 @@ struct gomory_test { void print_term(lar_term & t, std::ostream & out) { vector> row; for (auto p : t) - row.push_back(std::make_pair(p.coeff(), p.column().index())); + row.push_back(std::make_pair(p.coeff(), p.j())); print_row(out, row); } diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 088a7dac0..84077b98e 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -786,25 +786,25 @@ void test_term() { lar_solver solver; unsigned _x = 0; unsigned _y = 1; - var_index x = solver.add_named_var(_x, true, "x"); - var_index y = solver.add_named_var(_y, true, "y"); + lpvar x = solver.add_named_var(_x, true, "x"); + lpvar y = solver.add_named_var(_y, true, "y"); enable_trace("lar_solver"); enable_trace("cube"); - vector> pairs; - pairs.push_back(std::pair(mpq(2), x)); - pairs.push_back(std::pair(mpq(1), y)); + vector> pairs; + pairs.push_back(std::pair(mpq(2), x)); + pairs.push_back(std::pair(mpq(1), y)); int ti = 0; unsigned x_plus_y = solver.add_term(pairs, ti++); solver.add_var_bound(x_plus_y, lconstraint_kind::GE, mpq(5, 3)); solver.add_var_bound(x_plus_y, lconstraint_kind::LE, mpq(14, 3)); pairs.pop_back(); - pairs.push_back(std::pair(mpq(-1), y)); + pairs.push_back(std::pair(mpq(-1), y)); unsigned x_minus_y = solver.add_term(pairs, ti++); solver.add_var_bound(x_minus_y, lconstraint_kind::GE, mpq(5, 3)); solver.add_var_bound(x_minus_y, lconstraint_kind::LE, mpq(14, 3)); auto status = solver.solve(); std::cout << lp_status_to_string(status) << std::endl; - std::unordered_map model; + std::unordered_map model; if (status != lp_status::OPTIMAL) { std::cout << "non optimal" << std::endl; return; @@ -834,24 +834,24 @@ void test_term() { void test_evidence_for_total_inf_simple(argument_parser &args_parser) { lar_solver solver; - var_index x = solver.add_var(0, false); - var_index y = solver.add_var(1, false); + lpvar x = solver.add_var(0, false); + lpvar y = solver.add_var(1, false); solver.add_var_bound(x, LE, mpq(-1)); solver.add_var_bound(y, GE, mpq(0)); - vector> ls; + vector> ls; - ls.push_back(std::pair(mpq(1), x)); - ls.push_back(std::pair(mpq(1), y)); + ls.push_back(std::pair(mpq(1), x)); + ls.push_back(std::pair(mpq(1), y)); unsigned j = solver.add_term(ls, 1); solver.add_var_bound(j, GE, mpq(1)); ls.pop_back(); - ls.push_back(std::pair(-mpq(1), y)); + ls.push_back(std::pair(-mpq(1), y)); j = solver.add_term(ls, 2); solver.add_var_bound(j, GE, mpq(0)); auto status = solver.solve(); std::cout << lp_status_to_string(status) << std::endl; - std::unordered_map model; + std::unordered_map model; lp_assert(solver.get_status() == lp_status::INFEASIBLE); } void test_bound_propagation_one_small_sample1() { @@ -873,20 +873,20 @@ void test_bound_propagation_one_small_sample1() { unsigned a = ls.add_var(0, false); unsigned b = ls.add_var(1, false); unsigned c = ls.add_var(2, false); - vector> coeffs; - coeffs.push_back(std::pair(mpq(1), a)); - coeffs.push_back(std::pair(mpq(-1), c)); + vector> coeffs; + coeffs.push_back(std::pair(mpq(1), a)); + coeffs.push_back(std::pair(mpq(-1), c)); ls.add_term(coeffs, -1); coeffs.pop_back(); - coeffs.push_back(std::pair(mpq(-1), b)); + coeffs.push_back(std::pair(mpq(-1), b)); ls.add_term(coeffs, -1); coeffs.clear(); - coeffs.push_back(std::pair(mpq(1), a)); - coeffs.push_back(std::pair(mpq(-1), b)); + coeffs.push_back(std::pair(mpq(1), a)); + coeffs.push_back(std::pair(mpq(-1), b)); // ls.add_constraint(coeffs, LE, zero_of_type()); // coeffs.clear(); - // coeffs.push_back(std::pair(mpq(1), b)); - // coeffs.push_back(std::pair(mpq(-1), c)); + // coeffs.push_back(std::pair(mpq(1), b)); + // coeffs.push_back(std::pair(mpq(-1), c)); // ls.add_constraint(coeffs, LE, zero_of_type()); // vector ev; // ls.add_var_bound(a, LE, mpq(1)); @@ -942,9 +942,9 @@ void test_bound_propagation_one_row() { lar_solver ls; unsigned x0 = ls.add_var(0, false); unsigned x1 = ls.add_var(1, false); - vector> c; - c.push_back(std::pair(mpq(1), x0)); - c.push_back(std::pair(mpq(-1), x1)); + vector> c; + c.push_back(std::pair(mpq(1), x0)); + c.push_back(std::pair(mpq(-1), x1)); // todo : restore test // ls.add_constraint(c, EQ, one_of_type()); // vector ev; @@ -957,9 +957,9 @@ void test_bound_propagation_one_row_with_bounded_vars() { lar_solver ls; unsigned x0 = ls.add_var(0, false); unsigned x1 = ls.add_var(1, false); - vector> c; - c.push_back(std::pair(mpq(1), x0)); - c.push_back(std::pair(mpq(-1), x1)); + vector> c; + c.push_back(std::pair(mpq(1), x0)); + c.push_back(std::pair(mpq(-1), x1)); // todo: restore test // ls.add_constraint(c, EQ, one_of_type()); // vector ev; @@ -974,9 +974,9 @@ void test_bound_propagation_one_row_mixed() { lar_solver ls; unsigned x0 = ls.add_var(0, false); unsigned x1 = ls.add_var(1, false); - vector> c; - c.push_back(std::pair(mpq(1), x0)); - c.push_back(std::pair(mpq(-1), x1)); + vector> c; + c.push_back(std::pair(mpq(1), x0)); + c.push_back(std::pair(mpq(-1), x1)); // todo: restore test // ls.add_constraint(c, EQ, one_of_type()); // vector ev; @@ -991,16 +991,16 @@ void test_bound_propagation_two_rows() { unsigned x = ls.add_var(0, false); unsigned y = ls.add_var(1, false); unsigned z = ls.add_var(2, false); - vector> c; - c.push_back(std::pair(mpq(1), x)); - c.push_back(std::pair(mpq(2), y)); - c.push_back(std::pair(mpq(3), z)); + vector> c; + c.push_back(std::pair(mpq(1), x)); + c.push_back(std::pair(mpq(2), y)); + c.push_back(std::pair(mpq(3), z)); // todo: restore test // ls.add_constraint(c, GE, one_of_type()); // c.clear(); - // c.push_back(std::pair(mpq(3), x)); - // c.push_back(std::pair(mpq(2), y)); - // c.push_back(std::pair(mpq(y), z)); + // c.push_back(std::pair(mpq(3), x)); + // c.push_back(std::pair(mpq(2), y)); + // c.push_back(std::pair(mpq(y), z)); // ls.add_constraint(c, GE, one_of_type()); // ls.add_var_bound(x, LE, mpq(2)); // vector ev; @@ -1016,10 +1016,10 @@ void test_total_case_u() { unsigned x = ls.add_var(0, false); unsigned y = ls.add_var(1, false); unsigned z = ls.add_var(2, false); - vector> c; - c.push_back(std::pair(mpq(1), x)); - c.push_back(std::pair(mpq(2), y)); - c.push_back(std::pair(mpq(3), z)); + vector> c; + c.push_back(std::pair(mpq(1), x)); + c.push_back(std::pair(mpq(2), y)); + c.push_back(std::pair(mpq(3), z)); // todo: restore test // ls.add_constraint(c, LE, one_of_type()); // ls.add_var_bound(x, GE, zero_of_type()); @@ -1044,10 +1044,10 @@ void test_total_case_l() { unsigned x = ls.add_var(0, false); unsigned y = ls.add_var(1, false); unsigned z = ls.add_var(2, false); - vector> c; - c.push_back(std::pair(mpq(1), x)); - c.push_back(std::pair(mpq(2), y)); - c.push_back(std::pair(mpq(3), z)); + vector> c; + c.push_back(std::pair(mpq(1), x)); + c.push_back(std::pair(mpq(2), y)); + c.push_back(std::pair(mpq(3), z)); // todo: restore test // ls.add_constraint(c, GE, one_of_type()); // ls.add_var_bound(x, LE, one_of_type()); @@ -1611,15 +1611,15 @@ void test_maximize_term() { int_solver i_solver(solver); // have to create it too unsigned _x = 0; unsigned _y = 1; - var_index x = solver.add_var(_x, false); - var_index y = solver.add_var(_y, true); - vector> term_ls; - term_ls.push_back(std::pair(mpq(1), x)); - term_ls.push_back(std::pair(mpq(-1), y)); + lpvar x = solver.add_var(_x, false); + lpvar y = solver.add_var(_y, true); + vector> term_ls; + term_ls.push_back(std::pair(mpq(1), x)); + term_ls.push_back(std::pair(mpq(-1), y)); unsigned term_x_min_y = solver.add_term(term_ls, -1); term_ls.clear(); - term_ls.push_back(std::pair(mpq(2), x)); - term_ls.push_back(std::pair(mpq(2), y)); + term_ls.push_back(std::pair(mpq(2), x)); + term_ls.push_back(std::pair(mpq(2), y)); unsigned term_2x_pl_2y = solver.add_term(term_ls, -1); solver.add_var_bound(term_x_min_y, LE, zero_of_type()); @@ -1627,7 +1627,7 @@ void test_maximize_term() { solver.find_feasible_solution(); lp_assert(solver.get_status() == lp_status::OPTIMAL); std::cout << solver.constraints(); - std::unordered_map model; + std::unordered_map model; solver.get_model(model); for (auto p : model) { std::cout << "v[" << p.first << "] = " << p.second << std::endl; @@ -1918,4 +1918,4 @@ void test_patching() { test_patching_alpha(rational(x1, x2), rational(a1, a2)); } -} \ No newline at end of file +} diff --git a/src/test/lp/smt_reader.h b/src/test/lp/smt_reader.h index 7843d5714..7a0ea5ff9 100644 --- a/src/test/lp/smt_reader.h +++ b/src/test/lp/smt_reader.h @@ -28,7 +28,7 @@ Revision History: #include #include #include -#include "math/lp/ul_pair.h" +#include "math/lp/column.h" #include "math/lp/lar_constraints.h" #include #include @@ -383,7 +383,7 @@ namespace lp { } void add_constraint_to_solver(lar_solver * solver, formula_constraint & fc, unsigned i) { - vector> ls; + vector> ls; for (auto & it : fc.m_coeffs) { ls.push_back(std::make_pair(it.first, solver->add_var(register_name(it.second), false))); } From ee2be7d64225af60e190e3ba3137acac33be964b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 25 Jan 2024 08:41:31 -0800 Subject: [PATCH 123/224] attempting to build ARM Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 384 +++++++++++++++++++++++++++++++++++ scripts/nightly.yaml | 44 +++- 2 files changed, 426 insertions(+), 2 deletions(-) create mode 100644 scripts/mk_win_dist_cmake.py diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py new file mode 100644 index 000000000..45dd03e13 --- /dev/null +++ b/scripts/mk_win_dist_cmake.py @@ -0,0 +1,384 @@ +############################################ +# Copyright (c) 2012 Microsoft Corporation +# +# Scripts for automatically generating +# Window distribution zip files. +# +# Author: Leonardo de Moura (leonardo) +############################################ + +import os +import subprocess +import zipfile +from mk_exception import * +from mk_project import * +import mk_util + +BUILD_DIR = 'build-dist' +BUILD_X64_DIR = os.path.join('build-dist', 'x64') +BUILD_X86_DIR = os.path.join('build-dist', 'x86') +BUILD_ARM64_DIR = os.path.join('build-dist', 'arm64') # ARM64 build directory +VERBOSE = True +DIST_DIR = 'dist' +FORCE_MK = False +ASSEMBLY_VERSION = None +DOTNET_CORE_ENABLED = True +DOTNET_KEY_FILE = None +JAVA_ENABLED = True +ZIP_BUILD_OUTPUTS = False +GIT_HASH = False +PYTHON_ENABLED = True +X86ONLY = False +X64ONLY = False +ARM64ONLY = False # ARM64 flag +MAKEJOBS = getenv("MAKEJOBS", "24") + + +def set_verbose(flag): + global VERBOSE + VERBOSE = flag + +def is_verbose(): + return VERBOSE + +def mk_dir(d): + if not os.path.exists(d): + os.makedirs(d) + +def set_build_dir(path): + global BUILD_DIR, BUILD_X86_DIR, BUILD_X64_DIR, BUILD_ARM64_DIR + BUILD_DIR = mk_util.norm_path(path) + BUILD_X86_DIR = os.path.join(path, 'x86') + BUILD_X64_DIR = os.path.join(path, 'x64') + BUILD_ARM64_DIR = os.path.join(path, 'arm64') # Set ARM64 build directory + mk_dir(BUILD_X86_DIR) + mk_dir(BUILD_X64_DIR) + mk_dir(BUILD_ARM64_DIR) + +def display_help(): + print("mk_win_dist.py: Z3 Windows distribution generator\n") + print("This script generates the zip files containing executables, dlls, header files for Windows.") + print("It must be executed from the Z3 root directory.") + print("\nOptions:") + print(" -h, --help display this message.") + print(" -s, --silent do not print verbose messages.") + print(" -b , --build= subdirectory where x86 and x64 Z3 versions will be built (default: build-dist).") + print(" -f, --force force script to regenerate Makefiles.") + print(" --assembly-version assembly version for dll") + print(" --nodotnet do not include .NET bindings in the binary distribution files.") + print(" --dotnet-key= strongname sign the .NET assembly with the private key in .") + print(" --nojava do not include Java bindings in the binary distribution files.") + print(" --nopython do not include Python bindings in the binary distribution files.") + print(" --zip package build outputs in zip file.") + print(" --githash include git hash in the Zip file.") + print(" --x86-only x86 dist only.") + print(" --x64-only x64 dist only.") + print(" --arm64-only arm64 dist only.") + exit(0) + +# Parse configuration option for mk_make script +def parse_options(): + global FORCE_MK, JAVA_ENABLED, ZIP_BUILD_OUTPUTS, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, ASSEMBLY_VERSION, PYTHON_ENABLED, X86ONLY, X64ONLY, ARM64ONLY + path = BUILD_DIR + options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', + 'help', + 'silent', + 'force', + 'nojava', + 'nodotnet', + 'dotnet-key=', + 'assembly-version=', + 'zip', + 'githash', + 'nopython', + 'x86-only', + 'x64-only', + 'arm64-only' + ]) + for opt, arg in options: + if opt in ('-b', '--build'): + if arg == 'src': + raise MKException('The src directory should not be used to host the Makefile') + path = arg + elif opt in ('-s', '--silent'): + set_verbose(False) + elif opt in ('-h', '--help'): + display_help() + elif opt in ('-f', '--force'): + FORCE_MK = True + elif opt == '--nodotnet': + DOTNET_CORE_ENABLED = False + elif opt == '--assembly-version': + ASSEMBLY_VERSION = arg + elif opt == '--nopython': + PYTHON_ENABLED = False + elif opt == '--dotnet-key': + DOTNET_KEY_FILE = arg + elif opt == '--nojava': + JAVA_ENABLED = False + elif opt == '--zip': + ZIP_BUILD_OUTPUTS = True + elif opt == '--githash': + GIT_HASH = True + elif opt == '--x86-only' and not X64ONLY: + X86ONLY = True + elif opt == '--arm64-only' and not X86ONLY and not X64ONLY: + ARM64ONLY = True + elif opt == '--x64-only' and not X86ONLY: + X64ONLY = True + else: + raise MKException("Invalid command line option '%s'" % opt) + set_build_dir(path) + +# Check whether build directory already exists or not +def check_build_dir(path): + return os.path.exists(path) and os.path.exists(os.path.join(path, 'Makefile')) + +# Create a build directory using mk_make.py +def mk_build_dir(path, arch): + if not check_build_dir(path) or FORCE_MK: + subprocess.call(["call", "md", path, "2>NUL"], shell=True) + + if arch == "arm64": + arch = "amd64_arm64" + + opts0 = ["cd", path] + + opts1 = ['"C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Auxiliary\\Build\\vcvarsall.bat"', arch] + + opts = ["cmake", "-S", "."] + if DOTNET_CORE_ENABLED: + opts.append('-DZ3_BUILD_DOTNET_BINDINGS=ON') + if DOTNET_KEY_FILE is not None: + opts.append('-DDOTNET_SIGNING_KEY_FILE=' + DOTNET_KEY_FILE) + if ASSEMBLY_VERSION is not None: + opts.append('-DZ3_ASSEMBLY_VERSION=' + ASSEMBLY_VERSION) + if JAVA_ENABLED: + opts.append('-DZ3_BUILD_JAVA_BINDINGS=ON') + if GIT_HASH: + git_hash = mk_util.git_hash() + opts.append('-DGIT_HASH=' + git_hash) + if PYTHON_ENABLED: + opts.append('-DZ3_BUILD_PYTHON_BINDINGS=ON') + opts.append('-DZ3_USE_LIBGMP=OFF') + opts.append('-DZ3_BUILD_LIBZ3_SHARED=ON') + opts.append('-DCMAKE_INSTALL_PREFIX=' + path) + opts.append('-G "NMake Makefiles"') + opts.append('../..') + args = " ".join(opts0) + "& " + " ".join(opts1) + "& " + " ".join(opts) + print(args) + if subprocess.call(args, shell=True) != 0: + raise MKException("Failed to generate build directory at '%s'" % path) + + +# Create build directories +def mk_build_dirs(): + mk_build_dir(BUILD_X86_DIR, 'x86') + mk_build_dir(BUILD_X64_DIR, 'x64') + mk_build_dir(BUILD_ARM64_DIR, 'arm64') # ARM64 build directory creation + +# Check if on Visual Studio command prompt +def check_vc_cmd_prompt(): + try: + DEVNULL = open(os.devnull, 'wb') + subprocess.call(['cl'], stdout=DEVNULL, stderr=DEVNULL) + except: + raise MKException("You must execute the mk_win_dist.py script on a Visual Studio Command Prompt") + +def exec_cmds(cmds): + cmd_file = 'z3_tmp.cmd' + f = open(cmd_file, 'w') + for cmd in cmds: + f.write(cmd) + f.write('\n') + f.close() + res = 0 + try: + res = subprocess.call(cmd_file, shell=True) + except: + res = 1 + try: + os.erase(cmd_file) + except: + pass + return res + +def get_build_dir(arch): + if arch == 'x64': + return BUILD_X64_DIR + if arch == 'x86': + return BUILD_X86_DIR + return BUILD_ARM64_DIR + +def mk_z3(arch): + build_dir = get_build_dir(arch) + if arch == "arm64": + arch = "x64_arm64" + cmds = [] + cmds.append('call "%VCINSTALLDIR%Auxiliary\\build\\vcvarsall.bat" ' + arch + ' ') + cmds.append('cd %s' % build_dir) + cmds.append('nmake') + if exec_cmds(cmds) != 0: + raise MKException("Failed to make z3, x64: %s" % x64) + +def mk_z3s(): + mk_z3('x86') + mk_z3('x64') + mk_z3('arm64') + +def get_z3_name(arch): + major, minor, build, revision = get_version() + print("Assembly version:", major, minor, build, revision) + platform = arch + if GIT_HASH: + return 'z3-%s.%s.%s.%s-%s-win' % (major, minor, build, mk_util.git_hash(), platform) + else: + return 'z3-%s.%s.%s-%s-win' % (major, minor, build, platform) + +def mk_dist_dir(arch): + build_path = get_build_dir(arch) + dist_path = os.path.join(DIST_DIR, get_z3_name(arch)) + mk_dir(dist_path) + mk_win_dist(build_path, dist_path) + if is_verbose(): + print(f"Generated {platform} distribution folder at '{dist_path}'") + +def mk_dist_dirs(): + mk_dist_dir("x86") + mk_dist_dir("x64") + mk_dist_dir("arm64") + +def get_dist_path(arch): + return get_z3_name(arch) + +def mk_zip(arch): + dist_path = get_dist_path(arch) + old = os.getcwd() + try: + os.chdir(DIST_DIR) + zfname = '%s.zip' % dist_path + zipout = zipfile.ZipFile(zfname, 'w', zipfile.ZIP_DEFLATED) + for root, dirs, files in os.walk(dist_path): + for f in files: + zipout.write(os.path.join(root, f)) + if is_verbose(): + print("Generated '%s'" % zfname) + except: + pass + os.chdir(old) + +# Create a zip file for each platform +def mk_zips(): + mk_zip(False) + mk_zip(True) + + +VS_RUNTIME_PATS = [re.compile(r'vcomp.*\.dll'), + re.compile(r'msvcp.*\.dll'), + re.compile(r'msvcr.*\.dll'), + re.compile(r'vcrun.*\.dll')] + +# Copy Visual Studio Runtime libraries +def cp_vs_runtime(arch): + platform = arch + vcdir = os.environ['VCINSTALLDIR'] + path = '%sredist' % vcdir + vs_runtime_files = [] + print("Walking %s" % path) + # Everything changes with every release of VS + # Prior versions of VS had DLLs under "redist\x64" + # There are now several variants of redistributables + # The naming convention defies my understanding so + # we use a "check_root" filter to find some hopefully suitable + # redistributable. + def check_root(root): + return platform in root and ("CRT" in root or "MP" in root) and "onecore" not in root and "debug" not in root + for root, dirs, files in os.walk(path): + for filename in files: + if fnmatch(filename, '*.dll') and check_root(root): + print("Checking %s %s" % (root, filename)) + for pat in VS_RUNTIME_PATS: + if pat.match(filename): + fname = os.path.join(root, filename) + if not os.path.isdir(fname): + vs_runtime_files.append(fname) + if not vs_runtime_files: + raise MKException("Did not find any runtime files to include") + bin_dist_path = os.path.join(DIST_DIR, get_dist_path(arch), 'bin') + for f in vs_runtime_files: + shutil.copy(f, bin_dist_path) + if is_verbose(): + print("Copied '%s' to '%s'" % (f, bin_dist_path)) + +def cp_vs_runtimes(): + cp_vs_runtime("x86") + cp_vs_runtime("x64") + cp_vs_runtime("arm64") + +def cp_license(arch): + shutil.copy("LICENSE.txt", os.path.join(DIST_DIR, get_dist_path(arch))) + +def cp_licenses(): + cp_license("x86") + cp_license("x64") + cp_license("arm64") + +def init_flags(): + global DOTNET_KEY_FILE, JAVA_ENABLED, PYTHON_ENABLED, ASSEMBLY_VERSION + mk_util.DOTNET_CORE_ENABLED = True + mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE + mk_util.ASSEMBLY_VERSION = ASSEMBLY_VERSION + mk_util.JAVA_ENABLED = JAVA_ENABLED + mk_util.PYTHON_ENABLED = PYTHON_ENABLED + mk_util.ALWAYS_DYNAMIC_BASE = True + + +# Entry point +def main(): + if os.name != 'nt': + raise MKException("This script is for Windows only") + + parse_options() + check_vc_cmd_prompt() + init_flags() + + if X86ONLY: + mk_build_dir(BUILD_X86_DIR, 'x86') + mk_z3('x86') + init_project_def() + mk_dist_dir('x86') + cp_license('x86') + cp_vs_runtime('x86') + if ZIP_BUILD_OUTPUTS: + mk_zip('x86') + elif X64ONLY: + mk_build_dir(BUILD_X64_DIR, 'x64') + mk_z3('x64') + init_project_def() + mk_dist_dir('x64') + cp_license('x64') + cp_vs_runtime('x64') + if ZIP_BUILD_OUTPUTS: + mk_zip('x64') + elif ARM64ONLY: # ARM64 build process + mk_build_dir(BUILD_ARM64_DIR, 'arm64') + mk_z3('arm64') + init_project_def() + mk_dist_dir('arm64') + cp_license('arm64') + cp_vs_runtime('arm64') + if ZIP_BUILD_OUTPUTS: + mk_zip('arm64') + + else: + mk_build_dirs() + mk_z3s() + init_project_def() + mk_dist_dirs() + cp_licenses() + cp_vs_runtimes() + if ZIP_BUILD_OUTPUTS: + mk_zips() + +main() + diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 55c4c5f0c..968c9dbbb 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -162,7 +162,7 @@ stages: inputs: script: call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 & - python scripts\mk_win_dist.py + python scripts\mk_win_dist_cmake.py --assembly-version=$(AssemblyVersion) --x86-only --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk @@ -202,7 +202,7 @@ stages: inputs: script: call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 & - python scripts\mk_win_dist.py + python scripts\mk_win_dist_cmake.py --assembly-version=$(AssemblyVersion) --x64-only --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk @@ -233,6 +233,46 @@ stages: symbolServerType: TeamServices detailedLog: true + - job: WindowsArm64 + displayName: "Windows ARM64-bit build" + pool: + vmImage: "windows-latest" + steps: + - task: CmdLine@2 + inputs: + script: + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64_arm64 & + python scripts\mk_win_dist_cmake.py + --assembly-version=$(AssemblyVersion) + --arm64-only + --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk + --zip + - task: CopyFiles@2 + inputs: + sourceFolder: dist + contents: '*.zip' + targetFolder: $(Build.ArtifactStagingDirectory) + - task: PublishPipelineArtifact@1 + inputs: + targetPath: $(Build.ArtifactStagingDirectory) + artifactName: 'WindowsArm64' + - task: CopyFiles@2 + displayName: 'Collect Symbols' + inputs: + sourceFolder: dist + contents: '**/*.pdb' + targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' + # Publish symbol archive to match nuget package + # Index your source code and publish symbols to a file share or Azure Artifacts symbol server + - task: PublishSymbols@2 + inputs: + symbolsFolder: '$(Build.ArtifactStagingDirectory)/symbols' + searchPattern: '**/*.pdb' + indexSources: false # Github not supported + publishSymbols: true + symbolServerType: TeamServices + detailedLog: true + - stage: Package From 9d59d86a1c9a657f284fc562cb80467b0dc0e24a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 25 Jan 2024 09:42:28 -0800 Subject: [PATCH 124/224] update cmake build Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 145 ++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 72 deletions(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index 45dd03e13..8578af296 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -11,8 +11,6 @@ import os import subprocess import zipfile from mk_exception import * -from mk_project import * -import mk_util BUILD_DIR = 'build-dist' BUILD_X64_DIR = os.path.join('build-dist', 'x64') @@ -33,6 +31,7 @@ X64ONLY = False ARM64ONLY = False # ARM64 flag MAKEJOBS = getenv("MAKEJOBS", "24") +ARCHS = [] def set_verbose(flag): global VERBOSE @@ -46,11 +45,12 @@ def mk_dir(d): os.makedirs(d) def set_build_dir(path): - global BUILD_DIR, BUILD_X86_DIR, BUILD_X64_DIR, BUILD_ARM64_DIR - BUILD_DIR = mk_util.norm_path(path) + global BUILD_DIR, BUILD_X86_DIR, BUILD_X64_DIR, BUILD_ARM64_DIR, ARCHS + BUILD_DIR = os.path.expanduser(os.path.normpath(path)) BUILD_X86_DIR = os.path.join(path, 'x86') BUILD_X64_DIR = os.path.join(path, 'x64') BUILD_ARM64_DIR = os.path.join(path, 'arm64') # Set ARM64 build directory + ARCHS = {'x64': BUILD_X64_DIR, 'x86':BUILD_X86_DIR, 'arm64':BUILD_ARM64_DIR} mk_dir(BUILD_X86_DIR) mk_dir(BUILD_X64_DIR) mk_dir(BUILD_ARM64_DIR) @@ -59,11 +59,12 @@ def display_help(): print("mk_win_dist.py: Z3 Windows distribution generator\n") print("This script generates the zip files containing executables, dlls, header files for Windows.") print("It must be executed from the Z3 root directory.") - print("\nOptions:") + print("\nOptions:") print(" -h, --help display this message.") print(" -s, --silent do not print verbose messages.") print(" -b , --build= subdirectory where x86 and x64 Z3 versions will be built (default: build-dist).") print(" -f, --force force script to regenerate Makefiles.") + print(" --version= release version.") print(" --assembly-version assembly version for dll") print(" --nodotnet do not include .NET bindings in the binary distribution files.") print(" --dotnet-key= strongname sign the .NET assembly with the private key in .") @@ -134,6 +135,27 @@ def parse_options(): def check_build_dir(path): return os.path.exists(path) and os.path.exists(os.path.join(path, 'Makefile')) +def check_output(cmd): + out = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0] + if out != None: + enc = sys.getdefaultencoding() + if enc != None: return out.decode(enc).rstrip('\r\n') + else: return out.rstrip('\r\n') + else: + return "" + +def get_git_hash(): + try: + branch = check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']) + r = check_output(['git', 'show-ref', '--abbrev=12', 'refs/heads/%s' % branch]) + except: + raise MKException("Failed to retrieve git hash") + ls = r.split(' ') + if len(ls) != 2: + raise MKException("Unexpected git output " + r) + return ls[0] + + # Create a build directory using mk_make.py def mk_build_dir(path, arch): if not check_build_dir(path) or FORCE_MK: @@ -149,18 +171,14 @@ def mk_build_dir(path, arch): opts = ["cmake", "-S", "."] if DOTNET_CORE_ENABLED: opts.append('-DZ3_BUILD_DOTNET_BINDINGS=ON') - if DOTNET_KEY_FILE is not None: - opts.append('-DDOTNET_SIGNING_KEY_FILE=' + DOTNET_KEY_FILE) - if ASSEMBLY_VERSION is not None: - opts.append('-DZ3_ASSEMBLY_VERSION=' + ASSEMBLY_VERSION) if JAVA_ENABLED: opts.append('-DZ3_BUILD_JAVA_BINDINGS=ON') if GIT_HASH: - git_hash = mk_util.git_hash() + git_hash = get_git_hash() opts.append('-DGIT_HASH=' + git_hash) if PYTHON_ENABLED: opts.append('-DZ3_BUILD_PYTHON_BINDINGS=ON') - opts.append('-DZ3_USE_LIBGMP=OFF') + opts.append('-DZ3_USE_LIB_GMP=OFF') opts.append('-DZ3_BUILD_LIBZ3_SHARED=ON') opts.append('-DCMAKE_INSTALL_PREFIX=' + path) opts.append('-G "NMake Makefiles"') @@ -173,10 +191,10 @@ def mk_build_dir(path, arch): # Create build directories def mk_build_dirs(): - mk_build_dir(BUILD_X86_DIR, 'x86') - mk_build_dir(BUILD_X64_DIR, 'x64') - mk_build_dir(BUILD_ARM64_DIR, 'arm64') # ARM64 build directory creation - + global ARCHS + for k in ARCHS: + mk_build_dir(ARCHS[k], k) + # Check if on Visual Studio command prompt def check_vc_cmd_prompt(): try: @@ -222,18 +240,20 @@ def mk_z3(arch): raise MKException("Failed to make z3, x64: %s" % x64) def mk_z3s(): - mk_z3('x86') - mk_z3('x64') - mk_z3('arm64') + global ARCHS + for k in ARCHS: + mk_z3(k) def get_z3_name(arch): - major, minor, build, revision = get_version() - print("Assembly version:", major, minor, build, revision) - platform = arch + global ASSEMBLY_VERSION + version = "4" + if ASSEMBLY_VERSION: + version = ASSEMBLY_VERSION + print("Assembly version:", version) if GIT_HASH: - return 'z3-%s.%s.%s.%s-%s-win' % (major, minor, build, mk_util.git_hash(), platform) + return 'z3-%s.%s-%s-win' % (version, get_git_hash(), arch) else: - return 'z3-%s.%s.%s-%s-win' % (major, minor, build, platform) + return 'z3-%s-%s-win' % (version, arch) def mk_dist_dir(arch): build_path = get_build_dir(arch) @@ -244,10 +264,10 @@ def mk_dist_dir(arch): print(f"Generated {platform} distribution folder at '{dist_path}'") def mk_dist_dirs(): - mk_dist_dir("x86") - mk_dist_dir("x64") - mk_dist_dir("arm64") - + global ARCHS + for k in ARCHS: + mk_dist_dir(k) + def get_dist_path(arch): return get_z3_name(arch) @@ -269,8 +289,9 @@ def mk_zip(arch): # Create a zip file for each platform def mk_zips(): - mk_zip(False) - mk_zip(True) + global ARCHS + for k in ARCHS: + mk_zip(k) VS_RUNTIME_PATS = [re.compile(r'vcomp.*\.dll'), @@ -311,28 +332,31 @@ def cp_vs_runtime(arch): print("Copied '%s' to '%s'" % (f, bin_dist_path)) def cp_vs_runtimes(): - cp_vs_runtime("x86") - cp_vs_runtime("x64") - cp_vs_runtime("arm64") - + global ARCHS + for k in ARCHS: + cp_vs_runtime(k) + def cp_license(arch): shutil.copy("LICENSE.txt", os.path.join(DIST_DIR, get_dist_path(arch))) def cp_licenses(): - cp_license("x86") - cp_license("x64") - cp_license("arm64") - -def init_flags(): - global DOTNET_KEY_FILE, JAVA_ENABLED, PYTHON_ENABLED, ASSEMBLY_VERSION - mk_util.DOTNET_CORE_ENABLED = True - mk_util.DOTNET_KEY_FILE = DOTNET_KEY_FILE - mk_util.ASSEMBLY_VERSION = ASSEMBLY_VERSION - mk_util.JAVA_ENABLED = JAVA_ENABLED - mk_util.PYTHON_ENABLED = PYTHON_ENABLED - mk_util.ALWAYS_DYNAMIC_BASE = True + global ARCHS + for k in ARCHS: + cp_license(k) +def build_for_arch(arch): + global ARCHS + build_dir = ARCHS[arch] + mk_build_dir(build_dir, arch) + mk_z3(arch) + init_project_def() + mk_dist_dir(arch) + cp_license(arch) + cp_vs_runtime(arch) + if ZIP_BUILD_OUTPUTS: + mk_zip(arch) + # Entry point def main(): if os.name != 'nt': @@ -340,36 +364,13 @@ def main(): parse_options() check_vc_cmd_prompt() - init_flags() if X86ONLY: - mk_build_dir(BUILD_X86_DIR, 'x86') - mk_z3('x86') - init_project_def() - mk_dist_dir('x86') - cp_license('x86') - cp_vs_runtime('x86') - if ZIP_BUILD_OUTPUTS: - mk_zip('x86') + build_for_arch("x86") elif X64ONLY: - mk_build_dir(BUILD_X64_DIR, 'x64') - mk_z3('x64') - init_project_def() - mk_dist_dir('x64') - cp_license('x64') - cp_vs_runtime('x64') - if ZIP_BUILD_OUTPUTS: - mk_zip('x64') - elif ARM64ONLY: # ARM64 build process - mk_build_dir(BUILD_ARM64_DIR, 'arm64') - mk_z3('arm64') - init_project_def() - mk_dist_dir('arm64') - cp_license('arm64') - cp_vs_runtime('arm64') - if ZIP_BUILD_OUTPUTS: - mk_zip('arm64') - + build_for_arch("x64") + elif ARM64ONLY: + build_for_arch("arm64") else: mk_build_dirs() mk_z3s() From dec5715f034048f959e0e868c7844f86d15ee5d1 Mon Sep 17 00:00:00 2001 From: Yisu Remy Wang Date: Thu, 25 Jan 2024 09:49:01 -0800 Subject: [PATCH 125/224] Expose forall and exists to Julia (#7099) --- src/api/julia/z3jl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/julia/z3jl.cpp b/src/api/julia/z3jl.cpp index 5aef2f41d..336a73976 100644 --- a/src/api/julia/z3jl.cpp +++ b/src/api/julia/z3jl.cpp @@ -303,6 +303,8 @@ JLCXX_MODULE define_julia_module(jlcxx::Module &m) m.method("xnor", &xnor); m.method("min", &min); m.method("max", &max); + m.method("exists", static_cast(&exists)); + m.method("forall", static_cast(&forall)); m.method("abs", static_cast(&abs)); m.method("sqrt", static_cast(&sqrt)); m.method("fma", static_cast(&fma)); From 637ffcd491697014e86a35b59b670cc938989631 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 25 Jan 2024 12:23:15 -0800 Subject: [PATCH 126/224] Update mk_win_dist_cmake.py --- scripts/mk_win_dist_cmake.py | 117 ++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 57 deletions(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index 8578af296..08273a33b 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -10,7 +10,18 @@ import os import subprocess import zipfile +import re +import getopt +import sys +import shutil from mk_exception import * +from fnmatch import fnmatch + +def getenv(name, default): + try: + return os.environ[name].strip(' "\'') + except: + return default BUILD_DIR = 'build-dist' BUILD_X64_DIR = os.path.join('build-dist', 'x64') @@ -156,44 +167,55 @@ def get_git_hash(): return ls[0] + # Create a build directory using mk_make.py -def mk_build_dir(path, arch): - if not check_build_dir(path) or FORCE_MK: - subprocess.call(["call", "md", path, "2>NUL"], shell=True) +def mk_build_dir(arch): + global ARCHS + build_path = ARCHS[arch] + install_path = DIST_DIR + if not check_build_dir(build_path) or FORCE_MK: + mk_dir(build_path) if arch == "arm64": arch = "amd64_arm64" - opts0 = ["cd", path] - - opts1 = ['"C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Auxiliary\\Build\\vcvarsall.bat"', arch] - - opts = ["cmake", "-S", "."] + cmds = [] + cmds.append(f"cd {build_path}") + cmds.append(f"call \"C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Auxiliary\\Build\\vcvarsall.bat\" {arch}") + cmd = [] + cmd.append("cmake -S .") if DOTNET_CORE_ENABLED: - opts.append('-DZ3_BUILD_DOTNET_BINDINGS=ON') + cmd.append(' -DZ3_BUILD_DOTNET_BINDINGS=ON') + cmd.append(' -DZ3_INSTALL_DOTNET_BINDINGS=ON') if JAVA_ENABLED: - opts.append('-DZ3_BUILD_JAVA_BINDINGS=ON') + cmd.append(' -DZ3_BUILD_JAVA_BINDINGS=ON') + cmd.append(' -DZ3_INSTALL_JAVA_BINDINGS=ON') + if PYTHON_ENABLED: + cmd.append(' -DZ3_BUILD_PYTHON_BINDINGS=ON') + cmd.append(' -DZ3_INSTALL_PYTHON_BINDINGS=ON') + cmd.append(' -DCMAKE_INSTALL_PYTHON_PKG_DIR=python') + if GIT_HASH: git_hash = get_git_hash() - opts.append('-DGIT_HASH=' + git_hash) - if PYTHON_ENABLED: - opts.append('-DZ3_BUILD_PYTHON_BINDINGS=ON') - opts.append('-DZ3_USE_LIB_GMP=OFF') - opts.append('-DZ3_BUILD_LIBZ3_SHARED=ON') - opts.append('-DCMAKE_INSTALL_PREFIX=' + path) - opts.append('-G "NMake Makefiles"') - opts.append('../..') - args = " ".join(opts0) + "& " + " ".join(opts1) + "& " + " ".join(opts) - print(args) - if subprocess.call(args, shell=True) != 0: - raise MKException("Failed to generate build directory at '%s'" % path) + cmd.append(' -DGIT_HASH=' + git_hash) + cmd.append(' -DZ3_USE_LIB_GMP=OFF') + cmd.append(' -DZ3_BUILD_LIBZ3_SHARED=ON') + cmd.append(' -DCMAKE_BUILD_TYPE=RelWithDebInfo') + cmd.append(' -DCMAKE_INSTALL_PREFIX=' + install_path) + cmd.append(' -G "NMake Makefiles"') + cmd.append(' ../..\n') + cmds.append("".join(cmd)) + print(cmds) + sys.stdout.flush() + if exec_cmds(cmds) != 0: + raise MKException("failed to run commands") # Create build directories def mk_build_dirs(): global ARCHS for k in ARCHS: - mk_build_dir(ARCHS[k], k) + mk_build_dir(k) # Check if on Visual Studio command prompt def check_vc_cmd_prompt(): @@ -222,11 +244,8 @@ def exec_cmds(cmds): return res def get_build_dir(arch): - if arch == 'x64': - return BUILD_X64_DIR - if arch == 'x86': - return BUILD_X86_DIR - return BUILD_ARM64_DIR + global ARCHS + return ARCHS[arch] def mk_z3(arch): build_dir = get_build_dir(arch) @@ -235,7 +254,7 @@ def mk_z3(arch): cmds = [] cmds.append('call "%VCINSTALLDIR%Auxiliary\\build\\vcvarsall.bat" ' + arch + ' ') cmds.append('cd %s' % build_dir) - cmds.append('nmake') + cmds.append('nmake install') if exec_cmds(cmds) != 0: raise MKException("Failed to make z3, x64: %s" % x64) @@ -255,28 +274,16 @@ def get_z3_name(arch): else: return 'z3-%s-%s-win' % (version, arch) -def mk_dist_dir(arch): - build_path = get_build_dir(arch) - dist_path = os.path.join(DIST_DIR, get_z3_name(arch)) - mk_dir(dist_path) - mk_win_dist(build_path, dist_path) - if is_verbose(): - print(f"Generated {platform} distribution folder at '{dist_path}'") - -def mk_dist_dirs(): - global ARCHS - for k in ARCHS: - mk_dist_dir(k) - -def get_dist_path(arch): - return get_z3_name(arch) - + def mk_zip(arch): - dist_path = get_dist_path(arch) + global ARCHS + build_dir = ARCHS[arch] + dist_dir = os.path.join(build_dir, DIST_DIR) + dist_name = get_z3_name(arch) old = os.getcwd() try: - os.chdir(DIST_DIR) - zfname = '%s.zip' % dist_path + os.chdir(dist_dir) + zfname = '%s.zip' % dist_name zipout = zipfile.ZipFile(zfname, 'w', zipfile.ZIP_DEFLATED) for root, dirs, files in os.walk(dist_path): for f in files: @@ -324,8 +331,9 @@ def cp_vs_runtime(arch): if not os.path.isdir(fname): vs_runtime_files.append(fname) if not vs_runtime_files: - raise MKException("Did not find any runtime files to include") - bin_dist_path = os.path.join(DIST_DIR, get_dist_path(arch), 'bin') + raise MKException("Did not find any runtime files to include") + build_dir = get_build_dir(arch) + bin_dist_path = os.path.join(build_dir, DIST_DIR, 'bin') for f in vs_runtime_files: shutil.copy(f, bin_dist_path) if is_verbose(): @@ -337,7 +345,7 @@ def cp_vs_runtimes(): cp_vs_runtime(k) def cp_license(arch): - shutil.copy("LICENSE.txt", os.path.join(DIST_DIR, get_dist_path(arch))) + shutil.copy("LICENSE.txt", os.path.join(DIST_DIR, get_z3_name(arch))) def cp_licenses(): global ARCHS @@ -347,11 +355,8 @@ def cp_licenses(): def build_for_arch(arch): global ARCHS - build_dir = ARCHS[arch] - mk_build_dir(build_dir, arch) + mk_build_dir(arch) mk_z3(arch) - init_project_def() - mk_dist_dir(arch) cp_license(arch) cp_vs_runtime(arch) if ZIP_BUILD_OUTPUTS: @@ -374,8 +379,6 @@ def main(): else: mk_build_dirs() mk_z3s() - init_project_def() - mk_dist_dirs() cp_licenses() cp_vs_runtimes() if ZIP_BUILD_OUTPUTS: From c8c2e3a7b729d7fbcfcbf0d6369a9f8511aaac50 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 25 Jan 2024 15:05:33 -0800 Subject: [PATCH 127/224] update java install/build Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 6 ++++-- scripts/nightly.yaml | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index 08273a33b..c4d691b6f 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -190,6 +190,8 @@ def mk_build_dir(arch): if JAVA_ENABLED: cmd.append(' -DZ3_BUILD_JAVA_BINDINGS=ON') cmd.append(' -DZ3_INSTALL_JAVA_BINDINGS=ON') + cmd.append(' -DZ3_JAVA_JAR_INSTALLDIR=java') + cmd.append(' -DZ3_JAVA_JNI_LIB_INSTALLDIR=java') if PYTHON_ENABLED: cmd.append(' -DZ3_BUILD_PYTHON_BINDINGS=ON') cmd.append(' -DZ3_INSTALL_PYTHON_BINDINGS=ON') @@ -252,11 +254,11 @@ def mk_z3(arch): if arch == "arm64": arch = "x64_arm64" cmds = [] - cmds.append('call "%VCINSTALLDIR%Auxiliary\\build\\vcvarsall.bat" ' + arch + ' ') + cmds.append('call "%VCINSTALLDIR%Auxiliary\\build\\vcvarsall.bat" ' + arch) cmds.append('cd %s' % build_dir) cmds.append('nmake install') if exec_cmds(cmds) != 0: - raise MKException("Failed to make z3, x64: %s" % x64) + raise MKException("Failed to make z3")) def mk_z3s(): global ARCHS diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 968c9dbbb..1915ed996 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -169,7 +169,7 @@ stages: --zip - task: CopyFiles@2 inputs: - sourceFolder: dist + sourceFolder: build-dist/x86/dist contents: '*.zip' targetFolder: $(Build.ArtifactStagingDirectory) - task: PublishPipelineArtifact@1 @@ -179,7 +179,7 @@ stages: - task: CopyFiles@2 displayName: 'Collect Symbols' inputs: - sourceFolder: dist + sourceFolder: build-dist/x86/dist contents: '**/*.pdb' targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' # Publish symbol archive to match nuget package @@ -209,7 +209,7 @@ stages: --zip - task: CopyFiles@2 inputs: - sourceFolder: dist + sourceFolder: build-dist/x64/dist contents: '*.zip' targetFolder: $(Build.ArtifactStagingDirectory) - task: PublishPipelineArtifact@1 @@ -219,7 +219,7 @@ stages: - task: CopyFiles@2 displayName: 'Collect Symbols' inputs: - sourceFolder: dist + sourceFolder: build-dist/x64/dist contents: '**/*.pdb' targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' # Publish symbol archive to match nuget package @@ -249,7 +249,7 @@ stages: --zip - task: CopyFiles@2 inputs: - sourceFolder: dist + sourceFolder: build-dist/arm64/dist contents: '*.zip' targetFolder: $(Build.ArtifactStagingDirectory) - task: PublishPipelineArtifact@1 @@ -259,7 +259,7 @@ stages: - task: CopyFiles@2 displayName: 'Collect Symbols' inputs: - sourceFolder: dist + sourceFolder: build-dist/arm64/dist contents: '**/*.pdb' targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' # Publish symbol archive to match nuget package From 527f824adff5715b112d14b748ae4a37a5726d6a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 25 Jan 2024 15:07:54 -0800 Subject: [PATCH 128/224] update java install/build Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index c4d691b6f..54d4bfd0f 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -258,7 +258,7 @@ def mk_z3(arch): cmds.append('cd %s' % build_dir) cmds.append('nmake install') if exec_cmds(cmds) != 0: - raise MKException("Failed to make z3")) + raise MKException("Failed to make z3") def mk_z3s(): global ARCHS From 2af1cff11f495bd07b97a0ecc1a663390372a0f0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 27 Jan 2024 16:29:19 -0800 Subject: [PATCH 129/224] updating java cmake scrip Signed-off-by: Nikolaj Bjorner --- src/api/java/CMakeLists.txt | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/api/java/CMakeLists.txt b/src/api/java/CMakeLists.txt index 9501de3eb..39ca1e76e 100644 --- a/src/api/java/CMakeLists.txt +++ b/src/api/java/CMakeLists.txt @@ -204,11 +204,13 @@ add_custom_target(build_z3_java_bindings # Rule to build ``com.microsoft.z3.jar`` # TODO: Should we set ``CMAKE_JNI_TARGET`` to ``TRUE``? +# REMARK: removed VERSION to fix issue with using this to create installations. + add_jar(z3JavaJar SOURCES ${Z3_JAVA_JAR_SOURCE_FILES_FULL_PATH} OUTPUT_NAME ${Z3_JAVA_PACKAGE_NAME} OUTPUT_DIR "${PROJECT_BINARY_DIR}" - VERSION "${Z3_VERSION}" +# VERSION "${Z3_VERSION}" ) ############################################################################### @@ -219,21 +221,22 @@ if (Z3_INSTALL_JAVA_BINDINGS) # Provide cache variables for the install locations that the user can change. # This defaults to ``/usr/local/java`` which seems to be the location for ``.jar`` # files on Linux distributions - set(Z3_JAVA_JAR_INSTALLDIR - "${CMAKE_INSTALL_DATAROOTDIR}/java" - CACHE - PATH - "Directory to install Z3 Java jar file relative to install prefix" - ) - # FIXME: I don't think this the right installation location - set(Z3_JAVA_JNI_LIB_INSTALLDIR - "${CMAKE_INSTALL_LIBDIR}" - CACHE - PATH - "Directory to install Z3 Java JNI bridge library relative to install prefix" - ) + if (NOT Z3_JAVA_JAR_INSTALLDIR) + set(Z3_JAVA_JAR_INSTALLDIR + "${CMAKE_INSTALL_DATAROOTDIR}/java" + CACHE + PATH + "Directory to install Z3 Java jar file relative to install prefix" + ) + endif() + if (NOT Z3_JAVA_JNI_LIB_INSTALLDIR) + set(Z3_JAVA_JNI_LIB_INSTALLDIR + "${CMAKE_INSTALL_LIBDIR}" + CACHE + PATH + "Directory to install Z3 Java JNI bridge library relative to install prefix" + ) + endif() install(TARGETS z3java DESTINATION "${Z3_JAVA_JNI_LIB_INSTALLDIR}") - # Note: Don't use ``DESTINATION`` here as the version of ``UseJava.cmake`` shipped - # with CMake 2.8.12.2 handles that incorrectly. install_jar(z3JavaJar "${Z3_JAVA_JAR_INSTALLDIR}") endif() From f8a3b6f5212b68565f3227448482dd4add8eaea5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 27 Jan 2024 17:05:48 -0800 Subject: [PATCH 130/224] fix #7102 --- src/model/model_evaluator.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index 9cef0472f..f4d8e369e 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -20,6 +20,7 @@ Revision History: #include "ast/ast_util.h" #include "ast/for_each_expr.h" #include "ast/recfun_decl_plugin.h" +#include "ast/polymorphism_util.h" #include "ast/rewriter/rewriter_types.h" #include "ast/rewriter/bool_rewriter.h" #include "ast/rewriter/arith_rewriter.h" @@ -371,7 +372,7 @@ struct evaluator_cfg : public default_rewriter_cfg { bool get_macro(func_decl * f, expr * & def, quantifier * & , proof * &) { func_interp * fi = m_model.get_func_interp(f); def = nullptr; - if (fi != nullptr) { + if (fi) { if (fi->is_partial()) { if (m_model_completion) { sort * s = f->get_range(); @@ -384,6 +385,24 @@ struct evaluator_cfg : public default_rewriter_cfg { def = fi->get_interp(); SASSERT(def != nullptr); } + else if (f->is_polymorphic() && (fi = m_model.get_func_interp(m.poly_root(f)))) { + if (fi->is_partial()) { + if (m_model_completion) { + sort * s = f->get_range(); + expr * val = m_model.get_some_value(s); + fi->set_else(val); + } + else + return false; + } + def = fi->get_interp(); + polymorphism::substitution subst(m); + polymorphism::util util(m); + util.unify(f, m.poly_root(f), subst); + def = subst(def); + SASSERT(def != nullptr); + + } else if (m_model_completion && (f->get_family_id() == null_family_id || m.get_plugin(f->get_family_id())->is_considered_uninterpreted(f))) { From 2b683941b78e4003b9406a9ec235b1dfabf7d00d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 27 Jan 2024 17:46:23 -0800 Subject: [PATCH 131/224] fix #7103 --- src/smt/theory_special_relations.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 6203df103..30eac685d 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -893,11 +893,17 @@ namespace smt { func_decl* memf, *nextf, *connectedf; - std::string member, next, connected_sym; - unsigned index = r.decl()->get_parameter(0).get_int(); - member = "member" + std::to_string(index); - next = "next" + std::to_string(index); - connected_sym = "connected" + std::to_string(index); + std::string member, next, connected_sym, id; + auto const& pa = r.decl()->get_parameter(0); + if (pa.is_int()) + id = std::to_string(pa.get_int()); + else if (pa.is_ast() && is_func_decl(pa.get_ast())) + id = to_func_decl(pa.get_ast())->get_name().str(); + else + throw default_exception("expected an integer or function declaration"); + member = "member" + id; + next = "next" + id; + connected_sym = "connected" + id; { sort* dom[2] = { s, listS }; recfun::promise_def mem = p.ensure_def(symbol(member), 2, dom, m.mk_bool_sort(), true); From 908aaa06f7dbc31fb2fb206600ede6535fef81c1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Jan 2024 12:26:51 -0800 Subject: [PATCH 132/224] fix #7101 --- src/model/model_evaluator.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp index f4d8e369e..6f218934b 100644 --- a/src/model/model_evaluator.cpp +++ b/src/model/model_evaluator.cpp @@ -172,18 +172,20 @@ struct evaluator_cfg : public default_rewriter_cfg { struct has_redex {}; struct has_redex_finder { - array_util& au; - has_redex_finder(array_util& au): au(au) {} + evaluator_cfg& ev; + has_redex_finder(evaluator_cfg& ev): ev(ev) {} void operator()(var* v) {} void operator()(quantifier* q) {} void operator()(app* a) { - if (au.is_as_array(a->get_decl())) + if (ev.m_ar.is_as_array(a->get_decl())) throw has_redex(); - if (au.get_manager().is_eq(a)) + if (ev.m_ar.get_manager().is_eq(a)) + throw has_redex(); + if (ev.m_fpau.is_fp(a)) throw has_redex(); } }; - has_redex_finder ha(m_ar); + has_redex_finder ha(*this); try { for_each_expr(ha, e); } From 4be8b7d88c8640897cad1aa39c904139908a812d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Jan 2024 18:47:29 -0800 Subject: [PATCH 133/224] update win-dist Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 162 +++++++++++++++++++---------------- scripts/nightly.yaml | 12 +-- 2 files changed, 92 insertions(+), 82 deletions(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index 54d4bfd0f..146656f52 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -24,25 +24,24 @@ def getenv(name, default): return default BUILD_DIR = 'build-dist' -BUILD_X64_DIR = os.path.join('build-dist', 'x64') -BUILD_X86_DIR = os.path.join('build-dist', 'x86') -BUILD_ARM64_DIR = os.path.join('build-dist', 'arm64') # ARM64 build directory -VERBOSE = True DIST_DIR = 'dist' +BUILD_X64_DIR = os.path.join(BUILD_DIR, 'x64') +BUILD_X86_DIR = os.path.join(BUILD_DIR, 'x86') +BUILD_ARM64_DIR = os.path.join(BUILD_DIR, 'arm64') +VERBOSE = True FORCE_MK = False ASSEMBLY_VERSION = None DOTNET_CORE_ENABLED = True DOTNET_KEY_FILE = None JAVA_ENABLED = True +JULIA_ENABLED = False ZIP_BUILD_OUTPUTS = False GIT_HASH = False PYTHON_ENABLED = True X86ONLY = False X64ONLY = False -ARM64ONLY = False # ARM64 flag -MAKEJOBS = getenv("MAKEJOBS", "24") - -ARCHS = [] +ARM64ONLY = False +ARCHITECTURES = [] def set_verbose(flag): global VERBOSE @@ -53,15 +52,40 @@ def is_verbose(): def mk_dir(d): if not os.path.exists(d): + if is_verbose(): + print("Make directory", d) os.makedirs(d) +def get_z3_name(arch): + version = "4" + if ASSEMBLY_VERSION: + version = ASSEMBLY_VERSION + print("Assembly version:", version) + if GIT_HASH: + return 'z3-%s.%s-%s-win' % (version, get_git_hash(), arch) + else: + return 'z3-%s-%s-win' % (version, arch) + +def get_build_dir(arch): + return ARCHITECTURES[arch] + +def get_build_dist_path(arch): + return os.path.join(get_build_dir(arch), DIST_DIR) + +def get_bin_path(arch): + return os.path.join(get_build_dist_path(arch), "bin") + +def get_dist_path(arch): + return os.path.join(DIST_DIR, arch) + + def set_build_dir(path): - global BUILD_DIR, BUILD_X86_DIR, BUILD_X64_DIR, BUILD_ARM64_DIR, ARCHS + global BUILD_DIR, BUILD_X86_DIR, BUILD_X64_DIR, BUILD_ARM64_DIR, ARCHITECTURES BUILD_DIR = os.path.expanduser(os.path.normpath(path)) BUILD_X86_DIR = os.path.join(path, 'x86') BUILD_X64_DIR = os.path.join(path, 'x64') BUILD_ARM64_DIR = os.path.join(path, 'arm64') # Set ARM64 build directory - ARCHS = {'x64': BUILD_X64_DIR, 'x86':BUILD_X86_DIR, 'arm64':BUILD_ARM64_DIR} + ARCHITECTURES = {'x64': BUILD_X64_DIR, 'x86':BUILD_X86_DIR, 'arm64':BUILD_ARM64_DIR} mk_dir(BUILD_X86_DIR) mk_dir(BUILD_X64_DIR) mk_dir(BUILD_ARM64_DIR) @@ -81,6 +105,7 @@ def display_help(): print(" --dotnet-key= strongname sign the .NET assembly with the private key in .") print(" --nojava do not include Java bindings in the binary distribution files.") print(" --nopython do not include Python bindings in the binary distribution files.") + print(" --julia build Julia bindings.") print(" --zip package build outputs in zip file.") print(" --githash include git hash in the Zip file.") print(" --x86-only x86 dist only.") @@ -90,7 +115,7 @@ def display_help(): # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, ZIP_BUILD_OUTPUTS, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, ASSEMBLY_VERSION, PYTHON_ENABLED, X86ONLY, X64ONLY, ARM64ONLY + global FORCE_MK, JAVA_ENABLED, JULIA_ENABLED, ZIP_BUILD_OUTPUTS, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, ASSEMBLY_VERSION, PYTHON_ENABLED, X86ONLY, X64ONLY, ARM64ONLY path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', @@ -103,6 +128,7 @@ def parse_options(): 'zip', 'githash', 'nopython', + 'julia', 'x86-only', 'x64-only', 'arm64-only' @@ -128,6 +154,8 @@ def parse_options(): DOTNET_KEY_FILE = arg elif opt == '--nojava': JAVA_ENABLED = False + elif opt == '--julia': + JULIA_ENABLED = True elif opt == '--zip': ZIP_BUILD_OUTPUTS = True elif opt == '--githash': @@ -170,18 +198,19 @@ def get_git_hash(): # Create a build directory using mk_make.py def mk_build_dir(arch): - global ARCHS - build_path = ARCHS[arch] - install_path = DIST_DIR + build_path = get_build_dir(arch) if not check_build_dir(build_path) or FORCE_MK: mk_dir(build_path) - if arch == "arm64": arch = "amd64_arm64" cmds = [] + if JULIA_ENABLED: + cmds.append('julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\"))"') + cmds.append('julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))" > tmp.env') + cmds.append('set /P JlCxxDir= Date: Mon, 29 Jan 2024 19:32:31 -0800 Subject: [PATCH 134/224] special purpose dotnet copy Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index 146656f52..e75d5a616 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -215,7 +215,7 @@ def mk_build_dir(arch): cmd.append("cmake -S .") if DOTNET_CORE_ENABLED: cmd.append(' -DZ3_BUILD_DOTNET_BINDINGS=ON') - cmd.append(' -DZ3_INSTALL_DOTNET_BINDINGS=ON') +# cmd.append(' -DZ3_INSTALL_DOTNET_BINDINGS=ON') if JAVA_ENABLED: cmd.append(' -DZ3_BUILD_JAVA_BINDINGS=ON') cmd.append(' -DZ3_INSTALL_JAVA_BINDINGS=ON') @@ -273,9 +273,9 @@ def exec_cmds(cmds): -def mk_z3(arch): +def build_z3(arch): if is_verbose(): - print("mk z3") + print("build z3") build_dir = get_build_dir(arch) if arch == "arm64": arch = "x64_arm64" @@ -360,6 +360,17 @@ def cp_license(arch): mk_dir(path) shutil.copy("LICENSE.txt", path) +def cp_dotnet(arch): + if not DOTNET_CORE_ENABLED: + return + if is_verbose(): + print("copy dotnet") + build_dir = get_build_dir(arch) + dist_dir = get_build_dist_path(arch) + shutil.copytree(os.path.join(build_dir, "Microsoft.Z3"), + os.path.join(dist_dir, "Microsoft.Z3"), + dirs_exist_ok=True) + def cp_pdb(arch): if is_verbose(): print("copy pdb") @@ -372,9 +383,10 @@ def cp_pdb(arch): def build_for_arch(arch): mk_build_dir(arch) - mk_z3(arch) + build_z3(arch) cp_license(arch) cp_pdb(arch) + cp_dotnet(arch) cp_vs_runtime(arch) mk_zip(arch) From f7ed4adfbb77c2c23c2890f68a9e3303d324fb1e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Jan 2024 19:47:05 -0800 Subject: [PATCH 135/224] update path for win distributions Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index e75d5a616..cd58bbc8b 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -69,10 +69,13 @@ def get_z3_name(arch): def get_build_dir(arch): return ARCHITECTURES[arch] -def get_build_dist_path(arch): +def get_build_dist(arch): return os.path.join(get_build_dir(arch), DIST_DIR) -def get_bin_path(arch): +def get_build_dist_path(arch): + return os.path.join(get_build_dir(arch), DIST_DIR, get_z3_name(arch)) + +def get_bin_dist_path(arch): return os.path.join(get_build_dist_path(arch), "bin") def get_dist_path(arch): @@ -234,7 +237,7 @@ def mk_build_dir(arch): cmd.append(' -DZ3_USE_LIB_GMP=OFF') cmd.append(' -DZ3_BUILD_LIBZ3_SHARED=ON') cmd.append(' -DCMAKE_BUILD_TYPE=RelWithDebInfo') - cmd.append(' -DCMAKE_INSTALL_PREFIX=' + DIST_DIR) + cmd.append(' -DCMAKE_INSTALL_PREFIX=' + os.path.join(DIST_DIR, get_z3_name(arch))) cmd.append(' -G "Ninja"') cmd.append(' ../..\n') cmds.append("".join(cmd)) @@ -302,7 +305,7 @@ def mk_zip(arch): mk_dir(dist_path) zfname = os.path.join(dist_path, '%s.zip' % dist_name) zipout = zipfile.ZipFile(zfname, 'w', zipfile.ZIP_DEFLATED) - os.chdir(build_dist) + os.chdir(get_build_dist(arch)) for root, dirs, files in os.walk("."): for f in files: if is_verbose(): @@ -347,7 +350,7 @@ def cp_vs_runtime(arch): vs_runtime_files.append(fname) if not vs_runtime_files: raise MKException("Did not find any runtime files to include") - bin_dist_path = get_bin_path(arch) + bin_dist_path = get_bin_dist_path(arch) for f in vs_runtime_files: shutil.copy(f, bin_dist_path) if is_verbose(): @@ -375,7 +378,7 @@ def cp_pdb(arch): if is_verbose(): print("copy pdb") build_dir = get_build_dir(arch) - bin_path = get_bin_path(arch) + bin_path = get_bin_dist_path(arch) mk_dir(bin_path) for f in os.listdir(build_dir): if f.endswith("pdb"): From 9bd8e355818f73392945c52d40485a87e462f3f6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2024 10:07:38 -0800 Subject: [PATCH 136/224] adapt paths to new distribution Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_task.py | 11 +++++++++-- scripts/mk_win_dist_cmake.py | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/scripts/mk_nuget_task.py b/scripts/mk_nuget_task.py index 58251c6f8..be6dd203b 100644 --- a/scripts/mk_nuget_task.py +++ b/scripts/mk_nuget_task.py @@ -78,8 +78,15 @@ def unpack(packages, symbols, arch): if symbols: files += ["Microsoft.Z3.pdb", "Microsoft.Z3.xml"] for b in files: - zip_ref.extract(f"{package_dir}/bin/{b}", f"{tmp}") - replace(f"{tmp}/{package_dir}/bin/{b}", f"out/lib/netstandard2.0/{b}") + file = f"{package_dir}/bin/{b}" + if os.path.exists(file): + zip_ref.extract(file, f"{tmp}") + replace(f"{tmp}/{package_dir}/bin/{b}", f"out/lib/netstandard2.0/{b}") + file = os.path.join(file,"netstandard2.0") + if os.path.exists(file): + zip_ref.extract(file, f"{tmp}") + replace(f"{tmp}/{package_dir}/bin/netstandard2.0/{b}", f"out/lib/netstandard2.0/{b}") + def mk_targets(source_root): mk_dir("out/build") diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index cd58bbc8b..d99f364e1 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -369,9 +369,9 @@ def cp_dotnet(arch): if is_verbose(): print("copy dotnet") build_dir = get_build_dir(arch) - dist_dir = get_build_dist_path(arch) + dist_dir = get_bin_dist_path(arch) shutil.copytree(os.path.join(build_dir, "Microsoft.Z3"), - os.path.join(dist_dir, "Microsoft.Z3"), + dist_dir, dirs_exist_ok=True) def cp_pdb(arch): From b3b95dbc5cba6ef2780730984ccf68be75b675e4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2024 11:06:27 -0800 Subject: [PATCH 137/224] move installation directories to under bin Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index d99f364e1..b27b6892f 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -223,11 +223,11 @@ def mk_build_dir(arch): cmd.append(' -DZ3_BUILD_JAVA_BINDINGS=ON') cmd.append(' -DZ3_INSTALL_JAVA_BINDINGS=ON') cmd.append(' -DZ3_JAVA_JAR_INSTALLDIR=java') - cmd.append(' -DZ3_JAVA_JNI_LIB_INSTALLDIR=java') + cmd.append(' -DZ3_JAVA_JNI_LIB_INSTALLDIR=bin/java') if PYTHON_ENABLED: cmd.append(' -DZ3_BUILD_PYTHON_BINDINGS=ON') cmd.append(' -DZ3_INSTALL_PYTHON_BINDINGS=ON') - cmd.append(' -DCMAKE_INSTALL_PYTHON_PKG_DIR=python') + cmd.append(' -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python') if JULIA_ENABLED: cmd.append(' -DJlCxx_DIR=%JlCxxDir%\\..\\lib\\cmake\\JlCxx') From 680b0f523ff41d14f09a25abe598f64e6479ee57 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2024 12:32:09 -0800 Subject: [PATCH 138/224] add download stage for arm64 Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index f89f82f18..1c3245ea4 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -581,6 +581,11 @@ stages: inputs: artifactName: 'Windows64' targetPath: tmp + - task: DownloadPipelineArtifact@2 + displayName: "Download windowsARM64" + inputs: + artifactName: 'WindowsArm64' + targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download Mac" inputs: From e0bed3bcfac8cf5e1b1086dd5b32f425e5117fa5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2024 13:26:22 -0800 Subject: [PATCH 139/224] build Julia for x64 Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 1c3245ea4..c8c2c34e6 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -205,6 +205,7 @@ stages: python scripts\mk_win_dist_cmake.py --assembly-version=$(AssemblyVersion) --x64-only + --julia --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --zip - task: CopyFiles@2 From 5d4303f2689c865b184384743d0a220914b095fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2024 13:27:16 -0800 Subject: [PATCH 140/224] build Julia for x64 Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index c8c2c34e6..e746a6be0 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -205,7 +205,7 @@ stages: python scripts\mk_win_dist_cmake.py --assembly-version=$(AssemblyVersion) --x64-only - --julia + --julia --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --zip - task: CopyFiles@2 From f81180173b0ecf6fa5ffc54c9243c6603bf957e0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2024 14:41:10 -0800 Subject: [PATCH 141/224] remove optional Julia build Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 1 + scripts/nightly.yaml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index b27b6892f..38707e50b 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -230,6 +230,7 @@ def mk_build_dir(arch): cmd.append(' -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python') if JULIA_ENABLED: cmd.append(' -DJlCxx_DIR=%JlCxxDir%\\..\\lib\\cmake\\JlCxx') + cmd.append(' -DZ3_BUILD_JULIA_BINDINGS=True') if GIT_HASH: git_hash = get_git_hash() diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index e746a6be0..1c3245ea4 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -205,7 +205,6 @@ stages: python scripts\mk_win_dist_cmake.py --assembly-version=$(AssemblyVersion) --x64-only - --julia --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --zip - task: CopyFiles@2 From 67e5ba9f7983cf0787526253457759eea672b624 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2024 14:53:59 -0800 Subject: [PATCH 142/224] update release scripts Signed-off-by: Nikolaj Bjorner --- scripts/build-win-signed.yml | 8 ++++---- scripts/release.yml | 20 +++++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/scripts/build-win-signed.yml b/scripts/build-win-signed.yml index f1e08958d..bae692c52 100644 --- a/scripts/build-win-signed.yml +++ b/scripts/build-win-signed.yml @@ -19,7 +19,7 @@ jobs: inputs: script: call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{parameters.BuildArchitecture}} && - python scripts\mk_win_dist.py + python scripts\mk_win_dist_cmake.py --${{parameters.BuildArchitecture}}-only --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - task: CopyFiles@2 @@ -42,7 +42,7 @@ jobs: displayName: Sign inputs: ConnectedServiceName: 'z3-esrp-signing-2' - FolderPath: 'dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' + FolderPath: 'dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' Pattern: 'Microsoft.Z3.dll,libz3.dll,libz3java.dll,z3.exe' signConfigType: 'inlineSignParams' inlineOperation: | @@ -82,12 +82,12 @@ jobs: - task: DeleteFiles@1 displayName: Cleanup inputs: - SourceFolder: 'dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' + SourceFolder: 'dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' Contents: 'CodeSignSummary*' - task: ArchiveFiles@2 displayName: Zip inputs: - rootFolderOrFile: 'dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win' + rootFolderOrFile: 'dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win' includeRootFolder: true archiveType: 'zip' archiveFile: '$(Build.ArtifactStagingDirectory)/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win.zip' diff --git a/scripts/release.yml b/scripts/release.yml index c146a85fd..317aff429 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -209,6 +209,11 @@ stages: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'x86' + - template: build-win-signed.yml + parameters: + ReleaseVersion: $(ReleaseVersion) + BuildArchitecture: 'arm64' + # Creates Z3 packages in various formats - stage: Package @@ -525,16 +530,21 @@ stages: inputs: artifact: 'WindowsBuild-x86' path: $(Agent.TempDirectory) - - task: DownloadPipelineArtifact@2 - displayName: "Download Python" - inputs: - artifactName: 'PythonPackage' - path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 displayName: 'Download Win64 Build' inputs: artifact: 'WindowsBuild-x64' path: $(Agent.TempDirectory) + - task: DownloadPipelineArtifact@2 + displayName: 'Download Arm64 Build' + inputs: + artifact: 'WindowsBuild-arm64' + path: $(Agent.TempDirectory) + - task: DownloadPipelineArtifact@2 + displayName: "Download Python" + inputs: + artifactName: 'PythonPackage' + path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 displayName: 'Download NuGet64 Package' inputs: From 28c44a6ed0661a0f128bebc22d7d57eaab6ec390 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2024 15:41:14 -0800 Subject: [PATCH 143/224] fix #7105 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 2 +- src/api/python/z3/z3printer.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index b3b4351ab..2f34b91f6 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -9069,7 +9069,7 @@ def AtMost(*args): def AtLeast(*args): - """Create an at-most Pseudo-Boolean k constraint. + """Create an at-least Pseudo-Boolean k constraint. >>> a, b, c = Bools('a b c') >>> f = AtLeast(a, b, c, 2) diff --git a/src/api/python/z3/z3printer.py b/src/api/python/z3/z3printer.py index df50aa9b9..2da5f89da 100644 --- a/src/api/python/z3/z3printer.py +++ b/src/api/python/z3/z3printer.py @@ -99,6 +99,7 @@ _z3_op_to_str = { Z3_OP_ARRAY_EXT: "Ext", Z3_OP_PB_AT_MOST: "AtMost", + Z3_OP_PB_AT_LEAST: "AtLeast", Z3_OP_PB_LE: "PbLe", Z3_OP_PB_GE: "PbGe", Z3_OP_PB_EQ: "PbEq", @@ -1111,6 +1112,10 @@ class Formatter: k = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0) return seq1(self.pp_name(a), [seq3([self.pp_expr(ch, d + 1, xs) for ch in a.children()]), to_format(k)]) + def pp_atleast(self, a, d, f, xs): + k = Z3_get_decl_int_parameter(a.ctx_ref(), a.decl().ast, 0) + return seq1(self.pp_name(a), [seq3([self.pp_expr(ch, d + 1, xs) for ch in a.children()]), to_format(k)]) + def pp_pbcmp(self, a, d, f, xs): chs = a.children() rchs = range(len(chs)) @@ -1163,6 +1168,8 @@ class Formatter: return self.pp_K(a, d, xs) elif k == Z3_OP_PB_AT_MOST: return self.pp_atmost(a, d, f, xs) + elif k == Z3_OP_PB_AT_LEAST: + return self.pp_atleast(a, d, f, xs) elif k == Z3_OP_PB_LE: return self.pp_pbcmp(a, d, f, xs) elif k == Z3_OP_PB_GE: From 99ebbd634156f8618d138df5afdb8e2f3a08f803 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2024 16:28:52 -0800 Subject: [PATCH 144/224] porting unix distribution script to cmake Signed-off-by: Nikolaj Bjorner --- scripts/mk_unix_dist_cmake.py | 268 ++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 scripts/mk_unix_dist_cmake.py diff --git a/scripts/mk_unix_dist_cmake.py b/scripts/mk_unix_dist_cmake.py new file mode 100644 index 000000000..3a38ad65b --- /dev/null +++ b/scripts/mk_unix_dist_cmake.py @@ -0,0 +1,268 @@ +############################################ +# Copyright (c) 2013 Microsoft Corporation +# +# Scripts for automatically generating +# Linux/OSX/BSD distribution zip files. +# +# Author: Leonardo de Moura (leonardo) +############################################ + +import os +import subprocess +import zipfile +import re +import getopt +import sys +import shutil +from mk_exception import * +from fnmatch import fnmatch + +def getenv(name, default): + try: + return os.environ[name].strip(' "\'') + except: + return default + +BUILD_DIR = 'build-dist' +DIST_DIR = 'dist' +VERBOSE = True +FORCE_MK = False +ASSEMBLY_VERSION = None +DOTNET_CORE_ENABLED = True +DOTNET_KEY_FILE = None +JAVA_ENABLED = True +JULIA_ENABLED = False +GIT_HASH = False +PYTHON_ENABLED = True +ARM64 = False +MAKEJOBS = getenv("MAKEJOBS", "24") + +def set_verbose(flag): + global VERBOSE + VERBOSE = flag + +def is_verbose(): + return VERBOSE + +def mk_dir(d): + if not os.path.exists(d): + if is_verbose(): + print("Make directory", d) + os.makedirs(d) + +def get_z3_name(): + version = "4" + if ASSEMBLY_VERSION: + version = ASSEMBLY_VERSION + print("Assembly version:", version) + if GIT_HASH: + return 'z3-%s.%s' % (version, get_git_hash()) + else: + return 'z3-%s' % (version) + +def get_build_dir(): + return BUILD_DIR + +def get_build_dist(): + return os.path.join(get_build_dir(), DIST_DIR) + +def get_build_dist_path(): + return os.path.join(get_build_dist(), get_z3_name()) + +def set_build_dir(path): + global BUILD_DIR + BUILD_DIR = os.path.expanduser(os.path.normpath(path)) + mk_dir(BUILD_DIR) + +def display_help(): + print("mk_unix_dist_cmake.py: Z3 Unix distribution generator\n") + print("This script generates the zip files containing executables, shared objects, header files for Unix.") + print("It must be executed from the Z3 root directory.") + print("\nOptions:") + print(" -h, --help display this message.") + print(" -s, --silent do not print verbose messages.") + print(" -b , --build= subdirectory where Z3 will be built (default: build-dist).") + print(" -f, --force force script to regenerate Makefiles.") + print(" --version= release version.") + print(" --assembly-version assembly version for dll") + print(" --nodotnet do not include .NET bindings in the binary distribution files.") + print(" --dotnet-key= strongname sign the .NET assembly with the private key in .") + print(" --nojava do not include Java bindings in the binary distribution files.") + print(" --nopython do not include Python bindings in the binary distribution files.") + print(" --julia build Julia bindings.") + print(" --githash include git hash in the Zip file.") + print(" --arm64 build for ARM64 architecture.") + exit(0) + +# Parse configuration option for mk_make script +def parse_options(): + global FORCE_MK, JAVA_ENABLED, JULIA_ENABLED, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, ASSEMBLY_VERSION, PYTHON_ENABLED, ARM64 + path = BUILD_DIR + options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', + 'help', + 'silent', + 'force', + 'nojava', + 'nodotnet', + 'dotnet-key=', + 'assembly-version=', + 'githash', + 'nopython', + 'julia', + 'arm64' + ]) + for opt, arg in options: + if opt in ('-b', '--build'): + if arg == 'src': + raise MKException('The src directory should not be used to host the Makefile') + path = arg + elif opt in ('-s', '--silent'): + set_verbose(False) + elif opt in ('-h', '--help'): + display_help() + elif opt in ('-f', '--force'): + FORCE_MK = True + elif opt == '--nodotnet': + DOTNET_CORE_ENABLED = False + elif opt == '--assembly-version': + ASSEMBLY_VERSION = arg + elif opt == '--nopython': + PYTHON_ENABLED = False + elif opt == '--dotnet-key': + DOTNET_KEY_FILE = arg + elif opt == '--nojava': + JAVA_ENABLED = False + elif opt == '--julia': + JULIA_ENABLED = True + elif opt == '--githash': + GIT_HASH = True + elif opt == '--arm64': + ARM64 = True + else: + raise MKException("Invalid command line option '%s'" % opt) + set_build_dir(path) + +def check_output(cmd): + out = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0] + if out != None: + enc = sys.getdefaultencoding() + if enc != None: return out.decode(enc).rstrip('\r\n') + else: return out.rstrip('\r\n') + else: + return "" + +def get_git_hash(): + try: + branch = check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']) + r = check_output(['git', 'show-ref', '--abbrev=12', 'refs/heads/%s' % branch]) + except: + raise MKException("Failed to retrieve git hash") + ls = r.split(' ') + if len(ls) != 2: + raise MKException("Unexpected git output " + r) + return ls[0] + +# Create a build directory using CMake +def mk_build_dir(): + build_path = get_build_dir() + if not os.path.exists(build_path) or FORCE_MK: + mk_dir(build_path) + cmds = [] + cmds.append(f"cd {build_path}") + cmd = [] + cmd.append("cmake -S .") + if DOTNET_CORE_ENABLED: + cmd.append(' -DZ3_BUILD_DOTNET_BINDINGS=ON') + if JAVA_ENABLED: + cmd.append(' -DZ3_BUILD_JAVA_BINDINGS=ON') + cmd.append(' -DZ3_INSTALL_JAVA_BINDINGS=ON') + cmd.append(' -DZ3_JAVA_JAR_INSTALLDIR=java') + cmd.append(' -DZ3_JAVA_JNI_LIB_INSTALLDIR=bin/java') + if PYTHON_ENABLED: + cmd.append(' -DZ3_BUILD_PYTHON_BINDINGS=ON') + cmd.append(' -DZ3_INSTALL_PYTHON_BINDINGS=ON') + cmd.append(' -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python') + if JULIA_ENABLED: + cmd.append(' -DZ3_BUILD_JULIA_BINDINGS=ON') + cmd.append(' -DZ3_INSTALL_JULIA_BINDINGS=ON') + if GIT_HASH: + git_hash = get_git_hash() + cmd.append(' -DGIT_HASH=' + git_hash) + cmd.append(' -DZ3_USE_LIB_GMP=OFF') + cmd.append(' -DZ3_BUILD_LIBZ3_SHARED=ON') + cmd.append(' -DCMAKE_BUILD_TYPE=RelWithDebInfo') + cmd.append(' -DCMAKE_INSTALL_PREFIX=' + get_build_dist_path()) + cmd.append(' -G "Ninja"') + cmd.append(' ..\n') + cmds.append("".join(cmd)) + print("CMAKE commands:", cmds) + sys.stdout.flush() + if exec_cmds(cmds) != 0: + raise MKException("failed to run commands") + +def exec_cmds(cmds): + cmd_file = 'z3_tmp.sh' + f = open(cmd_file, 'w') + for cmd in cmds: + f.write(cmd) + f.write('\n') + f.close() + res = 0 + try: + res = subprocess.call(['sh', cmd_file]) + except: + res = 1 + try: + os.remove(cmd_file) + except: + pass + return res + +def build_z3(): + if is_verbose(): + print("build z3") + build_dir = get_build_dir() + cmds = [] + cmds.append('cd %s' % build_dir) + cmds.append('ninja install') + if exec_cmds(cmds) != 0: + raise MKException("Failed to make z3") + +def mk_zip(): + build_dist = get_build_dist_path() + dist_name = get_z3_name() + old = os.getcwd() + try: + if is_verbose(): + print("dist path", build_dist) + mk_dir(build_dist) + zfname = '%s.zip' % dist_name + zipout = zipfile.ZipFile(zfname, 'w', zipfile.ZIP_DEFLATED) + os.chdir(get_build_dist()) + for root, dirs, files in os.walk("."): + for f in files: + if is_verbose(): + print("adding ", os.path.join(root, f)) + zipout.write(os.path.join(root, f)) + if is_verbose(): + print("Generated '%s'" % zfname) + except: + pass + os.chdir(old) + +def cp_license(): + if is_verbose(): + print("copy licence") + path = get_build_dist_path() + mk_dir(path) + shutil.copy("LICENSE.txt", path) + +# Entry point +def main(): + parse_options() + mk_build_dir() + build_z3() + cp_license() + mk_zip() + +main() From 50deece29e2de6d3e77ebca2118b92a363f8da52 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2024 20:38:01 -0800 Subject: [PATCH 145/224] fix #7098 --- src/smt/smt_context_pp.cpp | 2 +- src/smt/theory_pb.cpp | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 4842f6e23..57875a8bd 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -132,7 +132,7 @@ namespace smt { void context::display_literal_info(std::ostream & out, literal l) const { smt::display_compact(out, l, m_bool_var2expr.data()); - display_literal_smt2(out, l); + display_literal_smt2(out << " " << l << ": ", l); out << "relevant: " << is_relevant(bool_var2expr(l.var())) << ", val: " << get_assignment(l) << "\n"; } diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 718d5c65a..25c8e7195 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1807,7 +1807,7 @@ namespace smt { bool theory_pb::resolve_conflict(card& c, literal_vector const& confl) { - TRACE("pb", display(tout, c, true); ); + TRACE("pb", display(tout << "resolve conflict\n", c, true); ); bool_var v; m_conflict_lvl = 0; @@ -1839,8 +1839,19 @@ namespace smt { literal conseq = ~confl[2]; int bound = 1; + auto clear_marks = [&]() { + while (m_num_marks > 0 && idx > 0) { + v = lits[idx].var(); + if (ctx.is_marked(v)) { + ctx.unset_mark(v); + } + --idx; + } + }; + while (m_num_marks > 0) { + TRACE("pb", tout << "conseq: " << conseq << "\n"); v = conseq.var(); int offset = get_abs_coeff(v); @@ -1850,13 +1861,7 @@ namespace smt { } SASSERT(validate_lemma()); if (offset > 1000) { - while (m_num_marks > 0 && idx > 0) { - v = lits[idx].var(); - if (ctx.is_marked(v)) { - ctx.unset_mark(v); - } - --idx; - } + clear_marks(); return false; } @@ -1884,8 +1889,11 @@ namespace smt { clause& cls = *js.get_clause(); justification* cjs = cls.get_justification(); unsigned num_lits = cls.get_num_literals(); - if (cjs && typeid(smt::unit_resolution_justification) == typeid(*cjs)) - ; + CTRACE("pb", cjs, tout << (typeid(smt::unit_resolution_justification) == typeid(*cjs)) << "\n"); + if (cjs && typeid(smt::unit_resolution_justification) == typeid(*cjs)) { + clear_marks(); + return false; + } else if (cjs && !is_proof_justification(*cjs)) { TRACE("pb", tout << "not processing justification over: " << conseq << " " << typeid(*cjs).name() << "\n";); break; @@ -1954,7 +1962,8 @@ namespace smt { while (true) { conseq = lits[idx]; v = conseq.var(); - if (ctx.is_marked(v)) break; + if (ctx.is_marked(v)) + break; SASSERT(idx > 0); --idx; } From 738c5b6d0d7314f701f27f13cb966eb76588e312 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2024 21:30:27 -0800 Subject: [PATCH 146/224] add warning messages for #7100 --- src/api/api_config_params.cpp | 10 ++++++++-- src/params/context_params.cpp | 21 +++++++++++++++++---- src/params/context_params.h | 5 +++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/api/api_config_params.cpp b/src/api/api_config_params.cpp index 93d4e27e1..d463b1fb7 100644 --- a/src/api/api_config_params.cpp +++ b/src/api/api_config_params.cpp @@ -98,7 +98,10 @@ extern "C" { LOG_Z3_set_param_value(c, param_id, param_value); try { ast_context_params * p = reinterpret_cast(c); - p->set(param_id, param_value); + if (p->is_shell_only_parameter(param_id)) + warning_msg("parameter %s can only be set for the shell, not binary API", param_id); + else + p->set(param_id, param_value); } catch (z3_exception & ex) { // The error handler is only available for contexts @@ -111,7 +114,10 @@ extern "C" { Z3_TRY; LOG_Z3_update_param_value(c, param_id, param_value); RESET_ERROR_CODE(); - mk_c(c)->params().set(param_id, param_value); + if (mk_c(c)->params().is_shell_only_parameter(param_id)) + warning_msg("parameter %s can only be set for the shell, not binary API", param_id); + else + mk_c(c)->params().set(param_id, param_value); Z3_CATCH; } diff --git a/src/params/context_params.cpp b/src/params/context_params.cpp index fbdd90b8c..1d5d10b39 100644 --- a/src/params/context_params.cpp +++ b/src/params/context_params.cpp @@ -51,15 +51,18 @@ void context_params::set_uint(unsigned & opt, char const * param, char const * v } } -void context_params::set(char const * param, char const * value) { - std::string p = param; - unsigned n = static_cast(p.size()); - for (unsigned i = 0; i < n; i++) { +static void lower_case(std::string& p) { + for (size_t i = 0; i < p.size(); i++) { if (p[i] >= 'A' && p[i] <= 'Z') p[i] = p[i] - 'A' + 'a'; else if (p[i] == '-') p[i] = '_'; } +} + +void context_params::set(char const * param, char const * value) { + std::string p = param; + lower_case(p); if (p == "timeout") { set_uint(m_timeout, param, value); } @@ -195,5 +198,15 @@ void context_params::get_solver_params(params_ref & p, bool & proofs_enabled, bo p.set_bool("auto_config", false); } +bool context_params::is_shell_only_parameter(char const* _p) const { + std::string p(_p); + lower_case(p); + if (p == "dump_models" || p == "well_sorted_check" || + p == "model_validate" || p == "smtlib2_compliant" || + p == "stats") + return true; + + return false; +} diff --git a/src/params/context_params.h b/src/params/context_params.h index ad4cee31d..1f169a5bd 100644 --- a/src/params/context_params.h +++ b/src/params/context_params.h @@ -70,5 +70,10 @@ public: */ params_ref merge_default_params(params_ref const & p); + /** + \brief Is this a parameter that can only be set for the shell. + */ + bool is_shell_only_parameter(char const* p) const; + }; From ac1f9719a433b2874d6121c699fb00d9f61c85cc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 02:25:14 -0800 Subject: [PATCH 147/224] move nightly builds of Unixes to use cmake Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 1c3245ea4..6a92e2baf 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -49,6 +49,7 @@ stages: artifactName: 'Ubuntu-20.04' targetPath: $(Build.ArtifactStagingDirectory) + - job: Ubuntu displayName: "Ubuntu build" pool: @@ -80,6 +81,42 @@ stages: artifactName: 'UbuntuArm64' targetPath: $(Build.ArtifactStagingDirectory) + - job: UbuntuArm64CMAKE + displayName: "Ubuntu ARM64 build - CMAKE" + pool: + vmImage: "ubuntu-latest" + steps: + - script: sudo apt update + - script: sudo apt install gcc-arm-none-eabi -y + - script: sudo apt install gcc-arm-linux-gnueabihf -y + - script: sudo apt install gcc-aarch64-linux-gnu -y + - script: sudo apt install g++-aarch64-linux-gnu -y + - script: | + mkdir dist + CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc cmake + -DCMAKE_BUILD_TYPE=RelWithDebInfo + -DZ3_BUILD_DOTNET_BINDINGS=ON + -DZ3_INSTALL_DOTNET_BINDINGS=ON + -DZ3_BUILD_JAVA_BINDINGS=ON + -DZ3_INSTALL_JAVA_BINDINGS=ON + -DZ3_JAVA_JAR_INSTALL_DIR=bin + -DZ3_AVA_JNI_LIB_INSTALLDI=bin + -DZ3_BUILD_PYTHON_BINDINGS=ON + -DZ3_INSTALL_PYTHON_BINDINGS=ON + -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python + -DZ3_BUILD_LIBZ3_SHARED=ON + -DCMAKE_INSTALL_PREFIX=dist + -G "Ninja" .. + ninja install + - script: | + cd dist + zip bin z3-$(NightlyVersion)-ubuntu-arm64.zip + - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. + - task: PublishPipelineArtifact@0 + inputs: + artifactName: 'UbuntuArm64CMAKE' + targetPath: $(Build.ArtifactStagingDirectory) + - job: UbuntuDoc displayName: "Ubuntu Doc build" pool: @@ -601,6 +638,11 @@ stages: inputs: artifactName: 'UbuntuArm64' targetPath: tmp + - task: DownloadPipelineArtifact@2 + displayName: 'Download Ubuntu ARM64 Build - CMAKE' + inputs: + artifact: 'UbuntuArm64CMAKE' + targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download Ubuntu" inputs: From 4b4e057441fc3d28a73bc1fe4891db093957a458 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 02:31:53 -0800 Subject: [PATCH 148/224] install ninja Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 6a92e2baf..166c7b883 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -91,6 +91,7 @@ stages: - script: sudo apt install gcc-arm-linux-gnueabihf -y - script: sudo apt install gcc-aarch64-linux-gnu -y - script: sudo apt install g++-aarch64-linux-gnu -y + - script: sudo apt install ninja-build -y - script: | mkdir dist CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc cmake From d3fbb9d0c5a286c5194503278ca1b92ccb807b58 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 02:50:53 -0800 Subject: [PATCH 149/224] add line continuations to nightly.yaml Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 166c7b883..69aa87603 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -94,19 +94,19 @@ stages: - script: sudo apt install ninja-build -y - script: | mkdir dist - CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc cmake - -DCMAKE_BUILD_TYPE=RelWithDebInfo - -DZ3_BUILD_DOTNET_BINDINGS=ON - -DZ3_INSTALL_DOTNET_BINDINGS=ON - -DZ3_BUILD_JAVA_BINDINGS=ON - -DZ3_INSTALL_JAVA_BINDINGS=ON - -DZ3_JAVA_JAR_INSTALL_DIR=bin - -DZ3_AVA_JNI_LIB_INSTALLDI=bin - -DZ3_BUILD_PYTHON_BINDINGS=ON - -DZ3_INSTALL_PYTHON_BINDINGS=ON - -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python - -DZ3_BUILD_LIBZ3_SHARED=ON - -DCMAKE_INSTALL_PREFIX=dist + CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc cmake \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo\ + -DZ3_BUILD_DOTNET_BINDINGS=ON\ + -DZ3_INSTALL_DOTNET_BINDINGS=ON \ + -DZ3_BUILD_JAVA_BINDINGS=ON\ + -DZ3_INSTALL_JAVA_BINDINGS=ON\ + -DZ3_JAVA_JAR_INSTALL_DIR=bin\ + -DZ3_AVA_JNI_LIB_INSTALLDI=bin\ + -DZ3_BUILD_PYTHON_BINDINGS=ON\ + -DZ3_INSTALL_PYTHON_BINDINGS=ON\ + -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python\ + -DZ3_BUILD_LIBZ3_SHARED=ON\ + -DCMAKE_INSTALL_PREFIX=dist\ -G "Ninja" .. ninja install - script: | From 5c4ad4fdd7217aa4c086b7cc99a8b37a437b7f07 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 02:57:02 -0800 Subject: [PATCH 150/224] cd to dist in nightly.yaml Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 69aa87603..e28ad8849 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -94,6 +94,7 @@ stages: - script: sudo apt install ninja-build -y - script: | mkdir dist + cd dist CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo\ -DZ3_BUILD_DOTNET_BINDINGS=ON\ @@ -107,11 +108,10 @@ stages: -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python\ -DZ3_BUILD_LIBZ3_SHARED=ON\ -DCMAKE_INSTALL_PREFIX=dist\ - -G "Ninja" .. + -G "Ninja" /.. ninja install - - script: | - cd dist zip bin z3-$(NightlyVersion)-ubuntu-arm64.zip + cd .. - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@0 inputs: From 5551f1e35bc7c40e0218b69cb1a66dfd9e2dec39 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 15:27:02 -0800 Subject: [PATCH 151/224] update nightly Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index e28ad8849..8f637f7a1 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -95,8 +95,9 @@ stages: - script: | mkdir dist cd dist - CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc cmake \ + cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo\ + -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++\ -DZ3_BUILD_DOTNET_BINDINGS=ON\ -DZ3_INSTALL_DOTNET_BINDINGS=ON \ -DZ3_BUILD_JAVA_BINDINGS=ON\ @@ -108,7 +109,7 @@ stages: -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python\ -DZ3_BUILD_LIBZ3_SHARED=ON\ -DCMAKE_INSTALL_PREFIX=dist\ - -G "Ninja" /.. + -G "Ninja" ../ ninja install zip bin z3-$(NightlyVersion)-ubuntu-arm64.zip cd .. From e26344efd7d47e7d3698f35efca72a484564bf63 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 15:27:54 -0800 Subject: [PATCH 152/224] update nightly Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 8f637f7a1..e0f0daae5 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -97,7 +97,7 @@ stages: cd dist cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo\ - -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++\ + -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++\ -DZ3_BUILD_DOTNET_BINDINGS=ON\ -DZ3_INSTALL_DOTNET_BINDINGS=ON \ -DZ3_BUILD_JAVA_BINDINGS=ON\ From e820701f9d0fdd7be96057fec6ec8f178aa275e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 15:38:10 -0800 Subject: [PATCH 153/224] fix #7107 Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 9a9b92393..62c7c8ddd 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4265,9 +4265,11 @@ namespace smt { SASSERT(num_lits == 1); expr * unit = bool_var2expr(lits[0].var()); bool unit_sign = lits[0].sign(); + while (m.is_not(unit, unit)) + unit_sign = !unit_sign; m_units_to_reassert.push_back(unit); m_units_to_reassert_sign.push_back(unit_sign); - TRACE("reassert_units", tout << "asserting #" << unit->get_id() << " " << unit_sign << " @ " << m_scope_lvl << "\n";); + TRACE("reassert_units", tout << "asserting " << mk_pp(unit, m) << " #" << unit->get_id() << " " << unit_sign << " @ " << m_scope_lvl << "\n";); } m_conflict_resolution->release_lemma_atoms(); From 9a095cc9e62650cfa985fab398637d208a82d6c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 16:31:28 -0800 Subject: [PATCH 154/224] Update nightly.yaml for Azure Pipelines --- scripts/nightly.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index e0f0daae5..f70bdb5d0 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -93,8 +93,6 @@ stages: - script: sudo apt install g++-aarch64-linux-gnu -y - script: sudo apt install ninja-build -y - script: | - mkdir dist - cd dist cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo\ -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++\ @@ -111,9 +109,8 @@ stages: -DCMAKE_INSTALL_PREFIX=dist\ -G "Ninja" ../ ninja install - zip bin z3-$(NightlyVersion)-ubuntu-arm64.zip - cd .. - - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. + zip -r z3-$(NightlyVersion)-ubuntu-arm64.zip dist + - script: cp *.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@0 inputs: artifactName: 'UbuntuArm64CMAKE' From f16afe55d64031c551b13a9adf1e1acc2a9106eb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 16:34:53 -0800 Subject: [PATCH 155/224] Update nightly.yaml for Azure Pipelines --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index f70bdb5d0..97fcca775 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -107,7 +107,7 @@ stages: -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python\ -DZ3_BUILD_LIBZ3_SHARED=ON\ -DCMAKE_INSTALL_PREFIX=dist\ - -G "Ninja" ../ + -G "Ninja" . ninja install zip -r z3-$(NightlyVersion)-ubuntu-arm64.zip dist - script: cp *.zip $(Build.ArtifactStagingDirectory)/. From 0a1a57cf01769fd400860bd72ec6a9ecd50f50bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 17:08:17 -0800 Subject: [PATCH 156/224] Update nightly.yaml for Azure Pipelines --- scripts/nightly.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 97fcca775..05def3a5f 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -93,6 +93,8 @@ stages: - script: sudo apt install g++-aarch64-linux-gnu -y - script: sudo apt install ninja-build -y - script: | + mkdir build + cd build cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo\ -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++\ @@ -107,10 +109,11 @@ stages: -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python\ -DZ3_BUILD_LIBZ3_SHARED=ON\ -DCMAKE_INSTALL_PREFIX=dist\ - -G "Ninja" . + -G "Ninja" ../ ninja install zip -r z3-$(NightlyVersion)-ubuntu-arm64.zip dist - - script: cp *.zip $(Build.ArtifactStagingDirectory)/. + cd .. + - script: cp build/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@0 inputs: artifactName: 'UbuntuArm64CMAKE' From d624eec9765b3e80794a1e5b9122da3a2f1acbda Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 17:41:53 -0800 Subject: [PATCH 157/224] Update nightly.yaml --- scripts/nightly.yaml | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 05def3a5f..6a8babeef 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -81,21 +81,26 @@ stages: artifactName: 'UbuntuArm64' targetPath: $(Build.ArtifactStagingDirectory) - - job: UbuntuArm64CMAKE - displayName: "Ubuntu ARM64 build - CMAKE" + - job: UbuntuBuilds + displayName: "Ubuntu Builds" pool: vmImage: "ubuntu-latest" + strategy: + matrix: + arm64: + setupcmds: 'sudo apt update& sudo apt install gcc-arm-none-eabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu ninja-build -y' + buildenv: 'CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc' + arch: 'arm64' + x64: + setupcmds: 'sudo apt update& sudo apt install ninja-build -y' + buildenv: '' + arch: 'x64' steps: - - script: sudo apt update - - script: sudo apt install gcc-arm-none-eabi -y - - script: sudo apt install gcc-arm-linux-gnueabihf -y - - script: sudo apt install gcc-aarch64-linux-gnu -y - - script: sudo apt install g++-aarch64-linux-gnu -y - - script: sudo apt install ninja-build -y + - script: $(setupcmds) - script: | - mkdir build - cd build - cmake \ + mkdir $(arch) + cd $(arch) + $(buildenv) cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo\ -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++\ -DZ3_BUILD_DOTNET_BINDINGS=ON\ @@ -111,12 +116,13 @@ stages: -DCMAKE_INSTALL_PREFIX=dist\ -G "Ninja" ../ ninja install + zip -r z3-$(NightlyVersion)-ubuntu-arm64.zip dist cd .. - - script: cp build/*.zip $(Build.ArtifactStagingDirectory)/. + - script: cp $(arch)/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@0 inputs: - artifactName: 'UbuntuArm64CMAKE' + artifactName: 'ubuntu-builds' targetPath: $(Build.ArtifactStagingDirectory) - job: UbuntuDoc @@ -641,9 +647,9 @@ stages: artifactName: 'UbuntuArm64' targetPath: tmp - task: DownloadPipelineArtifact@2 - displayName: 'Download Ubuntu ARM64 Build - CMAKE' + displayName: 'Download Ubuntu Builds' inputs: - artifact: 'UbuntuArm64CMAKE' + artifact: 'ubuntu-builds' targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download Ubuntu" From 432432be9c8cc154fd84c9cbae873ad910f867c3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 17:58:05 -0800 Subject: [PATCH 158/224] update ubuntu builds Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 6a8babeef..c0d17696c 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -91,10 +91,12 @@ stages: setupcmds: 'sudo apt update& sudo apt install gcc-arm-none-eabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu ninja-build -y' buildenv: 'CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc' arch: 'arm64' + name: 'z3-$(NightlyVersion)-ubuntu-arm64' x64: setupcmds: 'sudo apt update& sudo apt install ninja-build -y' buildenv: '' arch: 'x64' + name: 'z3-$(NightlyVersion)-ubuntu-x64' steps: - script: $(setupcmds) - script: | @@ -107,17 +109,16 @@ stages: -DZ3_INSTALL_DOTNET_BINDINGS=ON \ -DZ3_BUILD_JAVA_BINDINGS=ON\ -DZ3_INSTALL_JAVA_BINDINGS=ON\ - -DZ3_JAVA_JAR_INSTALL_DIR=bin\ - -DZ3_AVA_JNI_LIB_INSTALLDI=bin\ + -DZ3_JAVA_JAR_INSTALLDIR=bin\ + -DZ3_JAVA_JNI_LIB_INSTALLDIR=bin\ -DZ3_BUILD_PYTHON_BINDINGS=ON\ -DZ3_INSTALL_PYTHON_BINDINGS=ON\ -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python\ -DZ3_BUILD_LIBZ3_SHARED=ON\ - -DCMAKE_INSTALL_PREFIX=dist\ + -DCMAKE_INSTALL_PREFIX=$(name)\ -G "Ninja" ../ ninja install - - zip -r z3-$(NightlyVersion)-ubuntu-arm64.zip dist + zip -r $(name).zip $(name) cd .. - script: cp $(arch)/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@0 From 85072974b992b16c0fa7dacc7f6e15f41fd9217f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 19:05:27 -0800 Subject: [PATCH 159/224] update ubuntu builds Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index c0d17696c..e69b097a9 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -92,11 +92,13 @@ stages: buildenv: 'CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc' arch: 'arm64' name: 'z3-$(NightlyVersion)-ubuntu-arm64' + compiler: 'aarch64-linux-gnu-g++-11' x64: setupcmds: 'sudo apt update& sudo apt install ninja-build -y' buildenv: '' arch: 'x64' name: 'z3-$(NightlyVersion)-ubuntu-x64' + compiler: 'g++' steps: - script: $(setupcmds) - script: | @@ -104,7 +106,7 @@ stages: cd $(arch) $(buildenv) cmake \ -DCMAKE_BUILD_TYPE=RelWithDebInfo\ - -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++\ + -DCMAKE_CXX_COMPILER=$(compiler)\ -DZ3_BUILD_DOTNET_BINDINGS=ON\ -DZ3_INSTALL_DOTNET_BINDINGS=ON \ -DZ3_BUILD_JAVA_BINDINGS=ON\ From ec6640d7939dab2f1088557032805ebfec922d47 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 31 Jan 2024 19:47:52 -0800 Subject: [PATCH 160/224] Update nightly.yaml --- scripts/nightly.yaml | 79 +++++--------------------------------------- 1 file changed, 9 insertions(+), 70 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index e69b097a9..d0745010f 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -49,38 +49,6 @@ stages: artifactName: 'Ubuntu-20.04' targetPath: $(Build.ArtifactStagingDirectory) - - - job: Ubuntu - displayName: "Ubuntu build" - pool: - vmImage: "ubuntu-latest" - steps: - - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - - script: git clone https://github.com/z3prover/z3test z3test - - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - - task: PublishPipelineArtifact@0 - inputs: - artifactName: 'Ubuntu' - targetPath: $(Build.ArtifactStagingDirectory) - - - job: UbuntuArm64 - displayName: "Ubuntu ARM64 build" - pool: - vmImage: "ubuntu-latest" - steps: - - script: sudo apt update - - script: sudo apt install gcc-arm-none-eabi -y - - script: sudo apt install gcc-arm-linux-gnueabihf -y - - script: sudo apt install gcc-aarch64-linux-gnu -y - - script: sudo apt install g++-aarch64-linux-gnu -y - - script: CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 - - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - - task: PublishPipelineArtifact@0 - inputs: - artifactName: 'UbuntuArm64' - targetPath: $(Build.ArtifactStagingDirectory) - - job: UbuntuBuilds displayName: "Ubuntu Builds" pool: @@ -125,7 +93,7 @@ stages: - script: cp $(arch)/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@0 inputs: - artifactName: 'ubuntu-builds' + artifactName: 'ubuntu-$(arch)' targetPath: $(Build.ArtifactStagingDirectory) - job: UbuntuDoc @@ -182,25 +150,6 @@ stages: artifactName: '$(name)Build' targetPath: $(Build.ArtifactStagingDirectory) -# - job: MuslLinuxBuild -# condition: eq(0,1) -# variables: -# python: "/opt/python/cp310-cp310/bin/python" -# name: MuslLinux -# displayName: "MuslLinux build" -# pool: -# vmImage: "ubuntu-latest" -# container: "quay.io/pypa/musllinux_1_1_x86_64:latest" -# steps: -# - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava -# - script: git clone https://github.com/z3prover/z3test z3test -# - script: $(python) z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 -# - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/ -# - task: PublishPipelineArtifact@0 -# inputs: -# artifactName: '$(name)Build' -# targetPath: $(Build.ArtifactStagingDirectory) - - job: Windows32 displayName: "Windows 32-bit build" pool: @@ -341,11 +290,6 @@ stages: inputs: artifact: 'Windows64' path: $(Agent.TempDirectory)\package - - task: DownloadPipelineArtifact@2 - displayName: 'Download Ubuntu Build' - inputs: - artifact: 'Ubuntu' - path: $(Agent.TempDirectory)\package - task: DownloadPipelineArtifact@2 displayName: 'Download Ubuntu 20.04 Build' inputs: @@ -354,8 +298,13 @@ stages: - task: DownloadPipelineArtifact@2 displayName: 'Download Ubuntu ARM64 Build' inputs: - artifact: 'UbuntuArm64' + artifact: 'ubuntu-arm64' path: $(Agent.TempDirectory)\package + - task: DownloadPipelineArtifact@2 + displayName: 'Download Ubuntu Build' + inputs: + artifact: 'ubuntu-x64' + path: $(Agent.TempDirectory)\package - task: DownloadPipelineArtifact@2 displayName: 'Download macOS Build' inputs: @@ -577,11 +526,6 @@ stages: inputs: artifactName: 'ManyLinuxBuild' targetPath: $(Agent.TempDirectory) -# - task: DownloadPipelineArtifact@2 -# displayName: 'Download MuslLinux Build' -# inputs: -# artifact: 'MuslLinuxBuild' -# path: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: artifactName: 'Mac' @@ -647,17 +591,12 @@ stages: - task: DownloadPipelineArtifact@2 displayName: "Download Ubuntu Arm64" inputs: - artifactName: 'UbuntuArm64' - targetPath: tmp - - task: DownloadPipelineArtifact@2 - displayName: 'Download Ubuntu Builds' - inputs: - artifact: 'ubuntu-builds' + artifactName: 'ubuntu-arm64' targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download Ubuntu" inputs: - artifactName: 'Ubuntu' + artifactName: 'ubuntu-x64' targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download Ubuntu-20.04" From ca0e9a1526e7f97d6728e806e3f2f9e61636b306 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2024 04:54:32 -0800 Subject: [PATCH 161/224] remove explicit option for shared build, set to Release mode. .so artifacts take 800MB in distribution Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index d0745010f..8683523f5 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -73,7 +73,7 @@ stages: mkdir $(arch) cd $(arch) $(buildenv) cmake \ - -DCMAKE_BUILD_TYPE=RelWithDebInfo\ + -DCMAKE_BUILD_TYPE=Release\ -DCMAKE_CXX_COMPILER=$(compiler)\ -DZ3_BUILD_DOTNET_BINDINGS=ON\ -DZ3_INSTALL_DOTNET_BINDINGS=ON \ @@ -84,7 +84,6 @@ stages: -DZ3_BUILD_PYTHON_BINDINGS=ON\ -DZ3_INSTALL_PYTHON_BINDINGS=ON\ -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python\ - -DZ3_BUILD_LIBZ3_SHARED=ON\ -DCMAKE_INSTALL_PREFIX=$(name)\ -G "Ninja" ../ ninja install From 5cac9b84e4b4ce3b16f7d43a3e65efcd1c74bc39 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2024 09:36:52 -0800 Subject: [PATCH 162/224] fix build warnings Signed-off-by: Nikolaj Bjorner --- src/math/lp/column.h | 1 - src/qe/qsat.cpp | 1 - src/sat/smt/q_solver.cpp | 1 - src/smt/theory_seq.cpp | 1 - 4 files changed, 4 deletions(-) diff --git a/src/math/lp/column.h b/src/math/lp/column.h index 4f3e68966..1b2d1f2e5 100644 --- a/src/math/lp/column.h +++ b/src/math/lp/column.h @@ -45,7 +45,6 @@ class column { u_dependency* m_lower_bound_witness = nullptr; u_dependency* m_upper_bound_witness = nullptr; bool m_associated_with_row = false; - lpvar m_j; //the column index lar_term* m_term = nullptr; public: lar_term* term() const { return m_term; } diff --git a/src/qe/qsat.cpp b/src/qe/qsat.cpp index 720614573..dc0613c59 100644 --- a/src/qe/qsat.cpp +++ b/src/qe/qsat.cpp @@ -1014,7 +1014,6 @@ namespace qe { case AST_APP: { app* a = to_app(e); expr_ref_vector args(m); - unsigned num_args = a->get_num_args(); bool all_visited = true; for (expr* arg : *a) { if (visited.find(arg, r)) { diff --git a/src/sat/smt/q_solver.cpp b/src/sat/smt/q_solver.cpp index aec106072..ed6cb643b 100644 --- a/src/sat/smt/q_solver.cpp +++ b/src/sat/smt/q_solver.cpp @@ -120,7 +120,6 @@ namespace q { } sat::literal solver::instantiate(quantifier* _q, bool negate, std::function& mk_var) { - sat::literal sk; expr_ref tmp(m); quantifier_ref q(_q, m); expr_ref_vector vars(m); diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index d27d7ba54..0d16120b1 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -1270,7 +1270,6 @@ bool theory_seq::solve_nc(unsigned idx) { expr_ref c(m); expr* a = nullptr, *b = nullptr; VERIFY(m_util.str.is_contains(n.contains(), a, b)); - literal pre, cnt, ctail, emp; lbool is_gt = ctx.get_assignment(len_gt); TRACE("seq", ctx.display_literal_smt2(tout << len_gt << " := " << is_gt << "\n", len_gt) << "\n";); From 28d62bfedb39787aaac09c197826de661c311cd1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2024 14:26:01 -0800 Subject: [PATCH 163/224] move to use release.yml version for windows build Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 8683523f5..3d59a11d7 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -149,7 +149,13 @@ stages: artifactName: '$(name)Build' targetPath: $(Build.ArtifactStagingDirectory) + - template: build-win-signed.yml + parameters: + ReleaseVersion: $(ReleaseVersion) + BuildArchitecture: 'x86' + - job: Windows32 + condition: eq(0, 1) displayName: "Windows 32-bit build" pool: vmImage: "windows-latest" @@ -416,7 +422,7 @@ stages: - task: DownloadPipelineArtifact@2 displayName: 'Download Win32 Build' inputs: - artifact: 'Windows32' + artifact: 'WindowsBuild-x86' path: $(Agent.TempDirectory)\package - task: NuGetToolInstaller@0 inputs: From 06466be999a48be0fd889f5d1a344e6a4161dd5a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2024 16:41:14 -0800 Subject: [PATCH 164/224] disable arm64 nightly Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 3d59a11d7..3b6479a3e 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -55,12 +55,12 @@ stages: vmImage: "ubuntu-latest" strategy: matrix: - arm64: - setupcmds: 'sudo apt update& sudo apt install gcc-arm-none-eabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu ninja-build -y' - buildenv: 'CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc' - arch: 'arm64' - name: 'z3-$(NightlyVersion)-ubuntu-arm64' - compiler: 'aarch64-linux-gnu-g++-11' +# arm64: +# setupcmds: 'sudo apt update& sudo apt install gcc-arm-none-eabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu ninja-build -y' +# buildenv: 'CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc' +# arch: 'arm64' +# name: 'z3-$(NightlyVersion)-ubuntu-arm64' +# compiler: 'aarch64-linux-gnu-g++-11' x64: setupcmds: 'sudo apt update& sudo apt install ninja-build -y' buildenv: '' From bd2d96eacba6af3f7766fe58770fd2f71eddcd08 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2024 20:16:04 -0800 Subject: [PATCH 165/224] update folder names to align with mk_win_dist_cmake Signed-off-by: Nikolaj Bjorner --- scripts/build-win-signed.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/build-win-signed.yml b/scripts/build-win-signed.yml index bae692c52..4f20b5332 100644 --- a/scripts/build-win-signed.yml +++ b/scripts/build-win-signed.yml @@ -25,7 +25,7 @@ jobs: - task: CopyFiles@2 displayName: 'Collect Symbols' inputs: - sourceFolder: dist + sourceFolder: build-dist/${{parameters.BuildArchitecture}}/ contents: '**/*.pdb' targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' # Publish symbol archive to match nuget package @@ -35,14 +35,14 @@ jobs: symbolsFolder: '$(Build.ArtifactStagingDirectory)/symbols' searchPattern: '**/*.pdb' indexSources: false # Github sources not supported - publishSymbols: true + publishSymbols: true. symbolServerType: TeamServices detailedLog: true - task: EsrpCodeSigning@2 displayName: Sign inputs: ConnectedServiceName: 'z3-esrp-signing-2' - FolderPath: 'dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' + FolderPath: 'build-dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' Pattern: 'Microsoft.Z3.dll,libz3.dll,libz3java.dll,z3.exe' signConfigType: 'inlineSignParams' inlineOperation: | @@ -82,12 +82,12 @@ jobs: - task: DeleteFiles@1 displayName: Cleanup inputs: - SourceFolder: 'dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' + SourceFolder: 'build-dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' Contents: 'CodeSignSummary*' - task: ArchiveFiles@2 displayName: Zip inputs: - rootFolderOrFile: 'dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win' + rootFolderOrFile: 'build-dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win' includeRootFolder: true archiveType: 'zip' archiveFile: '$(Build.ArtifactStagingDirectory)/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win.zip' From 77b98d5b02c2f0ffe5411b3c09ff26c830f2b832 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2024 20:54:36 -0800 Subject: [PATCH 166/224] update folder names to align with mk_win_dist_cmake Signed-off-by: Nikolaj Bjorner --- scripts/build-win-signed.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build-win-signed.yml b/scripts/build-win-signed.yml index 4f20b5332..5ebf71f6a 100644 --- a/scripts/build-win-signed.yml +++ b/scripts/build-win-signed.yml @@ -26,7 +26,7 @@ jobs: displayName: 'Collect Symbols' inputs: sourceFolder: build-dist/${{parameters.BuildArchitecture}}/ - contents: '**/*.pdb' + contents: '*.pdb' targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' # Publish symbol archive to match nuget package # Index your source code and publish symbols to a file share or Azure Artifacts symbol server From 93cbcd00bd460812b3623518957c5b604e3b50ab Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2024 21:42:21 -0800 Subject: [PATCH 167/224] rename Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 3b6479a3e..f019fb508 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -59,13 +59,13 @@ stages: # setupcmds: 'sudo apt update& sudo apt install gcc-arm-none-eabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu ninja-build -y' # buildenv: 'CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc' # arch: 'arm64' -# name: 'z3-$(NightlyVersion)-ubuntu-arm64' +# name: 'z3-$(AssemblyVersion)-arm64-ubuntu' # compiler: 'aarch64-linux-gnu-g++-11' x64: setupcmds: 'sudo apt update& sudo apt install ninja-build -y' buildenv: '' arch: 'x64' - name: 'z3-$(NightlyVersion)-ubuntu-x64' + name: 'z3-$(AssemblyVersion)-x64-ubuntu' compiler: 'g++' steps: - script: $(setupcmds) From d231913c04d1e947ccc34ddd476267601d5d7c2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2024 21:44:59 -0800 Subject: [PATCH 168/224] remove period Signed-off-by: Nikolaj Bjorner --- scripts/build-win-signed.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build-win-signed.yml b/scripts/build-win-signed.yml index 5ebf71f6a..71b25c371 100644 --- a/scripts/build-win-signed.yml +++ b/scripts/build-win-signed.yml @@ -35,7 +35,7 @@ jobs: symbolsFolder: '$(Build.ArtifactStagingDirectory)/symbols' searchPattern: '**/*.pdb' indexSources: false # Github sources not supported - publishSymbols: true. + publishSymbols: true symbolServerType: TeamServices detailedLog: true - task: EsrpCodeSigning@2 From 30c14f533edf359b27a9ba536f597af79f4a29b1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2024 22:39:21 -0800 Subject: [PATCH 169/224] include variable ReleaseVersion in Nightly Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index f019fb508..4000da737 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -2,6 +2,7 @@ variables: Major: '4' Minor: '12' Patch: '6' + ReleaseVersion: $(Major).$(Minor).$(Patch) AssemblyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId) NightlyVersion: $(AssemblyVersion)-$(Build.DefinitionName) From 426020639131761351153bf6824ce09d90abcce6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2024 23:16:18 -0800 Subject: [PATCH 170/224] include variable ReleaseVersion in Nightly Signed-off-by: Nikolaj Bjorner --- scripts/build-win-signed.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build-win-signed.yml b/scripts/build-win-signed.yml index 71b25c371..778a0bba0 100644 --- a/scripts/build-win-signed.yml +++ b/scripts/build-win-signed.yml @@ -21,6 +21,7 @@ jobs: call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{parameters.BuildArchitecture}} && python scripts\mk_win_dist_cmake.py --${{parameters.BuildArchitecture}}-only + --assembly-version=${{parameters.ReleaseVersion}} --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - task: CopyFiles@2 displayName: 'Collect Symbols' From 0d24ec361340510768cf5ed3b2764c816d60b26d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Feb 2024 09:45:38 -0800 Subject: [PATCH 171/224] add 'dist' to folder path Signed-off-by: Nikolaj Bjorner --- scripts/build-win-signed.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/build-win-signed.yml b/scripts/build-win-signed.yml index 778a0bba0..cdc896ca7 100644 --- a/scripts/build-win-signed.yml +++ b/scripts/build-win-signed.yml @@ -43,7 +43,7 @@ jobs: displayName: Sign inputs: ConnectedServiceName: 'z3-esrp-signing-2' - FolderPath: 'build-dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' + FolderPath: 'build-dist/${{parameters.BuildArchitecture}}/dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' Pattern: 'Microsoft.Z3.dll,libz3.dll,libz3java.dll,z3.exe' signConfigType: 'inlineSignParams' inlineOperation: | @@ -83,12 +83,12 @@ jobs: - task: DeleteFiles@1 displayName: Cleanup inputs: - SourceFolder: 'build-dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' + SourceFolder: 'build-dist/${{parameters.BuildArchitecture}}/dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' Contents: 'CodeSignSummary*' - task: ArchiveFiles@2 displayName: Zip inputs: - rootFolderOrFile: 'build-dist/${{parameters.BuildArchitecture}}/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win' + rootFolderOrFile: 'build-dist/${{parameters.BuildArchitecture}}/dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win' includeRootFolder: true archiveType: 'zip' archiveFile: '$(Build.ArtifactStagingDirectory)/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win.zip' From 2280e9562af30da2f1fa93990b6b92687d601647 Mon Sep 17 00:00:00 2001 From: Yisu Remy Wang Date: Fri, 2 Feb 2024 09:46:31 -0800 Subject: [PATCH 172/224] Improve instructions for working with the Julia API (#7108) --- src/api/julia/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/julia/README.md b/src/api/julia/README.md index ec4b1e109..12e846191 100644 --- a/src/api/julia/README.md +++ b/src/api/julia/README.md @@ -14,7 +14,10 @@ make ## Julia part -The Z3 binaries are provided to [Z3.jl](https://github.com/ahumenberger/Z3.jl) via [z3_jll.jl](https://github.com/JuliaBinaryWrappers/z3_jll.jl). That is, in order to release a new Z3 version one has to update the corresponding [build script](https://github.com/JuliaPackaging/Yggdrasil/tree/master/Z/z3) which triggers a new version of z3_jll.jl. +The Z3 binaries are provided to [Z3.jl](https://github.com/ahumenberger/Z3.jl) via [z3_jll.jl](https://github.com/JuliaBinaryWrappers/z3_jll.jl). +That is, in order to propagate any C++ changes to the Julia side, one has to: +1. Release a new version of Z3. +2. Update the corresponding [build script](https://github.com/JuliaPackaging/Yggdrasil/tree/master/Z/z3) to use the new Z3 release. ### Using the compiled version of Z3 From 9db834c223ceda1a06bc32326763bfe391a6978f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Feb 2024 09:56:39 -0800 Subject: [PATCH 173/224] add back legacy build-win-signed Signed-off-by: Nikolaj Bjorner --- scripts/build-win-signed-cmake.yml | 98 ++++++++++++++++++++++++++++++ scripts/build-win-signed.yml | 13 ++-- scripts/nightly.yaml | 2 +- 3 files changed, 105 insertions(+), 8 deletions(-) create mode 100644 scripts/build-win-signed-cmake.yml diff --git a/scripts/build-win-signed-cmake.yml b/scripts/build-win-signed-cmake.yml new file mode 100644 index 000000000..cdc896ca7 --- /dev/null +++ b/scripts/build-win-signed-cmake.yml @@ -0,0 +1,98 @@ +parameters: + ReleaseVersion: '' + BuildArchitecture: '' + +jobs: +- job: WindowsBuild${{parameters.BuildArchitecture}} + displayName: "Windows build (${{parameters.BuildArchitecture}})" + pool: + vmImage: "windows-latest" + steps: + - powershell: write-host $(System.TeamProjectId) + displayName: 'System.TeamProjectId' + - powershell: write-host $(System.DefinitionId) + displayName: 'System.DefinitionId' + - powershell: write-host $(Build.BuildId) + displayName: 'Build.BuildId' + - task: CmdLine@2 + displayName: Build + inputs: + script: + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{parameters.BuildArchitecture}} && + python scripts\mk_win_dist_cmake.py + --${{parameters.BuildArchitecture}}-only + --assembly-version=${{parameters.ReleaseVersion}} + --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk + - task: CopyFiles@2 + displayName: 'Collect Symbols' + inputs: + sourceFolder: build-dist/${{parameters.BuildArchitecture}}/ + contents: '*.pdb' + targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' + # Publish symbol archive to match nuget package + # Index your source code and publish symbols to a file share or Azure Artifacts symbol server + - task: PublishSymbols@2 + inputs: + symbolsFolder: '$(Build.ArtifactStagingDirectory)/symbols' + searchPattern: '**/*.pdb' + indexSources: false # Github sources not supported + publishSymbols: true + symbolServerType: TeamServices + detailedLog: true + - task: EsrpCodeSigning@2 + displayName: Sign + inputs: + ConnectedServiceName: 'z3-esrp-signing-2' + FolderPath: 'build-dist/${{parameters.BuildArchitecture}}/dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' + Pattern: 'Microsoft.Z3.dll,libz3.dll,libz3java.dll,z3.exe' + signConfigType: 'inlineSignParams' + inlineOperation: | + [ + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolSign", + "parameters": [ + { + "parameterName": "OpusName", + "parameterValue": "Microsoft" + }, + { + "parameterName": "OpusInfo", + "parameterValue": "http://www.microsoft.com" + }, + { + "parameterName": "PageHash", + "parameterValue": "/NPH" + }, + { + "parameterName": "FileDigest", + "parameterValue": "/fd sha256" + }, + { + "parameterName": "TimeStamp", + "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + ], + "toolName": "signtool.exe", + "toolVersion": "6.2.9304.0" + } + ] + SessionTimeout: '60' + MaxConcurrency: '50' + MaxRetryAttempts: '5' + - task: DeleteFiles@1 + displayName: Cleanup + inputs: + SourceFolder: 'build-dist/${{parameters.BuildArchitecture}}/dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' + Contents: 'CodeSignSummary*' + - task: ArchiveFiles@2 + displayName: Zip + inputs: + rootFolderOrFile: 'build-dist/${{parameters.BuildArchitecture}}/dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win' + includeRootFolder: true + archiveType: 'zip' + archiveFile: '$(Build.ArtifactStagingDirectory)/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win.zip' + - task: PublishPipelineArtifact@1 + inputs: + targetPath: '$(Build.ArtifactStagingDirectory)/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win.zip' + artifactName: 'WindowsBuild-${{parameters.BuildArchitecture}}' \ No newline at end of file diff --git a/scripts/build-win-signed.yml b/scripts/build-win-signed.yml index cdc896ca7..f1e08958d 100644 --- a/scripts/build-win-signed.yml +++ b/scripts/build-win-signed.yml @@ -19,15 +19,14 @@ jobs: inputs: script: call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{parameters.BuildArchitecture}} && - python scripts\mk_win_dist_cmake.py + python scripts\mk_win_dist.py --${{parameters.BuildArchitecture}}-only - --assembly-version=${{parameters.ReleaseVersion}} --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - task: CopyFiles@2 displayName: 'Collect Symbols' inputs: - sourceFolder: build-dist/${{parameters.BuildArchitecture}}/ - contents: '*.pdb' + sourceFolder: dist + contents: '**/*.pdb' targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' # Publish symbol archive to match nuget package # Index your source code and publish symbols to a file share or Azure Artifacts symbol server @@ -43,7 +42,7 @@ jobs: displayName: Sign inputs: ConnectedServiceName: 'z3-esrp-signing-2' - FolderPath: 'build-dist/${{parameters.BuildArchitecture}}/dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' + FolderPath: 'dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' Pattern: 'Microsoft.Z3.dll,libz3.dll,libz3java.dll,z3.exe' signConfigType: 'inlineSignParams' inlineOperation: | @@ -83,12 +82,12 @@ jobs: - task: DeleteFiles@1 displayName: Cleanup inputs: - SourceFolder: 'build-dist/${{parameters.BuildArchitecture}}/dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' + SourceFolder: 'dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win/bin' Contents: 'CodeSignSummary*' - task: ArchiveFiles@2 displayName: Zip inputs: - rootFolderOrFile: 'build-dist/${{parameters.BuildArchitecture}}/dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win' + rootFolderOrFile: 'dist/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win' includeRootFolder: true archiveType: 'zip' archiveFile: '$(Build.ArtifactStagingDirectory)/z3-${{parameters.ReleaseVersion}}-${{parameters.BuildArchitecture}}-win.zip' diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 4000da737..7d9faf474 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -150,7 +150,7 @@ stages: artifactName: '$(name)Build' targetPath: $(Build.ArtifactStagingDirectory) - - template: build-win-signed.yml + - template: build-win-signed-cmake.yml parameters: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'x86' From 485a018c59c7c3faada92ffe6bf1761987b0eca6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Feb 2024 09:57:41 -0800 Subject: [PATCH 174/224] add back legacy build-win-signed Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index 317aff429..0a6e9de57 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -209,7 +209,7 @@ stages: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'x86' - - template: build-win-signed.yml + - template: build-win-signed-cmake.yml parameters: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'arm64' From 05d625bf0bf711051447d8b0ec5bc2b8b5b7b8b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Feb 2024 11:07:17 -0800 Subject: [PATCH 175/224] fixing paths and re-add arm64 Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 7d9faf474..95ccb0819 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -56,12 +56,12 @@ stages: vmImage: "ubuntu-latest" strategy: matrix: -# arm64: -# setupcmds: 'sudo apt update& sudo apt install gcc-arm-none-eabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu ninja-build -y' -# buildenv: 'CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc' -# arch: 'arm64' -# name: 'z3-$(AssemblyVersion)-arm64-ubuntu' -# compiler: 'aarch64-linux-gnu-g++-11' + arm64: + setupcmds: 'sudo apt update& sudo apt install gcc-arm-none-eabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu ninja-build -y' + buildenv: 'CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc' + arch: 'arm64' + name: 'z3-$(AssemblyVersion)-arm64-ubuntu' + compiler: 'aarch64-linux-gnu-g++-11' x64: setupcmds: 'sudo apt update& sudo apt install ninja-build -y' buildenv: '' @@ -178,7 +178,7 @@ stages: - task: PublishPipelineArtifact@1 inputs: targetPath: $(Build.ArtifactStagingDirectory) - artifactName: 'Windows32' + artifactName: 'WindowsBuild-x86' - task: CopyFiles@2 displayName: 'Collect Symbols' inputs: @@ -522,7 +522,7 @@ stages: steps: - task: DownloadPipelineArtifact@2 inputs: - artifactName: 'Windows32' + artifactName: 'WindowsBuild-x86' targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: @@ -572,7 +572,7 @@ stages: - task: DownloadPipelineArtifact@2 displayName: "Download windows32" inputs: - artifactName: 'Windows32' + artifactName: 'WindowsBuild-x86' targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download windows64" From cfc8774dac5ca09a60adce7ffda30b58562d8f3b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Feb 2024 13:04:09 -0800 Subject: [PATCH 176/224] move windows builds to use mk_win_dist_cmake in nightly Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 136 ++++--------------------------------------- 1 file changed, 12 insertions(+), 124 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 95ccb0819..4a054919a 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -155,127 +155,15 @@ stages: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'x86' - - job: Windows32 - condition: eq(0, 1) - displayName: "Windows 32-bit build" - pool: - vmImage: "windows-latest" - steps: - - task: CmdLine@2 - inputs: - script: - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 & - python scripts\mk_win_dist_cmake.py - --assembly-version=$(AssemblyVersion) - --x86-only - --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - --zip - - task: CopyFiles@2 - inputs: - sourceFolder: dist/x86 - contents: '*.zip' - targetFolder: $(Build.ArtifactStagingDirectory) - - task: PublishPipelineArtifact@1 - inputs: - targetPath: $(Build.ArtifactStagingDirectory) - artifactName: 'WindowsBuild-x86' - - task: CopyFiles@2 - displayName: 'Collect Symbols' - inputs: - sourceFolder: build-dist/x86 - contents: '**/*.pdb' - targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' - # Publish symbol archive to match nuget package - # Index your source code and publish symbols to a file share or Azure Artifacts symbol server - - task: PublishSymbols@2 - inputs: - symbolsFolder: '$(Build.ArtifactStagingDirectory)/symbols' - searchPattern: '**/*.pdb' - indexSources: false # Github not supported - publishSymbols: true - symbolServerType: TeamServices - detailedLog: true - - - job: Windows64 - displayName: "Windows 64-bit build" - pool: - vmImage: "windows-latest" - steps: - - task: CmdLine@2 - inputs: - script: - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 & - python scripts\mk_win_dist_cmake.py - --assembly-version=$(AssemblyVersion) - --x64-only - --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - --zip - - task: CopyFiles@2 - inputs: - sourceFolder: dist/x64 - contents: '*.zip' - targetFolder: $(Build.ArtifactStagingDirectory) - - task: PublishPipelineArtifact@1 - inputs: - targetPath: $(Build.ArtifactStagingDirectory) - artifactName: 'Windows64' - - task: CopyFiles@2 - displayName: 'Collect Symbols' - inputs: - sourceFolder: build-dist/x64 - contents: '**/*.pdb' - targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' - # Publish symbol archive to match nuget package - # Index your source code and publish symbols to a file share or Azure Artifacts symbol server - - task: PublishSymbols@2 - inputs: - symbolsFolder: '$(Build.ArtifactStagingDirectory)/symbols' - searchPattern: '**/*.pdb' - indexSources: false # Github not supported - publishSymbols: true - symbolServerType: TeamServices - detailedLog: true - - - job: WindowsArm64 - displayName: "Windows ARM64-bit build" - pool: - vmImage: "windows-latest" - steps: - - task: CmdLine@2 - inputs: - script: - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64_arm64 & - python scripts\mk_win_dist_cmake.py - --assembly-version=$(AssemblyVersion) - --arm64-only - --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - --zip - - task: CopyFiles@2 - inputs: - sourceFolder: dist/arm64 - contents: '*.zip' - targetFolder: $(Build.ArtifactStagingDirectory) - - task: PublishPipelineArtifact@1 - inputs: - targetPath: $(Build.ArtifactStagingDirectory) - artifactName: 'WindowsArm64' - - task: CopyFiles@2 - displayName: 'Collect Symbols' - inputs: - sourceFolder: build-dist/arm64 - contents: '**/*.pdb' - targetFolder: '$(Build.ArtifactStagingDirectory)/symbols' - # Publish symbol archive to match nuget package - # Index your source code and publish symbols to a file share or Azure Artifacts symbol server - - task: PublishSymbols@2 - inputs: - symbolsFolder: '$(Build.ArtifactStagingDirectory)/symbols' - searchPattern: '**/*.pdb' - indexSources: false # Github not supported - publishSymbols: true - symbolServerType: TeamServices - detailedLog: true + - template: build-win-signed-cmake.yml + parameters: + ReleaseVersion: $(ReleaseVersion) + BuildArchitecture: 'x64' +- template: build-win-signed-cmake.yml + parameters: + ReleaseVersion: $(ReleaseVersion) + BuildArchitecture: 'arm64' - stage: Package @@ -294,7 +182,7 @@ stages: - task: DownloadPipelineArtifact@2 displayName: 'Download Win64 Build' inputs: - artifact: 'Windows64' + artifact: 'WindowsBuild-x64' path: $(Agent.TempDirectory)\package - task: DownloadPipelineArtifact@2 displayName: 'Download Ubuntu 20.04 Build' @@ -526,7 +414,7 @@ stages: targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: - artifactName: 'Windows64' + artifactName: 'WindowsBuild-64' targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: @@ -577,12 +465,12 @@ stages: - task: DownloadPipelineArtifact@2 displayName: "Download windows64" inputs: - artifactName: 'Windows64' + artifactName: 'WindowsBuild-x64' targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download windowsARM64" inputs: - artifactName: 'WindowsArm64' + artifactName: 'WindowsBuild-arm64' targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download Mac" From 736d6348e60b8742ea1c0a6d761b2f101ca06807 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Feb 2024 13:05:01 -0800 Subject: [PATCH 177/224] move windows builds to use mk_win_dist_cmake in nightly Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 4a054919a..7339ff3c2 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -160,7 +160,7 @@ stages: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'x64' -- template: build-win-signed-cmake.yml + - template: build-win-signed-cmake.yml parameters: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'arm64' From 14fb235dd8d4bd50b4eb2b81fb948d65e960104d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Feb 2024 16:16:19 -0800 Subject: [PATCH 178/224] update mk-win-dist-cmake Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index 38707e50b..1e505f412 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -34,7 +34,6 @@ ASSEMBLY_VERSION = None DOTNET_CORE_ENABLED = True DOTNET_KEY_FILE = None JAVA_ENABLED = True -JULIA_ENABLED = False ZIP_BUILD_OUTPUTS = False GIT_HASH = False PYTHON_ENABLED = True @@ -81,7 +80,6 @@ def get_bin_dist_path(arch): def get_dist_path(arch): return os.path.join(DIST_DIR, arch) - def set_build_dir(path): global BUILD_DIR, BUILD_X86_DIR, BUILD_X64_DIR, BUILD_ARM64_DIR, ARCHITECTURES BUILD_DIR = os.path.expanduser(os.path.normpath(path)) @@ -89,9 +87,6 @@ def set_build_dir(path): BUILD_X64_DIR = os.path.join(path, 'x64') BUILD_ARM64_DIR = os.path.join(path, 'arm64') # Set ARM64 build directory ARCHITECTURES = {'x64': BUILD_X64_DIR, 'x86':BUILD_X86_DIR, 'arm64':BUILD_ARM64_DIR} - mk_dir(BUILD_X86_DIR) - mk_dir(BUILD_X64_DIR) - mk_dir(BUILD_ARM64_DIR) def display_help(): print("mk_win_dist.py: Z3 Windows distribution generator\n") @@ -108,7 +103,6 @@ def display_help(): print(" --dotnet-key= strongname sign the .NET assembly with the private key in .") print(" --nojava do not include Java bindings in the binary distribution files.") print(" --nopython do not include Python bindings in the binary distribution files.") - print(" --julia build Julia bindings.") print(" --zip package build outputs in zip file.") print(" --githash include git hash in the Zip file.") print(" --x86-only x86 dist only.") @@ -118,7 +112,7 @@ def display_help(): # Parse configuration option for mk_make script def parse_options(): - global FORCE_MK, JAVA_ENABLED, JULIA_ENABLED, ZIP_BUILD_OUTPUTS, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, ASSEMBLY_VERSION, PYTHON_ENABLED, X86ONLY, X64ONLY, ARM64ONLY + global FORCE_MK, JAVA_ENABLED, ZIP_BUILD_OUTPUTS, GIT_HASH, DOTNET_CORE_ENABLED, DOTNET_KEY_FILE, ASSEMBLY_VERSION, PYTHON_ENABLED, X86ONLY, X64ONLY, ARM64ONLY path = BUILD_DIR options, remainder = getopt.gnu_getopt(sys.argv[1:], 'b:hsf', ['build=', 'help', @@ -131,7 +125,6 @@ def parse_options(): 'zip', 'githash', 'nopython', - 'julia', 'x86-only', 'x64-only', 'arm64-only' @@ -157,8 +150,6 @@ def parse_options(): DOTNET_KEY_FILE = arg elif opt == '--nojava': JAVA_ENABLED = False - elif opt == '--julia': - JULIA_ENABLED = True elif opt == '--zip': ZIP_BUILD_OUTPUTS = True elif opt == '--githash': @@ -208,10 +199,6 @@ def mk_build_dir(arch): arch = "amd64_arm64" cmds = [] - if JULIA_ENABLED: - cmds.append('julia -e "using Pkg; Pkg.add(PackageSpec(name=\"libcxxwrap_julia_jll\"))"') - cmds.append('julia -e "using libcxxwrap_julia_jll; print(dirname(libcxxwrap_julia_jll.libcxxwrap_julia_path))" > tmp.env') - cmds.append('set /P JlCxxDir= Date: Fri, 2 Feb 2024 16:33:27 -0800 Subject: [PATCH 179/224] update mk-win-dist-cmake Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index 1e505f412..adfb2e4dd 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -196,7 +196,7 @@ def mk_build_dir(arch): if not check_build_dir(build_path) or FORCE_MK: mk_dir(build_path) if arch == "arm64": - arch = "amd64_arm64" + arch = "x64_arm64" cmds = [] cmds.append(f"cd {build_path}") From e398f84e857bb1338b89ae609c8b7d452216eb57 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2024 11:35:13 -0800 Subject: [PATCH 180/224] update build-win-signed-cmake Signed-off-by: Nikolaj Bjorner --- scripts/build-win-signed-cmake.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/build-win-signed-cmake.yml b/scripts/build-win-signed-cmake.yml index cdc896ca7..ac3ac2824 100644 --- a/scripts/build-win-signed-cmake.yml +++ b/scripts/build-win-signed-cmake.yml @@ -18,7 +18,6 @@ jobs: displayName: Build inputs: script: - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{parameters.BuildArchitecture}} && python scripts\mk_win_dist_cmake.py --${{parameters.BuildArchitecture}}-only --assembly-version=${{parameters.ReleaseVersion}} From e295ac93af00e80652a10a7fcf1c417a087611b2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2024 11:46:11 -0800 Subject: [PATCH 181/224] update build-win-signed-cmake Signed-off-by: Nikolaj Bjorner --- scripts/build-win-signed-cmake.yml | 2 ++ scripts/mk_win_dist_cmake.py | 4 ++-- scripts/nightly.yaml | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/build-win-signed-cmake.yml b/scripts/build-win-signed-cmake.yml index ac3ac2824..620379f0c 100644 --- a/scripts/build-win-signed-cmake.yml +++ b/scripts/build-win-signed-cmake.yml @@ -1,6 +1,7 @@ parameters: ReleaseVersion: '' BuildArchitecture: '' + VCArchitecture: '' jobs: - job: WindowsBuild${{parameters.BuildArchitecture}} @@ -18,6 +19,7 @@ jobs: displayName: Build inputs: script: + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{parameters.VCArchitecture}} & python scripts\mk_win_dist_cmake.py --${{parameters.BuildArchitecture}}-only --assembly-version=${{parameters.ReleaseVersion}} diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index adfb2e4dd..506288738 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -196,7 +196,7 @@ def mk_build_dir(arch): if not check_build_dir(build_path) or FORCE_MK: mk_dir(build_path) if arch == "arm64": - arch = "x64_arm64" + arch = "amd64_arm64" cmds = [] cmds.append(f"cd {build_path}") @@ -266,7 +266,7 @@ def build_z3(arch): print("build z3") build_dir = get_build_dir(arch) if arch == "arm64": - arch = "x64_arm64" + arch = "amd64_arm64" cmds = [] cmds.append('call "%VCINSTALLDIR%Auxiliary\\build\\vcvarsall.bat" ' + arch) cmds.append('cd %s' % build_dir) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 7339ff3c2..352bcf22b 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -154,17 +154,19 @@ stages: parameters: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'x86' + VCArchitecture: 'x86' - template: build-win-signed-cmake.yml parameters: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'x64' + VCArchitecture: 'x64' - template: build-win-signed-cmake.yml parameters: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'arm64' - + VCArchitecture: 'amd64_arm64' - stage: Package jobs: From 24ffef8ac505ddb2ffbe2a57165be9ff9ed1ca31 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2024 12:26:27 -0800 Subject: [PATCH 182/224] fix typo Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 352bcf22b..3b84235b0 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -416,7 +416,7 @@ stages: targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: - artifactName: 'WindowsBuild-64' + artifactName: 'WindowsBuild-x64' targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: From a5a819c2916b64deee0069c71c07fa1edaef9067 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2024 12:48:58 -0800 Subject: [PATCH 183/224] port updates to egraph from poly Signed-off-by: Nikolaj Bjorner --- src/ast/euf/euf_ac_plugin.cpp | 2 +- src/ast/euf/euf_ac_plugin.h | 4 +- src/ast/euf/euf_arith_plugin.h | 2 +- src/ast/euf/euf_bv_plugin.cpp | 94 ++++++++++++++++++++------------ src/ast/euf/euf_bv_plugin.h | 3 +- src/ast/euf/euf_enode.cpp | 2 +- src/ast/euf/euf_enode.h | 4 -- src/ast/euf/euf_justification.h | 27 +++++++-- src/ast/euf/euf_plugin.cpp | 3 +- src/ast/euf/euf_plugin.h | 2 +- src/ast/euf/euf_specrel_plugin.h | 2 +- 11 files changed, 91 insertions(+), 54 deletions(-) diff --git a/src/ast/euf/euf_ac_plugin.cpp b/src/ast/euf/euf_ac_plugin.cpp index 5e8ec997f..174ef363b 100644 --- a/src/ast/euf/euf_ac_plugin.cpp +++ b/src/ast/euf/euf_ac_plugin.cpp @@ -109,7 +109,7 @@ namespace euf { m_shared_nodes.setx(n->get_id(), true, false); sort(monomial(m)); m_shared_todo.insert(m_shared.size()); - m_shared.push_back({ n, m, justification::axiom() }); + m_shared.push_back({ n, m, justification::axiom(get_id()) }); push_undo(is_register_shared); } diff --git a/src/ast/euf/euf_ac_plugin.h b/src/ast/euf/euf_ac_plugin.h index 911f539f9..7da346dba 100644 --- a/src/ast/euf/euf_ac_plugin.h +++ b/src/ast/euf/euf_ac_plugin.h @@ -137,7 +137,7 @@ namespace euf { } }; - unsigned m_fid = 0; + theory_id m_fid = 0; unsigned m_op = null_decl_kind; func_decl* m_decl = nullptr; vector m_eqs; @@ -273,7 +273,7 @@ namespace euf { ~ac_plugin() override {} - unsigned get_id() const override { return m_fid; } + theory_id get_id() const override { return m_fid; } void register_node(enode* n) override; diff --git a/src/ast/euf/euf_arith_plugin.h b/src/ast/euf/euf_arith_plugin.h index cbdb51bef..4c2a88d36 100644 --- a/src/ast/euf/euf_arith_plugin.h +++ b/src/ast/euf/euf_arith_plugin.h @@ -35,7 +35,7 @@ namespace euf { ~arith_plugin() override {} - unsigned get_id() const override { return a.get_family_id(); } + theory_id get_id() const override { return a.get_family_id(); } void register_node(enode* n) override; diff --git a/src/ast/euf/euf_bv_plugin.cpp b/src/ast/euf/euf_bv_plugin.cpp index b4abe5e29..1b32e9b3a 100644 --- a/src/ast/euf/euf_bv_plugin.cpp +++ b/src/ast/euf/euf_bv_plugin.cpp @@ -161,20 +161,27 @@ namespace euf { void bv_plugin::propagate_values(enode* x) { if (!is_value(x)) return; - + + auto val_x = get_value(x); enode* a, * b; - for (enode* p : enode_parents(x)) - if (is_concat(p, a, b) && is_value(a) && is_value(b) && !is_value(p)) + unsigned lo, hi; + for (enode* p : enode_parents(x)) { + if (is_concat(p, a, b) && is_value(a) && is_value(b)) push_merge(mk_concat(a->get_interpreted(), b->get_interpreted()), mk_value_concat(a, b)); - + + if (is_extract(p, lo, hi)) { + auto val_p = mod2k(machine_div2k(val_x, lo), hi - lo + 1); + auto ix = x->get_interpreted(); + auto ex = mk(bv.mk_extract(hi, lo, ix->get_expr()), 1, &ix); + push_merge(ex, mk_value(val_p, width(p))); + } + } + for (enode* sib : enode_class(x)) { if (is_concat(sib, a, b)) { - if (!is_value(a) || !is_value(b)) { - auto val = get_value(x); - auto val_a = machine_div2k(val, width(b)); - auto val_b = mod2k(val, width(b)); - push_merge(mk_concat(mk_value(val_a, width(a)), mk_value(val_b, width(b))), x->get_interpreted()); - } + auto val_a = machine_div2k(val_x, width(b)); + auto val_b = mod2k(val_x, width(b)); + push_merge(mk_concat(mk_value(val_a, width(a)), mk_value(val_b, width(b))), x->get_interpreted()); } } } @@ -198,7 +205,9 @@ namespace euf { enode* arg_r = arg->get_root(); enode* n_r = n->get_root(); + m_ensure_concat.reset(); auto ensure_concat = [&](unsigned lo, unsigned mid, unsigned hi) { + // verbose_stream() << lo << " " << mid << " " << hi << "\n"; TRACE("bv", tout << "ensure-concat " << lo << " " << mid << " " << hi << "\n"); unsigned lo_, hi_; for (enode* p1 : enode_parents(n)) @@ -212,14 +221,14 @@ namespace euf { TRACE("bv", tout << "propagate-above " << g.bpp(b) << "\n"); for (enode* sib : enode_class(b)) if (is_extract(sib, lo2, hi2) && sib->get_arg(0)->get_root() == arg_r && hi1 + 1 == lo2) - ensure_concat(lo1, hi1, hi2); + m_ensure_concat.push_back({lo1, hi1, hi2}); }; auto propagate_below = [&](enode* a) { TRACE("bv", tout << "propagate-below " << g.bpp(a) << "\n"); for (enode* sib : enode_class(a)) if (is_extract(sib, lo2, hi2) && sib->get_arg(0)->get_root() == arg_r && hi2 + 1 == lo1) - ensure_concat(lo2, hi2, hi1); + m_ensure_concat.push_back({lo2, hi2, hi1}); }; for (enode* p : enode_parents(n)) { @@ -230,6 +239,10 @@ namespace euf { propagate_above(a); } } + + for (auto [lo, mid, hi] : m_ensure_concat) + ensure_concat(lo, mid, hi); + } class bv_plugin::undo_split : public trail { @@ -432,13 +445,14 @@ namespace euf { delta += width(arg); } } - } - for (auto p : euf::enode_parents(n->get_root())) { - if (bv.is_extract(p->get_expr(), lo, hi, e)) { - SASSERT(g.find(e)->get_root() == n->get_root()); - m_todo.push_back({ p, offset + lo }); + for (auto p : euf::enode_parents(sib)) { + if (bv.is_extract(p->get_expr(), lo, hi, e)) { + SASSERT(g.find(e)->get_root() == n->get_root()); + m_todo.push_back({ p, offset + lo }); + } } } + } clear_offsets(); } @@ -462,17 +476,17 @@ namespace euf { auto child = g.find(e); m_todo.push_back({ child, offset + lo }); } - } - for (auto p : euf::enode_parents(n->get_root())) { - if (bv.is_concat(p->get_expr())) { - unsigned delta = 0; - for (unsigned j = p->num_args(); j-- > 0; ) { - auto arg = p->get_arg(j); - if (arg->get_root() == n->get_root()) - m_todo.push_back({ p, offset + delta }); - delta += width(arg); + for (auto p : euf::enode_parents(sib)) { + if (bv.is_concat(p->get_expr())) { + unsigned delta = 0; + for (unsigned j = p->num_args(); j-- > 0; ) { + auto arg = p->get_arg(j); + if (arg->get_root() == n->get_root()) + m_todo.push_back({ p, offset + delta }); + delta += width(arg); + } } - } + } } } clear_offsets(); @@ -511,6 +525,9 @@ namespace euf { m_offsets.reserve(n->get_root_id() + 1); m_offsets[n->get_root_id()].reset(); } + for (auto const& off : m_offsets) { + SASSERT(off.empty()); + } m_jtodo.reset(); return; } @@ -521,20 +538,27 @@ namespace euf { just.push_back({ n, sib, j }); for (unsigned j = sib->num_args(); j-- > 0; ) { auto arg = sib->get_arg(j); - m_jtodo.push_back({ arg, offset + delta, j2 }); + m_jtodo.push_back({ arg, offs + delta, j2 }); delta += width(arg); } } - } - for (auto p : euf::enode_parents(n->get_root())) { - if (bv.is_extract(p->get_expr(), lo, hi, e)) { - SASSERT(g.find(e)->get_root() == n->get_root()); - unsigned j2 = just.size(); - just.push_back({ g.find(e), n, j}); - m_jtodo.push_back({ p, offset + lo, j2}); + for (auto p : euf::enode_parents(sib)) { + if (bv.is_extract(p->get_expr(), lo, hi, e)) { + SASSERT(g.find(e)->get_root() == n->get_root()); + unsigned j2 = just.size(); + just.push_back({ g.find(e), n, j }); + m_jtodo.push_back({ p, offs + lo, j2 }); + } } } + } + IF_VERBOSE(0, + g.display(verbose_stream()); + verbose_stream() << g.bpp(a) << " offset " << offset << " " << g.bpp(b) << "\n"; + for (auto const& [n, offset, j] : m_jtodo) + verbose_stream() << g.bpp(n) << " offset " << offset << " " << g.bpp(n->get_root()) << "\n"; + ); UNREACHABLE(); } diff --git a/src/ast/euf/euf_bv_plugin.h b/src/ast/euf/euf_bv_plugin.h index b90318c4d..ec2c0b448 100644 --- a/src/ast/euf/euf_bv_plugin.h +++ b/src/ast/euf/euf_bv_plugin.h @@ -72,6 +72,7 @@ namespace euf { bool unfold_width(enode* x, enode_vector& xs, enode* y, enode_vector& ys); bool unfold_sub(enode* x, enode_vector& xs); void merge(enode_vector& xs, enode_vector& ys, justification j); + svector> m_ensure_concat; void propagate_extract(enode* n); void propagate_values(enode* n); @@ -96,7 +97,7 @@ namespace euf { ~bv_plugin() override {} - unsigned get_id() const override { return bv.get_family_id(); } + theory_id get_id() const override { return bv.get_family_id(); } void register_node(enode* n) override; diff --git a/src/ast/euf/euf_enode.cpp b/src/ast/euf/euf_enode.cpp index 335c8f3e9..2149059b4 100644 --- a/src/ast/euf/euf_enode.cpp +++ b/src/ast/euf/euf_enode.cpp @@ -135,7 +135,7 @@ namespace euf { enode* prev = this; justification js = m_justification; prev->m_target = nullptr; - prev->m_justification = justification::axiom(); + prev->m_justification = justification::axiom(null_theory_id); while (curr != nullptr) { enode* new_curr = curr->m_target; justification new_js = curr->m_justification; diff --git a/src/ast/euf/euf_enode.h b/src/ast/euf/euf_enode.h index 0f22ff20e..50a7ce479 100644 --- a/src/ast/euf/euf_enode.h +++ b/src/ast/euf/euf_enode.h @@ -36,10 +36,6 @@ namespace euf { typedef std::pair enode_bool_pair; typedef svector enode_bool_pair_vector; typedef id_var_list<> th_var_list; - typedef int theory_var; - typedef int theory_id; - const theory_var null_theory_var = -1; - const theory_id null_theory_id = -1; class enode { expr* m_expr = nullptr; diff --git a/src/ast/euf/euf_justification.h b/src/ast/euf/euf_justification.h index f9d3b3637..8a5a58ad9 100644 --- a/src/ast/euf/euf_justification.h +++ b/src/ast/euf/euf_justification.h @@ -28,6 +28,11 @@ namespace euf { class enode; + typedef int theory_var; + typedef int theory_id; + const theory_var null_theory_var = -1; + const theory_id null_theory_id = -1; + class justification { public: typedef stacked_dependency_manager dependency_manager; @@ -42,6 +47,7 @@ namespace euf { }; kind_t m_kind; union { + int m_theory_id; bool m_comm; enode* m_n1; }; @@ -76,19 +82,27 @@ namespace euf { m_n2(n2) {} - public: - justification(): + justification(int theory_id): m_kind(kind_t::axiom_t), - m_comm(false), + m_theory_id(theory_id), m_external(nullptr) {} - static justification axiom() { return justification(); } + public: + + justification(): + m_kind(kind_t::axiom_t), + m_theory_id(null_theory_id), + m_external(nullptr) + {} + + static justification axiom(int theory_id) { return justification(theory_id); } static justification congruence(bool c, uint64_t ts) { return justification(c, ts); } static justification external(void* ext) { return justification(ext); } static justification dependent(dependency* d) { return justification(d, 1); } static justification equality(enode* a, enode* b) { return justification(a, b); } + bool is_axiom() const { return m_kind == kind_t::axiom_t; } bool is_external() const { return m_kind == kind_t::external_t; } bool is_congruence() const { return m_kind == kind_t::congruence_t; } bool is_commutative() const { return m_comm; } @@ -98,6 +112,7 @@ namespace euf { enode* lhs() const { SASSERT(is_equality()); return m_n1; } enode* rhs() const { SASSERT(is_equality()); return m_n2; } uint64_t timestamp() const { SASSERT(is_congruence()); return m_timestamp; } + theory_id get_theory_id() const { SASSERT(is_axiom()); return m_theory_id; } template T* ext() const { SASSERT(is_external()); return static_cast(m_external); } @@ -106,7 +121,7 @@ namespace euf { case kind_t::external_t: return external(copy_justification(m_external)); case kind_t::axiom_t: - return axiom(); + return axiom(m_theory_id); case kind_t::congruence_t: return congruence(m_comm, m_timestamp); case kind_t::dependent_t: @@ -114,7 +129,7 @@ namespace euf { return dependent(m_dependency); default: UNREACHABLE(); - return axiom(); + return axiom(-1); } } diff --git a/src/ast/euf/euf_plugin.cpp b/src/ast/euf/euf_plugin.cpp index 57c1849fd..f95107bc3 100644 --- a/src/ast/euf/euf_plugin.cpp +++ b/src/ast/euf/euf_plugin.cpp @@ -26,12 +26,13 @@ namespace euf { } void plugin::push_merge(enode* a, enode* b, justification j) { + TRACE("euf", tout << "push-merge " << g.bpp(a) << " == " << g.bpp(b) << " " << j << "\n"); g.push_merge(a, b, j); } void plugin::push_merge(enode* a, enode* b) { TRACE("plugin", tout << g.bpp(a) << " == " << g.bpp(b) << "\n"); - g.push_merge(a, b, justification::axiom()); + g.push_merge(a, b, justification::axiom(get_id())); } enode* plugin::mk(expr* e, unsigned n, enode* const* args) { diff --git a/src/ast/euf/euf_plugin.h b/src/ast/euf/euf_plugin.h index ff49d6c40..8dbd4d7e7 100644 --- a/src/ast/euf/euf_plugin.h +++ b/src/ast/euf/euf_plugin.h @@ -40,7 +40,7 @@ namespace euf { virtual ~plugin() {} - virtual unsigned get_id() const = 0; + virtual theory_id get_id() const = 0; virtual void register_node(enode* n) = 0; diff --git a/src/ast/euf/euf_specrel_plugin.h b/src/ast/euf/euf_specrel_plugin.h index 228bb5e15..ae93bd2a5 100644 --- a/src/ast/euf/euf_specrel_plugin.h +++ b/src/ast/euf/euf_specrel_plugin.h @@ -37,7 +37,7 @@ namespace euf { ~specrel_plugin() override {} - unsigned get_id() const override { return sp.get_family_id(); } + theory_id get_id() const override { return sp.get_family_id(); } void register_node(enode* n) override; From 9425c419add21de09c088bb775f37e56038fc3c2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2024 15:38:05 -0800 Subject: [PATCH 184/224] port remaining egraph update Signed-off-by: Nikolaj Bjorner --- src/ast/euf/euf_egraph.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ast/euf/euf_egraph.cpp b/src/ast/euf/euf_egraph.cpp index 12f817212..f19a146c5 100644 --- a/src/ast/euf/euf_egraph.cpp +++ b/src/ast/euf/euf_egraph.cpp @@ -69,7 +69,7 @@ namespace euf { } enode_bool_pair egraph::insert_table(enode* p) { - TRACE("euf", tout << "insert_table " << bpp(p) << "\n"); + TRACE("euf_verbose", tout << "insert_table " << bpp(p) << "\n"); //SASSERT(!m_table.contains_ptr(p)); auto rc = m_table.insert(p); p->m_cg = rc.first; @@ -522,7 +522,7 @@ namespace euf { } void egraph::remove_parents(enode* r) { - TRACE("euf", tout << bpp(r) << "\n"); + TRACE("euf_verbose", tout << bpp(r) << "\n"); SASSERT(all_of(enode_parents(r), [&](enode* p) { return !p->is_marked1(); })); for (enode* p : enode_parents(r)) { if (p->is_marked1()) @@ -533,7 +533,7 @@ namespace euf { SASSERT(m_table.contains_ptr(p)); p->mark1(); erase_from_table(p); - CTRACE("euf", m_table.contains_ptr(p), tout << bpp(p) << "\n"; display(tout)); + CTRACE("euf_verbose", m_table.contains_ptr(p), tout << bpp(p) << "\n"; display(tout)); SASSERT(!m_table.contains_ptr(p)); } else if (p->is_equality()) @@ -546,11 +546,11 @@ namespace euf { if (!p->is_marked1()) continue; p->unmark1(); - TRACE("euf", tout << "reinsert " << bpp(r1) << " " << bpp(r2) << " " << bpp(p) << " " << p->cgc_enabled() << "\n";); + TRACE("euf_verbose", tout << "reinsert " << bpp(r1) << " " << bpp(r2) << " " << bpp(p) << " " << p->cgc_enabled() << "\n";); if (p->cgc_enabled()) { auto [p_other, comm] = insert_table(p); SASSERT(m_table.contains_ptr(p) == (p_other == p)); - CTRACE("euf", p_other != p, tout << "reinsert " << bpp(p) << " == " << bpp(p_other) << " " << p->value() << " " << p_other->value() << "\n"); + CTRACE("euf_verbose", p_other != p, tout << "reinsert " << bpp(p) << " == " << bpp(p_other) << " " << p->value() << " " << p_other->value() << "\n"); if (p_other != p) m_to_merge.push_back(to_merge(p_other, p, comm)); else @@ -584,14 +584,14 @@ namespace euf { void egraph::undo_eq(enode* r1, enode* n1, unsigned r2_num_parents) { enode* r2 = r1->get_root(); - TRACE("euf", tout << "undo-eq old-root: " << bpp(r1) << " current-root " << bpp(r2) << " node: " << bpp(n1) << "\n";); + TRACE("euf_verbose", tout << "undo-eq old-root: " << bpp(r1) << " current-root " << bpp(r2) << " node: " << bpp(n1) << "\n";); r2->dec_class_size(r1->class_size()); r2->set_is_shared(l_undef); std::swap(r1->m_next, r2->m_next); auto begin = r2->begin_parents() + r2_num_parents, end = r2->end_parents(); for (auto it = begin; it != end; ++it) { enode* p = *it; - TRACE("euf", tout << "erase " << bpp(p) << "\n";); + TRACE("euf_verbose", tout << "erase " << bpp(p) << "\n";); SASSERT(!p->cgc_enabled() || m_table.contains_ptr(p)); SASSERT(!p->cgc_enabled() || p->is_cgr()); if (p->cgc_enabled()) @@ -673,7 +673,7 @@ namespace euf { SASSERT(n1->get_root()->reaches(n1)); SASSERT(n1->m_target); n1->m_target = nullptr; - n1->m_justification = justification::axiom(); + n1->m_justification = justification::axiom(null_theory_id); n1->get_root()->reverse_justification(); // --------------- // n1 -> ... -> r1 @@ -804,7 +804,10 @@ namespace euf { explain_eq(justifications, cc, a, b, j2); } else if (j.is_equality()) - explain_eq(justifications, cc, j.lhs(), j.rhs()); + explain_eq(justifications, cc, j.lhs(), j.rhs()); + else if (j.is_axiom() && j.get_theory_id() != null_theory_id) { + IF_VERBOSE(20, verbose_stream() << "TODO add theory axiom to justification\n"); + } if (cc && j.is_congruence()) cc->push_back(std::tuple(a->get_app(), b->get_app(), j.timestamp(), j.is_commutative())); } From bc70282a180e7d703bd15fd98ee0c4755619f015 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2024 15:42:06 -0800 Subject: [PATCH 185/224] mute some compiler warnings Signed-off-by: Nikolaj Bjorner --- src/ast/euf/euf_bv_plugin.cpp | 7 ++++--- src/ast/rewriter/bool_rewriter.cpp | 7 ------- src/math/polynomial/polynomial.cpp | 2 ++ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/ast/euf/euf_bv_plugin.cpp b/src/ast/euf/euf_bv_plugin.cpp index 1b32e9b3a..4b0cd6cfc 100644 --- a/src/ast/euf/euf_bv_plugin.cpp +++ b/src/ast/euf/euf_bv_plugin.cpp @@ -525,9 +525,10 @@ namespace euf { m_offsets.reserve(n->get_root_id() + 1); m_offsets[n->get_root_id()].reset(); } - for (auto const& off : m_offsets) { - SASSERT(off.empty()); - } + DEBUG_CODE( + for (auto const& off : m_offsets) { + VERIFY(off.empty()); + }); m_jtodo.reset(); return; } diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 13a392d24..2176ff129 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -545,16 +545,9 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_ bool simp = false; bool modified = false; bool forward = true; - unsigned rounds = 0; expr* narg; while (true) { - rounds++; -#if 0 - if (rounds > 10) - verbose_stream() << "rounds: " << rounds << "\n"; -#endif - #define PROCESS_ARG() \ { \ diff --git a/src/math/polynomial/polynomial.cpp b/src/math/polynomial/polynomial.cpp index 96a4a05ca..da6bc7b39 100644 --- a/src/math/polynomial/polynomial.cpp +++ b/src/math/polynomial/polynomial.cpp @@ -3624,6 +3624,7 @@ namespace polynomial { unsigned counter = 0; while (true) { + (void)counter; SASSERT(degree(pp_u, x) >= degree(pp_v, x)); unsigned delta = degree(pp_u, x) - degree(pp_v, x); TRACE("polynomial_gcd_detail", @@ -4169,6 +4170,7 @@ namespace polynomial { unsigned counter = 0; for (;; counter++) { + (void) counter; while (true) { peek_fresh(interpolator.inputs(), p, val); // the selected value must satisfy lc_g(val) != 0 From b9bec1861a9c5f25cd6585b6a90f68ad3277c3f6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2024 16:08:31 -0800 Subject: [PATCH 186/224] copy over dotnet files Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 3b84235b0..b4db84449 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -88,6 +88,7 @@ stages: -DCMAKE_INSTALL_PREFIX=$(name)\ -G "Ninja" ../ ninja install + cp -r Microsoft.Z3 $(name)/. zip -r $(name).zip $(name) cd .. - script: cp $(arch)/*.zip $(Build.ArtifactStagingDirectory)/. From c9267055c2dc6b579023d4b52ae63095f78dc184 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2024 16:14:03 -0800 Subject: [PATCH 187/224] update assembly names Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_task.py | 1 + scripts/nightly.yaml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/mk_nuget_task.py b/scripts/mk_nuget_task.py index be6dd203b..c315b0071 100644 --- a/scripts/mk_nuget_task.py +++ b/scripts/mk_nuget_task.py @@ -24,6 +24,7 @@ def mk_dir(d): os_info = { 'ubuntu-latest' : ('so', 'linux-x64'), 'ubuntu-18' : ('so', 'linux-x64'), 'ubuntu-20' : ('so', 'linux-x64'), + 'ubuntu-22' : ('so', 'linux-x64'), 'x64-glibc-2.35' : ('so', 'linux-x64'), 'x64-win' : ('dll', 'win-x64'), 'x86-win' : ('dll', 'win-x86'), diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index b4db84449..43d4fa1e1 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -60,13 +60,13 @@ stages: setupcmds: 'sudo apt update& sudo apt install gcc-arm-none-eabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu ninja-build -y' buildenv: 'CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc' arch: 'arm64' - name: 'z3-$(AssemblyVersion)-arm64-ubuntu' + name: 'z3-$(AssemblyVersion)-arm64-ubuntu-22' compiler: 'aarch64-linux-gnu-g++-11' x64: setupcmds: 'sudo apt update& sudo apt install ninja-build -y' buildenv: '' arch: 'x64' - name: 'z3-$(AssemblyVersion)-x64-ubuntu' + name: 'z3-$(AssemblyVersion)-x64-ubuntu-22' compiler: 'g++' steps: - script: $(setupcmds) From a2fa4ff1bcefaf6499a200185c1c5500bcb20a13 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2024 16:52:20 -0800 Subject: [PATCH 188/224] update assembly names Signed-off-by: Nikolaj Bjorner --- scripts/mk_nuget_task.py | 8 ++++---- scripts/release.yml | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/mk_nuget_task.py b/scripts/mk_nuget_task.py index c315b0071..9de592c08 100644 --- a/scripts/mk_nuget_task.py +++ b/scripts/mk_nuget_task.py @@ -21,10 +21,10 @@ def mk_dir(d): if not os.path.exists(d): os.makedirs(d) -os_info = { 'ubuntu-latest' : ('so', 'linux-x64'), - 'ubuntu-18' : ('so', 'linux-x64'), - 'ubuntu-20' : ('so', 'linux-x64'), - 'ubuntu-22' : ('so', 'linux-x64'), +os_info = { 'x64-ubuntu-latest' : ('so', 'linux-x64'), + 'x64-ubuntu-18' : ('so', 'linux-x64'), + 'x64-ubuntu-20' : ('so', 'linux-x64'), + 'x64-ubuntu-22' : ('so', 'linux-x64'), 'x64-glibc-2.35' : ('so', 'linux-x64'), 'x64-win' : ('dll', 'win-x64'), 'x86-win' : ('dll', 'win-x86'), diff --git a/scripts/release.yml b/scripts/release.yml index 0a6e9de57..7a2c4ef41 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -213,6 +213,7 @@ stages: parameters: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'arm64' + VCArchitecture: 'amd64_arm64' # Creates Z3 packages in various formats From 3b90816025b05e7dfb5d24b2d3906173e175e0bd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2024 11:15:59 -0800 Subject: [PATCH 189/224] add option to persist clauses #7109 Signed-off-by: Nikolaj Bjorner --- src/smt/params/smt_params.cpp | 2 ++ src/smt/params/smt_params.h | 8 +++++ src/smt/params/smt_params_helper.pyg | 1 + src/smt/theory_user_propagator.cpp | 45 +++++++++++++++++----------- src/smt/theory_user_propagator.h | 4 +++ 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/smt/params/smt_params.cpp b/src/smt/params/smt_params.cpp index 3c63e2fff..ef617f724 100644 --- a/src/smt/params/smt_params.cpp +++ b/src/smt/params/smt_params.cpp @@ -51,6 +51,7 @@ void smt_params::updt_local_params(params_ref const & _p) { m_core_validate = p.core_validate(); m_logic = _p.get_sym("logic", m_logic); m_string_solver = p.string_solver(); + m_up_persist_clauses = p.up_persist_clauses(); validate_string_solver(m_string_solver); if (_p.get_bool("arith.greatest_error_pivot", false)) m_arith_pivot_strategy = arith_pivot_strategy::ARITH_PIVOT_GREATEST_ERROR; @@ -145,6 +146,7 @@ void smt_params::display(std::ostream & out) const { DISPLAY_PARAM(m_agility_factor); DISPLAY_PARAM(m_restart_agility_threshold); + DISPLAY_PARAM(m_up_persist_clauses); DISPLAY_PARAM(m_lemma_gc_strategy); DISPLAY_PARAM(m_lemma_gc_half); DISPLAY_PARAM(m_recent_lemmas_size); diff --git a/src/smt/params/smt_params.h b/src/smt/params/smt_params.h index 07b6b6095..c678b7536 100644 --- a/src/smt/params/smt_params.h +++ b/src/smt/params/smt_params.h @@ -170,6 +170,14 @@ struct smt_params : public preprocessor_params, unsigned m_old_clause_relevancy = 6; //!< Max. number of unassigned literals to be considered relevant. double m_inv_clause_decay = 1; //!< clause activity decay + // ----------------------------------- + // + // User propagator configuration + // + // ----------------------------------- + + bool m_up_persist_clauses = false; + // ----------------------------------- // // SMT-LIB (debug) pretty printer diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index c4660d1ea..708fa87d8 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -102,6 +102,7 @@ def_module_params(module_name='smt', ('arith.print_ext_var_names', BOOL, False, 'print external variable names'), ('pb.conflict_frequency', UINT, 1000, 'conflict frequency for Pseudo-Boolean theory'), ('pb.learn_complements', BOOL, True, 'learn complement literals for Pseudo-Boolean theory'), + ('up.persist_clauses', BOOL, True, 'replay propagated clauses below the levels they are asserted'), ('array.weak', BOOL, False, 'weak array theory'), ('array.extensional', BOOL, True, 'extensional array theory'), ('clause_proof', BOOL, False, 'record a clausal proof'), diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 84a6799fb..395be3e68 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -293,7 +293,7 @@ void theory_user_propagator::pop_scope_eh(unsigned num_scopes) { } bool theory_user_propagator::can_propagate() { - return m_qhead < m_prop.size() || m_to_add_qhead < m_to_add.size(); + return m_qhead < m_prop.size() || m_to_add_qhead < m_to_add.size() || m_replay_qhead < m_clauses_to_replay.size(); } void theory_user_propagator::propagate_consequence(prop_info const& prop) { @@ -321,12 +321,10 @@ void theory_user_propagator::propagate_consequence(prop_info const& prop) { ctx.set_conflict(js); } else { -#if 1 for (auto& lit : m_lits) lit.neg(); for (auto const& [a,b] : m_eqs) m_lits.push_back(~mk_eq(a->get_expr(), b->get_expr(), false)); -#endif literal lit; if (has_quantifiers(prop.m_conseq)) { @@ -340,19 +338,17 @@ void theory_user_propagator::propagate_consequence(prop_info const& prop) { lit = mk_literal(prop.m_conseq); ctx.mark_as_relevant(lit); -#if 0 - justification* js = - ctx.mk_justification( - ext_theory_propagation_justification( - get_id(), ctx, m_lits.size(), m_lits.data(), m_eqs.size(), m_eqs.data(), lit)); - - ctx.assign(lit, js); -#endif - -#if 1 m_lits.push_back(lit); - ctx.mk_th_lemma(get_id(), m_lits); -#endif + if (ctx.get_fparams().m_up_persist_clauses) { + ctx.mk_th_axiom(get_id(), m_lits); + expr_ref_vector clause(m); + for (auto lit : m_lits) + clause.push_back(ctx.literal2expr(lit)); + m_clauses_to_replay.push_back(clause); + } + else { + ctx.mk_th_lemma(get_id(), m_lits); + } TRACE("user_propagate", ctx.display(tout);); } } @@ -363,12 +359,20 @@ void theory_user_propagator::propagate_new_fixed(prop_info const& prop) { void theory_user_propagator::propagate() { - if (m_qhead == m_prop.size() && m_to_add_qhead == m_to_add.size()) + if (m_qhead == m_prop.size() && m_to_add_qhead == m_to_add.size() && m_replay_qhead == m_clauses_to_replay.size()) return; TRACE("user_propagate", tout << "propagating queue head: " << m_qhead << " prop queue: " << m_prop.size() << "\n"); force_push(); - unsigned qhead = m_to_add_qhead; + unsigned qhead = m_replay_qhead; + if (qhead < m_clauses_to_replay.size()) { + for (; qhead < m_clauses_to_replay.size() && !ctx.inconsistent(); ++qhead) + replay_clause(m_clauses_to_replay.get(qhead)); + ctx.push_trail(value_trail(m_replay_qhead)); + m_replay_qhead = qhead; + } + + qhead = m_to_add_qhead; if (qhead < m_to_add.size()) { for (; qhead < m_to_add.size(); ++qhead) add_expr(m_to_add.get(qhead), true); @@ -391,6 +395,13 @@ void theory_user_propagator::propagate() { } +void theory_user_propagator::replay_clause(expr_ref_vector const& clause) { + m_lits.reset(); + for (expr* e : clause) + m_lits.push_back(mk_literal(e)); + ctx.mk_th_axiom(get_id(), m_lits); +} + bool theory_user_propagator::internalize_atom(app* atom, bool gate_ctx) { return internalize_term(atom); } diff --git a/src/smt/theory_user_propagator.h b/src/smt/theory_user_propagator.h index 4b365ef7a..5dbae59ed 100644 --- a/src/smt/theory_user_propagator.h +++ b/src/smt/theory_user_propagator.h @@ -86,6 +86,8 @@ namespace smt { expr* m_next_split_var = nullptr; unsigned m_next_split_idx = 0; lbool m_next_split_phase = l_undef; + vector m_clauses_to_replay; + unsigned m_replay_qhead = 0; expr* var2expr(theory_var v) { return m_var2expr.get(v); } theory_var expr2var(expr* e) { check_defined(e); return m_expr2var[e->get_id()]; } @@ -101,6 +103,8 @@ namespace smt { bool_var enode_to_bool(enode* n, unsigned bit); + void replay_clause(expr_ref_vector const& clause); + public: theory_user_propagator(context& ctx); From 3cec3fc63dd2e41e72fba19235bd5682b3c6e76c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2024 15:26:17 -0800 Subject: [PATCH 190/224] bypass replaying new clause within propagation Signed-off-by: Nikolaj Bjorner --- src/smt/theory_user_propagator.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 395be3e68..93faf9e4e 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -345,6 +345,9 @@ void theory_user_propagator::propagate_consequence(prop_info const& prop) { for (auto lit : m_lits) clause.push_back(ctx.literal2expr(lit)); m_clauses_to_replay.push_back(clause); + if (m_replay_qhead + 1 < m_clauses_to_replay.size()) + std::swap(m_clauses_to_replay[m_replay_qhead], m_clauses_to_replay[m_clauses_to_replay.size()-1]); + ++m_replay_qhead; } else { ctx.mk_th_lemma(get_id(), m_lits); From 7970e4fe510c05bf5a021c594c6c13bfcd88b62b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2024 16:42:10 -0800 Subject: [PATCH 191/224] add clause persistence to sat/smt solver Signed-off-by: Nikolaj Bjorner --- src/sat/smt/user_solver.cpp | 46 ++++++++++++++++++++++++++++++++++--- src/sat/smt/user_solver.h | 5 ++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/sat/smt/user_solver.cpp b/src/sat/smt/user_solver.cpp index 01c1786ec..0204573dc 100644 --- a/src/sat/smt/user_solver.cpp +++ b/src/sat/smt/user_solver.cpp @@ -178,8 +178,10 @@ namespace user_solver { void solver::propagate_consequence(prop_info const& prop) { sat::literal lit = ctx.internalize(prop.m_conseq, false, false); if (s().value(lit) != l_true) { - s().assign(lit, mk_justification(m_qhead)); + auto j = mk_justification(m_qhead); + s().assign(lit, j); ++m_stats.m_num_propagations; + persist_clause(lit, j); } } @@ -188,9 +190,17 @@ namespace user_solver { } bool solver::unit_propagate() { - if (m_qhead == m_prop.size()) + if (m_qhead == m_prop.size() && m_replay_qhead == m_clauses_to_replay.size()) return false; force_push(); + + bool replayed = false; + if (m_replay_qhead < m_clauses_to_replay.size()) { + replayed = true; + ctx.push(value_trail(m_replay_qhead)); + for (; m_replay_qhead < m_clauses_to_replay.size(); ++m_replay_qhead) + replay_clause(m_clauses_to_replay.get(m_replay_qhead)); + } ctx.push(value_trail(m_qhead)); unsigned np = m_stats.m_num_propagations; for (; m_qhead < m_prop.size() && !s().inconsistent(); ++m_qhead) { @@ -200,7 +210,37 @@ namespace user_solver { else propagate_new_fixed(prop); } - return np < m_stats.m_num_propagations; + return np < m_stats.m_num_propagations || replayed; + } + + void solver::replay_clause(expr_ref_vector const& clause) { + sat::literal_vector lits; + for (expr* e : clause) + lits.push_back(ctx.mk_literal(e)); + add_clause(lits); + } + + void solver::persist_clause(sat::literal lit, sat::justification const& sj) { + if (!ctx.get_config().m_up_persist_clauses) + return; + + expr_ref_vector clause(m); + auto idx = sj.get_ext_justification_idx(); + auto& j = justification::from_index(idx); + auto const& prop = m_prop[j.m_propagation_index]; + sat::literal_vector r; + for (unsigned id : prop.m_ids) + r.append(m_id2justification[id]); + for (auto lit : r) + clause.push_back(ctx.literal2expr(~lit)); + for (auto const& [a,b] : prop.m_eqs) + clause.push_back(m.mk_not(m.mk_eq(a, b))); + clause.push_back(ctx.literal2expr(lit)); + + m_clauses_to_replay.push_back(clause); + if (m_replay_qhead + 1 < m_clauses_to_replay.size()) + std::swap(m_clauses_to_replay[m_replay_qhead], m_clauses_to_replay[m_clauses_to_replay.size()-1]); + ++m_replay_qhead; } void solver::collect_statistics(::statistics& st) const { diff --git a/src/sat/smt/user_solver.h b/src/sat/smt/user_solver.h index cd94441ea..373b046b8 100644 --- a/src/sat/smt/user_solver.h +++ b/src/sat/smt/user_solver.h @@ -77,6 +77,8 @@ namespace user_solver { stats m_stats; sat::bool_var m_next_split_var = sat::null_bool_var; lbool m_next_split_phase = l_undef; + vector m_clauses_to_replay; + unsigned m_replay_qhead = 0; struct justification { unsigned m_propagation_index { 0 }; @@ -105,6 +107,9 @@ namespace user_solver { sat::bool_var enode_to_bool(euf::enode* n, unsigned idx); + void replay_clause(expr_ref_vector const& clause); + void persist_clause(sat::literal lit, sat::justification const& j); + public: solver(euf::solver& ctx); From 548b9d091fda2c20a62ca97dddef8b6d5cdf11c6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2024 18:23:46 -0800 Subject: [PATCH 192/224] move libz3.so from lib to bin, remove lib from distribution Signed-off-by: Nikolaj Bjorner --- scripts/nightly.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 43d4fa1e1..478fdb969 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -88,7 +88,9 @@ stages: -DCMAKE_INSTALL_PREFIX=$(name)\ -G "Ninja" ../ ninja install - cp -r Microsoft.Z3 $(name)/. + cp -r Microsoft.Z3 $(name)/bin/. + cp $(name)/lib/libz3.so $(name)/bin/. + rm -rf $(name)/lib zip -r $(name).zip $(name) cd .. - script: cp $(arch)/*.zip $(Build.ArtifactStagingDirectory)/. From b9528b1c5681d04efa8fe7fd9686194bfaec289a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2024 19:06:30 -0800 Subject: [PATCH 193/224] update self-validator to handle root expressions Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 60 +++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 16b28c246..62b55908a 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -3073,6 +3073,11 @@ namespace nlsat { return out; } + std::ostream& display_polynomial_smt2(std::ostream & out, poly const* p, display_var_proc const & proc) const { + m_pm.display_smt2(out, p, proc); + return out; + } + std::ostream& display_ineq_smt2(std::ostream & out, ineq_atom const & a, display_var_proc const & proc) const { switch (a.get_kind()) { case atom::LT: out << "(< "; break; @@ -3087,13 +3092,13 @@ namespace nlsat { if (i > 0) out << " "; if (a.is_even(i)) { out << "(* "; - m_pm.display_smt2(out, a.p(i), proc); + display_polynomial_smt2(out, a.p(i), proc); out << " "; - m_pm.display_smt2(out, a.p(i), proc); + display_polynomial_smt2(out, a.p(i), proc); out << ")"; } else { - m_pm.display_smt2(out, a.p(i), proc); + display_polynomial_smt2(out, a.p(i), proc); } } if (sz > 1) @@ -3102,12 +3107,21 @@ namespace nlsat { return out; } + std::ostream& display_poly_root(std::ostream& out, char const* y, root_atom const& a, display_var_proc const& proc) const { + out << "(exists (("; proc(out,a.x()); out << " Real))\n"; + out << "(and (= " << y << " "; + proc(out, a.x()); + out << ") (= 0 "; + display_polynomial_smt2(out, a.p(), proc); + out << ")))\n"; + return out; + } std::ostream& display_binary_smt2(std::ostream& out, poly const* p1, char const* rel, poly const* p2, display_var_proc const& proc) const { out << "(" << rel << " "; - m_pm.display_smt2(out, p1, proc); + display_polynomial_smt2(out, p1, proc); out << " "; - m_pm.display_smt2(out, p2, proc); + display_polynomial_smt2(out, p2, proc); out << ")"; return out; } @@ -3147,9 +3161,39 @@ namespace nlsat { std::ostream& display_root_smt2(std::ostream& out, root_atom const& a, display_var_proc const& proc) const { if (a.i() == 1 && m_pm.degree(a.p(), a.x()) == 1) - return display_linear_root_smt2(out, a, proc); - else - return display_root(out, a, proc); + return display_linear_root_smt2(out, a, proc); +#if 1 + out << "(exists ("; + for (unsigned j = 0; j < a.i(); ++j) { + std::string y = std::string("y") + std::to_string(j); + out << "(" << y << " Real) "; + } + out << ")\n"; + out << "(and\n"; + for (unsigned j = 0; j < a.i(); ++j) { + std::string y = std::string("y") + std::to_string(j); + display_poly_root(out, y.c_str(), a, proc); + } + for (unsigned j = 0; j + 1 < a.i(); ++j) { + std::string y1 = std::string("y") + std::to_string(j); + std::string y2 = std::string("y") + std::to_string(j+1); + out << "(< " << y1 << " " << y2 << ")\n"; + } + std::string y0 = "y0"; + std::string yn = "y" + std::to_string(a.i() - 1); + switch (a.get_kind()) { + case atom::ROOT_LT: out << "(< "; proc(out, a.x()); out << " " << y0 << ")"; break; + case atom::ROOT_GT: out << "(> "; proc(out, a.x()); out << " " << yn << ")"; break; + case atom::ROOT_LE: out << "(<= "; proc(out, a.x()); out << " " << y0 << ")"; break; + case atom::ROOT_GE: out << "(>= "; proc(out, a.x()); out << " " << yn << ")"; break; + case atom::ROOT_EQ: out << "(= "; proc(out, a.x()); out << " " << y0 << ")"; NOT_IMPLEMENTED_YET(); break; + } + out << "))"; + return out; +#endif + + + return display_root(out, a, proc); } std::ostream& display_root(std::ostream & out, root_atom const & a, display_var_proc const & proc) const { From d743e1b47c44b5f53d67952f9be327e7b5af1b3a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2024 19:11:35 -0800 Subject: [PATCH 194/224] add note that the encoding is a first approximation 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 62b55908a..7f44cdbcd 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -3163,6 +3163,7 @@ namespace nlsat { if (a.i() == 1 && m_pm.degree(a.p(), a.x()) == 1) return display_linear_root_smt2(out, a, proc); #if 1 + // A first approximation: this encoding assumes roots are distinct out << "(exists ("; for (unsigned j = 0; j < a.i(); ++j) { std::string y = std::string("y") + std::to_string(j); From 446a9dec080fd0d18825e791e6215e4b6d3738f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2024 19:26:50 -0800 Subject: [PATCH 195/224] distinguish vs-arch from arch identifier Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index 506288738..e3f874d57 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -195,12 +195,13 @@ def mk_build_dir(arch): build_path = get_build_dir(arch) if not check_build_dir(build_path) or FORCE_MK: mk_dir(build_path) + vsarch = arc if arch == "arm64": - arch = "amd64_arm64" + vsarch = "amd64_arm64" cmds = [] cmds.append(f"cd {build_path}") - cmds.append('call "%VCINSTALLDIR%Auxiliary\\build\\vcvarsall.bat" ' + arch) + cmds.append('call "%VCINSTALLDIR%Auxiliary\\build\\vcvarsall.bat" ' + vsarch) cmd = [] cmd.append("cmake -S .") if DOTNET_CORE_ENABLED: From f4474a3edb0e56f11d1e45e4318b2c7256306811 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2024 20:30:56 -0800 Subject: [PATCH 196/224] typo Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index e3f874d57..fa5358621 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -195,7 +195,7 @@ def mk_build_dir(arch): build_path = get_build_dir(arch) if not check_build_dir(build_path) or FORCE_MK: mk_dir(build_path) - vsarch = arc + vsarch = arch if arch == "arm64": vsarch = "amd64_arm64" From 8555f2558778e4416e361b5fe64248dac37d10d3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 4 Feb 2024 21:08:04 -0800 Subject: [PATCH 197/224] add todo note, and log more lemmas Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 7f44cdbcd..79a42e678 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -1853,9 +1853,12 @@ namespace nlsat { tout << "new valid clause:\n"; display(tout, m_lazy_clause.size(), m_lazy_clause.data()) << "\n";); + + if (m_log_lemmas) + log_lemma(verbose_stream(), m_lazy_clause.size(), m_lazy_clause.data(), true); + if (m_check_lemmas) { check_lemma(m_lazy_clause.size(), m_lazy_clause.data(), true, nullptr); - log_lemma(verbose_stream(), m_lazy_clause.size(), m_lazy_clause.data(), true); m_valids.push_back(mk_clause_core(m_lazy_clause.size(), m_lazy_clause.data(), false, nullptr)); } @@ -3163,7 +3166,6 @@ namespace nlsat { if (a.i() == 1 && m_pm.degree(a.p(), a.x()) == 1) return display_linear_root_smt2(out, a, proc); #if 1 - // A first approximation: this encoding assumes roots are distinct out << "(exists ("; for (unsigned j = 0; j < a.i(); ++j) { std::string y = std::string("y") + std::to_string(j); @@ -3180,14 +3182,16 @@ namespace nlsat { std::string y2 = std::string("y") + std::to_string(j+1); out << "(< " << y1 << " " << y2 << ")\n"; } - std::string y0 = "y0"; + // TODO we need (forall z : z < yn . p(z) => z = y1 or ... z = y_{n-1}) + // to say y1, .., yn are the first n distinct roots. + // std::string yn = "y" + std::to_string(a.i() - 1); switch (a.get_kind()) { - case atom::ROOT_LT: out << "(< "; proc(out, a.x()); out << " " << y0 << ")"; break; + case atom::ROOT_LT: out << "(< "; proc(out, a.x()); out << " " << yn << ")"; break; case atom::ROOT_GT: out << "(> "; proc(out, a.x()); out << " " << yn << ")"; break; - case atom::ROOT_LE: out << "(<= "; proc(out, a.x()); out << " " << y0 << ")"; break; + case atom::ROOT_LE: out << "(<= "; proc(out, a.x()); out << " " << yn << ")"; break; case atom::ROOT_GE: out << "(>= "; proc(out, a.x()); out << " " << yn << ")"; break; - case atom::ROOT_EQ: out << "(= "; proc(out, a.x()); out << " " << y0 << ")"; NOT_IMPLEMENTED_YET(); break; + case atom::ROOT_EQ: out << "(= "; proc(out, a.x()); out << " " << yn << ")"; NOT_IMPLEMENTED_YET(); break; } out << "))"; return out; From 683070a175eb6d9621d7464f7cbb013897df07a4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Feb 2024 10:44:41 -0800 Subject: [PATCH 198/224] finish encoding of n'th root Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 79a42e678..1b4924c6a 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -3182,10 +3182,24 @@ namespace nlsat { std::string y2 = std::string("y") + std::to_string(j+1); out << "(< " << y1 << " " << y2 << ")\n"; } + + std::string yn = "y" + std::to_string(a.i() - 1); + // TODO we need (forall z : z < yn . p(z) => z = y1 or ... z = y_{n-1}) // to say y1, .., yn are the first n distinct roots. // - std::string yn = "y" + std::to_string(a.i() - 1); + out << "(forall ((z Real)) (=> (and (< z " << yn << ") "; display_poly_root(out, "z", a, proc) << ") "; + if (a.i() == 1) { + out << "false))\n"; + } + else { + out << "(or "; + for (unsigned j = 0; j + 1 < a.i(); ++j) { + std::string y1 = std::string("y") + std::to_string(j); + out << "(= z " << y1 << ") "; + } + out << ")))\n"; + } switch (a.get_kind()) { case atom::ROOT_LT: out << "(< "; proc(out, a.x()); out << " " << yn << ")"; break; case atom::ROOT_GT: out << "(> "; proc(out, a.x()); out << " " << yn << ")"; break; From f4eaa6fc984659e5118a77d8aec1dc1c8fa8b6b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Feb 2024 14:41:29 -0800 Subject: [PATCH 199/224] improve logging Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_solver.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 1b4924c6a..baec54b1f 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -916,15 +916,20 @@ namespace nlsat { } void log_lemma(std::ostream& out, unsigned n, literal const* cls, bool is_valid) { + ++m_lemma_count; + out << "(set-logic NRA)\n"; if (is_valid) { display_smt2_bool_decls(out); display_smt2_arith_decls(out); } else display_smt2(out); - display_smt2(out << "(assert (not ", n, cls) << "))\n"; + for (unsigned i = 0; i < n; ++i) + display_smt2(out << "(assert ", ~cls[i]) << ")\n"; display(out << "(echo \"#" << m_lemma_count << " ", n, cls) << "\")\n"; out << "(check-sat)\n(reset)\n"; + + TRACE("nlsat", display(tout << "(echo \"#" << m_lemma_count << " ", n, cls) << "\")\n"); } clause * mk_clause_core(unsigned num_lits, literal const * lits, bool learned, _assumption_set a) { @@ -941,10 +946,9 @@ namespace nlsat { clause * mk_clause(unsigned num_lits, literal const * lits, bool learned, _assumption_set a) { SASSERT(num_lits > 0); clause * cls = mk_clause_core(num_lits, lits, learned, a); - ++m_lemma_count; TRACE("nlsat_sort", display(tout << "mk_clause:\n", *cls) << "\n";); std::sort(cls->begin(), cls->end(), lit_lt(*this)); - TRACE("nlsat_sort", display(tout << "#" << m_lemma_count << " after sort:\n", *cls) << "\n";); + TRACE("nlsat", display(tout << " after sort:\n", *cls) << "\n";); if (learned && m_log_lemmas) { log_lemma(verbose_stream(), *cls); } @@ -2100,6 +2104,9 @@ namespace nlsat { if (m_check_lemmas) { check_lemma(m_lemma.size(), m_lemma.data(), false, m_lemma_assumptions.get()); } + + if (m_log_lemmas) + log_lemma(verbose_stream(), m_lemma.size(), m_lemma.data(), false); // There are two possibilities: // 1) m_lemma contains only literals from previous stages, and they From c40e72aaa3e3a7fea2824d2cf4d66958fc202ea8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 5 Feb 2024 15:31:33 -0800 Subject: [PATCH 200/224] include debug output --- src/nlsat/nlsat_interval_set.cpp | 3 +-- src/nlsat/nlsat_solver.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index bf240119e..693690380 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -663,9 +663,8 @@ namespace nlsat { continue; m_already_visited.setx(lidx, true, false); js.push_back(l); - if (s->m_intervals[i].m_clause) { + if (s->m_intervals[i].m_clause) clauses.push_back(const_cast(s->m_intervals[i].m_clause)); - } } for (unsigned i = 0; i < num; i++) { literal l = s->m_intervals[i].m_justification; diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index baec54b1f..71a6b7a47 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -1273,7 +1273,7 @@ namespace nlsat { if (include_l) core.push_back(~l); auto j = mk_lazy_jst(m_allocator, core.size(), core.data(), clauses.size(), clauses.data()); - TRACE("nlsat_resolve", display(tout, j); display_eval(tout, j)); + TRACE("nlsat_resolve", display(tout, j); display_eval(tout << "evaluated:", j)); assign(l, j); SASSERT(value(l) == l_true); } @@ -1384,7 +1384,9 @@ namespace nlsat { tmp = m_ism.mk_union(curr_set, xk_set); if (m_ism.is_full(tmp)) { TRACE("nlsat_inf_set", tout << "infeasible set + current set = R, skip literal\n"; - display(tout, cls) << "\n";); + display(tout, cls) << "\n"; + m_ism.display(tout, tmp); tout << "\n"; + ); R_propagate(~l, tmp, false); continue; } From 937d4aa8f464ff98ff0465e333f9645b11213651 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Feb 2024 12:40:30 -0800 Subject: [PATCH 201/224] move files from lib and java directory to bin Signed-off-by: Nikolaj Bjorner --- scripts/mk_win_dist_cmake.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/scripts/mk_win_dist_cmake.py b/scripts/mk_win_dist_cmake.py index fa5358621..f3c83cfb6 100644 --- a/scripts/mk_win_dist_cmake.py +++ b/scripts/mk_win_dist_cmake.py @@ -77,6 +77,12 @@ def get_build_dist_path(arch): def get_bin_dist_path(arch): return os.path.join(get_build_dist_path(arch), "bin") +def get_lib_dist_path(arch): + return os.path.join(get_build_dist_path(arch), "lib") + +def get_java_dist_path(arch): + return os.path.join(get_build_dist_path(arch), "java") + def get_dist_path(arch): return os.path.join(DIST_DIR, arch) @@ -360,6 +366,21 @@ def cp_dotnet(arch): dist_dir, dirs_exist_ok=True) +def cp_into_bin(arch): + if is_verbose(): + print("copy lib") + lib_dir = get_lib_dist_path(arch) + bin_dir = get_bin_dist_path(arch) + shutil.copyfile(os.path.join(lib_dir, "libz3.lib"), + os.path.join(bin_dir, "libz3.lib")) + shutil.rmtree(lib_dir) + if JAVA_ENABLED: + java_dir = get_java_dist_path(arch) + shutil.copytree(java_dir, + bin_dir, + dirs_exist_ok=True) + shutil.rmtree(java_dir) + def cp_pdb(arch): if is_verbose(): print("copy pdb") @@ -367,7 +388,7 @@ def cp_pdb(arch): bin_path = get_bin_dist_path(arch) mk_dir(bin_path) for f in os.listdir(build_dir): - if f.endswith("pdb"): + if f.endswith("libz3.pdb"): shutil.copy(os.path.join(build_dir, f), bin_path) def build_for_arch(arch): @@ -377,6 +398,7 @@ def build_for_arch(arch): cp_pdb(arch) cp_dotnet(arch) cp_vs_runtime(arch) + cp_into_bin(arch) mk_zip(arch) # Entry point From 53f89a81c181926956dc26bfcd6466acf1579b41 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Thu, 8 Feb 2024 14:06:43 +0700 Subject: [PATCH 202/224] Fix some typos. (#7115) --- .../bounded model checking/loop_unrolling.smt2 | 2 +- .../loop_unrolling_bitvec.smt2 | 2 +- examples/python/proofreplay.py | 2 +- src/api/python/z3/z3.py | 2 +- src/ast/rewriter/seq_rewriter.cpp | 18 +++++++++--------- src/ast/rewriter/seq_rewriter.h | 2 +- src/ast/rewriter/seq_skolem.h | 2 +- src/opt/opt_lns.cpp | 2 +- src/qe/mbp/mbp_arith.cpp | 2 +- src/qe/mbp/mbp_solve_plugin.cpp | 2 +- src/qe/qe.cpp | 4 ++-- src/qe/qe_mbp.cpp | 2 +- src/smt/smt_internalizer.cpp | 2 +- src/smt/theory_arith_int.h | 2 +- src/smt/theory_utvpi.cpp | 2 +- src/tactic/core/tseitin_cnf_tactic.cpp | 4 ++-- src/tactic/dependent_expr_state_tactic.h | 2 +- src/tactic/fd_solver/smtfd_solver.cpp | 2 +- src/tactic/goal_proof_converter.h | 2 +- src/tactic/ufbv/quasi_macros_tactic.h | 2 +- src/test/lp/smt_reader.h | 4 ++-- src/test/mpz.cpp | 2 +- 22 files changed, 33 insertions(+), 33 deletions(-) diff --git a/examples/SMT-LIB2/bounded model checking/loop_unrolling.smt2 b/examples/SMT-LIB2/bounded model checking/loop_unrolling.smt2 index 45ce586f1..746767809 100644 --- a/examples/SMT-LIB2/bounded model checking/loop_unrolling.smt2 +++ b/examples/SMT-LIB2/bounded model checking/loop_unrolling.smt2 @@ -50,7 +50,7 @@ ) ) -; Transition funcion +; Transition function (define-fun body ((f_0 Int) (f Int) (i_0 Int) (i_1 Int)(_A (Array Int Int)) (_x Int)) Bool (and (= f (ite (= _x (select _A i_0)) 1 f_0)) diff --git a/examples/SMT-LIB2/bounded model checking/loop_unrolling_bitvec.smt2 b/examples/SMT-LIB2/bounded model checking/loop_unrolling_bitvec.smt2 index ceb792875..a4db5dd98 100644 --- a/examples/SMT-LIB2/bounded model checking/loop_unrolling_bitvec.smt2 +++ b/examples/SMT-LIB2/bounded model checking/loop_unrolling_bitvec.smt2 @@ -52,7 +52,7 @@ ) ) -; Transition funcion +; Transition function (define-fun body ((f_0 IntValue) (f IntValue) (i_0 IntValue) (i_1 IntValue)(_A (Array IntValue IntValue)) (_x IntValue)) Bool (and (= f (ite (= _x (select _A i_0)) #x00000001 f_0)) diff --git a/examples/python/proofreplay.py b/examples/python/proofreplay.py index c8c9ff47e..5c82f43a9 100644 --- a/examples/python/proofreplay.py +++ b/examples/python/proofreplay.py @@ -86,7 +86,7 @@ if __name__ == "__main__": # The pair -inst 2 indicates that two quantifier instantiations were not self-validated # They were instead validated using a call to SMT solving. A log for an smt invocation # is exemplified in the next line. - # Note that the pair +inst 6 indicates that 6 quantifier instantations were validated + # Note that the pair +inst 6 indicates that 6 quantifier instantiations were validated # using a syntactic (cheap) check. Some quantifier instantiations based on quantifier elimination # are not simple substitutions and therefore a simple syntactic check does not suffice. set_param("solver.proof.check", True) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 2f34b91f6..37f161a05 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8984,7 +8984,7 @@ def substitute_funs(t, *m): m = m1 if z3_debug(): _z3_assert(is_expr(t), "Z3 expression expected") - _z3_assert(all([isinstance(p, tuple) and is_func_decl(p[0]) and is_expr(p[1]) for p in m]), "Z3 invalid substitution, funcion pairs expected.") + _z3_assert(all([isinstance(p, tuple) and is_func_decl(p[0]) and is_expr(p[1]) for p in m]), "Z3 invalid substitution, function pairs expected.") num = len(m) _from = (FuncDecl * num)() _to = (Ast * num)() diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 12ab1cbb1..aa5813224 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -3478,7 +3478,7 @@ expr_ref seq_rewriter::mk_antimirov_deriv_union(expr* d1, expr* d2) { // // restrict(d, false) = [] // -// it is already assumed that the restriction takes place witin a branch +// it is already assumed that the restriction takes place within a branch // so the condition is not added explicitly but propagated down in order to eliminate // infeasible cases expr_ref seq_rewriter::mk_antimirov_deriv_restrict(expr* e, expr* d, expr* cond) { @@ -3717,7 +3717,7 @@ expr_ref seq_rewriter::mk_regex_concat(expr* r, expr* s) { result = re().mk_plus(re().mk_full_char(ele_sort)); else if (re().is_concat(r, r1, r2)) // create the resulting concatenation in right-associative form except for the following case - // TODO: maintain the followig invariant for A ++ B{m,n} + C + // TODO: maintain the following invariant for A ++ B{m,n} + C // concat(concat(A, B{m,n}), C) (if A != () and C != ()) // concat(B{m,n}, C) (if A == () and C != ()) // where A, B, C are regexes @@ -3725,11 +3725,11 @@ expr_ref seq_rewriter::mk_regex_concat(expr* r, expr* s) { // In other words, do not make A ++ B{m,n} into right-assoc form, but keep B{m,n} at the top // This will help to identify this situation in the merge routine: // concat(concat(A, B{0,m}), C) | concat(concat(A, B{0,n}), C) - // simplies to + // simplifies to // concat(concat(A, B{0,max(m,n)}), C) // analogously: // concat(concat(A, B{0,m}), C) & concat(concat(A, B{0,n}), C) - // simplies to + // simplifies to // concat(concat(A, B{0,min(m,n)}), C) result = mk_regex_concat(r1, mk_regex_concat(r2, s)); else { @@ -3850,12 +3850,12 @@ bool seq_rewriter::pred_implies(expr* a, expr* b) { Utility function to decide if two BDDs (nested if-then-else terms) have exactly the same structure and conditions. */ -bool seq_rewriter::ite_bdds_compatabile(expr* a, expr* b) { +bool seq_rewriter::ite_bdds_compatible(expr* a, expr* b) { expr* ca = nullptr, *a1 = nullptr, *a2 = nullptr; expr* cb = nullptr, *b1 = nullptr, *b2 = nullptr; if (m().is_ite(a, ca, a1, a2) && m().is_ite(b, cb, b1, b2)) { - return (ca == cb) && ite_bdds_compatabile(a1, b1) - && ite_bdds_compatabile(a2, b2); + return (ca == cb) && ite_bdds_compatible(a1, b1) + && ite_bdds_compatible(a2, b2); } else if (m().is_ite(a) || m().is_ite(b)) { return false; @@ -3915,7 +3915,7 @@ expr_ref seq_rewriter::mk_der_op_rec(decl_kind k, expr* a, expr* b) { // sophisticated: in an antimirov union of n terms, we really // want to check if any pair of them is compatible. else if (m().is_ite(a) && m().is_ite(b) && - !ite_bdds_compatabile(a, b)) { + !ite_bdds_compatible(a, b)) { k = _OP_RE_ANTIMIROV_UNION; } #endif @@ -4269,7 +4269,7 @@ expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) { } else if (re().is_reverse(r, r1)) { if (re().is_to_re(r1, r2)) { - // First try to exctract hd and tl such that r = hd ++ tl and |tl|=1 + // First try to extract hd and tl such that r = hd ++ tl and |tl|=1 expr_ref hd(m()), tl(m()); if (get_head_tail_reversed(r2, hd, tl)) { // Use mk_der_cond to normalize diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 92a6a17fa..af4756576 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -201,7 +201,7 @@ class seq_rewriter { expr_ref mk_der_compl(expr* a); expr_ref mk_der_cond(expr* cond, expr* ele, sort* seq_sort); expr_ref mk_der_antimirov_union(expr* r1, expr* r2); - bool ite_bdds_compatabile(expr* a, expr* b); + bool ite_bdds_compatible(expr* a, expr* b); /* if r has the form deriv(en..deriv(e1,to_re(s))..) returns 's = [e1..en]' else returns '() in r'*/ expr_ref is_nullable_symbolic_regex(expr* r, sort* seq_sort); #ifdef Z3DEBUG diff --git a/src/ast/rewriter/seq_skolem.h b/src/ast/rewriter/seq_skolem.h index 4b828abf6..4e327f0fa 100644 --- a/src/ast/rewriter/seq_skolem.h +++ b/src/ast/rewriter/seq_skolem.h @@ -8,7 +8,7 @@ Module Name: Abstract: Skolem function support for sequences. - Skolem functions are auxiliary funcions useful for axiomatizing sequence + Skolem functions are auxiliary functions useful for axiomatizing sequence operations. Author: diff --git a/src/opt/opt_lns.cpp b/src/opt/opt_lns.cpp index ba5a071d3..878c4a3ea 100644 --- a/src/opt/opt_lns.cpp +++ b/src/opt/opt_lns.cpp @@ -196,7 +196,7 @@ namespace opt { } unsigned lns::improve_linear(model_ref& mdl) { - scoped_bounding _scoped_bouding(*this); + scoped_bounding _scoped_bounding(*this); unsigned num_improved = 0; unsigned max_conflicts = m_max_conflicts; while (m.inc()) { diff --git a/src/qe/mbp/mbp_arith.cpp b/src/qe/mbp/mbp_arith.cpp index 91813c697..255c4f814 100644 --- a/src/qe/mbp/mbp_arith.cpp +++ b/src/qe/mbp/mbp_arith.cpp @@ -674,7 +674,7 @@ namespace mbp { id = mbo.add_var(r, a.is_int(v)); tids.insert(v, id); } - CTRACE("qe", kv.m_value.is_zero(), tout << mk_pp(v, m) << " has coefficeint 0\n";); + CTRACE("qe", kv.m_value.is_zero(), tout << mk_pp(v, m) << " has coefficient 0\n";); if (!kv.m_value.is_zero()) { coeffs.push_back(var(id, kv.m_value)); } diff --git a/src/qe/mbp/mbp_solve_plugin.cpp b/src/qe/mbp/mbp_solve_plugin.cpp index d46a09284..3820af59e 100644 --- a/src/qe/mbp/mbp_solve_plugin.cpp +++ b/src/qe/mbp/mbp_solve_plugin.cpp @@ -248,7 +248,7 @@ namespace mbp { return false; } - // returns `true` if a rewritting happened + // returns `true` if a rewriting happened bool try_int_mul_solve(expr *atom, bool is_pos, expr_ref &res) { if (!is_pos) diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 12365b204..325f343b4 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -157,8 +157,8 @@ namespace qe { // // Partition variables into buckets. - // The var_paritions buckets covering disjoint subsets of - // the conjuncts. The remaining variables in vars are non-partioned. + // The var_partitions buckets covering disjoint subsets of + // the conjuncts. The remaining variables in vars are non-partitioned. // bool partition_vars( unsigned num_vars, diff --git a/src/qe/qe_mbp.cpp b/src/qe/qe_mbp.cpp index 861c841a9..97f12238d 100644 --- a/src/qe/qe_mbp.cpp +++ b/src/qe/qe_mbp.cpp @@ -416,7 +416,7 @@ public: //don't use mbp_qel on some theories where model evaluation is //incomplete This is not a limitation of qel. Fix this either by //making mbp choices less dependent on the model evaluation methods - //or fix theory rewriters to make terms evalution complete + //or fix theory rewriters to make terms evaluation complete if (m_use_qel && !has_unsupported_th(fmls)) { bool dsub = m_dont_sub; m_dont_sub = !force_elim; diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index b6d1e2f2b..2b18d9a3f 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1830,7 +1830,7 @@ namespace smt { // Case) there is a variable old_v in the var-list of n. // // Remark: This variable was moved to the var-list of n due to a add_eq. - SASSERT(th->get_enode(old_v) != n); // this varialbe is not owned by n + SASSERT(th->get_enode(old_v) != n); // this variable is not owned by n SASSERT(n->get_root()->get_th_var(th_id) != null_theory_var); // the root has also a variable in its var-list. n->replace_th_var(v, th_id); push_trail(replace_th_var_trail( n, th_id, old_v)); diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index 4746040ce..cb3a83a0d 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -503,7 +503,7 @@ namespace smt { theory_var x_i = r.get_base_var(); SASSERT(is_int(x_i)); - // The following assertion is wrong. It may be violated in mixed-real-interger problems. + // The following assertion is wrong. It may be violated in mixed-real-integer problems. // The check is_gomory_cut_target will discard rows where any variable contains infinitesimals. // SASSERT(m_value[x_i].is_rational()); // infinitesimals are not used for integer variables SASSERT(!m_value[x_i].is_int()); // the base variable is not assigned to an integer value. diff --git a/src/smt/theory_utvpi.cpp b/src/smt/theory_utvpi.cpp index da2883938..2072474b0 100644 --- a/src/smt/theory_utvpi.cpp +++ b/src/smt/theory_utvpi.cpp @@ -11,7 +11,7 @@ Author: Revision History: - The implementaton is derived from theory_diff_logic. + The implementation is derived from theory_diff_logic. --*/ #include "smt/theory_utvpi.h" diff --git a/src/tactic/core/tseitin_cnf_tactic.cpp b/src/tactic/core/tseitin_cnf_tactic.cpp index 411b8aa6e..dce1fe459 100644 --- a/src/tactic/core/tseitin_cnf_tactic.cpp +++ b/src/tactic/core/tseitin_cnf_tactic.cpp @@ -905,10 +905,10 @@ public: void collect_param_descrs(param_descrs & r) override { insert_max_memory(r); - r.insert("common_patterns", CPK_BOOL, "minimize the number of auxiliary variables during CNF encoding by identifing commonly used patterns", "true"); + r.insert("common_patterns", CPK_BOOL, "minimize the number of auxiliary variables during CNF encoding by identifying commonly used patterns", "true"); r.insert("distributivity", CPK_BOOL, "minimize the number of auxiliary variables during CNF encoding by applying distributivity over unshared subformulas", "true"); r.insert("distributivity_blowup", CPK_UINT, "maximum overhead for applying distributivity during CNF encoding", "32"); - r.insert("ite_chaing", CPK_BOOL, "minimize the number of auxiliary variables during CNF encoding by identifing if-then-else chains", "true"); + r.insert("ite_chaing", CPK_BOOL, "minimize the number of auxiliary variables during CNF encoding by identifying if-then-else chains", "true"); r.insert("ite_extra", CPK_BOOL, "add redundant clauses (that improve unit propagation) when encoding if-then-else formulas", "true"); } diff --git a/src/tactic/dependent_expr_state_tactic.h b/src/tactic/dependent_expr_state_tactic.h index b5ea4d6c1..4d695e300 100644 --- a/src/tactic/dependent_expr_state_tactic.h +++ b/src/tactic/dependent_expr_state_tactic.h @@ -64,7 +64,7 @@ public: } /** - * size(), [](), update() and inconsisent() implement the abstract interface of dependent_expr_state + * size(), [](), update() and inconsistent() implement the abstract interface of dependent_expr_state */ unsigned qtail() const override { return m_goal->size(); } diff --git a/src/tactic/fd_solver/smtfd_solver.cpp b/src/tactic/fd_solver/smtfd_solver.cpp index 01370812f..4d0912fdc 100644 --- a/src/tactic/fd_solver/smtfd_solver.cpp +++ b/src/tactic/fd_solver/smtfd_solver.cpp @@ -433,7 +433,7 @@ namespace smtfd { void populate_model(model_ref& mdl, expr_ref_vector const& terms); /** - * \brief check consistency properties that can only be achived using a global analysis of terms + * \brief check consistency properties that can only be achieved using a global analysis of terms */ void global_check(expr_ref_vector const& core); diff --git a/src/tactic/goal_proof_converter.h b/src/tactic/goal_proof_converter.h index a17ff0ea1..cfe0d9709 100644 --- a/src/tactic/goal_proof_converter.h +++ b/src/tactic/goal_proof_converter.h @@ -37,7 +37,7 @@ public: } proof_ref operator()(ast_manager & m, unsigned num_source, proof * const * source) override { - // ignore the proofs from the arguments, instead obtain the proofs fromt he subgoals. + // ignore the proofs from the arguments, instead obtain the proofs from the subgoals. SASSERT(num_source == 0); proof_converter_ref_buffer pc_buffer; for (goal_ref g : m_goals) { diff --git a/src/tactic/ufbv/quasi_macros_tactic.h b/src/tactic/ufbv/quasi_macros_tactic.h index faa939954..ec2a45527 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.h +++ b/src/tactic/ufbv/quasi_macros_tactic.h @@ -18,7 +18,7 @@ Tactic Documentation ## Tactic quasi-macro-finder ### Short Description -dentifies and applies quasi-macros. +Identifies and applies quasi-macros. ### Long Description diff --git a/src/test/lp/smt_reader.h b/src/test/lp/smt_reader.h index 7a0ea5ff9..0e638399f 100644 --- a/src/test/lp/smt_reader.h +++ b/src/test/lp/smt_reader.h @@ -343,7 +343,7 @@ namespace lp { solver->add_constraint(&c); } - void create_equality_contraint_for_var(column* col, bound * b, lar_solver *solver) { + void create_equality_constraint_for_var(column* col, bound * b, lar_solver *solver) { lar_constraint c(EQ, b->m_fixed_value); var_index i = solver->add_var(col->m_name); c.add_variable_to_constraint(i, numeric_traits::one()); @@ -366,7 +366,7 @@ namespace lp { create_upper_constraint_for_var(col, b, solver); } if (b->m_value_is_fixed) { - create_equality_contraint_for_var(col, b, solver); + create_equality_constraint_for_var(col, b, solver); } } } diff --git a/src/test/mpz.cpp b/src/test/mpz.cpp index 694f13e96..2c76b3a66 100644 --- a/src/test/mpz.cpp +++ b/src/test/mpz.cpp @@ -322,7 +322,7 @@ void tst_scoped() { #define NUM_PRIMES 168 unsigned g_primes[NUM_PRIMES] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997 }; -// Return a big number by multipling powers of the first NUM_PRIMES. +// Return a big number by multiplying powers of the first NUM_PRIMES. // - ratio: rand() % ratio == 0 is used to decide whether a specific prime will be included or not. // - max_pw: if condition above is satisfied, then we use (rand() % max_pw) + 1 as the power. void mk_big_num(unsynch_mpz_manager & m, unsigned ratio, unsigned max_pw, mpz & r) { From f1d97c7a3a5ed37a23226f1bffe359421115b7ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Feb 2024 20:30:17 +0700 Subject: [PATCH 203/224] allow callbacks to be nested --- src/api/python/z3/z3.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 37f161a05..1bfd987d6 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -11570,47 +11570,54 @@ def user_prop_fresh(ctx, _new_ctx): def user_prop_fixed(ctx, cb, id, value): prop = _prop_closures.get(ctx) - prop.cb = cb + old_cb = prop.cb + prop.cb = cb id = _to_expr_ref(to_Ast(id), prop.ctx()) value = _to_expr_ref(to_Ast(value), prop.ctx()) prop.fixed(id, value) - prop.cb = None + prop.cb = old_cb def user_prop_created(ctx, cb, id): prop = _prop_closures.get(ctx) + old_cb = prop.cb prop.cb = cb id = _to_expr_ref(to_Ast(id), prop.ctx()) prop.created(id) - prop.cb = None + prop.cb = old_cb + def user_prop_final(ctx, cb): prop = _prop_closures.get(ctx) + old_cb = prop.cb prop.cb = cb prop.final() - prop.cb = None + prop.cb = old_cb def user_prop_eq(ctx, cb, x, y): prop = _prop_closures.get(ctx) + old_cb = prop.cb prop.cb = cb x = _to_expr_ref(to_Ast(x), prop.ctx()) y = _to_expr_ref(to_Ast(y), prop.ctx()) prop.eq(x, y) - prop.cb = None + prop.cb = old_cb def user_prop_diseq(ctx, cb, x, y): prop = _prop_closures.get(ctx) + old_cb = prop.cb prop.cb = cb x = _to_expr_ref(to_Ast(x), prop.ctx()) y = _to_expr_ref(to_Ast(y), prop.ctx()) prop.diseq(x, y) - prop.cb = None + prop.cb = old_cb def user_prop_decide(ctx, cb, t, idx, phase): prop = _prop_closures.get(ctx) + old_cb = prop.cb prop.cb = cb t = _to_expr_ref(to_Ast(t_ref), prop.ctx()) prop.decide(t, idx, phase) - prop.cb = None + prop.cb = old_cb _user_prop_push = Z3_push_eh(user_prop_push) From 4d06c399cc977f905290250997e0e1ab96c3d37f Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 13 Feb 2024 10:51:44 -1000 Subject: [PATCH 204/224] replace DEBUG_CODE by #ifdef Z3DEBUG in nlsat Signed-off-by: Lev Nachmanson --- src/nlsat/nlsat_evaluator.cpp | 35 +++++++++++---------- src/nlsat/nlsat_explain.cpp | 27 ++++++++-------- src/nlsat/nlsat_interval_set.cpp | 13 ++++---- src/nlsat/nlsat_solver.cpp | 52 +++++++++++++++++-------------- src/nlsat/tactic/nlsat_tactic.cpp | 4 ++- 5 files changed, 70 insertions(+), 61 deletions(-) diff --git a/src/nlsat/nlsat_evaluator.cpp b/src/nlsat/nlsat_evaluator.cpp index 1f93737dc..ca6f9efae 100644 --- a/src/nlsat/nlsat_evaluator.cpp +++ b/src/nlsat/nlsat_evaluator.cpp @@ -286,23 +286,24 @@ namespace nlsat { } bool check_invariant() const { - DEBUG_CODE( - SASSERT(m_sections.size() == m_sorted_sections.size()); - for (unsigned i = 0; i < m_sorted_sections.size(); i++) { - SASSERT(m_sorted_sections[i] < m_sections.size()); - SASSERT(m_sections[m_sorted_sections[i]].m_pos == i); - } - unsigned total_num_sections = 0; - unsigned total_num_signs = 0; - for (unsigned i = 0; i < m_info.size(); i++) { - SASSERT(m_info[i].m_first_section <= m_poly_sections.size()); - SASSERT(m_info[i].m_num_roots == 0 || m_info[i].m_first_section < m_poly_sections.size()); - SASSERT(m_info[i].m_first_sign < m_poly_signs.size()); - total_num_sections += m_info[i].m_num_roots; - total_num_signs += m_info[i].m_num_roots + 1; - } - SASSERT(total_num_sections == m_poly_sections.size()); - SASSERT(total_num_signs == m_poly_signs.size());); +#ifdef Z3DEBUG + SASSERT(m_sections.size() == m_sorted_sections.size()); + for (unsigned i = 0; i < m_sorted_sections.size(); i++) { + SASSERT(m_sorted_sections[i] < m_sections.size()); + SASSERT(m_sections[m_sorted_sections[i]].m_pos == i); + } + unsigned total_num_sections = 0; + unsigned total_num_signs = 0; + for (unsigned i = 0; i < m_info.size(); i++) { + SASSERT(m_info[i].m_first_section <= m_poly_sections.size()); + SASSERT(m_info[i].m_num_roots == 0 || m_info[i].m_first_section < m_poly_sections.size()); + SASSERT(m_info[i].m_first_sign < m_poly_signs.size()); + total_num_sections += m_info[i].m_num_roots; + total_num_signs += m_info[i].m_num_roots + 1; + } + SASSERT(total_num_sections == m_poly_sections.size()); + SASSERT(total_num_signs == m_poly_signs.size()); +#endif return true; } diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index 0b76a14ef..87fda76ef 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -1531,12 +1531,13 @@ namespace nlsat { m_solver.display(tout, num, ls); m_solver.display(tout);); - DEBUG_CODE( - for (unsigned i = 0; i < num; ++i) { - SASSERT(m_solver.value(ls[i]) == l_true); - atom* a = m_atoms[ls[i].var()]; - SASSERT(!a || m_evaluator.eval(a, ls[i].sign())); - }); +#ifdef Z3DEBUG + for (unsigned i = 0; i < num; ++i) { + SASSERT(m_solver.value(ls[i]) == l_true); + atom* a = m_atoms[ls[i].var()]; + SASSERT(!a || m_evaluator.eval(a, ls[i].sign())); + } +#endif split_literals(x, num, ls, lits); collect_polys(lits.size(), lits.data(), m_ps); var mx_var = max_var(m_ps); @@ -1571,13 +1572,13 @@ namespace nlsat { for (unsigned i = 0; i < result.size(); ++i) { result.set(i, ~result[i]); } - DEBUG_CODE( - TRACE("nlsat", m_solver.display(tout, result.size(), result.data()) << "\n"; ); - for (literal l : result) { - CTRACE("nlsat", l_true != m_solver.value(l), m_solver.display(tout, l) << " " << m_solver.value(l) << "\n";); - SASSERT(l_true == m_solver.value(l)); - }); - +#ifdef Z3DEBUG + TRACE("nlsat", m_solver.display(tout, result.size(), result.data()) << "\n"; ); + for (literal l : result) { + CTRACE("nlsat", l_true != m_solver.value(l), m_solver.display(tout, l) << " " << m_solver.value(l) << "\n";); + SASSERT(l_true == m_solver.value(l)); + } +#endif } void split_literals(var x, unsigned n, literal const* ls, svector& lits) { diff --git a/src/nlsat/nlsat_interval_set.cpp b/src/nlsat/nlsat_interval_set.cpp index 693690380..f928fd5b6 100644 --- a/src/nlsat/nlsat_interval_set.cpp +++ b/src/nlsat/nlsat_interval_set.cpp @@ -98,12 +98,13 @@ namespace nlsat { // Check if the intervals are valid, ordered, and are disjoint. bool check_interval_set(anum_manager & am, unsigned sz, interval const * ints) { - DEBUG_CODE( - for (unsigned i = 0; i < sz; i++) { - interval const & curr = ints[i]; - SASSERT(check_interval(am, curr)); - SASSERT(i >= sz - 1 || check_no_overlap(am, curr, ints[i+1])); - }); +#ifdef Z3DEBUG + for (unsigned i = 0; i < sz; i++) { + interval const & curr = ints[i]; + SASSERT(check_interval(am, curr)); + SASSERT(i >= sz - 1 || check_no_overlap(am, curr, ints[i+1])); + } +#endif return true; } diff --git a/src/nlsat/nlsat_solver.cpp b/src/nlsat/nlsat_solver.cpp index 71a6b7a47..d99603dcd 100644 --- a/src/nlsat/nlsat_solver.cpp +++ b/src/nlsat/nlsat_solver.cpp @@ -1868,7 +1868,8 @@ namespace nlsat { m_valids.push_back(mk_clause_core(m_lazy_clause.size(), m_lazy_clause.data(), false, nullptr)); } - DEBUG_CODE({ +#ifdef Z3DEBUG + { unsigned sz = m_lazy_clause.size(); for (unsigned i = 0; i < sz; i++) { literal l = m_lazy_clause[i]; @@ -1881,7 +1882,8 @@ namespace nlsat { SASSERT(l.sign() || m_bvalues[b] == l_true); } } - }); + } +#endif checkpoint(); resolve_clause(b, m_lazy_clause.size(), m_lazy_clause.data()); @@ -2191,19 +2193,20 @@ namespace nlsat { // ----------------------- bool check_watches() const { - DEBUG_CODE( - for (var x = 0; x < num_vars(); x++) { +#ifdef Z3DEBUG + for (var x = 0; x < num_vars(); x++) { clause_vector const & cs = m_watches[x]; unsigned sz = cs.size(); for (unsigned i = 0; i < sz; i++) { SASSERT(max_var(*(cs[i])) == x); } - }); + } +#endif return true; } bool check_bwatches() const { - DEBUG_CODE( +#ifdef Z3DEBUG for (bool_var b = 0; b < m_bwatches.size(); b++) { clause_vector const & cs = m_bwatches[b]; unsigned sz = cs.size(); @@ -2212,7 +2215,8 @@ namespace nlsat { SASSERT(max_var(c) == null_var); SASSERT(max_bvar(c) == b); } - }); + } +#endif return true; } @@ -2432,11 +2436,11 @@ namespace nlsat { // undo_until_size(0) undo_until_stage(null_var); m_cache.reset(); - DEBUG_CODE({ - for (var x = 0; x < num_vars(); x++) { - SASSERT(m_watches[x].empty()); - } - }); +#ifdef Z3DEBUG + for (var x = 0; x < num_vars(); x++) { + SASSERT(m_watches[x].empty()); + } +#endif // update m_perm mapping for (unsigned ext_x = 0; ext_x < sz; ext_x++) { // p: internal -> new pos @@ -2452,12 +2456,12 @@ namespace nlsat { SASSERT(m_infeasible[x] == 0); } m_inv_perm.swap(new_inv_perm); - DEBUG_CODE({ - for (var x = 0; x < num_vars(); x++) { - SASSERT(x == m_inv_perm[m_perm[x]]); - SASSERT(m_watches[x].empty()); - } - }); +#ifdef Z3DEBUG + for (var x = 0; x < num_vars(); x++) { + SASSERT(x == m_inv_perm[m_perm[x]]); + SASSERT(m_watches[x].empty()); + } +#endif m_pm.rename(sz, p); TRACE("nlsat_bool_assignment_bug", tout << "before reinit cache\n"; display_bool_assignment(tout);); reinit_cache(); @@ -2477,12 +2481,12 @@ namespace nlsat { var_vector p; p.append(m_perm); reorder(p.size(), p.data()); - DEBUG_CODE({ - for (var x = 0; x < num_vars(); x++) { - SASSERT(m_perm[x] == x); - SASSERT(m_inv_perm[x] == x); - } - }); +#ifdef Z3DEBUG + for (var x = 0; x < num_vars(); x++) { + SASSERT(m_perm[x] == x); + SASSERT(m_inv_perm[x] == x); + } +#endif } /** diff --git a/src/nlsat/tactic/nlsat_tactic.cpp b/src/nlsat/tactic/nlsat_tactic.cpp index 3baf9da87..9426de78e 100644 --- a/src/nlsat/tactic/nlsat_tactic.cpp +++ b/src/nlsat/tactic/nlsat_tactic.cpp @@ -125,7 +125,9 @@ class nlsat_tactic : public tactic { continue; // don't care md->register_decl(to_app(a)->get_decl(), val == l_true ? m.mk_true() : m.mk_false()); } - DEBUG_CODE(eval_model(*md.get(), g);); +#ifdef Z3DEBUG + eval_model(*md.get(), g); +#endif // VERIFY(eval_model(*md.get(), g)); mc = model2model_converter(md.get()); return ok; From dba2f788df715e7cb78881ff291f569d3df19778 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 14 Feb 2024 09:24:31 +0700 Subject: [PATCH 205/224] ci: Update `microsoft/setup-msbuild` to `v2` from `v1.3`. (#7119) This changes from using Node 16 to Node 20 internally, eliminating some deprecation warnings from within GitHub Actions. --- .github/workflows/Windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 08fe45462..74eb04d15 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -24,7 +24,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1.3 + uses: microsoft/setup-msbuild@v2 - run: | md build cd build From 155dfb10c49172bec5aeab459f288c290f721e31 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 14 Feb 2024 09:25:32 +0700 Subject: [PATCH 206/224] Fix some typos in identifiers. (#7118) --- src/api/z3_api.h | 2 +- src/smt/theory_arith_int.h | 4 ++-- src/util/sexpr.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index fa8ccfe03..cbf9803db 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -1363,7 +1363,7 @@ typedef enum { - 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. + - Z3_FILE_ACCESS_ERROR: A file could not be accessed. - Z3_INVALID_USAGE: API call is invalid in the current state. - Z3_INTERNAL_FATAL: An error internal to Z3 occurred. - Z3_DEC_REF_ERROR: Trying to decrement the reference counter of an AST that was deleted or the reference counter was not initialized with #Z3_inc_ref. diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index cb3a83a0d..75c8785a7 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -99,7 +99,7 @@ namespace smt { theory_var result = null_theory_var; numeral range; numeral new_range; - numeral small_range_thresold(1024); + numeral small_range_threshold(1024); unsigned n = 0; for (row const& row : m_rows) { theory_var v = row.get_base_var(); @@ -117,7 +117,7 @@ namespace smt { numeral const & u = upper_bound(v).get_rational(); new_range = u; new_range -= l; - if (new_range > small_range_thresold) { + if (new_range > small_range_threshold) { // } else if (result == null_theory_var || new_range < range) { diff --git a/src/util/sexpr.cpp b/src/util/sexpr.cpp index e20c56234..dcf427dfe 100644 --- a/src/util/sexpr.cpp +++ b/src/util/sexpr.cpp @@ -26,11 +26,11 @@ Notes: #endif struct sexpr_composite : public sexpr { - unsigned m_num_chilren; + unsigned m_num_children; sexpr * m_children[0]; sexpr_composite(unsigned num_children, sexpr * const * children, unsigned line, unsigned pos): sexpr(kind_t::COMPOSITE, line, pos), - m_num_chilren(num_children) { + m_num_children(num_children) { for (unsigned i = 0; i < num_children; i++) { m_children[i] = children[i]; children[i]->inc_ref(); @@ -107,7 +107,7 @@ std::string const & sexpr::get_string() const { unsigned sexpr::get_num_children() const { SASSERT(is_composite()); - return static_cast(this)->m_num_chilren; + return static_cast(this)->m_num_children; } sexpr * sexpr::get_child(unsigned idx) const { From 2b14793213363381f2ee0d674242aad9863e30c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 14 Feb 2024 17:08:09 +0700 Subject: [PATCH 207/224] #7117 probably overflow of unsigned for large capacity --- src/util/chashtable.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util/chashtable.h b/src/util/chashtable.h index 450d2bfa4..b15d6017f 100644 --- a/src/util/chashtable.h +++ b/src/util/chashtable.h @@ -161,8 +161,12 @@ protected: unsigned curr_cellar = (m_capacity - m_slots); unsigned new_slots = m_slots * 2; unsigned new_cellar = curr_cellar * 2; + if (new_slots < m_slots || new_cellar < curr_cellar) + throw default_exception("table overflow"); while (true) { unsigned new_capacity = new_slots + new_cellar; + if (new_capacity < new_slots) + throw default_exception("table overflow"); cell * new_table = alloc_table(new_capacity); cell * next_cell = copy_table(m_table, m_slots, m_capacity, new_table, new_slots, new_capacity, @@ -179,6 +183,8 @@ protected: return; } dealloc_vect(new_table, new_capacity); + if (2*new_cellar < new_cellar) + throw default_exception("table overflow"); new_cellar *= 2; } } From 84d592c1f2e42d16842222f1ed60a63661b9bf4c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 16 Feb 2024 09:59:57 +0700 Subject: [PATCH 208/224] fix #7121 Signed-off-by: Nikolaj Bjorner --- src/ast/converters/generic_model_converter.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/ast/converters/generic_model_converter.cpp b/src/ast/converters/generic_model_converter.cpp index 1e81f9131..c50d86cae 100644 --- a/src/ast/converters/generic_model_converter.cpp +++ b/src/ast/converters/generic_model_converter.cpp @@ -43,6 +43,7 @@ void generic_model_converter::operator()(model_ref & md) { expr_ref val(m); unsigned arity; bool reset_ev = false; + obj_map> uninterpreted; for (unsigned i = m_entries.size(); i-- > 0; ) { entry const& e = m_entries[i]; switch (e.m_instruction) { @@ -63,6 +64,13 @@ void generic_model_converter::operator()(model_ref & md) { reset_ev = old_val != nullptr; md->register_decl(e.m_f, val); } + // corner case when uninterpreted constants are eliminated + sort* s = e.m_f->get_range(); + if (m.is_uninterp(s) && !md->has_uninterpreted_sort(s)) { + uninterpreted.insert_if_not_there(s, {}); + if (!uninterpreted[s].contains(val)) + uninterpreted[s].push_back(val); + } } else { func_interp * old_val = md->get_func_interp(e.m_f); @@ -84,6 +92,9 @@ void generic_model_converter::operator()(model_ref & md) { break; } } + for (auto const& [s, u] : uninterpreted) { + md->register_usort(s, u.size(), u.data()); + } TRACE("model_converter", tout << "after generic_model_converter\n"; model_v2_pp(tout, *md);); } From 199ef30e0c528cc3b32277b65b15efb0618c2310 Mon Sep 17 00:00:00 2001 From: Cal Jacobson Date: Sun, 18 Feb 2024 18:20:24 +1300 Subject: [PATCH 209/224] conditionally depend on importlib_resources (#7116) In python >= 3.9, it's available as part of the stdlib. --- src/api/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 325fb4230..c3f65f848 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -341,7 +341,7 @@ setup( license='MIT License', keywords=['z3', 'smt', 'sat', 'prover', 'theorem'], packages=['z3'], - install_requires = ['importlib-resources'], + install_requires = ["importlib-resources; python_version < '3.9'"], include_package_data=True, package_data={ 'z3': [os.path.join('lib', '*'), os.path.join('include', '*.h'), os.path.join('include', 'c++', '*.h')] From f7691d34fd3e8dfe2cd0f3373ed05510e0d046c9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2024 08:16:01 -0800 Subject: [PATCH 210/224] fix generic example Signed-off-by: Nikolaj Bjorner --- examples/java/JavaGenericExample.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/java/JavaGenericExample.java b/examples/java/JavaGenericExample.java index 1a4ac6628..b2f30cd77 100644 --- a/examples/java/JavaGenericExample.java +++ b/examples/java/JavaGenericExample.java @@ -1366,10 +1366,10 @@ class JavaGenericExample System.out.println("EnumExample"); Log.append("EnumExample"); - Symbol name = ctx.mkSymbol("fruit"); + Symbol name = ctx.mkSymbol("fruit2"); - EnumSort fruit = ctx.mkEnumSort(name, ctx.mkSymbol("apple"), - ctx.mkSymbol("banana"), ctx.mkSymbol("orange")); + EnumSort fruit = ctx.mkEnumSort(name, ctx.mkSymbol("apple2"), + ctx.mkSymbol("banana2"), ctx.mkSymbol("orange2")); System.out.println((fruit.getConsts()[0])); System.out.println((fruit.getConsts()[1])); From a3d00ce35663ee707aa852acc0d1ac90e5938b9e Mon Sep 17 00:00:00 2001 From: Thomas Haas Date: Wed, 21 Feb 2024 17:39:58 +0100 Subject: [PATCH 211/224] Improved Java phantom references (#7131) * Reworked phantom reference handling. - Replaced IDecRefQueue with a new Z3ReferenceQueue class - Z3ReferenceQueue manages custom subclasses of phantom references in a doubly-linked list - Replaced all subclasses of IDecRefQueue with subclasses of Z3ReferenceQueue.Reference. These custom reference classes are embedded in the class they reference count. - Context now owns a single Z3ReferenceQueue for all types of references. * Made Statistics.Entry a static subclass * Made Context.close idempotent (as recommended) * Update CMakeLists.txt for building the Java API. * Updated CMakeLists.txt again. * Use correct SuppressWarning annotation to silence the compiler * Formatting --- src/api/java/AST.java | 16 ++- src/api/java/ASTDecRefQueue.java | 31 ---- src/api/java/ASTMap.java | 16 ++- src/api/java/ASTVector.java | 34 +++-- src/api/java/ApplyResult.java | 16 ++- src/api/java/ApplyResultDecRefQueue.java | 31 ---- src/api/java/AstMapDecRefQueue.java | 30 ---- src/api/java/AstVectorDecRefQueue.java | 30 ---- src/api/java/CMakeLists.txt | 21 +-- src/api/java/Constructor.java | 16 ++- src/api/java/ConstructorDecRefQueue.java | 12 -- src/api/java/ConstructorList.java | 16 ++- src/api/java/ConstructorListDecRefQueue.java | 12 -- src/api/java/Context.java | 135 +---------------- src/api/java/Fixedpoint.java | 17 ++- src/api/java/FixedpointDecRefQueue.java | 31 ---- src/api/java/FuncInterp.java | 30 +++- src/api/java/FuncInterpDecRefQueue.java | 31 ---- src/api/java/FuncInterpEntryDecRefQueue.java | 30 ---- src/api/java/Goal.java | 16 ++- src/api/java/GoalDecRefQueue.java | 30 ---- src/api/java/IDecRefQueue.java | 83 ----------- src/api/java/Model.java | 16 ++- src/api/java/ModelDecRefQueue.java | 30 ---- src/api/java/Optimize.java | 16 ++- src/api/java/OptimizeDecRefQueue.java | 30 ---- src/api/java/ParamDescrs.java | 16 ++- src/api/java/ParamDescrsDecRefQueue.java | 31 ---- src/api/java/Params.java | 16 ++- src/api/java/ParamsDecRefQueue.java | 30 ---- src/api/java/Probe.java | 16 ++- src/api/java/ProbeDecRefQueue.java | 32 ----- src/api/java/Simplifier.java | 20 ++- src/api/java/SimplifierDecRefQueue.java | 31 ---- src/api/java/Solver.java | 16 ++- src/api/java/SolverDecRefQueue.java | 27 ---- src/api/java/Statistics.java | 20 ++- src/api/java/StatisticsDecRefQueue.java | 30 ---- src/api/java/Tactic.java | 17 ++- src/api/java/TacticDecRefQueue.java | 31 ---- src/api/java/Z3ReferenceQueue.java | 144 +++++++++++++++++++ 41 files changed, 448 insertions(+), 805 deletions(-) delete mode 100644 src/api/java/ASTDecRefQueue.java delete mode 100644 src/api/java/ApplyResultDecRefQueue.java delete mode 100644 src/api/java/AstMapDecRefQueue.java delete mode 100644 src/api/java/AstVectorDecRefQueue.java delete mode 100644 src/api/java/ConstructorDecRefQueue.java delete mode 100644 src/api/java/ConstructorListDecRefQueue.java delete mode 100644 src/api/java/FixedpointDecRefQueue.java delete mode 100644 src/api/java/FuncInterpDecRefQueue.java delete mode 100644 src/api/java/FuncInterpEntryDecRefQueue.java delete mode 100644 src/api/java/GoalDecRefQueue.java delete mode 100644 src/api/java/IDecRefQueue.java delete mode 100644 src/api/java/ModelDecRefQueue.java delete mode 100644 src/api/java/OptimizeDecRefQueue.java delete mode 100644 src/api/java/ParamDescrsDecRefQueue.java delete mode 100644 src/api/java/ParamsDecRefQueue.java delete mode 100644 src/api/java/ProbeDecRefQueue.java delete mode 100644 src/api/java/SimplifierDecRefQueue.java delete mode 100644 src/api/java/SolverDecRefQueue.java delete mode 100644 src/api/java/StatisticsDecRefQueue.java delete mode 100644 src/api/java/TacticDecRefQueue.java create mode 100644 src/api/java/Z3ReferenceQueue.java diff --git a/src/api/java/AST.java b/src/api/java/AST.java index c28c0cfcb..99cdde948 100644 --- a/src/api/java/AST.java +++ b/src/api/java/AST.java @@ -19,6 +19,8 @@ package com.microsoft.z3; import com.microsoft.z3.enumerations.Z3_ast_kind; +import java.lang.ref.ReferenceQueue; + /** * The abstract syntax tree (AST) class. **/ @@ -196,7 +198,7 @@ public class AST extends Z3Object implements Comparable @Override void addToReferenceQueue() { - getContext().getASTDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, ASTRef::new); } static AST create(Context ctx, long obj) @@ -217,4 +219,16 @@ public class AST extends Z3Object implements Comparable throw new Z3Exception("Unknown AST kind"); } } + + private static class ASTRef extends Z3ReferenceQueue.Reference { + + private ASTRef(AST referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.decRef(ctx.nCtx(), z3Obj); + } + } } diff --git a/src/api/java/ASTDecRefQueue.java b/src/api/java/ASTDecRefQueue.java deleted file mode 100644 index b0a6fa217..000000000 --- a/src/api/java/ASTDecRefQueue.java +++ /dev/null @@ -1,31 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - ASTDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class ASTDecRefQueue extends IDecRefQueue -{ - public ASTDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.decRef(ctx.nCtx(), obj); - } -}; diff --git a/src/api/java/ASTMap.java b/src/api/java/ASTMap.java index 916811cec..23a16a828 100644 --- a/src/api/java/ASTMap.java +++ b/src/api/java/ASTMap.java @@ -17,6 +17,8 @@ Notes: package com.microsoft.z3; +import java.lang.ref.ReferenceQueue; + /** * Map from AST to AST **/ @@ -123,6 +125,18 @@ class ASTMap extends Z3Object { @Override void addToReferenceQueue() { - getContext().getASTMapDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, ASTMapRef::new); + } + + private static class ASTMapRef extends Z3ReferenceQueue.Reference { + + private ASTMapRef(ASTMap referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.astMapDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/ASTVector.java b/src/api/java/ASTVector.java index a6b436a99..8a5603fcb 100644 --- a/src/api/java/ASTVector.java +++ b/src/api/java/ASTVector.java @@ -17,6 +17,8 @@ Notes: package com.microsoft.z3; +import java.lang.ref.ReferenceQueue; + /** * Vectors of ASTs. **/ @@ -101,16 +103,6 @@ public class ASTVector extends Z3Object { super(ctx, Native.mkAstVector(ctx.nCtx())); } - @Override - void incRef() { - Native.astVectorIncRef(getContext().nCtx(), getNativeObject()); - } - - @Override - void addToReferenceQueue() { - getContext().getASTVectorDRQ().storeReference(getContext(), this); - } - /** * Translates the AST vector into an AST[] * */ @@ -241,4 +233,26 @@ public class ASTVector extends Z3Object { res[i] = (RealExpr)Expr.create(getContext(), get(i).getNativeObject()); return res; } + + @Override + void incRef() { + Native.astVectorIncRef(getContext().nCtx(), getNativeObject()); + } + + @Override + void addToReferenceQueue() { + getContext().getReferenceQueue().storeReference(this, ASTVectorRef::new); + } + + private static class ASTVectorRef extends Z3ReferenceQueue.Reference { + + private ASTVectorRef(ASTVector referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.astVectorDecRef(ctx.nCtx(), z3Obj); + } + } } \ No newline at end of file diff --git a/src/api/java/ApplyResult.java b/src/api/java/ApplyResult.java index 6cfedd404..b0e035c4f 100644 --- a/src/api/java/ApplyResult.java +++ b/src/api/java/ApplyResult.java @@ -17,6 +17,8 @@ Notes: package com.microsoft.z3; +import java.lang.ref.ReferenceQueue; + /** * ApplyResult objects represent the result of an application of a tactic to a * goal. It contains the subgoals that were produced. @@ -66,6 +68,18 @@ public class ApplyResult extends Z3Object { @Override void addToReferenceQueue() { - getContext().getApplyResultDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, ApplyResultRef::new); + } + + private static class ApplyResultRef extends Z3ReferenceQueue.Reference { + + private ApplyResultRef(ApplyResult referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.applyResultDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/ApplyResultDecRefQueue.java b/src/api/java/ApplyResultDecRefQueue.java deleted file mode 100644 index e1a660781..000000000 --- a/src/api/java/ApplyResultDecRefQueue.java +++ /dev/null @@ -1,31 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - ApplyResultDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class ApplyResultDecRefQueue extends IDecRefQueue -{ - public ApplyResultDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.applyResultDecRef(ctx.nCtx(), obj); - } -}; diff --git a/src/api/java/AstMapDecRefQueue.java b/src/api/java/AstMapDecRefQueue.java deleted file mode 100644 index 6c96970b7..000000000 --- a/src/api/java/AstMapDecRefQueue.java +++ /dev/null @@ -1,30 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - AstMapDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class ASTMapDecRefQueue extends IDecRefQueue { - public ASTMapDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.astMapDecRef(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/AstVectorDecRefQueue.java b/src/api/java/AstVectorDecRefQueue.java deleted file mode 100644 index e7ce3e33e..000000000 --- a/src/api/java/AstVectorDecRefQueue.java +++ /dev/null @@ -1,30 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - AstVectorDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class ASTVectorDecRefQueue extends IDecRefQueue { - public ASTVectorDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.astVectorDecRef(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/CMakeLists.txt b/src/api/java/CMakeLists.txt index 39ca1e76e..c5221014f 100644 --- a/src/api/java/CMakeLists.txt +++ b/src/api/java/CMakeLists.txt @@ -91,17 +91,13 @@ add_custom_command(OUTPUT ${Z3_JAVA_ENUMERATION_PACKAGE_FILES_FULL_PATH} set(Z3_JAVA_JAR_SOURCE_FILES AlgebraicNum.java - ApplyResultDecRefQueue.java ApplyResult.java ArithExpr.java ArithSort.java ArrayExpr.java ArraySort.java - ASTDecRefQueue.java AST.java - AstMapDecRefQueue.java ASTMap.java - AstVectorDecRefQueue.java ASTVector.java BitVecExpr.java BitVecNum.java @@ -109,9 +105,7 @@ set(Z3_JAVA_JAR_SOURCE_FILES BoolExpr.java BoolSort.java CharSort.java - ConstructorDecRefQueue.java Constructor.java - ConstructorListDecRefQueue.java ConstructorList.java Context.java DatatypeExpr.java @@ -121,7 +115,6 @@ set(Z3_JAVA_JAR_SOURCE_FILES FiniteDomainExpr.java FiniteDomainNum.java FiniteDomainSort.java - FixedpointDecRefQueue.java Fixedpoint.java FPExpr.java FPNum.java @@ -130,13 +123,9 @@ set(Z3_JAVA_JAR_SOURCE_FILES FPRMSort.java FPSort.java FuncDecl.java - FuncInterpDecRefQueue.java - FuncInterpEntryDecRefQueue.java FuncInterp.java Global.java - GoalDecRefQueue.java Goal.java - IDecRefQueue.java IntExpr.java IntNum.java IntSort.java @@ -144,16 +133,11 @@ set(Z3_JAVA_JAR_SOURCE_FILES Lambda.java ListSort.java Log.java - ModelDecRefQueue.java Model.java - OptimizeDecRefQueue.java Optimize.java - ParamDescrsDecRefQueue.java ParamDescrs.java - ParamsDecRefQueue.java Params.java Pattern.java - ProbeDecRefQueue.java Probe.java Quantifier.java RatNum.java @@ -166,16 +150,12 @@ set(Z3_JAVA_JAR_SOURCE_FILES SeqSort.java SetSort.java Simplifier.java - SimplifierDecRefQueue.java - SolverDecRefQueue.java Solver.java Sort.java - StatisticsDecRefQueue.java Statistics.java Status.java StringSymbol.java Symbol.java - TacticDecRefQueue.java Tactic.java TupleSort.java UninterpretedSort.java @@ -183,6 +163,7 @@ set(Z3_JAVA_JAR_SOURCE_FILES Version.java Z3Exception.java Z3Object.java + Z3ReferenceQueue.java ) set(Z3_JAVA_JAR_SOURCE_FILES_FULL_PATH "") foreach (java_src_file ${Z3_JAVA_JAR_SOURCE_FILES}) diff --git a/src/api/java/Constructor.java b/src/api/java/Constructor.java index 59565f565..8e1766cb0 100644 --- a/src/api/java/Constructor.java +++ b/src/api/java/Constructor.java @@ -17,6 +17,8 @@ Notes: package com.microsoft.z3; +import java.lang.ref.ReferenceQueue; + /** * Constructors are used for datatype sorts. **/ @@ -91,7 +93,7 @@ public class Constructor extends Z3Object { @Override void addToReferenceQueue() { - getContext().getConstructorDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, ConstructorRef::new); } static Constructor of(Context ctx, Symbol name, Symbol recognizer, @@ -114,4 +116,16 @@ public class Constructor extends Z3Object { return new Constructor<>(ctx, n, nativeObj); } + + private static class ConstructorRef extends Z3ReferenceQueue.Reference> { + + private ConstructorRef(Constructor referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.delConstructor(ctx.nCtx(), z3Obj); + } + } } diff --git a/src/api/java/ConstructorDecRefQueue.java b/src/api/java/ConstructorDecRefQueue.java deleted file mode 100644 index a76b26bb7..000000000 --- a/src/api/java/ConstructorDecRefQueue.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.microsoft.z3; - -public class ConstructorDecRefQueue extends IDecRefQueue> { - public ConstructorDecRefQueue() { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.delConstructor(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/ConstructorList.java b/src/api/java/ConstructorList.java index d015c51c0..577c802f0 100644 --- a/src/api/java/ConstructorList.java +++ b/src/api/java/ConstructorList.java @@ -17,6 +17,8 @@ Notes: package com.microsoft.z3; +import java.lang.ref.ReferenceQueue; + /** * Lists of constructors **/ @@ -34,7 +36,7 @@ public class ConstructorList extends Z3Object { @Override void addToReferenceQueue() { - getContext().getConstructorListDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, ConstructorListRef::new); } ConstructorList(Context ctx, Constructor[] constructors) @@ -43,4 +45,16 @@ public class ConstructorList extends Z3Object { constructors.length, Constructor.arrayToNative(constructors))); } + + private static class ConstructorListRef extends Z3ReferenceQueue.Reference> { + + private ConstructorListRef(ConstructorList referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.delConstructorList(ctx.nCtx(), z3Obj); + } + } } diff --git a/src/api/java/ConstructorListDecRefQueue.java b/src/api/java/ConstructorListDecRefQueue.java deleted file mode 100644 index 2f5dfcb35..000000000 --- a/src/api/java/ConstructorListDecRefQueue.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.microsoft.z3; - -public class ConstructorListDecRefQueue extends IDecRefQueue> { - public ConstructorListDecRefQueue() { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.delConstructorList(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/Context.java b/src/api/java/Context.java index ad690b7e9..f3efa632a 100644 --- a/src/api/java/Context.java +++ b/src/api/java/Context.java @@ -4319,119 +4319,9 @@ public class Context implements AutoCloseable { checkContextMatch(a); } - private ASTDecRefQueue m_AST_DRQ = new ASTDecRefQueue(); - private ASTMapDecRefQueue m_ASTMap_DRQ = new ASTMapDecRefQueue(); - private ASTVectorDecRefQueue m_ASTVector_DRQ = new ASTVectorDecRefQueue(); - private ApplyResultDecRefQueue m_ApplyResult_DRQ = new ApplyResultDecRefQueue(); - private FuncInterpEntryDecRefQueue m_FuncEntry_DRQ = new FuncInterpEntryDecRefQueue(); - private FuncInterpDecRefQueue m_FuncInterp_DRQ = new FuncInterpDecRefQueue(); - private GoalDecRefQueue m_Goal_DRQ = new GoalDecRefQueue(); - private ModelDecRefQueue m_Model_DRQ = new ModelDecRefQueue(); - private ParamsDecRefQueue m_Params_DRQ = new ParamsDecRefQueue(); - private ParamDescrsDecRefQueue m_ParamDescrs_DRQ = new ParamDescrsDecRefQueue(); - private ProbeDecRefQueue m_Probe_DRQ = new ProbeDecRefQueue(); - private SolverDecRefQueue m_Solver_DRQ = new SolverDecRefQueue(); - private StatisticsDecRefQueue m_Statistics_DRQ = new StatisticsDecRefQueue(); - private TacticDecRefQueue m_Tactic_DRQ = new TacticDecRefQueue(); - private SimplifierDecRefQueue m_Simplifier_DRQ = new SimplifierDecRefQueue(); - private FixedpointDecRefQueue m_Fixedpoint_DRQ = new FixedpointDecRefQueue(); - private OptimizeDecRefQueue m_Optimize_DRQ = new OptimizeDecRefQueue(); - private ConstructorDecRefQueue m_Constructor_DRQ = new ConstructorDecRefQueue(); - private ConstructorListDecRefQueue m_ConstructorList_DRQ = - new ConstructorListDecRefQueue(); + private Z3ReferenceQueue m_RefQueue = new Z3ReferenceQueue(this); - public IDecRefQueue> getConstructorDRQ() { - return m_Constructor_DRQ; - } - - public IDecRefQueue> getConstructorListDRQ() { - return m_ConstructorList_DRQ; - } - - public IDecRefQueue getASTDRQ() - { - return m_AST_DRQ; - } - - public IDecRefQueue getASTMapDRQ() - { - return m_ASTMap_DRQ; - } - - public IDecRefQueue getASTVectorDRQ() - { - return m_ASTVector_DRQ; - } - - public IDecRefQueue getApplyResultDRQ() - { - return m_ApplyResult_DRQ; - } - - public IDecRefQueue> getFuncEntryDRQ() - { - return m_FuncEntry_DRQ; - } - - public IDecRefQueue> getFuncInterpDRQ() - { - return m_FuncInterp_DRQ; - } - - public IDecRefQueue getGoalDRQ() - { - return m_Goal_DRQ; - } - - public IDecRefQueue getModelDRQ() - { - return m_Model_DRQ; - } - - public IDecRefQueue getParamsDRQ() - { - return m_Params_DRQ; - } - - public IDecRefQueue getParamDescrsDRQ() - { - return m_ParamDescrs_DRQ; - } - - public IDecRefQueue getProbeDRQ() - { - return m_Probe_DRQ; - } - - public IDecRefQueue getSolverDRQ() - { - return m_Solver_DRQ; - } - - public IDecRefQueue getStatisticsDRQ() - { - return m_Statistics_DRQ; - } - - public IDecRefQueue getTacticDRQ() - { - return m_Tactic_DRQ; - } - - public IDecRefQueue getSimplifierDRQ() - { - return m_Simplifier_DRQ; - } - - public IDecRefQueue getFixedpointDRQ() - { - return m_Fixedpoint_DRQ; - } - - public IDecRefQueue getOptimizeDRQ() - { - return m_Optimize_DRQ; - } + Z3ReferenceQueue getReferenceQueue() { return m_RefQueue; } /** * Disposes of the context. @@ -4439,27 +4329,16 @@ public class Context implements AutoCloseable { @Override public void close() { - m_AST_DRQ.forceClear(this); - m_ASTMap_DRQ.forceClear(this); - m_ASTVector_DRQ.forceClear(this); - m_ApplyResult_DRQ.forceClear(this); - m_FuncEntry_DRQ.forceClear(this); - m_FuncInterp_DRQ.forceClear(this); - m_Goal_DRQ.forceClear(this); - m_Model_DRQ.forceClear(this); - m_Params_DRQ.forceClear(this); - m_Probe_DRQ.forceClear(this); - m_Solver_DRQ.forceClear(this); - m_Optimize_DRQ.forceClear(this); - m_Statistics_DRQ.forceClear(this); - m_Tactic_DRQ.forceClear(this); - m_Simplifier_DRQ.forceClear(this); - m_Fixedpoint_DRQ.forceClear(this); + if (m_ctx == 0) + return; + + m_RefQueue.forceClear(); m_boolSort = null; m_intSort = null; m_realSort = null; m_stringSort = null; + m_RefQueue = null; synchronized (creation_lock) { Native.delContext(m_ctx); diff --git a/src/api/java/Fixedpoint.java b/src/api/java/Fixedpoint.java index 96e1dd0cb..c35f15e96 100644 --- a/src/api/java/Fixedpoint.java +++ b/src/api/java/Fixedpoint.java @@ -19,6 +19,8 @@ package com.microsoft.z3; import com.microsoft.z3.enumerations.Z3_lbool; +import java.lang.ref.ReferenceQueue; + /** * Object for managing fixedpoints **/ @@ -327,9 +329,18 @@ public class Fixedpoint extends Z3Object @Override void addToReferenceQueue() { - getContext().getFixedpointDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, FixedpointRef::new); } - @Override - void checkNativeObject(long obj) { } + private static class FixedpointRef extends Z3ReferenceQueue.Reference { + + private FixedpointRef(Fixedpoint referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.fixedpointDecRef(ctx.nCtx(), z3Obj); + } + } } diff --git a/src/api/java/FixedpointDecRefQueue.java b/src/api/java/FixedpointDecRefQueue.java deleted file mode 100644 index 69ed82092..000000000 --- a/src/api/java/FixedpointDecRefQueue.java +++ /dev/null @@ -1,31 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - FixedpointDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class FixedpointDecRefQueue extends IDecRefQueue { - public FixedpointDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) - { - Native.fixedpointDecRef(ctx.nCtx(), obj); - } -}; diff --git a/src/api/java/FuncInterp.java b/src/api/java/FuncInterp.java index 64f96534b..3d2affc4a 100644 --- a/src/api/java/FuncInterp.java +++ b/src/api/java/FuncInterp.java @@ -17,6 +17,8 @@ Notes: package com.microsoft.z3; +import java.lang.ref.ReferenceQueue; + /** * A function interpretation is represented as a finite map and an 'else' value. * Each entry in the finite map represents the value of a function given a set @@ -93,7 +95,19 @@ public class FuncInterp extends Z3Object { @Override void addToReferenceQueue() { - getContext().getFuncEntryDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, FuncEntryRef::new); + } + + private static class FuncEntryRef extends Z3ReferenceQueue.Reference> { + + private FuncEntryRef(Entry referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.funcEntryDecRef(ctx.nCtx(), z3Obj); + } } } @@ -186,6 +200,18 @@ public class FuncInterp extends Z3Object { @Override void addToReferenceQueue() { - getContext().getFuncInterpDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, FuncInterpRef::new); + } + + private static class FuncInterpRef extends Z3ReferenceQueue.Reference> { + + private FuncInterpRef(FuncInterp referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.funcInterpDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/FuncInterpDecRefQueue.java b/src/api/java/FuncInterpDecRefQueue.java deleted file mode 100644 index 06a6f2af8..000000000 --- a/src/api/java/FuncInterpDecRefQueue.java +++ /dev/null @@ -1,31 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - FuncInterpDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class FuncInterpDecRefQueue extends IDecRefQueue> -{ - public FuncInterpDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.funcInterpDecRef(ctx.nCtx(), obj); - } -}; diff --git a/src/api/java/FuncInterpEntryDecRefQueue.java b/src/api/java/FuncInterpEntryDecRefQueue.java deleted file mode 100644 index 77bb78f5b..000000000 --- a/src/api/java/FuncInterpEntryDecRefQueue.java +++ /dev/null @@ -1,30 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - FuncInterpEntryDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class FuncInterpEntryDecRefQueue extends IDecRefQueue> { - public FuncInterpEntryDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.funcEntryDecRef(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/Goal.java b/src/api/java/Goal.java index 3326f81fe..e79ca7b74 100644 --- a/src/api/java/Goal.java +++ b/src/api/java/Goal.java @@ -19,6 +19,8 @@ package com.microsoft.z3; import com.microsoft.z3.enumerations.Z3_goal_prec; +import java.lang.ref.ReferenceQueue; + /** * A goal (aka problem). A goal is essentially a set of formulas, that can be * solved and/or transformed using tactics and solvers. @@ -262,6 +264,18 @@ public class Goal extends Z3Object { @Override void addToReferenceQueue() { - getContext().getGoalDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, GoalRef::new); + } + + private static class GoalRef extends Z3ReferenceQueue.Reference { + + private GoalRef(Goal referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.goalDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/GoalDecRefQueue.java b/src/api/java/GoalDecRefQueue.java deleted file mode 100644 index 90bad1fb1..000000000 --- a/src/api/java/GoalDecRefQueue.java +++ /dev/null @@ -1,30 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - GoalDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class GoalDecRefQueue extends IDecRefQueue { - public GoalDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.goalDecRef(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/IDecRefQueue.java b/src/api/java/IDecRefQueue.java deleted file mode 100644 index b9ece3172..000000000 --- a/src/api/java/IDecRefQueue.java +++ /dev/null @@ -1,83 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - IDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -import java.lang.ref.PhantomReference; -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.util.IdentityHashMap; -import java.util.Map; - -/** - * A queue to handle management of native memory. - * - *

Mechanics: once an object is created, a metadata is stored for it in - * {@code referenceMap}, and a {@link PhantomReference} is created with a - * reference to {@code referenceQueue}. - * Once the object becomes strongly unreachable, the phantom reference gets - * added by JVM to the {@code referenceQueue}. - * After each object creation, we iterate through the available objects in - * {@code referenceQueue} and decrement references for them. - * - * @param Type of object stored in queue. - */ -public abstract class IDecRefQueue { - private final ReferenceQueue referenceQueue = new ReferenceQueue<>(); - private final Map, Long> referenceMap = - new IdentityHashMap<>(); - - protected IDecRefQueue() {} - - /** - * An implementation of this method should decrement the reference on a - * given native object. - * This function should always be called on the {@code ctx} thread. - * - * @param ctx Z3 context. - * @param obj Pointer to a Z3 object. - */ - protected abstract void decRef(Context ctx, long obj); - - public void storeReference(Context ctx, T obj) { - PhantomReference ref = new PhantomReference<>(obj, referenceQueue); - referenceMap.put(ref, obj.getNativeObject()); - clear(ctx); - } - - /** - * Clean all references currently in {@code referenceQueue}. - */ - protected void clear(Context ctx) - { - Reference ref; - while ((ref = referenceQueue.poll()) != null) { - long z3ast = referenceMap.remove(ref); - decRef(ctx, z3ast); - } - } - - /** - * Clean all references stored in {@code referenceMap}, - * regardless of whether they are in {@code referenceMap} or not. - */ - public void forceClear(Context ctx) { - for (long ref : referenceMap.values()) { - decRef(ctx, ref); - } - } -} diff --git a/src/api/java/Model.java b/src/api/java/Model.java index ffc4dd47f..cf9ab4b64 100644 --- a/src/api/java/Model.java +++ b/src/api/java/Model.java @@ -19,6 +19,8 @@ package com.microsoft.z3; import com.microsoft.z3.enumerations.Z3_sort_kind; +import java.lang.ref.ReferenceQueue; + /** * A Model contains interpretations (assignments) of constants and functions. **/ @@ -296,6 +298,18 @@ public class Model extends Z3Object { @Override void addToReferenceQueue() { - getContext().getModelDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, ModelRef::new); + } + + private static class ModelRef extends Z3ReferenceQueue.Reference { + + private ModelRef(Model referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.modelDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/ModelDecRefQueue.java b/src/api/java/ModelDecRefQueue.java deleted file mode 100644 index f1b7c3fdd..000000000 --- a/src/api/java/ModelDecRefQueue.java +++ /dev/null @@ -1,30 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - ModelDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class ModelDecRefQueue extends IDecRefQueue { - public ModelDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.modelDecRef(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/Optimize.java b/src/api/java/Optimize.java index 83833e36b..9679a96cd 100644 --- a/src/api/java/Optimize.java +++ b/src/api/java/Optimize.java @@ -20,6 +20,8 @@ package com.microsoft.z3; import com.microsoft.z3.enumerations.Z3_lbool; +import java.lang.ref.ReferenceQueue; + /** * Object for managing optimization context @@ -421,6 +423,18 @@ public class Optimize extends Z3Object { @Override void addToReferenceQueue() { - getContext().getOptimizeDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, OptimizeRef::new); + } + + private static class OptimizeRef extends Z3ReferenceQueue.Reference { + + private OptimizeRef(Optimize referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.optimizeDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/OptimizeDecRefQueue.java b/src/api/java/OptimizeDecRefQueue.java deleted file mode 100644 index 0acf20068..000000000 --- a/src/api/java/OptimizeDecRefQueue.java +++ /dev/null @@ -1,30 +0,0 @@ -/** -Copyright (c) 2012-2015 Microsoft Corporation - -Module Name: - - OptimizeDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class OptimizeDecRefQueue extends IDecRefQueue { - public OptimizeDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.optimizeDecRef(ctx.nCtx(), obj); - } -}; diff --git a/src/api/java/ParamDescrs.java b/src/api/java/ParamDescrs.java index fdaf29647..0695f8fe0 100644 --- a/src/api/java/ParamDescrs.java +++ b/src/api/java/ParamDescrs.java @@ -19,6 +19,8 @@ package com.microsoft.z3; import com.microsoft.z3.enumerations.Z3_param_kind; +import java.lang.ref.ReferenceQueue; + /** * A ParamDescrs describes a set of parameters. **/ @@ -97,6 +99,18 @@ public class ParamDescrs extends Z3Object { @Override void addToReferenceQueue() { - getContext().getParamDescrsDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, ParamDescrsRef::new); + } + + private static class ParamDescrsRef extends Z3ReferenceQueue.Reference { + + private ParamDescrsRef(ParamDescrs referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.paramDescrsDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/ParamDescrsDecRefQueue.java b/src/api/java/ParamDescrsDecRefQueue.java deleted file mode 100644 index ee3257db9..000000000 --- a/src/api/java/ParamDescrsDecRefQueue.java +++ /dev/null @@ -1,31 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - ParamDescrsDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class ParamDescrsDecRefQueue extends IDecRefQueue { - public ParamDescrsDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) - { - Native.paramDescrsDecRef(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/Params.java b/src/api/java/Params.java index a76dd3cab..1edfa67ba 100644 --- a/src/api/java/Params.java +++ b/src/api/java/Params.java @@ -18,6 +18,8 @@ Notes: package com.microsoft.z3; +import java.lang.ref.ReferenceQueue; + /** * A ParameterSet represents a configuration in the form of Symbol/value pairs. **/ @@ -130,6 +132,18 @@ public class Params extends Z3Object { @Override void addToReferenceQueue() { - getContext().getParamsDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, ParamsRef::new); + } + + private static class ParamsRef extends Z3ReferenceQueue.Reference { + + private ParamsRef(Params referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.paramsDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/ParamsDecRefQueue.java b/src/api/java/ParamsDecRefQueue.java deleted file mode 100644 index 349713f67..000000000 --- a/src/api/java/ParamsDecRefQueue.java +++ /dev/null @@ -1,30 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - ParamDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class ParamsDecRefQueue extends IDecRefQueue { - public ParamsDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.paramsDecRef(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/Probe.java b/src/api/java/Probe.java index a36f3b64b..cb4b13442 100644 --- a/src/api/java/Probe.java +++ b/src/api/java/Probe.java @@ -17,6 +17,8 @@ Notes: package com.microsoft.z3; +import java.lang.ref.ReferenceQueue; + /** * Probes are used to inspect a goal (aka problem) and collect information that * may be used to decide which solver and/or preprocessing step will be used. @@ -56,6 +58,18 @@ public class Probe extends Z3Object { @Override void addToReferenceQueue() { - getContext().getProbeDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, ProbeRef::new); + } + + private static class ProbeRef extends Z3ReferenceQueue.Reference { + + private ProbeRef(Probe referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.probeDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/ProbeDecRefQueue.java b/src/api/java/ProbeDecRefQueue.java deleted file mode 100644 index b25446c0c..000000000 --- a/src/api/java/ProbeDecRefQueue.java +++ /dev/null @@ -1,32 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - ProbeDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class ProbeDecRefQueue extends IDecRefQueue -{ - public ProbeDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) - { - Native.probeDecRef(ctx.nCtx(), obj); - } -}; diff --git a/src/api/java/Simplifier.java b/src/api/java/Simplifier.java index b3fc89ccf..c89241a7d 100644 --- a/src/api/java/Simplifier.java +++ b/src/api/java/Simplifier.java @@ -18,6 +18,8 @@ Author: package com.microsoft.z3; +import java.lang.ref.ReferenceQueue; + public class Simplifier extends Z3Object { /* * A string containing a description of parameters accepted by the simplifier. @@ -32,7 +34,7 @@ public class Simplifier extends Z3Object { * Retrieves parameter descriptions for Simplifiers. */ public ParamDescrs getParameterDescriptions() { - return new ParamDescrs(getContext(), Native.simplifierGetParamDescrs(getContext().nCtx(), getNativeObject())); + return new ParamDescrs(getContext(), Native.simplifierGetParamDescrs(getContext().nCtx(), getNativeObject())); } Simplifier(Context ctx, long obj) @@ -53,6 +55,18 @@ public class Simplifier extends Z3Object { @Override void addToReferenceQueue() { - getContext().getSimplifierDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, SimplifierRef::new); } -} \ No newline at end of file + + private static class SimplifierRef extends Z3ReferenceQueue.Reference { + + private SimplifierRef(Simplifier referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.simplifierDecRef(ctx.nCtx(), z3Obj); + } + } +} \ No newline at end of file diff --git a/src/api/java/SimplifierDecRefQueue.java b/src/api/java/SimplifierDecRefQueue.java deleted file mode 100644 index ba15dd5be..000000000 --- a/src/api/java/SimplifierDecRefQueue.java +++ /dev/null @@ -1,31 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - SimplifierDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class SimplifierDecRefQueue extends IDecRefQueue { - public SimplifierDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) - { - Native.simplifierDecRef(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index ce795d758..b814a4db6 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -19,6 +19,8 @@ Notes: package com.microsoft.z3; import com.microsoft.z3.enumerations.Z3_lbool; + +import java.lang.ref.ReferenceQueue; import java.util.*; /** @@ -403,6 +405,18 @@ public class Solver extends Z3Object { @Override void addToReferenceQueue() { - getContext().getSolverDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, SolverRef::new); + } + + private static class SolverRef extends Z3ReferenceQueue.Reference { + + private SolverRef(Solver referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.solverDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/SolverDecRefQueue.java b/src/api/java/SolverDecRefQueue.java deleted file mode 100644 index efa15d939..000000000 --- a/src/api/java/SolverDecRefQueue.java +++ /dev/null @@ -1,27 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - SolverDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class SolverDecRefQueue extends IDecRefQueue { - public SolverDecRefQueue() { super(); } - - @Override - protected void decRef(Context ctx, long obj) { - Native.solverDecRef(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/Statistics.java b/src/api/java/Statistics.java index d509424ed..6d42e1af0 100644 --- a/src/api/java/Statistics.java +++ b/src/api/java/Statistics.java @@ -17,6 +17,8 @@ Notes: package com.microsoft.z3; +import java.lang.ref.ReferenceQueue; + /** * Objects of this class track statistical information about solvers. **/ @@ -25,7 +27,7 @@ public class Statistics extends Z3Object { * Statistical data is organized into pairs of [Key, Entry], where every * Entry is either a {@code DoubleEntry} or a {@code UIntEntry} **/ - public class Entry + public static class Entry { /** * The key of the entry. @@ -191,11 +193,23 @@ public class Statistics extends Z3Object { @Override void incRef() { - getContext().getStatisticsDRQ().storeReference(getContext(), this); + Native.statsIncRef(getContext().nCtx(), getNativeObject()); } @Override void addToReferenceQueue() { - Native.statsIncRef(getContext().nCtx(), getNativeObject()); + getContext().getReferenceQueue().storeReference(this, StatisticsRef::new); + } + + private static class StatisticsRef extends Z3ReferenceQueue.Reference { + + private StatisticsRef(Statistics referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.statsDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/StatisticsDecRefQueue.java b/src/api/java/StatisticsDecRefQueue.java deleted file mode 100644 index ed698e4ca..000000000 --- a/src/api/java/StatisticsDecRefQueue.java +++ /dev/null @@ -1,30 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - StatisticsDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class StatisticsDecRefQueue extends IDecRefQueue { - public StatisticsDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) { - Native.statsDecRef(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/Tactic.java b/src/api/java/Tactic.java index 11d02ca73..d70d8a409 100644 --- a/src/api/java/Tactic.java +++ b/src/api/java/Tactic.java @@ -17,6 +17,8 @@ Notes: package com.microsoft.z3; +import java.lang.ref.ReferenceQueue; + /** * Tactics are the basic building block for creating custom solvers for specific * problem domains. The complete list of tactics may be obtained using @@ -98,6 +100,19 @@ public class Tactic extends Z3Object { @Override void addToReferenceQueue() { - getContext().getTacticDRQ().storeReference(getContext(), this); + //getContext().getTacticDRQ().storeReference(getContext(), this); + getContext().getReferenceQueue().storeReference(this, TacticRef::new); + } + + private static class TacticRef extends Z3ReferenceQueue.Reference { + + private TacticRef(Tactic referent, ReferenceQueue q) { + super(referent, q); + } + + @Override + void decRef(Context ctx, long z3Obj) { + Native.tacticDecRef(ctx.nCtx(), z3Obj); + } } } diff --git a/src/api/java/TacticDecRefQueue.java b/src/api/java/TacticDecRefQueue.java deleted file mode 100644 index 8f151f25c..000000000 --- a/src/api/java/TacticDecRefQueue.java +++ /dev/null @@ -1,31 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - TacticDecRefQueue.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -class TacticDecRefQueue extends IDecRefQueue { - public TacticDecRefQueue() - { - super(); - } - - @Override - protected void decRef(Context ctx, long obj) - { - Native.tacticDecRef(ctx.nCtx(), obj); - } -} diff --git a/src/api/java/Z3ReferenceQueue.java b/src/api/java/Z3ReferenceQueue.java new file mode 100644 index 000000000..22435599f --- /dev/null +++ b/src/api/java/Z3ReferenceQueue.java @@ -0,0 +1,144 @@ +/** +Copyright (c) 2012-2014 Microsoft Corporation + +Module Name: + + IDecRefQueue.java + +Abstract: + +Author: + + @author Christoph Wintersteiger (cwinter) 2012-03-15 + +Notes: + +**/ + +package com.microsoft.z3; + +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; + +/** + * A queue to handle management of native memory. + * + *

Mechanics: When an object is created, a so-called {@link PhantomReference} + * is constructed that is associated with the created object and the reference queue {@code referenceQueue}. + * Once the object becomes strongly unreachable, the phantom reference gets + * added by JVM to the {@code referenceQueue}. + * After each object creation, we iterate through the available objects in + * {@code referenceQueue} and decrement references for them. + *

+ * In order for this to work, we need to (i) associate to each phantom reference the underlying + * native object (and its type) that it references and (ii) keep the phantom references themselves alive, so they are not + * garbage collected before the object they reference. + * We use a doubly-linked list of custom phantom references, subclasses of {@link Reference}, to achieve this. + * + */ +class Z3ReferenceQueue { + private final Context ctx; + private final ReferenceQueue referenceQueue = new ReferenceQueue<>(); + private final Reference referenceList = emptyList(); + + Z3ReferenceQueue(Context ctx) { + this.ctx = ctx; + } + + /** + * Create and store a new phantom reference. + */ + void storeReference(T z3Object, ReferenceConstructor refConstructor) { + referenceList.insert(refConstructor.construct(z3Object, referenceQueue)); + clear(); + } + + /** + * Clean all references currently in {@code referenceQueue}. + */ + private void clear() { + Reference ref; + while ((ref = (Reference)referenceQueue.poll()) != null) { + ref.cleanup(ctx); + } + } + + /** + * Clean all references stored in {@code referenceList}, + * regardless of whether they are in {@code referenceQueue} or not. + */ + @SuppressWarnings("StatementWithEmptyBody") + public void forceClear() { + // Decrement all reference counters + Reference cur = referenceList.next; + while (cur.next != null) { + cur.decRef(ctx, cur.nativePtr); + cur = cur.next; + } + + // Bulk-delete the reference list's entries + referenceList.next = cur; + cur.prev = referenceList; + + // Empty the reference queue so that there are no living phantom references anymore. + // This makes sure that all stored phantom references can be GC'd now. + while (referenceQueue.poll() != null) {} + } + + private static Reference emptyList() { + Reference head = new DummyReference(); + Reference tail = new DummyReference(); + head.next = tail; + tail.prev = head; + return head; + } + + // ================================================================================================================ + + @FunctionalInterface + interface ReferenceConstructor { + Reference construct(T reference, ReferenceQueue queue); + } + + abstract static class Reference extends PhantomReference { + + private Reference prev; + private Reference next; + private final long nativePtr; + + Reference(T referent, ReferenceQueue q) { + super(referent, q); + this.nativePtr = referent != null ? referent.getNativeObject() : 0; + } + + private void cleanup(Context ctx) { + decRef(ctx, nativePtr); + assert (prev != null && next != null); + prev.next = next; + next.prev = prev; + } + + private void insert(Reference ref) { + assert next != null; + ref.prev = this; + ref.next = this.next; + ref.next.prev = ref; + next = ref; + } + + abstract void decRef(Context ctx, long z3Obj); + } + + private static class DummyReference extends Reference { + + public DummyReference() { + super(null, null); + } + + @Override + void decRef(Context ctx, long z3Obj) { + // Should never be called. + assert false; + } + } +} From 79b7d8a9e274ea7b18f09e35d7facb539ddce9cb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2024 10:00:11 -0800 Subject: [PATCH 212/224] throttle squash-store #7134 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/array_rewriter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ast/rewriter/array_rewriter.cpp b/src/ast/rewriter/array_rewriter.cpp index 228ba9914..bd67a940e 100644 --- a/src/ast/rewriter/array_rewriter.cpp +++ b/src/ast/rewriter/array_rewriter.cpp @@ -206,7 +206,9 @@ br_status array_rewriter::mk_store_core(unsigned num_args, expr * const * args, bool array_rewriter::squash_store(unsigned n, expr* const* args, expr_ref& result) { ptr_buffer parents, sargs; expr* a = args[0]; - while (m_util.is_store(a)) { + unsigned rounds = 0; + while (m_util.is_store(a) && rounds < 10) { + ++rounds; lbool r = compare_args(n - 2, args + 1, to_app(a)->get_args() + 1); switch (r) { case l_undef: From 785f71b1a6986ed18221b3023bc5cfe3e54ed54f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 21 Feb 2024 19:35:24 -0800 Subject: [PATCH 213/224] prepare for 12.6 Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES.md | 11 +++++++++++ scripts/release.yml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index c795e7a68..a0d8d4510 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -10,6 +10,17 @@ Version 4.next - native word level bit-vector solving. - introduction of simple induction lemmas to handle a limited repertoire of induction proofs. +Version 4.12.6 +============== +- remove expensive rewrite that coallesces adjacent stores +- improved Java use of reference queues thanks to Thomas Haas #7131 +- fixes to conditional import of python library thanks to Cal Jacobson #7116 +- include universe for constants that get removed during pre-processing #7121 +- code improvements, Bruce Mitchener #7119 +- fix nested callback handling for user propagators +- include ARM64 binaries in distribution +- added Julia API, Thanks to Yisu Remy Yang #7108 + Version 4.12.5 ============== - Fixes to pypi setup and build for MacOS distributions diff --git a/scripts/release.yml b/scripts/release.yml index 7a2c4ef41..27011bbe1 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -594,7 +594,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(1,1) + condition: eq(1,0) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From 143a35d370f6b212180caf50674c5328fb3890ff Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 23 Feb 2024 00:35:15 +0700 Subject: [PATCH 214/224] Fix typos. (#7137) --- RELEASE_NOTES.md | 2 +- src/api/python/z3/z3.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index a0d8d4510..9b041c07e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -12,7 +12,7 @@ Version 4.next Version 4.12.6 ============== -- remove expensive rewrite that coallesces adjacent stores +- remove expensive rewrite that coalesces adjacent stores - improved Java use of reference queues thanks to Thomas Haas #7131 - fixes to conditional import of python library thanks to Cal Jacobson #7116 - include universe for constants that get removed during pre-processing #7121 diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 1bfd987d6..16db39afd 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -11658,7 +11658,7 @@ class UserPropagateBase: # # Either solver is set or ctx is set. - # Propagators that are created throuh callbacks + # Propagators that are created through callbacks # to "fresh" inherit the context of that is supplied # as argument to the callback. # This context should not be deleted. It is owned by the solver. From c0621cb760f50278ec4fdd8ae5f2ca0b83276b14 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 23 Feb 2024 00:35:47 +0700 Subject: [PATCH 215/224] ci: Stop using deprecated `::set-output`. (#7136) This has been deprecated and the replacement functionality is described here: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ --- .github/workflows/coverage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 30a385b3f..b90b40925 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -90,6 +90,7 @@ jobs: - name: Get date id: date run: echo "::set-output name=date::$(date +'%Y-%m-%d')" + run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT - uses: actions/upload-artifact@v4 with: From 019c0648faf6b24ae6c4221ba0f1d5757c6f4593 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 22 Feb 2024 09:37:08 -0800 Subject: [PATCH 216/224] Update coverage.yml --- .github/workflows/coverage.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index b90b40925..a0f66d5a8 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -89,8 +89,9 @@ jobs: - name: Get date id: date - run: echo "::set-output name=date::$(date +'%Y-%m-%d')" - run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + run: | + echo "::set-output name=date::$(date +'%Y-%m-%d')" + echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT - uses: actions/upload-artifact@v4 with: From 19f5e7ffeacd06f022d65ee9a7f1168b73b0cfd0 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 23 Feb 2024 01:36:13 +0700 Subject: [PATCH 217/224] ci: Really fix set-output. (#7138) I accidentally left the old line in PR #7136. --- .github/workflows/coverage.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index a0f66d5a8..679eeee3a 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -89,9 +89,7 @@ jobs: - name: Get date id: date - run: | - echo "::set-output name=date::$(date +'%Y-%m-%d')" - echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT - uses: actions/upload-artifact@v4 with: From 85425a6e088766c017d12cd4680e39efe9edf761 Mon Sep 17 00:00:00 2001 From: John Fleisher Date: Sat, 24 Feb 2024 05:13:35 -0500 Subject: [PATCH 218/224] Update nightly.yaml for Azure Pipelines (#7139) * Update nightly.yaml for Azure Pipelines match nightly builds to release builds * Fix nightly.yaml * fix indent * fix indent * Update nightly.yaml * Update nightly.yaml * Update nightly.yaml for Azure Pipelines * Update nightly.yaml for Azure Pipelines --------- Co-authored-by: Nikolaj Bjorner --- scripts/nightly.yaml | 227 ++++++++++++++++++++++++------------------- 1 file changed, 128 insertions(+), 99 deletions(-) diff --git a/scripts/nightly.yaml b/scripts/nightly.yaml index 478fdb969..f6c3c66c7 100644 --- a/scripts/nightly.yaml +++ b/scripts/nightly.yaml @@ -4,26 +4,41 @@ variables: Patch: '6' ReleaseVersion: $(Major).$(Minor).$(Patch) AssemblyVersion: $(Major).$(Minor).$(Patch).$(Build.BuildId) - NightlyVersion: $(AssemblyVersion)-$(Build.DefinitionName) + NightlyVersion: $(AssemblyVersion)-$(Build.buildId) stages: - stage: Build jobs: - - job: Mac - displayName: "Mac Build" + - job: MacBuild + displayName: "macOS Build" pool: vmImage: "macOS-11" steps: - - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk - - script: git clone https://github.com/z3prover/z3test z3test - - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - - task: PublishPipelineArtifact@1 + - task: PythonScript@0 + displayName: Build inputs: - artifactName: 'Mac' + scriptSource: 'filepath' + scriptPath: scripts/mk_unix_dist.py + arguments: --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk + - script: git clone https://github.com/z3prover/z3test z3test + displayName: 'Clone z3test' + - task: PythonScript@0 + displayName: Test + inputs: + scriptSource: 'filepath' + scriptPath: z3test/scripts/test_benchmarks.py + arguments: build-dist/z3 z3test/regressions/smt2 + - task: CopyFiles@2 + inputs: + sourceFolder: dist + contents: '*.zip' + targetFolder: $(Build.ArtifactStagingDirectory) + - task: PublishPipelineArtifact@0 + inputs: + artifactName: 'macOSBuild' targetPath: $(Build.ArtifactStagingDirectory) - - job: MacArm64 + - job: MacBuildArm64 displayName: "Mac ARM64 Build" pool: vmImage: "macOS-11" @@ -36,67 +51,76 @@ stages: artifactName: 'MacArm64' targetPath: $(Build.ArtifactStagingDirectory) - - job: Ubuntu20 - displayName: "Ubuntu20 build" + - job: UbuntuBuild + displayName: "Ubuntu build" + pool: + vmImage: "ubuntu-latest" + steps: + - task: PythonScript@0 + displayName: Build + inputs: + scriptSource: 'filepath' + scriptPath: scripts/mk_unix_dist.py + arguments: --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk + - script: git clone https://github.com/z3prover/z3test z3test + displayName: 'Clone z3test' + - task: PythonScript@0 + displayName: Test + inputs: + scriptSource: 'filepath' + scriptPath: z3test/scripts/test_benchmarks.py + arguments: build-dist/z3 z3test/regressions/smt2 + - task: CopyFiles@2 + inputs: + sourceFolder: dist + contents: '*.zip' + targetFolder: $(Build.ArtifactStagingDirectory) + - task: PublishPipelineArtifact@0 + inputs: + artifactName: 'UbuntuBuild' + targetPath: $(Build.ArtifactStagingDirectory) + + - job: UbuntuBuild20 + displayName: "Ubuntu build 20" pool: vmImage: "ubuntu-20.04" steps: - - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk + - task: PythonScript@0 + displayName: Build + inputs: + scriptSource: 'filepath' + scriptPath: scripts/mk_unix_dist.py + arguments: --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk + - script: git clone https://github.com/z3prover/z3test z3test + displayName: 'Clone z3test' + - task: PythonScript@0 + displayName: Test + inputs: + scriptSource: 'filepath' + scriptPath: z3test/scripts/test_benchmarks.py + arguments: build-dist/z3 z3test/regressions/smt2 + - task: CopyFiles@2 + inputs: + sourceFolder: dist + contents: '*.zip' + targetFolder: $(Build.ArtifactStagingDirectory) + - task: PublishPipelineArtifact@0 + inputs: + artifactName: 'UbuntuBuild20' + targetPath: $(Build.ArtifactStagingDirectory) + + - job: UbuntuArm64 + displayName: "Ubuntu ARM64 build" + pool: + vmImage: "ubuntu-latest" + steps: + - script: python scripts/mk_unix_dist.py --dotnet-key=$(Build.SourcesDirectory)/resources/z3.snk --arch=arm64 - script: git clone https://github.com/z3prover/z3test z3test - script: python z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/. - task: PublishPipelineArtifact@0 inputs: - artifactName: 'Ubuntu-20.04' - targetPath: $(Build.ArtifactStagingDirectory) - - - job: UbuntuBuilds - displayName: "Ubuntu Builds" - pool: - vmImage: "ubuntu-latest" - strategy: - matrix: - arm64: - setupcmds: 'sudo apt update& sudo apt install gcc-arm-none-eabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu g++-aarch64-linux-gnu ninja-build -y' - buildenv: 'CXX=aarch64-linux-gnu-g++ CC=aarch64-linux-gnu-gcc' - arch: 'arm64' - name: 'z3-$(AssemblyVersion)-arm64-ubuntu-22' - compiler: 'aarch64-linux-gnu-g++-11' - x64: - setupcmds: 'sudo apt update& sudo apt install ninja-build -y' - buildenv: '' - arch: 'x64' - name: 'z3-$(AssemblyVersion)-x64-ubuntu-22' - compiler: 'g++' - steps: - - script: $(setupcmds) - - script: | - mkdir $(arch) - cd $(arch) - $(buildenv) cmake \ - -DCMAKE_BUILD_TYPE=Release\ - -DCMAKE_CXX_COMPILER=$(compiler)\ - -DZ3_BUILD_DOTNET_BINDINGS=ON\ - -DZ3_INSTALL_DOTNET_BINDINGS=ON \ - -DZ3_BUILD_JAVA_BINDINGS=ON\ - -DZ3_INSTALL_JAVA_BINDINGS=ON\ - -DZ3_JAVA_JAR_INSTALLDIR=bin\ - -DZ3_JAVA_JNI_LIB_INSTALLDIR=bin\ - -DZ3_BUILD_PYTHON_BINDINGS=ON\ - -DZ3_INSTALL_PYTHON_BINDINGS=ON\ - -DCMAKE_INSTALL_PYTHON_PKG_DIR=bin/python\ - -DCMAKE_INSTALL_PREFIX=$(name)\ - -G "Ninja" ../ - ninja install - cp -r Microsoft.Z3 $(name)/bin/. - cp $(name)/lib/libz3.so $(name)/bin/. - rm -rf $(name)/lib - zip -r $(name).zip $(name) - cd .. - - script: cp $(arch)/*.zip $(Build.ArtifactStagingDirectory)/. - - task: PublishPipelineArtifact@0 - inputs: - artifactName: 'ubuntu-$(arch)' + artifactName: 'UbuntuArm64' targetPath: $(Build.ArtifactStagingDirectory) - job: UbuntuDoc @@ -134,36 +158,51 @@ stages: inputs: artifactName: 'UbuntuDoc' targetPath: $(Build.ArtifactStagingDirectory) - - - job: ManyLinuxBuild - variables: - python: "/opt/python/cp37-cp37m/bin/python" - name: ManyLinux + + - job: LinuxBuilds displayName: "ManyLinux build" + variables: + name: ManyLinux + python: "/opt/python/cp37-cp37m/bin/python" pool: vmImage: "ubuntu-latest" container: "quay.io/pypa/manylinux2014_x86_64:latest" steps: - - script: $(python) scripts/mk_unix_dist.py --nodotnet --nojava + - task: PythonScript@0 + displayName: Build + inputs: + scriptSource: 'filepath' + scriptPath: scripts/mk_unix_dist.py + arguments: --nodotnet --nojava + pythonInterpreter: $(python) - script: git clone https://github.com/z3prover/z3test z3test - - script: $(python) z3test/scripts/test_benchmarks.py build-dist/z3 z3test/regressions/smt2 - - script: cp dist/*.zip $(Build.ArtifactStagingDirectory)/ + displayName: 'Clone z3test' + - task: PythonScript@0 + displayName: Test + inputs: + scriptSource: 'filepath' + scriptPath: z3test/scripts/test_benchmarks.py + arguments: build-dist/z3 z3test/regressions/smt2 + pythonInterpreter: $(python) + - task: CopyFiles@2 + inputs: + sourceFolder: dist + contents: '*.zip' + targetFolder: $(Build.ArtifactStagingDirectory) - task: PublishPipelineArtifact@0 inputs: - artifactName: '$(name)Build' + artifactName: 'ManyLinuxBuild' targetPath: $(Build.ArtifactStagingDirectory) - - - template: build-win-signed-cmake.yml - parameters: - ReleaseVersion: $(ReleaseVersion) - BuildArchitecture: 'x86' - VCArchitecture: 'x86' - - - template: build-win-signed-cmake.yml + + - template: build-win-signed.yml parameters: ReleaseVersion: $(ReleaseVersion) BuildArchitecture: 'x64' - VCArchitecture: 'x64' + + - template: build-win-signed.yml + parameters: + ReleaseVersion: $(ReleaseVersion) + BuildArchitecture: 'x86' - template: build-win-signed-cmake.yml parameters: @@ -192,22 +231,17 @@ stages: - task: DownloadPipelineArtifact@2 displayName: 'Download Ubuntu 20.04 Build' inputs: - artifact: 'Ubuntu-20.04' + artifact: 'UbuntuBuild20' path: $(Agent.TempDirectory)\package - task: DownloadPipelineArtifact@2 displayName: 'Download Ubuntu ARM64 Build' inputs: - artifact: 'ubuntu-arm64' - path: $(Agent.TempDirectory)\package - - task: DownloadPipelineArtifact@2 - displayName: 'Download Ubuntu Build' - inputs: - artifact: 'ubuntu-x64' - path: $(Agent.TempDirectory)\package + artifact: 'UbuntuArm64' + path: $(Agent.TempDirectory)\package - task: DownloadPipelineArtifact@2 displayName: 'Download macOS Build' inputs: - artifact: 'Mac' + artifact: 'macOsBuild' path: $(Agent.TempDirectory)\package - task: DownloadPipelineArtifact@2 displayName: 'Download macOS Arm64 Build' @@ -427,7 +461,7 @@ stages: targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: - artifactName: 'Mac' + artifactName: 'macOsBuild' targetPath: $(Agent.TempDirectory) - task: DownloadPipelineArtifact@2 inputs: @@ -480,7 +514,7 @@ stages: - task: DownloadPipelineArtifact@2 displayName: "Download Mac" inputs: - artifactName: 'Mac' + artifactName: 'macOsBuild' targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download MacArm64" @@ -490,17 +524,12 @@ stages: - task: DownloadPipelineArtifact@2 displayName: "Download Ubuntu Arm64" inputs: - artifactName: 'ubuntu-arm64' - targetPath: tmp - - task: DownloadPipelineArtifact@2 - displayName: "Download Ubuntu" - inputs: - artifactName: 'ubuntu-x64' + artifactName: 'UbuntuArm64' targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download Ubuntu-20.04" inputs: - artifactName: 'Ubuntu-20.04' + artifactName: 'UbuntuBuild20' targetPath: tmp - task: DownloadPipelineArtifact@2 displayName: "Download Doc" From fa2c0e027894a8d55d2b841e27cbeecc99692a3f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 24 Feb 2024 14:35:07 -0800 Subject: [PATCH 219/224] enable release publish Signed-off-by: Nikolaj Bjorner --- scripts/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/release.yml b/scripts/release.yml index 27011bbe1..7a2c4ef41 100644 --- a/scripts/release.yml +++ b/scripts/release.yml @@ -594,7 +594,7 @@ stages: # Enable on release: - job: PyPIPublish - condition: eq(1,0) + condition: eq(1,1) displayName: "Publish to PyPI" pool: vmImage: "ubuntu-latest" From b56179521483fe658862b584ba8e6936bf44fb47 Mon Sep 17 00:00:00 2001 From: Jakob Rath Date: Mon, 26 Feb 2024 10:40:37 +0100 Subject: [PATCH 220/224] fix --- src/sat/smt/polysat/ule_constraint.cpp | 2 +- src/sat/smt/polysat/viable.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sat/smt/polysat/ule_constraint.cpp b/src/sat/smt/polysat/ule_constraint.cpp index c0c64ee2a..368dfc720 100644 --- a/src/sat/smt/polysat/ule_constraint.cpp +++ b/src/sat/smt/polysat/ule_constraint.cpp @@ -227,7 +227,6 @@ namespace polysat { lhs *= x; SASSERT(lhs.leading_coefficient().is_power_of_two()); } - TRACE("bv_verbose", tout << "simplified " << lhs << " <= " << rhs << "\n"); } // simplify_impl } @@ -262,6 +261,7 @@ namespace polysat { if (old_is_positive != is_positive || old_lhs != lhs || old_rhs != rhs) { ule_pp const old_ule(to_lbool(old_is_positive), old_lhs, old_rhs); ule_pp const new_ule(to_lbool(is_positive), lhs, rhs); + TRACE("bv", tout << "original: " << old_ule << "\nsimplified: " << new_ule << "\n"); // always-false and always-true constraints should be rewritten to 0 != 0 and 0 == 0, respectively. if (is_always_false(old_is_positive, old_lhs, old_rhs)) { SASSERT(!is_positive); diff --git a/src/sat/smt/polysat/viable.cpp b/src/sat/smt/polysat/viable.cpp index c4c4c9f10..aba3d1322 100644 --- a/src/sat/smt/polysat/viable.cpp +++ b/src/sat/smt/polysat/viable.cpp @@ -648,11 +648,17 @@ namespace polysat { verbose_stream() << "\n\n\n\n\n\nNon-viable assignment for v" << m_var << " size " << c.size(m_var) << "\n"; display_one(verbose_stream() << "entry: ", e) << "\n"; verbose_stream() << "value " << value << "\n"; + m_fixed_bits.display(verbose_stream() << "fixed: ") << "\n"; fixed_slice_extra_vector fixed; offset_slice_extra_vector subslices; c.s.get_fixed_sub_slices(m_var, fixed, subslices); // TODO: move into m_fixed bits? + // this case occurs if e-graph merges e.g. nodes "x - 2" and "3"; + // polysat will see assignment "x = 5" but no fixed bits + if (subslices.empty()) + return null_dependency; + unsigned max_level = 0; for (auto const& slice : subslices) max_level = std::max(max_level, slice.level); @@ -681,6 +687,9 @@ namespace polysat { unsigned w_level = slice.level; // level where value of w was fixed if (w == m_var) return null_dependency; + if (w == e->var) + return null_dependency; + // verbose_stream() << "v" << m_var << " size " << c.size(m_var) << ", v" << w << " size " << c.size(w) << " offset " << offset << " level " << w_level << "\n"; // Let: From 94e2e0c3e6958b62fad7f6ca328080584ab0d177 Mon Sep 17 00:00:00 2001 From: Jakob Rath Date: Mon, 26 Feb 2024 10:51:01 +0100 Subject: [PATCH 221/224] pass along lemma name --- src/sat/smt/intblast_solver.cpp | 10 +++++----- src/sat/smt/intblast_solver.h | 6 +++--- src/sat/smt/polysat_model.cpp | 12 ++++++------ src/sat/smt/polysat_solver.cpp | 14 +++++++------- src/sat/smt/polysat_solver.h | 6 +++--- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/sat/smt/intblast_solver.cpp b/src/sat/smt/intblast_solver.cpp index 6877b328f..6ee96264e 100644 --- a/src/sat/smt/intblast_solver.cpp +++ b/src/sat/smt/intblast_solver.cpp @@ -182,20 +182,20 @@ namespace intblast { translate_expr(e); } - lbool solver::check_axiom(sat::literal_vector const& lits) { + lbool solver::check_axiom(char const* name, sat::literal_vector const& lits) { sat::literal_vector core; for (auto lit : lits) core.push_back(~lit); - return check_core(core, {}); + return check_core(name, core, {}); } - lbool solver::check_propagation(sat::literal lit, sat::literal_vector const& lits, euf::enode_pair_vector const& eqs) { + lbool solver::check_propagation(char const* name, sat::literal lit, sat::literal_vector const& lits, euf::enode_pair_vector const& eqs) { sat::literal_vector core; core.append(lits); core.push_back(~lit); - return check_core(core, eqs); + return check_core(name, core, eqs); } - lbool solver::check_core(sat::literal_vector const& lits, euf::enode_pair_vector const& eqs) { + lbool solver::check_core(char const* name, sat::literal_vector const& lits, euf::enode_pair_vector const& eqs) { m_core.reset(); m_vars.reset(); m_is_plugin = false; diff --git a/src/sat/smt/intblast_solver.h b/src/sat/smt/intblast_solver.h index 0aceb8b2b..83ff52f11 100644 --- a/src/sat/smt/intblast_solver.h +++ b/src/sat/smt/intblast_solver.h @@ -105,9 +105,9 @@ namespace intblast { ~solver() override {} - lbool check_axiom(sat::literal_vector const& lits); - lbool check_core(sat::literal_vector const& lits, euf::enode_pair_vector const& eqs); - lbool check_propagation(sat::literal lit, sat::literal_vector const& lits, euf::enode_pair_vector const& eqs); + lbool check_axiom(char const* name, sat::literal_vector const& lits); + lbool check_core(char const* name, sat::literal_vector const& lits, euf::enode_pair_vector const& eqs); + lbool check_propagation(char const* name, sat::literal lit, sat::literal_vector const& lits, euf::enode_pair_vector const& eqs); lbool check_solver_state(); diff --git a/src/sat/smt/polysat_model.cpp b/src/sat/smt/polysat_model.cpp index 815f6df51..8f68ede0a 100644 --- a/src/sat/smt/polysat_model.cpp +++ b/src/sat/smt/polysat_model.cpp @@ -97,24 +97,24 @@ namespace polysat { return out; } - void solver::validate_propagate(sat::literal lit, sat::literal_vector const& core, euf::enode_pair_vector const& eqs) { + void solver::validate_propagate(char const* name, sat::literal lit, sat::literal_vector const& core, euf::enode_pair_vector const& eqs) { if (!ctx.get_config().m_core_validate) return; - auto r = m_intblast.check_propagation(lit, core, eqs); + auto r = m_intblast.check_propagation(name, lit, core, eqs); VERIFY (r != l_true); } - void solver::validate_conflict(sat::literal_vector const& core, euf::enode_pair_vector const& eqs) { + void solver::validate_conflict(char const* name, sat::literal_vector const& core, euf::enode_pair_vector const& eqs) { if (!ctx.get_config().m_core_validate) return; - auto r = m_intblast.check_core(core, eqs); + auto r = m_intblast.check_core(name, core, eqs); VERIFY (r != l_true); } - void solver::validate_axiom(sat::literal_vector const& clause) { + void solver::validate_axiom(char const* name, sat::literal_vector const& clause) { if (!ctx.get_config().m_core_validate) return; - auto r = m_intblast.check_axiom(clause); + auto r = m_intblast.check_axiom(name, clause); VERIFY (r != l_true); } diff --git a/src/sat/smt/polysat_solver.cpp b/src/sat/smt/polysat_solver.cpp index 7ae6c99ef..5a20737d0 100644 --- a/src/sat/smt/polysat_solver.cpp +++ b/src/sat/smt/polysat_solver.cpp @@ -130,7 +130,7 @@ namespace polysat { TRACE("bv", tout << "conflict: " << lits << " "; for (auto [a, b] : eqs) tout << ctx.bpp(a) << " == " << ctx.bpp(b) << " "; tout << "\n"; s().display(tout)); - validate_conflict(lits, eqs); + validate_conflict(hint_info, lits, eqs); ctx.set_conflict(ex); } @@ -264,7 +264,7 @@ namespace polysat { verbose_stream() << "contradictory propagation " << sc << " <- " << deps << "\n"; } auto ex = euf::th_explain::propagate(*this, core, eqs, lit, hint); - validate_propagate(lit, core, eqs); + validate_propagate(hint_info, lit, core, eqs); ctx.propagate(lit, ex); return dependency(lit.var()); } @@ -313,7 +313,7 @@ namespace polysat { if (ctx.use_drat() && hint_info) hint = mk_proof_hint(hint_info, core, eqs); auto ex = euf::th_explain::conflict(*this, core, eqs, hint); - validate_conflict(core, eqs); + validate_conflict(hint_info, core, eqs); ctx.set_conflict(ex); } } @@ -328,7 +328,7 @@ namespace polysat { core.pop_back(); } auto ex = euf::th_explain::propagate(*this, core, eqs, lit, hint); - validate_propagate(lit, core, eqs); + validate_propagate(hint_info, lit, core, eqs); ctx.propagate(lit, ex); } else if (sign) { @@ -341,7 +341,7 @@ namespace polysat { if (ctx.use_drat() && hint_info) hint = mk_proof_hint(hint_info, core, eqs); auto ex = euf::th_explain::conflict(*this, core, eqs, hint); - validate_conflict(core, eqs); + validate_conflict(hint_info, core, eqs); ctx.set_conflict(ex); } } @@ -385,7 +385,7 @@ namespace polysat { } TRACE("bv", display_clause(name, tout, lits)); IF_VERBOSE(1, display_clause(name, verbose_stream(), lits)); - validate_axiom(lits); + validate_axiom(name, lits); s().add_clause(lits.size(), lits.data(), sat::status::th(is_redundant, get_id(), hint)); return true; } @@ -393,7 +393,7 @@ namespace polysat { void solver::add_axiom(char const* name, sat::literal const* begin, sat::literal const* end, bool is_redundant) { ++m_stats.m_num_axioms; sat::literal_vector lits; - validate_axiom(sat::literal_vector(static_cast(end - begin), begin)); + validate_axiom(name, sat::literal_vector(static_cast(end - begin), begin)); for (auto it = begin; it != end; ++it) { auto lit = *it; if (s().value(lit) == l_true && s().lvl(lit) == 0) diff --git a/src/sat/smt/polysat_solver.h b/src/sat/smt/polysat_solver.h index 3eba74a82..1bfeb4f18 100644 --- a/src/sat/smt/polysat_solver.h +++ b/src/sat/smt/polysat_solver.h @@ -239,9 +239,9 @@ namespace polysat { void add_axiom(char const* name, sat::literal const* begin, sat::literal const* end, bool is_redundant); void equiv_axiom(char const* name, sat::literal a, sat::literal b); - void validate_propagate(sat::literal lit, sat::literal_vector const& core, euf::enode_pair_vector const& eqs); - void validate_conflict(sat::literal_vector const& core, euf::enode_pair_vector const& eqs); - void validate_axiom(sat::literal_vector const& clause); + void validate_propagate(char const* name, sat::literal lit, sat::literal_vector const& core, euf::enode_pair_vector const& eqs); + void validate_conflict(char const* name, sat::literal_vector const& core, euf::enode_pair_vector const& eqs); + void validate_axiom(char const* name, sat::literal_vector const& clause); std::ostream& display_clause(char const * name, std::ostream& out, sat::literal_vector const& lits) const; From b2166da464e8afa77a6ca88d5372137d0a9cf722 Mon Sep 17 00:00:00 2001 From: Jakob Rath Date: Mon, 26 Feb 2024 10:55:07 +0100 Subject: [PATCH 222/224] add code for offline validation --- src/sat/smt/intblast_solver.cpp | 38 +++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/sat/smt/intblast_solver.cpp b/src/sat/smt/intblast_solver.cpp index 6ee96264e..9db6f448e 100644 --- a/src/sat/smt/intblast_solver.cpp +++ b/src/sat/smt/intblast_solver.cpp @@ -233,8 +233,42 @@ namespace intblast { es[i] = tmp; } +#if 0 + namespace fs = std::filesystem; + static unsigned num_check = 0; + fs::path filename = std::string("validation/int-") + std::to_string(++num_check) + ".smt2"; + fs::create_directories(filename.parent_path()); + IF_VERBOSE(1, verbose_stream() << "validation check written to file " << filename << "\n"); + std::ofstream file(filename); + std::string name_esc; + if (name) { + name_esc = name; + for (char& c : name_esc) + if (c == '|') + c = '!'; + } + else + name_esc = ""; + + file << "(set-logic ALL)\n"; + file << "(set-info :source |\n"; + file << " Name: " << name_esc << "\n"; + file << original_es << "\n|)\n"; + + m_solver->push(); + m_solver->assert_expr(es); + m_solver->display(file) << "(check-sat)\n"; + m_solver->pop(1); + + file.close(); + + // if (num_check == 68) + // std::abort(); + + r = l_false; +#else IF_VERBOSE(2, verbose_stream() << "check\n" << original_es << "\n"); - + IF_VERBOSE(2, { m_solver->push(); @@ -243,8 +277,8 @@ namespace intblast { m_solver->pop(1); }); - r = m_solver->check_sat(es); +#endif } m_solver->collect_statistics(m_stats); From af017d09064999dc57cd93fcf8b0c4f2896cafee Mon Sep 17 00:00:00 2001 From: Jakob Rath Date: Mon, 26 Feb 2024 11:56:04 +0100 Subject: [PATCH 223/224] bad merge? --- src/math/lp/int_solver.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/math/lp/int_solver.cpp b/src/math/lp/int_solver.cpp index c3516f0e4..f547ba274 100644 --- a/src/math/lp/int_solver.cpp +++ b/src/math/lp/int_solver.cpp @@ -201,12 +201,7 @@ namespace lp { if (r == lia_move::undef && should_gomory_cut()) r = gomory(*this).get_gomory_cuts(2); if (r == lia_move::undef) r = int_branch(*this)(); - - m_cut_vars.reset(); - if (settings().get_cancel_flag()) - return lia_move::undef; - if (r == lia_move::undef) - r = int_branch(*this)(); + if (settings().get_cancel_flag()) r = lia_move::undef; return r; } From 4a726208af264f4553c7fd550a8cbbb34f6a9f7c Mon Sep 17 00:00:00 2001 From: Jakob Rath Date: Mon, 26 Feb 2024 12:02:49 +0100 Subject: [PATCH 224/224] bad merge? --- scripts/mk_nuget_task.py | 9 --------- src/api/python/setup.py | 7 ++++--- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/scripts/mk_nuget_task.py b/scripts/mk_nuget_task.py index 515488d5e..9de592c08 100644 --- a/scripts/mk_nuget_task.py +++ b/scripts/mk_nuget_task.py @@ -96,11 +96,7 @@ def mk_targets(source_root): def mk_icon(source_root): mk_dir("out/content") shutil.copy(f"{source_root}/resources/icon.jpg", "out/content/icon.jpg") -<<<<<<< HEAD # shutil.copy(f"{source_root}/src/api/dotnet/README.md", "out/content/README.md") -======= - shutil.copy(f"{source_root}/src/api/dotnet/README.md", "out/content/README.md") ->>>>>>> bdc40b1f5f83cca22dc1d6c5808e935a3b50176c @@ -121,7 +117,6 @@ Linux Dependencies: © Microsoft Corporation. All rights reserved. smt constraint solver theorem prover content/icon.jpg - content/README.md https://github.com/Z3Prover/z3 MIT @@ -131,10 +126,6 @@ Linux Dependencies: - - - - """.format(version, repo, branch, commit, arch) print(contents) sym = "sym." if symbols else "" diff --git a/src/api/python/setup.py b/src/api/python/setup.py index 73a6ce726..c3f65f848 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -313,11 +313,12 @@ if 'bdist_wheel' in sys.argv and '--plat-name' not in sys.argv: osver = RELEASE_METADATA[3] if osver.count('.') > 1: osver = '.'.join(osver.split('.')[:2]) - osver = osver.replace('.','_') + if osver.startswith("11"): + osver = "11_0" if arch == 'x64': - plat_name ='macosx_%s_x86_64' % re.sub(r'\A(1[1-9])(_[\d]+)*\Z', r'\1_0', osver) + plat_name ='macosx_%s_x86_64' % osver.replace('.', '_') elif arch == 'arm64': - plat_name ='macosx_%s_arm64' % osver + plat_name ='macosx_%s_arm64' % osver.replace('.', '_') else: raise Exception(f"idk how os {distos} {osver} works. what goes here?") else: